source: tags/arb-6.0/PRIMER_DESIGN/PRD_Design.cxx

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