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