source: tags/ms_r16q3/STAT/ST_ml.cxx

Last change on this file was 15176, checked in by westram, 8 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.2 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : ST_ml.cxx                                         //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "st_ml.hxx"
12#include "MostLikelySeq.hxx"
13
14#include <ColumnStat.hxx>
15#include <AP_filter.hxx>
16#include <AP_Tree.hxx>
17#include <arb_progress.h>
18#include <gui_aliview.hxx>
19#include <ad_cb.h>
20
21#include <cctype>
22#include <cmath>
23
24DNA_Table dna_table;
25
26DNA_Table::DNA_Table() {
27    int i;
28    for (i = 0; i < 256; i++) {
29        switch (toupper(i)) {
30            case 'A':
31                char_to_enum_table[i] = ST_A;
32                break;
33            case 'C':
34                char_to_enum_table[i] = ST_C;
35                break;
36            case 'G':
37                char_to_enum_table[i] = ST_G;
38                break;
39            case 'T':
40            case 'U':
41                char_to_enum_table[i] = ST_T;
42                break;
43            case '-':
44                char_to_enum_table[i] = ST_GAP;
45                break;
46            default:
47                char_to_enum_table[i] = ST_UNKNOWN;
48        }
49    }
50}
51
52// -----------------------
53//      ST_base_vector
54
55void ST_base_vector::setBase(const ST_base_vector& inv_frequencies, char base) {
56    base = toupper(base);
57   
58    memset((char *) &b[0], 0, sizeof(b));
59    DNA_Base     ub = dna_table.char_to_enum(base);
60
61    if (ub != ST_UNKNOWN) {
62        b[ub] = 1.0;                                // ill. access ?
63    }
64    else {
65        const double k = 1.0 / ST_MAX_BASE;
66        b[ST_A]   = k;
67        b[ST_C]   = k;
68        b[ST_G]   = k;
69        b[ST_T]   = k;
70        b[ST_GAP] = k;
71    }
72    for (int i = 0; i < ST_MAX_BASE; i++) {
73        b[i] *= inv_frequencies.b[i];
74    }
75    ld_lik = 0; // ? why not 1.0 ?
76    lik = 1.0;
77}
78
79inline void ST_base_vector::check_overflow() {
80    ST_FLOAT sum = summarize();
81
82    if (sum < .00001) {                             // what happend no data, extremely unlikely
83        setTo(0.25);                                // strange! shouldn't this be 1.0/ST_MAX_BASE ?
84        ld_lik -= 5;                                // ???
85    }
86    else {
87        while (sum < 0.25) {
88            sum    *= 4;
89            ld_lik -= 2;
90            multiplyWith(4);
91        }
92    }
93
94    if (ld_lik> 10000) printf("overflow\n");
95}
96
97inline ST_base_vector& ST_base_vector::operator*=(const ST_base_vector& other) {
98    b[ST_A]   *= other.b[ST_A];
99    b[ST_C]   *= other.b[ST_C];
100    b[ST_G]   *= other.b[ST_G];
101    b[ST_T]   *= other.b[ST_T];
102    b[ST_GAP] *= other.b[ST_GAP];
103   
104    ld_lik += other.ld_lik; // @@@ correct to use 'plus' here ? why ?
105    lik    *= other.lik;
106
107    return *this;
108}
109
110void ST_base_vector::print() {
111    int i;
112    for (i = 0; i < ST_MAX_BASE; i++) {
113        printf("%.3G ", b[i]);
114    }
115}
116
117// -----------------------
118//      ST_rate_matrix
119
120void ST_rate_matrix::set(double dist, double /* TT_ratio */) {
121    const double k = 1.0 / ST_MAX_BASE;
122    ST_FLOAT exp_dist = exp(-dist);
123
124    diag = k + (1.0 - k) * exp_dist;
125    rest = k - k * exp_dist;
126}
127
128void ST_rate_matrix::print() {
129    for (int i = 0; i < ST_MAX_BASE; i++) {
130        for (int j = 0; j < ST_MAX_BASE; j++) {
131            printf("%.3G ", i == j ? diag : rest);
132        }
133        printf("\n");
134    }
135}
136
137
138inline void ST_rate_matrix::transform(const ST_base_vector& in, ST_base_vector& out) const {
139    // optimized matrix/vector multiplication
140    // original version: http://bugs.arb-home.de/browser/trunk/STAT/ST_ml.cxx?rev=6403#L155
141
142    ST_FLOAT sum            = in.summarize();
143    ST_FLOAT diag_rest_diff = diag-rest;
144    ST_FLOAT sum_rest_prod  = sum*rest;
145
146    out.b[ST_A]   = in.b[ST_A]*diag_rest_diff + sum_rest_prod;
147    out.b[ST_C]   = in.b[ST_C]*diag_rest_diff + sum_rest_prod;
148    out.b[ST_G]   = in.b[ST_G]*diag_rest_diff + sum_rest_prod;
149    out.b[ST_T]   = in.b[ST_T]*diag_rest_diff + sum_rest_prod;
150    out.b[ST_GAP] = in.b[ST_GAP]*diag_rest_diff + sum_rest_prod;
151
152    out.ld_lik = in.ld_lik;
153    out.lik    = in.lik;
154}
155
156
157// -----------------------
158//      MostLikelySeq
159
160MostLikelySeq::MostLikelySeq(const AliView *aliview, ST_ML *st_ml_)
161    : AP_sequence(aliview)
162    , st_ml(st_ml_)
163    , sequence(new ST_base_vector[ST_MAX_SEQ_PART])
164    , up_to_date(false)
165    , color_out(NULL)
166    , color_out_valid_till(NULL)
167{
168}
169
170MostLikelySeq::~MostLikelySeq() {
171    delete [] sequence;
172    free(color_out);
173    free(color_out_valid_till);
174
175    unbind_from_species(true);
176}
177
178static void st_sequence_callback(GBDATA*, MostLikelySeq *seq) {
179    seq->sequence_change();
180}
181
182static void st_sequence_del_callback(GBDATA*, MostLikelySeq *seq) {
183    seq->unbind_from_species(false);
184}
185
186
187GB_ERROR MostLikelySeq::bind_to_species(GBDATA *gb_species) {
188    GB_ERROR error = AP_sequence::bind_to_species(gb_species);
189    if (!error) {
190        GBDATA *gb_seq = get_bound_species_data();
191        st_assert(gb_seq);
192
193        error             = GB_add_callback(gb_seq, GB_CB_CHANGED, makeDatabaseCallback(st_sequence_callback,     this));
194        if (!error) error = GB_add_callback(gb_seq, GB_CB_DELETE,  makeDatabaseCallback(st_sequence_del_callback, this));
195    }
196    return error;
197}
198void MostLikelySeq::unbind_from_species(bool remove_callbacks) {
199    GBDATA *gb_seq = get_bound_species_data();
200
201    if (gb_seq) { 
202        if (remove_callbacks) {
203            GB_remove_callback(gb_seq, GB_CB_CHANGED, makeDatabaseCallback(st_sequence_callback,     this));
204            GB_remove_callback(gb_seq, GB_CB_DELETE,  makeDatabaseCallback(st_sequence_del_callback, this));
205        }
206        AP_sequence::unbind_from_species();
207    }
208}
209
210void MostLikelySeq::sequence_change() {
211    st_ml->clear_all();
212}
213
214AP_sequence *MostLikelySeq::dup() const {
215    return new MostLikelySeq(get_aliview(), st_ml);
216}
217
218void MostLikelySeq::set(const char *) {
219    st_assert(0);                                   // hmm why not perform set_sequence() here ?
220}
221
222void MostLikelySeq::unset() {
223}
224
225void MostLikelySeq::set_sequence() {
226    /*! Transform the sequence from character to vector
227     * for current range [ST_ML::first_pos .. ST_ML::last_pos]
228     */
229
230    GBDATA *gb_data = get_bound_species_data();
231    st_assert(gb_data);
232
233    size_t                source_sequence_len = (size_t)GB_read_string_count(gb_data);
234    const char           *source_sequence     = GB_read_char_pntr(gb_data) + st_ml->get_first_pos();
235    ST_base_vector       *dest                = sequence;
236    const ST_base_vector *freq                = st_ml->get_inv_base_frequencies() + st_ml->get_first_pos();
237
238    size_t range_len = st_ml->get_last_pos() - st_ml->get_first_pos();
239    size_t data_len  = std::min(range_len, source_sequence_len);
240    size_t pos       = 0;
241
242    for (; pos<data_len;  ++pos) dest[pos].setBase(freq[pos], toupper(source_sequence[pos]));
243    for (; pos<range_len; ++pos) dest[pos].setBase(freq[pos], '.');
244
245    up_to_date = true;
246}
247
248AP_FLOAT MostLikelySeq::combine(const AP_sequence *, const AP_sequence *, char *) {
249    st_assert(0);
250    return -1.0;
251}
252
253void MostLikelySeq::partial_match(const AP_sequence *, long *, long *) const {
254    st_assert(0);                                   // function is expected to be unused
255}
256uint32_t MostLikelySeq::checksum() const {
257    st_assert(0); // function is expected to be unused
258    return 0;
259}
260
261void MostLikelySeq::calculate_ancestor(const MostLikelySeq *lefts, double leftl, const MostLikelySeq *rights, double rightl) {
262    st_assert(!up_to_date);
263
264    ST_base_vector        hbv;
265    double                lc   = leftl / st_ml->get_step_size();
266    double                rc   = rightl / st_ml->get_step_size();
267    const ST_base_vector *lb   = lefts->sequence;
268    const ST_base_vector *rb   = rights->sequence;
269    ST_base_vector       *dest = sequence;
270
271    for (size_t pos = st_ml->get_first_pos(); pos < st_ml->get_last_pos(); pos++) {
272        st_assert(lb->lik == 1 && rb->lik == 1);
273
274        int distl = (int) (st_ml->get_rate_at(pos) * lc);
275        int distr = (int) (st_ml->get_rate_at(pos) * rc);
276
277        st_ml->get_matrix_for(distl).transform(*lb, *dest);
278        st_ml->get_matrix_for(distr).transform(*rb, hbv);
279
280        *dest *= hbv;
281        dest->check_overflow();
282
283        st_assert(dest->lik == 1);
284
285        dest++;
286        lb++;
287        rb++;
288    }
289
290    up_to_date = true;
291}
292
293ST_base_vector *MostLikelySeq::tmp_out = 0;
294
295void MostLikelySeq::calc_out(const MostLikelySeq *next_branch, double dist) {
296    // result will be in tmp_out
297
298    ST_base_vector *out   = tmp_out + st_ml->get_first_pos();
299    double          lc    = dist / st_ml->get_step_size();
300    ST_base_vector *lefts = next_branch->sequence;
301
302    for (size_t pos = st_ml->get_first_pos(); pos < st_ml->get_last_pos(); pos++) {
303        int distl = (int) (st_ml->get_rate_at(pos) * lc);
304        st_ml->get_matrix_for(distl).transform(*lefts, *out);
305
306        // correct frequencies
307#if defined(WARN_TODO)
308#warning check if st_ml->get_base_frequency_at(pos).lik is 1 - if so, use vec-mult here
309#endif
310        for (int i = ST_A; i < ST_MAX_BASE; i++) {
311            out->b[i] *= st_ml->get_base_frequency_at(pos).b[i];
312        }
313
314        lefts++;
315        out++;
316    }
317}
318
319void MostLikelySeq::print() {
320    const char *data = GB_read_char_pntr(get_bound_species_data());
321    for (size_t i = 0; i < ST_MAX_SEQ_PART; i++) {
322        printf("POS %3zu  %c     ", i, data[i]);
323        printf("\n");
324    }
325}
326
327AP_FLOAT MostLikelySeq::count_weighted_bases() const {
328    st_assert(0);
329    return -1.0;
330}
331
332// --------------
333//      ST_ML
334
335ST_ML::ST_ML(GBDATA *gb_maini) {
336    memset((char *) this, 0, sizeof(*this));
337    gb_main = gb_maini;
338}
339
340ST_ML::~ST_ML() {
341    delete tree_root;
342    free(alignment_name);
343    if (hash_2_ap_tree) GBS_free_hash(hash_2_ap_tree);
344    delete not_valid;
345    delete [] base_frequencies;
346    delete [] inv_base_frequencies;
347    delete [] rate_matrices;
348    if (!column_stat) {
349        // rates and ttratio have been allocated (see ST_ML::calc_st_ml)
350        delete [] rates;
351        delete [] ttratio;
352    }
353}
354
355
356void ST_ML::create_frequencies() {
357    //! Translate characters to base frequencies
358
359    size_t filtered_length = get_filtered_length();
360    base_frequencies       = new ST_base_vector[filtered_length];
361    inv_base_frequencies   = new ST_base_vector[filtered_length];
362
363    if (!column_stat) {
364        for (size_t i = 0; i < filtered_length; i++) {
365            base_frequencies[i].setTo(1.0);
366            base_frequencies[i].lik = 1.0;
367
368            inv_base_frequencies[i].setTo(1.0);
369            inv_base_frequencies[i].lik = 1.0;
370        }
371    }
372    else {
373        for (size_t i = 0; i < filtered_length; i++) {
374            const ST_FLOAT  NO_FREQ   = 0.01;
375            ST_base_vector& base_freq = base_frequencies[i];
376
377            base_freq.setTo(NO_FREQ);
378
379            static struct {
380                unsigned char c;
381                DNA_Base      b;
382            } toCount[] = {
383                { 'A', ST_A }, { 'a', ST_A },
384                { 'C', ST_C }, { 'c', ST_C },
385                { 'G', ST_G }, { 'g', ST_G },
386                { 'T', ST_T }, { 't', ST_T },
387                { 'U', ST_T }, { 'u', ST_T },
388                { '-', ST_GAP },
389                { 0, ST_UNKNOWN },
390            };
391
392            for (int j = 0; toCount[j].c; ++j) {
393                const float *freq = column_stat->get_frequencies(toCount[j].c);
394                if (freq) base_freq.b[toCount[j].b] += freq[i];
395            }
396
397            ST_FLOAT sum    = base_freq.summarize();
398            ST_FLOAT smooth = sum*0.01;             // smooth by %1 to avoid "crazy values"
399            base_freq.increaseBy(smooth);
400
401            sum += smooth*ST_MAX_BASE; // correct sum
402
403            ST_FLOAT min = base_freq.min_frequency();
404           
405            // @@@ if min == 0.0 all inv_base_frequencies will be set to inf ? correct ?
406            // maybe min should be better calculated after next if-else-clause ?
407
408            if (sum>NO_FREQ) {
409                base_freq.multiplyWith(ST_MAX_BASE/sum);
410            }
411            else {
412                base_freq.setTo(1.0); // columns w/o data
413            }
414
415            base_freq.lik = 1.0;
416           
417            inv_base_frequencies[i].makeInverseOf(base_freq, min);
418            inv_base_frequencies[i].lik = 1.0;
419        }
420    }
421}
422
423void ST_ML::insert_tree_into_hash_rek(AP_tree *node) {
424    node->gr.gc = 0;
425    if (node->is_leaf) {
426        GBS_write_hash(hash_2_ap_tree, node->name, (long) node);
427    }
428    else {
429        insert_tree_into_hash_rek(node->get_leftson());
430        insert_tree_into_hash_rek(node->get_rightson());
431    }
432}
433
434void ST_ML::create_matrices(double max_disti, int nmatrices) {
435    delete [] rate_matrices;
436    rate_matrices = new ST_rate_matrix[nmatrices];
437
438    max_dist          = max_disti;
439    max_rate_matrices = nmatrices;
440    step_size         = max_dist / max_rate_matrices;
441
442    for (int i = 0; i < max_rate_matrices; i++) {
443        rate_matrices[i].set((i + 1) * step_size, 0); // ttratio[i]
444    }
445}
446
447long ST_ML::delete_species(const char *key, long val, void *cd_st_ml) {
448    ST_ML *st_ml = (ST_ML*)cd_st_ml;
449
450    if (GBS_read_hash(st_ml->keep_species_hash, key)) {
451        return val;
452    }
453    else {
454        AP_tree *leaf = (AP_tree *)val;
455        UNCOVERED();
456        destroy(leaf->REMOVE());
457
458        return 0;
459    }
460}
461
462inline GB_ERROR tree_size_ok(AP_tree_root *tree_root) {
463    GB_ERROR error = NULL;
464
465    AP_tree *root = tree_root->get_root_node();
466    if (!root || root->is_leaf) {
467        const char *tree_name = tree_root->get_tree_name();
468        error = GBS_global_string("Too few species remained in tree '%s'", tree_name);
469    }
470    return error;
471}
472
473void ST_ML::cleanup() {
474    freenull(alignment_name);
475
476    if (MostLikelySeq::tmp_out) {
477        delete MostLikelySeq::tmp_out;
478        MostLikelySeq::tmp_out = NULL;
479    }
480
481    delete tree_root;
482    tree_root = NULL;
483
484    if (hash_2_ap_tree) {
485        GBS_free_hash(hash_2_ap_tree);
486        hash_2_ap_tree = NULL;
487    }
488
489    is_initialized = false;
490}
491
492GB_ERROR ST_ML::calc_st_ml(const char *tree_name, const char *alignment_namei,
493                           const char *species_names, int marked_only,
494                           ColumnStat *colstat, const WeightedFilter *weighted_filter)
495{
496    // acts as contructor, leaks as hell when called twice
497
498    GB_ERROR error = 0;
499
500    if (is_initialized) cleanup();
501
502    {
503        GB_transaction ta(gb_main);
504        arb_progress progress("Activating column statistic");
505
506        column_stat                = colstat;
507        GB_ERROR column_stat_error = column_stat->calculate(NULL);
508
509        if (column_stat_error) fprintf(stderr, "Column statistic error: %s (using equal rates/tt-ratio for all columns)\n", column_stat_error);
510
511        alignment_name = ARB_strdup(alignment_namei);
512        long ali_len   = GBT_get_alignment_len(gb_main, alignment_name);
513
514        if (ali_len<0) {
515            error = GB_await_error();
516        }
517        else if (ali_len<10) {
518            error = "alignment too short";
519        }
520        else {
521            {
522                AliView *aliview = NULL;
523                if (weighted_filter) {
524                    aliview = weighted_filter->create_aliview(alignment_name, error);
525                }
526                else {
527                    AP_filter filter(ali_len);      // unfiltered
528
529                    error = filter.is_invalid();
530                    if (!error) {
531                        AP_weights weights(&filter);
532                        aliview = new AliView(gb_main, filter, weights, alignment_name);
533                    }
534                }
535
536                st_assert(contradicted(aliview, error));
537
538                if (!error) {
539                    MostLikelySeq *seq_templ = new MostLikelySeq(aliview, this); // @@@ error: never freed! (should be freed when freeing tree_root!)
540                    tree_root = new AP_tree_root(aliview, seq_templ, false);
541                    // do not delete 'aliview' or 'seq_templ' (they belong to 'tree_root' now)
542                }
543            }
544
545            if (!error) {
546                tree_root->loadFromDB(tree_name);       // tree is not linked!
547
548                if (!tree_root->get_root_node()) { // no tree
549                    error = GBS_global_string("Failed to load tree '%s'", tree_name);
550                }
551                else {
552                    {
553                        size_t species_in_tree = count_species_in_tree();
554                        hash_2_ap_tree         = GBS_create_hash(species_in_tree, GB_MIND_CASE);
555                    }
556
557                    // delete species from tree:
558                    if (species_names) {                    // keep names
559                        tree_root->remove_leafs(AWT_REMOVE_ZOMBIES);
560
561                        error = tree_size_ok(tree_root);
562                        if (!error) {
563                            char *l, *n;
564                            keep_species_hash = GBS_create_hash(GBT_get_species_count(gb_main), GB_MIND_CASE);
565                            for (l = (char *) species_names; l; l = n) {
566                                n = strchr(l, 1);
567                                if (n) *n = 0;
568                                GBS_write_hash(keep_species_hash, l, 1);
569                                if (n) *(n++) = 1;
570                            }
571
572                            insert_tree_into_hash_rek(tree_root->get_root_node());
573                            GBS_hash_do_loop(hash_2_ap_tree, delete_species, this);
574                            GBS_free_hash(keep_species_hash);
575                            keep_species_hash = 0;
576                            GBT_link_tree(tree_root->get_root_node(), gb_main, true, 0, 0);
577                        }
578                    }
579                    else {                                  // keep marked/all
580                        GBT_link_tree(tree_root->get_root_node(), gb_main, true, 0, 0);
581                        tree_root->remove_leafs(marked_only ? AWT_KEEP_MARKED : AWT_REMOVE_ZOMBIES);
582
583                        error = tree_size_ok(tree_root);
584                        if (!error) insert_tree_into_hash_rek(tree_root->get_root_node());
585                    }
586                }
587            }
588
589            if (!error) {
590                // calc frequencies
591
592                progress.subtitle("calculating frequencies");
593
594                size_t filtered_length = get_filtered_length();
595                if (!column_stat_error) {
596                    rates   = column_stat->get_rates();
597                    ttratio = column_stat->get_ttratio();
598                }
599                else {
600                    float *alloc_rates   = new float[filtered_length];
601                    float *alloc_ttratio = new float[filtered_length];
602
603                    for (size_t i = 0; i < filtered_length; i++) {
604                        alloc_rates[i]   = 1.0;
605                        alloc_ttratio[i] = 2.0;
606                    }
607                    rates   = alloc_rates;
608                    ttratio = alloc_ttratio;
609
610                    column_stat = 0;                // mark rates and ttratio as "allocated" (see ST_ML::~ST_ML)
611                }
612                create_frequencies();
613                latest_modification = GB_read_clock(gb_main); // set update time
614                create_matrices(2.0, 1000);
615
616                MostLikelySeq::tmp_out = new ST_base_vector[filtered_length]; // @@@ error: never freed!
617                is_initialized         = true;
618            }
619        }
620
621        if (error) {
622            cleanup();
623            error = ta.close(error);
624        }
625    }
626    return error;
627}
628
629MostLikelySeq *ST_ML::getOrCreate_seq(AP_tree *node) {
630    MostLikelySeq *seq = DOWNCAST(MostLikelySeq*, node->get_seq());
631    if (!seq) {
632        seq = new MostLikelySeq(tree_root->get_aliview(), this); // @@@ why not use dup() ?
633
634        node->set_seq(seq);
635        if (node->is_leaf) {
636            st_assert(node->gb_node);
637            seq->bind_to_species(node->gb_node);
638        }
639    }
640    return seq;
641}
642
643const MostLikelySeq *ST_ML::get_mostlikely_sequence(AP_tree *node) {
644    /*! go through the tree and calculate the ST_base_vector from bottom to top
645     */
646
647    MostLikelySeq *seq = getOrCreate_seq(node);
648    if (!seq->is_up_to_date()) {
649        if (node->is_leaf) {
650            seq->set_sequence();
651        }
652        else {
653            const MostLikelySeq *leftSeq  = get_mostlikely_sequence(node->get_leftson());
654            const MostLikelySeq *rightSeq = get_mostlikely_sequence(node->get_rightson());
655
656            seq->calculate_ancestor(leftSeq, node->leftlen, rightSeq, node->rightlen);
657        }
658    }
659
660    return seq;
661}
662
663void ST_ML::clear_all() {
664    GB_transaction ta(gb_main);
665    undo_tree(tree_root->get_root_node());
666    latest_modification = GB_read_clock(gb_main);
667}
668
669void ST_ML::undo_tree(AP_tree *node) {
670    MostLikelySeq *seq = getOrCreate_seq(node);
671    seq->forget_sequence();
672    if (!node->is_leaf) {
673        undo_tree(node->get_leftson());
674        undo_tree(node->get_rightson());
675    }
676}
677
678#define GET_ML_VECTORS_BUG_WORKAROUND_INCREMENT (ST_MAX_SEQ_PART-1) // workaround bug in get_ml_vectors
679
680MostLikelySeq *ST_ML::get_ml_vectors(const char *species_name, AP_tree *node, size_t start_ali_pos, size_t end_ali_pos) {
681    /* result will be in tmp_out
682     *
683     * assert end_ali_pos - start_ali_pos < ST_MAX_SEQ_PART
684     *
685     * @@@ CAUTION!!! get_ml_vectors has a bug:
686     * it does not calculate the last value, if (end_ali_pos-start_ali_pos+1)==ST_MAX_SEQ_PART
687     * (search for GET_ML_VECTORS_BUG_WORKAROUND_INCREMENT)
688     *
689     * I'm not sure whether this is really a bug! Maybe it's only some misunderstanding about
690     * 'end_ali_pos', because it does not mark the last calculated position, but the position
691     * behind the last calculated position! @@@ Need to rename it!
692     *
693     */
694
695    if (!node) {
696        if (!hash_2_ap_tree) return 0;
697        node = (AP_tree *) GBS_read_hash(hash_2_ap_tree, species_name);
698        if (!node) return 0;
699    }
700
701    st_assert(start_ali_pos<end_ali_pos);
702    st_assert((end_ali_pos - start_ali_pos + 1) <= ST_MAX_SEQ_PART);
703
704    MostLikelySeq *seq = getOrCreate_seq(node);
705
706    if (start_ali_pos != first_pos || end_ali_pos > last_pos) {
707        undo_tree(tree_root->get_root_node());      // undo everything
708        first_pos = start_ali_pos;
709        last_pos  = end_ali_pos;
710    }
711
712    AP_tree *pntr;
713    for (pntr = node->get_father(); pntr; pntr = pntr->get_father()) {
714        MostLikelySeq *sequ = getOrCreate_seq(pntr);
715        if (sequ) sequ->forget_sequence();
716    }
717
718    node->set_root();
719
720    const MostLikelySeq *seq_of_brother = get_mostlikely_sequence(node->get_brother());
721
722    seq->calc_out(seq_of_brother, node->father->leftlen + node->father->rightlen);
723    return seq;
724}
725
726bool ST_ML::update_ml_likelihood(char *result[4], int& latest_update, const char *species_name, AP_tree *node) {
727    /*! calculates values for 'Detailed column statistics' in ARB_EDIT4
728     * @return true if calculated with sucess
729     *
730     * @param result if result[0] is NULL, memory will be allocated and assigned to result[0 .. 3].
731     *        You should NOT allocate result yourself, but you can reuse it for multiple calls.
732     * @param latest_update has to contain and will be set to the latest statistic modification time
733     *        (0 is a good start value)
734     * @param species_name name of the species (for which the column statistic shall be calculated)
735     * @param node of the current tree (for which the column statistic shall be calculated)
736     *
737     * Note: either 'species_name' or 'node' needs to be specified, but NOT BOTH
738     */
739
740    st_assert(contradicted(species_name, node));
741
742    if (latest_update < latest_modification) {
743        if (!node) {                                // if node isn't given search it using species name
744            st_assert(hash_2_ap_tree);              // ST_ML was not prepared for search-by-name
745            if (hash_2_ap_tree) node = (AP_tree *) GBS_read_hash(hash_2_ap_tree, species_name);
746            if (!node) return false;
747        }
748
749        DNA_Base adb[4];
750        int      i;
751
752        size_t ali_len = get_alignment_length();
753        st_assert(get_filtered_length() == ali_len); // assume column stat was calculated w/o filters
754
755        if (!result[0]) {                           // allocate Array-elements for result
756            for (i = 0; i < 4; i++) {
757                ARB_calloc(result[i], ali_len+1); // [0 .. alignment_len[ + zerobyte
758            }
759        }
760
761        for (i = 0; i < 4; i++) {
762            adb[i] = dna_table.char_to_enum("ACGU"[i]);
763        }
764
765        for (size_t seq_start = 0; seq_start < ali_len; seq_start += GET_ML_VECTORS_BUG_WORKAROUND_INCREMENT) {
766            size_t seq_end = std::min(ali_len, seq_start+GET_ML_VECTORS_BUG_WORKAROUND_INCREMENT);
767            get_ml_vectors(0, node, seq_start, seq_end);
768        }
769
770        MostLikelySeq *seq = getOrCreate_seq(node);
771
772        for (size_t pos = 0; pos < ali_len; pos++) {
773            ST_base_vector& vec = seq->tmp_out[pos];
774            double          sum = vec.summarize();
775
776            if (sum == 0) {
777                for (i = 0; i < 4; i++) {
778                    result[i][pos] = -1;
779                }
780            }
781            else {
782                double div = 100.0 / sum;
783
784                for (i = 0; i < 4; i++) {
785                    result[i][pos] = char ((vec.b[adb[i]] * div) + 0.5);
786                }
787            }
788        }
789
790        latest_update = latest_modification;
791    }
792    return true;
793}
794
795ST_ML_Color *ST_ML::get_color_string(const char *species_name, AP_tree *node, size_t start_ali_pos, size_t end_ali_pos) {
796    /*! (Re-)Calculates the color string of a given node for sequence positions [start_ali_pos .. end_ali_pos[
797     */
798   
799    if (!node) {
800        // if node isn't given, search it using species name:
801        if (!hash_2_ap_tree) return 0;
802        node = (AP_tree *) GBS_read_hash(hash_2_ap_tree, species_name);
803        if (!node) return 0;
804    }
805
806    // align start_ali_pos/end_ali_pos to previous/next pos divisible by ST_BUCKET_SIZE:
807    start_ali_pos &= ~(ST_BUCKET_SIZE - 1);
808    end_ali_pos    = (end_ali_pos & ~(ST_BUCKET_SIZE - 1)) + ST_BUCKET_SIZE - 1;
809
810    size_t ali_len = get_alignment_length();
811    if (end_ali_pos > ali_len) {
812        end_ali_pos = ali_len;
813    }
814
815    double         val;
816    MostLikelySeq *seq = getOrCreate_seq(node);
817    size_t         pos;
818
819    if (!seq->color_out) { // allocate mem for color_out if we not already have it
820        ARB_calloc(seq->color_out,            ali_len);
821        ARB_calloc(seq->color_out_valid_till, (ali_len >> LD_BUCKET_SIZE) + ST_BUCKET_SIZE);
822    }
823    // search for first out-dated position:
824    for (pos = start_ali_pos; pos <= end_ali_pos; pos += ST_BUCKET_SIZE) {
825        if (seq->color_out_valid_till[pos >> LD_BUCKET_SIZE] < latest_modification) break;
826    }
827    if (pos > end_ali_pos) {                        // all positions are up-to-date
828        return seq->color_out;                      // => return existing result
829    }
830
831    for (size_t start = start_ali_pos; start <= end_ali_pos; start += GET_ML_VECTORS_BUG_WORKAROUND_INCREMENT) {
832        int end = std::min(end_ali_pos, start+GET_ML_VECTORS_BUG_WORKAROUND_INCREMENT);
833        get_ml_vectors(0, node, start, end);        // calculates tmp_out (see below)
834    }
835
836    const char *source_sequence = 0;
837    GBDATA *gb_data = seq->get_bound_species_data();
838    if (gb_data) source_sequence = GB_read_char_pntr(gb_data);
839
840    // create color string in 'outs':
841    ST_ML_Color    *outs   = seq->color_out  + start_ali_pos;
842    ST_base_vector *vec    = seq->tmp_out    + start_ali_pos; // tmp_out was calculated by get_ml_vectors above
843    const char     *source = source_sequence + start_ali_pos;
844
845    for (pos = start_ali_pos; pos <= end_ali_pos; pos++) {
846        {
847            DNA_Base b = dna_table.char_to_enum(*source); // convert seq-character to enum DNA_Base
848            *outs      = 0;
849
850            if (b != ST_UNKNOWN) {
851                ST_FLOAT max = vec->max_frequency();
852                val          = max / (0.0001 + vec->b[b]); // calc ratio of max/real base-char
853
854                if (val > 1.0) {                    // if real base-char is NOT the max-likely base-char
855                    *outs = (int) (log(val));       // => insert color
856                }
857            }
858        }
859        outs++;
860        vec++;
861        source++;
862
863        seq->color_out_valid_till[pos >> LD_BUCKET_SIZE] = latest_modification;
864    }
865    return seq->color_out;
866}
867
868void ST_ML::create_column_statistic(AW_root *awr, const char *awarname, AW_awar *awar_default_alignment) {
869    column_stat = new ColumnStat(get_gb_main(), awr, awarname, awar_default_alignment);
870}
871
872const TreeNode *ST_ML::get_gbt_tree() const {
873    return tree_root->get_root_node();
874}
875
876size_t ST_ML::count_species_in_tree() const {
877    ARB_tree_info info;
878    tree_root->get_root_node()->calcTreeInfo(info);
879    return info.leafs;
880}
881
882AP_tree *ST_ML::find_node_by_name(const char *species_name) {
883    AP_tree *node = NULL;
884    if (hash_2_ap_tree) node = (AP_tree *)GBS_read_hash(hash_2_ap_tree, species_name);
885    return node;
886}
887
888const AP_filter *ST_ML::get_filter() const { return tree_root->get_filter(); }
889size_t ST_ML::get_filtered_length() const { return get_filter()->get_filtered_length(); }
890size_t ST_ML::get_alignment_length() const { return get_filter()->get_length(); }
891
Note: See TracBrowser for help on using the repository browser.