1
// ============================================================= //
3
// File : arb_consensus_tree.cxx //
4
// Purpose : build consensus tree with the same library //
7
// Coded by Ralf Westram (coder@reallysoft.de) in March 2012 //
8
// Institute of Microbiology (Technical University Munich) //
9
// http://www.arb-home.de/ //
11
// ============================================================= //
13
#include <CT_ctree.hxx>
15
#include <TreeWrite.h>
22
static GBT_TREE *build_consensus_tree(const CharPtrArray& input_trees, GB_ERROR& error, size_t& different_species, double weight, char *&comment) {
23
// read all input trees, generate and return consensus tree
24
// (Note: the 'weight' used here doesn't matter atm, since all trees are added with the same weight)
30
GBT_TREE *consense_tree = NULL;
31
if (input_trees.empty()) {
32
error = "no trees given";
35
ConsensusTreeBuilder tree_builder;
37
for (size_t i = 0; !error && i<input_trees.size(); ++i) {
38
char *warnings = NULL;
40
TreeRoot *root = new TreeRoot(new SizeAwareNodeFactory, true); // will be deleted when tree gets deleted
41
SizeAwareTree *tree = DOWNCAST(SizeAwareTree*, TREE_load(input_trees[i], *root, NULL, true, &warnings));
43
error = GBS_global_string("Failed to load tree '%s' (Reason: %s)", input_trees[i], GB_await_error());
47
GB_warningf("while loading tree '%s':\n%s", input_trees[i], warnings);
50
tree_builder.add(tree, input_trees[i], weight);
54
if (!error) consense_tree = tree_builder.get(different_species, error);
55
if (!error) comment = tree_builder.get_remark();
57
arb_assert(contradicted(consense_tree, error));
61
static char *create_tree_name(const char *savename) {
62
// create a DB treename (using savename as hint)
65
// as default use part behind '/' and remove file extension
66
const char *lslash = strrchr(savename, '/');
67
if (lslash) savename = lslash+1;
69
const char *ldot = strrchr(savename, '.');
71
tree_name = ldot ? GB_strpartdup(savename, ldot-1) : strdup(savename);
72
if (tree_name[0] == 0) freedup(tree_name, "tree_consensus");
75
// make sure tree name starts with 'tree_'
76
if (!ARB_strBeginsWith(tree_name, "tree_")) {
77
freeset(tree_name, GBS_global_string_copy("tree_%s", tree_name));
82
static GB_ERROR save_tree_as_newick(GBT_TREE *tree, const char *savename, const char *comment) {
83
// save a tree to a newick file
85
// since ARB only saves trees out of a database,
89
// - save to newick as usual
92
GBDATA *gb_main = GB_open("", "crw");
93
GB_ERROR error = NULL;
96
error = GB_await_error();
99
char *db_tree_name = create_tree_name(savename);
102
GB_transaction ta(gb_main);
103
error = GBT_write_tree_with_remark(gb_main, db_tree_name, tree, comment);
105
if (!error) error = TREE_write_Newick(gb_main, db_tree_name, NULL, true, true, true, true, TREE_SINGLE_QUOTES, savename);
112
error = GBS_global_string("Failed to save tree to '%s' (Reason: %s)", savename, error);
118
int ARB_main(int argc, char *argv[]) {
119
GB_ERROR error = NULL;
122
printf("Usage: arb_consensus_tree [options] [tree]+\n"
123
"Purpose: Create a consensus tree out of multiple trees\n"
125
" -w outfile write consensus tree to outfile\n");
127
// @@@ wanted options
128
// - do not add relative frequency of used subtrees as bootstrap values
129
// - multifurcate branches with bootstrap value below XXX
130
// - eliminate branches with bootstrap value below YYY
134
char *savename = NULL;
136
ConstStrArray input_tree_names;
138
for (int a = 1; a<argc; ++a) {
139
const char *arg = argv[a];
142
case 'w': savename = strdup(argv[++a]); break;
143
default : error = GBS_global_string("Unknown switch '-%c'", arg[1]); break;
147
input_tree_names.put(argv[a]);
151
if (!error && input_tree_names.empty()) error = "no input trees specified";
154
size_t species_count;
156
GBT_TREE *cons_tree = build_consensus_tree(input_tree_names, error, species_count, 1.0, comment);
159
error = GBS_global_string("Failed to build consensus tree (Reason: %s)", error);
162
size_t leafs = GBT_count_leafs(cons_tree);
163
double percent = size_t((leafs*1000)/species_count)/10.0;
165
printf("Generated tree contains %.1f%% of species (%zu of %zu found in input trees)\n",
166
percent, leafs, species_count);
169
error = save_tree_as_newick(cons_tree, savename, comment);
172
printf("successfully created consensus tree\n"
173
"(no savename specified -> tree not saved)\n");
183
printf("Error in arb_consensus_tree: %s\n", error);
186
return error ? EXIT_FAILURE : EXIT_SUCCESS;
189
// --------------------------------------------------------------------------------
193
#include <test_unit.h>
196
#include "command_output.h"
198
// #define TEST_AUTO_UPDATE // uncomment to update expected trees (if more than date differs)
200
static char *custom_tree_name(int dir, const char *name) { return GBS_global_string_copy("consense/%i/%s.tree", dir, name); }
201
static char *custom_numbered_tree_name(int dir, const char *name, int treeNr) { return GBS_global_string_copy("consense/%i/%s_%i.tree", dir, name, treeNr); }
203
static void add_inputnames(StrArray& to, int dir, const char *basename, int first_tree, int last_tree) {
204
for (int t = first_tree; t <= last_tree; ++t) {
205
to.put(custom_numbered_tree_name(dir, basename, t));
209
static double calc_intree_distance(GBT_TREE *tree) {
210
if (tree->is_leaf) return 0.0;
214
calc_intree_distance(tree->leftson) +
215
calc_intree_distance(tree->rightson);
218
#define LENSUM_EPSILON .000001
220
static arb_test::match_expectation consense_tree_generated(GBT_TREE *tree, GB_ERROR error, size_t species_count, size_t expected_species_count, double expected_intree_distance) {
221
using namespace arb_test;
222
expectation_group expected;
224
expected.add(that(error).is_equal_to_NULL());
225
expected.add(that(tree).does_differ_from_NULL());
228
expected.add(that(species_count).is_equal_to(expected_species_count));
229
expected.add(that(GBT_count_leafs(tree)).is_equal_to(expected_species_count));
230
expected.add(that(calc_intree_distance(tree)).fulfills(epsilon_similar(LENSUM_EPSILON), expected_intree_distance));
233
return all().ofgroup(expected);
236
static arb_test::match_expectation build_expected_consensus_tree(const int treedir, const char *basename, int first_tree, int last_tree, double weight, const char *outbasename, size_t expected_species_count, double expected_intree_distance) {
237
using namespace arb_test;
238
expectation_group expected;
239
arb_suppress_progress hideProgress;
241
GB_ERROR error = NULL;
242
StrArray input_tree_names;
243
add_inputnames(input_tree_names, treedir, basename, first_tree, last_tree);
245
size_t species_count;
247
GBT_TREE *tree = build_consensus_tree(input_tree_names, error, species_count, weight, comment);
248
expected.add(consense_tree_generated(tree, error, species_count, expected_species_count, expected_intree_distance));
250
char *saveas = custom_tree_name(treedir, outbasename);
251
error = save_tree_as_newick(tree, saveas, comment);
252
expected.add(that(error).is_equal_to_NULL());
255
char *expected_save = custom_tree_name(treedir, GBS_global_string("%s_expected", outbasename));
256
bool exported_as_expected = arb_test::textfiles_have_difflines_ignoreDates(expected_save, saveas, 0);
258
#if defined(TEST_AUTO_UPDATE)
259
if (!exported_as_expected) {
260
ASSERT_RESULT(int, 0, system(GBS_global_string("cp %s %s", saveas, expected_save)));
262
#else // !defined(TEST_AUTO_UPDATE)
263
expected.add(that(exported_as_expected).is_equal_to(true));
265
TEST_EXPECT_ZERO_OR_SHOW_ERRNO(GB_unlink(saveas));
273
return all().ofgroup(expected);
276
void TEST_consensus_tree_1() {
277
TEST_EXPECTATION(build_expected_consensus_tree(1, "bootstrapped", 1, 5, 0.7, "consense1", 22, 0.925779));
278
// ../UNIT_TESTER/run/consense/1/consense1.tree
280
void TEST_consensus_tree_1_single() {
281
TEST_EXPECTATION(build_expected_consensus_tree(1, "bootstrapped", 1, 1, 0.01, "consense1_single", 22, 0.924610));
282
// ../UNIT_TESTER/run/consense/1/consense1_single.tree
285
void TEST_consensus_tree_2() {
286
TEST_EXPECTATION(build_expected_consensus_tree(2, "bootstrapped", 1, 4, 2.5, "consense2", 59, 2.849827));
287
// ../UNIT_TESTER/run/consense/2/consense2.tree
290
void TEST_consensus_tree_3() {
291
TEST_EXPECTATION(build_expected_consensus_tree(3, "bootstrapped", 1, 3, 137.772, "consense3", 128, 2.170685));
292
// ../UNIT_TESTER/run/consense/3/consense3.tree
295
void TEST_consensus_tree_from_disjunct_trees() {
296
TEST_EXPECTATION(build_expected_consensus_tree(4, "disjunct", 1, 2, 137.772, "disjunct_merged", 15, 2.034290));
297
// ../UNIT_TESTER/run/consense/4/disjunct_merged.tree
300
void TEST_consensus_tree_from_partly_overlapping_trees() {
301
// tree_disjunct_3 contains 7 species
302
// (3 from upper subtree (tree_disjunct_1) and 4 from lower subtree (tree_disjunct_2))
304
TEST_EXPECTATION(build_expected_consensus_tree(4, "disjunct", 1, 3, 137.772, "overlap_merged", 15, 2.596455));
305
// ../UNIT_TESTER/run/consense/4/overlap_merged.tree
308
void TEST_consensus_tree_from_minimal_overlapping_trees() {
309
// tree_disjunct_0 only contains 2 species (1 from upper and 1 from lower subtree).
310
TEST_EXPECTATION(build_expected_consensus_tree(4, "disjunct", 0, 2, 137.772, "overlap_mini_merged", 15, 2.750745));
311
// ../UNIT_TESTER/run/consense/4/overlap_mini_merged.tree
314
void TEST_consensus_tree_described_in_arbhelp() {
315
// see ../HELP_SOURCE/oldhelp/consense_algo.hlp
316
TEST_EXPECTATION(build_expected_consensus_tree(5, "help", 1, 2, 2.0, "help_merged", 6, 1.050000));
317
// ../UNIT_TESTER/run/consense/5/help_merged.tree
320
void TEST_consensus_tree_from_trees_overlapping_by_twothirds() {
321
// These 3 trees where copied from an existing tree.
322
// From each copy one third of all species has been removed
323
// (removed sets were disjunct)
324
TEST_EXPECTATION(build_expected_consensus_tree(6, "overlap_two_thirds", 1, 3, 19.2, "overlap_twothirds_merged", 15, 3.561680));
325
// ../UNIT_TESTER/run/consense/6/overlap_twothirds_merged.tree
328
void TEST_consensus_tree_from_mostly_overlapping_trees() {
329
// the 3 trees were copied from tree_disjunct_source.
330
// from each tree 2 (different) species were deleted.
331
TEST_EXPECTATION(build_expected_consensus_tree(7, "disjunct_del2", 1, 3, 137.772, "overlap_mostly", 15, 1.820057));
332
// ../UNIT_TESTER/run/consense/7/overlap_mostly.tree
335
void TEST_consensus_tree_from_mostly_overlapping_trees_2() {
336
// the 3 trees were copied from tree_disjunct1
337
// from each tree 1 (different) species was deleted.
338
TEST_EXPECTATION(build_expected_consensus_tree(8, "overlap2", 1, 3, 137.772, "overlap2_mostly", 8, 0.529109));
339
// ../UNIT_TESTER/run/consense/8/overlap2_mostly.tree
344
#define REPEATED_TESTS
346
#if defined(REPEATED_TESTS)
347
void TEST_consensus_tree_generation_is_deterministic() {
348
TEST_consensus_tree_described_in_arbhelp();
349
TEST_consensus_tree_from_minimal_overlapping_trees();
350
TEST_consensus_tree_from_partly_overlapping_trees();
351
TEST_consensus_tree_from_disjunct_trees();
352
TEST_consensus_tree_3();
353
TEST_consensus_tree_2();
354
TEST_consensus_tree_1_single();
355
TEST_consensus_tree_1();
358
void TEST_arb_consensus_tree() {
359
TEST_STDOUT_CONTAINS("(arb_consensus_tree -x || true)", "Unknown switch '-x'");
360
TEST_STDOUT_CONTAINS("(arb_consensus_tree -w sth || true)", "no input trees specified");
363
char *saveas = custom_tree_name(1, "consense1");
364
char *expected = custom_tree_name(1, "consense1_expected");
366
TEST_STDOUT_CONTAINS("arb_consensus_tree"
367
" -w consense/1/consense1.tree"
368
" consense/1/bootstrapped_1.tree"
369
" consense/1/bootstrapped_2.tree"
370
" consense/1/bootstrapped_3.tree"
371
" consense/1/bootstrapped_4.tree"
372
" consense/1/bootstrapped_5.tree"
376
TEST_EXPECT_TEXTFILE_DIFFLINES_IGNORE_DATES(saveas, expected, 0);
377
TEST_EXPECT_ZERO_OR_SHOW_ERRNO(GB_unlink(saveas));
384
char *saveas = custom_tree_name(2, "consense2");
385
char *expected = custom_tree_name(2, "consense2_expected");
387
TEST_STDOUT_CONTAINS("arb_consensus_tree"
388
" -w consense/2/consense2.tree"
389
" consense/2/bootstrapped_1.tree"
390
" consense/2/bootstrapped_2.tree"
391
" consense/2/bootstrapped_3.tree"
392
" consense/2/bootstrapped_4.tree"
396
TEST_EXPECT_TEXTFILE_DIFFLINES_IGNORE_DATES(saveas, expected, 0);
397
TEST_EXPECT_ZERO_OR_SHOW_ERRNO(GB_unlink(saveas));
403
#endif // REPEATED_TESTS
405
// #define TREEIO_AUTO_UPDATE // uncomment to auto-update expected test-results
406
// #define TREEIO_AUTO_UPDATE_IF_EXPORT_DIFFERS // uncomment to auto-update expected test-results
407
// #define TREEIO_AUTO_UPDATE_IF_REEXPORT_DIFFERS // uncomment to auto-update expected test-results
409
static const char *findFirstNameContaining(GBT_TREE *tree, const char *part) {
410
const char *found = NULL;
411
if (tree->name && strstr(tree->name, part)) {
414
else if (!tree->is_leaf) {
415
found = findFirstNameContaining(tree->leftson, part);
416
if (!found) found = findFirstNameContaining(tree->rightson, part);
421
void TEST_SLOW_treeIO_stable() {
422
const char *dbname = "trees/bootstrap_groups.arb";
423
const char *treename = "tree_bootstrap_and_groups";
424
const char *savename = "bg";
427
GBDATA *gb_main = GB_open(dbname, "rw");
429
TEST_REJECT_NULL(gb_main);
431
GBT_TREE_NodeFactory nodeMaker;
433
char *outfile = GBS_global_string_copy("trees/%s.tree", savename);
435
for (int save_branchlengths = 0; save_branchlengths <= 1; ++save_branchlengths) {
436
for (int save_bootstraps = 0; save_bootstraps <= 1; ++save_bootstraps) {
437
for (int save_groupnames = 0; save_groupnames <= 1; ++save_groupnames) {
438
bool quoting_occurs = save_bootstraps && save_groupnames;
439
for (int pretty = 0; pretty <= 1; ++pretty) {
441
for (int quoting = TREE_DISALLOW_QUOTES; quoting <= (quoting_occurs ? TREE_DOUBLE_QUOTES : TREE_DISALLOW_QUOTES); ++quoting) {
442
TREE_node_quoting quoteMode = TREE_node_quoting(quoting);
444
char *paramID = GBS_global_string_copy("%s_%s%s%s_%i",
446
save_bootstraps ? "Bs" : "",
447
save_groupnames ? "Grp" : "",
448
save_branchlengths ? "Len" : "",
451
TEST_ANNOTATE(GBS_global_string("for paramID='%s'", paramID));
453
GB_ERROR export_error = TREE_write_Newick(gb_main, treename, NULL, save_branchlengths, save_bootstraps, save_groupnames, pretty, quoteMode, outfile);
454
TEST_EXPECT_NULL(export_error);
456
char *expectedfile = GBS_global_string_copy("trees/%s_exp_%s.tree", savename, paramID);
458
#if defined(TREEIO_AUTO_UPDATE)
459
system(GBS_global_string("cp %s %s", outfile, expectedfile));
460
#else // !defined(TREEIO_AUTO_UPDATE)
461
bool exported_as_expected = arb_test::textfiles_have_difflines_ignoreDates(expectedfile, outfile, 0);
462
#if defined(TREEIO_AUTO_UPDATE_IF_EXPORT_DIFFERS)
463
if (!exported_as_expected) {
464
system(GBS_global_string("cp %s %s", outfile, expectedfile));
466
#else // !defined(TREEIO_AUTO_UPDATE_IF_EXPORT_DIFFERS)
467
TEST_EXPECT(exported_as_expected);
470
// reimport exported tree
471
const char *reloaded_treename = "tree_reloaded";
473
char *comment = NULL;
474
GBT_TREE *tree = TREE_load(expectedfile, nodeMaker, &comment, true, NULL);
475
GB_ERROR load_error = tree ? NULL : GB_await_error();
477
TEST_EXPECTATION(all().of(that(tree).does_differ_from_NULL(),
478
that(load_error).is_equal_to_NULL()));
481
GB_transaction ta(gb_main);
482
GB_ERROR store_error = GBT_write_tree_with_remark(gb_main, reloaded_treename, tree, comment);
483
TEST_EXPECT_NULL(store_error);
487
if (save_groupnames) {
488
const char *quotedGroup = findFirstNameContaining(tree, "quoted");
489
const char *underscoreGroup = findFirstNameContaining(tree, "bs100");
490
TEST_EXPECT_EQUAL(quotedGroup, "quoted");
491
TEST_EXPECT_EQUAL(underscoreGroup, "__bs100");
493
const char *capsLeaf = findFirstNameContaining(tree, "Caps");
494
TEST_EXPECT_EQUAL(capsLeaf, "_MhuCaps");
500
GB_ERROR reexport_error = TREE_write_Newick(gb_main, reloaded_treename, NULL, save_branchlengths, save_bootstraps, save_groupnames, pretty, quoteMode, outfile);
501
TEST_EXPECT_NULL(reexport_error);
503
// eliminate comments added by loading/saving
504
char *outfile2 = GBS_global_string_copy("trees/%s2.tree", savename);
506
char *cmd = GBS_global_string_copy("cat %s"
507
" | grep -v 'Loaded from trees/.*_exp_'"
508
" | grep -v 'tree_reloaded saved to'"
509
" > %s", outfile, outfile2);
510
TEST_EXPECT_NO_ERROR(GBK_system(cmd));
514
bool reexported_as_expected = arb_test::textfiles_have_difflines(expectedfile, outfile2, 0);
516
#if defined(TREEIO_AUTO_UPDATE_IF_REEXPORT_DIFFERS)
517
if (!reexported_as_expected) {
518
system(GBS_global_string("cp %s %s", outfile2, expectedfile));
520
#else // !defined(TREEIO_AUTO_UPDATE_IF_REEXPORT_DIFFERS)
521
TEST_EXPECT(reexported_as_expected);
524
TEST_EXPECT_ZERO_OR_SHOW_ERRNO(unlink(outfile2));
536
TEST_EXPECT_ZERO_OR_SHOW_ERRNO(unlink(outfile));
542
void TEST_CONSENSUS_TREE_functionality() {
543
// functionality wanted in RootedTree (for use in library CONSENSUS_TREE)
545
char *comment = NULL;
547
SizeAwareTree *tree = DOWNCAST(SizeAwareTree*, TREE_load("trees/bg_exp_p_GrpLen_0.tree",
548
*new TreeRoot(new SizeAwareNodeFactory, true),
549
&comment, false, NULL));
550
// -> ../UNIT_TESTER/run/trees/bg_exp_p_GrpLen_0.tree
552
#define ORG_1111 "(AticSea6,(RblAerol,RblMesop))"
553
#define TOP_1111 "((RblAerol,RblMesop),AticSea6)"
554
#define BOT_1111 ORG_1111
556
#define ORG_11121 "((DnrShiba,RsbElon4),MmbAlkal)"
557
#define TOP_11121 ORG_11121
558
#define BOT_11121 "(MmbAlkal,(DnrShiba,RsbElon4))"
560
#define ORG_11122 "((MabPelag,MabSalin),PaoMaris)"
561
#define TOP_11122 ORG_11122
562
#define BOT_11122 "(PaoMaris,(MabPelag,MabSalin))"
564
#define ORG_1112 "(" ORG_11121 "," ORG_11122 ")"
565
#define TOP_1112 "(" TOP_11121 "," TOP_11122 ")"
566
#define BOT_1112 "(" BOT_11121 "," BOT_11122 ")"
567
#define EDG_1112 "(" TOP_11121 "," BOT_11122 ")"
569
#define ORG_111 "(" ORG_1111 "," ORG_1112 ")"
570
#define TOP_111 "(" TOP_1112 "," TOP_1111 ")"
571
#define BOT_111 "(" BOT_1111 "," BOT_1112 ")"
572
#define EDG_111 "(" EDG_1112 "," BOT_1111 ")"
574
#define ORG_112 "(OnlGran2,RsnAnta2)"
575
#define TOP_112 ORG_112
576
#define BOT_112 ORG_112
578
#define ORG_11 "(" ORG_111 "," ORG_112 ")"
579
#define TOP_11 "(" TOP_111 "," TOP_112 ")"
580
#define BOT_11 "(" BOT_112 "," BOT_111 ")"
581
#define EDG_11 "(" EDG_111 "," BOT_112 ")"
583
#define ORG_12 "(_MhuCaps,ThtNivea)"
584
#define TOP_12 "(ThtNivea,_MhuCaps)"
585
#define BOT_12 TOP_12
587
#define ORG_1 "(" ORG_11 "," ORG_12 ")"
588
#define TOP_1 "(" TOP_11 "," TOP_12 ")"
589
#define BOT_1 "(" BOT_12 "," BOT_11 ")"
590
#define EDG_1 "(" EDG_11 "," BOT_12 ")"
592
#define ORG_2 "((LbnMarin,LbnzAlb4),LbnAlexa)"
594
#define BOT_2 "(LbnAlexa,(LbnMarin,LbnzAlb4))"
597
TEST_ASSERT_VALID_TREE(tree);
598
TEST_EXPECT_NEWICK(nSIMPLE, tree, "(" ORG_1 "," ORG_2 ");");
600
TEST_EXPECT_NEWICK(nSIMPLE, tree, "(" ORG_2 "," ORG_1 ");");
603
TEST_ASSERT_VALID_TREE(tree);
604
TreeOrder order[] = { BIG_BRANCHES_TO_TOP, BIG_BRANCHES_TO_BOTTOM, BIG_BRANCHES_TO_EDGE };
606
for (size_t o1 = 0; o1<ARRAY_ELEMS(order); ++o1) {
607
TreeOrder to_order = order[o1];
608
for (size_t o2 = 0; o2<ARRAY_ELEMS(order); ++o2) {
609
TreeOrder from_order = order[o2];
611
for (int rotate = 0; rotate<=1; ++rotate) {
612
tree->reorder_tree(from_order);
613
if (rotate) tree->rotate_subtree();
614
tree->reorder_tree(to_order);
617
case BIG_BRANCHES_TO_TOP: TEST_EXPECT_NEWICK(nSIMPLE, tree, "(" TOP_1 "," TOP_2 ");"); break;
618
case BIG_BRANCHES_TO_EDGE: TEST_EXPECT_NEWICK(nSIMPLE, tree, "(" EDG_1 "," BOT_2 ");"); break;
619
case BIG_BRANCHES_TO_BOTTOM: TEST_EXPECT_NEWICK(nSIMPLE, tree, "(" BOT_2 "," BOT_1 ");"); break;
620
default: TEST_REJECT(true); break;
627
// test rotate_subtree
628
TEST_ASSERT_VALID_TREE(tree);
629
tree->reorder_tree(BIG_BRANCHES_TO_TOP);
630
tree->rotate_subtree(); TEST_EXPECT_NEWICK(nSIMPLE, tree, "((LbnAlexa,(LbnzAlb4,LbnMarin)),((_MhuCaps,ThtNivea),((RsnAnta2,OnlGran2),((AticSea6,(RblMesop,RblAerol)),((PaoMaris,(MabSalin,MabPelag)),(MmbAlkal,(RsbElon4,DnrShiba)))))));");
631
tree->rotate_subtree(); TEST_EXPECT_NEWICK(nSIMPLE, tree, "(" TOP_1 "," TOP_2 ");");
635
TEST_ASSERT_VALID_TREE(tree);
636
RootedTree *AticSea6Grandpa = tree->findLeafNamed("AticSea6")->get_father()->get_father();
637
TEST_REJECT_NULL(AticSea6Grandpa);
638
TEST_ASSERT_VALID_TREE(AticSea6Grandpa);
640
AticSea6Grandpa->set_root();
641
TEST_EXPECT_NEWICK(nSIMPLE, tree,
642
"((" ORG_1112 "," TOP_1111 ")," // AticSea6 is direct son of TOP_1111
643
"((" ORG_2 "," TOP_12 ")," ORG_112 "));");
645
// test auto-detection of "best" root
646
TEST_ASSERT_VALID_TREE(tree);
647
tree->get_tree_root()->find_innermost_edge().set_root();
648
TEST_EXPECT_NEWICK(nLENGTH, tree,
649
"((((LbnMarin:0.019,LbnzAlb4:0.003):0.016,LbnAlexa:0.032):0.122,(ThtNivea:0.230,_MhuCaps:0.194):0.427):0.076,"
650
"(((((DnrShiba:0.076,RsbElon4:0.053):0.034,MmbAlkal:0.069):0.016,((MabPelag:0.001,MabSalin:0.009):0.095,PaoMaris:0.092):0.036):0.030,((RblAerol:0.085,RblMesop:0.042):0.238,AticSea6:0.111):0.018):0.036,(OnlGran2:0.057,RsnAnta2:0.060):0.021):0.076);");
652
TEST_ASSERT_VALID_TREE(tree);
659
// --------------------------------------------------------------------------------