WSTester updated to work plus hopefully all the other changes that need to go into...
[jabaws.git] / binaries / src / ViennaRNA / lib / fold.c
diff --git a/binaries/src/ViennaRNA/lib/fold.c b/binaries/src/ViennaRNA/lib/fold.c
new file mode 100644 (file)
index 0000000..7b24966
--- /dev/null
@@ -0,0 +1,2751 @@
+/** \file **/
+
+/*
+                  minimum free energy
+                  RNA secondary structure prediction
+
+                  c Ivo Hofacker, Chrisoph Flamm
+                  original implementation by
+                  Walter Fontana
+                  g-quadruplex support and threadsafety
+                  by Ronny Lorenz
+
+                  Vienna RNA package
+*/
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+
+#include "utils.h"
+#include "energy_par.h"
+#include "fold_vars.h"
+#include "pair_mat.h"
+#include "params.h"
+#include "loop_energies.h"
+#include "data_structures.h"
+#include "gquad.h"
+#include "fold.h"
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+
+#define PAREN
+#define STACK_BULGE1      1       /* stacking energies for bulges of size 1 */
+#define NEW_NINIO         1       /* new asymetry penalty */
+#define MAXSECTORS        500     /* dimension for a backtrack array */
+#define LOCALITY          0.      /* locality parameter for base-pairs */
+
+#define SAME_STRAND(I,J)  (((I)>=cut_point)||((J)<cut_point))
+
+/*
+#################################
+# GLOBAL VARIABLES              #
+#################################
+*/
+PUBLIC  int logML     = 0;  /* if nonzero use logarithmic ML energy in energy_of_struct */
+PUBLIC  int uniq_ML   = 0;  /* do ML decomposition uniquely (for subopt) */
+PUBLIC  int cut_point = -1; /* set to first pos of second seq for cofolding */
+PUBLIC  int eos_debug = 0;  /* verbose info from energy_of_struct */
+
+/*
+#################################
+# PRIVATE VARIABLES             #
+#################################
+*/
+PRIVATE int     *indx     = NULL; /* index for moving in the triangle matrices c[] and fMl[]*/
+PRIVATE int     *c        = NULL; /* energy array, given that i-j pair */
+PRIVATE int     *cc       = NULL; /* linear array for calculating canonical structures */
+PRIVATE int     *cc1      = NULL; /*   "     "        */
+PRIVATE int     *f5       = NULL; /* energy of 5' end */
+PRIVATE int     *f53      = NULL; /* energy of 5' end with 3' nucleotide not available for mismatches */
+PRIVATE int     *fML      = NULL; /* multi-loop auxiliary energy array */
+PRIVATE int     *fM1      = NULL; /* second ML array, only for subopt */
+PRIVATE int     *fM2      = NULL; /* fM2 = multiloop region with exactly two stems, extending to 3' end        */
+PRIVATE int     *Fmi      = NULL; /* holds row i of fML (avoids jumps in memory) */
+PRIVATE int     *DMLi     = NULL; /* DMLi[j] holds MIN(fML[i,k]+fML[k+1,j])  */
+PRIVATE int     *DMLi1    = NULL; /*             MIN(fML[i+1,k]+fML[k+1,j])  */
+PRIVATE int     *DMLi2    = NULL; /*             MIN(fML[i+2,k]+fML[k+1,j])  */
+PRIVATE int     *DMLi_a   = NULL; /* DMLi_a[j] holds min energy for at least two multiloop stems in [i,j], where j is available for dangling onto a surrounding stem */
+PRIVATE int     *DMLi_o   = NULL; /* DMLi_o[j] holds min energy for at least two multiloop stems in [i,j], where j is unavailable for dangling onto a surrounding stem */
+PRIVATE int     *DMLi1_a  = NULL;
+PRIVATE int     *DMLi1_o  = NULL;
+PRIVATE int     *DMLi2_a  = NULL;
+PRIVATE int     *DMLi2_o  = NULL;
+PRIVATE int     Fc, FcH, FcI, FcM;  /* parts of the exterior loop energies */
+PRIVATE sect    sector[MAXSECTORS]; /* stack of partial structures for backtracking */
+PRIVATE char    *ptype = NULL;      /* precomputed array of pair types */
+PRIVATE short   *S = NULL, *S1 = NULL;
+PRIVATE paramT  *P          = NULL;
+PRIVATE int     init_length = -1;
+PRIVATE int     *BP = NULL; /* contains the structure constrainsts: BP[i]
+                        -1: | = base must be paired
+                        -2: < = base must be paired with j<i
+                        -3: > = base must be paired with j>i
+                        -4: x = base must not pair
+                        positive int: base is paired with int      */
+PRIVATE short   *pair_table         = NULL; /* needed by energy of struct */
+PRIVATE bondT   *base_pair2         = NULL; /* this replaces base_pair from fold_vars.c */
+PRIVATE int     circular            = 0;
+PRIVATE int     struct_constrained  = 0;
+PRIVATE int     with_gquad          = 0;
+
+PRIVATE int     *ggg = NULL;    /* minimum free energies of the gquadruplexes */
+
+#ifdef _OPENMP
+
+#pragma omp threadprivate(indx, c, cc, cc1, f5, f53, fML, fM1, fM2, Fmi,\
+                          DMLi, DMLi1, DMLi2, DMLi_a, DMLi_o, DMLi1_a, DMLi1_o, DMLi2_a, DMLi2_o,\
+                          Fc, FcH, FcI, FcM,\
+                          sector, ptype, S, S1, P, init_length, BP, pair_table, base_pair2, circular, struct_constrained,\
+                          ggg, with_gquad)
+
+#endif
+
+/*
+#################################
+# PRIVATE FUNCTION DECLARATIONS #
+#################################
+*/
+PRIVATE void  get_arrays(unsigned int size);
+PRIVATE int   stack_energy(int i, const char *string, int verbostiy_level);
+PRIVATE int   energy_of_extLoop_pt(int i, short *pair_table);
+PRIVATE int   energy_of_ml_pt(int i, short *pt);
+PRIVATE int   ML_Energy(int i, int is_extloop);
+PRIVATE void  make_ptypes(const short *S, const char *structure);
+PRIVATE void  backtrack(const char *sequence, int s);
+PRIVATE int   fill_arrays(const char *sequence);
+PRIVATE void  fill_arrays_circ(const char *string, int *bt);
+PRIVATE void  init_fold(int length, paramT *parameters);
+/* needed by cofold/eval */
+PRIVATE int   cut_in_loop(int i);
+
+/* deprecated functions */
+/*@unused@*/
+int oldLoopEnergy(int i, int j, int p, int q, int type, int type_2);
+int LoopEnergy(int n1, int n2, int type, int type_2, int si1, int sj1, int sp1, int sq1);
+int HairpinE(int size, int type, int si1, int sj1, const char *string);
+
+
+/*
+#################################
+# BEGIN OF FUNCTION DEFINITIONS #
+#################################
+*/
+
+/* allocate memory for folding process */
+PRIVATE void init_fold(int length, paramT *parameters){
+
+#ifdef _OPENMP
+/* Explicitly turn off dynamic threads */
+  omp_set_dynamic(0);
+#endif
+
+  if (length<1) nrerror("initialize_fold: argument must be greater 0");
+  free_arrays();
+  get_arrays((unsigned) length);
+  init_length=length;
+
+  indx = get_indx((unsigned)length);
+
+  update_fold_params_par(parameters);
+}
+
+/*--------------------------------------------------------------------------*/
+
+PRIVATE void get_arrays(unsigned int size){
+  if(size >= (unsigned int)sqrt((double)INT_MAX))
+    nrerror("get_arrays@fold.c: sequence length exceeds addressable range");
+
+  c     = (int *) space(sizeof(int)*((size*(size+1))/2+2));
+  fML   = (int *) space(sizeof(int)*((size*(size+1))/2+2));
+  if (uniq_ML)
+    fM1 = (int *) space(sizeof(int)*((size*(size+1))/2+2));
+
+  ptype = (char *)space(sizeof(char)*((size*(size+1))/2+2));
+  f5    = (int *) space(sizeof(int)*(size+2));
+  f53   = (int *) space(sizeof(int)*(size+2));
+  cc    = (int *) space(sizeof(int)*(size+2));
+  cc1   = (int *) space(sizeof(int)*(size+2));
+  Fmi   = (int *) space(sizeof(int)*(size+1));
+  DMLi  = (int *) space(sizeof(int)*(size+1));
+  DMLi1 = (int *) space(sizeof(int)*(size+1));
+  DMLi2 = (int *) space(sizeof(int)*(size+1));
+
+  DMLi_a  = (int *) space(sizeof(int)*(size+1));
+  DMLi_o  = (int *) space(sizeof(int)*(size+1));
+  DMLi1_a = (int *) space(sizeof(int)*(size+1));
+  DMLi1_o = (int *) space(sizeof(int)*(size+1));
+  DMLi2_a = (int *) space(sizeof(int)*(size+1));
+  DMLi2_o = (int *) space(sizeof(int)*(size+1));
+
+  base_pair2 = (bondT *) space(sizeof(bondT)*(1+size/2+200)); /* add a guess of how many G's may be involved in a G quadruplex */
+
+  /* extra array(s) for circfold() */
+  if(circular) fM2 =  (int *) space(sizeof(int)*(size+2));
+}
+
+/*--------------------------------------------------------------------------*/
+
+PUBLIC void free_arrays(void){
+  if(indx)      free(indx);
+  if(c)         free(c);
+  if(fML)       free(fML);
+  if(f5)        free(f5);
+  if(f53)       free(f53);
+  if(cc)        free(cc);
+  if(cc1)       free(cc1);
+  if(ptype)     free(ptype);
+  if(fM1)       free(fM1);
+  if(fM2)       free(fM2);
+  if(base_pair2) free(base_pair2);
+  if(Fmi)       free(Fmi);
+  if(DMLi)      free(DMLi);
+  if(DMLi1)     free(DMLi1);
+  if(DMLi2)     free(DMLi2);
+  if(DMLi_a)    free(DMLi_a);
+  if(DMLi_o)    free(DMLi_o);
+  if(DMLi1_a)   free(DMLi1_a);
+  if(DMLi1_o)   free(DMLi1_o);
+  if(DMLi2_a)   free(DMLi2_a);
+  if(DMLi2_o)   free(DMLi2_o);
+  if(P)         free(P);
+  if(ggg)       free(ggg);
+
+  indx = c = fML = f5 = f53 = cc = cc1 = fM1 = fM2 = Fmi = DMLi = DMLi1 = DMLi2 = ggg = NULL;
+  DMLi_a = DMLi_o = DMLi1_a = DMLi1_o = DMLi2_a = DMLi2_o = NULL;
+  ptype       = NULL;
+  base_pair   = NULL;
+  base_pair2  = NULL;
+  P           = NULL;
+  init_length = 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+PUBLIC void export_fold_arrays( int **f5_p,
+                                int **c_p,
+                                int **fML_p,
+                                int **fM1_p,
+                                int **indx_p,
+                                char **ptype_p){
+  /* make the DP arrays available to routines such as subopt() */
+  *f5_p     = f5;
+  *c_p      = c;
+  *fML_p    = fML;
+  *fM1_p    = fM1;
+  *indx_p   = indx;
+  *ptype_p  = ptype;
+}
+
+PUBLIC void export_fold_arrays_par( int **f5_p,
+                                    int **c_p,
+                                    int **fML_p,
+                                    int **fM1_p,
+                                    int **indx_p,
+                                    char **ptype_p,
+                                    paramT **P_p){
+  export_fold_arrays(f5_p, c_p, fML_p, fM1_p, indx_p,ptype_p);
+  *P_p = P;
+}
+
+PUBLIC void export_circfold_arrays( int *Fc_p,
+                                    int *FcH_p,
+                                    int *FcI_p,
+                                    int *FcM_p,
+                                    int **fM2_p,
+                                    int **f5_p,
+                                    int **c_p,
+                                    int **fML_p,
+                                    int **fM1_p,
+                                    int **indx_p,
+                                    char **ptype_p){
+  /* make the DP arrays available to routines such as subopt() */
+  *f5_p     = f5;
+  *c_p      = c;
+  *fML_p    = fML;
+  *fM1_p    = fM1;
+  *fM2_p    = fM2;
+  *Fc_p     = Fc;
+  *FcH_p    = FcH;
+  *FcI_p    = FcI;
+  *FcM_p    = FcM;
+  *indx_p   = indx;
+  *ptype_p  = ptype;
+}
+
+PUBLIC void export_circfold_arrays_par( int *Fc_p,
+                                    int *FcH_p,
+                                    int *FcI_p,
+                                    int *FcM_p,
+                                    int **fM2_p,
+                                    int **f5_p,
+                                    int **c_p,
+                                    int **fML_p,
+                                    int **fM1_p,
+                                    int **indx_p,
+                                    char **ptype_p,
+                                    paramT **P_p){
+  export_circfold_arrays(Fc_p, FcH_p, FcI_p, FcM_p, fM2_p, f5_p, c_p, fML_p, fM1_p, indx_p, ptype_p);
+  *P_p = P;
+}
+/*--------------------------------------------------------------------------*/
+
+
+PUBLIC float fold(const char *string, char *structure){
+  return fold_par(string, structure, NULL, fold_constrained, 0);
+}
+
+PUBLIC float circfold(const char *string, char *structure){
+  return fold_par(string, structure, NULL, fold_constrained, 1);
+}
+
+PUBLIC float fold_par(const char *string,
+                      char *structure,
+                      paramT *parameters,
+                      int is_constrained,
+                      int is_circular){
+
+  int i, length, energy, bonus, bonus_cnt, s;
+
+  bonus               = 0;
+  bonus_cnt           = 0;
+  s                   = 0;
+  circular            = is_circular;
+  struct_constrained  = is_constrained;
+  length              = (int) strlen(string);
+
+#ifdef _OPENMP
+  init_fold(length, parameters);
+#else
+  if (parameters) init_fold(length, parameters);
+  else if (length>init_length) init_fold(length, parameters);
+  else if (fabs(P->temperature - temperature)>1e-6) update_fold_params();
+#endif
+
+  with_gquad  = P->model_details.gquad;
+  S           = encode_sequence(string, 0);
+  S1          = encode_sequence(string, 1);
+  BP          = (int *)space(sizeof(int)*(length+2));
+
+  make_ptypes(S, structure);
+
+  energy = fill_arrays(string);
+
+  if(circular){
+    fill_arrays_circ(string, &s);
+    energy = Fc;
+  }
+  backtrack(string, s);
+
+#ifdef PAREN
+  parenthesis_structure(structure, base_pair2, length);
+#else
+  letter_structure(structure, base_pair2, length);
+#endif
+
+  /*
+  *  Backward compatibility:
+  *  This block may be removed if deprecated functions
+  *  relying on the global variable "base_pair" vanishs from within the package!
+  */
+  base_pair = base_pair2;
+  /*
+  {
+    if(base_pair) free(base_pair);
+    base_pair = (bondT *)space(sizeof(bondT) * (1+length/2));
+    memcpy(base_pair, base_pair2, sizeof(bondT) * (1+length/2));
+  }
+  */
+
+  /* check constraints */
+  for(i=1;i<=length;i++) {
+    if((BP[i]<0)&&(BP[i]>-4)) {
+      bonus_cnt++;
+      if((BP[i]==-3)&&(structure[i-1]==')')) bonus++;
+      if((BP[i]==-2)&&(structure[i-1]=='(')) bonus++;
+      if((BP[i]==-1)&&(structure[i-1]!='.')) bonus++;
+    }
+
+    if(BP[i]>i) {
+      int l;
+      bonus_cnt++;
+      for(l=1; l<=base_pair2[0].i; l++)
+        if(base_pair2[l].i != base_pair2[l].j)
+          if((i==base_pair2[l].i)&&(BP[i]==base_pair2[l].j)) bonus++;
+    }
+  }
+
+  if (bonus_cnt>bonus) fprintf(stderr,"\ncould not enforce all constraints\n");
+  bonus*=BONUS;
+
+  free(S); free(S1); free(BP);
+
+  energy += bonus;      /*remove bonus energies from result */
+
+  if (backtrack_type=='C')
+    return (float) c[indx[length]+1]/100.;
+  else if (backtrack_type=='M')
+    return (float) fML[indx[length]+1]/100.;
+  else
+    return (float) energy/100.;
+}
+
+/**
+*** fill "c", "fML" and "f5" arrays and return  optimal energy
+**/
+PRIVATE int fill_arrays(const char *string) {
+
+  int   i, j, k, length, energy, en, mm5, mm3;
+  int   decomp, new_fML, max_separation;
+  int   no_close, type, type_2, tt;
+  int   bonus=0;
+  
+  int   dangle_model, noGUclosure, with_gquads;
+
+  dangle_model  = P->model_details.dangles;
+  noGUclosure   = P->model_details.noGUclosure;
+
+  length = (int) strlen(string);
+
+  max_separation = (int) ((1.-LOCALITY)*(double)(length-2)); /* not in use */
+
+  if(with_gquad)
+    ggg = get_gquad_matrix(S, P);
+
+
+  for (j=1; j<=length; j++) {
+    Fmi[j]=DMLi[j]=DMLi1[j]=DMLi2[j]=INF;
+  }
+
+  for (j = 1; j<=length; j++)
+    for (i=(j>TURN?(j-TURN):1); i<j; i++) {
+      c[indx[j]+i] = fML[indx[j]+i] = INF;
+      if (uniq_ML) fM1[indx[j]+i] = INF;
+    }
+
+  if (length <= TURN) return 0;
+
+  for (i = length-TURN-1; i >= 1; i--) { /* i,j in [1..length] */
+
+    for (j = i+TURN+1; j <= length; j++) {
+      int p, q, ij, jj, ee;
+      int minq, maxq, l1, up, c0, c1, c2, c3;
+      int MLenergy;
+      ij = indx[j]+i;
+      bonus = 0;
+      type = ptype[ij];
+      energy = INF;
+      /* enforcing structure constraints */
+      if ((BP[i]==j)||(BP[i]==-1)||(BP[i]==-2)) bonus -= BONUS;
+      if ((BP[j]==-1)||(BP[j]==-3)) bonus -= BONUS;
+      if ((BP[i]==-4)||(BP[j]==-4)) type=0;
+
+      no_close = (((type==3)||(type==4))&&noGUclosure&&(bonus==0));
+
+      if (j-i-1 > max_separation) type = 0;  /* forces locality degree */
+
+      if (type) {   /* we have a pair */
+        int new_c=0, stackEnergy=INF;
+        /* hairpin ----------------------------------------------*/
+
+        new_c = (no_close) ? FORBIDDEN : E_Hairpin(j-i-1, type, S1[i+1], S1[j-1], string+i-1, P);
+
+        /*--------------------------------------------------------
+          check for elementary structures involving more than one
+          closing pair.
+          --------------------------------------------------------*/
+
+        for (p = i+1; p <= MIN2(j-2-TURN,i+MAXLOOP+1) ; p++) {
+          minq = j-i+p-MAXLOOP-2;
+          if (minq<p+1+TURN) minq = p+1+TURN;
+          for (q = minq; q < j; q++) {
+            type_2 = ptype[indx[q]+p];
+
+            if (type_2==0) continue;
+            type_2 = rtype[type_2];
+
+            if (noGUclosure)
+              if (no_close||(type_2==3)||(type_2==4))
+                if ((p>i+1)||(q<j-1)) continue;  /* continue unless stack */
+
+            energy = E_IntLoop(p-i-1, j-q-1, type, type_2,
+                                S1[i+1], S1[j-1], S1[p-1], S1[q+1], P);
+
+            ee = energy+c[indx[q]+p];
+            new_c = MIN2(new_c, ee);
+            if ((p==i+1)&&(j==q+1)) stackEnergy = energy; /* remember stack energy */
+
+          } /* end q-loop */
+        } /* end p-loop */
+        /* multi-loop decomposition ------------------------*/
+
+
+        if (!no_close) {
+          decomp = DMLi1[j-1];
+          tt = rtype[type];
+          switch(dangle_model){
+            /* no dangles */
+            case 0:   decomp += E_MLstem(tt, -1, -1, P);
+                      break;
+
+            /* double dangles */
+            case 2:   decomp += E_MLstem(tt, S1[j-1], S1[i+1], P);
+                      break;
+
+            /* normal dangles, aka dangles = 1 || 3 */
+            default:  decomp += E_MLstem(tt, -1, -1, P);
+                      decomp = MIN2(decomp, DMLi2[j-1] + E_MLstem(tt, -1, S1[i+1], P) + P->MLbase);
+                      decomp = MIN2(decomp, DMLi2[j-2] + E_MLstem(tt, S1[j-1], S1[i+1], P) + 2*P->MLbase);
+                      decomp = MIN2(decomp, DMLi1[j-2] + E_MLstem(tt, S1[j-1], -1, P) + P->MLbase);
+                      break;
+          }
+          MLenergy = decomp + P->MLclosing;
+          new_c = MIN2(new_c, MLenergy);
+        }
+
+        /* coaxial stacking of (i.j) with (i+1.k) or (k+1.j-1) */
+
+        if (dangle_model==3) {
+          decomp = INF;
+          for (k = i+2+TURN; k < j-2-TURN; k++) {
+            type_2 = rtype[ptype[indx[k]+i+1]];
+            if (type_2)
+              decomp = MIN2(decomp, c[indx[k]+i+1]+P->stack[type][type_2]+fML[indx[j-1]+k+1]);
+            type_2 = rtype[ptype[indx[j-1]+k+1]];
+            if (type_2)
+              decomp = MIN2(decomp, c[indx[j-1]+k+1]+P->stack[type][type_2]+fML[indx[k]+i+1]);
+          }
+          /* no TermAU penalty if coax stack */
+          decomp += 2*P->MLintern[1] + P->MLclosing;
+          new_c = MIN2(new_c, decomp);
+        }
+
+        if(with_gquad){
+          /* include all cases where a g-quadruplex may be enclosed by base pair (i,j) */
+          if (!no_close) {
+            tt = rtype[type];
+            energy = E_GQuad_IntLoop(i, j, type, S1, ggg, indx, P);
+            new_c = MIN2(new_c, energy);
+          }
+        }
+
+        new_c = MIN2(new_c, cc1[j-1]+stackEnergy);
+        cc[j] = new_c + bonus;
+        if (noLonelyPairs)
+          c[ij] = cc1[j-1]+stackEnergy+bonus;
+        else
+          c[ij] = cc[j];
+
+      } /* end >> if (pair) << */
+
+      else c[ij] = INF;
+
+      /* done with c[i,j], now compute fML[i,j] and fM1[i,j] */
+
+      /* (i,j) + MLstem ? */
+      new_fML = INF;
+      if(type){
+        new_fML = c[ij];
+        switch(dangle_model){
+          case 2:   new_fML += E_MLstem(type, (i==1) ? S1[length] : S1[i-1], S1[j+1], P);
+                    break;
+          default:  new_fML += E_MLstem(type, -1, -1, P);
+                    break;
+        }
+      }
+
+      if(with_gquad){
+        new_fML = MIN2(new_fML, ggg[indx[j] + i] + E_MLstem(0, -1, -1, P));
+      }
+
+      if (uniq_ML){
+        fM1[ij] = MIN2(fM1[indx[j-1]+i] + P->MLbase, new_fML);
+      }
+
+      /* free ends ? -----------------------------------------*/
+      /*  we must not just extend 3'/5' end by unpaired nucleotides if
+      *   dangle_model == 1, this could lead to d5+d3 contributions were
+      *   mismatch must be taken!
+      */
+      switch(dangle_model){
+        /* no dangles */
+        case 0:   new_fML = MIN2(new_fML, fML[ij+1]+P->MLbase);
+                  new_fML = MIN2(fML[indx[j-1]+i]+P->MLbase, new_fML);
+                  break;
+
+        /* double dangles */
+        case 2:   new_fML = MIN2(new_fML, fML[ij+1]+P->MLbase);
+                  new_fML = MIN2(fML[indx[j-1]+i]+P->MLbase, new_fML);
+                  break;
+
+        /* normal dangles, aka dangle_model = 1 || 3 */
+        default:  mm5 = ((i>1) || circular) ? S1[i] : -1;
+                  mm3 = ((j<length) || circular) ? S1[j] : -1;
+                  new_fML = MIN2(new_fML, fML[ij+1] + P->MLbase);
+                  new_fML = MIN2(new_fML, fML[indx[j-1]+i] + P->MLbase);
+                  tt = ptype[ij+1];
+                  if(tt) new_fML = MIN2(new_fML, c[ij+1] + E_MLstem(tt, mm5, -1, P) + P->MLbase);
+                  tt = ptype[indx[j-1]+i];
+                  if(tt) new_fML = MIN2(new_fML, c[indx[j-1]+i] + E_MLstem(tt, -1, mm3, P) + P->MLbase);
+                  tt = ptype[indx[j-1]+i+1];
+                  if(tt) new_fML = MIN2(new_fML, c[indx[j-1]+i+1] + E_MLstem(tt, mm5, mm3, P) + 2*P->MLbase);
+                  break;
+      }
+
+      /* modular decomposition -------------------------------*/
+      for (decomp = INF, k = i + 1 + TURN; k <= j - 2 - TURN; k++)
+        decomp = MIN2(decomp, Fmi[k]+fML[indx[j]+k+1]);
+      DMLi[j] = decomp;               /* store for use in ML decompositon */
+      new_fML = MIN2(new_fML,decomp);
+
+      /* coaxial stacking */
+      if (dangle_model==3) {
+        /* additional ML decomposition as two coaxially stacked helices */
+        for (decomp = INF, k = i+1+TURN; k <= j-2-TURN; k++) {
+          type = ptype[indx[k]+i]; type = rtype[type];
+          type_2 = ptype[indx[j]+k+1]; type_2 = rtype[type_2];
+          if (type && type_2)
+            decomp = MIN2(decomp,
+                          c[indx[k]+i]+c[indx[j]+k+1]+P->stack[type][type_2]);
+        }
+
+        decomp += 2*P->MLintern[1];        /* no TermAU penalty if coax stack */
+#if 0
+        /* This is needed for Y shaped ML loops with coax stacking of
+           interior pairts, but backtracking will fail if activated */
+        DMLi[j] = MIN2(DMLi[j], decomp);
+        DMLi[j] = MIN2(DMLi[j], DMLi[j-1]+P->MLbase);
+        DMLi[j] = MIN2(DMLi[j], DMLi1[j]+P->MLbase);
+        new_fML = MIN2(new_fML, DMLi[j]);
+#endif
+        new_fML = MIN2(new_fML, decomp);
+      }
+      fML[ij] = Fmi[j] = new_fML;     /* substring energy */
+
+    }
+
+    {
+      int *FF; /* rotate the auxilliary arrays */
+      FF = DMLi2; DMLi2 = DMLi1; DMLi1 = DMLi; DMLi = FF;
+      FF = cc1; cc1=cc; cc=FF;
+      for (j=1; j<=length; j++) {cc[j]=Fmi[j]=DMLi[j]=INF; }
+    }
+  }
+
+  /* calculate energies of 5' and 3' fragments */
+
+  f5[TURN+1]= 0;
+  /* duplicated code may be faster than conditions inside loop ;) */
+  switch(dangle_model){
+    /* dont use dangling end and mismatch contributions at all */
+    case 0:   for(j=TURN+2; j<=length; j++){
+                f5[j] = f5[j-1];
+                for (i=j-TURN-1; i>1; i--){
+
+                  if(with_gquad){
+                    f5[j] = MIN2(f5[j], f5[i-1] + ggg[indx[j]+i]);
+                  }
+
+                  type = ptype[indx[j]+i];
+                  if(!type) continue;
+                  en = c[indx[j]+i];
+                  f5[j] = MIN2(f5[j], f5[i-1] + en + E_ExtLoop(type, -1, -1, P));
+                }
+
+                if(with_gquad){
+                  f5[j] = MIN2(f5[j], ggg[indx[j]+1]);
+                }
+
+                type=ptype[indx[j]+1];
+                if(!type) continue;
+                en = c[indx[j]+1];
+                f5[j] = MIN2(f5[j], en + E_ExtLoop(type, -1, -1, P));
+              }
+              break;
+
+    /* always use dangles on both sides */
+    case 2:   for(j=TURN+2; j<length; j++){
+                f5[j] = f5[j-1];
+                for (i=j-TURN-1; i>1; i--){
+
+                  if(with_gquad){
+                    f5[j] = MIN2(f5[j], f5[i-1] + ggg[indx[j]+i]);
+                  }
+
+                  type = ptype[indx[j]+i];
+                  if(!type) continue;
+                  en = c[indx[j]+i];
+                  f5[j] = MIN2(f5[j], f5[i-1] + en + E_ExtLoop(type, S1[i-1], S1[j+1], P));
+                }
+
+                if(with_gquad){
+                  f5[j] = MIN2(f5[j], ggg[indx[j]+1]);
+                }
+
+                type=ptype[indx[j]+1];
+                if(!type) continue;
+                en = c[indx[j]+1];
+                f5[j] = MIN2(f5[j], en + E_ExtLoop(type, -1, S1[j+1], P));
+              }
+              f5[length] = f5[length-1];
+              for (i=length-TURN-1; i>1; i--){
+
+                if(with_gquad){
+                  f5[length] = MIN2(f5[length], f5[i-1] + ggg[indx[length]+i]);
+                }
+
+                type = ptype[indx[length]+i];
+                if(!type) continue;
+                en = c[indx[length]+i];
+                f5[length] = MIN2(f5[length], f5[i-1] + en + E_ExtLoop(type, S1[i-1], -1, P));
+              }
+
+              if(with_gquad){
+                f5[length] = MIN2(f5[length], ggg[indx[length]+1]);
+              }
+
+              type=ptype[indx[length]+1];
+              if(!type) break;
+              en = c[indx[length]+1];
+              f5[length] = MIN2(f5[length], en + E_ExtLoop(type, -1, -1, P));
+
+
+              break;
+
+    /* normal dangles, aka dangle_model = 1 || 3 */
+    default:  for(j=TURN+2; j<=length; j++){
+                f5[j] = f5[j-1];
+                for (i=j-TURN-1; i>1; i--){
+
+                  if(with_gquad){
+                    f5[j] = MIN2(f5[j], f5[i-1] + ggg[indx[j]+i]);
+                  }
+
+                  type = ptype[indx[j]+i];
+                  if(type){
+                    en = c[indx[j]+i];
+                    f5[j] = MIN2(f5[j], f5[i-1] + en + E_ExtLoop(type, -1, -1, P));
+                    f5[j] = MIN2(f5[j], f5[i-2] + en + E_ExtLoop(type, S1[i-1], -1, P));
+                  }
+                  type = ptype[indx[j-1]+i];
+                  if(type){
+                    en = c[indx[j-1]+i];
+                    f5[j] = MIN2(f5[j], f5[i-1] + en + E_ExtLoop(type, -1, S1[j], P));
+                    f5[j] = MIN2(f5[j], f5[i-2] + en + E_ExtLoop(type, S1[i-1], S1[j], P));
+                  }
+                }
+
+                if(with_gquad){
+                  f5[j] = MIN2(f5[j], ggg[indx[j]+1]);
+                }
+
+                type = ptype[indx[j]+1];
+                if(type) f5[j] = MIN2(f5[j], c[indx[j]+1] + E_ExtLoop(type, -1, -1, P));
+                type = ptype[indx[j-1]+1];
+                if(type) f5[j] = MIN2(f5[j], c[indx[j-1]+1] + E_ExtLoop(type, -1, S1[j], P));
+              }
+  }
+  return f5[length];
+}
+
+#include "circfold.inc"
+
+/**
+*** trace back through the "c", "f5" and "fML" arrays to get the
+*** base pairing list. No search for equivalent structures is done.
+*** This is fast, since only few structure elements are recalculated.
+***
+*** normally s=0.
+*** If s>0 then s items have been already pushed onto the sector stack
+**/
+PRIVATE void backtrack(const char *string, int s) {
+  int   i, j, ij, k, l1, mm5, mm3, length, energy, en, new;
+  int   no_close, type, type_2, tt, minq, maxq, c0, c1, c2, c3;
+  int   bonus;
+  int   b=0;
+  int   dangle_model = P->model_details.dangles;
+
+  length = strlen(string);
+  if (s==0) {
+    sector[++s].i = 1;
+    sector[s].j = length;
+    sector[s].ml = (backtrack_type=='M') ? 1 : ((backtrack_type=='C')? 2: 0);
+  }
+  while (s>0) {
+    int ml, fij, fi, cij, traced, i1, j1, p, q, jj=0, gq=0;
+    int canonical = 1;     /* (i,j) closes a canonical structure */
+    i  = sector[s].i;
+    j  = sector[s].j;
+    ml = sector[s--].ml;   /* ml is a flag indicating if backtracking is to
+                              occur in the fML- (1) or in the f-array (0) */
+    if (ml==2) {
+      base_pair2[++b].i = i;
+      base_pair2[b].j   = j;
+      goto repeat1;
+    }
+
+    else if(ml==7) { /* indicates that i,j are enclosing a gquadruplex */
+      /* actually, do something here */
+    }
+
+    if (j < i+TURN+1) continue; /* no more pairs in this interval */
+
+    fij = (ml == 1)? fML[indx[j]+i] : f5[j];
+    fi  = (ml == 1)?(fML[indx[j-1]+i]+P->MLbase): f5[j-1];
+
+    if (fij == fi) {  /* 3' end is unpaired */
+      sector[++s].i = i;
+      sector[s].j   = j-1;
+      sector[s].ml  = ml;
+      continue;
+    }
+
+    if (ml == 0) { /* backtrack in f5 */
+      switch(dangle_model){
+        case 0:   /* j is paired. Find pairing partner */
+                  for(k=j-TURN-1,traced=0; k>=1; k--){
+
+                    if(with_gquad){
+                      if(fij == f5[k-1] + ggg[indx[j]+k]){
+                        /* found the decomposition */
+                        traced = j; jj = k - 1; gq = 1;
+                        break;
+                      }
+                    }
+
+                    type = ptype[indx[j]+k];
+                    if(type)
+                      if(fij == E_ExtLoop(type, -1, -1, P) + c[indx[j]+k] + f5[k-1]){
+                        traced=j; jj = k-1;
+                        break;
+                      }
+                  }
+                  break;
+
+        case 2:   mm3 = (j<length) ? S1[j+1] : -1;
+                  for(k=j-TURN-1,traced=0; k>=1; k--){
+
+                    if(with_gquad){
+                      if(fij == f5[k-1] + ggg[indx[j]+k]){
+                        /* found the decomposition */
+                        traced = j; jj = k - 1; gq = 1;
+                        break;
+                      }
+                    }
+
+                    type = ptype[indx[j]+k];
+                    if(type)
+                      if(fij == E_ExtLoop(type, (k>1) ? S1[k-1] : -1, mm3, P) + c[indx[j]+k] + f5[k-1]){
+                        traced=j; jj = k-1;
+                        break;
+                      }
+                  }
+                  break;
+
+        default:  for(traced = 0, k=j-TURN-1; k>1; k--){
+
+                    if(with_gquad){
+                      if(fij == f5[k-1] + ggg[indx[j]+k]){
+                        /* found the decomposition */
+                        traced = j; jj = k - 1; gq = 1;
+                        break;
+                      }
+                    }
+
+                    type = ptype[indx[j] + k];
+                    if(type){
+                      en = c[indx[j] + k];
+                      if(fij == f5[k-1] + en + E_ExtLoop(type, -1, -1, P)){
+                        traced = j;
+                        jj = k-1;
+                        break;
+                      }
+                      if(fij == f5[k-2] + en + E_ExtLoop(type, S1[k-1], -1, P)){
+                        traced = j;
+                        jj = k-2;
+                        break;
+                      }
+                    }
+                    type = ptype[indx[j-1] + k];
+                    if(type){
+                      en = c[indx[j-1] + k];
+                      if(fij == f5[k-1] + en + E_ExtLoop(type, -1, S1[j], P)){
+                        traced = j-1;
+                        jj = k-1;
+                        break;
+                      }
+                      if(fij == f5[k-2] + en + E_ExtLoop(type, S1[k-1], S1[j], P)){
+                        traced = j-1;
+                        jj = k-2;
+                        break;
+                      }
+                    }
+                  }
+                  if(!traced){
+
+                    if(with_gquad){
+                      if(fij == ggg[indx[j]+1]){
+                        /* found the decomposition */
+                        traced = j; jj = 0; gq = 1;
+                        break;
+                      }
+                    }
+
+                    type = ptype[indx[j]+1];
+                    if(type){
+                      if(fij == c[indx[j]+1] + E_ExtLoop(type, -1, -1, P)){
+                        traced = j;
+                        jj = 0;
+                        break;
+                      }
+                    }
+                    type = ptype[indx[j-1]+1];
+                    if(type){
+                      if(fij == c[indx[j-1]+1] + E_ExtLoop(type, -1, S1[j], P)){
+                        traced = j-1;
+                        jj = 0;
+                        break;
+                      }
+                    }
+                  }
+                  break;
+      }
+
+      if (!traced){
+        fprintf(stderr, "%s\n", string);
+        nrerror("backtrack failed in f5");
+      }
+      /* push back the remaining f5 portion */
+      sector[++s].i = 1;
+      sector[s].j   = jj;
+      sector[s].ml  = ml;
+
+      /* trace back the base pair found */
+      i=k; j=traced;
+
+      if(with_gquad && gq){
+        /* goto backtrace of gquadruplex */
+        goto repeat_gquad;
+      }
+
+      base_pair2[++b].i = i;
+      base_pair2[b].j   = j;
+      goto repeat1;
+    }
+    else { /* trace back in fML array */
+      if (fML[indx[j]+i+1]+P->MLbase == fij) { /* 5' end is unpaired */
+        sector[++s].i = i+1;
+        sector[s].j   = j;
+        sector[s].ml  = ml;
+        continue;
+      }
+
+      ij  = indx[j]+i;
+
+      if(with_gquad){
+        if(fij == ggg[ij] + E_MLstem(0, -1, -1, P)){
+          /* go to backtracing of quadruplex */
+          goto repeat_gquad;
+        }
+      }
+
+      tt  = ptype[ij];
+      en  = c[ij];
+      switch(dangle_model){
+        case 0:   if(fij == en + E_MLstem(tt, -1, -1, P)){
+                    base_pair2[++b].i = i;
+                    base_pair2[b].j   = j;
+                    goto repeat1;
+                  }
+                  break;
+
+        case 2:   if(fij == en + E_MLstem(tt, S1[i-1], S1[j+1], P)){
+                    base_pair2[++b].i = i;
+                    base_pair2[b].j   = j;
+                    goto repeat1;
+                  }
+                  break;
+
+        default:  if(fij == en + E_MLstem(tt, -1, -1, P)){
+                    base_pair2[++b].i = i;
+                    base_pair2[b].j   = j;
+                    goto repeat1;
+                  }
+                  tt = ptype[ij+1];
+                  if(fij == c[ij+1] + E_MLstem(tt, S1[i], -1, P) + P->MLbase){
+                    base_pair2[++b].i = ++i;
+                    base_pair2[b].j   = j;
+                    goto repeat1;
+                  }
+                  tt = ptype[indx[j-1]+i];
+                  if(fij == c[indx[j-1]+i] + E_MLstem(tt, -1, S1[j], P) + P->MLbase){
+                    base_pair2[++b].i = i;
+                    base_pair2[b].j   = --j;
+                    goto repeat1;
+                  }
+                  tt = ptype[indx[j-1]+i+1];
+                  if(fij == c[indx[j-1]+i+1] + E_MLstem(tt, S1[i], S1[j], P) + 2*P->MLbase){
+                    base_pair2[++b].i = ++i;
+                    base_pair2[b].j   = --j;
+                    goto repeat1;
+                  }
+                  break;
+      }
+
+      for(k = i + 1 + TURN; k <= j - 2 - TURN; k++)
+        if(fij == (fML[indx[k]+i]+fML[indx[j]+k+1]))
+          break;
+
+      if ((dangle_model==3)&&(k > j - 2 - TURN)) { /* must be coax stack */
+        ml = 2;
+        for (k = i+1+TURN; k <= j - 2 - TURN; k++) {
+          type    = rtype[ptype[indx[k]+i]];
+          type_2  = rtype[ptype[indx[j]+k+1]];
+          if (type && type_2)
+            if (fij == c[indx[k]+i]+c[indx[j]+k+1]+P->stack[type][type_2]+
+                       2*P->MLintern[1])
+              break;
+        }
+      }
+      sector[++s].i = i;
+      sector[s].j   = k;
+      sector[s].ml  = ml;
+      sector[++s].i = k+1;
+      sector[s].j   = j;
+      sector[s].ml  = ml;
+
+      if (k>j-2-TURN) nrerror("backtrack failed in fML");
+      continue;
+    }
+
+  repeat1:
+
+    /*----- begin of "repeat:" -----*/
+    ij = indx[j]+i;
+    if (canonical)  cij = c[ij];
+
+    type = ptype[ij];
+
+    bonus = 0;
+    if (struct_constrained) {
+      if ((BP[i]==j)||(BP[i]==-1)||(BP[i]==-2)) bonus -= BONUS;
+      if ((BP[j]==-1)||(BP[j]==-3)) bonus -= BONUS;
+    }
+    if (noLonelyPairs)
+      if (cij == c[ij]){
+        /* (i.j) closes canonical structures, thus
+           (i+1.j-1) must be a pair                */
+        type_2 = ptype[indx[j-1]+i+1]; type_2 = rtype[type_2];
+        cij -= P->stack[type][type_2] + bonus;
+        base_pair2[++b].i = i+1;
+        base_pair2[b].j   = j-1;
+        i++; j--;
+        canonical=0;
+        goto repeat1;
+      }
+    canonical = 1;
+
+
+    no_close = (((type==3)||(type==4))&&no_closingGU&&(bonus==0));
+    if (no_close) {
+      if (cij == FORBIDDEN) continue;
+    } else
+      if (cij == E_Hairpin(j-i-1, type, S1[i+1], S1[j-1],string+i-1, P)+bonus)
+        continue;
+
+    for (p = i+1; p <= MIN2(j-2-TURN,i+MAXLOOP+1); p++) {
+      minq = j-i+p-MAXLOOP-2;
+      if (minq<p+1+TURN) minq = p+1+TURN;
+      for (q = j-1; q >= minq; q--) {
+
+        type_2 = ptype[indx[q]+p];
+        if (type_2==0) continue;
+        type_2 = rtype[type_2];
+        if (no_closingGU)
+          if (no_close||(type_2==3)||(type_2==4))
+            if ((p>i+1)||(q<j-1)) continue;  /* continue unless stack */
+
+        /* energy = oldLoopEnergy(i, j, p, q, type, type_2); */
+        energy = E_IntLoop(p-i-1, j-q-1, type, type_2,
+                            S1[i+1], S1[j-1], S1[p-1], S1[q+1], P);
+
+        new = energy+c[indx[q]+p]+bonus;
+        traced = (cij == new);
+        if (traced) {
+          base_pair2[++b].i = p;
+          base_pair2[b].j   = q;
+          i = p, j = q;
+          goto repeat1;
+        }
+      }
+    }
+
+    /* end of repeat: --------------------------------------------------*/
+
+    /* (i.j) must close a multi-loop */
+    tt = rtype[type];
+    i1 = i+1; j1 = j-1;
+
+    if(with_gquad){
+      /*
+        The case that is handled here actually resembles something like
+        an interior loop where the enclosing base pair is of regular
+        kind and the enclosed pair is not a canonical one but a g-quadruplex
+        that should then be decomposed further...
+      */
+      if(backtrack_GQuad_IntLoop(cij, i, j, type, S, ggg, indx, &p, &q, P)){
+        i = p; j = q;
+        goto repeat_gquad;
+      }
+    }
+
+    sector[s+1].ml  = sector[s+2].ml = 1;
+
+    switch(dangle_model){
+      case 0:   en = cij - E_MLstem(tt, -1, -1, P) - P->MLclosing - bonus;
+                for(k = i+2+TURN; k < j-2-TURN; k++){
+                  if(en == fML[indx[k]+i+1] + fML[indx[j-1]+k+1])
+                    break;
+                }
+                break;
+
+      case 2:   en = cij - E_MLstem(tt, S1[j-1], S1[i+1], P) - P->MLclosing - bonus;
+                for(k = i+2+TURN; k < j-2-TURN; k++){
+                    if(en == fML[indx[k]+i+1] + fML[indx[j-1]+k+1])
+                      break;
+                }
+                break;
+
+      default:  for(k = i+2+TURN; k < j-2-TURN; k++){
+                  en = cij - P->MLclosing - bonus;
+                  if(en == fML[indx[k]+i+1] + fML[indx[j-1]+k+1] + E_MLstem(tt, -1, -1, P)){
+                    break;
+                  }
+                  else if(en == fML[indx[k]+i+2] + fML[indx[j-1]+k+1] + E_MLstem(tt, -1, S1[i+1], P) + P->MLbase){
+                    i1 = i+2;
+                    break;
+                  }
+                  else if(en == fML[indx[k]+i+1] + fML[indx[j-2]+k+1] + E_MLstem(tt, S1[j-1], -1, P) + P->MLbase){
+                    j1 = j-2;
+                    break;
+                  }
+                  else if(en == fML[indx[k]+i+2] + fML[indx[j-2]+k+1] + E_MLstem(tt, S1[j-1], S1[i+1], P) + 2*P->MLbase){
+                    i1 = i+2;
+                    j1 = j-2;
+                    break;
+                  }
+                  /* coaxial stacking of (i.j) with (i+1.k) or (k.j-1) */
+                  /* use MLintern[1] since coax stacked pairs don't get TerminalAU */
+                  if(dangle_model == 3){
+                    type_2 = rtype[ptype[indx[k]+i+1]];
+                    if (type_2) {
+                      en = c[indx[k]+i+1]+P->stack[type][type_2]+fML[indx[j-1]+k+1];
+                      if (cij == en+2*P->MLintern[1]+P->MLclosing) {
+                        ml = 2;
+                        sector[s+1].ml  = 2;
+                        traced = 1;
+                        break;
+                      }
+                    }
+                    type_2 = rtype[ptype[indx[j-1]+k+1]];
+                    if (type_2) {
+                      en = c[indx[j-1]+k+1]+P->stack[type][type_2]+fML[indx[k]+i+1];
+                      if (cij == en+2*P->MLintern[1]+P->MLclosing) {
+                        sector[s+2].ml = 2;
+                        traced = 1;
+                        break;
+                      }
+                    }
+                  }
+                }
+                break;
+    }
+
+    if (k<=j-3-TURN) { /* found the decomposition */
+      sector[++s].i = i1;
+      sector[s].j   = k;
+      sector[++s].i = k+1;
+      sector[s].j   = j1;
+    } else {
+#if 0
+      /* Y shaped ML loops fon't work yet */
+      if (dangle_model==3) {
+        d5 = P->dangle5[tt][S1[j-1]];
+        d3 = P->dangle3[tt][S1[i+1]];
+        /* (i,j) must close a Y shaped ML loop with coax stacking */
+        if (cij ==  fML[indx[j-2]+i+2] + mm + d3 + d5 + P->MLbase + P->MLbase) {
+          i1 = i+2;
+          j1 = j-2;
+        } else if (cij ==  fML[indx[j-2]+i+1] + mm + d5 + P->MLbase)
+          j1 = j-2;
+        else if (cij ==  fML[indx[j-1]+i+2] + mm + d3 + P->MLbase)
+          i1 = i+2;
+        else /* last chance */
+          if (cij != fML[indx[j-1]+i+1] + mm + P->MLbase)
+            fprintf(stderr,  "backtracking failed in repeat");
+        /* if we arrive here we can express cij via fML[i1,j1]+dangles */
+        sector[++s].i = i1;
+        sector[s].j   = j1;
+      }
+      else
+#endif
+        nrerror("backtracking failed in repeat");
+    }
+
+    continue; /* this is a workarround to not accidentally proceed in the following block */
+
+  repeat_gquad:
+    /*
+      now we do some fancy stuff to backtrace the stacksize and linker lengths
+      of the g-quadruplex that should reside within position i,j
+    */
+    {
+      int l[3], L, a;
+      L = -1;
+      
+      get_gquad_pattern_mfe(S, i, j, P, &L, l);
+      if(L != -1){
+        /* fill the G's of the quadruplex into base_pair2 */
+        for(a=0;a<L;a++){
+          base_pair2[++b].i = i+a;
+          base_pair2[b].j   = i+a;
+          base_pair2[++b].i = i+L+l[0]+a;
+          base_pair2[b].j   = i+L+l[0]+a;
+          base_pair2[++b].i = i+L+l[0]+L+l[1]+a;
+          base_pair2[b].j   = i+L+l[0]+L+l[1]+a;
+          base_pair2[++b].i = i+L+l[0]+L+l[1]+L+l[2]+a;
+          base_pair2[b].j   = i+L+l[0]+L+l[1]+L+l[2]+a;
+        }
+        goto repeat_gquad_exit;
+      }
+      nrerror("backtracking failed in repeat_gquad");
+    }
+  repeat_gquad_exit:
+    asm("nop");
+
+  } /* end of infinite while loop */
+
+  base_pair2[0].i = b;    /* save the total number of base pairs */
+}
+
+PUBLIC char *backtrack_fold_from_pair(char *sequence, int i, int j) {
+  char *structure;
+  sector[1].i  = i;
+  sector[1].j  = j;
+  sector[1].ml = 2;
+  base_pair2[0].i=0;
+  S   = encode_sequence(sequence, 0);
+  S1  = encode_sequence(sequence, 1);
+  backtrack(sequence, 1);
+  structure = (char *) space((strlen(sequence)+1)*sizeof(char));
+  parenthesis_structure(structure, base_pair2, strlen(sequence));
+  free(S);free(S1);
+  return structure;
+}
+
+/*---------------------------------------------------------------------------*/
+
+PUBLIC void letter_structure(char *structure, bondT *bp, int length){
+  int   n, k, x, y;
+  char  alpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+  for (n = 0; n < length; structure[n++] = ' ');
+  structure[length] = '\0';
+
+  for (n = 0, k = 1; k <= bp[0].i; k++) {
+    y = bp[k].j;
+    x = bp[k].i;
+    if (x-1 > 0 && y+1 <= length) {
+      if (structure[x-2] != ' ' && structure[y] == structure[x-2]) {
+        structure[x-1] = structure[x-2];
+        structure[y-1] = structure[x-1];
+        continue;
+      }
+    }
+    if (structure[x] != ' ' && structure[y-2] == structure[x]) {
+      structure[x-1] = structure[x];
+      structure[y-1] = structure[x-1];
+      continue;
+    }
+    n++;
+    structure[x-1] = alpha[n-1];
+    structure[y-1] = alpha[n-1];
+  }
+}
+
+/*---------------------------------------------------------------------------*/
+
+PUBLIC void parenthesis_structure(char *structure, bondT *bp, int length){
+  int n, k;
+
+  for (n = 0; n < length; structure[n++] = '.');
+  structure[length] = '\0';
+
+  for (k = 1; k <= bp[0].i; k++){
+
+    if(bp[k].i == bp[k].j){ /* Gquad bonds are marked as bp[i].i == bp[i].j */
+      structure[bp[k].i-1] = '+';
+    } else { /* the following ones are regular base pairs */
+      structure[bp[k].i-1] = '(';
+      structure[bp[k].j-1] = ')';
+    }
+  }
+}
+
+PUBLIC void parenthesis_zuker(char *structure, bondT *bp, int length){
+  int k, i, j, temp;
+
+  for (k = 0; k < length; structure[k++] = '.');
+  structure[length] = '\0';
+
+  for (k = 1; k <= bp[0].i; k++) {
+    i=bp[k].i;
+    j=bp[k].j;
+    if (i>length) i-=length;
+    if (j>length) j-=length;
+    if (i>j) {
+      temp=i; i=j; j=temp;
+    }
+    if(i == j){ /* Gquad bonds are marked as bp[i].i == bp[i].j */
+      structure[i-1] = '+';
+    } else { /* the following ones are regular base pairs */
+      structure[i-1] = '(';
+      structure[j-1] = ')';
+    }
+  }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+PUBLIC void update_fold_params(void){
+  update_fold_params_par(NULL);
+}
+
+PUBLIC void update_fold_params_par(paramT *parameters){
+  if(P) free(P);
+  if(parameters){
+    P = get_parameter_copy(parameters);
+  } else {
+    model_detailsT md;
+    set_model_details(&md);
+    P = get_scaled_parameters(temperature, md);
+  }
+  make_pair_matrix();
+  if (init_length < 0) init_length=0;
+}
+
+/*---------------------------------------------------------------------------*/
+PUBLIC float energy_of_structure(const char *string, const char *structure, int verbosity_level){
+  return energy_of_struct_par(string, structure, NULL, verbosity_level);
+}
+
+PUBLIC float energy_of_struct_par(const char *string,
+                                  const char *structure,
+                                  paramT *parameters,
+                                  int verbosity_level){
+  int   energy;
+  short *ss, *ss1;
+
+  update_fold_params_par(parameters);
+
+  if (strlen(structure)!=strlen(string))
+    nrerror("energy_of_struct: string and structure have unequal length");
+
+  /* save the S and S1 pointers in case they were already in use */
+  ss = S; ss1 = S1;
+  S   = encode_sequence(string, 0);
+  S1  = encode_sequence(string, 1);
+
+  pair_table = make_pair_table(structure);
+
+  energy = energy_of_structure_pt(string, pair_table, S, S1, verbosity_level);
+
+  free(pair_table);
+  free(S); free(S1);
+  S=ss; S1=ss1;
+  return  (float) energy/100.;
+}
+
+/*  returns a correction term that may be added to the energy retrieved
+    from energy_of_struct_par() to correct misinterpreted loops. This
+    correction is necessary since energy_of_struct_par() will forget 
+    about the existance of gquadruplexes and just treat them as unpaired
+    regions.
+
+    recursive variant
+*/
+PRIVATE int en_corr_of_loop_gquad(int i,
+                                  int j,
+                                  const char *string,
+                                  const char *structure,
+                                  short *pt,
+                                  int *loop_idx,
+                                  const short *s1){
+
+  int pos, energy, p, q, r, s, u, type, type2;
+  int L, l[3];
+
+  energy = 0;
+  q = i;
+  while((pos = parse_gquad(structure + q-1, &L, l)) > 0){
+    q += pos-1;
+    p = q - 4*L - l[0] - l[1] - l[2] + 1;
+    if(q > j) break;
+    /* we've found the first g-quadruplex at position [p,q] */
+    energy += E_gquad(L, l, P);
+    /* check if it's enclosed in a base pair */
+    if(loop_idx[p] == 0){ q++; continue; /* g-quad in exterior loop */}
+    else{
+      energy += E_MLstem(0, -1, -1, P);
+      /*  find its enclosing pair */
+      int num_elem, num_g, elem_i, elem_j, up_mis;
+      num_elem  = 0;
+      num_g     = 1;
+      r         = p - 1;
+      up_mis    = q - p + 1;
+
+      /* seek for first pairing base located 5' of the g-quad */
+      for(r = p - 1; !pt[r] && (r >= i); r--);
+      if(r < i) nrerror("this should not happen");
+
+      if(r < pt[r]){ /* found the enclosing pair */
+        s = pt[r];
+      } else {
+        num_elem++;
+        elem_i = pt[r];
+        elem_j = r;
+        r = pt[r]-1 ;
+        /* seek for next pairing base 5' of r */
+        for(; !pt[r] && (r >= i); r--);
+        if(r < i) nrerror("so nich");
+        if(r < pt[r]){ /* found the enclosing pair */
+          s = pt[r];
+        } else {
+          /* hop over stems and unpaired nucleotides */
+          while((r > pt[r]) && (r >= i)){
+            if(pt[r]){ r = pt[r]; num_elem++;}
+            r--;
+          }
+          if(r < i) nrerror("so nich");
+          s = pt[r]; /* found the enclosing pair */
+        }
+      }
+      /* now we have the enclosing pair (r,s) */
+
+      u = q+1;
+      /* we know everything about the 5' part of this loop so check the 3' part */
+      while(u<s){
+        if(structure[u-1] == '.') u++;
+        else if (structure[u-1] == '+'){ /* found another gquad */
+          pos = parse_gquad(structure + u - 1, &L, l);
+          if(pos > 0){
+            energy += E_gquad(L, l, P) + E_MLstem(0, -1, -1, P);
+            up_mis += pos;
+            u += pos;
+            num_g++;
+          }
+        } else { /* we must have found a stem */
+          if(!(u < pt[u])) nrerror("wtf!");
+          num_elem++; elem_i = u; elem_j = pt[u];
+          energy += en_corr_of_loop_gquad(u, pt[u], string, structure, pt, loop_idx, s1);
+          u = pt[u] + 1;
+        }
+      }
+      if(u!=s) nrerror("what the hell");
+      else{ /* we are done since we've found no other 3' structure element */
+        switch(num_elem){
+          /* g-quad was misinterpreted as hairpin closed by (r,s) */
+          case 0:   /* if(num_g == 1)
+                      if((p-r-1 == 0) || (s-q-1 == 0))
+                        nrerror("too few unpaired bases");
+                    */
+                    type = pair[s1[r]][s1[s]];
+                    if(dangles == 2)
+                      energy += P->mismatchI[type][s1[r+1]][s1[s-1]];
+                    if(type > 2)
+                      energy += P->TerminalAU;
+                    energy += P->internal_loop[s - r - 1 - up_mis];
+                    energy -= E_Hairpin(s - r - 1,
+                                        type,
+                                        s1[r + 1],
+                                        s1[s - 1],
+                                        string + r - 1,
+                                        P);
+                    break;
+          /* g-quad was misinterpreted as interior loop closed by (r,s) with enclosed pair (elem_i, elem_j) */
+          case 1:   type = pair[s1[r]][s1[s]];
+                    type2 = pair[s1[elem_i]][s1[elem_j]];
+                    energy += P->MLclosing
+                              + E_MLstem(rtype[type], s1[s-1], s1[r+1], P)
+                              + (elem_i - r - 1 + s - elem_j - 1 - up_mis) * P->MLbase
+                              + E_MLstem(type2, s1[elem_i-1], s1[elem_j+1], P);
+                    energy -= E_IntLoop(elem_i - r - 1,
+                                        s - elem_j - 1,
+                                        type,
+                                        rtype[type2],
+                                        s1[r + 1],
+                                        s1[s - 1],
+                                        s1[elem_i - 1],
+                                        s1[elem_j + 1],
+                                        P);
+                    break;
+          /* gquad was misinterpreted as unpaired nucleotides in a multiloop */
+          default:  energy -= (up_mis) * P->MLbase;
+                    break;
+        }
+      }
+      q = s+1;
+    }
+  }
+  return energy;
+}
+
+PUBLIC float energy_of_gquad_structure( const char *string,
+                                        const char *structure,
+                                        int verbosity_level){
+
+  int   energy, gge, *loop_idx;
+  short *ss, *ss1;
+
+#ifdef _OPENMP
+  if(P == NULL) update_fold_params();
+#else
+  if((init_length<0)||(P==NULL)) update_fold_params();
+#endif
+
+  if (fabs(P->temperature - temperature)>1e-6) update_fold_params();
+
+  if (strlen(structure)!=strlen(string))
+    nrerror("energy_of_struct: string and structure have unequal length");
+
+  /* save the S and S1 pointers in case they were already in use */
+  ss = S; ss1 = S1;
+  S   = encode_sequence(string, 0);
+  S1  = encode_sequence(string, 1);
+
+  /* the pair_table looses every information about the gquad position
+     thus we have to find add the energy contributions for each loop
+     that contains a gquad by ourself, substract all miscalculated
+     contributions, i.e. loops that actually contain a gquad, from
+     energy_of_structure_pt()
+  */
+  pair_table  = make_pair_table(structure);
+  energy      = energy_of_structure_pt(string, pair_table, S, S1, verbosity_level);
+
+  loop_idx    = make_loop_index_pt(pair_table);
+  gge         = en_corr_of_loop_gquad(1, S[0], string, structure, pair_table, loop_idx, S1);
+  energy     += gge;
+
+  free(pair_table);
+  free(loop_idx);
+  free(S); free(S1);
+  S=ss; S1=ss1;
+  return  (float) energy/100.;
+}
+
+PUBLIC int energy_of_structure_pt(const char *string,
+                                  short *ptable,
+                                  short *s,
+                                  short *s1,
+                                  int verbosity_level){
+  return energy_of_struct_pt_par(string, ptable, s, s1, NULL, verbosity_level);
+}
+
+PUBLIC int energy_of_struct_pt_par( const char *string,
+                                    short *ptable,
+                                    short *s,
+                                    short *s1,
+                                    paramT *parameters,
+                                    int verbosity_level){
+  /* auxiliary function for kinfold,
+     for most purposes call energy_of_struct instead */
+
+  int   i, length, energy;
+  short *ss, *ss1;
+
+  update_fold_params_par(parameters);
+
+  pair_table = ptable;
+  ss  = S;
+  ss1 = S1;
+  S = s;
+  S1 = s1;
+
+  length = S[0];
+/*   energy =  backtrack_type=='M' ? ML_Energy(0, 0) : ML_Energy(0, 1); */
+    energy =  backtrack_type=='M' ? energy_of_ml_pt(0, ptable) : energy_of_extLoop_pt(0, ptable);
+  if (verbosity_level>0)
+    printf("External loop                           : %5d\n", energy);
+  for (i=1; i<=length; i++) {
+    if (pair_table[i]==0) continue;
+    energy += stack_energy(i, string, verbosity_level);
+    i=pair_table[i];
+  }
+  for (i=1; !SAME_STRAND(i,length); i++) {
+    if (!SAME_STRAND(i,pair_table[i])) {
+      energy+=P->DuplexInit;
+      break;
+    }
+  }
+  S   = ss;
+  S1  = ss1;
+  return energy;
+}
+
+PUBLIC float energy_of_circ_structure(const char *string,
+                                      const char *structure,
+                                      int verbosity_level){
+  return energy_of_circ_struct_par(string, structure, NULL, verbosity_level);
+}
+
+PUBLIC float energy_of_circ_struct_par( const char *string,
+                                        const char *structure,
+                                        paramT *parameters,
+                                        int verbosity_level){
+
+  int   i, j, length, energy=0, en0, degree=0, type;
+  short *ss, *ss1;
+
+  update_fold_params_par(parameters);
+
+  int dangle_model = P->model_details.dangles;
+
+  if (strlen(structure)!=strlen(string))
+    nrerror("energy_of_struct: string and structure have unequal length");
+
+  /* save the S and S1 pointers in case they were already in use */
+  ss = S; ss1 = S1;
+  S   = encode_sequence(string, 0);
+  S1  = encode_sequence(string, 1);
+
+  pair_table = make_pair_table(structure);
+
+  length = S[0];
+
+  for (i=1; i<=length; i++) {
+    if (pair_table[i]==0) continue;
+    degree++;
+    energy += stack_energy(i, string, verbosity_level);
+    i=pair_table[i];
+  }
+
+  if (degree==0) return 0.;
+  for (i=1; pair_table[i]==0; i++);
+  j = pair_table[i];
+  type=pair[S[j]][S[i]];
+  if (type==0) type=7;
+  if (degree==1) {
+    char loopseq[10];
+    int u, si1, sj1;
+    for (i=1; pair_table[i]==0; i++);
+    u = length-j + i-1;
+    if (u<7) {
+      strcpy(loopseq , string+j-1);
+      strncat(loopseq, string, i);
+    }
+    si1 = (i==1)?S1[length] : S1[i-1];
+    sj1 = (j==length)?S1[1] : S1[j+1];
+    en0 = E_Hairpin(u, type, sj1, si1, loopseq, P);
+  } else
+    if (degree==2) {
+      int p,q, u1,u2, si1, sq1, type_2;
+      for (p=j+1; pair_table[p]==0; p++);
+      q=pair_table[p];
+      u1 = p-j-1;
+      u2 = i-1 + length-q;
+      type_2 = pair[S[q]][S[p]];
+      if (type_2==0) type_2=7;
+      si1 = (i==1)? S1[length] : S1[i-1];
+      sq1 = (q==length)? S1[1] : S1[q+1];
+      en0 = E_IntLoop(u1, u2, type, type_2,
+                       S1[j+1], si1, S1[p-1], sq1,P);
+    } else { /* degree > 2 */
+      en0 = ML_Energy(0, 0) - P->MLintern[0];
+      if (dangle_model) {
+        int d5, d3;
+        if (pair_table[1]) {
+          j = pair_table[1];
+          type = pair[S[1]][S[j]];
+          if (dangle_model==2)
+            en0 += P->dangle5[type][S1[length]];
+          else { /* dangle_model==1 */
+            if (pair_table[length]==0) {
+              d5 = P->dangle5[type][S1[length]];
+              if (pair_table[length-1]!=0) {
+                int tt;
+                tt = pair[S[pair_table[length-1]]][S[length-1]];
+                d3 = P->dangle3[tt][S1[length]];
+                if (d3<d5) d5 = 0;
+                else d5 -= d3;
+              }
+              en0 += d5;
+            }
+          }
+        }
+        if (pair_table[length]) {
+          i = pair_table[length];
+          type = pair[S[i]][S[length]];
+          if (dangle_model==2)
+            en0 += P->dangle3[type][S1[1]];
+          else { /* dangle_model==1 */
+            if (pair_table[1]==0) {
+              d3 = P->dangle3[type][S1[1]];
+              if (pair_table[2]) {
+                int tt;
+                tt = pair[S[2]][S[pair_table[2]]];
+                d5 = P->dangle5[tt][1];
+                if (d5<d3) d3=0;
+                else d3 -= d5;
+              }
+              en0 += d3;
+            }
+          }
+        }
+      }
+    }
+
+  if (verbosity_level>0)
+    printf("External loop                           : %5d\n", en0);
+  energy += en0;
+  /* fprintf(stderr, "ext loop degree %d tot %d\n", degree, energy); */
+  free(S); free(S1);
+  S=ss; S1=ss1;
+  return  (float) energy/100.0;
+}
+
+/*---------------------------------------------------------------------------*/
+PRIVATE int stack_energy(int i, const char *string, int verbosity_level)
+{
+  /* calculate energy of substructure enclosed by (i,j) */
+  int ee, energy = 0;
+  int j, p, q, type;
+
+  j=pair_table[i];
+  type = pair[S[i]][S[j]];
+  if (type==0) {
+    type=7;
+    if (verbosity_level>=0)
+      fprintf(stderr,"WARNING: bases %d and %d (%c%c) can't pair!\n", i, j,
+              string[i-1],string[j-1]);
+  }
+
+  p=i; q=j;
+  while (p<q) { /* process all stacks and interior loops */
+    int type_2;
+    while (pair_table[++p]==0);
+    while (pair_table[--q]==0);
+    if ((pair_table[q]!=(short)p)||(p>q)) break;
+    type_2 = pair[S[q]][S[p]];
+    if (type_2==0) {
+      type_2=7;
+      if (verbosity_level>=0)
+        fprintf(stderr,"WARNING: bases %d and %d (%c%c) can't pair!\n", p, q,
+                string[p-1],string[q-1]);
+    }
+    /* energy += LoopEnergy(i, j, p, q, type, type_2); */
+    if ( SAME_STRAND(i,p) && SAME_STRAND(q,j) )
+      ee = E_IntLoop(p-i-1, j-q-1, type, type_2, S1[i+1], S1[j-1], S1[p-1], S1[q+1],P);
+    else
+      ee = energy_of_extLoop_pt(cut_in_loop(i), pair_table);
+    if (verbosity_level>0)
+      printf("Interior loop (%3d,%3d) %c%c; (%3d,%3d) %c%c: %5d\n",
+             i,j,string[i-1],string[j-1],p,q,string[p-1],string[q-1], ee);
+    energy += ee;
+    i=p; j=q; type = rtype[type_2];
+  } /* end while */
+
+  /* p,q don't pair must have found hairpin or multiloop */
+
+  if (p>q) {                       /* hair pin */
+    if (SAME_STRAND(i,j))
+      ee = E_Hairpin(j-i-1, type, S1[i+1], S1[j-1], string+i-1, P);
+    else
+      ee = energy_of_extLoop_pt(cut_in_loop(i), pair_table);
+    energy += ee;
+    if (verbosity_level>0)
+      printf("Hairpin  loop (%3d,%3d) %c%c              : %5d\n",
+             i, j, string[i-1],string[j-1], ee);
+
+    return energy;
+  }
+
+  /* (i,j) is exterior pair of multiloop */
+  while (p<j) {
+    /* add up the contributions of the substructures of the ML */
+    energy += stack_energy(p, string, verbosity_level);
+    p = pair_table[p];
+    /* search for next base pair in multiloop */
+    while (pair_table[++p]==0);
+  }
+  {
+    int ii;
+    ii = cut_in_loop(i);
+    ee = (ii==0) ? energy_of_ml_pt(i, pair_table) : energy_of_extLoop_pt(ii, pair_table);
+  }
+  energy += ee;
+  if (verbosity_level>0)
+    printf("Multi    loop (%3d,%3d) %c%c              : %5d\n",
+           i,j,string[i-1],string[j-1],ee);
+
+  return energy;
+}
+
+/*---------------------------------------------------------------------------*/
+
+
+
+/**
+*** Calculate the energy contribution of
+*** stabilizing dangling-ends/mismatches
+*** for all stems branching off the exterior
+*** loop
+**/
+PRIVATE int energy_of_extLoop_pt(int i, short *pair_table) {
+  int energy, mm5, mm3;
+  int p, q, q_prev;
+  int length = (int)pair_table[0];
+
+  /* helper variables for dangles == 1 case */
+  int E3_available;  /* energy of 5' part where 5' mismatch is available for current stem */
+  int E3_occupied;   /* energy of 5' part where 5' mismatch is unavailable for current stem */
+
+  int dangle_model = P->model_details.dangles;
+
+  /* initialize vars */
+  energy      = 0;
+  p           = (i==0) ? 1 : i;
+  q_prev      = -1;
+
+  if(dangle_model%2 == 1){
+    E3_available = INF;
+    E3_occupied  = 0;
+  }
+
+  /* seek to opening base of first stem */
+  while(p <= length && !pair_table[p]) p++;
+
+  while(p < length){
+    int tt;
+    /* p must have a pairing partner */
+    q  = (int)pair_table[p];
+    /* get type of base pair (p,q) */
+    tt = pair[S[p]][S[q]];
+    if(tt==0) tt=7;
+
+    switch(dangle_model){
+      /* no dangles */
+      case 0:   energy += E_ExtLoop(tt, -1, -1, P);
+                break;
+      /* the beloved double dangles */
+      case 2:   mm5 = ((SAME_STRAND(p-1,p)) && (p>1))       ? S1[p-1] : -1;
+                mm3 = ((SAME_STRAND(q,q+1)) && (q<length))  ? S1[q+1] : -1;
+                energy += E_ExtLoop(tt, mm5, mm3, P);
+                break;
+
+      default:  {
+                  int tmp;
+                  if(q_prev + 2 < p){
+                    E3_available = MIN2(E3_available, E3_occupied);
+                    E3_occupied  = E3_available;
+                  }
+                  mm5 = ((SAME_STRAND(p-1,p)) && (p>1) && !pair_table[p-1])       ? S1[p-1] : -1;
+                  mm3 = ((SAME_STRAND(q,q+1)) && (q<length) && !pair_table[q+1])  ? S1[q+1] : -1;
+                  tmp = MIN2(
+                                                E3_occupied  + E_ExtLoop(tt, -1, mm3, P),
+                                                E3_available + E_ExtLoop(tt, mm5, mm3, P)
+                                              );
+                  E3_available =       MIN2(
+                                                E3_occupied  + E_ExtLoop(tt, -1, -1, P),
+                                                E3_available + E_ExtLoop(tt, mm5, -1, P)
+                                              );
+                  E3_occupied = tmp;
+                }
+                break;
+
+    } /* end switch dangle_model */
+    /* seek to the next stem */
+    p = q + 1;
+    q_prev = q;
+    while (p <= length && !pair_table[p]) p++;
+    if(p==i) break; /* cut was in loop */
+  }
+
+  if(dangle_model%2 == 1)
+    energy = MIN2(E3_occupied, E3_available);
+
+  return energy;
+}
+
+/**
+*** i is the 5'-base of the closing pair
+***
+*** since each helix can coaxially stack with at most one of its
+*** neighbors we need an auxiliarry variable  cx_energy
+*** which contains the best energy given that the last two pairs stack.
+*** energy  holds the best energy given the previous two pairs do not
+*** stack (i.e. the two current helices may stack)
+*** We don't allow the last helix to stack with the first, thus we have to
+*** walk around the Loop twice with two starting points and take the minimum
+***/
+PRIVATE int energy_of_ml_pt(int i, short *pt){
+
+  int energy, cx_energy, tmp, tmp2, best_energy=INF;
+  int i1, j, p, q, q_prev, q_prev2, u, x, type, count, mm5, mm3, tt, ld5, new_cx, dang5, dang3, dang;
+  int mlintern[NBPAIRS+1];
+
+  /* helper variables for dangles == 1|5 case */
+  int E_mm5_available;  /* energy of 5' part where 5' mismatch of current stem is available */
+  int E_mm5_occupied;   /* energy of 5' part where 5' mismatch of current stem is unavailable */
+  int E2_mm5_available; /* energy of 5' part where 5' mismatch of current stem is available with possible 3' dangle for enclosing pair (i,j) */
+  int E2_mm5_occupied;  /* energy of 5' part where 5' mismatch of current stem is unavailable with possible 3' dangle for enclosing pair (i,j) */
+  int dangle_model = P->model_details.dangles;
+
+  if(i >= pt[i])
+    nrerror("energy_of_ml_pt: i is not 5' base of a closing pair!");
+
+  j = (int)pt[i];
+
+  /* init the variables */
+  energy      = 0;
+  p           = i+1;
+  q_prev      = i-1;
+  q_prev2     = i;
+
+  for (x = 0; x <= NBPAIRS; x++) mlintern[x] = P->MLintern[x];
+
+  /* seek to opening base of first stem */
+  while(p <= j && !pair_table[p]) p++;
+  u = p - i - 1;
+
+  switch(dangle_model){
+    case 0:   while(p < j){
+                /* p must have a pairing partner */
+                q  = (int)pair_table[p];
+                /* get type of base pair (p,q) */
+                tt = pair[S[p]][S[q]];
+                if(tt==0) tt=7;
+                energy += E_MLstem(tt, -1, -1, P);
+                /* seek to the next stem */
+                p = q + 1;
+                q_prev = q_prev2 = q;
+                while (p <= j && !pair_table[p]) p++;
+                u += p - q - 1; /* add unpaired nucleotides */
+              }
+              /* now lets get the energy of the enclosing stem */
+              type = pair[S[j]][S[i]]; if (type==0) type=7;
+              energy += E_MLstem(type, -1, -1, P);
+              break;
+
+    case 2:   while(p < j){
+                /* p must have a pairing partner */
+                q  = (int)pair_table[p];
+                /* get type of base pair (p,q) */
+                tt = pair[S[p]][S[q]];
+                if(tt==0) tt=7;
+                mm5 = (SAME_STRAND(p-1,p))  ? S1[p-1] : -1;
+                mm3 = (SAME_STRAND(q,q+1))  ? S1[q+1] : -1;
+                energy += E_MLstem(tt, mm5, mm3, P);
+                /* seek to the next stem */
+                p = q + 1;
+                q_prev = q_prev2 = q;
+                while (p <= j && !pair_table[p]) p++;
+                u += p - q - 1; /* add unpaired nucleotides */
+              }
+              type = pair[S[j]][S[i]]; if (type==0) type=7;
+              mm5 = ((SAME_STRAND(j-1,j)) && !pair_table[j-1])  ? S1[j-1] : -1;
+              mm3 = ((SAME_STRAND(i,i+1)) && !pair_table[i+1])  ? S1[i+1] : -1;
+              energy += E_MLstem(type, S1[j-1], S1[i+1], P);
+              break;
+
+    case 3:   /* we treat helix stacking different */
+              for (count=0; count<2; count++) { /* do it twice */
+                ld5 = 0; /* 5' dangle energy on prev pair (type) */
+                if ( i==0 ) {
+                  j = (unsigned int)pair_table[0]+1;
+                  type = 0;  /* no pair */
+                }
+                else {
+                  j = (unsigned int)pair_table[i];
+                  type = pair[S[j]][S[i]]; if (type==0) type=7;
+                  /* prime the ld5 variable */
+                  if (SAME_STRAND(j-1,j)) {
+                    ld5 = P->dangle5[type][S1[j-1]];
+                    if ((p=(unsigned int)pair_table[j-2]) && SAME_STRAND(j-2, j-1))
+                    if (P->dangle3[pair[S[p]][S[j-2]]][S1[j-1]]<ld5) ld5 = 0;
+                  }
+                }
+                i1=i; p = i+1; u=0;
+                energy = 0; cx_energy=INF;
+                do { /* walk around the multi-loop */
+                  new_cx = INF;
+
+                  /* hop over unpaired positions */
+                  while (p <= (unsigned int)pair_table[0] && pair_table[p]==0) p++;
+
+                  /* memorize number of unpaired positions */
+                  u += p-i1-1;
+                  /* get position of pairing partner */
+                  if ( p == (unsigned int)pair_table[0]+1 ){
+                    q = 0;tt = 0; /* virtual root pair */
+                  } else {
+                    q  = (unsigned int)pair_table[p];
+                    /* get type of base pair P->q */
+                    tt = pair[S[p]][S[q]]; if (tt==0) tt=7;
+                  }
+
+                  energy += mlintern[tt];
+                  cx_energy += mlintern[tt];
+
+                  dang5=dang3=0;
+                  if ((SAME_STRAND(p-1,p))&&(p>1))
+                    dang5=P->dangle5[tt][S1[p-1]];      /* 5'dangle of pq pair */
+                  if ((SAME_STRAND(i1,i1+1))&&(i1<(unsigned int)S[0]))
+                    dang3 = P->dangle3[type][S1[i1+1]]; /* 3'dangle of previous pair */
+
+                  switch (p-i1-1) {
+                    case 0:   /* adjacent helices */
+                              if (i1!=0){
+                                if (SAME_STRAND(i1,p)) {
+                                  new_cx = energy + P->stack[rtype[type]][rtype[tt]];
+                                  /* subtract 5'dangle and TerminalAU penalty */
+                                  new_cx += -ld5 - mlintern[tt]-mlintern[type]+2*mlintern[1];
+                                }
+                                ld5=0;
+                                energy = MIN2(energy, cx_energy);
+                              }
+                              break;
+                    case 1:   /* 1 unpaired base between helices */
+                              dang = MIN2(dang3, dang5);
+                              energy = energy +dang; ld5 = dang - dang3;
+                              /* may be problem here: Suppose
+                                cx_energy>energy, cx_energy+dang5<energy
+                                and the following helices are also stacked (i.e.
+                                we'll subtract the dang5 again */
+                              if (cx_energy+dang5 < energy) {
+                                energy = cx_energy+dang5;
+                                ld5 = dang5;
+                              }
+                              new_cx = INF;  /* no coax stacking with mismatch for now */
+                              break;
+                    default:  /* many unpaired base between helices */
+                              energy += dang5 +dang3;
+                              energy = MIN2(energy, cx_energy + dang5);
+                              new_cx = INF;  /* no coax stacking possible */
+                              ld5 = dang5;
+                              break;
+                  }
+                  type = tt;
+                  cx_energy = new_cx;
+                  i1 = q; p=q+1;
+                } while (q!=i);
+                best_energy = MIN2(energy, best_energy); /* don't use cx_energy here */
+                /* fprintf(stderr, "%6.2d\t", energy); */
+                /* skip a helix and start again */
+                while (pair_table[p]==0) p++;
+                if (i == (unsigned int)pair_table[p]) break;
+                i = (unsigned int)pair_table[p];
+              } /* end doing it twice */
+              energy = best_energy;
+              break;
+
+    default:  E_mm5_available = E2_mm5_available  = INF;
+              E_mm5_occupied  = E2_mm5_occupied   = 0;
+              while(p < j){
+                /* p must have a pairing partner */
+                q  = (int)pair_table[p];
+                /* get type of base pair (p,q) */
+                tt = pair[S[p]][S[q]];
+                if(tt==0) tt=7;
+                if(q_prev + 2 < p){
+                  E_mm5_available = MIN2(E_mm5_available, E_mm5_occupied);
+                  E_mm5_occupied  = E_mm5_available;
+                }
+                if(q_prev2 + 2 < p){
+                  E2_mm5_available  = MIN2(E2_mm5_available, E2_mm5_occupied);
+                  E2_mm5_occupied   = E2_mm5_available;
+                }
+                mm5 = ((SAME_STRAND(p-1,p)) && !pair_table[p-1])  ? S1[p-1] : -1;
+                mm3 = ((SAME_STRAND(q,q+1)) && !pair_table[q+1])  ? S1[q+1] : -1;
+                tmp =                   MIN2(
+                                              E_mm5_occupied  + E_MLstem(tt, -1, mm3, P),
+                                              E_mm5_available + E_MLstem(tt, mm5, mm3, P)
+                                            );
+                tmp   =                 MIN2(tmp, E_mm5_available + E_MLstem(tt, -1, mm3, P));
+                tmp2  =                 MIN2(
+                                              E_mm5_occupied  + E_MLstem(tt, -1, -1, P),
+                                              E_mm5_available + E_MLstem(tt, mm5, -1, P)
+                                            );
+                E_mm5_available =       MIN2(tmp2, E_mm5_available  + E_MLstem(tt, -1, -1, P));
+                E_mm5_occupied  = tmp;
+
+                tmp =                  MIN2(
+                                              E2_mm5_occupied  + E_MLstem(tt, -1, mm3, P),
+                                              E2_mm5_available + E_MLstem(tt, mm5, mm3, P)
+                                            );
+                tmp =                   MIN2(tmp, E2_mm5_available + E_MLstem(tt, -1, mm3, P));
+                tmp2 =                  MIN2(
+                                              E2_mm5_occupied  + E_MLstem(tt, -1, -1, P),
+                                              E2_mm5_available + E_MLstem(tt, mm5, -1, P)
+                                            );
+                E2_mm5_available =      MIN2(tmp2, E2_mm5_available + E_MLstem(tt, -1, -1, P));
+                E2_mm5_occupied = tmp;
+                /* printf("(%d,%d): \n E_o = %d, E_a = %d, E2_o = %d, E2_a = %d\n", p, q, E_mm5_occupied,E_mm5_available,E2_mm5_occupied,E2_mm5_available); */
+                /* seek to the next stem */
+                p = q + 1;
+                q_prev = q_prev2 = q;
+                while (p <= j && !pair_table[p]) p++;
+                u += p - q - 1; /* add unpaired nucleotides */
+              }
+              /* now lets see how we get the minimum including the enclosing stem */
+              type = pair[S[j]][S[i]]; if (type==0) type=7;
+              mm5 = ((SAME_STRAND(j-1,j)) && !pair_table[j-1])  ? S1[j-1] : -1;
+              mm3 = ((SAME_STRAND(i,i+1)) && !pair_table[i+1])  ? S1[i+1] : -1;
+              if(q_prev + 2 < p){
+                E_mm5_available = MIN2(E_mm5_available, E_mm5_occupied);
+                E_mm5_occupied  = E_mm5_available;
+              }
+              if(q_prev2 + 2 < p){
+                E2_mm5_available  = MIN2(E2_mm5_available, E2_mm5_occupied);
+                E2_mm5_occupied   = E2_mm5_available;
+              }
+              energy = MIN2(E_mm5_occupied  + E_MLstem(type, -1, -1, P),
+                            E_mm5_available + E_MLstem(type, mm5, -1, P)
+                          );
+              energy = MIN2(energy, E_mm5_available   + E_MLstem(type, -1, -1, P));
+              energy = MIN2(energy, E2_mm5_occupied   + E_MLstem(type, -1, mm3, P));
+              energy = MIN2(energy, E2_mm5_occupied   + E_MLstem(type, -1, -1, P));
+              energy = MIN2(energy, E2_mm5_available  + E_MLstem(type, mm5, mm3, P));
+              energy = MIN2(energy, E2_mm5_available  + E_MLstem(type, -1, mm3, P));
+              energy = MIN2(energy, E2_mm5_available  + E_MLstem(type, mm5, -1, P));
+              energy = MIN2(energy, E2_mm5_available  + E_MLstem(type, -1, -1, P));
+              break;
+  }/* end switch dangle_model */
+
+  energy += P->MLclosing;
+  /* logarithmic ML loop energy if logML */
+  if(logML && (u>6))
+    energy += 6*P->MLbase+(int)(P->lxc*log((double)u/6.));
+  else
+    energy += (u*P->MLbase);
+
+  return energy;
+}
+
+/*---------------------------------------------------------------------------*/
+
+PUBLIC int loop_energy(short * ptable, short *s, short *s1, int i) {
+  /* compute energy of a single loop closed by base pair (i,j) */
+  int j, type, p,q, energy;
+  short *Sold, *S1old, *ptold;
+
+  ptold=pair_table;   Sold = S;   S1old = S1;
+  pair_table = ptable;   S = s;   S1 = s1;
+
+  if (i==0) { /* evaluate exterior loop */
+    energy = energy_of_extLoop_pt(0,pair_table);
+    pair_table=ptold; S=Sold; S1=S1old;
+    return energy;
+  }
+  j = pair_table[i];
+  if (j<i) nrerror("i is unpaired in loop_energy()");
+  type = pair[S[i]][S[j]];
+  if (type==0) {
+    type=7;
+    if (eos_debug>=0)
+      fprintf(stderr,"WARNING: bases %d and %d (%c%c) can't pair!\n", i, j,
+              Law_and_Order[S[i]],Law_and_Order[S[j]]);
+  }
+  p=i; q=j;
+
+
+  while (pair_table[++p]==0);
+  while (pair_table[--q]==0);
+  if (p>q) { /* Hairpin */
+    char loopseq[8] = "";
+    if (SAME_STRAND(i,j)) {
+      if (j-i-1<7) {
+        int u;
+        for (u=0; i+u<=j; u++) loopseq[u] = Law_and_Order[S[i+u]];
+        loopseq[u] = '\0';
+      }
+      energy = E_Hairpin(j-i-1, type, S1[i+1], S1[j-1], loopseq, P);
+    } else {
+      energy = energy_of_extLoop_pt(cut_in_loop(i), pair_table);
+    }
+  }
+  else if (pair_table[q]!=(short)p) { /* multi-loop */
+    int ii;
+    ii = cut_in_loop(i);
+    energy = (ii==0) ? energy_of_ml_pt(i, pair_table) : energy_of_extLoop_pt(ii, pair_table);
+  }
+  else { /* found interior loop */
+    int type_2;
+    type_2 = pair[S[q]][S[p]];
+    if (type_2==0) {
+      type_2=7;
+      if (eos_debug>=0)
+        fprintf(stderr,"WARNING: bases %d and %d (%c%c) can't pair!\n", p, q,
+                Law_and_Order[S[p]],Law_and_Order[S[q]]);
+    }
+    /* energy += LoopEnergy(i, j, p, q, type, type_2); */
+    if ( SAME_STRAND(i,p) && SAME_STRAND(q,j) )
+      energy = E_IntLoop(p-i-1, j-q-1, type, type_2,
+                          S1[i+1], S1[j-1], S1[p-1], S1[q+1], P);
+    else
+      energy = energy_of_extLoop_pt(cut_in_loop(i), pair_table);
+  }
+
+  pair_table=ptold; S=Sold; S1=S1old;
+  return energy;
+}
+
+/*---------------------------------------------------------------------------*/
+
+
+PUBLIC float energy_of_move(const char *string, const char *structure, int m1, int m2) {
+  int   energy;
+  short *ss, *ss1;
+
+#ifdef _OPENMP
+  if(P == NULL) update_fold_params();
+#else
+  if((init_length<0)||(P==NULL)) update_fold_params();
+#endif
+
+  if (fabs(P->temperature - temperature)>1e-6) update_fold_params();
+
+  if (strlen(structure)!=strlen(string))
+    nrerror("energy_of_struct: string and structure have unequal length");
+
+  /* save the S and S1 pointers in case they were already in use */
+  ss = S; ss1 = S1;
+  S   = encode_sequence(string, 0);
+  S1  = encode_sequence(string, 1);
+
+  pair_table = make_pair_table(structure);
+
+  energy = energy_of_move_pt(pair_table, S, S1, m1, m2);
+
+  free(pair_table);
+  free(S); free(S1);
+  S=ss; S1=ss1;
+  return  (float) energy/100.;
+}
+
+/*---------------------------------------------------------------------------*/
+
+PUBLIC int energy_of_move_pt(short *pt, short *s, short *s1, int m1, int m2) {
+  /*compute change in energy given by move (m1,m2)*/
+  int en_post, en_pre, i,j,k,l, len;
+
+  len = pt[0];
+  k = (m1>0)?m1:-m1;
+  l = (m2>0)?m2:-m2;
+  /* first find the enclosing pair i<k<l<j */
+  for (j=l+1; j<=len; j++) {
+    if (pt[j]<=0) continue; /* unpaired */
+    if (pt[j]<k) break;   /* found it */
+    if (pt[j]>j) j=pt[j]; /* skip substructure */
+    else {
+      fprintf(stderr, "%d %d %d %d ", m1, m2, j, pt[j]);
+      nrerror("illegal move or broken pair table in energy_of_move()");
+    }
+  }
+  i = (j<=len) ? pt[j] : 0;
+  en_pre = loop_energy(pt, s, s1, i);
+  en_post = 0;
+  if (m1<0) { /*it's a delete move */
+    en_pre += loop_energy(pt, s, s1, k);
+    pt[k]=0;
+    pt[l]=0;
+  } else { /* insert move */
+    pt[k]=l;
+    pt[l]=k;
+    en_post += loop_energy(pt, s, s1, k);
+  }
+  en_post += loop_energy(pt, s, s1, i);
+  /*  restore pair table */
+  if (m1<0) {
+    pt[k]=l;
+    pt[l]=k;
+  } else {
+    pt[k]=0;
+    pt[l]=0;
+  }
+  return (en_post - en_pre);
+}
+
+
+
+PRIVATE int cut_in_loop(int i) {
+  /* walk around the loop;  return j pos of pair after cut if
+     cut_point in loop else 0 */
+  int  p, j;
+  p = j = pair_table[i];
+  do {
+    i  = pair_table[p];  p = i+1;
+    while ( pair_table[p]==0 ) p++;
+  } while (p!=j && SAME_STRAND(i,p));
+  return SAME_STRAND(i,p) ? 0 : j;
+}
+
+/*---------------------------------------------------------------------------*/
+
+PRIVATE void make_ptypes(const short *S, const char *structure) {
+  int n,i,j,k,l;
+
+  n=S[0];
+  for (k=1; k<n-TURN; k++)
+    for (l=1; l<=2; l++) {
+      int type,ntype=0,otype=0;
+      i=k; j = i+TURN+l; if (j>n) continue;
+      type = pair[S[i]][S[j]];
+      while ((i>=1)&&(j<=n)) {
+        if ((i>1)&&(j<n)) ntype = pair[S[i-1]][S[j+1]];
+        if (noLonelyPairs && (!otype) && (!ntype))
+          type = 0; /* i.j can only form isolated pairs */
+        ptype[indx[j]+i] = (char) type;
+        otype =  type;
+        type  = ntype;
+        i--; j++;
+      }
+    }
+
+  if (struct_constrained && (structure != NULL))
+    constrain_ptypes(structure, (unsigned int)n, ptype, BP, TURN, 0);
+}
+
+PUBLIC void assign_plist_from_db(plist **pl, const char *struc, float pr){
+  /* convert bracket string to plist */
+  short *pt;
+  int i, k = 0, size, n;
+  plist *gpl, *ptr;
+
+  size  = strlen(struc);
+  n     = 2;
+
+  pt  = make_pair_table(struc);
+  *pl = (plist *)space(n*size*sizeof(plist));
+  for(i = 1; i < size; i++){
+    if(pt[i]>i){
+      (*pl)[k].i      = i;
+      (*pl)[k].j      = pt[i];
+      (*pl)[k].p      = pr;
+      (*pl)[k++].type = 0;
+    }
+  }
+
+  gpl = get_plist_gquad_from_db(struc, pr);
+  for(ptr = gpl; ptr->i != 0; ptr++){
+    if (k == n * size - 1){
+      n *= 2;
+      *pl = (plist *)xrealloc(*pl, n * size * sizeof(plist));
+    }
+    (*pl)[k].i      = ptr->i;
+    (*pl)[k].j      = ptr->j;
+    (*pl)[k].p       = ptr->p;
+    (*pl)[k++].type = ptr->type;
+  }
+  free(gpl);
+
+  (*pl)[k].i      = 0;
+  (*pl)[k].j      = 0;
+  (*pl)[k].p      = 0.;
+  (*pl)[k++].type = 0.;
+  free(pt);
+  *pl = (plist *)xrealloc(*pl, k * sizeof(plist));
+}
+
+
+/*###########################################*/
+/*# deprecated functions below              #*/
+/*###########################################*/
+
+PUBLIC int HairpinE(int size, int type, int si1, int sj1, const char *string) {
+  int energy;
+
+  energy = (size <= 30) ? P->hairpin[size] :
+    P->hairpin[30]+(int)(P->lxc*log((size)/30.));
+
+  if (tetra_loop){
+    if (size == 4) { /* check for tetraloop bonus */
+      char tl[7]={0}, *ts;
+      strncpy(tl, string, 6);
+      if ((ts=strstr(P->Tetraloops, tl)))
+        return (P->Tetraloop_E[(ts - P->Tetraloops)/7]);
+    }
+    if (size == 6) {
+      char tl[9]={0}, *ts;
+      strncpy(tl, string, 8);
+      if ((ts=strstr(P->Hexaloops, tl)))
+        return (energy = P->Hexaloop_E[(ts - P->Hexaloops)/9]);
+    }
+    if (size == 3) {
+      char tl[6]={0,0,0,0,0,0}, *ts;
+      strncpy(tl, string, 5);
+      if ((ts=strstr(P->Triloops, tl))) {
+        return (P->Triloop_E[(ts - P->Triloops)/6]);
+      }
+      if (type>2)  /* neither CG nor GC */
+        energy += P->TerminalAU; /* penalty for closing AU GU pair IVOO??
+                                    sind dass jetzt beaunuesse oder mahlnuesse (vorzeichen?)*/
+      return energy;
+    }
+   }
+   energy += P->mismatchH[type][si1][sj1];
+
+  return energy;
+}
+
+/*---------------------------------------------------------------------------*/
+
+PUBLIC int oldLoopEnergy(int i, int j, int p, int q, int type, int type_2) {
+  /* compute energy of degree 2 loop (stack bulge or interior) */
+  int n1, n2, m, energy;
+  n1 = p-i-1;
+  n2 = j-q-1;
+
+  if (n1>n2) { m=n1; n1=n2; n2=m; } /* so that n2>=n1 */
+
+  if (n2 == 0)
+    energy = P->stack[type][type_2];   /* stack */
+
+  else if (n1==0) {                  /* bulge */
+    energy = (n2<=MAXLOOP)?P->bulge[n2]:
+      (P->bulge[30]+(int)(P->lxc*log(n2/30.)));
+
+#if STACK_BULGE1
+    if (n2==1) energy+=P->stack[type][type_2];
+#endif
+  } else {                           /* interior loop */
+
+    if ((n1+n2==2)&&(james_rule))
+      /* special case for loop size 2 */
+      energy = P->int11[type][type_2][S1[i+1]][S1[j-1]];
+    else {
+      energy = (n1+n2<=MAXLOOP)?(P->internal_loop[n1+n2]):
+        (P->internal_loop[30]+(int)(P->lxc*log((n1+n2)/30.)));
+
+#if NEW_NINIO
+      energy += MIN2(MAX_NINIO, (n2-n1)*P->ninio[2]);
+#else
+      m       = MIN2(4, n1);
+      energy += MIN2(MAX_NINIO,((n2-n1)*P->ninio[m]));
+#endif
+      energy += P->mismatchI[type][S1[i+1]][S1[j-1]]+
+        P->mismatchI[type_2][S1[q+1]][S1[p-1]];
+    }
+  }
+  return energy;
+}
+
+/*--------------------------------------------------------------------------*/
+
+PUBLIC int LoopEnergy(int n1, int n2, int type, int type_2,
+                      int si1, int sj1, int sp1, int sq1) {
+  /* compute energy of degree 2 loop (stack bulge or interior) */
+  int nl, ns, energy;
+
+  if (n1>n2) { nl=n1; ns=n2;}
+  else {nl=n2; ns=n1;}
+
+  if (nl == 0)
+    return P->stack[type][type_2];    /* stack */
+
+  if (ns==0) {                       /* bulge */
+    energy = (nl<=MAXLOOP)?P->bulge[nl]:
+      (P->bulge[30]+(int)(P->lxc*log(nl/30.)));
+    if (nl==1) energy += P->stack[type][type_2];
+    else {
+      if (type>2) energy += P->TerminalAU;
+      if (type_2>2) energy += P->TerminalAU;
+    }
+    return energy;
+  }
+  else {                             /* interior loop */
+    if (ns==1) {
+      if (nl==1)                     /* 1x1 loop */
+        return P->int11[type][type_2][si1][sj1];
+      if (nl==2) {                   /* 2x1 loop */
+        if (n1==1)
+          energy = P->int21[type][type_2][si1][sq1][sj1];
+        else
+          energy = P->int21[type_2][type][sq1][si1][sp1];
+        return energy;
+      }
+        else {  /* 1xn loop */
+        energy = (nl+1<=MAXLOOP)?(P->internal_loop[nl+1]):
+        (P->internal_loop[30]+(int)(P->lxc*log((nl+1)/30.)));
+        energy += MIN2(MAX_NINIO, (nl-ns)*P->ninio[2]);
+        energy += P->mismatch1nI[type][si1][sj1]+
+        P->mismatch1nI[type_2][sq1][sp1];
+        return energy;
+        }
+    }
+    else if (ns==2) {
+      if(nl==2)      {   /* 2x2 loop */
+        return P->int22[type][type_2][si1][sp1][sq1][sj1];}
+      else if (nl==3)  { /* 2x3 loop */
+        energy = P->internal_loop[5]+P->ninio[2];
+        energy += P->mismatch23I[type][si1][sj1]+
+          P->mismatch23I[type_2][sq1][sp1];
+        return energy;
+      }
+
+    }
+    { /* generic interior loop (no else here!)*/
+      energy = (n1+n2<=MAXLOOP)?(P->internal_loop[n1+n2]):
+        (P->internal_loop[30]+(int)(P->lxc*log((n1+n2)/30.)));
+
+      energy += MIN2(MAX_NINIO, (nl-ns)*P->ninio[2]);
+
+      energy += P->mismatchI[type][si1][sj1]+
+        P->mismatchI[type_2][sq1][sp1];
+    }
+  }
+  return energy;
+}
+
+PRIVATE int ML_Energy(int i, int is_extloop) {
+  /* i is the 5'-base of the closing pair (or 0 for exterior loop)
+     loop is scored as ML if extloop==0 else as exterior loop
+
+     since each helix can coaxially stack with at most one of its
+     neighbors we need an auxiliarry variable  cx_energy
+     which contains the best energy given that the last two pairs stack.
+     energy  holds the best energy given the previous two pairs do not
+     stack (i.e. the two current helices may stack)
+     We don't allow the last helix to stack with the first, thus we have to
+     walk around the Loop twice with two starting points and take the minimum
+  */
+
+  int energy, cx_energy, best_energy=INF;
+  int i1, j, p, q, u, x, type, count;
+  int mlintern[NBPAIRS+1], mlclosing, mlbase;
+  int dangle_model = P->model_details.dangles;
+
+  if (is_extloop) {
+    for (x = 0; x <= NBPAIRS; x++)
+      mlintern[x] = P->MLintern[x]-P->MLintern[1]; /* 0 or TerminalAU */
+    mlclosing = mlbase = 0;
+  } else {
+    for (x = 0; x <= NBPAIRS; x++) mlintern[x] = P->MLintern[x];
+    mlclosing = P->MLclosing; mlbase = P->MLbase;
+  }
+
+  /*  as we do not only have dangling end but also mismatch contributions,
+  **  we do this a bit different to previous implementations
+  */
+  if(is_extloop){
+    energy = 0;
+    i1  = i;
+    p   = i+1;
+
+    int E_mm5_available, E_mm5_occupied;
+    /* find out if we may have 5' mismatch for the next stem */
+    while (p <= (int)pair_table[0] && pair_table[p]==0) p++;
+    /* get position of pairing partner */
+    if(p < (int)pair_table[0]){
+        E_mm5_occupied  = (p - i - 1 > 0) ? INF : 0;
+        E_mm5_available = (p - i - 1 > 0) ? 0 : INF;
+    }
+
+    if(p < (int)pair_table[0])
+      do{
+        int tt;
+        /* p must have a pairing partner */
+        q  = (int)pair_table[p];
+        /* get type of base pair (p,q) */
+        tt = pair[S[p]][S[q]];
+        if(tt==0) tt=7;
+
+        int mm5 = ((SAME_STRAND(p-1,p)) && (p>1)) ? S1[p-1]: -1;
+        int mm3 = ((SAME_STRAND(q,q+1)) && (q<(unsigned int)pair_table[0])) ? S1[q+1]: -1;
+
+        switch(dangle_model){
+          /* dangle_model == 0 */
+          case 0: energy += E_ExtLoop(tt, -1, -1, P);
+                  break;
+          /* dangle_model == 1 */
+          case 1: {
+                    /* check for unpaired nucleotide 3' to the current stem */
+                    int u3 = ((q < pair_table[0]) && (pair_table[q+1] == 0)) ? 1 : 0;
+                    if(pair_table[p-1] != 0) mm5 = -1;
+
+                    if(!u3){
+                      mm3 = -1;
+                      E_mm5_occupied  = MIN2(
+                                              E_mm5_occupied  + E_ExtLoop(tt, -1, -1, P),
+                                              E_mm5_available + E_ExtLoop(tt, mm5, -1, P)
+                                            );
+                      E_mm5_available = E_mm5_occupied;
+                    }
+                    else{
+                      E_mm5_occupied  = MIN2(
+                                              E_mm5_occupied  + E_ExtLoop(tt, -1, mm3, P),
+                                              E_mm5_available + E_ExtLoop(tt, mm5, mm3, P)
+                                            );
+                      E_mm5_available = MIN2(
+                                              E_mm5_occupied  + E_ExtLoop(tt, -1, -1, P),
+                                              E_mm5_available + E_ExtLoop(tt, mm5, -1, P)
+                                            );
+                    }
+                  }
+                  break;
+
+          /* the beloved case dangle_model == 2 */
+          case 2: energy += E_ExtLoop(tt, mm5, mm3, P);
+                  break;
+
+          /* dangle_model == 3 a.k.a. helix stacking */
+          case 3: break;
+
+        } /* end switch dangle_model */
+
+        /* seek to the next stem */
+        p = q + 1;
+        while (p <= (int)pair_table[0] && pair_table[p]==0) p++;
+        if(p == (int)pair_table[0] + 1){
+          if(dangle_model == 1)
+            energy = (p > q + 1) ? E_mm5_occupied : E_mm5_available;
+          q = 0;
+          break;
+        }
+      } while(q != i);
+  }
+  /* not exterior loop */
+  else{
+    for (count=0; count<2; count++) { /* do it twice */
+      int ld5 = 0; /* 5' dangle energy on prev pair (type) */
+      if ( i==0 ) {
+        j = (unsigned int)pair_table[0]+1;
+        type = 0;  /* no pair */
+      }
+      else {
+        j = (unsigned int)pair_table[i];
+        type = pair[S[j]][S[i]]; if (type==0) type=7;
+
+        if (dangle_model==3) { /* prime the ld5 variable */
+          if (SAME_STRAND(j-1,j)) {
+            ld5 = P->dangle5[type][S1[j-1]];
+            if ((p=(unsigned int)pair_table[j-2]) && SAME_STRAND(j-2, j-1))
+                if (P->dangle3[pair[S[p]][S[j-2]]][S1[j-1]]<ld5) ld5 = 0;
+          }
+        }
+      }
+      i1=i; p = i+1; u=0;
+      energy = 0; cx_energy=INF;
+      do { /* walk around the multi-loop */
+        int tt, new_cx = INF;
+
+        /* hop over unpaired positions */
+        while (p <= (unsigned int)pair_table[0] && pair_table[p]==0) p++;
+
+        /* memorize number of unpaired positions */
+        u += p-i1-1;
+        /* get position of pairing partner */
+        if ( p == (unsigned int)pair_table[0]+1 ){
+          q = 0;tt = 0; /* virtual root pair */
+        } else {
+        q  = (unsigned int)pair_table[p];
+          /* get type of base pair P->q */
+        tt = pair[S[p]][S[q]]; if (tt==0) tt=7;
+        }
+
+        energy += mlintern[tt];
+        cx_energy += mlintern[tt];
+
+        if (dangle_model) {
+          int dang5=0, dang3=0, dang;
+          if ((SAME_STRAND(p-1,p))&&(p>1))
+            dang5=P->dangle5[tt][S1[p-1]];      /* 5'dangle of pq pair */
+          if ((SAME_STRAND(i1,i1+1))&&(i1<(unsigned int)S[0]))
+            dang3 = P->dangle3[type][S1[i1+1]]; /* 3'dangle of previous pair */
+
+          switch (p-i1-1) {
+          case 0: /* adjacent helices */
+            if (dangle_model==2)
+              energy += dang3+dang5;
+            else if (dangle_model==3 && i1!=0) {
+              if (SAME_STRAND(i1,p)) {
+                new_cx = energy + P->stack[rtype[type]][rtype[tt]];
+                /* subtract 5'dangle and TerminalAU penalty */
+                new_cx += -ld5 - mlintern[tt]-mlintern[type]+2*mlintern[1];
+              }
+              ld5=0;
+              energy = MIN2(energy, cx_energy);
+            }
+            break;
+          case 1: /* 1 unpaired base between helices */
+            dang = (dangle_model==2)?(dang3+dang5):MIN2(dang3, dang5);
+            if (dangle_model==3) {
+              energy = energy +dang; ld5 = dang - dang3;
+              /* may be problem here: Suppose
+                 cx_energy>energy, cx_energy+dang5<energy
+                 and the following helices are also stacked (i.e.
+                 we'll subtract the dang5 again */
+              if (cx_energy+dang5 < energy) {
+                energy = cx_energy+dang5;
+                ld5 = dang5;
+              }
+              new_cx = INF;  /* no coax stacking with mismatch for now */
+            } else
+              energy += dang;
+            break;
+          default: /* many unpaired base between helices */
+            energy += dang5 +dang3;
+            if (dangle_model==3) {
+              energy = MIN2(energy, cx_energy + dang5);
+              new_cx = INF;  /* no coax stacking possible */
+              ld5 = dang5;
+            }
+          }
+          type = tt;
+        }
+        if (dangle_model==3) cx_energy = new_cx;
+        i1 = q; p=q+1;
+      } while (q!=i);
+      best_energy = MIN2(energy, best_energy); /* don't use cx_energy here */
+      /* fprintf(stderr, "%6.2d\t", energy); */
+      if (dangle_model!=3 || is_extloop) break;  /* may break cofold with co-ax */
+      /* skip a helix and start again */
+      while (pair_table[p]==0) p++;
+      if (i == (unsigned int)pair_table[p]) break;
+      i = (unsigned int)pair_table[p];
+    }
+    energy = best_energy;
+    energy += mlclosing;
+    /* logarithmic ML loop energy if logML */
+    if ( (!is_extloop) && logML && (u>6) )
+      energy += 6*mlbase+(int)(P->lxc*log((double)u/6.));
+    else
+      energy += mlbase*u;
+    /* fprintf(stderr, "\n"); */
+  }
+  return energy;
+}
+
+PUBLIC void initialize_fold(int length){
+  /* DO NOTHING */
+}
+
+PUBLIC float energy_of_struct(const char *string, const char *structure){
+  return energy_of_structure(string, structure, eos_debug);
+}
+
+PUBLIC int energy_of_struct_pt(const char *string, short * ptable, short *s, short *s1){
+  return energy_of_structure_pt(string, ptable, s, s1, eos_debug);
+}
+
+PUBLIC float energy_of_circ_struct(const char *string, const char *structure){
+  return energy_of_circ_structure(string, structure, eos_debug);
+}
+