1 #ifndef VIENNA_RNA_PACKAGE_LOOPS_INTERNAL_H
2 #define VIENNA_RNA_PACKAGE_LOOPS_INTERNAL_H
3 
4 #include <ViennaRNA/utils/basic.h>
5 #include <ViennaRNA/params/default.h>
6 #include <ViennaRNA/datastructures/basic.h>
7 #include <ViennaRNA/fold_compound.h>
8 #include <ViennaRNA/params/basic.h>
9 #include <ViennaRNA/constraints/hard.h>
10 #include <ViennaRNA/constraints/soft.h>
11 
12 #ifdef VRNA_WARN_DEPRECATED
13 # if defined(DEPRECATED)
14 #   undef DEPRECATED
15 # endif
16 # if defined(__clang__)
17 #  define DEPRECATED(func, msg) func __attribute__ ((deprecated("", msg)))
18 # elif defined(__GNUC__)
19 #  define DEPRECATED(func, msg) func __attribute__ ((deprecated(msg)))
20 # else
21 #  define DEPRECATED(func, msg) func
22 # endif
23 #else
24 # define DEPRECATED(func, msg) func
25 #endif
26 
27 #ifdef __GNUC__
28 # define INLINE inline
29 #else
30 # define INLINE
31 #endif
32 
33 /**
34  *  @file     ViennaRNA/loops/internal.h
35  *  @ingroup  eval, eval_loops, eval_loops_int
36  *  @brief    Energy evaluation of interior loops for MFE and partition function calculations
37  */
38 
39 /**
40  *  @addtogroup   eval_loops_int
41  *  @{
42  *  @brief  Functions to evaluate the free energy contributions for internal loops
43  */
44 
45 
46 /**
47  *  @name Basic free energy interface
48  *  @{
49  */
50 int
51 vrna_E_int_loop(vrna_fold_compound_t  *fc,
52                 int                   i,
53                 int                   j);
54 
55 
56 /**
57  *  @brief Evaluate the free energy contribution of an interior loop with delimiting
58  *  base pairs @f$(i,j)@f$ and @f$(k,l)@f$
59  *
60  *  @note This function is polymorphic, i.e. it accepts #vrna_fold_compound_t of type
61  *        #VRNA_FC_TYPE_SINGLE as well as #VRNA_FC_TYPE_COMPARATIVE
62  */
63 int
64 vrna_eval_int_loop(vrna_fold_compound_t *fc,
65                    int                  i,
66                    int                  j,
67                    int                  k,
68                    int                  l);
69 
70 
71 int
72 vrna_E_ext_int_loop(vrna_fold_compound_t  *fc,
73                     int                   i,
74                     int                   j,
75                     int                   *ip,
76                     int                   *iq);
77 
78 
79 int
80 vrna_E_stack(vrna_fold_compound_t *fc,
81              int                  i,
82              int                  j);
83 
84 
85 /* End basic interface */
86 /**@}*/
87 
88 
89 /**
90  *  @name Boltzmann weight (partition function) interface
91  *  @{
92  */
93 
94 
95 /* j < i indicates circular folding, i.e. collect contributions for exterior int loops */
96 FLT_OR_DBL
97 vrna_exp_E_int_loop(vrna_fold_compound_t  *fc,
98                     int                   i,
99                     int                   j);
100 
101 
102 FLT_OR_DBL
103 vrna_exp_E_interior_loop(vrna_fold_compound_t *fc,
104                          int                  i,
105                          int                  j,
106                          int                  k,
107                          int                  l);
108 
109 
110 /* End partition function interface */
111 /**@}*/
112 
113 /**
114  * @}
115  */
116 
117 
118 /**
119  *  @addtogroup mfe_backtracking
120  *  @{
121  */
122 
123 
124 /**
125  *  @brief Backtrack a stacked pair closed by @f$ (i,j) @f$
126  *
127  */
128 int
129 vrna_BT_stack(vrna_fold_compound_t  *fc,
130               int                   *i,
131               int                   *j,
132               int                   *en,
133               vrna_bp_stack_t       *bp_stack,
134               int                   *stack_count);
135 
136 
137 /**
138  *  @brief Backtrack an interior loop closed by @f$ (i,j) @f$
139  *
140  */
141 int
142 vrna_BT_int_loop(vrna_fold_compound_t *fc,
143                  int                  *i,
144                  int                  *j,
145                  int                  en,
146                  vrna_bp_stack_t      *bp_stack,
147                  int                  *stack_count);
148 
149 
150 /**
151  * @}
152  */
153 
154 
155 #ifndef VRNA_DISABLE_BACKWARD_COMPATIBILITY
156 /**
157  *  @addtogroup   eval_deprecated
158  *  @{
159  */
160 
161 
162 #ifdef ON_SAME_STRAND
163 #undef ON_SAME_STRAND
164 #endif
165 
166 #define ON_SAME_STRAND(I, J, C)  (((I) >= (C)) || ((J) < (C)))
167 
168 /**
169  *  <H2>Compute the Energy of an interior-loop</H2>
170  *  This function computes the free energy @f$\Delta G@f$ of an interior-loop with the
171  *  following structure: <BR>
172  *  <PRE>
173  *        3'  5'
174  *        |   |
175  *        U - V
176  *    a_n       b_1
177  *     .        .
178  *     .        .
179  *     .        .
180  *    a_1       b_m
181  *        X - Y
182  *        |   |
183  *        5'  3'
184  *  </PRE>
185  *  This general structure depicts an interior-loop that is closed by the base pair (X,Y).
186  *  The enclosed base pair is (V,U) which leaves the unpaired bases a_1-a_n and b_1-b_n
187  *  that constitute the loop. In this example, the length of the interior-loop is @f$(n+m)@f$
188  *  where n or m may be 0 resulting in a bulge-loop or base pair stack.
189  *  The mismatching nucleotides for the closing pair (X,Y) are:<BR>
190  *  5'-mismatch: a_1<BR>
191  *  3'-mismatch: b_m<BR>
192  *  and for the enclosed base pair (V,U):<BR>
193  *  5'-mismatch: b_1<BR>
194  *  3'-mismatch: a_n<BR>
195  *  @note Base pairs are always denoted in 5'->3' direction. Thus the enclosed base pair
196  *  must be 'turned arround' when evaluating the free energy of the interior-loop
197  *  @see scale_parameters()
198  *  @see vrna_param_t
199  *  @note This function is threadsafe
200  *
201  *  @param  n1      The size of the 'left'-loop (number of unpaired nucleotides)
202  *  @param  n2      The size of the 'right'-loop (number of unpaired nucleotides)
203  *  @param  type    The pair type of the base pair closing the interior loop
204  *  @param  type_2  The pair type of the enclosed base pair
205  *  @param  si1     The 5'-mismatching nucleotide of the closing pair
206  *  @param  sj1     The 3'-mismatching nucleotide of the closing pair
207  *  @param  sp1     The 3'-mismatching nucleotide of the enclosed pair
208  *  @param  sq1     The 5'-mismatching nucleotide of the enclosed pair
209  *  @param  P       The datastructure containing scaled energy parameters
210  *  @return The Free energy of the Interior-loop in dcal/mol
211  */
212 PRIVATE INLINE int E_IntLoop(int          n1,
213                              int          n2,
214                              int          type,
215                              int          type_2,
216                              int          si1,
217                              int          sj1,
218                              int          sp1,
219                              int          sq1,
220                              vrna_param_t *P);
221 
222 
223 /**
224  *  <H2>Compute Boltzmann weight @f$e^{-\Delta G/kT} @f$ of interior loop</H2>
225  *  multiply by scale[u1+u2+2] for scaling
226  *  @see get_scaled_pf_parameters()
227  *  @see vrna_exp_param_t
228  *  @see E_IntLoop()
229  *  @note This function is threadsafe
230  *
231  *  @param  u1      The size of the 'left'-loop (number of unpaired nucleotides)
232  *  @param  u2      The size of the 'right'-loop (number of unpaired nucleotides)
233  *  @param  type    The pair type of the base pair closing the interior loop
234  *  @param  type2   The pair type of the enclosed base pair
235  *  @param  si1     The 5'-mismatching nucleotide of the closing pair
236  *  @param  sj1     The 3'-mismatching nucleotide of the closing pair
237  *  @param  sp1     The 3'-mismatching nucleotide of the enclosed pair
238  *  @param  sq1     The 5'-mismatching nucleotide of the enclosed pair
239  *  @param  P       The datastructure containing scaled Boltzmann weights of the energy parameters
240  *  @return The Boltzmann weight of the Interior-loop
241  */
242 PRIVATE INLINE FLT_OR_DBL exp_E_IntLoop(int               u1,
243                                         int               u2,
244                                         int               type,
245                                         int               type2,
246                                         short             si1,
247                                         short             sj1,
248                                         short             sp1,
249                                         short             sq1,
250                                         vrna_exp_param_t  *P);
251 
252 
253 PRIVATE INLINE int E_IntLoop_Co(int           type,
254                                 int           type_2,
255                                 int           i,
256                                 int           j,
257                                 int           p,
258                                 int           q,
259                                 int           cutpoint,
260                                 short         si1,
261                                 short         sj1,
262                                 short         sp1,
263                                 short         sq1,
264                                 int           dangles,
265                                 vrna_param_t  *P);
266 
267 
268 /*
269  *  ugly but fast interior loop evaluation
270  *
271  *  Avoid including this function in your own code. It only serves
272  *  as a fast inline block internally re-used throughout the RNAlib. It
273  *  evalutes the free energy of interior loops in single sequences or sequence
274  *  hybrids. Soft constraints are also applied if available.
275  *
276  *  NOTE: do not include into doxygen reference manual!
277  */
278 PRIVATE INLINE int
ubf_eval_int_loop(int i,int j,int p,int q,int i1,int j1,int p1,int q1,short si,short sj,short sp,short sq,unsigned char type,unsigned char type_2,int * rtype,int ij,int cp,vrna_param_t * P,vrna_sc_t * sc)279 ubf_eval_int_loop(int           i,
280                   int           j,
281                   int           p,
282                   int           q,
283                   int           i1,
284                   int           j1,
285                   int           p1,
286                   int           q1,
287                   short         si,
288                   short         sj,
289                   short         sp,
290                   short         sq,
291                   unsigned char type,
292                   unsigned char type_2,
293                   int           *rtype,
294                   int           ij,
295                   int           cp,
296                   vrna_param_t  *P,
297                   vrna_sc_t     *sc)
298 {
299   int energy, u1, u2;
300 
301   u1  = p1 - i;
302   u2  = j1 - q;
303 
304   if ((cp < 0) || (ON_SAME_STRAND(i, p, cp) && ON_SAME_STRAND(q, j, cp))) {
305     /* regular interior loop */
306     energy = E_IntLoop(u1, u2, type, type_2, si, sj, sp, sq, P);
307   } else {
308     /* interior loop like cofold structure */
309     short Si, Sj;
310     Si      = ON_SAME_STRAND(i, i1, cp) ? si : -1;
311     Sj      = ON_SAME_STRAND(j1, j, cp) ? sj : -1;
312     energy  = E_IntLoop_Co(rtype[type], rtype[type_2],
313                            i, j, p, q,
314                            cp,
315                            Si, Sj,
316                            sp, sq,
317                            P->model_details.dangles,
318                            P);
319   }
320 
321   /* add soft constraints */
322   if (sc) {
323     if (sc->energy_up)
324       energy += sc->energy_up[i1][u1]
325                 + sc->energy_up[q1][u2];
326 
327     if (sc->energy_bp)
328       energy += sc->energy_bp[ij];
329 
330     if (sc->energy_stack)
331       if (u1 + u2 == 0) {
332         int a = sc->energy_stack[i]
333                 + sc->energy_stack[p]
334                 + sc->energy_stack[q]
335                 + sc->energy_stack[j];
336         energy += a;
337       }
338 
339     if (sc->f)
340       energy += sc->f(i, j, p, q, VRNA_DECOMP_PAIR_IL, sc->data);
341   }
342 
343   return energy;
344 }
345 
346 
347 PRIVATE INLINE int
ubf_eval_int_loop2(int i,int j,int p,int q,int i1,int j1,int p1,int q1,short si,short sj,short sp,short sq,unsigned char type,unsigned char type_2,int * rtype,int ij,unsigned int * sn,unsigned int * ss,vrna_param_t * P,vrna_sc_t * sc)348 ubf_eval_int_loop2(int            i,
349                    int            j,
350                    int            p,
351                    int            q,
352                    int            i1,
353                    int            j1,
354                    int            p1,
355                    int            q1,
356                    short          si,
357                    short          sj,
358                    short          sp,
359                    short          sq,
360                    unsigned char  type,
361                    unsigned char  type_2,
362                    int            *rtype,
363                    int            ij,
364                    unsigned int   *sn,
365                    unsigned int   *ss,
366                    vrna_param_t   *P,
367                    vrna_sc_t      *sc)
368 {
369   int energy, u1, u2;
370 
371   u1  = p1 - i;
372   u2  = j1 - q;
373 
374   if ((sn[i] == sn[p]) && (sn[q] == sn[j])) {
375     /* regular interior loop */
376     energy = E_IntLoop(u1, u2, type, type_2, si, sj, sp, sq, P);
377   } else {
378     /* interior loop like cofold structure */
379     short Si, Sj;
380     Si      = (sn[i1] == sn[i]) ? si : -1;
381     Sj      = (sn[j] == sn[j1]) ? sj : -1;
382     energy  = E_IntLoop_Co(rtype[type], rtype[type_2],
383                            i, j, p, q,
384                            ss[1],
385                            Si, Sj,
386                            sp, sq,
387                            P->model_details.dangles,
388                            P);
389   }
390 
391   /* add soft constraints */
392   if (sc) {
393     if (sc->energy_up)
394       energy += sc->energy_up[i1][u1]
395                 + sc->energy_up[q1][u2];
396 
397     if (sc->energy_bp)
398       energy += sc->energy_bp[ij];
399 
400     if (sc->energy_stack)
401       if (u1 + u2 == 0) {
402         int a = sc->energy_stack[i]
403                 + sc->energy_stack[p]
404                 + sc->energy_stack[q]
405                 + sc->energy_stack[j];
406         energy += a;
407       }
408 
409     if (sc->f)
410       energy += sc->f(i, j, p, q, VRNA_DECOMP_PAIR_IL, sc->data);
411   }
412 
413   return energy;
414 }
415 
416 
417 /*
418  *  ugly but fast exterior interior loop evaluation
419  *
420  *  Avoid including this function in your own code. It only serves
421  *  as a fast inline block internally re-used throughout the RNAlib. It
422  *  evalutes the free energy of interior loops in single sequences or sequence
423  *  hybrids. Soft constraints are also applied if available.
424  *
425  *  NOTE: do not include into doxygen reference manual!
426  */
427 PRIVATE INLINE int
ubf_eval_ext_int_loop(int i,int j,int p,int q,int i1,int j1,int p1,int q1,short si,short sj,short sp,short sq,unsigned char type,unsigned char type_2,int length,vrna_param_t * P,vrna_sc_t * sc)428 ubf_eval_ext_int_loop(int           i,
429                       int           j,
430                       int           p,
431                       int           q,
432                       int           i1,
433                       int           j1,
434                       int           p1,
435                       int           q1,
436                       short         si,
437                       short         sj,
438                       short         sp,
439                       short         sq,
440                       unsigned char type,
441                       unsigned char type_2,
442                       int           length,
443                       vrna_param_t  *P,
444                       vrna_sc_t     *sc)
445 {
446   int energy, u1, u2, u3;
447 
448   u1  = i1;
449   u2  = p1 - j;
450   u3  = length - q;
451 
452   energy = E_IntLoop(u2, u1 + u3, type, type_2, si, sj, sp, sq, P);
453 
454   /* add soft constraints */
455   if (sc) {
456     if (sc->energy_up) {
457       energy += sc->energy_up[j1][u2]
458                 + ((u3 > 0) ? sc->energy_up[q1][u3] : 0)
459                 + ((u1 > 0) ? sc->energy_up[1][u1] : 0);
460     }
461 
462     if (sc->energy_stack)
463       if (u1 + u2 + u3 == 0)
464         energy += sc->energy_stack[i]
465                   + sc->energy_stack[p]
466                   + sc->energy_stack[q]
467                   + sc->energy_stack[j];
468 
469     if (sc->f)
470       energy += sc->f(i, j, p, q, VRNA_DECOMP_PAIR_IL, sc->data);
471   }
472 
473   return energy;
474 }
475 
476 
477 PRIVATE INLINE int
E_IntLoop(int n1,int n2,int type,int type_2,int si1,int sj1,int sp1,int sq1,vrna_param_t * P)478 E_IntLoop(int           n1,
479           int           n2,
480           int           type,
481           int           type_2,
482           int           si1,
483           int           sj1,
484           int           sp1,
485           int           sq1,
486           vrna_param_t  *P)
487 {
488   /* compute energy of degree 2 loop (stack bulge or interior) */
489   int nl, ns, u, energy;
490 
491   if (n1 > n2) {
492     nl  = n1;
493     ns  = n2;
494   } else {
495     nl  = n2;
496     ns  = n1;
497   }
498 
499   if (nl == 0)
500     return P->stack[type][type_2];  /* stack */
501 
502   if (ns == 0) {
503     /* bulge */
504     energy = (nl <= MAXLOOP) ? P->bulge[nl] :
505              (P->bulge[30] + (int)(P->lxc * log(nl / 30.)));
506     if (nl == 1) {
507       energy += P->stack[type][type_2];
508     } else {
509       if (type > 2)
510         energy += P->TerminalAU;
511 
512       if (type_2 > 2)
513         energy += P->TerminalAU;
514     }
515 
516     return energy;
517   } else {
518     /* interior loop */
519     if (ns == 1) {
520       if (nl == 1)                    /* 1x1 loop */
521         return P->int11[type][type_2][si1][sj1];
522 
523       if (nl == 2) {
524         /* 2x1 loop */
525         if (n1 == 1)
526           energy = P->int21[type][type_2][si1][sq1][sj1];
527         else
528           energy = P->int21[type_2][type][sq1][si1][sp1];
529 
530         return energy;
531       } else {
532         /* 1xn loop */
533         energy =
534           (nl + 1 <=
535            MAXLOOP) ? (P->internal_loop[nl + 1]) : (P->internal_loop[30] +
536                                                     (int)(P->lxc * log((nl + 1) / 30.)));
537         energy  += MIN2(MAX_NINIO, (nl - ns) * P->ninio[2]);
538         energy  += P->mismatch1nI[type][si1][sj1] + P->mismatch1nI[type_2][sq1][sp1];
539         return energy;
540       }
541     } else if (ns == 2) {
542       if (nl == 2) {
543         /* 2x2 loop */
544         return P->int22[type][type_2][si1][sp1][sq1][sj1];
545       } else if (nl == 3) {
546         /* 2x3 loop */
547         energy  = P->internal_loop[5] + P->ninio[2];
548         energy  += P->mismatch23I[type][si1][sj1] + P->mismatch23I[type_2][sq1][sp1];
549         return energy;
550       }
551     }
552 
553     {
554       /* generic interior loop (no else here!)*/
555       u       = nl + ns;
556       energy  =
557         (u <=
558          MAXLOOP) ? (P->internal_loop[u]) : (P->internal_loop[30] + (int)(P->lxc * log((u) / 30.)));
559 
560       energy += MIN2(MAX_NINIO, (nl - ns) * P->ninio[2]);
561 
562       energy += P->mismatchI[type][si1][sj1] + P->mismatchI[type_2][sq1][sp1];
563     }
564   }
565 
566   return energy;
567 }
568 
569 
570 PRIVATE INLINE FLT_OR_DBL
exp_E_IntLoop(int u1,int u2,int type,int type2,short si1,short sj1,short sp1,short sq1,vrna_exp_param_t * P)571 exp_E_IntLoop(int               u1,
572               int               u2,
573               int               type,
574               int               type2,
575               short             si1,
576               short             sj1,
577               short             sp1,
578               short             sq1,
579               vrna_exp_param_t  *P)
580 {
581   int     ul, us, no_close = 0;
582   double  z           = 0.;
583   int     noGUclosure = P->model_details.noGUclosure;
584 
585   if ((noGUclosure) && ((type2 == 3) || (type2 == 4) || (type == 3) || (type == 4)))
586     no_close = 1;
587 
588   if (u1 > u2) {
589     ul  = u1;
590     us  = u2;
591   } else {
592     ul  = u2;
593     us  = u1;
594   }
595 
596   if (ul == 0) {
597     /* stack */
598     z = P->expstack[type][type2];
599   } else if (!no_close) {
600     if (us == 0) {
601       /* bulge */
602       z = P->expbulge[ul];
603       if (ul == 1) {
604         z *= P->expstack[type][type2];
605       } else {
606         if (type > 2)
607           z *= P->expTermAU;
608 
609         if (type2 > 2)
610           z *= P->expTermAU;
611       }
612 
613       return (FLT_OR_DBL)z;
614     } else if (us == 1) {
615       if (ul == 1)                     /* 1x1 loop */
616         return (FLT_OR_DBL)(P->expint11[type][type2][si1][sj1]);
617 
618       if (ul == 2) {
619         /* 2x1 loop */
620         if (u1 == 1)
621           return (FLT_OR_DBL)(P->expint21[type][type2][si1][sq1][sj1]);
622         else
623           return (FLT_OR_DBL)(P->expint21[type2][type][sq1][si1][sp1]);
624       } else {
625         /* 1xn loop */
626         z = P->expinternal[ul + us] * P->expmismatch1nI[type][si1][sj1] *
627             P->expmismatch1nI[type2][sq1][sp1];
628         return (FLT_OR_DBL)(z * P->expninio[2][ul - us]);
629       }
630     } else if (us == 2) {
631       if (ul == 2) {
632         /* 2x2 loop */
633         return (FLT_OR_DBL)(P->expint22[type][type2][si1][sp1][sq1][sj1]);
634       } else if (ul == 3) {
635         /* 2x3 loop */
636         z = P->expinternal[5] * P->expmismatch23I[type][si1][sj1] *
637             P->expmismatch23I[type2][sq1][sp1];
638         return (FLT_OR_DBL)(z * P->expninio[2][1]);
639       }
640     }
641 
642     /* generic interior loop (no else here!)*/
643     z = P->expinternal[ul + us] * P->expmismatchI[type][si1][sj1] *
644         P->expmismatchI[type2][sq1][sp1];
645     return (FLT_OR_DBL)(z * P->expninio[2][ul - us]);
646   }
647 
648   return (FLT_OR_DBL)z;
649 }
650 
651 
652 PRIVATE INLINE int
E_IntLoop_Co(int type,int type_2,int i,int j,int p,int q,int cutpoint,short si1,short sj1,short sp1,short sq1,int dangles,vrna_param_t * P)653 E_IntLoop_Co(int          type,
654              int          type_2,
655              int          i,
656              int          j,
657              int          p,
658              int          q,
659              int          cutpoint,
660              short        si1,
661              short        sj1,
662              short        sp1,
663              short        sq1,
664              int          dangles,
665              vrna_param_t *P)
666 {
667   int e, energy, ci, cj, cp, cq, d3, d5, d5_2, d3_2, tmm, tmm_2;
668 
669   energy = 0;
670   if (type > 2)
671     energy += P->TerminalAU;
672 
673   if (type_2 > 2)
674     energy += P->TerminalAU;
675 
676   if (!dangles)
677     return energy;
678 
679   ci  = ON_SAME_STRAND(i, i + 1, cutpoint);
680   cj  = ON_SAME_STRAND(j - 1, j, cutpoint);
681   cp  = ON_SAME_STRAND(p - 1, p, cutpoint);
682   cq  = ON_SAME_STRAND(q, q + 1, cutpoint);
683 
684   d3    = ci  ? P->dangle3[type][si1]   : 0;
685   d5    = cj  ? P->dangle5[type][sj1]   : 0;
686   d5_2  = cp  ? P->dangle5[type_2][sp1] : 0;
687   d3_2  = cq  ? P->dangle3[type_2][sq1] : 0;
688 
689   tmm   = (cj && ci) ? P->mismatchExt[type][sj1][si1]   : d5 + d3;
690   tmm_2 = (cp && cq) ? P->mismatchExt[type_2][sp1][sq1] : d5_2 + d3_2;
691 
692   if (dangles == 2)
693     return energy + tmm + tmm_2;
694 
695   /* now we may have non-double dangles only */
696   if (p - i > 2) {
697     if (j - q > 2) {
698       /* all degrees of freedom */
699       e = MIN2(tmm, d5);
700       e = MIN2(e, d3);
701       energy += e;
702       e = MIN2(tmm_2, d5_2);
703       e = MIN2(e, d3_2);
704       energy += e;
705     } else if (j - q == 2) {
706       /* all degrees of freedom in 5' part between i and p */
707       e = MIN2(tmm + d5_2, d3 + d5_2);
708       e = MIN2(e, d5 + d5_2);
709       e = MIN2(e, d3 + tmm_2);
710       e = MIN2(e, d3 + d3_2);
711       e = MIN2(e, tmm_2); /* no dangles on enclosing pair */
712       e = MIN2(e, d5_2);  /* no dangles on enclosing pair */
713       e = MIN2(e, d3_2);  /* no dangles on enclosing pair */
714       energy += e;
715     } else {
716       /* no unpaired base between q and j */
717       energy += d3 + d5_2;
718     }
719   } else if (p - i == 2) {
720     if (j - q > 2) {
721       /* all degrees of freedom in 3' part between q and j */
722       e = MIN2(tmm + d3_2, d5 + d3_2);
723       e = MIN2(e, d5 + d3_2);
724       e = MIN2(e, d3 + d3_2);
725       e = MIN2(e, d5 + tmm_2);
726       e = MIN2(e, tmm_2);
727       e = MIN2(e, d5_2);
728       e = MIN2(e, d3_2);
729       energy += e;
730     } else if (j - q == 2) {
731       /* one possible dangling base between either side */
732       e = MIN2(tmm, tmm_2);
733       e = MIN2(e, d3);
734       e = MIN2(e, d5);
735       e = MIN2(e, d5_2);
736       e = MIN2(e, d3_2);
737       e = MIN2(e, d3 + d3_2);
738       e = MIN2(e, d5 + d5_2);
739       energy += e;
740     } else {
741       /* one unpaired base between i and p */
742       energy += MIN2(d3, d5_2);
743     }
744   } else {
745     /* no unpaired base between i and p */
746     if (j - q > 2) {
747       /* all degrees of freedom in 3' part between q and j */
748       energy += d5 + d3_2;
749     } else if (j - q == 2) {
750       /* one unpaired base between q and j */
751       energy += MIN2(d5, d3_2);
752     }
753   }
754 
755   return energy;
756 }
757 
758 
759 /**
760  * @}
761  */
762 
763 #endif
764 
765 #endif
766