ARB
ad_trees.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : ad_trees.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 #include "tree_position.h"
12 #include "ad_trees.h"
13 #include "NT_tree_cmp.h"
14 
15 #include <CT_ctree.hxx>
16 
17 #include <TreeAdmin.h>
18 #include <TreeRead.h>
19 #include <TreeWrite.h>
20 #include <TreeCallbacks.hxx>
21 
22 #include <awt_sel_boxes.hxx>
23 #include <awt_modules.hxx>
24 #include <awt_TreeAwars.hxx>
25 
26 #include <aw_awars.hxx>
27 #include <aw_edit.hxx>
28 #include <aw_file.hxx>
29 #include <aw_msg.hxx>
30 #include <aw_root.hxx>
31 #include <aw_select.hxx>
32 
33 #include <arb_strbuf.h>
34 #include <arb_file.h>
35 #include <arb_diff.h>
36 #include <arb_defs.h>
37 
38 #include <cctype>
39 #include <awt_config_manager.hxx>
40 
41 #define AWAR_TREE_SAV "ad_tree/"
42 #define AWAR_TREE_TMP "tmp/ad_tree/"
43 
44 #define AWAR_TREE_SECURITY AWAR_TREE_TMP "tree_security"
45 #define AWAR_TREE_REM AWAR_TREE_TMP "tree_rem"
46 #define AWAR_TREE_IMPORT AWAR_TREE_TMP "import_tree"
47 
48 #define AWAR_GROUPXFER_SAV AWAR_TREE_SAV "groupxfer/"
49 
50 #define AWAR_GROUPXFER_SOURCE AWAR_GROUPXFER_SAV "restrict"
51 #define AWAR_GROUPXFER_OVERWRITE_MODE AWAR_GROUPXFER_SAV "overwrite"
52 #define AWAR_GROUPXFER_INGROUP_ABS AWAR_GROUPXFER_SAV "ingroup/abs"
53 #define AWAR_GROUPXFER_INGROUP_REL AWAR_GROUPXFER_SAV "ingroup/rel"
54 #define AWAR_GROUPXFER_INGROUP_LIM AWAR_GROUPXFER_SAV "ingroup/lim"
55 #define AWAR_GROUPXFER_OUTGROUP_ABS AWAR_GROUPXFER_SAV "outgroup/abs"
56 #define AWAR_GROUPXFER_OUTGROUP_REL AWAR_GROUPXFER_SAV "outgroup/rel"
57 #define AWAR_GROUPXFER_OUTGROUP_LIM AWAR_GROUPXFER_SAV "outgroup/lim"
58 #define AWAR_GROUPXFER_UNKNOWN_ABS AWAR_GROUPXFER_SAV "unknown"
59 #define AWAR_GROUPXFER_KEELING AWAR_GROUPXFER_SAV "keeling"
60 #define AWAR_GROUPXFER_ACI AWAR_GROUPXFER_SAV "aci"
61 
62 #define AWAR_TREE_EXPORT_FILEBASE AWAR_TREE_TMP "export_tree"
63 #define AWAR_TREE_EXPORT_FILTER AWAR_TREE_EXPORT_FILEBASE "/filter"
64 #define AWAR_TREE_EXPORT_NAME AWAR_TREE_EXPORT_FILEBASE "/file_name"
65 
66 #define AWAR_TREE_EXPORT_SAV AWAR_TREE_SAV "export_tree/"
67 
68 #define AWAR_TREE_EXPORT_FORMAT AWAR_TREE_EXPORT_SAV "format"
69 #define AWAR_TREE_EXPORT_NDS AWAR_TREE_EXPORT_SAV "NDS"
70 #define AWAR_TREE_EXPORT_INCLUDE_BOOTSTRAPS AWAR_TREE_EXPORT_SAV "bootstraps"
71 #define AWAR_TREE_EXPORT_INCLUDE_BRANCHLENS AWAR_TREE_EXPORT_SAV "branchlens"
72 #define AWAR_TREE_EXPORT_INCLUDE_GROUPNAMES AWAR_TREE_EXPORT_SAV "groupnames"
73 #define AWAR_TREE_EXPORT_HIDE_FOLDED_GROUPS AWAR_TREE_EXPORT_SAV "hide_folded"
74 #define AWAR_TREE_EXPORT_QUOTEMODE AWAR_TREE_EXPORT_SAV "quote_mode"
75 #define AWAR_TREE_EXPORT_REPLACE AWAR_TREE_EXPORT_SAV "replace"
76 
77 
78 #define AWAR_TREE_CONSENSE_TMP AWAR_TREE_TMP "consense/"
79 #define AWAR_TREE_CONSENSE_SAV AWAR_TREE_SAV "consense/"
80 
81 #define AWAR_TREE_CONSENSE_TREE AWAR_TREE_CONSENSE_SAV "tree"
82 #define AWAR_TREE_CONSENSE_SELECTED AWAR_TREE_CONSENSE_TMP "selected"
83 
84 static void tree_vars_callback(AW_root *aw_root) {
85  // map tree awars to display database entries (security+comment)
86 
87  if (GLOBAL.gb_main) {
89 
90  char *treename = aw_root->awar(AWAR_TREE_NAME)->read_string();
91  GBDATA *gb_tree = GBT_find_tree(GLOBAL.gb_main, treename);
92 
93  if (!gb_tree) {
94  aw_root->awar(AWAR_TREE_SECURITY)->unmap();
95  aw_root->awar(AWAR_TREE_REM)->unmap();
96  }
97  else {
98  GBDATA *tree_prot = GB_search(gb_tree, "security", GB_FIND);
99  if (!tree_prot) GBT_readOrCreate_int(gb_tree, "security", GB_read_security_write(gb_tree));
100  tree_prot = GB_search(gb_tree, "security", GB_INT);
101 
102  GBDATA *tree_rem = GB_search(gb_tree, "remark", GB_STRING);
103  aw_root->awar(AWAR_TREE_SECURITY)->map(tree_prot);
104  aw_root->awar(AWAR_TREE_REM) ->map(tree_rem);
105  }
106 
107  // create default filename from tree-name:
108  {
109  char *suffix = aw_root->awar(AWAR_TREE_EXPORT_FILTER)->read_string();
110  char *fname = GBS_string_eval(treename, GBS_global_string("*=*1.%s:tree_*=*1", suffix));
111 
112  aw_root->awar(AWAR_TREE_EXPORT_NAME)->write_string(fname); // create default file name
113 
114  free(fname);
115  free(suffix);
116  }
117 
118  free(treename);
119  }
120 }
121 
122 static void update_default_treename_cb(AW_root *aw_root) {
123  // update import tree name depending on file name
125 
126  char *treename = aw_root->awar(AWAR_TREE_IMPORT "/file_name")->read_string();
127  char *treename_nopath = strrchr(treename, '/');
128 
129  if (treename_nopath) {
130  ++treename_nopath;
131  }
132  else {
133  treename_nopath = treename;
134  }
135 
136  char *fname = GBS_string_eval(treename_nopath, "*.tree=tree_*1:*.ntree=tree_*1:*.xml=tree_*1:.=:-=_: =_");
137  aw_root->awar(AWAR_TREE_IMPORT "/tree_name")->write_string(fname);
138 
139  free(fname);
140  free(treename);
141 }
142 
143 static void ad_tree_set_security(AW_root *aw_root) {
144  if (GLOBAL.gb_main) {
146 
147  char *treename = aw_root->awar(AWAR_TREE_NAME)->read_string();
148  GBDATA *gb_tree = GBT_find_tree(GLOBAL.gb_main, treename);
149 
150  if (gb_tree) {
151  long prot = aw_root->awar(AWAR_TREE_SECURITY)->read_int();
152  long old = GB_read_security_delete(gb_tree);
153 
154  GB_ERROR error = NULp;
155  if (old != prot) {
156  error = GB_write_security_delete(gb_tree, prot);
157  if (!error) error = GB_write_security_write(gb_tree, prot);
158  }
159  aw_message_if(error);
160  }
161  free(treename);
162  }
163 }
164 
169 };
170 
174 };
175 
176 static void update_filter_cb(AW_root *root) {
177  const char *filter_type = NULp;
178 
180  case AD_TREE_EXPORT_FORMAT_XML: filter_type = "xml"; break;
183  switch (ExportNodeType(root->awar(AWAR_TREE_EXPORT_NDS)->read_int())) {
184  case AD_TREE_EXPORT_NODE_SPECIES_NAME: filter_type = "tree"; break;
185  case AD_TREE_EXPORT_NODE_NDS: filter_type = "ntree"; break;
186  default: nt_assert(0); break;
187  }
188  break;
189  default: nt_assert(0); break;
190  }
191 
192  nt_assert(filter_type);
193  root->awar(AWAR_TREE_EXPORT_FILTER)->write_string(filter_type);
194 }
195 
196 void create_trees_var(AW_root *aw_root, AW_default aw_def) {
197  AW_awar *awar_tree_name = aw_root->awar_string(AWAR_TREE_NAME, NULp, aw_def)->set_srt(SRT_AUTOCORRECT_TREENAME);
198 
199  aw_root->awar_pointer(AWAR_GROUP, NULp, aw_def);
200 
201  TreeAdmin::create_awars(aw_root, aw_def, true);
202 
203  aw_root->awar_int (AWAR_TREE_SECURITY, 0, aw_def);
204  aw_root->awar_string(AWAR_TREE_REM, NULp, aw_def);
205 
206  AW_create_fileselection_awars(aw_root, AWAR_TREE_EXPORT_FILEBASE, "", ".tree", "treefile");
209 
210  aw_root->awar_int(AWAR_TREE_EXPORT_INCLUDE_BOOTSTRAPS, 0, aw_def);
211  aw_root->awar_int(AWAR_TREE_EXPORT_INCLUDE_BRANCHLENS, 1, aw_def);
212  aw_root->awar_int(AWAR_TREE_EXPORT_HIDE_FOLDED_GROUPS, 0, aw_def);
213  aw_root->awar_int(AWAR_TREE_EXPORT_INCLUDE_GROUPNAMES, 1, aw_def);
214  aw_root->awar_int(AWAR_TREE_EXPORT_QUOTEMODE, TREE_SINGLE_QUOTES, aw_def); // old default behavior
215  aw_root->awar_int(AWAR_TREE_EXPORT_REPLACE, 0, aw_def); // old default behavior
216 
217  AW_create_fileselection_awars(aw_root, AWAR_TREE_IMPORT, "", ".tree", "treefile");
218 
219  aw_root->awar_string(AWAR_TREE_IMPORT "/tree_name", "tree_", aw_def)->set_srt(SRT_AUTOCORRECT_TREENAME);
220 
222  awar_tree_name->add_callback(tree_vars_callback);
223  awar_tree_name->map(AWAR_TREE);
225 
228 
229  aw_root->awar_float(AWAR_GROUPXFER_INGROUP_ABS, 1.0, aw_def);
230  aw_root->awar_float(AWAR_GROUPXFER_OUTGROUP_ABS, 1.0, aw_def);
231  aw_root->awar_float(AWAR_GROUPXFER_INGROUP_REL, 0.0, aw_def);
232  aw_root->awar_float(AWAR_GROUPXFER_OUTGROUP_REL, 0.0, aw_def);
233  aw_root->awar_float(AWAR_GROUPXFER_INGROUP_LIM, 0.0, aw_def);
234  aw_root->awar_float(AWAR_GROUPXFER_OUTGROUP_LIM, 100.0, aw_def);
235  aw_root->awar_float(AWAR_GROUPXFER_UNKNOWN_ABS, 0.0001, aw_def);
236  aw_root->awar_float(AWAR_GROUPXFER_KEELING, 0.01, aw_def);
237 
238  aw_root->awar_string(AWAR_GROUPXFER_ACI, "", aw_def);
239 
240  aw_root->awar_string(AWAR_TREE_CONSENSE_TREE, "tree_consensus", aw_def)->set_srt(SRT_AUTOCORRECT_TREENAME);
241  AW_awar *ctree_awar = aw_root->awar_string(AWAR_TREE_CONSENSE_SELECTED, "", aw_def);
242  AWT_registerTreeAwarSimple(ctree_awar);
243 
244  update_filter_cb(aw_root);
245  tree_vars_callback(aw_root);
246 }
247 
248 static void tree_save_cb(AW_window *aww) {
249  AW_root *aw_root = aww->get_root();
250  char *tree_name = aw_root->awar(AWAR_TREE_NAME)->read_string();
251 
252  GB_ERROR error = NULp;
253 
254  if (!tree_name || !strlen(tree_name)) {
255  error = "Please select a tree first";
256  }
257  else {
258  char *fname = aw_root->awar(AWAR_TREE_EXPORT_NAME)->read_string();
259  char *db_name = aw_root->awar(AWAR_DB_NAME)->read_string();
260 
262  ExportTreeType exportType = static_cast<ExportTreeType>(aw_root->awar(AWAR_TREE_EXPORT_FORMAT)->read_int());
264 
265  switch (exportType) {
267  error = TREE_write_XML(GLOBAL.gb_main, db_name, tree_name, node_gen,
269  fname);
270  break;
271 
275  if (aw_root->awar(AWAR_TREE_EXPORT_REPLACE)->read_int()) {
276  quoteMode = TREE_node_quoting(quoteMode|TREE_FORCE_REPLACE);
277  }
278 
279  error = TREE_write_Newick(GLOBAL.gb_main, tree_name, node_gen,
284  quoteMode,
285  fname);
286  break;
287  }
288 
289  delete node_gen;
290  free(db_name);
291  free(fname);
292  }
293 
294  aww->hide_or_notify(error);
295  free(tree_name);
296 
298 }
299 
301  { AWAR_TREE_EXPORT_FORMAT, "format" },
302  { AWAR_TREE_EXPORT_NDS, "nodetype" },
304  { AWAR_TREE_EXPORT_INCLUDE_BOOTSTRAPS, "bootstraps" },
305  { AWAR_TREE_EXPORT_INCLUDE_GROUPNAMES, "groupnames" },
306  { AWAR_TREE_EXPORT_HIDE_FOLDED_GROUPS, "hidefolded" },
307  { AWAR_TREE_EXPORT_QUOTEMODE, "quotemode" },
308  { AWAR_TREE_EXPORT_REPLACE, "replacechars" },
309 
310  { NULp, NULp }
311 };
312 
314  AW_window_simple *aws = new AW_window_simple;
315  aws->init(root, "SAVE_TREE", "TREE SAVE");
316  aws->load_xfig("tree_export.fig");
317 
318  aws->at("close");
319  aws->callback(AW_POPDOWN);
320  aws->create_button("CLOSE", "CLOSE", "C");
321 
322  aws->at("help");
323  aws->callback(makeHelpCallback("tr_export.hlp"));
324  aws->create_button("HELP", "HELP", "H");
325 
327 
328  aws->auto_space(10, 10);
329 
330  aws->at("user");
331  aws->create_option_menu(AWAR_TREE_EXPORT_FORMAT, true);
332  aws->insert_option("NEWICK TREE FORMAT", "N", AD_TREE_EXPORT_FORMAT_NEWICK);
333  aws->insert_option("NEWICK TREE FORMAT (pretty, but big)", "P", AD_TREE_EXPORT_FORMAT_NEWICK_PRETTY);
334  aws->insert_option("ARB_XML TREE FORMAT", "X", AD_TREE_EXPORT_FORMAT_XML);
335  aws->update_option_menu();
336 
337  aws->at("user2");
338  aws->label("Nodetype");
339  aws->create_toggle_field(AWAR_TREE_EXPORT_NDS, 1);
340  aws->insert_default_toggle("Species ID ('name')", "S", 0);
341  aws->insert_toggle("NDS", "N", 1);
342  aws->update_toggle_field();
343 
344  aws->at_newline(); aws->label("Save branch lengths"); aws->create_toggle(AWAR_TREE_EXPORT_INCLUDE_BRANCHLENS);
345  aws->at_newline(); aws->label("Save bootstrap values"); aws->create_toggle(AWAR_TREE_EXPORT_INCLUDE_BOOTSTRAPS);
346  aws->at_newline(); aws->label("Save group names"); aws->create_toggle(AWAR_TREE_EXPORT_INCLUDE_GROUPNAMES);
347  aws->at_newline(); aws->label("Hide folded groups (XML only)"); aws->create_toggle(AWAR_TREE_EXPORT_HIDE_FOLDED_GROUPS);
348 
349  aws->at_newline();
350  aws->label("Name quoting (Newick only)");
351  aws->create_option_menu(AWAR_TREE_EXPORT_QUOTEMODE, true);
352  aws->insert_option("none", "n", TREE_DISALLOW_QUOTES);
353  aws->insert_option("single", "s", TREE_SINGLE_QUOTES);
354  aws->insert_option("double", "d", TREE_DOUBLE_QUOTES);
355  aws->insert_option("single (forced)", "i", TREE_SINGLE_QUOTES|TREE_FORCE_QUOTES);
356  aws->insert_option("double (forced)", "o", TREE_DOUBLE_QUOTES|TREE_FORCE_QUOTES);
357  aws->update_option_menu();
358 
359  aws->at_newline(); aws->label("Replace problem chars"); aws->create_toggle(AWAR_TREE_EXPORT_REPLACE);
360 
361  aws->at_newline();
362  aws->button_length(10);
363 
364  aws->callback(tree_save_cb);
365  aws->create_button("SAVE", "SAVE", "o");
366 
367  AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "tree_export", tree_export_config_mapping);
368 
369  aws->window_fit();
370  update_filter_cb(root);
371 
372  return aws;
373 }
374 
375 static char *readXmlTree(char *fname) {
376  // create a temp file
377  char tempFile[] = "newickXXXXXX";
378  int createTempFile = mkstemp(tempFile);
379 
380  if (createTempFile) {
381  GBS_strstruct buf(strlen(fname));
382 
383  // extract path from fname in order to place a copy of dtd file required to validate xml file
384  {
385  char *tmpFname = ARB_strdup(fname);
386  for (char *tok = strtok(tmpFname, "/"); tok;) {
387  char *tmp = tok;
388  tok = strtok(NULp, "/");
389  if (tok) {
390  buf.put('/');
391  buf.cat(tmp);
392  }
393  }
394  free(tmpFname);
395  }
396 
397  // linking arb_tree.dtd file to the Path from where xml file is loaded
398 #if defined(WARN_TODO)
399 #warning fix hack
400 #endif
401  char *command = GBS_global_string_copy("ln -s %s/lib/dtd/arb_tree.dtd %s/.", GB_getenvARBHOME(), buf.get_data());
403 
404  // execute xml2newick to convert xml format tree to newick format tree
405  command = GBS_global_string_copy("xml2newick %s %s", fname, tempFile);
407 
408  free(command);
409 
410  // return newick format tree file
411  return ARB_strdup(tempFile);
412  }
413  else {
414  printf("Failed to create Temporary File to Parse xml file!\n");
415  return NULp;
416  }
417 }
418 
419 static void tree_load_cb(AW_window *aww) {
420  GB_ERROR error = NULp;
421  AW_root *aw_root = aww->get_root();
422  char *tree_name = aw_root->awar(AWAR_TREE_IMPORT "/tree_name")->read_string();
423 
424  {
425  char *pcTreeFormat = aw_root->awar(AWAR_TREE_IMPORT "/filter")->read_string();
426  char *fname = aw_root->awar(AWAR_TREE_IMPORT "/file_name")->read_string();
427  if (strcmp(pcTreeFormat, "xml") == 0) {
428  char *tempFname = readXmlTree(fname);
429 
430  error = TREE_load_to_db(GLOBAL.gb_main, tempFname, tree_name);
431 
432  GB_unlink_or_warn(tempFname, NULp);
433  free(tempFname);
434  }
435  else {
436  error = TREE_load_to_db(GLOBAL.gb_main, fname, tree_name);
437  }
438 
439  free(fname);
440  free(pcTreeFormat);
441  }
442 
443  aww->hide_or_notify(error);
444  if (!error) aw_root->awar(AWAR_TREE)->write_string(tree_name); // show new tree
445 
446  free(tree_name);
447 }
448 
450  AW_window_simple *aws = new AW_window_simple;
451  aws->init(root, "LOAD_TREE", "TREE LOAD");
452  aws->load_xfig("sel_box_tree.fig");
453 
454  aws->at("close");
455  aws->callback(AW_POPDOWN);
456  aws->create_button("CLOSE", "CLOSE", "C");
457 
458  aws->at("help");
459  aws->callback(makeHelpCallback("tr_import.hlp"));
460  aws->create_button("HELP", "HELP", "H");
461 
462  aws->at("format");
463  aws->create_option_menu(AWAR_TREE_IMPORT "/filter", false);
464  aws->insert_default_option("Newick", "t", "tree");
465  aws->insert_option("XML", "x", "xml");
466  aws->update_option_menu();
467 
468  aws->at("user");
469  aws->label("Tree name");
470  aws->create_input_field(AWAR_TREE_IMPORT "/tree_name", 15);
471 
473 
474  aws->at("save2");
475  aws->callback(tree_load_cb);
476  aws->create_button("LOAD", "LOAD", "o");
477 
478  aws->window_fit();
479 
480  return aws;
481 }
482 
483 static void ad_move_tree_info(AW_window *aww, bool transferGroups) {
484  AW_root *awr = aww->get_root();
485 
486  char *log_file = NULp;
487  GB_ERROR error = NULp;
488 
491 
492  if (transferGroups) {
493  // log file is only written if transferring groups!
494  char *log_name = GB_unique_filename("arb_node", "log");
495  log_file = GB_create_tempfile(log_name);
496  if (!log_file) error = GB_await_error();
497  free(log_name);
498 
501  }
502 
503  if (!error) {
504  char *src_tree = TreeAdmin::source_tree_awar(awr)->read_string();
505  char *dst_tree = TreeAdmin::dest_tree_awar(awr)->read_string();
506  char *aci = awr->awar(AWAR_GROUPXFER_ACI)->read_string();
507 
508  NT_deselect_group(awr); // avoid crash (if group selected in target tree)
509 
510  GroupMatchScorer userScorer;
511  if (transferGroups) {
512  userScorer.setLimits(RatioLimits(awr->awar(AWAR_GROUPXFER_INGROUP_LIM)->read_float()/100, 1.0),
514 
518 
521  }
522 
523  error = NTREE_move_tree_info(GLOBAL.gb_main, src_tree, dst_tree, log_file, mode, what, userScorer, aci);
524 
525  if (mode == COMPARE_TOPOLOGY && !error) {
526  // if tree is not shown -> provide hint
527  TREE_canvas *canvas_showing_dest = NT_get_canvas_showing_tree(dst_tree, false);
528  if (!canvas_showing_dest) {
529  aw_message(GBS_global_string("Note: annotations added to tree '%s'\n"
530  "Press the right 'Display' button to view that tree", dst_tree));
531  }
532  }
533 
534  if (log_file) {
535  AW_edit(log_file);
536  GB_remove_on_exit(log_file);
537  }
538 
539  free(aci);
540  free(dst_tree);
541  free(src_tree);
542  }
543 
544  aw_message_if(error);
545 
546  free(log_file);
547 }
548 
549 static void swap_source_dest_cb(AW_window *aww) {
550  AW_root *root = aww->get_root();
551 
554 
555  char *old_src = s->read_string();
556  s->write_string(d->read_char_pntr());
557  d->write_string(old_src);
558  free(old_src);
559 }
560 
561 static void copy_tree_awar_cb(UNFIXED, AW_awar *aw_source, AW_awar *aw_dest) {
562  const char *tree = aw_source->read_char_pntr();
563  if (tree && tree[0]) aw_dest->write_string(tree);
564 }
565 
567  AW_root *root = aws->get_root();
568 
569  aws->auto_space(10, 3);
570 
571  aws->at("tree1");
573  aws->at("tree2");
575 
576  AW_awar *awar_displayed_tree = root->awar(AWAR_TREE_NAME);
577 
578  { // let source tree default to currently displayed tree:
579  static bool firstCall = true;
580  if (firstCall) {
581  TreeAdmin::source_tree_awar(root)->write_string(awar_displayed_tree->read_char_pntr());
582  firstCall = false;
583  }
584  }
585 
586 
587  aws->at("select1");
588  aws->callback(makeWindowCallback(copy_tree_awar_cb, awar_displayed_tree, TreeAdmin::source_tree_awar(root))); aws->create_autosize_button("SELECT_DISPLAYED1", "Use shown");
589  aws->callback(makeWindowCallback(copy_tree_awar_cb, TreeAdmin::source_tree_awar(root), awar_displayed_tree)); aws->create_autosize_button("DISPLAY_SELECTED1", "Display");
590 
592  aws->create_autosize_button("SWAP", "Swap");
593 
594  aws->at("select2");
595  aws->callback(makeWindowCallback(copy_tree_awar_cb, awar_displayed_tree, TreeAdmin::dest_tree_awar(root))); aws->create_autosize_button("SELECT_DISPLAYED2", "Use shown");
596  aws->callback(makeWindowCallback(copy_tree_awar_cb, TreeAdmin::dest_tree_awar(root), awar_displayed_tree)); aws->create_autosize_button("DISPLAY_SELECTED2", "Display");
597 }
598 
599 static AW_window_simple *create_select_other_tree_window(AW_root *root, const char *winId, const char *winTitle, const char *helpFile, AW_awar *awar_displayed_tree) {
600  AW_window_simple *aws = new AW_window_simple;
601  aws->init(root, winId, winTitle);
602  aws->load_xfig("ad_one_tree.fig");
603 
604  aws->at("close");
605  aws->auto_space(10, 3);
606 
607  aws->callback(AW_POPDOWN);
608  aws->create_button("CLOSE", "Close", "C");
609 
610  aws->at("help");
611  aws->callback(makeHelpCallback(helpFile));
612  aws->create_button("HELP", "Help", "H");
613 
614  AW_awar *awar_other_tree = TreeAdmin::dest_tree_awar(root);
615 
616  aws->at("tree");
617  awt_create_TREE_selection_list(GLOBAL.gb_main, aws, awar_other_tree->awar_name, true);
618 
619  aws->at("select");
620  aws->callback(makeWindowCallback(copy_tree_awar_cb, awar_displayed_tree, awar_other_tree)); aws->create_autosize_button("SELECT_DISPLAYED", "Use");
621  aws->callback(makeWindowCallback(copy_tree_awar_cb, awar_other_tree, awar_displayed_tree)); aws->create_autosize_button("DISPLAY_SELECTED", "Display");
622 
623  aws->at("user");
624 
625  return aws;
626 }
627 
629  AW_window_simple *aws = new AW_window_simple;
630  aws->init(root, "CMP_TOPOLOGY", "Compare tree topologies");
631  aws->load_xfig("compare_topo.fig");
632 
633  aws->at("close");
634  aws->callback(AW_POPDOWN);
635  aws->create_button("CLOSE", "Close", "C");
636 
637  aws->at("help");
638  aws->callback(makeHelpCallback("compare_topo.hlp"));
639  aws->create_button("HELP", "Help", "H");
640 
642 
643  aws->at("user");
644  aws->callback(makeWindowCallback(ad_move_tree_info, false));
645  aws->create_autosize_button("CMP_TOPOLOGY", "Compare topologies");
646 
647  return aws;
648 }
649 
651  { AWAR_GROUPXFER_INGROUP_ABS, "ingroup_abs" },
652  { AWAR_GROUPXFER_INGROUP_REL, "ingroup_rel" },
653  { AWAR_GROUPXFER_OUTGROUP_ABS, "outgroup_abs" },
654  { AWAR_GROUPXFER_OUTGROUP_REL, "outgroup_rel" },
655 
656  { AWAR_GROUPXFER_UNKNOWN_ABS, "unknown_abs" },
657  { AWAR_GROUPXFER_KEELING, "keeling" },
658 
659  { AWAR_GROUPXFER_INGROUP_LIM, "ingroup_lim" },
660  { AWAR_GROUPXFER_OUTGROUP_LIM, "outgroup_lim" },
661 
662  { AWAR_GROUPXFER_SOURCE, "sourceGroups" },
663  { AWAR_GROUPXFER_OVERWRITE_MODE, "overwriteGroups" },
664 
665  { AWAR_GROUPXFER_ACI, "aci" },
666 
667  { NULp, NULp },
668 };
669 
671  { "*only_perfect_groups", "Only copy perfectly matching groups with\n * 100% ingroup ratio and\n * 0% outgroup ratio", "ingroup_lim='100';outgroup_lim='0'" },
672 
673  { "*maximize_ingroup_ratio", "Maximize ingroup ratio \n over outgroup ratio.\n(Note: diff of factor 10 is maybe too strong)", "ingroup_abs='0';ingroup_rel='100';outgroup_abs='0';outgroup_rel='10'" },
674  { "*minimize_outgroup_ratio", "Minimize outgroup ratio \n over ingroup ratio.\n(Note: diff of factor 10 is maybe too strong)", "ingroup_abs='0';ingroup_rel='10';outgroup_abs='0';outgroup_rel='100'" },
675 
676  { "*report2name", "custom target group name:\n * add prefix \"XFRD_\" (allows to distinguish newly transferred from existing groups)\n * add suffix reporting penalty", "aci='\"XFRD_\";groupname;\" {penalty = \";penalty;\"}\"'" },
677 
678  { NULp, NULp, NULp },
679 };
680 
681 
682 
684  AW_window_simple *aws = new AW_window_simple;
685  aws->init(root, "COPY_NODE_INFO_OF_TREE", "Move groups");
686  aws->load_xfig("move_groups.fig");
687 
688  aws->button_length(11);
689 
690  aws->at("close");
691  aws->callback(AW_POPDOWN);
692  aws->create_button("CLOSE", "Close", "C");
693 
694  aws->at("help");
695  aws->callback(makeHelpCallback("move_groups.hlp"));
696  aws->create_button("HELP", "Help", "H");
697 
698  const int FLOAT_COLUMNS = 10;
699  const int PERCENT_COLUMNS = 5;
700 
701  aws->at("ipep"); aws->create_input_field(AWAR_GROUPXFER_INGROUP_ABS, FLOAT_COLUMNS);
702  aws->at("irp"); aws->create_input_field(AWAR_GROUPXFER_INGROUP_REL, FLOAT_COLUMNS);
703  aws->at("ilim"); aws->create_input_field(AWAR_GROUPXFER_INGROUP_LIM, PERCENT_COLUMNS);
704 
705  aws->at("opep"); aws->create_input_field(AWAR_GROUPXFER_OUTGROUP_ABS, FLOAT_COLUMNS);
706  aws->at("orp"); aws->create_input_field(AWAR_GROUPXFER_OUTGROUP_REL, FLOAT_COLUMNS);
707  aws->at("olim"); aws->create_input_field(AWAR_GROUPXFER_OUTGROUP_LIM, PERCENT_COLUMNS);
708 
709  aws->at("upep"); aws->create_input_field(AWAR_GROUPXFER_UNKNOWN_ABS, FLOAT_COLUMNS);
710  aws->at("keel"); aws->create_input_field(AWAR_GROUPXFER_KEELING, FLOAT_COLUMNS);
711 
712  aws->at("srcGrps");
713  aws->create_option_menu(AWAR_GROUPXFER_SOURCE, true);
714  aws->insert_option("all groups", "a", XFER_ALL_GROUPS);
715  aws->insert_option("groups with marked", "m", XFER_GROUPS_WITH_MARKED);
716  aws->update_option_menu();
717 
718  aws->at("tgtGrps");
719  aws->create_option_menu(AWAR_GROUPXFER_OVERWRITE_MODE, true);
720  aws->insert_option("remove existing groups", "r", REMOVE_EXISTING_GROUPS);
721  aws->insert_option("keep \"newname [was: oldname]\"", "k", KEEP_OLD_NAMES);
722  aws->update_option_menu();
723 
724  aws->at("aci");
725  aws->create_input_field(AWAR_GROUPXFER_ACI);
726 
728 
729  aws->at("go");
730  aws->callback(makeWindowCallback(ad_move_tree_info, true));
731  aws->create_button("GO", "GO", "G");
732 
733  aws->at("cfg");
734  AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "moveGroupInfo", moveGroupInfo_mapping, NULp, moveGroupInfo_predef);
735 
736  return aws;
737 }
738 
739 static void reorder_trees_cb(AW_window *aww, awt_reorder_mode dest) {
740  // moves the tree in the list of trees
741 
742  char *tree_name = aww->get_root()->awar(AWAR_TREE_NAME)->read_string();
743  GB_ERROR error = NULp;
744 
746  GBDATA *gb_treedata = GBT_get_tree_data(GLOBAL.gb_main);
747  GBDATA *gb_moved_tree = GB_entry(gb_treedata, tree_name);
748 
749  if (!gb_moved_tree) {
750  error = "No tree selected";
751  }
752  else {
753  GBT_ORDER_MODE move_mode;
754  GBDATA *gb_target_tree = NULp;
755 
756  switch (dest) {
757  case ARM_UP:
758  move_mode = GBT_INFRONTOF;
759  gb_target_tree = GBT_tree_infrontof(gb_moved_tree);
760  if (gb_target_tree) break;
761  FALLTHROUGH; // move top-tree up = move to bottom
762  case ARM_BOTTOM:
763  move_mode = GBT_BEHIND;
764  gb_target_tree = GBT_find_bottom_tree(GLOBAL.gb_main);
765  break;
766 
767  case ARM_DOWN:
768  move_mode = GBT_BEHIND;
769  gb_target_tree = GBT_tree_behind(gb_moved_tree);
770  if (gb_target_tree) break;
771  FALLTHROUGH; // move bottom-tree down = move to top
772  case ARM_TOP:
773  move_mode = GBT_INFRONTOF;
774  gb_target_tree = GBT_find_top_tree(GLOBAL.gb_main);
775  break;
776  }
777 
778  if (gb_target_tree && gb_target_tree != gb_moved_tree) {
779  error = GBT_move_tree(gb_moved_tree, move_mode, gb_target_tree);
780  }
781  }
782 
783  if (error) aw_message(error);
784  free(tree_name);
785 }
786 
788  static AW_window_simple *aws = NULp;
789 
790  if (!aws) {
791  AW_root *aw_root = awp->get_root();
792 
793  aws = new AW_window_simple;
794  aws->init(aw_root, "TREE_ADMIN", "TREE ADMIN");
795  aws->load_xfig("ad_tree.fig");
796 
797  aws->callback(AW_POPDOWN);
798  aws->at("close");
799  aws->create_button("CLOSE", "CLOSE", "C");
800 
801  aws->callback(makeHelpCallback("treeadm.hlp"));
802  aws->at("help");
803  aws->create_button("HELP", "HELP", "H");
804 
805  aws->button_length(40);
806 
807  aws->at("sel");
808  aws->create_button(NULp, AWAR_TREE_NAME, NULp, "+");
809 
810  aws->at("security");
811  aws->create_option_menu(AWAR_TREE_SECURITY, true);
812  aws->insert_option("0", "0", 0);
813  aws->insert_option("1", "1", 1);
814  aws->insert_option("2", "2", 2);
815  aws->insert_option("3", "3", 3);
816  aws->insert_option("4", "4", 4);
817  aws->insert_option("5", "5", 5);
818  aws->insert_default_option("6", "6", 6);
819  aws->update_option_menu();
820 
821  aws->at("rem");
822  aws->create_text_field(AWAR_TREE_REM);
823 
824 
825  aws->button_length(20);
826 
828 
829  aws->at("delete");
830  aws->help_text("treeadm.hlp");
831  aws->callback(makeWindowCallback(TreeAdmin::delete_tree_cb, &spec));
832  aws->create_button("DELETE", "Delete", "D");
833 
834  aws->at("rename");
835  aws->help_text("treeadm.hlp");
836  aws->callback(makeCreateWindowCallback(TreeAdmin::create_rename_window, &spec));
837  aws->create_button("RENAME", "Rename", "R");
838 
839  aws->at("copy");
840  aws->help_text("treeadm.hlp");
841  aws->callback(makeCreateWindowCallback(TreeAdmin::create_copy_window, &spec));
842  aws->create_button("COPY", "Copy", "C");
843 
844  aws->at("export");
845  aws->help_text("tr_export.hlp");
846  aws->callback(create_tree_export_window);
847  aws->create_button("EXPORT", "Export", "E");
848 
849  aws->at("import");
850  aws->help_text("tr_import.hlp");
851  aws->callback(create_tree_import_window);
852  aws->create_button("IMPORT", "Import", "I");
853 
854  aws->button_length(0);
855 
856  aws->at("list");
858 
859  aws->at("sort");
861  }
862 
863  aws->activate();
864 }
865 
866 // -----------------------
867 // consense tree
868 
869 
870 static void create_consense_tree_cb(AW_window *aww, AW_selection *selected_trees) {
871  AW_root *aw_root = aww->get_root();
872  GB_ERROR error = NULp;
873 
874  const char *cons_tree_name = aw_root->awar(AWAR_TREE_CONSENSE_TREE)->read_char_pntr();
875  if (!cons_tree_name || !cons_tree_name[0]) {
876  error = "No name specified for the consensus tree";
877  }
878  else {
879  StrArray tree_names;
880  selected_trees->get_values(tree_names);
881 
882  if (tree_names.size()<2) {
883  error = "Not enough trees selected (at least 2 needed)";
884  }
885  else {
887  GB_transaction ta(gb_main);
888 
889  {
890  arb_progress progress("Building consensus tree", 2L); // 2 steps: deconstruct, reconstruct
891  ConsensusTreeBuilder tree_builder;
892 
893  progress.subtitle("loading input trees");
894  for (size_t t = 0; t<tree_names.size() && !error; ++t) {
895  TreeRoot *root = new SizeAwareRoot; // will be deleted when tree gets deleted
896  SizeAwareTree *tree = DOWNCAST(SizeAwareTree*, GBT_read_tree(gb_main, tree_names[t], root));
897  if (!tree) {
898  error = GB_await_error();
899  }
900  else {
901  tree_builder.add(tree, tree_names[t], 1.0);
902  }
903  }
904 
905  if (!error) {
906  size_t species_count;
907  TreeNode *cons_tree = tree_builder.get(species_count, error); // triggers 2 implicit progress increments
908 
909  if (!error && progress.aborted()) {
910  error = "user abort";
911  }
912 
913  nt_assert(contradicted(cons_tree, error));
914  if (cons_tree) {
915  char *comment = tree_builder.get_tree_remark();
916  error = GBT_write_tree_with_remark(gb_main, cons_tree_name, cons_tree, comment);
917  free(comment);
918  UNCOVERED();
919  destroy(cons_tree);
920  }
921  }
922  if (error) progress.done();
923  }
924  error = ta.close(error);
925  }
926  }
927 
928  if (!error) {
929  aw_root->awar(AWAR_TREE_NAME)->write_string(cons_tree_name); // show in main window
930  }
931 
932  aw_message_if(error);
933 }
934 
936  AW_root *aw_root = aww->get_root();
938 }
939 
941  static AW_window_simple *aws = NULp;
942  if (!aws) {
943  aws = new AW_window_simple;
944  aws->init(aw_root, "CONSENSE_TREE", "Consensus Tree");
945  aws->load_xfig("ad_cons_tree.fig");
946 
947  aws->auto_space(10, 10);
948 
949  aws->callback(AW_POPDOWN);
950  aws->at("close");
951  aws->create_button("CLOSE", "CLOSE", "C");
952 
953  aws->callback(makeHelpCallback("consense_tree.hlp"));
954  aws->at("help");
955  aws->create_button("HELP", "HELP", "H");
956 
957  aws->at("list");
959  AW_selection *selected_trees = awt_create_subset_selection_list(aws, all_trees->get_sellist(), "selected", "add", "sort");
960 
961  aws->at("name");
962  aws->create_input_field(AWAR_TREE_CONSENSE_TREE);
963 
964  aws->callback(use_selected_as_target_cb);
965  aws->create_button("USE_AS_TARGET", "#moveLeft.xpm");
966 
967  aws->at("build");
968  aws->callback(makeWindowCallback(create_consense_tree_cb, selected_trees));
969  aws->create_autosize_button("BUILD", "Build consensus tree", "B");
970  }
971  return aws;
972 }
973 
975  // combines relative positions of a subtree in 2 trees (source- and target-tree).
976  // provides compare operations for SortByTopo
977 
978  TreeRelativePosition source; // in source tree ("ordering tree")
979  TreeRelativePosition target; // in target tree ("modified tree")
980 
981 public:
982 
984  : source(s),
985  target(t)
986  {
987  nt_assert(target.is_known());
988  }
990  : source(c1.source, c2.source),
991  target(c1.target, c2.target)
992  {}
993 
994  int compare(const CombinedPosInfo &right) const {
995  // result similar to strcmp(this, right)
996  if (!source.is_known() || !right.source.is_known()) {
997  // one subtree is completely unknown in source-tree
998  // => keep target-tree order
999  return target.compare(right.target);
1000  }
1001  return source.compare(right.source);
1002  }
1003 };
1004 
1005 class SortByTopo : virtual Noncopyable {
1006  TreePositionLookup source_pos; // in ordering topology
1007  const TreePositionLookup *target_pos; // in target topology (used where source_pos does not provide order)
1008 
1009  CombinedPosInfo reorder_subtree_rec(TreeNode *node) { // similar to ../ARBDB/TreeNode.cxx@reorder_subtree
1010  static const char *smallest_leafname; // has to be set to the alphabetically smallest name (when function exits)
1011 
1012  if (node->is_leaf()) {
1013  smallest_leafname = node->name;
1014  return CombinedPosInfo(source_pos.relative(node->name),
1015  target_pos->relative(node->name));
1016  }
1017 
1018  CombinedPosInfo leftInfo = reorder_subtree_rec(node->get_leftson());
1019  const char *smallest_left = smallest_leafname;
1020  CombinedPosInfo rightInfo = reorder_subtree_rec(node->get_rightson());
1021  const char *smallest_right = smallest_leafname;
1022 
1023  bool left_leafname_bigger = strcmp(smallest_left, smallest_right)>0;
1024  smallest_leafname = left_leafname_bigger ? smallest_right : smallest_left;
1025 
1026  {
1027  int cmp = leftInfo.compare(rightInfo);
1028  if (cmp>0 || (cmp == 0 && left_leafname_bigger)) {
1029  node->swap_sons();
1030  }
1031  }
1032 
1033  return CombinedPosInfo(leftInfo, rightInfo);
1034  }
1035 public:
1036 
1038  : source_pos(by),
1039  target_pos(NULp)
1040  {}
1041 
1042 #if defined(UNIT_TESTS)
1043  TreeRelativePosition sourcePos(const char *name) { return source_pos.relative(name); }
1044 #endif
1045 
1047  TreePositionLookup tpos(tree);
1048  LocallyModify<const TreePositionLookup*> provide(target_pos, &tpos);
1049  reorder_subtree_rec(tree);
1050  }
1051 };
1052 
1053 static GB_ERROR sort_tree_by_other_tree(GBDATA *gb_main, TreeNode *tree, const char *other_tree) {
1054  GB_ERROR error = NULp;
1055  GB_transaction ta(gb_main);
1056 
1057  TreeNode *otherTree = GBT_read_tree(gb_main, other_tree, new SimpleRoot);
1058  if (!otherTree) error = GB_await_error();
1059  else {
1060  SortByTopo sorter(otherTree);
1061  destroy(otherTree);
1062  sorter.reorder_subtree(tree);
1063  }
1064  return error;
1065 }
1066 
1068  const char *other_tree = TreeAdmin::dest_tree_awar(AW_root::SINGLETON)->read_char_pntr();
1069  error = sort_tree_by_other_tree(GLOBAL.gb_main, tree, other_tree);
1070  return !error;
1071 }
1072 
1075  aw_message_if(error);
1076 }
1077 
1079  AW_window_simple *aws = create_select_other_tree_window(aw_root, ntw->aww->local_id("SORT_BY_OTHER"), "Sort tree by other tree", "resortbyother.hlp", ntw->get_awar_tree());
1080 
1081  aws->callback(makeWindowCallback(sort_tree_by_other_tree_cb, ntw));
1082  aws->create_autosize_button("RESORT", "Sort according to source tree");
1083 
1084  return aws;
1085 }
1086 
1087 // ---------------------------
1088 // multifurcate tree
1089 
1090 #define AWAR_MFURC "tree/multifurc/"
1091 #define AWAR_MFURC_CONSIDER_BOOTSTRAP AWAR_MFURC "use_bs"
1092 #define AWAR_MFURC_CONSIDER_LENGTH AWAR_MFURC "use_len"
1093 #define AWAR_MFURC_CONSIDER_TERMINALS AWAR_MFURC "terminals"
1094 #define AWAR_MFURC_LENGTH_LIMIT AWAR_MFURC "len"
1095 #define AWAR_MFURC_BOOTSTRAP_LIMIT AWAR_MFURC "bs"
1096 
1098  aw_root->awar_int (AWAR_MFURC_CONSIDER_BOOTSTRAP, 0, props);
1099  aw_root->awar_int (AWAR_MFURC_CONSIDER_LENGTH, 1, props);
1100  aw_root->awar_int (AWAR_MFURC_CONSIDER_TERMINALS, 0, props);
1101  aw_root->awar_float(AWAR_MFURC_LENGTH_LIMIT, 0.1, props);
1102  aw_root->awar_float(AWAR_MFURC_BOOTSTRAP_LIMIT, 50, props);
1103 }
1105  AW_root *aw_root = ntw->aww->get_root();
1106 
1107  float below_bootstrap = 101.0;
1108  float below_length = 1000000.0;
1109  bool applyAtLeafs = aw_root->awar(AWAR_MFURC_CONSIDER_TERMINALS)->read_int();
1110 
1111  if (aw_root->awar(AWAR_MFURC_CONSIDER_BOOTSTRAP)->read_int()) below_bootstrap = aw_root->awar(AWAR_MFURC_BOOTSTRAP_LIMIT)->read_float();
1112  if (aw_root->awar(AWAR_MFURC_CONSIDER_LENGTH) ->read_int()) below_length = aw_root->awar(AWAR_MFURC_LENGTH_LIMIT) ->read_float();
1113 
1114  NT_multifurcate_tree(ntw, TreeNode::multifurc_limits(below_bootstrap, below_length, applyAtLeafs));
1115 }
1117  AW_window_simple *aws = new AW_window_simple;
1118 
1119  aws->init(aw_root, ntw->aww->local_id("multifurcate"), "Multifurcate tree");
1120  aws->at(10, 10);
1121  aws->auto_space(10, 10);
1122 
1123  aws->callback(AW_POPDOWN);
1124  aws->create_button("CLOSE", "CLOSE", "C");
1125 
1126  aws->callback(makeHelpCallback("multifurcate.hlp"));
1127  aws->create_button("HELP", "HELP", "H");
1128 
1129  const int LABEL_LENGTH = 46;
1130  aws->label_length(LABEL_LENGTH);
1131 
1132  aws->at_newline();
1133  aws->label("Multifurcate branches with branchlength below");
1134  aws->create_toggle(AWAR_MFURC_CONSIDER_LENGTH);
1135  aws->create_input_field(AWAR_MFURC_LENGTH_LIMIT, 10);
1136 
1137  aws->at_newline();
1138  aws->label(" AND bootstrap below");
1139  aws->create_toggle(AWAR_MFURC_CONSIDER_BOOTSTRAP);
1140  aws->create_input_field(AWAR_MFURC_BOOTSTRAP_LIMIT, 10);
1141 
1142  aws->label_length(0);
1143  aws->at_newline();
1144  aws->label("Also apply to terminal branches");
1145  aws->create_toggle(AWAR_MFURC_CONSIDER_TERMINALS);
1146 
1147  aws->at_newline();
1148  aws->callback(makeWindowCallback(multifurcation_cb, ntw));
1149  aws->create_autosize_button("MULTIFURCATE", "Multifurcate", "M");
1150 
1151  return aws;
1152 }
1153 
1154 // --------------------------------------------------------------------------------
1155 
1156 #ifdef UNIT_TESTS
1157 #ifndef TEST_UNIT_H
1158 #include <test_unit.h>
1159 #endif
1160 
1161 static const char *getTreeComment(GBDATA *gb_main, const char *treeName) {
1162  GB_transaction ta(gb_main);
1163  return GBT_tree_info_string(gb_main, treeName, -1);
1164 }
1165 
1166 #define TEST_EXPECT_TREE_COMMENT_CONTAINS(treeName,expected) TEST_EXPECT_CONTAINS(getTreeComment(gb_main,treeName),expected)
1167 #define TEST_EXPECT_TREE_COMMENT_DOESNT_CONTAIN(treeName,expected) TEST_EXPECT_DOESNT_CONTAIN(getTreeComment(gb_main,treeName),expected)
1168 #define TEST_EXPECT_TREE_COMMENT_DOESNT_CONTAIN__BROKEN(treeName,expected) TEST_EXPECT_DOESNT_CONTAIN__BROKEN(getTreeComment(gb_main,treeName),expected)
1169 
1170 static GB_ERROR sort_namedtree_by_other_tree(GBDATA *gb_main, const char *tree, const char *other_tree) {
1171  GB_ERROR error = NULp;
1172  GB_transaction ta(gb_main);
1173  SizeAwareTree *Tree = DOWNCAST(SizeAwareTree*, GBT_read_tree(gb_main, tree, new SizeAwareRoot));
1174  if (!Tree) error = GB_await_error();
1175  else {
1176  Tree->compute_tree();
1177  error = sort_tree_by_other_tree(gb_main, Tree, other_tree);
1178  if (!error) error = GBT_write_tree(gb_main, tree, Tree);
1179  }
1180  destroy(Tree);
1181  return error;
1182 }
1183 
1184 void TEST_sort_tree_by_other_tree() {
1185  GB_shell shell;
1186  GBDATA *gb_main = GB_open("TEST_trees.arb", "rw");
1187  TEST_REJECT_NULL(gb_main);
1188 
1189  const char *topo_test = "(((((((CloTyro3:1.046,CloTyro4:0.061):0.026,CloTyro2:0.017):0.017,CloTyrob:0.009):0.274,CloInnoc:0.371):0.057,CloBifer:0.388):0.124,(((CloButy2:0.009,CloButyr:0.000):0.564,CloCarni:0.120):0.010,CloPaste:0.179):0.131):0.081,((((CorAquat:0.084,CurCitre:0.058):0.103,CorGluta:0.522):0.053,CelBiazo:0.059):0.207,CytAquat:0.711):0.081);";
1190  const char *topo_center = "(((CloPaste:0.179,((CloButy2:0.009,CloButyr:0.000):0.564,CloCarni:0.120):0.010):0.131,((CloInnoc:0.371,((CloTyro2:0.017,(CloTyro3:1.046,CloTyro4:0.061):0.026):0.017,CloTyrob:0.009):0.274):0.057,CloBifer:0.388):0.124):0.081,((CelBiazo:0.059,((CorAquat:0.084,CurCitre:0.058):0.103,CorGluta:0.522):0.053):0.207,CytAquat:0.711):0.081);";
1191  const char *topo_bottom = "((CytAquat:0.711,(CelBiazo:0.059,(CorGluta:0.522,(CorAquat:0.084,CurCitre:0.058):0.103):0.053):0.207):0.081,((CloPaste:0.179,(CloCarni:0.120,(CloButy2:0.009,CloButyr:0.000):0.564):0.010):0.131,(CloBifer:0.388,(CloInnoc:0.371,(CloTyrob:0.009,(CloTyro2:0.017,(CloTyro3:1.046,CloTyro4:0.061):0.026):0.017):0.274):0.057):0.124):0.081);";
1192 
1193  const char *topo_vs_nj_bs = "(((((((CloTyro3:1.046,CloTyro4:0.061):0.026,CloTyro2:0.017):0.017,CloTyrob:0.009):0.274,CloInnoc:0.371):0.057,CloBifer:0.388):0.124,(((CloButyr:0.000,CloButy2:0.009):0.564,CloCarni:0.120):0.010,CloPaste:0.179):0.131):0.081,(((CorGluta:0.522,(CorAquat:0.084,CurCitre:0.058):0.103):0.053,CelBiazo:0.059):0.207,CytAquat:0.711):0.081);";
1194 
1195  TEST_EXPECT_DIFFERENT(topo_test, topo_center);
1196  TEST_EXPECT_DIFFERENT(topo_test, topo_bottom);
1197  TEST_EXPECT_DIFFERENT(topo_center, topo_bottom);
1198 
1199  // create sorted copies of tree_test
1200  {
1201  GB_transaction ta(gb_main);
1202  SizeAwareTree *tree = DOWNCAST(SizeAwareTree*, GBT_read_tree(gb_main, "tree_test", new SizeAwareRoot));
1203  TEST_REJECT_NULL(tree);
1204  TEST_EXPECT_NEWICK(nLENGTH, tree, topo_test);
1205 
1206  tree->reorder_tree(BIG_BRANCHES_TO_CENTER); TEST_EXPECT_NO_ERROR(GBT_write_tree(gb_main, "tree_sorted_center", tree)); TEST_EXPECT_NEWICK(nLENGTH, tree, topo_center);
1207  tree->reorder_tree(BIG_BRANCHES_TO_BOTTOM); TEST_EXPECT_NO_ERROR(GBT_write_tree(gb_main, "tree_sorted_bottom", tree)); TEST_EXPECT_NEWICK(nLENGTH, tree, topo_bottom);
1208 
1209  // test SortByTopo
1210  {
1211  SortByTopo sbt(tree);
1212  const double EPSILON = 0.0001;
1213 
1214  TEST_EXPECT_SIMILAR(sbt.sourcePos("CytAquat").value(), 0.0, EPSILON); // leftmost species (in topo_bottom)
1215  TEST_EXPECT_SIMILAR(sbt.sourcePos("CloTyro4").value(), 1.0, EPSILON); // rightmost species
1216 
1217  TEST_EXPECT_SIMILAR(sbt.sourcePos("CurCitre").value(), 0.2857, EPSILON); // (5 of 15)
1218  TEST_EXPECT_SIMILAR(sbt.sourcePos("CloButy2").value(), 0.5, EPSILON); // center species (8 of 15)
1219  TEST_EXPECT_SIMILAR(sbt.sourcePos("CloTyrob").value(), 0.7857, EPSILON); // (12 of 15)
1220 
1221  TEST_REJECT(sbt.sourcePos("Un-Known").is_known()); // unknown species
1222  }
1223 
1224  tree->reorder_tree(BIG_BRANCHES_TO_EDGE); TEST_EXPECT_NO_ERROR(GBT_write_tree(gb_main, "tree_work", tree));
1225 
1226  destroy(tree);
1227  }
1228 
1229 
1230  TEST_EXPECT_NO_ERROR(sort_namedtree_by_other_tree(gb_main, "tree_work", "tree_sorted_center")); TEST_EXPECT_SAVED_NEWICK(nLENGTH, gb_main, "tree_work", topo_center);
1231  TEST_EXPECT_NO_ERROR(sort_namedtree_by_other_tree(gb_main, "tree_work", "tree_sorted_bottom")); TEST_EXPECT_SAVED_NEWICK(nLENGTH, gb_main, "tree_work", topo_bottom);
1232  TEST_EXPECT_NO_ERROR(sort_namedtree_by_other_tree(gb_main, "tree_work", "tree_test")); TEST_EXPECT_SAVED_NEWICK(nLENGTH, gb_main, "tree_work", topo_test);
1233  TEST_EXPECT_NO_ERROR(sort_namedtree_by_other_tree(gb_main, "tree_work", "tree_nj_bs")); TEST_EXPECT_SAVED_NEWICK(nLENGTH, gb_main, "tree_work", topo_vs_nj_bs);
1234 
1235  // TEST_EXPECT_NO_ERROR(GB_save_as(gb_main, "TEST_trees_save.arb", "b")); // test-save db to examine saved trees (do not commit!)
1236 
1237  // ----------------------------------------------------------------------------------------------------
1238  // test high-level function TREE_load_to_db (see #701; placed here by laziness, not related to sorting trees)
1239  TEST_EXPECT_NO_ERROR(TREE_load_to_db(gb_main, "trees/test.tree", "tree_loaded")); // ../UNIT_TESTER/run/trees/test.tree
1240  TEST_EXPECT_ERROR_CLEAR();
1241  TEST_EXPECT_SAVED_NEWICK(nALL, gb_main, "tree_loaded", "(((s1:0.200,s2:0.400):0.600,(s3:0.300,s 4:0.100):0.100):0.000,(s5:0.020,s-6:0.040):0.060);");
1242  TEST_EXPECT_TREE_COMMENT_CONTAINS("tree_loaded", "covering most of tree reader code"); // test comment
1243 
1244  GB_close(gb_main);
1245 }
1246 
1247 void TEST_move_node_info() {
1248  GB_shell shell;
1249  GBDATA *gb_main = GB_open("TEST_trees.arb", "r");
1250 
1251  const char *treeTarget1 = "tree_removal";
1252  const char *treeTarget2 = "tree_test";
1253  const char *treeSortby1 = "tree_removal_copy";
1254  const char *treeSortby2 = "tree_test_copy";
1255 
1256  const char *treeSource1 = treeSortby2; // contains 1 group ("test")
1257  const char *treeSource2 = "tree_tree2"; // contains 2 groups ("g2" + "outer")
1258  const char *treeSource3 = "tree_groups"; // contains 5 groups
1259 
1260 #define GROUP_TEST "(CloTyrob,(CloTyro2,(CloTyro3,CloTyro4)))"
1261 #define GROUP_TEST_FLIPPED "(((CloTyro3,CloTyro4),CloTyro2),CloTyrob)"
1262 
1263 #define NAMED_GROUP_TEST GROUP_TEST "'test'"
1264 #define OVERWRITTEN_GROUP_TEST GROUP_TEST "'g2 [was: test]'"
1265 
1266  const char *org_topo1 = "((CloInnoc," GROUP_TEST "),(CloBifer,((CloCarni,CurCitre),((CloPaste,(Zombie1,(CloButy2,CloButyr))),(CytAquat,(CelBiazo,(CorGluta,(CorAquat,Zombie2))))))));";
1267  const char *org_topo2 = "((((" GROUP_TEST_FLIPPED ",CloInnoc),CloBifer),(((CloButy2,CloButyr),CloCarni),CloPaste)),((((CorAquat,CurCitre),CorGluta),CelBiazo),CytAquat));";
1268 
1269  // (index convention := source target)
1270  const char *unwanted_topo11 = "((CytAquat,(CelBiazo,(CorGluta,(CorAquat,Zombie2)))),((CloPaste,(Zombie1,(CloButy2,CloButyr))),((CloCarni,CurCitre),(CloBifer,(CloInnoc," NAMED_GROUP_TEST ")))));";
1271  const char *unwanted_topo21 = "((CloButy2,CloButyr),(Zombie1,(CloPaste,((((CloInnoc," OVERWRITTEN_GROUP_TEST "),CloBifer),(CloCarni,CurCitre)),(CytAquat,(CelBiazo,(CorGluta,(CorAquat,Zombie2)))))))'outer');";
1272 
1273  const char *sorted_topo11 = "(((((CloInnoc," NAMED_GROUP_TEST "),CloBifer),(CloCarni,CurCitre)),(CloPaste,(Zombie1,(CloButy2,CloButyr)))),(CytAquat,(CelBiazo,(CorGluta,(CorAquat,Zombie2)))));";
1274  const char *sorted_topo21 = "(((((((CloInnoc," OVERWRITTEN_GROUP_TEST "),CloBifer),(CloCarni,CurCitre)),(CytAquat,(CelBiazo,(CorGluta,(CorAquat,Zombie2))))),CloPaste),Zombie1)'outer',(CloButy2,CloButyr));";
1275  const char *topo32 = "((CloButy2,CloButyr)'upper',(((((" GROUP_TEST_FLIPPED "'low2',CloInnoc),CloBifer),((((CorAquat,CurCitre),CorGluta),CelBiazo),CytAquat)'low1'),CloPaste),CloCarni));";
1276  const char *topo32_rc = "((CloButy2,CloButyr)'upper',(((((" GROUP_TEST_FLIPPED "'low2',CloInnoc),CloBifer),((((CorAquat,CurCitre),CorGluta),CelBiazo),CytAquat)'low1'),CloPaste),CloCarni)'lower');"; // @@@ should be same as topo32 (see #451)
1277  const char *topo32_rel = "((CloButy2,CloButyr)" ",(((((" GROUP_TEST_FLIPPED "'low2 [p=0.250000;ir=100.0%;3->4]',CloInnoc),CloBifer)'low1 [p=0.232222;ir=100.0%;7->6]',((((CorAquat,CurCitre),CorGluta),CelBiazo),CytAquat)'upper [p=0.510000;ir=100.0%;5->5]'),CloPaste),CloCarni)'lower [p=0.230769;ir=100.0%;10->13]');"; // group 'upper' and 'low1' moved to different locations by relative scoring
1278  const char *topo32_li = "((CloButy2,CloButyr)" ",(((((" GROUP_TEST_FLIPPED "'low2',CloInnoc),CloBifer),((((CorAquat,CurCitre),CorGluta),CelBiazo),CytAquat)'low1'),CloPaste),CloCarni)'lower');"; // group 'upper' filtered by limits
1279 
1280  const char *compared_topo = "(((((((CloInnoc,(CloTyrob,(CloTyro2,(CloTyro3,CloTyro4)))),CloBifer),(CloCarni,CurCitre)'# 2')'# 2',(CytAquat,(CelBiazo,(CorGluta,(CorAquat,Zombie2)'# 1')'# 1')'# 1')'# 1')'# 1',CloPaste),Zombie1),(CloButy2,CloButyr));";
1281 
1282  const char *LOG = "move_node_info.log";
1283 
1284 // #define TEST_AUTO_UPDATE // uncomment to auto-update expected log-files
1285 #if defined(TEST_AUTO_UPDATE)
1286 # define TEST_LOGS_EXPECTED(expected) TEST_COPY_FILE(LOG, expected)
1287 #else
1288 # define TEST_LOGS_EXPECTED(expected) TEST_EXPECT_TEXTFILES_EQUAL(expected, LOG)
1289 #endif // TEST_AUTO_UPDATE
1290 
1291  // create copies of 'tree_removal' + 'tree_test'
1292  {
1293  GB_transaction ta(gb_main);
1294 
1295  // remove existing comments from trees (already contains some log-entries tested below)
1296  {
1297  const char *resetComment = "<comment reset>";
1298  TEST_EXPECT_NO_ERROR(GBT_write_tree_remark(gb_main, treeTarget1, resetComment));
1299  TEST_EXPECT_NO_ERROR(GBT_write_tree_remark(gb_main, treeTarget2, resetComment));
1300  }
1301 
1302  TEST_EXPECT_NO_ERROR(GBT_copy_tree(gb_main, treeTarget1, treeSortby1));
1303  TEST_EXPECT_NO_ERROR(GBT_copy_tree(gb_main, treeTarget2, treeSortby2));
1304 
1305  TEST_EXPECT_SAVED_NEWICK(nSIMPLE, gb_main, treeTarget1, org_topo1);
1306  TEST_EXPECT_SAVED_NEWICK(nSIMPLE, gb_main, treeTarget2, org_topo2);
1307  }
1308 
1309  GroupMatchScorer defaultScorer;
1310 
1311  // move node info
1312  {
1313  const char *comment_added = "Copied node info from tree_test_copy";
1314  TEST_EXPECT_TREE_COMMENT_DOESNT_CONTAIN(treeTarget1, comment_added);
1315 
1316  TEST_EXPECT_NO_ERROR(NTREE_move_tree_info(gb_main, treeSource1, treeTarget1, LOG, REMOVE_EXISTING_GROUPS, XFER_ALL_GROUPS, defaultScorer, NULp));
1317  TEST_LOGS_EXPECTED("group_xfer_11.log.expected");
1318 
1319  TEST_EXPECT_SAVED_NEWICK__BROKEN(nSIMPLE, gb_main, treeTarget1, org_topo1); // @@@ moving node info modifies topology; caused by NT_tree_cmp.cxx@NAIVE_ROOTING
1320  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget1, unwanted_topo11);
1321  TEST_EXPECT_TREE_COMMENT_CONTAINS(treeTarget1, comment_added);
1322 
1323  // @@@ when we have a function to set the root according to another tree (#449),
1324  // use that function here. sorting tree after that, should again result in 'org_topo1'!
1325 
1326  TEST_EXPECT_NO_ERROR(sort_namedtree_by_other_tree(gb_main, treeTarget1, treeSortby1));
1327  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget1, sorted_topo11);
1328  }
1329  {
1330  const char *comment_added = "Copied node info from tree_groups";
1331  TEST_EXPECT_TREE_COMMENT_DOESNT_CONTAIN(treeTarget2, comment_added);
1332 
1333  TEST_EXPECT_NO_ERROR(NTREE_move_tree_info(gb_main, treeSource3, treeTarget2, LOG, REMOVE_EXISTING_GROUPS, XFER_ALL_GROUPS, defaultScorer, NULp));
1334  TEST_LOGS_EXPECTED("group_xfer_32.log.expected");
1335 
1336  TEST_EXPECT_SAVED_NEWICK__BROKEN(nSIMPLE, gb_main, treeTarget2, org_topo2); // @@@ moving node info modifies topology; caused by NT_tree_cmp.cxx@NAIVE_ROOTING
1337  TEST_EXPECT_TREE_COMMENT_CONTAINS(treeTarget2, comment_added);
1338  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget2, topo32);
1339 
1340  // perform same group-xfer after 1st xfer changed root => inserts 4 instead of 3 groups (obviously caused by changed root position; see #451)
1341  TEST_EXPECT_NO_ERROR(NTREE_move_tree_info(gb_main, treeSource3, treeTarget2, LOG, REMOVE_EXISTING_GROUPS, XFER_ALL_GROUPS, defaultScorer, NULp));
1342  TEST_LOGS_EXPECTED("group_xfer_32_rc.log.expected");
1343  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget2, topo32_rc);
1344 
1345  {
1346  GroupMatchScorer relativeScorer;
1347  relativeScorer.setPerErrorPenalties(0.0, 0.0, 0.0001); // remove absolute penalties for in-/outgroup
1348  relativeScorer.setRelativePenalties(1.0, 1.0); // set relative penalties for in-/outgroup
1349 
1350  TEST_EXPECT_NO_ERROR(NTREE_move_tree_info(gb_main, treeSource3, treeTarget2, LOG, REMOVE_EXISTING_GROUPS, XFER_ALL_GROUPS, relativeScorer,
1351  "groupname;\" [p=\";penalty;\";ir=\";ingroup;\";\";oldsize;\"->\";newsize;\"]\""));
1352  TEST_LOGS_EXPECTED("group_xfer_32_rel.log.expected");
1353  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget2, topo32_rel);
1354  }
1355 
1356  // again perform same group-xfer using ingroup- and outgroup-limit
1357  {
1358  GroupMatchScorer limitedScorer;
1359  // limitedScorer.setLimits(RatioLimits(1.0, 1.0), RatioLimits(0.0, 0.0)); // filters all groups (upper, low2, low1 + lower)
1360  // limitedScorer.setLimits(RatioLimits(0.0, 1.0), RatioLimits(0.0, 1.0)); // filters no group (by definition)
1361  // limitedScorer.setLimits(RatioLimits(0.5, 1.0), RatioLimits(0.0, 1.0)); // group 'upper' placed at position with higher absolute penalty
1362  // limitedScorer.setLimits(RatioLimits(0.75, 1.0), RatioLimits(0.0, 1.0)); // weird (does keel groups)
1363  // limitedScorer.setLimits(RatioLimits(0.9, 1.0), RatioLimits(0.0, 1.0)); // removes group 'upper'
1364  // limitedScorer.setLimits(RatioLimits(0.0, 1.0), RatioLimits(0.0, 0.5)); // filters no group
1365  // limitedScorer.setLimits(RatioLimits(0.0, 1.0), RatioLimits(0.0, 0.1)); // filters groups 'twoleafs' + 'low2' (group 'lower' superseeded by 'low1')
1366  // limitedScorer.setLimits(RatioLimits(0.0, 1.0), RatioLimits(0.0, 0.3)); // filters group 'twoleafs'
1367  // limitedScorer.setLimits(RatioLimits(0.9, 1.0), RatioLimits(0.0, 0.1)); // filters all groups (weird)
1368  limitedScorer.setLimits(RatioLimits(0.7, 1.0), RatioLimits(0.0, 0.3)); // filters group 'upper' + group 'twoleafs'
1369  limitedScorer.setPerErrorPenalties(2.0, 2.0, 0.0002); // all values are 2*default -> result is same, scores are doubled!
1370 
1371  TEST_EXPECT_NO_ERROR(NTREE_move_tree_info(gb_main, treeSource3, treeTarget2, LOG, REMOVE_EXISTING_GROUPS, XFER_ALL_GROUPS, limitedScorer, "")); // test empty ACI does same as passing NULp
1372  TEST_LOGS_EXPECTED("group_xfer_32_li.log.expected");
1373  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget2, topo32_li);
1374  }
1375  }
1376 
1377  // add node info
1378  {
1379  const char *comment_added = "Added node info from tree_tree2";
1380  TEST_EXPECT_TREE_COMMENT_DOESNT_CONTAIN(treeTarget1, comment_added);
1381 
1382  TEST_EXPECT_NO_ERROR(NTREE_move_tree_info(gb_main, treeSource2, treeTarget1, LOG, KEEP_OLD_NAMES, XFER_ALL_GROUPS, defaultScorer, NULp));
1383  TEST_LOGS_EXPECTED("group_xfer_21.log.expected");
1384 
1385  TEST_EXPECT_SAVED_NEWICK__BROKEN(nSIMPLE, gb_main, treeTarget1, org_topo1); // @@@ moving node info modifies topology; caused by NT_tree_cmp.cxx@NAIVE_ROOTING
1386  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget1, unwanted_topo21);
1387  TEST_EXPECT_TREE_COMMENT_CONTAINS(treeTarget1, comment_added);
1388 
1389  // @@@ when we have a function to set the root according to another tree (#449),
1390  // use that function here. sorting tree after that, should again result in 'org_topo1'!
1391 
1392  TEST_EXPECT_NO_ERROR(sort_namedtree_by_other_tree(gb_main, treeTarget1, treeSortby1));
1393  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget1, sorted_topo21);
1394  }
1395 
1396  // compare node info
1397  {
1398  const char *comment_added = "Compared topology with tree_test";
1399  TEST_EXPECT_TREE_COMMENT_DOESNT_CONTAIN(treeTarget1, comment_added);
1400 
1401  TEST_EXPECT_NO_ERROR(NTREE_move_tree_info(gb_main, treeSource1, treeTarget1, NULp, COMPARE_TOPOLOGY, XFER_ALL_GROUPS, defaultScorer, NULp));
1402  TEST_EXPECT_SAVED_NEWICK(nREMARK, gb_main, treeTarget1, compared_topo);
1403  TEST_EXPECT_TREE_COMMENT_CONTAINS(treeTarget1, comment_added);
1404  }
1405 
1406  // test error cases:
1407  {
1408 #define DOESNT_MATTER_ARGS gb_main,treeSource2,treeTarget1,LOG,REMOVE_EXISTING_GROUPS,XFER_ALL_GROUPS
1409 
1410  GroupMatchScorer invalidScoring;
1411 
1412  invalidScoring.setPerErrorPenalties(1.0, 0.0, 0.0001);
1413  TEST_EXPECT_ERROR_CONTAINS(NTREE_move_tree_info(DOESNT_MATTER_ARGS, invalidScoring, NULp), "one outgroup penalty has to be different from zero");
1414 
1415  invalidScoring.setPerErrorPenalties(0.0, 1.0, 0.0001);
1416  TEST_EXPECT_ERROR_CONTAINS(NTREE_move_tree_info(DOESNT_MATTER_ARGS, invalidScoring, NULp), "one ingroup penalty has to be different from zero");
1417 
1418  invalidScoring.setPerErrorPenalties(-1.0, 1.0, 0.0001);
1419  TEST_EXPECT_ERROR_CONTAINS(NTREE_move_tree_info(DOESNT_MATTER_ARGS, invalidScoring, NULp), "invalid negative in/outgroup penalty");
1420 
1421  invalidScoring.setPerErrorPenalties(1.0, 1.0, 0.0001);
1422  invalidScoring.setRelativePenalties(100.0, -100.0);
1423  TEST_EXPECT_ERROR_CONTAINS(NTREE_move_tree_info(DOESNT_MATTER_ARGS, invalidScoring, NULp), "invalid negative in/outgroup penalty");
1424 
1425 #undef DOESNT_MATTER_ARGS
1426  }
1427 
1428  GB_unlink(LOG);
1429  GB_close(gb_main);
1430 }
1431 
1432 __ATTR__REDUCED_OPTIMIZE void TEST_edges() {
1433  GB_shell shell;
1434  GBDATA *gb_main = GB_open("TEST_trees.arb", "rw");
1435  TEST_REJECT_NULL(gb_main);
1436 
1437  {
1438  GB_transaction ta(gb_main);
1439  TreeNode *tree = GBT_read_tree(gb_main, "tree_test", new SizeAwareRoot);
1440 
1441  TreeNode *left = tree->findLeafNamed("CloTyro3"); TEST_REJECT_NULL(left);
1442  TreeNode *node = left->get_father(); TEST_REJECT_NULL(node);
1443  TreeNode *right = node->findLeafNamed("CloTyro4"); TEST_REJECT_NULL(right);
1444 
1445  TEST_EXPECT(node == right->get_father());
1446  TEST_EXPECT(node->get_leftson() == left);
1447  TEST_EXPECT(node->get_rightson() == right);
1448 
1449  TreeNode *parent = node->get_father(); TEST_REJECT_NULL(parent);
1450  TreeNode *brother = parent->findLeafNamed("CloTyro2"); TEST_REJECT_NULL(brother);
1451 
1452  TEST_EXPECT(node->get_brother() == brother);
1453 
1454  TreeNode *grandpa = parent->get_father(); TEST_REJECT_NULL(grandpa);
1455 
1456  // topology:
1457  //
1458  // grandpa
1459  // /
1460  // /
1461  // /
1462  // parent
1463  // /\ .
1464  // / \ .
1465  // / \ .
1466  // node brother
1467  // /\ .
1468  // / \ .
1469  // / \ .
1470  // left right
1471 
1472  // test next() and otherNext() for inner edge 'node->parent'
1473  {
1474  ARB_edge nodeUp = parentEdge(node);
1475 
1476  TEST_EXPECT(node->is_leftson()); // if child is left son..
1477  TEST_EXPECT(nodeUp.next().dest() == grandpa); // .. next() continues rootwards
1478  TEST_EXPECT(nodeUp.counter_next().dest() == brother);
1479 
1480  ARB_edge brotherUp = parentEdge(brother);
1481 
1482  TEST_EXPECT(brother->is_rightson()); // if child is right son..
1483  TEST_EXPECT(brotherUp.next().dest() == node); // .. next() continues with other son
1484  TEST_EXPECT(brotherUp.counter_next().dest() == grandpa);
1485 
1486  ARB_edge down = nodeUp.inverse();
1487 
1488  TEST_EXPECT(down.next().dest() == right); // next descends into right son
1489  TEST_EXPECT(down.counter_next().dest() == left);
1490 
1491  TEST_EXPECT(nodeUp.previous().source() == left);
1492  TEST_EXPECT(nodeUp.counter_previous().source() == right);
1493 
1494  ARB_edge toLeaf(node, left);
1495  TEST_EXPECT(toLeaf.is_edge_to_leaf());
1496 
1497  // all iterators should turn around at leaf:
1498  TEST_EXPECT(toLeaf.next().dest() == node);
1499  TEST_EXPECT(toLeaf.counter_next().dest() == node);
1500 
1501  ARB_edge fromLeaf(left, node);
1502  TEST_EXPECT(fromLeaf.previous().dest() == left);
1503  TEST_EXPECT(fromLeaf.counter_previous().dest() == left);
1504 
1505  ARB_edge rootEdge(tree->get_leftson(), tree->get_rightson());
1506 
1508  TEST_EXPECT(nodeUp.get_type() == EDGE_TO_ROOT);
1509  TEST_EXPECT(fromLeaf.get_type() == EDGE_TO_ROOT);
1510  TEST_EXPECT(down.get_type() == EDGE_TO_LEAF);
1511  TEST_EXPECT(toLeaf.get_type() == EDGE_TO_LEAF);
1512 
1513  // test iterators are inverse functions
1514  {
1515  ARB_edge e[] = { nodeUp, down, toLeaf, fromLeaf, rootEdge };
1516  const int EDGES = ARRAY_ELEMS(e);
1517  for (int i = 0; i<EDGES; ++i) {
1518  TEST_ANNOTATE(GBS_global_string("i=%i", i));
1519 
1520  TEST_EXPECT(e[i].next().previous() == e[i]);
1521  TEST_EXPECT(e[i].previous().next() == e[i]);
1522 
1523  TEST_EXPECT(e[i].counter_next().counter_previous() == e[i]);
1524  TEST_EXPECT(e[i].counter_previous().counter_next() == e[i]);
1525 
1526  ARB_edge inv(e[i].inverse());
1527 
1528  TEST_EXPECT(e[i].counter_next().inverse().next() == inv);
1529  TEST_EXPECT(e[i].counter_previous().inverse().previous() == inv);
1530  TEST_EXPECT(e[i].next().inverse().counter_next() == inv);
1531  TEST_EXPECT(e[i].previous().inverse().counter_previous() == inv);
1532  }
1533  }
1534 
1535  // test adjacent_distance
1536  const double EPSILON = 0.000001;
1537 
1538  const double NLEN = 0.025806;
1539  const double BLEN = 0.017316;
1540  const double PLEN = 0.017167;
1541  const double LLEN = 1.045690;
1542  const double RLEN = 0.060606;
1543 
1545  TEST_EXPECT_SIMILAR(nodeUp.length(), NLEN, EPSILON);
1546  TEST_EXPECT_SIMILAR(down.length(), NLEN, EPSILON);
1547  TEST_EXPECT_SIMILAR(nodeUp.length_or_adjacent_distance(), NLEN, EPSILON);
1548  TEST_EXPECT_SIMILAR(down.length_or_adjacent_distance(), NLEN, EPSILON);
1549 
1550  TEST_EXPECT_SIMILAR(brother->get_branchlength(), BLEN, EPSILON);
1551  TEST_EXPECT_SIMILAR(parent ->get_branchlength(), PLEN, EPSILON);
1552  TEST_EXPECT_SIMILAR(nodeUp.adjacent_distance(), BLEN+PLEN, EPSILON);
1553 
1554  TEST_EXPECT_SIMILAR(left ->get_branchlength(), LLEN, EPSILON);
1555  TEST_EXPECT_SIMILAR(right->get_branchlength(), RLEN, EPSILON);
1556  TEST_EXPECT_SIMILAR(down.adjacent_distance(), LLEN+RLEN, EPSILON);
1557 
1558  // modify lengths
1559  const double MOD_NLEN = 0.123456;
1560  const double MOD_LLEN = 0.246802;
1561 
1562  toLeaf.set_length(MOD_LLEN);
1563  nodeUp.set_length(MOD_NLEN);
1564 
1565  TEST_EXPECT_SIMILAR(toLeaf.length(), MOD_LLEN, EPSILON);
1566  TEST_EXPECT_SIMILAR(nodeUp.length(), MOD_NLEN, EPSILON);
1567  TEST_EXPECT_SIMILAR(down.length(), MOD_NLEN, EPSILON);
1568  }
1569 
1570  destroy(tree);
1571  }
1572 
1573  GB_close(gb_main);
1574 }
1575 
1576 void TEST_remove_bootstraps() {
1577  GB_shell shell;
1578  GBDATA *gb_main = GB_open("TEST_trees.arb", "rw");
1579  TEST_REJECT_NULL(gb_main);
1580 
1581  {
1582  GB_transaction ta(gb_main);
1583  TreeNode *tree = GBT_read_tree(gb_main, "tree_test", new SizeAwareRoot);
1584  TEST_REJECT_NULL(tree);
1585 
1586  const char *topo_org = "(((((((CloTyro3,CloTyro4)'40%',CloTyro2)'0%',CloTyrob)'97%',CloInnoc)'0%',CloBifer)'53%',(((CloButy2,CloButyr),CloCarni)'33%',CloPaste)'97%'),((((CorAquat,CurCitre),CorGluta)'17%',CelBiazo)'40%',CytAquat));";
1587  const char *topo_rem = "(((((((CloTyro3,CloTyro4)" ",CloTyro2)" ",CloTyrob)" ",CloInnoc)" ",CloBifer)" ",(((CloButy2,CloButyr),CloCarni)" ",CloPaste)" "),((((CorAquat,CurCitre),CorGluta)" ",CelBiazo)" ",CytAquat));";
1588 
1589  TEST_EXPECT_NEWICK(nREMARK, tree, topo_org);
1590 
1591  tree->remove_bootstrap();
1592  TEST_EXPECT_NEWICK(nREMARK, tree, topo_rem);
1593 
1594  destroy(tree);
1595  }
1596 
1597  GB_close(gb_main);
1598 }
1599 
1600 void TEST_multifurcate_tree() {
1601  GB_shell shell;
1602  GBDATA *gb_main = GB_open("TEST_trees.arb", "rw");
1603  TEST_REJECT_NULL(gb_main);
1604 
1605  const char *topo_test = "(((((((CloTyro3:1.046,CloTyro4:0.061)'40%':0.026,CloTyro2:0.017)'0%':0.017,CloTyrob:0.009)'97%:test':0.274,CloInnoc:0.371)'0%':0.057,CloBifer:0.388)'53%':0.124,(((CloButy2:0.009,CloButyr:0.000):0.564,CloCarni:0.120)'33%':0.010,CloPaste:0.179)'97%':0.131):0.081,((((CorAquat:0.084,CurCitre:0.058):0.103,CorGluta:0.522)'17%':0.053,CelBiazo:0.059)'40%':0.207,CytAquat:0.711):0.081);";
1606  // changes = " +0.307 -0.371 +0.064 "
1607  const char *topo_single = "(((((((CloTyro3:1.046,CloTyro4:0.061)'40%':0.026,CloTyro2:0.017)'0%':0.017,CloTyrob:0.009)'97%:test':0.581,CloInnoc:0.000)'0%':0.121,CloBifer:0.388)'53%':0.124,(((CloButy2:0.009,CloButyr:0.000):0.564,CloCarni:0.120)'33%':0.010,CloPaste:0.179)'97%':0.131):0.081,((((CorAquat:0.084,CurCitre:0.058):0.103,CorGluta:0.522)'17%':0.053,CelBiazo:0.059)'40%':0.207,CytAquat:0.711):0.081);";
1608  const char *topo_bs_less_101_005 = "(((((((CloTyro3:1.098,CloTyro4:0.064)" ":0.000,CloTyro2:0.000)" ":0.000,CloTyrob:0.000)'97%:test':0.287,CloInnoc:0.371)'0%':0.057,CloBifer:0.388)'53%':0.124,(((CloButy2:0.000,CloButyr:0.000):0.578,CloCarni:0.121)" ":0.000,CloPaste:0.181)'97%':0.132):0.081,((((CorAquat:0.084,CurCitre:0.058):0.103,CorGluta:0.522)'17%':0.053,CelBiazo:0.059)'40%':0.207,CytAquat:0.711):0.081);";
1609  const char *topo_bs_less_101_005_NT = "(((((((CloTyro3:1.078,CloTyro4:0.062)" ":0.000,CloTyro2:0.018)" ":0.000,CloTyrob:0.009)'97%:test':0.282,CloInnoc:0.371)'0%':0.057,CloBifer:0.388)'53%':0.124,(((CloButy2:0.009,CloButyr:0.000):0.570,CloCarni:0.121)" ":0.000,CloPaste:0.181)'97%':0.132):0.081,((((CorAquat:0.084,CurCitre:0.058):0.103,CorGluta:0.522)'17%':0.053,CelBiazo:0.059)'40%':0.207,CytAquat:0.711):0.081);";
1610  const char *topo_bs_less_30_005 = "(((((((CloTyro3:1.046,CloTyro4:0.061)'40%':0.027,CloTyro2:0.018)" ":0.000,CloTyrob:0.009)'97%:test':0.288,CloInnoc:0.371)'0%':0.057,CloBifer:0.388)'53%':0.124,(((CloButy2:0.009,CloButyr:0.000):0.564,CloCarni:0.120)'33%':0.010,CloPaste:0.179)'97%':0.131):0.081,((((CorAquat:0.084,CurCitre:0.058):0.103,CorGluta:0.522)'17%':0.053,CelBiazo:0.059)'40%':0.207,CytAquat:0.711):0.081);";
1611  const char *topo_bs_less_30 = "(((((((CloTyro3:1.046,CloTyro4:0.061)'40%':0.027,CloTyro2:0.018)" ":0.000,CloTyrob:0.009)'97%:test':0.302,CloInnoc:0.390)" ":0.000,CloBifer:0.407)'53%':0.131,(((CloButy2:0.009,CloButyr:0.000):0.564,CloCarni:0.120)'33%':0.010,CloPaste:0.179)'97%':0.131):0.081,((((CorAquat:0.084,CurCitre:0.058):0.109,CorGluta:0.554)" ":0.000,CelBiazo:0.062)'40%':0.220,CytAquat:0.711):0.081);";
1612  const char *topo_all = "(((((((CloTyro3:0.000,CloTyro4:0.000)" ":0.000,CloTyro2:0.000)" ":0.000,CloTyrob:0.000)'" "test':0.000,CloInnoc:0.000)" ":0.000,CloBifer:0.000)" ":0.000,(((CloButy2:0.000,CloButyr:0.000):0.000,CloCarni:0.000)" ":0.000,CloPaste:0.000)" ":0.000):0.000,((((CorAquat:0.000,CurCitre:0.000):0.000,CorGluta:0.000)" ":0.000,CelBiazo:0.000)" ":0.000,CytAquat:0.000):0.000);";
1613 
1614  const double STABLE_LENGTH = 5.362750;
1615  const double EPSILON = 0.000001;
1616 
1617  for (int test = 1; test<=6; ++test) {
1618  GB_transaction ta(gb_main);
1619  TreeNode *tree = GBT_read_tree(gb_main, "tree_test", new SizeAwareRoot);
1620 
1621  TEST_REJECT_NULL(tree);
1622  if (test == 1) {
1623  TEST_EXPECT_NEWICK(nALL, tree, topo_test);
1624  TEST_EXPECT_SIMILAR(tree->sum_child_lengths(), STABLE_LENGTH, EPSILON);
1625  }
1626 
1627  switch (test) {
1628  case 1:
1629  tree->multifurcate_whole_tree(TreeNode::multifurc_limits(101, 0.05, true));
1630  TEST_EXPECT_NEWICK(nALL, tree, topo_bs_less_101_005);
1631  TEST_EXPECT_SIMILAR(tree->sum_child_lengths(), STABLE_LENGTH, EPSILON);
1632  break;
1633  case 6:
1634  tree->multifurcate_whole_tree(TreeNode::multifurc_limits(101, 0.05, false));
1635  TEST_EXPECT_NEWICK(nALL, tree, topo_bs_less_101_005_NT);
1636  TEST_EXPECT_SIMILAR(tree->sum_child_lengths(), STABLE_LENGTH, EPSILON);
1637  break;
1638  case 2:
1639  tree->multifurcate_whole_tree(TreeNode::multifurc_limits(30, 0.05, true));
1640  TEST_EXPECT_NEWICK(nALL, tree, topo_bs_less_30_005);
1641  TEST_EXPECT_SIMILAR(tree->sum_child_lengths(), STABLE_LENGTH, EPSILON);
1642  break;
1643  case 3:
1644  tree->multifurcate_whole_tree(TreeNode::multifurc_limits(30, 1000, true));
1645  TEST_EXPECT_NEWICK(nALL, tree, topo_bs_less_30);
1646  TEST_EXPECT_SIMILAR(tree->sum_child_lengths(), STABLE_LENGTH, EPSILON);
1647  break;
1648  case 4:
1649  tree->multifurcate_whole_tree(TreeNode::multifurc_limits(101, 1000, true)); // multifurcate all
1650  TEST_EXPECT_NEWICK(nALL, tree, topo_all);
1652  break;
1653  case 5: {
1654  TreeNode *CloInnoc = tree->findLeafNamed("CloInnoc");
1655  TEST_REJECT_NULL(CloInnoc);
1656 
1657  parentEdge(CloInnoc).multifurcate();
1658  TEST_EXPECT_NEWICK(nALL, tree, topo_single);
1659 
1660  TEST_EXPECT_SIMILAR(tree->sum_child_lengths(), STABLE_LENGTH, EPSILON);
1661  break;
1662  }
1663  default:
1664  nt_assert(0);
1665  break;
1666  }
1667 
1668  destroy(tree);
1669  }
1670 
1671  GB_close(gb_main);
1672 }
1673 
1674 void TEST_TreeNode_attributes() {
1675  // -> ../UNIT_TESTER/run/trees/bg_exp_p__0.tree
1676  TreeNode *tree = TREE_load("trees/bg_exp_p__0.tree", new SimpleRoot, NULp, false, NULp);
1677 
1678  TreeNode *MabPelag = tree->findLeafNamed("MabPelag");
1679  TreeNode *MabSalin = tree->findLeafNamed("MabSalin");
1680  TreeNode *PaoMaris = tree->findLeafNamed("PaoMaris");
1681 
1682  TEST_EXPECT(MabPelag->father == MabSalin->father); // are brothers
1683 
1684  TreeNode *Mabs = MabPelag->father;
1685  TreeNode *PaoMabs = PaoMaris->father;
1686 
1687  // ((MabPelag, MabSalin), PaoMaris)
1688  // -------- Mabs ------
1689  // -------------- PaoMabs ---------
1690 
1691  TEST_EXPECT(Mabs->father == PaoMabs);
1692 
1693  // is_son_of
1694  TEST_EXPECT(MabPelag->is_son_of(Mabs));
1695  TEST_EXPECT(MabSalin->is_son_of(Mabs));
1696  TEST_EXPECT(Mabs->is_son_of(PaoMabs));
1697  TEST_EXPECT(PaoMaris->is_son_of(PaoMabs));
1698 
1699  // is_inside
1700  TEST_EXPECT(MabPelag->is_inside(Mabs)); // leaf in father
1701  TEST_EXPECT(Mabs->is_inside(PaoMabs)); // node in father
1702  TEST_EXPECT(MabPelag->is_inside(PaoMabs)); // leaf in grandfather
1703  TEST_EXPECT(MabPelag->is_inside(MabPelag)); // self-containment
1704  TEST_REJECT(Mabs->is_inside(MabPelag)); // not: father in child
1705  TEST_REJECT(MabPelag->is_inside(MabSalin)); // not: node in brother
1706 
1707  // is_ancestor_of
1708  TEST_EXPECT(Mabs->is_ancestor_of(MabPelag));
1709  TEST_EXPECT(Mabs->is_ancestor_of(MabSalin));
1710  TEST_REJECT(Mabs->is_ancestor_of(PaoMaris)); // brother is no ancestor
1711  TEST_REJECT(Mabs->is_ancestor_of(Mabs)); // node never is ancestor of itself
1712  TEST_REJECT(Mabs->is_ancestor_of(PaoMabs)); // child cannot be ancestor
1713 
1714  TEST_EXPECT(PaoMabs->is_ancestor_of(MabPelag)); // root of subtree (PaoMabs) is ancestor of all members..
1715  TEST_EXPECT(PaoMabs->is_ancestor_of(MabSalin));
1716  TEST_EXPECT(PaoMabs->is_ancestor_of(PaoMaris));
1717  TEST_EXPECT(PaoMabs->is_ancestor_of(Mabs));
1718  TEST_REJECT(PaoMabs->is_ancestor_of(PaoMabs)); // .. despite itself
1719 
1720  // in_same_branch_as / in_other_branch_than
1721  TEST_EXPECT(MabPelag->in_same_branch_as(MabPelag));
1722  TEST_EXPECT(MabPelag->in_other_branch_than(MabSalin));
1723  TEST_EXPECT(MabPelag->in_other_branch_than(PaoMaris));
1724  TEST_EXPECT(MabPelag->in_same_branch_as(Mabs));
1725  TEST_EXPECT(MabPelag->in_same_branch_as(PaoMabs));
1726 
1727  TEST_EXPECT(PaoMabs->in_same_branch_as(MabPelag));
1728  TEST_EXPECT(PaoMabs->in_same_branch_as(MabSalin));
1729  TEST_EXPECT(PaoMabs->in_same_branch_as(PaoMaris));
1730  TEST_EXPECT(PaoMabs->in_same_branch_as(Mabs));
1731  TEST_EXPECT(PaoMabs->in_same_branch_as(PaoMabs));
1732 
1733  TEST_EXPECT(Mabs->in_same_branch_as(MabPelag));
1734  TEST_EXPECT(Mabs->in_same_branch_as(MabSalin));
1735  TEST_EXPECT(Mabs->in_other_branch_than(PaoMaris));
1736  TEST_EXPECT(Mabs->in_same_branch_as(Mabs));
1737  TEST_EXPECT(Mabs->in_same_branch_as(PaoMabs));
1738 
1739  // ancestor_common_with
1740  TEST_EXPECT(MabPelag->ancestor_common_with(MabSalin) == Mabs);
1741  TEST_EXPECT(MabSalin->ancestor_common_with(MabPelag) == Mabs);
1742  TEST_EXPECT(PaoMaris->ancestor_common_with(MabPelag) == PaoMabs);
1743  TEST_EXPECT(PaoMabs->ancestor_common_with(Mabs) == PaoMabs);
1744  TEST_EXPECT(MabPelag->ancestor_common_with(PaoMabs) == PaoMabs);
1745 
1746  destroy(tree);
1747 }
1748 
1749 #endif // UNIT_TESTS
1750 
1751 // --------------------------------------------------------------------------------
1752 
GBDATA * GBT_find_bottom_tree(GBDATA *gb_main)
Definition: adtree.cxx:1004
const char * GB_ERROR
Definition: arb_core.h:25
bool is_rightson() const
Definition: TreeNode.h:193
NOT4PERL GB_ERROR GBT_move_tree(GBDATA *gb_moved_tree, GBT_ORDER_MODE mode, GBDATA *gb_target_tree)
Definition: adtree.cxx:1194
GB_ERROR NT_with_displayed_tree_do(TREE_canvas *ntw, bool(*displayed_tree_cb)(TreeNode *tree, GB_ERROR &error))
#define AWAR_TREE_EXPORT_NDS
Definition: ad_trees.cxx:69
#define AWAR_DB_NAME
Definition: aw_awar_defs.hxx:6
GBDATA * GB_open(const char *path, const char *opent)
Definition: ad_load.cxx:1363
void GB_remove_on_exit(const char *filename)
Definition: adsocket.cxx:1224
AW_awar * set_srt(const char *srt)
Definition: AW_awar.cxx:569
virtual void swap_sons()
Definition: TreeNode.h:512
#define AWAR_TREE_EXPORT_REPLACE
Definition: ad_trees.cxx:75
AW_window * create_rename_window(AW_root *root, const Spec *spec)
Definition: TreeAdmin.cxx:218
#define TEST_EXPECT_SIMILAR(expr, want, epsilon)
Definition: test_unit.h:1287
GB_ERROR GBT_write_tree_with_remark(GBDATA *gb_main, const char *tree_name, TreeNode *tree, const char *remark)
Definition: adtree.cxx:524
#define AWAR_TREE_EXPORT_FILTER
Definition: ad_trees.cxx:63
AW_window * NT_create_moveGroupInfo_window(AW_root *root)
Definition: ad_trees.cxx:683
TreeNode * findLeafNamed(const char *wantedName)
Definition: TreeNode.cxx:274
static void tree_vars_callback(AW_root *aw_root)
Definition: ad_trees.cxx:84
bool is_known() const
Definition: tree_position.h:47
#define AWAR_TREE_EXPORT_NAME
Definition: ad_trees.cxx:64
void load_xfig(const char *file, bool resize=true)
Definition: AW_window.cxx:717
GB_ERROR TREE_write_XML(GBDATA *gb_main, const char *db_name, const char *tree_name, const TREE_node_text_gen *node_gen, bool skip_folded, const char *path)
Definition: TreeWrite.cxx:259
static void multifurcation_cb(UNFIXED, TREE_canvas *ntw)
Definition: ad_trees.cxx:1104
static char * readXmlTree(char *fname)
Definition: ad_trees.cxx:375
void AWT_registerTreeAwarSimple(AW_awar *awar)
void AW_edit(const char *path)
Definition: AW_edit.cxx:16
#define AWAR_GROUPXFER_ACI
Definition: ad_trees.cxx:60
#define AWAR_TREE_REM
Definition: ad_trees.cxx:45
void GB_unlink_or_warn(const char *path, GB_ERROR *error)
Definition: arb_file.cxx:206
void reorder_subtree(TreeNode *tree)
Definition: ad_trees.cxx:1046
GBDATA * GBT_tree_behind(GBDATA *gb_tree)
Definition: adtree.cxx:990
void at(int x, int y)
Definition: AW_at.cxx:93
AW_selection * awt_create_subset_selection_list(AW_window *aww, AW_selection_list *parent_selection, const char *at_box, const char *at_add, const char *at_sort, bool autocorrect_subselection, SubsetChangedCb subChanged_cb, AW_CL cl_user)
#define AWAR_GROUPXFER_OUTGROUP_LIM
Definition: ad_trees.cxx:57
char * get_tree_remark() const
Definition: CT_ctree.cxx:145
GB_ERROR TREE_load_to_db(GBDATA *gb_main, const char *treefile, const char *tree_name)
Definition: TreeRead.cxx:712
void AW_create_standard_fileselection(AW_window *aws, const char *awar_prefix)
Definition: aw_file.hxx:30
ARB_edge_type get_type() const
Definition: TreeNode.h:725
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
void AWT_insert_config_manager(AW_window *aww, AW_default default_file_, const char *id, const StoreConfigCallback &store_cb, const RestoreConfigCallback &load_or_reset_cb, const char *macro_id, const AWT_predefined_config *predef)
#define AWAR_GROUPXFER_SOURCE
Definition: ad_trees.cxx:50
static void swap_source_dest_cb(AW_window *aww)
Definition: ad_trees.cxx:549
TreeNode * GBT_read_tree(GBDATA *gb_main, const char *tree_name, TreeRoot *troot)
Definition: adtree.cxx:791
long read_int() const
Definition: AW_awar.cxx:187
AW_window * NT_create_multifurcate_tree_window(AW_root *aw_root, TREE_canvas *ntw)
Definition: ad_trees.cxx:1116
#define AWAR_MFURC_CONSIDER_LENGTH
Definition: ad_trees.cxx:1092
#define AWAR_TREE_CONSENSE_TREE
Definition: ad_trees.cxx:81
ARB_edge inverse() const
Definition: TreeNode.h:753
NOT4PERL long * GBT_readOrCreate_int(GBDATA *gb_container, const char *fieldpath, long default_value)
Definition: adtools.cxx:402
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
#define SRT_AUTOCORRECT_TREENAME
Definition: arbdbt.h:79
void make_node_text_init(GBDATA *gb_main)
Definition: nds.cxx:851
#define AWAR_MFURC_CONSIDER_TERMINALS
Definition: ad_trees.cxx:1093
char * GBS_string_eval(const char *insource, const char *icommand)
Definition: admatch.cxx:699
void AW_POPDOWN(AW_window *window)
Definition: AW_window.cxx:52
static void update_default_treename_cb(AW_root *aw_root)
Definition: ad_trees.cxx:122
#define AWAR_GROUPXFER_INGROUP_LIM
Definition: ad_trees.cxx:54
ARB_edge previous() const
Definition: TreeNode.h:774
GBT_LEN length() const
Definition: TreeNode.h:732
void cat(const char *from)
Definition: arb_strbuf.h:158
#define LOG(x)
GBDATA * GBT_get_tree_data(GBDATA *gb_main)
Definition: adtree.cxx:26
int GB_unlink(const char *path)
Definition: arb_file.cxx:188
void get_values(StrArray &intoArray)
Definition: aw_select.hxx:198
ARB_edge rootEdge(TreeRoot *root)
Definition: TreeNode.h:857
#define ARRAY_ELEMS(array)
Definition: arb_defs.h:19
#define AWAR_GROUP
Definition: ad_trees.h:19
int compare(const CombinedPosInfo &right) const
Definition: ad_trees.cxx:994
#define AWAR_GROUPXFER_OUTGROUP_REL
Definition: ad_trees.cxx:56
static AWT_config_mapping_def moveGroupInfo_mapping[]
Definition: ad_trees.cxx:650
GB_CSTR GB_getenvARBHOME(void)
Definition: adsocket.cxx:565
static void ad_tree_set_security(AW_root *aw_root)
Definition: ad_trees.cxx:143
AW_window * NT_create_sort_tree_by_other_tree_window(AW_root *aw_root, TREE_canvas *ntw)
Definition: ad_trees.cxx:1078
#define DOWNCAST(totype, expr)
Definition: downcast.h:141
AW_awar * add_callback(const RootCallback &cb)
Definition: AW_awar.cxx:234
struct Unfixed_cb_parameter * UNFIXED
Definition: cb_base.h:15
ARB_edge next() const
Definition: TreeNode.h:763
ARB_edge parentEdge(TreeNode *son)
Definition: TreeNode.h:842
void setPerErrorPenalties(double ingroup_pep, double outgroup_pep, double unfound_pep)
Definition: NT_tree_cmp.h:154
GB_ERROR GBT_write_tree_remark(GBDATA *gb_main, const char *tree_name, const char *remark)
Definition: adtree.cxx:487
#define TEST_EXPECT_SAVED_NEWICK__BROKEN(format, gb_main, treename, expected_newick)
Definition: test_unit.h:1453
const double EPSILON
Definition: aw_position.hxx:73
const char * read_char_pntr() const
Definition: AW_awar.cxx:171
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:353
static AW_root * SINGLETON
Definition: aw_root.hxx:102
TREE_node_quoting
Definition: TreeWrite.h:34
#define AWAR_TREE_EXPORT_FORMAT
Definition: ad_trees.cxx:68
#define AWAR_TREE_IMPORT
Definition: ad_trees.cxx:46
WindowCallback makeHelpCallback(const char *helpfile)
Definition: aw_window.hxx:106
#define TEST_EXPECT(cond)
Definition: test_unit.h:1313
char * GB_create_tempfile(const char *name)
Definition: adsocket.cxx:1188
static void tree_save_cb(AW_window *aww)
Definition: ad_trees.cxx:248
const char * make_node_text_nds(GBDATA *gb_main, GBDATA *gbd, NDS_Type mode, TreeNode *species, const char *tree_name)
Definition: nds.cxx:855
void popup_tree_admin_window(AW_window *awp)
Definition: ad_trees.cxx:787
bool in_other_branch_than(const TreeNode *other) const
Definition: TreeNode.h:208
GBT_ORDER_MODE
Definition: arbdbt.h:43
#define TEST_EXPECT_NEWICK(format, tree, expected_newick)
Definition: test_unit.h:1449
AW_window * NT_create_consense_window(AW_root *aw_root)
Definition: ad_trees.cxx:940
const TreeNode * ancestor_common_with(const TreeNode *other) const
Definition: TreeNode.cxx:765
static void reorder_trees_cb(AW_window *aww, awt_reorder_mode dest)
Definition: ad_trees.cxx:739
int compare(const TreeRelativePosition &right) const
Definition: tree_position.h:52
AW_awar * awar_float(const char *var_name, float default_value=0.0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:560
AW_awar * dest_tree_awar(AW_root *root)
Definition: TreeAdmin.cxx:38
#define AWAR_GROUPXFER_INGROUP_REL
Definition: ad_trees.cxx:53
void create_awars(AW_root *root, AW_default aw_def, bool registerTreeAwar)
Definition: TreeAdmin.cxx:30
AW_window * NT_create_compareTopologies_window(AW_root *root)
Definition: ad_trees.cxx:628
const char * GBT_tree_info_string(GBDATA *gb_main, const char *tree_name, int maxTreeNameLen)
Definition: adtree.cxx:1068
static void copy_tree_awar_cb(UNFIXED, AW_awar *aw_source, AW_awar *aw_dest)
Definition: ad_trees.cxx:561
bool is_leftson() const
Definition: TreeNode.h:188
int GB_read_security_write(GBDATA *gbd)
Definition: arbdb.cxx:1570
bool aborted()
Definition: arb_progress.h:277
static void tree_load_cb(AW_window *aww)
Definition: ad_trees.cxx:419
static AWT_config_mapping_def tree_export_config_mapping[]
Definition: ad_trees.cxx:300
GBDATA * GBT_find_top_tree(GBDATA *gb_main)
Definition: adtree.cxx:996
void delete_tree_cb(AW_window *aww, const Spec *spec)
Definition: TreeAdmin.cxx:46
#define AWAR_TREE_NAME
Definition: ad_trees.h:18
void setRelativePenalties(double ingroup_inv_relpen, double outgroup_relpen)
Definition: NT_tree_cmp.h:159
GB_ERROR TREE_write_Newick(GBDATA *gb_main, const char *tree_name, const TREE_node_text_gen *node_gen, bool save_branchlengths, bool save_bootstraps, bool save_groupnames, bool pretty, TREE_node_quoting quoteMode, const char *path)
Definition: TreeWrite.cxx:336
GB_ERROR GBT_write_tree(GBDATA *gb_main, const char *tree_name, TreeNode *tree)
Definition: adtree.cxx:477
void add(SizeAwareTree *&tree, const char *treename, double weight)
Definition: CT_ctree.hxx:168
void setLimits(const RatioLimits &ingroupLimits, const RatioLimits &outgroupLimits)
Definition: NT_tree_cmp.h:147
#define TEST_REJECT(cond)
Definition: test_unit.h:1315
#define TEST_REJECT_NULL(n)
Definition: test_unit.h:1310
void multifurcate()
Definition: TreeNode.cxx:578
#define AWAR_TREE_EXPORT_INCLUDE_GROUPNAMES
Definition: ad_trees.cxx:72
TreeNode * father
Definition: TreeNode.h:131
static void error(const char *msg)
Definition: mkptypes.cxx:96
#define AWAR_TREE_EXPORT_QUOTEMODE
Definition: ad_trees.cxx:74
void AW_create_fileselection_awars(AW_root *awr, const char *awar_base, const char *directories, const char *filter, const char *file_name)
Definition: AW_file.cxx:72
TreeNode * TREE_load(const char *path, TreeRoot *troot, char **commentPtr, bool allow_length_scaling, char **warningPtr)
Definition: TreeRead.cxx:631
static bool sort_dtree_by_other_tree_cb(TreeNode *tree, GB_ERROR &error)
Definition: ad_trees.cxx:1067
#define AWAR_TREE
GB_ERROR GBT_copy_tree(GBDATA *gb_main, const char *source_name, const char *dest_name)
Definition: adtree.cxx:1251
void NT_create_twoTreeSelection(AW_window *aws)
Definition: ad_trees.cxx:566
static AWT_predefined_config moveGroupInfo_predef[]
Definition: ad_trees.cxx:670
bool in_same_branch_as(const TreeNode *other) const
Definition: TreeNode.h:204
TREE_canvas * NT_get_canvas_showing_tree(const char *tree_name, bool forceDisplay)
TreeNode * get_brother()
Definition: TreeNode.h:394
ARB_edge counter_previous() const
Definition: TreeNode.h:797
static void update_filter_cb(AW_root *root)
Definition: ad_trees.cxx:176
#define AWAR_GROUPXFER_OUTGROUP_ABS
Definition: ad_trees.cxx:55
#define cmp(h1, h2)
Definition: admap.cxx:50
GroupsToTransfer
Definition: NT_tree_cmp.h:27
void multifurcate_whole_tree(const multifurc_limits &below)
Definition: TreeNode.cxx:623
NOT4PERL GB_ERROR GB_xcmd(const char *cmd, XCMD_TYPE exectype) __ATTR__USERESULT_TODO
Definition: adsocket.cxx:874
#define AWAR_GROUPXFER_UNKNOWN_ABS
Definition: ad_trees.cxx:58
#define AWAR_MFURC_BOOTSTRAP_LIMIT
Definition: ad_trees.cxx:1095
bool is_son_of(const TreeNode *Father) const
Definition: TreeNode.h:184
char * read_string() const
Definition: AW_awar.cxx:201
GB_ERROR GB_write_security_write(GBDATA *gbd, unsigned long level)
Definition: arbdb.cxx:1582
static void create_consense_tree_cb(AW_window *aww, AW_selection *selected_trees)
Definition: ad_trees.cxx:870
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:554
void awt_create_order_buttons(AW_window *aws, awt_orderfun reorder_cb, AW_CL cl_user)
Definition: AWT_modules.cxx:17
SortByTopo(const TreeNode *by)
Definition: ad_trees.cxx:1037
AW_awar * unmap()
Definition: AW_awar.cxx:598
Definition: arbdb.h:86
void AW_refresh_fileselection(AW_root *awr, const char *awar_prefix)
Definition: AW_file.cxx:944
bool is_ancestor_of(const TreeNode *descendant) const
Definition: TreeNode.h:201
ExportNodeType
Definition: ad_trees.cxx:171
void create_autosize_button(const char *macro_name, AW_label label, const char *mnemonic=NULp, unsigned xtraSpace=1)
Definition: AW_button.cxx:419
float read_float() const
Definition: AW_awar.cxx:180
#define __ATTR__REDUCED_OPTIMIZE
Definition: test_unit.h:83
#define AWAR_TREE_CONSENSE_SELECTED
Definition: ad_trees.cxx:82
#define nt_assert(cond)
Definition: NT_local.h:27
#define AWAR_MFURC_CONSIDER_BOOTSTRAP
Definition: ad_trees.cxx:1091
#define AWAR_GROUPXFER_INGROUP_ABS
Definition: ad_trees.cxx:52
void NT_create_multifurcate_tree_awars(AW_root *aw_root, AW_default props)
Definition: ad_trees.cxx:1097
void create_trees_var(AW_root *aw_root, AW_default aw_def)
Definition: ad_trees.cxx:196
char * GB_unique_filename(const char *name_prefix, const char *suffix)
Definition: adsocket.cxx:1199
char * awar_name
Definition: aw_awar.hxx:103
int GB_read_security_delete(GBDATA *gbd)
Definition: arbdb.cxx:1578
TreeNode * dest() const
Definition: TreeNode.h:727
static AW_window_simple * create_select_other_tree_window(AW_root *root, const char *winId, const char *winTitle, const char *helpFile, AW_awar *awar_displayed_tree)
Definition: ad_trees.cxx:599
AW_DB_selection * awt_create_TREE_selection_list(GBDATA *gb_main, AW_window *aws, const char *varname, bool fallback2default)
static void ad_move_tree_info(AW_window *aww, bool transferGroups)
Definition: ad_trees.cxx:483
bool is_leaf() const
Definition: TreeNode.h:171
AW_awar * awar_int(const char *var_name, long default_value=0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:580
void auto_space(int xspace, int yspace)
Definition: AW_at.cxx:259
GroupTransferMode
Definition: NT_tree_cmp.h:21
GB_ERROR close(GB_ERROR error)
Definition: arbdbpp.cxx:32
#define AWAR_GROUPXFER_KEELING
Definition: ad_trees.cxx:59
static AW_window * create_tree_export_window(AW_root *root)
Definition: ad_trees.cxx:313
bool is_inside(const TreeNode *subtree) const
Definition: TreeNode.h:198
AW_awar * source_tree_awar(AW_root *root)
Definition: TreeAdmin.cxx:35
#define AWAR_TREE_EXPORT_INCLUDE_BRANCHLENS
Definition: ad_trees.cxx:71
SizeAwareTree * get(size_t &different_species, GB_ERROR &error)
Definition: CT_ctree.hxx:200
AW_window * create_copy_window(AW_root *root, const Spec *spec)
Definition: TreeAdmin.cxx:221
char * name
Definition: TreeNode.h:134
awt_reorder_mode
Definition: awt_modules.hxx:22
AW_awar * map(const char *awarn)
Definition: AW_awar.cxx:523
void subtitle(const char *stitle)
Definition: arb_progress.h:263
GB_ERROR GB_write_security_delete(GBDATA *gbd, unsigned long level)
Definition: arbdb.cxx:1603
GBT_LEN sum_child_lengths() const
Definition: TreeNode.cxx:670
#define TEST_EXPECT_NO_ERROR(call)
Definition: test_unit.h:1107
void remove_bootstrap()
Definition: TreeNode.cxx:644
void aw_message(const char *msg)
Definition: AW_status.cxx:932
ARB_edge counter_next() const
Definition: TreeNode.h:786
AW_root * get_root()
Definition: aw_window.hxx:348
#define TEST_EXPECT_SAVED_NEWICK(format, gb_main, treename, expected_newick)
Definition: test_unit.h:1452
#define NULp
Definition: cxxforward.h:97
GBDATA * gb_main
Definition: NT_local.h:37
ExportTreeType
Definition: ad_trees.cxx:165
static GB_ERROR sort_tree_by_other_tree(GBDATA *gb_main, TreeNode *tree, const char *other_tree)
Definition: ad_trees.cxx:1053
#define TEST_EXPECT_ERROR_CONTAINS(call, part)
Definition: test_unit.h:1103
CombinedPosInfo(const CombinedPosInfo &c1, const CombinedPosInfo &c2)
Definition: ad_trees.cxx:989
GB_ERROR write_string(const char *aw_string)
#define TEST_EXPECT_DIFFERENT(expr, want)
Definition: test_unit.h:1290
static char * command
Definition: arb_a2ps.c:319
const char * get_data() const
Definition: arb_strbuf.h:70
GB_ERROR NTREE_move_tree_info(GBDATA *gb_main, const char *tree_source, const char *tree_dest, const char *log_file, GroupTransferMode mode, GroupsToTransfer what, const GroupMatchScorer &scorer, const char *aci)
#define AWAR_MFURC_LENGTH_LIMIT
Definition: ad_trees.cxx:1094
const char * local_id(const char *id) const
Definition: AW_window.cxx:744
#define FALLTHROUGH
Definition: cxxforward.h:110
GBT_LEN get_branchlength() const
Definition: TreeNode.h:219
#define AWAR_TREE_EXPORT_INCLUDE_BOOTSTRAPS
Definition: ad_trees.cxx:70
GBDATA * GBT_find_tree(GBDATA *gb_main, const char *tree_name)
Definition: adtree.cxx:947
GB_transaction ta(gb_var)
void callback(const WindowCallback &cb)
Definition: AW_window.cxx:130
#define AWAR_TREE_EXPORT_HIDE_FOLDED_GROUPS
Definition: ad_trees.cxx:73
void destroy(TreeNode *that)
Definition: TreeNode.h:559
GBDATA * gb_main
Definition: adname.cxx:33
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:570
void set_length(GBT_LEN len)
Definition: TreeNode.h:736
AW_window * aww
Definition: awt_canvas.hxx:337
GBDATA * GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create)
Definition: adquery.cxx:531
#define AWAR_TREE_EXPORT_FILEBASE
Definition: ad_trees.cxx:62
void hide_or_notify(const char *error)
Definition: AW_window.cxx:1817
void NT_deselect_group(AW_root *awr)
Definition: NT_extern.cxx:988
#define AWAR_TREE_SECURITY
Definition: ad_trees.cxx:44
static void sort_tree_by_other_tree_cb(UNFIXED, TREE_canvas *ntw)
Definition: ad_trees.cxx:1073
static void use_selected_as_target_cb(AW_window *aww)
Definition: ad_trees.cxx:935
AW_awar * awar_pointer(const char *var_name, GBDATA *default_value=NULp, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:590
static AW_window * create_tree_import_window(AW_root *root)
Definition: ad_trees.cxx:449
AW_awar * get_awar_tree() const
CombinedPosInfo(const TreeRelativePosition &s, const TreeRelativePosition &t)
Definition: ad_trees.cxx:983
TreeRelativePosition relative(const char *name) const
Definition: tree_position.h:78
#define AW_ROOT_DEFAULT
Definition: aw_base.hxx:106
GBDATA * GB_entry(GBDATA *father, const char *key)
Definition: adquery.cxx:334
AW_selection_list * get_sellist()
Definition: aw_select.hxx:196
GBDATA * GBT_tree_infrontof(GBDATA *gb_tree)
Definition: adtree.cxx:985
void aw_message_if(GB_ERROR error)
Definition: aw_msg.hxx:21
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:195
void GB_close(GBDATA *gbd)
Definition: arbdb.cxx:649
NT_global GLOBAL
Definition: NT_main.cxx:44
TreeNode * source() const
Definition: TreeNode.h:726
void put(char c)
Definition: arb_strbuf.h:138
void NT_multifurcate_tree(TREE_canvas *ntw, const TreeNode::multifurc_limits &below)
#define UNCOVERED()
Definition: arb_assert.h:380
Definition: arbdb.h:66
#define AWAR_GROUPXFER_OVERWRITE_MODE
Definition: ad_trees.cxx:51
GB_write_int const char s
Definition: AW_awar.cxx:156