source: tags/cvs_2_svn/PRIMER_DESIGN/PRD_Design.cxx

Last change on this file was 5428, checked in by westram, 16 years ago
  • fixed includes for gcc 4.3.1
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.0 KB
Line 
1#ifndef   PRD_GLOBALS_HXX
2#include "PRD_Globals.hxx"
3#endif
4
5#include "PRD_Design.hxx"
6#include "PRD_SequenceIterator.hxx"
7#include "PRD_SearchFIFO.hxx"
8
9#include <iostream>
10
11#include <cstdio>
12#include <cstdlib>
13#include <cmath>
14
15// using namespace std; (does not work well with Solaris CC)
16using std::printf;
17using std::deque;
18using std::cout;
19using std::endl;
20using std::pair;
21
22//
23// Constructor
24//
25void PrimerDesign::init ( const char *sequence_, long int seqLength_,
26                          Range pos1_, Range pos2_, Range length_, Range distance_,
27                          Range ratio_, Range temperature_, int min_dist_to_next_, bool expand_IUPAC_Codes_,
28                          int   max_count_primerpairs_, double GC_factor_, double temp_factor_ )
29{
30    error     = 0;
31    sequence  = sequence_;
32    seqLength = seqLength_;
33    root1     = 0;
34    root2     = 0;
35    list1     = 0;
36    list2     = 0;
37    pairs     = 0;
38
39    show_status_txt    = 0;
40    show_status_double = 0;
41
42    setPositionalParameters ( pos1_, pos2_, length_, distance_ );
43    setConditionalParameters( ratio_, temperature_, min_dist_to_next_, expand_IUPAC_Codes_, max_count_primerpairs_, GC_factor_, temp_factor_ );
44}
45
46PrimerDesign::PrimerDesign( const char *sequence_, long int seqLength_,
47                            Range pos1_, Range pos2_, Range length_, Range distance_,
48                            Range ratio_, Range temperature_, int min_dist_to_next_, bool expand_IUPAC_Codes_,
49                            int   max_count_primerpairs_, double GC_factor_, double temp_factor_ )
50{
51    init ( sequence_, seqLength_, pos1_, pos2_, length_, distance_, ratio_, temperature_, min_dist_to_next_, expand_IUPAC_Codes_, max_count_primerpairs_, GC_factor_, temp_factor_ );
52}
53
54
55PrimerDesign::PrimerDesign( const char *sequence_, long int seqLength_,
56                            Range pos1_, Range pos2_, Range length_, Range distance_, int max_count_primerpairs_, double GC_factor_, double temp_factor_ )
57{
58    init ( sequence_, seqLength_, pos1_, pos2_, length_, distance_, Range(0,0), Range(0,0), -1, false, max_count_primerpairs_, GC_factor_, temp_factor_ );
59}
60
61
62PrimerDesign::PrimerDesign( const char *sequence_ , long int seqLength_)
63{
64    init ( sequence_, seqLength_, Range(0,0), Range(0,0), Range(0,0), Range(0,0), Range(0,0), Range(0,0), -1, false, 10, 0.5, 0.5 );
65}
66
67
68//
69// Destructor
70//
71PrimerDesign::~PrimerDesign ()
72{
73    if ( root1 ) delete root1;
74    if ( root2 ) delete root2;
75    if ( list1 ) delete list1;
76    if ( list2 ) delete list2;
77    if ( pairs ) delete [] pairs;
78}
79
80
81void PrimerDesign::setPositionalParameters( Range pos1_, Range pos2_, Range length_, Range distance_ )
82{
83    // first take all parameters, then test em
84    primer1         = (pos1_.min() < pos2_.min()) ? pos1_ : pos2_;
85    primer2         = (pos1_.min() < pos2_.min()) ? pos2_ : pos1_;
86    primer_length   = length_;
87    primer_distance = distance_;
88
89    // length > 0
90    if ( (length_.min() <= 0) || (length_.max() <= 0)  ) {
91        error = "invalid primer length (length <= 0)";
92        return;
93    }
94
95    // determine end of ranges
96    SequenceIterator *i = new SequenceIterator( sequence, primer1.min(), SequenceIterator::IGNORE, primer1.max(), SequenceIterator::FORWARD );
97    while ( i->nextBase() != SequenceIterator::EOS ) ;
98    primer1.max( i->pos );
99    i->restart( primer2.min(), SequenceIterator::IGNORE, primer2.max(), SequenceIterator::FORWARD );
100    while ( i->nextBase() != SequenceIterator::EOS ) ;
101    primer2.max( i->pos );
102
103    // primer1.max > primer2_.min =>  distance must be given
104    if ( (primer2.min() <= primer1.max()) && (distance_.min() <= 0) ) {
105        error = "using overlapping primer positions you MUST give a primer distance";
106        return;
107    }
108
109    // use distance-parameter ? (-1 = no)
110    if ( distance_.min() > 0 ) {
111        // pos2_.max - pos1_.min must be greater than distance_.min
112        if ( distance_.min() > primer2.max() - primer1.min() ) {
113            error = "invalid minimal primer distance (more than right.max - left.min)";
114            return;
115        }
116        // pos2_.min - pos1_.max must be less than distance_.max
117        if ( distance_.max() < primer2.min() - primer1.max() ) {
118            error = "invalid maximal primer distance (less than right.min - left.max)";
119            return;
120        }
121    }
122}
123
124
125void  PrimerDesign::setConditionalParameters( Range ratio_, Range temperature_, int min_dist_to_next_, bool expand_IUPAC_Codes_, int max_count_primerpairs_, double GC_factor_, double temp_factor_ )
126{
127    if ( (ratio_.min() < 0) || (ratio_.max() <= 0) )
128        GC_ratio = Range(-1,-1);
129    else
130        GC_ratio = ratio_;
131
132    if ( (temperature_.min() <= 0) || (temperature_.max() <= 0) )
133        temperature = Range (-1,-1);
134    else
135        temperature = temperature_;
136
137    GC_factor                  = GC_factor_;
138    temperature_factor         = temp_factor_;
139    min_distance_to_next_match = min_dist_to_next_;
140    expand_IUPAC_Codes         = expand_IUPAC_Codes_;
141    max_count_primerpairs      = max_count_primerpairs_;
142
143    if ( pairs ) delete [] pairs;
144    pairs = new Pair[ max_count_primerpairs ];
145}
146
147
148//
149// run the necessary steps .. abort on error
150//
151void PrimerDesign::run ( int print_stages_ )
152{
153#if defined(DEBUG)
154    printf("PrimerDesign : parameters are\n");
155    primer1.print("left                    : ","\n");
156    primer2.print("right                   : ","\n");
157    primer_length.print("length                  : ","\n");
158    primer_distance.print("distance                : ","\n");
159    GC_ratio.print("GC ratio                : ","\n");
160    temperature.print("temperature             : ","\n");
161    printf("GC factor               : %f\n",GC_factor);
162    printf("temp. factor            : %f\n",temperature_factor);
163    printf("min. dist to next match : %i\n",min_distance_to_next_match);
164    printf("expand IUPAC            : %s\n", expand_IUPAC_Codes ? "true" : "false");
165    printf("error                   : %s\n",error );
166#endif
167
168    if ( error ) {
169        printf( "not run cause : %s\n",error );
170        return;
171    }
172
173#if defined(DEBUG)
174    printf("sizeof(Node) = %zu\n", sizeof(Node));
175#endif // DEBUG
176
177    show_status("searching possible primers");
178    buildPrimerTrees();
179    if ( error ) return;
180    if ( print_stages_ & PRINT_RAW_TREES ) printPrimerTrees();
181
182    show_status("match possible primers vs. sequence");
183    matchSequenceAgainstPrimerTrees();
184    if ( error ) return;
185    if ( print_stages_ & PRINT_MATCHED_TREES ) printPrimerTrees();
186
187    show_status("evaluating primer pairs"); show_status(0.0);
188    convertTreesToLists();
189    if ( error ) return;
190    if ( print_stages_ & PRINT_PRIMER_LISTS ) printPrimerLists();
191
192    evaluatePrimerPairs();
193    if ( error ) return;
194    if ( print_stages_ & PRINT_PRIMER_PAIRS ) printPrimerPairs();
195}
196
197//
198// (re)construct raw primer trees
199//
200
201// add new child to parent or update existing child
202// returns child_index
203int PrimerDesign::insertNode ( Node *current_, unsigned char base_, PRD_Sequence_Pos pos_, int delivered_, int offset_, int left_, int right_ )
204{
205    int  index     = CHAR2CHILD.INDEX[ base_ ];
206    bool is_primer = primer_length.includes( delivered_ ); // new child is primer if true
207
208    //
209    // create new node if necessary or update existing node if its a primer
210    //
211    if ( current_->child[index] == NULL ) {
212        total_node_counter_left  += left_;
213        total_node_counter_right += right_;
214
215        if ( is_primer ) {
216            current_->child[index]     = new Node ( current_,base_,pos_,offset_ ); // primer => new child with positive last_base_index
217            primer_node_counter_left  += left_;
218            primer_node_counter_right += right_;
219        } else {
220            current_->child[index] = new Node ( current_,base_,0 ); // no primer => new child with zero position
221
222        }
223        current_->child_bits |= CHAR2BIT.FIELD[ base_ ];                            // update child_bits of current node
224    }
225    else {
226        if ( is_primer ) {
227            current_->child[index]->last_base_index = -pos_;                          // primer, but already exists => set pos to negative
228            primer_node_counter_left  -= left_;
229            primer_node_counter_right -= right_;
230        }
231    }
232
233    return index;
234}
235
236// check if (sub)tree contains a valid primer
237bool PrimerDesign::treeContainsPrimer ( Node *start )
238{
239    if ( start->isValidPrimer() ) return true;
240
241    for ( int i = 0; i < 4; i++ ) {
242        if ( start->child[i] != NULL ) {
243            if ( treeContainsPrimer( start->child[i] ) ) return true;
244        }
245    }
246
247    return false;
248}
249
250// remove non-primer-leaves and branches from the tree
251void PrimerDesign::clearTree ( Node *start, int left_, int right_ )
252{
253    // check children
254    for ( int i = 0; i < 4; i++ )
255        if ( start->child[i] != NULL ) clearTree( start->child[i], left_, right_ );
256
257    // check self
258    if ( start->isLeaf() && (!start->isValidPrimer()) && (start->parent != NULL) ) {
259        total_node_counter_left   -= left_;
260        total_node_counter_right  -= right_;
261
262        // remove self from parent
263        start->parent->child[ CHAR2CHILD.INDEX[ start->base ] ] = NULL;
264        start->parent->child_bits &= ~CHAR2BIT.FIELD[ start->base ];
265
266        // erase node
267        delete start;
268    }
269}
270
271void PrimerDesign::buildPrimerTrees ()
272{
273#if defined(DEBUG)
274    primer1.print("buildPrimerTrees : pos1\t\t","\n");
275    primer2.print("buildPrimerTrees : pos2\t\t","\n");
276    primer_length.print("buildPrimerTrees : length\t","\n");
277    //    printf("buildPrimerTrees : 0123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789\n");
278    //    printf("buildPrimerTrees : %s\n",sequence);
279    printf("buildPrimerTrees : (pos,base,delivered,last_base_index)\n" );
280#endif
281
282    //
283    // destroy old trees if exist
284    //
285    if (root1) delete root1;
286    if (root2) delete root2;
287    root1 = new Node();
288    root2 = new Node();
289    total_node_counter_left   = 0;
290    total_node_counter_right  = 0;
291    primer_node_counter_left  = 0;
292    primer_node_counter_right = 0;
293
294    //
295    // init iterator with sequence
296    //
297    SequenceIterator *sequence_iterator = new SequenceIterator( sequence );
298    char  base;
299    int   child_index;
300    Node *current_node;
301    int   offset = 0;
302
303    //
304    // init. offset-counter
305    //
306    sequence_iterator->restart( 0,primer1.min(),SequenceIterator::IGNORE,SequenceIterator::FORWARD );   // start at 1st absolute pos in aligned seq.
307    while ( sequence_iterator->nextBase() != SequenceIterator::EOS )                                    // count bases till left range
308        offset++;
309
310    //
311    // build first tree
312    //
313    long int primer1_length = primer1.max()-primer1.min()+1;
314    show_status("searching possible primers -- left");
315
316    for ( PRD_Sequence_Pos start_pos = primer1.min();
317          (start_pos < primer1.max()-primer_length.min()) && (sequence[start_pos] != '\x00');
318          start_pos++ ) {
319
320        show_status((double)(start_pos-primer1.min())/primer1_length/2);
321
322        // start iterator at new position
323        sequence_iterator->restart( start_pos,primer1.max(),primer_length.max(),SequenceIterator::FORWARD );
324        sequence_iterator->nextBase();
325        if ( sequence_iterator->pos != start_pos ) { // sequence_iterator has skipped spaces = > restart at first valid base
326            start_pos                                                                        = sequence_iterator->pos;
327        }
328        sequence_iterator->restart( start_pos,primer1.max(),primer_length.max(),SequenceIterator::FORWARD );
329
330        // start at top of tree
331        current_node = root1;
332
333        // iterate through sequence till end-of-sequence or primer_length.max bases read
334        base = sequence_iterator->nextBase();
335        while ( base != SequenceIterator::EOS ) {
336            if (! ((base == 'A') || (base == 'T') || (base == 'U') || (base == 'C') || (base == 'G')) ) break; // stop at IUPAC-Codes
337            child_index  = insertNode( current_node, base, sequence_iterator->pos, sequence_iterator->delivered, offset, 1,0 );
338            current_node = current_node->child[child_index];
339
340            // get next base
341            base = sequence_iterator->nextBase();
342        }
343
344        offset++;
345    }
346
347    //
348    // clear left tree
349    //
350#if defined(DEBUG)
351    printf ("           %li nodes left (%li primers)   %li nodes right (%li primers)\n", total_node_counter_left, primer_node_counter_left, total_node_counter_right, primer_node_counter_right );
352    printf ("           clearing left tree\n" );
353#endif
354    show_status("clearing left primertree");
355    clearTree( root1, 1, 0 );
356#if defined(DEBUG)
357    printf ("           %li nodes left (%li primers)   %li nodes right (%li primers)\n", total_node_counter_left, primer_node_counter_left, total_node_counter_right, primer_node_counter_right );
358#endif
359
360    //
361    // count bases till right range
362    //
363    sequence_iterator->restart( sequence_iterator->pos, primer2.min(),SequenceIterator::IGNORE,SequenceIterator::FORWARD ); // run from current pos
364    while ( sequence_iterator->nextBase() != SequenceIterator::EOS )                                                      // till begin of right range
365        offset++;
366
367    if ( !treeContainsPrimer( root1 ) ) {
368        error = "no primer in left range found .. maybe only spaces in that range ?";
369        delete sequence_iterator;
370        return;
371    }
372
373    //
374    // build second tree
375    //
376    long int primer2_length = primer2.max()-primer2.min()+1;
377    show_status("searching possible primers -- right");
378
379    for ( PRD_Sequence_Pos start_pos = primer2.min();
380          (start_pos < primer2.max()-primer_length.min()) && (sequence[start_pos] != '\x00');
381          start_pos++ ) {
382
383        show_status((double)(start_pos-primer2.min())/primer2_length/2+0.5);
384
385        // start iterator at new position
386        sequence_iterator->restart( start_pos,primer2.max(),primer_length.max(),SequenceIterator::FORWARD );
387        sequence_iterator->nextBase();
388        if ( sequence_iterator->pos != start_pos ) { // sequence_iterator has skipped spaces = > restart at first valid base
389            start_pos                                                                        = sequence_iterator->pos;
390        }
391        sequence_iterator->restart( start_pos,primer2.max(),primer_length.max(),SequenceIterator::FORWARD );
392
393        // start at top of tree
394        current_node = root2;
395
396        // iterate through sequence till end-of-sequence or primer_length.max bases read
397        base = sequence_iterator->nextBase();
398        while ( base != SequenceIterator::EOS ) {
399            if (! ((base == 'A') || (base == 'T') || (base == 'U') || (base == 'C') || (base == 'G')) ) break; // stop at unsure bases
400            child_index = insertNode( current_node, base, sequence_iterator->pos, sequence_iterator->delivered, offset+sequence_iterator->delivered, 0,1 );
401            current_node = current_node->child[child_index];
402
403            // get next base
404            base = sequence_iterator->nextBase();
405        }
406
407        offset++;
408    }
409
410    if ( !treeContainsPrimer( root2 ) ) {
411        error = "no primer in right range found .. maybe only spaces in that range ?";
412    }
413
414    delete sequence_iterator;
415
416    //
417    // clear left tree
418    //
419#if defined(DEBUG)
420    printf ("           %li nodes left (%li primers)   %li nodes right (%li primers)\n", total_node_counter_left, primer_node_counter_left, total_node_counter_right, primer_node_counter_right );
421    printf ("           clearing right tree\n" );
422#endif
423    show_status("clearing right primertree");
424    clearTree( root2, 0, 1 );
425#if defined(DEBUG)
426    printf ("           %li nodes left (%li primers)   %li nodes right (%li primers)\n", total_node_counter_left, primer_node_counter_left, total_node_counter_right, primer_node_counter_right );
427#endif
428}
429
430
431//
432// print all primers in trees
433//
434PRD_Sequence_Pos PrimerDesign::followUp( Node *node_, deque<char> *primer_, int direction_ )
435{
436    if ( direction_ == FORWARD ) primer_->push_front( node_->base );
437    else primer_->push_back( node_->base );
438
439    if ( node_->parent == NULL ) return node_->last_base_index;
440    else followUp( node_->parent, primer_, direction_ );
441    return 0;
442}
443
444void PrimerDesign::findNextPrimer( Node *start_at_, int depth_, int *counter_, int direction_ )
445{
446    // current node
447    printf (  "findNextPrimer : start_at_ [ %c,%4li,%2i (%c %c %c %c) ]\n",
448              start_at_->base,
449              start_at_->last_base_index,
450              start_at_->child_bits,
451              (start_at_->child[1] != NULL) ? 'G' : ' ',
452              (start_at_->child[0] != NULL) ? 'C' : ' ',
453              (start_at_->child[3] != NULL) ? 'T' : ' ',
454              (start_at_->child[2] != NULL) ? 'X' : ' ' );
455    if ( primer_length.includes(depth_) && start_at_->isValidPrimer() )
456        //   {
457        //     (*counter_)++;
458        //     printf( "findNextPrimer : %3i",depth_ );
459
460        //     // print last_base_indizes
461        //     if ( direction_ == FORWARD ) printf( "%7li           ",start_at_->last_base_index );
462        //                             else printf( "      0           " );
463
464        //     // print bases
465        //     deque<char> primer;
466        //     if ( direction_ == FORWARD )
467        //     {
468        //       printf( "%7li               '",followUp( start_at_, &primer, direction_ ) );
469        //       primer.pop_front();                                                     // erase 'base' of root-node
470        //     }
471        //     else
472        //     {
473        //       printf( "%7li               '",start_at_->last_base_index );
474        //       followUp( start_at_, &primer, direction_ );
475        //       primer.pop_back();                                                      // erase 'base' of root-node
476        //     }
477        //     copy( primer.begin(), primer.end(), ostream_iterator<char>(cout) );
478        //     printf( "'\n" );
479        //   }
480
481        // children
482        depth_++;
483    for ( int i=0; i < 4; i++ )
484        if ( start_at_->child[i] != NULL ) findNextPrimer( start_at_->child[i],  depth_, counter_, direction_ );
485}
486
487void PrimerDesign::printPrimerTrees ()
488{
489    // start at root1 with zero depth
490    int primer_counter;
491    primer_counter = 0;
492    cout << "findNextPrimer : depth  last_base:index  first_base:index  base" << endl;
493    findNextPrimer( root1,0, &primer_counter, FORWARD );
494    cout << "printPrimerTrees : " << primer_counter << " primer found" << endl << endl;
495
496    // start at root2 with zero depth
497    primer_counter = 0;
498    cout << "findNextPrimer : depth  last_base:index  first_base:index  base" << endl;
499    findNextPrimer( root2,0, &primer_counter, BACKWARD );
500    cout << "printPrimerTrees : " << primer_counter << " primer found" << endl;
501}
502
503
504//
505// match the sequence against the primer-trees
506//
507void PrimerDesign::matchSequenceAgainstPrimerTrees()
508{
509    SearchFIFO       *fifo1             = new SearchFIFO( root1,min_distance_to_next_match,expand_IUPAC_Codes );
510    SearchFIFO       *fifo2             = new SearchFIFO( root2,min_distance_to_next_match,expand_IUPAC_Codes );
511    SequenceIterator *sequence_iterator = new SequenceIterator( sequence,0,SequenceIterator::IGNORE,SequenceIterator::IGNORE,SequenceIterator::FORWARD );
512    char              base;
513    PRD_Sequence_Pos  pos               = sequence_iterator->pos;
514
515#if defined(DEBUG)
516    printf( "root1 : [C %p, G %p, A %p, TU %p]\n",root1->child[0],root1->child[1],root1->child[2],root1->child[3] );
517    printf( "root2 : [C %p, G %p, A %p, TU %p]\n",root2->child[0],root2->child[1],root2->child[2],root2->child[3] );
518#endif
519
520    show_status("match possible primers vs. seq. (forward)");
521    base    = sequence_iterator->nextBase();
522    while ( base != SequenceIterator::EOS ) {
523        pos = sequence_iterator->pos;
524
525        if ((pos&0x7f) == 0) {
526            show_status((double)pos/seqLength/2);
527        }
528
529        // tree/fifo 1
530        if ( primer1.includes( pos ) ) { // flush fifo1 if in range of Primer 1
531            fifo1->flush();
532        }
533        else {
534            // iterate through fifo1
535            fifo1->iterateWith( pos,base );
536
537            // append base to fifo1
538            fifo1->push( pos );
539        }
540
541        // tree/fifo2
542        if ( primer2.includes( pos ) ) { // flush fifo2 if in range of Primer 2
543            fifo2->flush();
544        }
545        else {
546            // iterate through fifo2
547            fifo2->iterateWith( pos,base );
548
549            // append base to fifo2
550            fifo2->push( pos );
551        }
552
553        // get next base in sequence
554        base = sequence_iterator->nextBase();
555    }
556
557    sequence_iterator->restart( pos, 0, SequenceIterator::IGNORE, SequenceIterator::BACKWARD );
558    fifo1->flush();
559    fifo2->flush();
560
561    show_status("match possible primers vs. seq. (backward)");
562    base = INVERT.BASE[ sequence_iterator->nextBase() ];
563    while ( base != SequenceIterator::EOS ) {
564        pos = sequence_iterator->pos;
565
566        if ((pos&0x7f) == 0) {
567            show_status((double)(seqLength-pos)/seqLength/2+0.5);
568        }
569
570        // tree/fifo 1
571        if ( primer1.includes( pos ) ) { // flush fifo1 if in range of Primer 1
572            fifo1->flush();
573        }
574        else {
575            // iterate through fifo1
576            fifo1->iterateWith( pos,base );
577
578            // append base to fifo1
579            fifo1->push( pos );
580        }
581
582        // tree/fifo2
583        if ( primer2.includes( pos ) ) { // flush fifo2 if in range of Primer 2
584            fifo2->flush();
585        }
586        else {
587            // iterate through fifo2
588            fifo2->iterateWith( pos,base );
589
590            // append base to fifo2
591            fifo2->push( base );
592        }
593
594        // get next base in sequence
595        base = INVERT.BASE[ sequence_iterator->nextBase() ];
596    }
597
598    delete fifo1;
599    delete fifo2;
600    delete sequence_iterator;
601
602    if ( !treeContainsPrimer( root1 ) ) {
603        error = "no primer in left range after match vs. sequence .. maybe some clustered IUPAC-Codes in sequence ?";
604        return;
605    }
606
607    if ( !treeContainsPrimer( root2 ) ) {
608        error = "no primer in right range after match vs. sequence .. maybe some clustered IUPAC-Codes in sequence ?";
609    }
610}
611
612
613//
614// convertTreesToLists
615//
616// this also checks GC-ratio, temperature and distance
617//
618void PrimerDesign::calcGCandAT ( int &GC_, int &AT_, Node *start_at_ )
619{
620    if ( start_at_ == NULL ) return;
621
622    if ( (start_at_->base == 'C') || (start_at_->base == 'G') )
623        GC_++;
624    else
625        AT_++;
626
627    calcGCandAT( GC_, AT_, start_at_->parent );
628}
629
630void PrimerDesign::convertTreesToLists ()
631{
632#ifdef DEBUG
633    GC_ratio.print( "convertTreesToLists : GC_ratio ","  " );
634    temperature.print( "temperature ","  " );
635    primer_distance.print( "primer_distance ","\n" );
636#endif
637
638    Node             *cur_node;
639    Item             *cur_item;
640    Item             *new_item;
641    int               depth;
642    int               AT;
643    int               GC;
644    bool              GC_and_temperature_matched;
645    PRD_Sequence_Pos  min_offset_1 = PRD_MAX_SEQUENCE_POS;
646    PRD_Sequence_Pos  max_offset_1 = -1;
647    PRD_Sequence_Pos  min_offset_2 = PRD_MAX_SEQUENCE_POS;
648    PRD_Sequence_Pos  max_offset_2 = -1;
649    pair< Node*,int > new_pair;      // < cur_node->child[i], depth >
650    deque< pair<Node*,int> > *stack;
651
652    //
653    // list 1
654    //
655    cur_item = NULL;
656    stack = new deque< pair<Node*,int> >;
657    // push children of root on stack
658    for ( int index = 0; index < 4; index++ )
659        if ( root1->child[index] != NULL ) {
660            new_pair = pair<Node*,int>( root1->child[index],1 );
661            stack->push_back( new_pair );
662        }
663
664    if ( !stack->empty() ) {
665        GC_and_temperature_matched = false;
666
667        while ( !stack->empty() ) {
668            // next node
669            cur_node = stack->back().first;
670            depth    = stack->back().second;
671            stack->pop_back();
672
673            // handle node
674            if ( primer_length.includes(depth) && cur_node->isValidPrimer() ) {
675                // calculate conditional parameters
676                GC = AT = 0;
677                calcGCandAT( GC, AT, cur_node );
678                AT = 4*GC + 2*AT;
679                GC = (GC * 100) / depth;
680
681                // create new item if conditional parameters are in range
682                if ( GC_ratio.includes(GC) && temperature.includes(AT) ) {
683                    GC_and_temperature_matched = true;
684                    new_item = new Item( cur_node->last_base_index, cur_node->offset, depth, GC, AT, NULL );
685
686                    // begin list with new item or append to list
687                    if ( cur_item == NULL ) list1          = new_item;
688                    else cur_item->next = new_item;
689
690                    cur_item = new_item;
691
692                    // store position
693                    if ( cur_node->offset < min_offset_1 ) min_offset_1 = cur_node->offset;
694                    if ( cur_node->offset > max_offset_1 ) max_offset_1 = cur_node->offset;
695                }
696            }
697
698            // push children on stack
699            for ( int index = 0; index < 4; index++ )
700                if ( cur_node->child[index] != NULL ) {
701                    new_pair = pair<Node*,int>( cur_node->child[index],depth+1 );
702                    stack->push_back( new_pair );
703                }
704        }
705        if ( !GC_and_temperature_matched ) {
706            error = "no primer over left range matched the given GC-Ratio/Temperature";
707            delete stack;
708            return;
709        }
710    }
711    else {
712        error = "convertTreesToLists : primertree over left range was empty :( ?";
713        delete stack;
714        return;
715    }
716
717#if defined(DEBUG)
718    printf( "convertTreesToLists : list1 : min_offset %7li  max_offset %7li\n", min_offset_1, max_offset_1 );
719#endif
720
721    //
722    // list 2
723    //
724    cur_item = NULL;
725    stack->clear();
726    bool distance_matched = false;
727    // push children of root on stack
728    for ( int index = 0; index < 4; index++ )
729        if ( root2->child[index] != NULL )
730        {
731            new_pair = pair<Node*,int>( root2->child[index],1 );
732            stack->push_back( new_pair );
733        }
734
735    if ( !stack->empty() ) {
736        GC_and_temperature_matched = false;
737
738        while ( !stack->empty() ) {
739            // next node
740            cur_node = stack->back().first;
741            depth    = stack->back().second;
742            stack->pop_back();
743
744            // push children on stack
745            for ( int index = 0; index < 4; index++ )
746                if ( cur_node->child[index] != NULL ) {
747                    new_pair = pair<Node*,int>( cur_node->child[index],depth+1 );
748                    stack->push_back( new_pair );
749                }
750
751            // handle node
752            if ( primer_length.includes(depth) && cur_node->isValidPrimer() ) {
753                // check position
754                if ( primer_distance.min() > 0 ) {
755                    distance_matched = primer_distance.includes( cur_node->offset-max_offset_1, cur_node->offset-min_offset_1 );
756                    if ( !distance_matched ) continue;
757                }
758
759                // calculate conditional parameters
760                GC = AT = 0;
761                calcGCandAT( GC, AT, cur_node );
762                AT = 4*GC + 2*AT;
763                GC = (GC * 100) / depth;
764
765                // create new item if conditional parameters are in range
766                if ( GC_ratio.includes(GC) && temperature.includes(AT) ) {
767                    GC_and_temperature_matched = true;
768                    new_item = new Item( cur_node->last_base_index, cur_node->offset, depth, GC, AT, NULL );
769
770                    // begin list with new item or append to list
771                    if ( cur_item == NULL ) list2          = new_item;
772                    else cur_item->next = new_item;
773
774                    cur_item = new_item;
775
776                    // store position
777                    if ( cur_node->offset < min_offset_2 ) min_offset_2 = cur_node->offset;
778                    if ( cur_node->offset > max_offset_2 ) max_offset_2 = cur_node->offset;
779                }
780            }
781        }
782
783        if ( primer_distance.min() > 0 ) {
784            if ( !distance_matched ) {
785                error = "no primer over right range was in reach of primers in left range .. check distance parameter";
786                delete stack;
787                return;
788            }
789        }
790
791        if ( !GC_and_temperature_matched ) {
792            error = "no primer over right range matched the given GC-Ratio and Temperature";
793            delete stack;
794            return;
795        }
796    }
797    else {
798        error = "convertTreesToLists : primertree over right range was empty :( ?";
799        delete stack;
800        return;
801    }
802
803    delete stack;
804
805#if defined(DEBUG)
806    printf( "convertTreesToLists : list2 : min_offset %7li  max_offset %7li\n", min_offset_2, max_offset_2 );
807#endif
808
809    //
810    // check positions of list1
811    //
812    if ( primer_distance.min() > 0 ) {  // skip check if primer_distance < 0
813        Item *to_remove = NULL;
814        cur_item = list1;
815
816        while ( cur_item != NULL ) {
817            if ( !primer_distance.includes( max_offset_2-cur_item->offset, min_offset_2-cur_item->offset ) ) {
818                // primer in list 1 out of range of primers in list 2 => remove from list 1
819
820                if ( cur_item == list1 ) {
821                    // 'to delete'-item is first in list
822                    list1 = list1->next;                                // list 1 starts with next item
823                    delete cur_item;                            // delete former first item
824                    cur_item = list1;                           // new first item is next to be examined
825                }
826                else {
827                    // run through list till 'next' is to delete
828                    to_remove = cur_item;                               // remember 'to delete'-item
829                    cur_item  = list1;                          // start at first
830                    while ( cur_item ->next != to_remove )      // run till 'next' is 'to delete'
831                        cur_item = cur_item->next;
832                    cur_item->next = cur_item->next->next;      // unlink 'next' from list
833                    cur_item = cur_item->next;                  // 'next' of 'to delete' is next to be examined
834                    delete to_remove;                           // ...
835                }
836            }
837            else
838                cur_item = cur_item->next;
839        }
840
841        int counter = 0;
842        for ( cur_item = list1; cur_item != NULL; cur_item = cur_item->next )
843            counter++;
844        if ( counter == 0 ) {
845            error = "no primers over left range are in reach of primers over right range .. check distance parameter";
846            return;
847        }
848    }
849
850    int counter = 0;
851    for ( cur_item = list1; cur_item != NULL; cur_item = cur_item->next )
852        counter++;
853    if ( counter == 0 ) {
854        error = "no primers left in left range after GC-ratio/Temperature/Distance - Check";
855        return;
856    }
857
858    counter = 0;
859    for ( cur_item = list2; cur_item != NULL; cur_item = cur_item->next )
860        counter++;
861    if ( counter == 0 ) {
862        error = "no primers left in right range after GC-ratio/Temperature/Distance - Check";
863        return;
864    }
865}
866
867
868//
869// printPrimerLists
870//
871void PrimerDesign::printPrimerLists ()
872{
873    int count = 0;
874
875    printf( "printPrimerLists : list 1 : [(start_pos,offset,length), GC_ratio, temperature]\n" );
876    Item *current = list1;
877    while ( current != NULL ) {
878        current->print( "","\n" );
879        current = current->next;
880        count++;
881    }
882    printf( " : %i valid primers\nprintPrimerLists : list 2 : [(start_pos,offset,length), GC_ratio, temperature]\n", count );
883    count = 0;
884    current = list2;
885    while ( current != NULL ) {
886        current->print( "","\n" );
887        current = current->next;
888        count++;
889    }
890    printf( " : %i valid primers\n", count );
891}
892
893
894
895//
896// evaluatePrimerPairs
897//
898inline double PrimerDesign::evaluatePair ( Item *one_, Item *two_ )
899{
900    if ( (one_ == NULL) || (two_ == NULL) )
901        return -1.0;
902
903    return abs(one_->GC_ratio - two_->GC_ratio)*GC_factor + abs(one_->temperature - two_->temperature)*temperature_factor;
904}
905
906void PrimerDesign::insertPair( double rating_, Item *one_, Item *two_ )
907{
908    int index = -1;
909
910    // search position
911    for ( int i = max_count_primerpairs-1; (i >= 0) && (index == -1); i-- )
912    {
913        // maybe insert new pair ?
914        if ( pairs[i].rating >= rating_)
915            index = i+1;
916    }
917
918    if ( index == -1 ) index = 0;
919
920    // swap till position
921    for ( int i = max_count_primerpairs-2; i >= index; i--) {
922        pairs[i+1].rating = pairs[i].rating;
923        pairs[i+1].one    = pairs[i].one;
924        pairs[i+1].two    = pairs[i].two;
925    }
926
927    // insert new values
928    pairs[index].rating = rating_;
929    pairs[index].one    = one_;
930    pairs[index].two    = two_;
931
932#if defined(DEBUG)
933    printf( "insertPair : [%3i] %6.2f\n", index, rating_ );
934#endif
935}
936
937void PrimerDesign::evaluatePrimerPairs ()
938{
939    Item    *one = list1;
940    Item    *two;
941    double   rating;
942    long int counter = 0;
943
944#ifdef DEBUG
945    printf ( "evaluatePrimerPairs : ...\ninsertPair : [index], rating\n" );
946#endif
947
948    show_status("evaluating primer pairs");
949    int list1_elems = 0;
950    int elems       = 0;
951    while (one) {
952        list1_elems++;
953        one = one->next;
954    }
955    one = list1;
956
957    // outer loop <= > run through list1
958    while ( one != NULL )
959    {
960        show_status(GBS_global_string("evaluating primer pairs (%6.3f)", pairs[0].rating));
961        show_status((double)elems/list1_elems);
962        elems++;
963
964        // inner loop <= > run through list2
965        two            = list2;
966        while ( two != NULL )
967        {
968            // evaluate pair
969            rating = evaluatePair( one, two );
970
971            // test if rating is besster that the worst of the best
972            if ( rating > pairs[max_count_primerpairs-1].rating )
973            {
974                // insert in the pairs
975                insertPair( rating, one, two );
976                counter++;
977            }
978
979            // next in inner loop
980            two = two->next;
981        }
982
983        // next in outer loop
984        one = one->next;
985    }
986
987    if ( counter == 0 ) error = "no primer pair could be found, sorry :(";
988
989#ifdef DEBUG
990    printf ( "evaluatePrimerPairs : ratings [ %.3f .. %.3f ]\n\n", pairs[max_count_primerpairs-1].rating, pairs[0].rating );
991#endif
992}
993
994void PrimerDesign::printPrimerPairs ()
995{
996#ifdef DEBUG
997    printf ( "printPairs [index] [rating ( primer1[(start_pos,offset,length),(GC,temp)] , primer2[(pos,offs,len),(GC,temp)])] \n" );
998#endif
999    for (int i = 0; i < max_count_primerpairs; i++) {
1000        printf( "printPairs : [%3i]",i );
1001        pairs[i].print( "\t","\n",sequence );
1002    }
1003}
1004
1005//  ------------------------------------------------------------
1006//      const char *PrimerDesign::get_result(int num) const
1007//  ------------------------------------------------------------
1008const char *PrimerDesign::get_result( int num, const char *&primers, int max_primer_length, int max_position_length, int max_length_length )  const
1009{
1010    if ( (num < 0) || (num >= max_count_primerpairs) ) return 0;                // check for valid index
1011    if ( !pairs[num].one || !pairs[num].two )          return 0;                // check for valid items at given index
1012
1013    primers = pairs[num].get_primers( sequence );
1014    return pairs[num].get_result( sequence,  max_primer_length,  max_position_length,  max_length_length );
1015}
Note: See TracBrowser for help on using the repository browser.