source: tags/arb-6.0.5/PARSIMONY/PARS_main.cxx

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