source: branches/profile/PARSIMONY/PARS_main.cxx

Last change on this file was 13642, checked in by westram, 9 years ago
  • add perfmeter (insert + optimize)
  • disable AUTO_CHECK_TREE_STRUCTURE (4me)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.0 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : PARS_main.cxx                                     //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "pars_main.hxx"
12#include "pars_dtree.hxx"
13#include "pars_klprops.hxx"
14#include "ap_tree_nlen.hxx"
15
16#include <aw_awars.hxx>
17#include <aw_preset.hxx>
18#include <aw_msg.hxx>
19#include <aw_root.hxx>
20#include <aw_question.hxx>
21
22#include <awt.hxx>
23#include <awt_sel_boxes.hxx>
24#include <awt_filter.hxx>
25
26#include <ColumnStat.hxx>
27#include <nds.h>
28#include <arb_progress.h>
29#include <arb_misc.h>
30
31#include <gui_aliview.hxx>
32#include <ad_cb.h>
33
34#include <TreeCallbacks.hxx>
35
36#include <list>
37#include <macros.hxx>
38
39#include "PerfMeter.h"
40
41
42#if defined(DEBUG)
43# define TESTMENU
44#endif // DEBUG
45
46using namespace std;
47
48AW_HEADER_MAIN
49
50#define AWAR_COLUMNSTAT_BASE "tmp/pars/colstat"
51#define AWAR_COLUMNSTAT_NAME AWAR_COLUMNSTAT_BASE "/name"
52
53GBDATA              *GLOBAL_gb_main = NULL;
54static ArbParsimony *GLOBAL_PARS    = NULL;
55
56inline AWT_graphic_tree *global_tree() { return GLOBAL_PARS->get_tree(); }
57
58// waaah more globals :(
59AP_main *ap_main;
60
61static void pars_saveNrefresh_changed_tree(AWT_canvas *ntw) {
62    ap_assert((AWT_TREE(ntw) == global_tree()));
63
64    GB_ERROR error = global_tree()->save(ntw->gb_main, 0, 0, 0);
65    if (error) aw_message(error);
66
67    ntw->zoom_reset_and_refresh();
68}
69
70__ATTR__NORETURN static void pars_exit(AW_window *aww) {
71    AW_root *aw_root = aww->get_root();
72    shutdown_macro_recording(aw_root);
73    aw_root->unlink_awars_from_DB(GLOBAL_gb_main);
74#if defined(DEBUG)
75    AWT_browser_forget_db(GLOBAL_gb_main);
76#endif // DEBUG
77    GB_close(GLOBAL_gb_main);
78    exit(EXIT_SUCCESS);
79}
80
81static void AP_user_push_cb(AW_window *aww, AWT_canvas *) {
82    ap_main->user_push();
83    aww->get_root()->awar(AWAR_STACKPOINTER)->write_int(ap_main->get_user_push_counter());
84}
85
86static void AP_user_pop_cb(AW_window *aww, AWT_canvas *ntw) {
87    if (ap_main->get_user_push_counter()<=0) {
88        aw_message("No tree on stack.");
89        return;
90    }
91    ap_main->user_pop();
92    rootNode()->compute_tree();
93    ASSERT_VALID_TREE(rootNode());
94    aww->get_root()->awar(AWAR_STACKPOINTER)->write_int(ap_main->get_user_push_counter());
95
96    pars_saveNrefresh_changed_tree(ntw);
97
98    if (ap_main->get_user_push_counter() <= 0) { // last tree was popped => push again
99        AP_user_push_cb(aww, ntw);
100    }
101}
102
103class InsertData {
104    int  abort_flag;
105    long currentspecies;
106   
107    arb_progress progress;
108
109public:
110
111    bool quick_add_flag;
112    InsertData(bool quick, long spec_count, int add_progress_steps)
113        : abort_flag(false),
114          currentspecies(0),
115          progress(GBS_global_string("Inserting %li species", spec_count), spec_count+add_progress_steps),
116          quick_add_flag(quick)
117    {
118    }
119
120    bool every_sixteenth() { return (currentspecies & 0xf) == 0; }
121
122    bool aborted() const { return abort_flag; }
123    void set_aborted(bool aborted_) { abort_flag = aborted_; }
124
125    void inc() {
126        ++currentspecies;
127        progress.inc();
128        abort_flag = progress.aborted();
129    }
130
131    arb_progress& get_progress() { return progress; }
132};
133
134
135static int sort_sequences_by_length(const char*, long leaf0_ptr, const char*, long leaf1_ptr) {
136    AP_tree *leaf0 = (AP_tree*)leaf0_ptr;
137    AP_tree *leaf1 = (AP_tree*)leaf1_ptr;
138
139    AP_FLOAT len0 = leaf0->get_seq()->weighted_base_count();
140    AP_FLOAT len1 = leaf1->get_seq()->weighted_base_count();
141
142    return len0<len1 ? 1 : (len0>len1 ? -1 : 0); // longest sequence first
143}
144
145static long transform_gbd_to_leaf(const char *key, long val, void *) {
146    if (!val) return val;
147
148#if defined(WARN_TODO)
149#warning use create_linked_leaf() when impl
150#endif
151
152    GBDATA       *gb_node = (GBDATA *)val;
153    AP_tree_root *troot   = ap_main->get_tree_root()->tree_static;
154    AP_tree_nlen *leaf    = DOWNCAST(AP_tree_nlen*, troot->makeNode());
155
156    leaf->forget_origin(); // new leaf is not part of tree yet
157
158    leaf->gb_node = gb_node;
159    leaf->name    = strdup(key);
160    leaf->is_leaf = true;
161
162    leaf->set_seq(troot->get_seqTemplate()->dup());
163    GB_ERROR error = leaf->get_seq()->bind_to_species(gb_node);
164    if (error) {
165        aw_message(error);
166        delete leaf; leaf = 0;
167    }
168    return (long)leaf;
169}
170
171static AP_tree_nlen *insert_species_in_tree(const char *key, AP_tree_nlen *leaf, InsertData *isits) {
172    if (!leaf) return leaf;
173    if (isits->aborted()) return leaf;
174
175    AP_tree_nlen *tree = rootNode();
176
177    if (leaf->get_seq()->weighted_base_count() < MIN_SEQUENCE_LENGTH) {
178        aw_message(GBS_global_string("Species %s has too short sequence (%f, minimum is %i)",
179                                     key,
180                                     leaf->get_seq()->weighted_base_count(),
181                                     MIN_SEQUENCE_LENGTH));
182        delete leaf;
183        return 0;
184    }
185
186    if (!tree) {                                    // no tree yet
187        static AP_tree_nlen *last_inserted = NULL; // @@@ move 'last_inserted' into 'InsertData'
188
189        if (!last_inserted) {                       // store 1st leaf
190            last_inserted = leaf;
191        }
192        else {                                      // 2nd leaf -> create initial tree
193            AP_tree_root *troot = ap_main->get_tree_root()->tree_static;
194
195            leaf->initial_insert(last_inserted, troot);
196            last_inserted = NULL;
197
198            ap_assert(troot->get_root_node() == leaf->get_father());
199            ASSERT_VALID_TREE(troot->get_root_node());
200        }
201    }
202    else {
203        ASSERT_VALID_TREE(tree);
204
205        AP_tree_nlen **branchlist;
206
207        {
208            AP_tree **blist;
209            long      bsum = 0;
210
211            tree->buildBranchList(blist, bsum, true, -1); // get all branches
212            branchlist = (AP_tree_nlen**)blist;
213        }
214
215        AP_tree_nlen *bestposl = tree->get_leftson();
216        AP_tree_nlen *bestposr = tree->get_rightson();
217
218        ap_assert(tree == rootNode());
219        leaf->insert(bestposl);
220        tree = NULL;                                // tree may have changed
221
222        {
223            AP_FLOAT curr_parsimony = rootNode()->costs();
224            AP_FLOAT best_parsimony = curr_parsimony;
225
226            ASSERT_VALID_TREE(rootNode());
227
228            for (long counter = 0; !isits->aborted() && branchlist[counter]; counter += 2) {
229                AP_tree_nlen *bl  = branchlist[counter];
230                AP_tree_nlen *blf = branchlist[counter+1];
231
232                if (blf->father == bl) {
233                    bl  = branchlist[counter+1];
234                    blf = branchlist[counter];
235                }
236
237                if (bl->father) {
238                    bl->set_root();
239                }
240
241                ASSERT_VALID_TREE(rootNode());
242
243                leaf->moveNextTo(bl, 0.5);
244                ASSERT_VALID_TREE(rootNode());
245
246                curr_parsimony = rootNode()->costs();
247                ASSERT_VALID_TREE(rootNode());
248
249                if (curr_parsimony < best_parsimony) {
250                    best_parsimony = curr_parsimony;
251                    bestposl = bl;
252                    bestposr = blf;
253                }
254
255            }
256        }
257        delete [] branchlist; branchlist = 0;
258        if (bestposl->father != bestposr) {
259            bestposl = bestposr;
260        }
261
262        ASSERT_VALID_TREE(rootNode());
263
264        leaf->moveNextTo(bestposl, 0.5);
265
266        ASSERT_VALID_TREE(rootNode());
267
268        if (!isits->quick_add_flag) {
269            int deep                           = 5;
270            if (isits->every_sixteenth()) deep = -1;
271           
272            arb_progress progress("optimization");
273            bestposl->get_father()->nn_interchange_rek(deep, AP_BL_NNI_ONLY, true);
274            ASSERT_VALID_TREE(rootNode());
275        }
276        AP_tree_nlen *brother = leaf->get_brother();
277        if (brother->is_leaf && leaf->father->father) {
278            bool brother_is_short = 2 * brother->get_seq()->weighted_base_count() < leaf->get_seq()->weighted_base_count();
279
280            if (brother_is_short) {
281                brother->remove();
282                leaf->remove();
283
284                for (int firstUse = 1; firstUse >= 0; --firstUse) {
285                    AP_tree_nlen *to_insert = firstUse ? leaf : brother;
286                    const char   *format    = firstUse ? "2:%s" : "shortseq:%s";
287
288                    char *label = GBS_global_string_copy(format, to_insert->name);
289                    insert_species_in_tree(label, to_insert, isits);
290                    free(label);
291                }
292            }
293        }
294
295        ASSERT_VALID_TREE(rootNode());
296    }
297
298    return leaf;
299}
300
301static long hash_insert_species_in_tree(const char *key, long leaf, void *cd_isits) {
302    InsertData *isits  = (InsertData*)cd_isits;
303    long        result = (long)insert_species_in_tree(key, (AP_tree_nlen*)leaf, isits);
304    isits->inc();
305    return result;
306}
307
308static long count_hash_elements(const char *, long val, void *cd_count) {
309    if (val) {
310        long *count = (long*)cd_count;
311        (*count)++;
312    }
313    return val;
314}
315
316enum AddWhat {
317    NT_ADD_MARKED,
318    NT_ADD_SELECTED,
319};
320
321static void nt_add(AW_window *, AWT_canvas *ntw, AddWhat what, bool quick) {
322    GB_ERROR  error = 0;
323
324    AP_tree *oldrootleft  = NULL;
325    AP_tree *oldrootright = NULL;
326    {
327        AP_tree *root = rootNode();
328        if (root) {
329            root->reset_subtree_layout();
330            oldrootleft  = root->get_leftson();
331            oldrootright = root->get_rightson();
332        }
333    }
334
335    GB_HASH *hash = 0;
336    {
337        GB_transaction ta(GLOBAL_gb_main);
338        switch (what) {
339            case NT_ADD_SELECTED: {
340                char *name = GBT_readOrCreate_string(GLOBAL_gb_main, AWAR_SPECIES_NAME, "");
341                if (name && strlen(name)) {
342                    GBDATA *gb_species = GBT_find_species(GLOBAL_gb_main, name);
343                    if (gb_species) {
344                        hash = GBS_create_hash(1, GB_MIND_CASE);
345                        GBS_write_hash(hash, name, (long)gb_species);
346                    }
347                    else error = GBS_global_string("Selected Species (%s) not found", name);
348                }
349                else error = "Please select a species";
350                free(name);
351                break;
352            }
353            case NT_ADD_MARKED: {
354                hash = GBT_create_marked_species_hash(GLOBAL_gb_main);
355                break;
356            }
357        }
358    }
359
360    if (!error) {
361        ap_assert(hash);
362
363        NT_remove_species_in_tree_from_hash(rootNode(), hash);
364
365        long max_species = 0;
366        GBS_hash_do_loop(hash, count_hash_elements, &max_species);
367
368        InsertPerfMeter insertPerf("(quick-)add", max_species);
369
370        int        implicitSteps = quick ? 1 : 2; // 1 step for calc_branchlengths, 1 step for NNI
371        InsertData isits(quick, max_species, implicitSteps);
372
373        GB_begin_transaction(GLOBAL_gb_main);
374        GBS_hash_do_loop(hash, transform_gbd_to_leaf, NULL);
375        GB_commit_transaction(GLOBAL_gb_main);
376
377        {
378            int skipped = max_species - GBS_hash_count_elems(hash);
379            if (skipped) {
380                aw_message(GBS_global_string("Skipped %i species (no data?)", skipped));
381                isits.get_progress().inc_by(skipped);
382            }
383        }
384
385        GBS_hash_do_sorted_loop(hash, hash_insert_species_in_tree, sort_sequences_by_length, &isits);
386
387        if (!quick) {
388            rootEdge()->nni_rek(-1, false, AP_BL_NNI_ONLY, NULL);
389            ++isits.get_progress();
390        }
391
392        if (rootNode()) {
393            rootEdge()->calc_branchlengths();
394            ++isits.get_progress();
395
396            ASSERT_VALID_TREE(rootNode());
397            rootNode()->compute_tree();
398
399            if (oldrootleft) {
400                if (oldrootleft->father == oldrootright) oldrootleft->set_root();
401                else                                     oldrootright->set_root();
402            }
403            else {
404                ARB_edge innermost = rootNode()->get_tree_root()->find_innermost_edge();
405                innermost.set_root();
406            }
407        }
408        else {
409            error = "Tree lost (no leafs left)";
410            isits.get_progress().done();
411        }
412
413        insertPerf.dump(stdout);
414    }
415
416    if (hash) GBS_free_hash(hash);
417    if (error) aw_message(error);
418
419    AWT_TREE(ntw)->reorder_tree(BIG_BRANCHES_TO_TOP);
420    pars_saveNrefresh_changed_tree(ntw);
421}
422
423// ------------------------------------------
424//      Adding partial sequences to tree
425
426class PartialSequence { 
427    GBDATA               *gb_species;
428    mutable AP_tree_nlen *self;                     // self converted to leaf (ready for insertion)
429    const AP_tree_nlen   *best_full_match;          // full sequence position which matched best
430    long                  overlap;                  // size of overlapping region
431    long                  penalty;                  // weighted mismatches
432    bool                  released;
433    bool                  multi_match;
434    string                multi_list;               // list of equal-rated insertion-points (not containing self)
435
436    AP_tree_nlen *get_self() const {
437        if (!self) {
438            ap_assert(!released); // request not possible, because leaf has already been released!
439
440            self = (AP_tree_nlen*)transform_gbd_to_leaf(GBT_read_name(gb_species), (long)gb_species, NULL);
441            ap_assert(self);
442        }
443        return self;
444    }
445
446public:
447    PartialSequence(GBDATA *gb_species_)
448        : gb_species(gb_species_), self(0), best_full_match(0)
449        , overlap(0),  penalty(LONG_MAX), released(false), multi_match(false)
450    {
451    }
452    PartialSequence(const PartialSequence& other)
453        : gb_species(other.gb_species),
454          self(other.self),
455          best_full_match(other.best_full_match),
456          overlap(other.overlap),
457          penalty(other.penalty),
458          released(other.released),
459          multi_match(other.multi_match),
460          multi_list(other.multi_list)
461    {
462        ap_assert(self == 0); // copying self not implemented
463    }
464    DECLARE_ASSIGNMENT_OPERATOR(PartialSequence);
465    ~PartialSequence() { ap_assert(self == 0); }
466
467    GBDATA *get_species() const { return gb_species; }
468    const AP_tree_nlen *get_best_match() const { return best_full_match; }
469    AP_FLOAT get_branchlength() const { return AP_FLOAT(penalty)/overlap; }
470    void test_match(const AP_tree_nlen *leaf_full);
471    bool is_multi_match() const { return multi_match; }
472
473    const char *get_name() const {
474        const char *name = get_self()->name;
475        ap_assert(name);
476        return name;
477    }
478
479    string get_multilist() const {
480        ap_assert(is_multi_match());
481        return string(best_full_match->name)+multi_list;
482    }
483
484    AP_tree_nlen *release() {
485        AP_tree_nlen *s = self;
486        self            = 0;
487        released        = true;
488        return s;
489    }
490
491    void dump() const {
492        printf("best match for '%s' is '%s' (overlap=%li penalty=%li)\n",
493               get_name(), best_full_match->name,
494               overlap, penalty);
495    }
496
497};
498
499void PartialSequence::test_match(const AP_tree_nlen *leaf_full) {
500    long curr_overlap;
501    long curr_penalty;
502
503    leaf_full->get_seq()->partial_match(get_self()->get_seq(), &curr_overlap, &curr_penalty);
504
505    bool better = false;
506
507    if (curr_overlap > overlap) {
508        better = true;
509    }
510    else if (curr_overlap == overlap) {
511        if (curr_penalty<penalty) {
512            better = true;
513        }
514        else if (curr_penalty == penalty) {
515            // found two equal-rated insertion points -> store data for warning
516#if defined(DEBUG)
517            if (!multi_match) dump();
518            printf("Another equal match is against '%s' (overlap=%li penalty=%li)\n", leaf_full->name, curr_overlap, curr_penalty);
519#endif // DEBUG
520
521            multi_match  = true;
522            multi_list.append(1, '/');
523            multi_list.append(leaf_full->name);
524        }
525    }
526
527    if (better) {
528        overlap         = curr_overlap;
529        penalty         = curr_penalty;
530        best_full_match = leaf_full;
531        multi_match     = false;
532        multi_list      = "";
533    }
534}
535
536static GB_ERROR nt_best_partial_match_rek(list<PartialSequence>& partial, const AP_tree_nlen *tree) {
537    GB_ERROR error = 0;
538
539    if (tree) {
540        if (tree->is_leaf && tree->name) {
541            if (tree->gb_node) {
542                int is_partial = GBT_is_partial(tree->gb_node, 0, true); // marks undef as 'full sequence'
543                if (is_partial == 0) { // do not consider other partial sequences
544                    list<PartialSequence>::iterator i = partial.begin();
545                    list<PartialSequence>::iterator e = partial.end();
546                    for (;  i != e; ++i) {
547                        i->test_match(tree);
548                    }
549                }
550                else if (is_partial == -1) {
551                    error = GB_await_error();
552                }
553            }
554        }
555        else {
556            error             = nt_best_partial_match_rek(partial, tree->get_leftson());
557            if (!error) error = nt_best_partial_match_rek(partial, tree->get_rightson());
558        }
559    }
560    return error;
561}
562
563static void count_partial_and_full(const AP_tree_nlen *at, int *partial, int *full, int *zombies, int default_value, bool define_if_undef) {
564    if (at->is_leaf) {
565        if (at->gb_node) {
566            int is_partial = GBT_is_partial(at->gb_node, default_value, define_if_undef);
567            if (is_partial) ++(*partial);
568            else ++(*full);
569        }
570        else {
571            ++(*zombies);
572        }
573    }
574    else {
575        count_partial_and_full(at->get_leftson(),  partial, full, zombies, default_value, define_if_undef);
576        count_partial_and_full(at->get_rightson(), partial, full, zombies, default_value, define_if_undef);
577    }
578}
579
580static const AP_tree_nlen *find_least_deep_leaf(const AP_tree_nlen *at, int depth, int *min_depth) {
581    if (depth >= *min_depth) {
582        return 0; // already found better or equal
583    }
584
585    if (at->is_leaf) {
586        if (at->gb_node) {
587            *min_depth = depth;
588            return at;
589        }
590        return 0;
591    }
592
593    const AP_tree_nlen *left  = find_least_deep_leaf(at->get_leftson(), depth+1, min_depth);
594    const AP_tree_nlen *right = find_least_deep_leaf(at->get_rightson(), depth+1, min_depth);
595
596    return right ? right : left;
597}
598inline AP_tree_nlen *find_least_deep_leaf(AP_tree_nlen *at, int depth, int *min_depth) {
599    return const_cast<AP_tree_nlen*>(find_least_deep_leaf(const_cast<const AP_tree_nlen*>(at), depth, min_depth));
600}
601
602static long push_partial(const char *, long val, void *cd_partial) {
603    list<PartialSequence> *partial = reinterpret_cast<list<PartialSequence> *>(cd_partial);
604    partial->push_back(PartialSequence((GBDATA*)val));
605    return val;
606}
607
608// -------------------------------
609//      Add Partial sequences
610
611static void NT_add_partial(AW_window *, AWT_canvas *ntw) {
612    GB_begin_transaction(GLOBAL_gb_main);
613    GB_ERROR error = NULL;
614
615    int full_marked_sequences = 0;
616
617    arb_progress part_add_progress("Adding partial sequences");
618
619    {
620        list<PartialSequence> partial;
621        {
622            GB_HASH *partial_hash = GBS_create_hash(GBT_get_species_count(GLOBAL_gb_main), GB_MIND_CASE);
623
624            int marked_found             = 0;
625            int partial_marked_sequences = 0;
626            int no_data                  = 0;      // no data in alignment
627
628            for (GBDATA *gb_marked = GBT_first_marked_species(GLOBAL_gb_main);
629                 !error && gb_marked;
630                 gb_marked = GBT_next_marked_species(gb_marked))
631            {
632                ++marked_found;
633
634                if (GBT_find_sequence(gb_marked, ap_main->get_aliname())) { // species has sequence in alignment
635                    const char *name = GBT_read_name(gb_marked);
636
637                    switch (GBT_is_partial(gb_marked, 1, true)) { // marks undef as 'partial sequence'
638                        case 0: { // full sequences
639                            aw_message(GBS_global_string("'%s' is a full sequence (cannot add partial)", name));
640                            ++full_marked_sequences;
641                            break;
642                        }
643                        case 1:     // partial sequences
644                            ++partial_marked_sequences;
645                            GBS_write_hash(partial_hash, name, (long)gb_marked);
646                            break;
647                        case -1:    // error
648                            error = GB_await_error();
649                            break;
650                        default:
651                            ap_assert(0);
652                            break;
653                    }
654                }
655                else {
656                    no_data++;
657                }
658            }
659
660            if (!error && !marked_found) error = "There are no marked species";
661
662            if (!error) {
663                NT_remove_species_in_tree_from_hash(rootNode(), partial_hash); // skip all species which are in tree
664                GBS_hash_do_loop(partial_hash, push_partial, &partial); // build partial list from hash
665
666                int partials_already_in_tree = partial_marked_sequences - partial.size();
667
668                if (no_data>0) aw_message(GBS_global_string("%i marked species have no data in '%s'", no_data, ap_main->get_aliname()));
669                if (full_marked_sequences>0) aw_message(GBS_global_string("%i marked species are declared full sequences", full_marked_sequences));
670                if (partials_already_in_tree>0) aw_message(GBS_global_string("%i marked species are already in tree", partials_already_in_tree));
671
672                if (partial.empty()) error = "No species left to add";
673            }
674        }
675
676        if (!error) error = GBT_add_new_changekey(GLOBAL_gb_main, "ARB_partial", GB_INT);
677
678        if (!error) {
679            rootNode()->reset_subtree_layout();
680
681            // find best matching full sequence for each partial sequence
682            error = nt_best_partial_match_rek(partial, rootNode());
683
684            list<PartialSequence>::iterator i = partial.begin();
685            list<PartialSequence>::iterator e = partial.end();
686
687            arb_progress part_insert_progress(partial.size());
688
689#if defined(DEBUG)
690            // show results :
691            for (; i != e; ++i) i->dump();
692            i = partial.begin();
693#endif // DEBUG
694
695            for (; i != e && !error; ++i) {
696                const char *name = i->get_name();
697
698                if (i->is_multi_match()) {
699                    aw_message(GBS_global_string("Insertion of '%s' is ambiguous.\n"
700                                                 "(took first of equal scored insertion points: %s)",
701                                                 name, i->get_multilist().c_str()));
702                }
703
704                AP_tree_nlen *part_leaf  = i->release();
705                AP_tree_nlen *full_seq   = const_cast<AP_tree_nlen*>(i->get_best_match());
706                AP_tree_nlen *brother    = full_seq->get_brother();
707                int           is_partial = 0;
708                AP_tree_nlen *target     = 0;
709
710                if (brother->is_leaf) {
711                    if (brother->gb_node) {
712                        is_partial = GBT_is_partial(brother->gb_node, 0, true);
713
714                        if (is_partial) { // brother is partial sequence
715                            target = brother; // insert as brother of brother
716                        }
717                        else {
718                            target = full_seq; // insert as brother of full_seq
719                        }
720                    }
721                    else {
722                        error = "There are zombies in your tree - please remove them";
723                    }
724                }
725                else {
726                    int partial_count = 0;
727                    int full_count    = 0;
728                    int zombie_count  = 0;
729
730                    count_partial_and_full(brother, &partial_count, &full_count, &zombie_count, 0, true);
731
732                    if (zombie_count) {
733                        error = "There are zombies in your tree - please remove them";
734                    }
735                    else if (full_count) {
736                        // brother is a subtree containing full sequences
737                        // -> add new brother to full_seq found above
738                        target = full_seq;
739                    }
740                    else {      // brother subtree only contains partial sequences
741                        // find one of the least-deep leafs
742                        int depth  = INT_MAX;
743                        target     = find_least_deep_leaf(brother, 0, &depth);
744                        is_partial = 1;
745                    }
746                }
747
748
749                if (!error) {
750#if defined(DEBUG)
751                    printf("inserting '%s'\n", name);
752#endif // DEBUG
753                    part_leaf->insert(target);
754
755                    // we need to create the sequence of the father node!
756                    AP_tree_nlen *father = part_leaf->get_father();
757                    father->costs();
758
759                    // ensure full-sequence is always on top
760                    if (father->rightson == target) {
761                        father->swap_sons();
762                    }
763
764                    if (!error) { // now correct the branch lengths modified by insert()
765                        // calc the original branchlen (of target leaf branch)
766                        GBT_LEN orglen = father->get_branchlength()+target->get_branchlength();
767
768                        if (is_partial) { // we have a subtree of partial sequences
769                            target->set_branchlength(orglen); // restore original branchlength
770                            father->set_branchlength(0); // all father branches are zero length
771                        }
772                        else { // we have a subtree of one full+one partial sequence
773                            ap_assert(full_seq->get_father() == father);
774
775                            father->set_branchlength(orglen); // father branch represents original length (w/o partial seq)
776                            full_seq->set_branchlength(0);    // full seq has no sub-branch length
777                        }
778                        part_leaf->set_branchlength(i->get_branchlength());
779                        printf("Adding with branchlength=%f\n", i->get_branchlength());
780                    }
781                }
782                else {
783                    delete part_leaf;
784                }
785
786                part_insert_progress.inc_and_check_user_abort(error);
787            }
788        }
789    }
790
791    if (full_marked_sequences) {
792        aw_message(GBS_global_string("%i marked full sequences were not added", full_marked_sequences));
793    }
794
795    if (error) {
796        aw_message(error);
797        GB_abort_transaction(GLOBAL_gb_main);
798    }
799    else {
800        GB_commit_transaction(GLOBAL_gb_main);
801    }
802
803    pars_saveNrefresh_changed_tree(ntw);
804}
805
806// -------------------------------
807//      add marked / selected
808
809static void NT_add_and_NNI(AW_window * aww, AWT_canvas *ntw, AddWhat what) { nt_add(aww, ntw, what, false); }
810static void NT_add_quick  (AW_window * aww, AWT_canvas *ntw, AddWhat what) { nt_add(aww, ntw, what, true);  }
811
812// ------------------------------------------
813//      remove and add marked / selected
814
815static void nt_reAdd(AW_window * aww, AWT_canvas *ntw, AddWhat what, bool quick) {
816    AW_awar *awar_best_pars = aww->get_root()->awar(AWAR_BEST_PARSIMONY);
817    int      oldparsval     = awar_best_pars->read_int();
818
819    AWT_graphic_tree *agt = AWT_TREE(ntw);
820    if (agt->get_root_node()) {
821        agt->tree_static->remove_leafs(AWT_RemoveType(AWT_REMOVE_BUT_DONT_FREE|AWT_REMOVE_MARKED));
822    }
823
824    // restore old parsimony value (otherwise the state where species were removed would count) :
825    awar_best_pars->write_int(oldparsval);
826
827    nt_add(aww, ntw, what, quick);
828}
829
830static void NT_reAdd_and_NNI(AW_window * aww, AWT_canvas *ntw, AddWhat what) { nt_reAdd(aww, ntw, what, false); }
831static void NT_reAdd_quick  (AW_window * aww, AWT_canvas *ntw, AddWhat what) { nt_reAdd(aww, ntw, what, true);  }
832
833// --------------------------------------------------------------------------------
834
835static void NT_branch_lengths(AW_window *, AWT_canvas *ntw) {
836    arb_progress progress("Calculating Branch Lengths");
837    rootEdge()->calc_branchlengths();
838    AWT_TREE(ntw)->reorder_tree(BIG_BRANCHES_TO_TOP);
839    pars_saveNrefresh_changed_tree(ntw);
840}
841
842static void NT_bootstrap(AW_window *, AWT_canvas *ntw, bool limit_only) {
843    arb_progress progress("Calculating Bootstrap Limit");
844    AP_BL_MODE mode       = AP_BL_MODE((limit_only ? AP_BL_BOOTSTRAP_LIMIT : AP_BL_BOOTSTRAP_ESTIMATE)|AP_BL_BL_ONLY);
845    rootEdge()->nni_rek(-1, false, mode, NULL);
846    AWT_TREE(ntw)->reorder_tree(BIG_BRANCHES_TO_TOP);
847    AWT_TREE(ntw)->displayed_root = AWT_TREE(ntw)->get_root_node();
848    pars_saveNrefresh_changed_tree(ntw);
849}
850
851static void NT_optimize(AW_window *, AWT_canvas *ntw) {
852    arb_progress progress("Optimizing Tree");
853    GLOBAL_PARS->optimize_tree(rootNode(), progress);
854    ASSERT_VALID_TREE(rootNode());
855    rootEdge()->calc_branchlengths();
856    AWT_TREE(ntw)->reorder_tree(BIG_BRANCHES_TO_TOP);
857    rootNode()->compute_tree();
858    pars_saveNrefresh_changed_tree(ntw);
859}
860
861static void NT_recursiveNNI(AW_window *, AWT_canvas *ntw) {
862    arb_progress progress("Recursive NNI");
863    AP_FLOAT orgPars = rootNode()->costs();
864    AP_FLOAT prevPars = orgPars;
865    progress.subtitle(GBS_global_string("Old parsimony: %.1f", orgPars));
866    while (!progress.aborted()) {
867        AP_FLOAT currPars = rootEdge()->nni_rek(-1, true, AP_BL_NNI_ONLY, NULL);
868        if (currPars == prevPars) break; // no improvement -> abort
869        progress.subtitle(GBS_global_string("New parsimony: %.1f (gain: %.1f)", currPars, orgPars-currPars));
870        prevPars = currPars;
871    }
872    rootEdge()->calc_branchlengths();
873    AWT_TREE(ntw)->reorder_tree(BIG_BRANCHES_TO_TOP);
874    rootNode()->compute_tree();
875    pars_saveNrefresh_changed_tree(ntw);
876}
877
878static AW_window *PARS_create_tree_settings_window(AW_root *aw_root) {
879    static AW_window_simple *aws = 0;
880    if (!aws) {
881        aws = new AW_window_simple;
882        aws->init(aw_root, "SAVE_DB", "SAVE ARB DB");
883        aws->load_xfig("awt/tree_settings.fig");
884
885        aws->at("close"); aws->callback((AW_CB0)AW_POPDOWN);
886        aws->create_button("CLOSE", "CLOSE", "C");
887
888        aws->at("help"); aws->callback(makeHelpCallback("nt_tree_settings.hlp"));
889        aws->create_button("HELP", "HELP", "H");
890
891        aws->at("button");
892        aws->auto_space(10, 10);
893        aws->label_length(30);
894
895        aws->label("Base Line Width");
896        aws->create_input_field(AWAR_DTREE_BASELINEWIDTH, 4);
897        aws->at_newline();
898
899        aws->label("Relative vert. Dist");
900        aws->create_input_field(AWAR_DTREE_VERICAL_DIST, 4);
901        aws->at_newline();
902
903        TREE_insert_jump_option_menu(aws, "On species change", AWAR_DTREE_AUTO_JUMP);
904        TREE_insert_jump_option_menu(aws, "On tree change",    AWAR_DTREE_AUTO_JUMP_TREE);
905    }
906    return aws;
907}
908
909// -----------------------
910//      test functions
911
912#if defined(TESTMENU)
913static void refreshTree(AWT_canvas *ntw) {
914    GB_transaction ta(ntw->gb_main);
915
916    AWT_TREE(ntw)->check_update(ntw->gb_main);
917    GB_ERROR error = AWT_TREE(ntw)->save(ntw->gb_main, 0, 0, 0);
918    if (error) aw_message(error);
919    ntw->zoom_reset_and_refresh();
920}
921#endif // TESTMENU
922
923static void setBranchlens(AP_tree_nlen *node, double newLen)
924{
925    node->setBranchlen(newLen, newLen);
926
927    if (!node->is_leaf)
928    {
929        setBranchlens(node->get_leftson(), newLen);
930        setBranchlens(node->get_rightson(), newLen);
931    }
932}
933#if defined(TESTMENU)
934static void TESTMENU_setBranchlen(AW_window *, AWT_canvas *ntw)
935{
936    AP_tree_nlen *root = rootNode();
937
938    setBranchlens(root, 1.0);
939    refreshTree(ntw);
940}
941
942static void TESTMENU_treeStats(AW_window *) {
943    ARB_tree_info tinfo;
944    AP_tree_nlen *root = rootNode();
945
946    if (root) {
947        {
948            GB_transaction ta(root->get_tree_root()->get_gb_main());
949            root->calcTreeInfo(tinfo);
950        }
951
952        puts("Tree stats:");
953
954        printf("nodes      =%6zu\n", tinfo.nodes());
955        printf(" inner     =%6zu\n", tinfo.innerNodes);
956        printf("  groups   =%6zu\n", tinfo.groups);
957        printf(" leafs     =%6zu\n", tinfo.leafs);
958        printf("  unlinked =%6zu (zombies?)\n", tinfo.unlinked);
959        printf("  linked   =%6zu\n", tinfo.linked());
960        printf("   marked  =%6zu\n", tinfo.marked);
961    }
962    else {
963        puts("No tree");
964    }
965}
966
967static void TESTMENU_mixTree(AW_window *, AWT_canvas *ntw)
968{
969    rootEdge()->mixTree(100);
970    refreshTree(ntw);
971}
972
973static void TESTMENU_sortTreeByName(AW_window *, AWT_canvas *ntw)
974{
975    AP_tree_nlen *root = rootNode();
976
977    root->sortByName();
978    refreshTree(ntw);
979}
980
981static void TESTMENU_buildAndDumpChain(AW_window *)
982{
983    AP_tree_nlen *root = rootNode();
984
985    root->get_leftson()->edgeTo(root->get_rightson())->testChain(2);
986    root->get_leftson()->edgeTo(root->get_rightson())->testChain(3);
987    root->get_leftson()->edgeTo(root->get_rightson())->testChain(4);
988    root->get_leftson()->edgeTo(root->get_rightson())->testChain(5);
989    root->get_leftson()->edgeTo(root->get_rightson())->testChain(6);
990    root->get_leftson()->edgeTo(root->get_rightson())->testChain(7);
991    root->get_leftson()->edgeTo(root->get_rightson())->testChain(8);
992    root->get_leftson()->edgeTo(root->get_rightson())->testChain(9);
993    root->get_leftson()->edgeTo(root->get_rightson())->testChain(10);
994    root->get_leftson()->edgeTo(root->get_rightson())->testChain(11);
995    root->get_leftson()->edgeTo(root->get_rightson())->testChain(-1);
996}
997
998static void init_TEST_menu(AW_window_menu_modes *awm, AWT_canvas *ntw)
999{
1000    awm->create_menu("Test[debug]", "g", AWM_ALL);
1001
1002    awm->insert_menu_topic("mixtree",         "Mix tree",           "M", "", AWM_ALL, makeWindowCallback(TESTMENU_mixTree, ntw));
1003    awm->insert_menu_topic("treestat",        "Tree statistics",    "s", "", AWM_ALL, TESTMENU_treeStats);
1004    awm->insert_menu_topic("setlens",         "Set branchlens",     "b", "", AWM_ALL, makeWindowCallback(TESTMENU_setBranchlen, ntw));
1005    awm->insert_menu_topic("sorttreebyname",  "Sort tree by name",  "o", "", AWM_ALL, makeWindowCallback(TESTMENU_sortTreeByName, ntw));
1006    awm->insert_menu_topic("buildndumpchain", "Build & dump chain", "c", "", AWM_ALL, TESTMENU_buildAndDumpChain);
1007}
1008#endif // TESTMENU
1009
1010static GB_ERROR pars_check_size(AW_root *awr, GB_ERROR& warning) {
1011    GB_ERROR error = NULL;
1012    warning        = NULL;
1013
1014    char *tree_name = awr->awar(AWAR_TREE)->read_string();
1015    char *filter    = awr->awar(AWAR_FILTER_FILTER)->read_string();
1016    long  ali_len   = 0;
1017
1018    if (strlen(filter)) {
1019        int i;
1020        for (i=0; filter[i]; i++) {
1021            if (filter[i] != '0') ali_len++;
1022        }
1023    }
1024    else {
1025        char *ali_name = awr->awar(AWAR_ALIGNMENT)->read_string();
1026        ali_len        = GBT_get_alignment_len(GLOBAL_gb_main, ali_name);
1027        if (ali_len<=0) {
1028            error = "Please select a valid alignment";
1029            GB_clear_error();
1030        }
1031        free(ali_name);
1032    }
1033
1034    if (!error) {
1035        long tree_size = GBT_size_of_tree(GLOBAL_gb_main, tree_name);
1036        if (tree_size == -1) {
1037            error = "Please select an existing tree";
1038        }
1039        else {
1040            unsigned long expected_memuse = (ali_len * tree_size * 4 / 1024);
1041            if (expected_memuse > GB_get_usable_memory()) {
1042                warning = GBS_global_string("Estimated memory usage (%s) exceeds physical memory (will swap)\n"
1043                                            "(did you specify a filter?)",
1044                                            GBS_readable_size(expected_memuse, "b"));
1045            }
1046        }
1047    }
1048
1049    free(filter);
1050    free(tree_name);
1051
1052    ap_assert(!GB_have_error());
1053    return error;
1054}
1055
1056static void pars_reset_optimal_parsimony(AW_window *aww, AWT_canvas *ntw) {
1057    AW_root *awr = aww->get_root();
1058    awr->awar(AWAR_BEST_PARSIMONY)->write_int(awr->awar(AWAR_PARSIMONY)->read_int());
1059    ntw->refresh();
1060}
1061
1062
1063static void pars_start_cb(AW_window *aw_parent, WeightedFilter *wfilt, const PARS_commands *cmds) {
1064    AW_root *awr = aw_parent->get_root();
1065    GB_begin_transaction(GLOBAL_gb_main);
1066    {
1067        GB_ERROR warning;
1068        GB_ERROR error = pars_check_size(awr, warning);
1069
1070        if (warning && !error) {
1071            char *question = GBS_global_string_copy("%s\nDo you want to continue?", warning);
1072            bool  cont     = aw_ask_sure("swap_warning", question);
1073            free(question);
1074
1075            if (!cont) error = "User abort";
1076
1077        }
1078
1079        if (error) {
1080            aw_message(error);
1081            GB_commit_transaction(GLOBAL_gb_main);
1082            return;
1083        }
1084    }
1085
1086
1087    AW_window_menu_modes *awm = new AW_window_menu_modes;
1088    awm->init(awr, "ARB_PARSIMONY", "ARB_PARSIMONY", 400, 200);
1089
1090    GLOBAL_PARS->generate_tree(wfilt);
1091
1092    AWT_canvas *ntw;
1093    {
1094        AP_tree_display_type  old_sort_type = global_tree()->tree_sort;
1095        global_tree()->set_tree_type(AP_LIST_SIMPLE, NULL); // avoid NDS warnings during startup
1096        ntw = new AWT_canvas(GLOBAL_gb_main, awm, awm->get_window_id(), global_tree(), AWAR_TREE);
1097        global_tree()->set_tree_type(old_sort_type, ntw);
1098    }
1099
1100    {
1101        GB_ERROR error = 0;
1102        arb_progress progress("loading tree");
1103        NT_reload_tree_event(awr, ntw, 0);             // load tree (but do not expose - first zombies need to be removed)
1104        if (!global_tree()->get_root_node()) {
1105            error = "Failed to load the selected tree";
1106        }
1107        else {
1108            AP_tree_edge::initialize(rootNode());   // builds edges
1109            long removed = global_tree()->tree_static->remove_leafs(AWT_REMOVE_ZOMBIES);
1110
1111            PARS_tree_init(global_tree());
1112            removed += global_tree()->tree_static->remove_leafs(AWT_RemoveType(AWT_REMOVE_ZOMBIES | AWT_REMOVE_NO_SEQUENCE));
1113
1114            if (!global_tree()->get_root_node()) {
1115                const char *aliname = global_tree()->tree_static->get_aliview()->get_aliname();
1116                error               = GBS_global_string("Less than 2 species contain data in '%s'\n"
1117                                                        "Tree vanished", aliname);
1118            }
1119            else if (removed) {
1120                aw_message(GBS_global_string("Removed %li leafs (zombies or species w/o data in alignment)", removed));
1121            }
1122
1123            error = GB_end_transaction(ntw->gb_main, error);
1124            if (!error) {
1125                progress.subtitle("Calculating inner nodes");
1126                GLOBAL_PARS->get_root_node()->costs();
1127            }
1128        }
1129        if (error) aw_popup_exit(error);
1130    }
1131
1132    awr->awar(AWAR_COLOR_GROUPS_USE)->add_callback(makeRootCallback(TREE_recompute_cb, ntw));
1133
1134    if (cmds->add_marked)           NT_add_quick(awm, ntw, NT_ADD_MARKED);
1135    if (cmds->add_selected)         NT_add_quick(awm, ntw, NT_ADD_SELECTED);
1136    if (cmds->calc_branch_lengths)  NT_branch_lengths(awm, ntw);
1137    if (cmds->calc_bootstrap)       NT_bootstrap(awm, ntw, 0);
1138    if (cmds->quit)                 pars_exit(awm);
1139
1140    GB_transaction ta(ntw->gb_main);
1141
1142    GBDATA *gb_arb_presets = GB_search(ntw->gb_main, "arb_presets", GB_CREATE_CONTAINER);
1143    GB_add_callback(gb_arb_presets, GB_CB_CHANGED, makeDatabaseCallback(AWT_expose_cb, ntw));
1144
1145#if defined(DEBUG)
1146    AWT_create_debug_menu(awm);
1147#endif // DEBUG
1148
1149    awm->create_menu("File", "F", AWM_ALL);
1150    {
1151        insert_macro_menu_entry(awm, false);
1152        awm->insert_menu_topic("print_tree", "Print Tree ...", "P", "tree2prt.hlp", AWM_ALL, makeWindowCallback(AWT_popup_print_window, ntw));
1153        awm->insert_menu_topic("quit",       "Quit",           "Q", "quit.hlp",     AWM_ALL, pars_exit);
1154    }
1155
1156    awm->create_menu("Species", "S", AWM_ALL);
1157    {
1158        NT_insert_mark_submenus(awm, ntw, 0);
1159
1160    }
1161    awm->create_menu("Tree", "T", AWM_ALL);
1162    {
1163
1164        awm->insert_menu_topic("nds",       "NDS (Node Display Setup) ...",      "N", "props_nds.hlp",   AWM_ALL, makeCreateWindowCallback(AWT_create_nds_window, ntw->gb_main));
1165
1166        awm->sep______________();
1167        awm->insert_menu_topic("tree_2_xfig", "Export tree to XFIG ...", "E", "tree2file.hlp", AWM_ALL, makeWindowCallback(AWT_popup_tree_export_window, ntw));
1168        awm->insert_menu_topic("tree_print",  "Print tree ...",          "P", "tree2prt.hlp",  AWM_ALL, makeWindowCallback(AWT_popup_print_window,       ntw));
1169        awm->sep______________();
1170        NT_insert_collapse_submenu(awm, ntw);
1171        awm->sep______________();
1172        awm->insert_sub_menu("Remove Species from Tree",     "R");
1173        {
1174            awm->insert_menu_topic("tree_remove_deleted", "Remove Zombies", "Z", "trm_del.hlp",    AWM_ALL, makeWindowCallback(NT_remove_leafs, ntw, AWT_RemoveType(AWT_REMOVE_BUT_DONT_FREE|AWT_REMOVE_ZOMBIES)));
1175            awm->insert_menu_topic("tree_remove_marked",  "Remove Marked",  "M", "trm_mrkd.hlp",   AWM_ALL, makeWindowCallback(NT_remove_leafs, ntw, AWT_RemoveType(AWT_REMOVE_BUT_DONT_FREE|AWT_REMOVE_MARKED)));
1176            awm->insert_menu_topic("tree_keep_marked",    "Keep Marked",    "K", "tkeep_mrkd.hlp", AWM_ALL, makeWindowCallback(NT_remove_leafs, ntw, AWT_RemoveType(AWT_REMOVE_BUT_DONT_FREE|AWT_KEEP_MARKED)));
1177        }
1178        awm->close_sub_menu();
1179        awm->insert_sub_menu("Add Species to Tree",      "A");
1180        {
1181            awm->insert_menu_topic("add_marked",         "Add Marked Species",                              "M", "pa_quick.hlp",   AWM_ALL, makeWindowCallback(NT_add_quick,     ntw, NT_ADD_MARKED));
1182            awm->insert_menu_topic("add_marked_nni",     "Add Marked Species + Local Optimization (NNI)",   "N", "pa_add.hlp",     AWM_ALL, makeWindowCallback(NT_add_and_NNI,   ntw, NT_ADD_MARKED));
1183            awm->insert_menu_topic("rm_add_marked",      "Remove & Add Marked Species",                     "R", "pa_quick.hlp",   AWM_ALL, makeWindowCallback(NT_reAdd_quick,   ntw, NT_ADD_MARKED));
1184            awm->insert_menu_topic("rm_add_marked_nni|", "Remove & Add Marked + Local Optimization (NNI)",  "L", "pa_add.hlp",     AWM_ALL, makeWindowCallback(NT_reAdd_and_NNI, ntw, NT_ADD_MARKED));
1185            awm->sep______________();
1186            awm->insert_menu_topic("add_marked_partial", "Add Marked Partial Species",                      "P", "pa_partial.hlp", AWM_ALL, makeWindowCallback(NT_add_partial,   ntw));
1187            awm->sep______________();
1188            awm->insert_menu_topic("add_selected",       "Add Selected Species",                            "S", "pa_quick.hlp",   AWM_ALL, makeWindowCallback(NT_add_quick,     ntw, NT_ADD_SELECTED));
1189            awm->insert_menu_topic("add_selected_nni",   "Add Selected Species + Local Optimization (NNI)", "O", "pa_add.hlp",     AWM_ALL, makeWindowCallback(NT_add_and_NNI,   ntw, NT_ADD_SELECTED));
1190        }
1191        awm->close_sub_menu();
1192        awm->sep______________();
1193        awm->insert_sub_menu("Tree Optimization",        "O");
1194        {
1195            awm->insert_menu_topic("nni",             "Local Optimization (NNI) of Marked Visible Nodes", "L", "",                 AWM_ALL, makeWindowCallback(NT_recursiveNNI, ntw));
1196            awm->insert_menu_topic("kl_optimization", "Global Optimization of Marked Visible Nodes",      "G", "pa_optimizer.hlp", AWM_ALL, makeWindowCallback(NT_optimize,     ntw));
1197        }
1198        awm->close_sub_menu();
1199        awm->insert_menu_topic("reset", "Reset optimal parsimony", "s", "", AWM_ALL, makeWindowCallback(pars_reset_optimal_parsimony, ntw));
1200        awm->sep______________();
1201        awm->insert_menu_topic("beautify_tree",       "Beautify Tree",            "B", "resorttree.hlp",       AWM_ALL, makeWindowCallback(NT_resort_tree_cb, ntw, BIG_BRANCHES_TO_TOP));
1202        awm->insert_menu_topic("calc_branch_lengths", "Calculate Branch Lengths", "L", "pa_branchlengths.hlp", AWM_ALL, makeWindowCallback(NT_branch_lengths, ntw));
1203        awm->sep______________();
1204        awm->insert_menu_topic("calc_upper_bootstrap_indep", "Calculate Upper Bootstrap Limit (dependent NNI)",   "d", "pa_bootstrap.hlp", AWM_ALL, makeWindowCallback(NT_bootstrap,        ntw, false));
1205        awm->insert_menu_topic("calc_upper_bootstrap_dep",   "Calculate Upper Bootstrap Limit (independent NNI)", "i", "pa_bootstrap.hlp", AWM_ALL, makeWindowCallback(NT_bootstrap,        ntw, true));
1206        awm->insert_menu_topic("tree_remove_remark",         "Remove Bootstrap Values",                           "V", "trm_boot.hlp",     AWM_ALL, makeWindowCallback(NT_remove_bootstrap, ntw));
1207    }
1208
1209#if defined(TESTMENU)
1210    init_TEST_menu(awm, ntw);
1211#endif // TESTMENU
1212
1213    awm->create_menu("Reset", "R", AWM_ALL);
1214    {
1215        awm->insert_menu_topic("reset_logical_zoom",  "Logical Zoom",  "L", "rst_log_zoom.hlp",  AWM_ALL, makeWindowCallback(NT_reset_lzoom_cb, ntw));
1216        awm->insert_menu_topic("reset_physical_zoom", "Physical Zoom", "P", "rst_phys_zoom.hlp", AWM_ALL, makeWindowCallback(NT_reset_pzoom_cb, ntw));
1217    }
1218
1219    awm->create_menu("Properties", "P", AWM_ALL);
1220    {
1221        awm->insert_menu_topic("props_menu",  "Menu: Colors and Fonts ...", "M", "props_frame.hlp",      AWM_ALL, AW_preset_window);
1222        awm->insert_menu_topic("props_tree",  "Tree: Colors and Fonts ...", "C", "pars_props_data.hlp",  AWM_ALL, makeCreateWindowCallback(AW_create_gc_window, ntw->gc_manager));
1223        awm->insert_menu_topic("props_tree2", "Tree: Settings ...",         "T", "nt_tree_settings.hlp", AWM_ALL, PARS_create_tree_settings_window);
1224        awm->insert_menu_topic("props_kl",    "KERN. LIN ...",              "K", "kernlin.hlp",          AWM_ALL, makeCreateWindowCallback(create_kernighan_window));
1225        awm->sep______________();
1226        AW_insert_common_property_menu_entries(awm);
1227        awm->sep______________();
1228        awm->insert_menu_topic("save_props", "Save Defaults (pars.arb)", "D", "savedef.hlp", AWM_ALL, AW_save_properties);
1229    }
1230    awm->button_length(5);
1231
1232    awm->insert_help_topic("ARB_PARSIMONY help", "P", "arb_pars.hlp", AWM_ALL, makeHelpCallback("arb_pars.hlp"));
1233
1234    // ----------------------
1235    //      mode buttons
1236    //
1237    // keep them synchronized as far as possible with those in ARB_PARSIMONY
1238    // see ../NTREE/NT_extern.cxx@keepModesSynchronized
1239
1240    awm->create_mode("mode_select.xpm", "mode_select.hlp", AWM_ALL, makeWindowCallback(nt_mode_event, ntw, AWT_MODE_SELECT));
1241    awm->create_mode("mode_mark.xpm",   "mode_mark.hlp",   AWM_ALL, makeWindowCallback(nt_mode_event, ntw, AWT_MODE_MARK));
1242    awm->create_mode("mode_group.xpm",  "mode_group.hlp",  AWM_ALL, makeWindowCallback(nt_mode_event, ntw, AWT_MODE_GROUP));
1243    awm->create_mode("mode_zoom.xpm",   "mode_pzoom.hlp",  AWM_ALL, makeWindowCallback(nt_mode_event, ntw, AWT_MODE_ZOOM));
1244    awm->create_mode("mode_lzoom.xpm",  "mode_lzoom.hlp",  AWM_ALL, makeWindowCallback(nt_mode_event, ntw, AWT_MODE_LZOOM));
1245
1246    // reserve mode-locations (to put the modes below at the same position as in ARB_NT)
1247    awm->create_mode("mode_empty.xpm", "mode.hlp", AWM_ALL, makeWindowCallback(nt_mode_event, ntw, AWT_MODE_EMPTY));
1248    awm->create_mode("mode_empty.xpm", "mode.hlp", AWM_ALL, makeWindowCallback(nt_mode_event, ntw, AWT_MODE_EMPTY));
1249
1250    // topology-modification-modes
1251    awm->create_mode("mode_setroot.xpm", "mode_setroot.hlp", AWM_ALL, makeWindowCallback(nt_mode_event, ntw, AWT_MODE_SETROOT));
1252    awm->create_mode("mode_swap.xpm",    "mode_swap.hlp",    AWM_ALL, makeWindowCallback(nt_mode_event, ntw, AWT_MODE_SWAP));
1253    awm->create_mode("mode_move.xpm",    "mode_move.hlp",    AWM_ALL, makeWindowCallback(nt_mode_event, ntw, AWT_MODE_MOVE));
1254
1255    awm->create_mode("mode_nni.xpm",      "mode_nni.hlp",      AWM_ALL, makeWindowCallback(nt_mode_event, ntw, AWT_MODE_NNI));
1256    awm->create_mode("mode_kernlin.xpm",  "mode_kernlin.hlp",  AWM_ALL, makeWindowCallback(nt_mode_event, ntw, AWT_MODE_KERNINGHAN));
1257    awm->create_mode("mode_optimize.xpm", "mode_optimize.hlp", AWM_ALL, makeWindowCallback(nt_mode_event, ntw, AWT_MODE_OPTIMIZE));
1258
1259    awm->at(5, 2);
1260    awm->auto_space(0, -2);
1261    awm->shadow_width(1);
1262
1263
1264    int db_treex, db_treey;
1265    awm->get_at_position(&db_treex, &db_treey);
1266    awm->callback(makeHelpCallback("nt_tree_select.hlp"));
1267    awm->button_length(16);
1268    awm->help_text("nt_tree_select.hlp");
1269    awm->create_button(0, AWAR_TREE);
1270
1271
1272    int db_stackx, db_stacky;
1273    awm->label_length(8);
1274    awm->label("Stored");
1275    awm->get_at_position(&db_stackx, &db_stacky);
1276    awm->button_length(6);
1277    awm->callback(makeHelpCallback("ap_stack.hlp"));
1278    awm->help_text("ap_stack.hlp");
1279    awm->create_button(0, AWAR_STACKPOINTER);
1280
1281    int db_parsx, db_parsy;
1282    awm->label_length(14);
1283    awm->label("Current Pars:");
1284    awm->get_at_position(&db_parsx, &db_parsy);
1285
1286    awm->button_length(10);
1287    awm->create_button(0, AWAR_PARSIMONY, 0, "+");
1288
1289    awm->button_length(0);
1290
1291    awm->callback(makeWindowCallback(NT_jump_cb, ntw, AP_JUMP_BY_BUTTON));
1292    awm->help_text("tr_jump.hlp");
1293    awm->create_button("JUMP", "Jump", 0);
1294
1295    awm->callback(makeHelpCallback("arb_pars.hlp"));
1296    awm->help_text("help.hlp");
1297    awm->create_button("HELP", "HELP", "H");
1298
1299    awm->at_newline();
1300
1301    awm->button_length(8);
1302    awm->at_x(db_stackx);
1303    awm->callback(makeWindowCallback(AP_user_pop_cb, ntw));
1304    awm->help_text("ap_stack.hlp");
1305    awm->create_button("POP", "RESTORE", 0);
1306
1307    awm->button_length(6);
1308    awm->callback(makeWindowCallback(AP_user_push_cb, ntw));
1309    awm->help_text("ap_stack.hlp");
1310    awm->create_button("PUSH", "STORE", 0);
1311
1312    awm->at_x(db_parsx);
1313    awm->label_length(14);
1314    awm->label("Optimal Pars:");
1315
1316    awm->button_length(10);
1317    awm->create_button(0, AWAR_BEST_PARSIMONY, 0, "+");
1318
1319    awm->button_length(0);
1320    awm->auto_space(0, -2);
1321
1322    awm->at_x(db_treex);
1323    awm->callback(makeWindowCallback(NT_set_tree_style, ntw, AP_TREE_RADIAL));
1324    awm->help_text("tr_type_radial.hlp");
1325    awm->create_button("RADIAL_TREE", "#radial.xpm", 0);
1326
1327    awm->callback(makeWindowCallback(NT_set_tree_style, ntw, AP_TREE_NORMAL));
1328    awm->help_text("tr_type_list.hlp");
1329    awm->create_button("LIST_TREE", "#dendro.xpm", 0);
1330
1331    awm->at_newline();
1332    awm->at(db_treex, awm->get_at_yposition());
1333
1334    {
1335        SmartPtr<AW_at_storage> maxSize(AW_at_storage::make(awm, AW_AT_MAXSIZE));
1336
1337        awm->button_length(AWAR_FOOTER_MAX_LEN);
1338        awm->create_button(0, AWAR_FOOTER);
1339        awm->at_newline();
1340        awm->restore_at_from(*maxSize);
1341    }
1342
1343    awm->get_at_position(&db_treex, &db_treey);
1344    awm->set_info_area_height(db_treey);
1345
1346    awm->set_bottom_area_height(0);
1347
1348    aw_parent->hide(); // hide parent
1349    awm->show();
1350
1351    awr->awar(AWAR_SPECIES_NAME)->add_callback(makeRootCallback(TREE_auto_jump_cb, ntw, false));
1352
1353    AP_user_push_cb(aw_parent, ntw); // push initial tree
1354}
1355
1356static AW_window *create_pars_init_window(AW_root *awr, const PARS_commands *cmds) {
1357    AW_window_simple *aws = new AW_window_simple;
1358    aws->init(awr, "PARS_PROPS", "SET PARSIMONY OPTIONS");
1359    aws->load_xfig("pars/init.fig");
1360
1361    aws->button_length(10);
1362    aws->label_length(10);
1363
1364    aws->callback(pars_exit);
1365    aws->at("close");
1366    aws->create_button("ABORT", "ABORT", "A");
1367
1368    aws->callback(makeHelpCallback("arb_pars_init.hlp"));
1369    aws->at("help");
1370    aws->create_button("HELP", "HELP", "H");
1371
1372    WeightedFilter *weighted_filter = // do NOT free (bound to callbacks)
1373        new WeightedFilter(GLOBAL_gb_main, aws->get_root(), AWAR_FILTER_NAME, AWAR_COLUMNSTAT_NAME, aws->get_root()->awar_string(AWAR_ALIGNMENT));
1374
1375    aws->at("filter");
1376    aws->callback(makeCreateWindowCallback(awt_create_select_filter_win, weighted_filter->get_adfiltercbstruct()));
1377    aws->create_button("SELECT_FILTER", AWAR_FILTER_NAME);
1378
1379    aws->at("weights");
1380    aws->callback(makeCreateWindowCallback(COLSTAT_create_selection_window, weighted_filter->get_column_stat()));
1381    aws->sens_mask(AWM_EXP);
1382    aws->create_button("SELECT_CSP", AWAR_COLUMNSTAT_NAME);
1383    aws->sens_mask(AWM_ALL);
1384
1385    aws->at("alignment");
1386    awt_create_ALI_selection_list(GLOBAL_gb_main, (AW_window *)aws, AWAR_ALIGNMENT, "*=");
1387
1388    aws->at("tree");
1389    awt_create_TREE_selection_list(GLOBAL_gb_main, aws, AWAR_TREE, true);
1390
1391    aws->callback(makeWindowCallback(pars_start_cb, weighted_filter, cmds));
1392    aws->at("go");
1393    aws->create_button("GO", "GO", "G");
1394
1395    return aws;
1396}
1397
1398static void create_parsimony_variables(AW_root *aw_root, AW_default db) {
1399    // kernighan
1400
1401    aw_root->awar_float("genetic/kh/nodes", 1.7, db);
1402    aw_root->awar_int("genetic/kh/maxdepth", 15, db);
1403    aw_root->awar_int("genetic/kh/incdepth", 5, db);
1404
1405    aw_root->awar_int("genetic/kh/static/enable", 1, db);
1406    aw_root->awar_int("genetic/kh/static/depth0", 2, db);
1407    aw_root->awar_int("genetic/kh/static/depth1", 2, db);
1408    aw_root->awar_int("genetic/kh/static/depth2", 2, db);
1409    aw_root->awar_int("genetic/kh/static/depth3", 2, db);
1410    aw_root->awar_int("genetic/kh/static/depth4", 1, db);
1411
1412    aw_root->awar_int("genetic/kh/dynamic/enable", 1,   db);
1413    aw_root->awar_int("genetic/kh/dynamic/start",  100, db);
1414    aw_root->awar_int("genetic/kh/dynamic/maxx",   6,   db);
1415    aw_root->awar_int("genetic/kh/dynamic/maxy",   150, db);
1416
1417    aw_root->awar_int("genetic/kh/function_type", AP_QUADRAT_START, db);
1418
1419    awt_create_dtree_awars(aw_root, db);
1420}
1421
1422static void pars_create_all_awars(AW_root *awr, AW_default aw_def) {
1423    awr->awar_string(AWAR_SPECIES_NAME, "",     GLOBAL_gb_main);
1424    awr->awar_string(AWAR_FOOTER,       "",     aw_def);
1425    awr->awar_string(AWAR_FILTER_NAME,  "none", GLOBAL_gb_main);
1426
1427    {
1428        GB_transaction  ta(GLOBAL_gb_main);
1429        char           *dali = GBT_get_default_alignment(GLOBAL_gb_main);
1430
1431        awr->awar_string(AWAR_ALIGNMENT, dali, GLOBAL_gb_main)->write_string(dali);
1432        free(dali);
1433    }
1434
1435    awt_set_awar_to_valid_filter_good_for_tree_methods(GLOBAL_gb_main, awr, AWAR_FILTER_NAME);
1436
1437    awr->awar_string(AWAR_FILTER_FILTER,    "", GLOBAL_gb_main);
1438    awr->awar_string(AWAR_FILTER_ALIGNMENT, "", aw_def);
1439
1440    awr->awar(AWAR_FILTER_ALIGNMENT)->map(AWAR_ALIGNMENT);
1441
1442    awr->awar_int(AWAR_PARS_TYPE, PARS_WAGNER, GLOBAL_gb_main);
1443
1444    {
1445        GB_transaction  ta(GLOBAL_gb_main);
1446        GBDATA *gb_tree_name = GB_search(GLOBAL_gb_main, AWAR_TREE, GB_STRING);
1447        char   *tree_name    = GB_read_string(gb_tree_name);
1448
1449        awr->awar_string(AWAR_TREE, "", aw_def)->write_string(tree_name);
1450        free(tree_name);
1451    }
1452
1453    awr->awar_int(AWAR_PARSIMONY,      0, aw_def);
1454    awr->awar_int(AWAR_BEST_PARSIMONY, 0, aw_def);
1455    awr->awar_int(AWAR_STACKPOINTER,   0, aw_def);
1456
1457    create_parsimony_variables(awr, GLOBAL_gb_main);
1458    create_nds_vars(awr, aw_def, GLOBAL_gb_main);
1459
1460#if defined(DEBUG)
1461    AWT_create_db_browser_awars(awr, aw_def);
1462#endif // DEBUG
1463
1464    GB_ERROR error = ARB_init_global_awars(awr, aw_def, GLOBAL_gb_main);
1465    if (error) aw_message(error);
1466}
1467
1468static AW_root *AD_map_viewer_aw_root = 0;
1469
1470void PARS_map_viewer(GBDATA *gb_species, AD_MAP_VIEWER_TYPE vtype) {
1471    if (vtype == ADMVT_SELECT && AD_map_viewer_aw_root && gb_species) {
1472        AD_map_viewer_aw_root->awar(AWAR_SPECIES_NAME)->write_string(GBT_read_name(gb_species));
1473    }
1474}
1475
1476int ARB_main(int argc, char *argv[]) {
1477    aw_initstatus();
1478
1479    GB_shell shell;
1480    AW_root *aw_root      = AWT_create_root("pars.arb", "ARB_PARS", need_macro_ability(), &argc, &argv);
1481    AD_map_viewer_aw_root = aw_root;
1482
1483    ap_main     = new AP_main;
1484    GLOBAL_PARS = new ArbParsimony(aw_root);
1485
1486    const char *db_server = ":";
1487
1488    PARS_commands cmds;
1489
1490    while (argc>=2 && argv[1][0] == '-') {
1491        argc--;
1492        argv++;
1493        if (!strcmp(argv[0], "-quit"))                   cmds.quit = 1;
1494        else if (!strcmp(argv[0], "-add_marked"))        cmds.add_marked = 1;
1495        else if (!strcmp(argv[0], "-add_selected"))      cmds.add_selected = 1;
1496        else if (!strcmp(argv[0], "-calc_branchlengths")) cmds.calc_branch_lengths = 1;
1497        else if (!strcmp(argv[0], "-calc_bootstrap"))    cmds.calc_bootstrap = 1;
1498        else {
1499            fprintf(stderr, "Unknown option '%s'\n", argv[0]);
1500
1501            printf("    Options:                Meaning:\n"
1502                   "\n"
1503                   "    -add_marked             add marked species   (without changing topology)\n"
1504                   "    -add_selected           add selected species (without changing topology)\n"
1505                   "    -calc_branchlengths     calculate branch lengths only\n"
1506                   "    -calc_bootstrap         estimate bootstrap values\n"
1507                   "    -quit                   quit after performing operations\n"
1508                   );
1509
1510            exit(EXIT_FAILURE);
1511        }
1512    }
1513
1514
1515    if (argc==2) db_server = argv[1];
1516
1517    GB_ERROR error = NULL;
1518    GLOBAL_gb_main = GBT_open(db_server, "rw");
1519
1520    if (!GLOBAL_gb_main) error = GB_await_error();
1521    else {
1522        error = configure_macro_recording(aw_root, "ARB_PARS", GLOBAL_gb_main);
1523
1524        if (!error) {
1525#if defined(DEBUG)
1526            AWT_announce_db_to_browser(GLOBAL_gb_main, GBS_global_string("ARB-database (%s)", db_server));
1527#endif // DEBUG
1528
1529            pars_create_all_awars(aw_root, AW_ROOT_DEFAULT);
1530
1531            AW_window *aww = create_pars_init_window(aw_root, &cmds);
1532            aww->show();
1533
1534            AWT_install_cb_guards();
1535            aw_root->main_loop();
1536        }
1537    }
1538
1539    if (error) aw_popup_exit(error);
1540    return EXIT_SUCCESS;
1541}
1542
1543
Note: See TracBrowser for help on using the repository browser.