source: tags/arb-6.0-rc3/PERL_SCRIPTS/ARBTOOLS/raxml2arb.pl

Last change on this file was 11626, checked in by westram, 10 years ago
  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 9.7 KB
Line 
1#!/usr/bin/perl
2# =============================================================== #
3#                                                                 #
4#   File      : raxml2arb.pl                                      #
5#   Purpose   : Import XX best of YY calculated raxml trees into  #
6#               ARB and generate comment containing likelyhood    #
7#               and content of info file                          #
8#                                                                 #
9#   Coded by Ralf Westram (coder@reallysoft.de) in March 2008     #
10#   Institute of Microbiology (Technical University Munich)       #
11#   http://www.arb-home.de/                                       #
12#                                                                 #
13# =============================================================== #
14
15use strict;
16use warnings;
17
18my $MODE_NORMAL       = 0;
19my $MODE_BOOTSTRAPPED = 1;
20my $MODE_OPTIMIZED    = 2;
21
22sub arb_message($) {
23  my ($msg) = @_;
24  print "Message: $msg\n";
25  system("arb_message \"$msg\"");
26}
27
28sub error($) {
29  my ($msg) = @_;
30  if ($msg =~ /at.*\.pl/o) {
31    my ($pe,$loc) = ($`,$&.$');
32    chomp $loc;
33    $msg = $pe."\n(".$loc.")\nPlease check console for additional error reasons";
34  }
35  arb_message($msg);
36  die $msg;
37}
38
39my $loaded_log = undef;
40my @log = ();
41
42sub loadLog($) {
43  my ($log) = @_;
44  if (defined $loaded_log) {
45    if ($log ne $loaded_log) {
46      $loaded_log = undef;
47      @log = ();
48    }
49  }
50  if (not defined $loaded_log) {
51    open(LOG,'<'.$log) || die "can't load '$log' (Reason: $!)";
52    my $line;
53    while (defined($line=<LOG>)) {
54      chomp($line);
55      push @log, $line;
56    }
57    close(LOG);
58  }
59}
60
61sub firstLogLineMatching($$) {
62  my ($log,$regexp) = @_;
63  loadLog($log);
64  foreach my $line (@log) {
65    if ($line =~ $regexp) { return ($line,$1); }
66  }
67  return (undef,undef);
68}
69
70sub raxml_filename($$$) {
71  my ($type,$name,$run) = @_;
72  my $fname = 'RAxML_'.$type.'.'.$name;
73  if (defined $run) { $fname .= '.RUN.'.$run; }
74  return $fname;
75}
76
77sub someWhat($$) {
78  my ($count,$what) = @_;
79  if ($count==1) { return '1 '.$what; }
80  return $count.' '.$what.'s';
81}
82
83my @splitted_trees = ();
84
85sub split_treefile($$$) {
86  my ($in,$out,$treesExpected) = @_;
87  @splitted_trees = ();
88  my $outcount = 0;
89  open(IN,'<'.$in) || die "can't read '$in' (Reason: $!)";
90  my $line;
91  while (defined($line=<IN>)) {
92    if ($line =~ /\(/o) {
93      my $outname = "$out.$outcount"; $outcount++;
94      open(OUT,'>'.$outname) || die "can't write '$outname' (Reason: $!)";
95      print OUT $line;
96      close(OUT);
97      push @splitted_trees, $outname;
98    }
99    else {
100      print "Unexpected line in '$in':\n";
101      print $line;
102    }
103  }
104  close(IN);
105  my $treesFound = scalar(@splitted_trees);
106  if ($treesFound!=$treesExpected) {
107    die "Failed to split '$in' into single treefiles\n".
108    "(expected to find $treesExpected trees, found $treesFound)";
109  }
110}
111
112sub treeInfo_normal($$) {
113  my ($name,$run) = @_;
114
115  my $result       = raxml_filename('result',$name,$run);
116  my $bipartitions = raxml_filename('bipartitions',$name,$run);
117  my $parsimony    = raxml_filename('parsimonyTree',$name,$run);
118  my $log          = raxml_filename('log',$name,$run);
119
120  if (not -f $result) { # no result tree, try bipartitions or parsimonyTree
121    if (-f $bipartitions) { return ($bipartitions,'unknown'); }
122    if (-f $parsimony) { return ($parsimony,'unknown'); }
123  }
124
125  my ($line) = firstLogLineMatching($log,qr/./); # first non-empty line
126  if (not $line =~ / (.*)$/o) {
127    die "can't parse likelyhood from '$log'";
128  }
129
130  my $likelyhood = $1;
131  return ($result,$likelyhood);
132}
133
134sub treeInfo_bootstrapped($$) {
135  my ($name,$run) = @_;
136
137  my $info = raxml_filename('info',$name,undef);
138  if (defined $run) {
139    my $treeCount = scalar(@splitted_trees);
140    if ($run>=$treeCount) {
141      die "Invalid run number $run - has to be in [0 .. ".($treeCount-1)."]";
142    }
143    my ($line,$likelyhood) = firstLogLineMatching($info,qr/^Bootstrap\[$run\]:\s.*\slikelihood\s+([^\s,]+),/);
144    if (not defined $likelyhood) {
145      die "Failed to parse likelyhood for 'Bootstrap[$run]' from '$info'";
146    }
147    return ($splitted_trees[$run],$likelyhood);
148  }
149  else {
150    my $bestTree = raxml_filename('bestTree',$name,undef);
151    my ($line,$likelyhood) = firstLogLineMatching($info,qr/^Final ML Optimization Likelihood:\s+(.*)$/);
152    if (not defined $likelyhood) {
153      arb_message("Failed to extract final likelyhood from '$info'");
154      $likelyhood = 'unknown';
155    }
156    return ($bestTree,$likelyhood);
157  }
158}
159
160
161
162sub treeInfo($$$) {
163  my ($mode,$name,$run) = @_;
164
165  if ($mode==$MODE_BOOTSTRAPPED)                     { return treeInfo_bootstrapped($name,$run); }
166  if ($mode==$MODE_NORMAL or $mode==$MODE_OPTIMIZED) { return treeInfo_normal($name,$run); }
167
168  die "Unhandled mode '$mode'";
169}
170
171sub findTrees($$$$\%) {
172  my ($name,$mode,$runs,$take,$likelyhood_r) = @_;
173
174  %$likelyhood_r = ();
175
176  my $singleTree = 0;
177  if    ($mode==$MODE_NORMAL)       { if ($runs==1) { $singleTree = 1; } }
178  elsif ($mode==$MODE_BOOTSTRAPPED) { if ($take==1) { $singleTree = 1; } }
179  elsif ($mode==$MODE_OPTIMIZED)    { $singleTree = 1; }
180  else { die; }
181
182  if ($singleTree==1) {
183    my ($tree,$likely) = treeInfo($mode,$name,undef);
184    $$likelyhood_r{$tree} = $likely;
185  }
186  else {
187    if ($mode==$MODE_BOOTSTRAPPED) {
188      my $raxml_out   = raxml_filename('bootstrap',$name,undef);
189      split_treefile($raxml_out, 'raxml2arb.tree',$runs);
190      print "Splitted '$raxml_out' into ".scalar(@splitted_trees)." treefiles\n";
191    }
192    for (my $r = 0; $r<$runs; $r++) {
193      my ($tree,$likely) = treeInfo($mode,$name,$r);
194      $$likelyhood_r{$tree} = $likely;
195    }
196  }
197}
198
199sub main() {
200  eval {
201    my $args = scalar(@ARGV);
202
203    if ($args != 6) {
204      die "Usage: raxml2arb.pl RUNNAME NUMBEROFRUNS [normal|bootstrapped|optimized] TAKETREES [import|consense] \"COMMENT\"\n".
205        "       import: Import the best TAKETREES trees of NUMBEROFRUNS generated trees into ARB\n".
206        "       consense: Create and import consensus tree of best TAKETREES trees of NUMBEROFRUNS generated trees\n";
207    }
208
209    my ($RUNNAME,$NUMBEROFRUNS,$MODE,$TAKETREES,$CONSENSE,$COMMENT) = @ARGV;
210
211    if ($NUMBEROFRUNS<1) { die "NUMBEROFRUNS has to be 1 or higher (NUMBEROFRUNS=$NUMBEROFRUNS)"; }
212
213    my %likelyhood  = (); # key=treefile, value=likelyhood
214    my @treesToTake = (); # treefiles
215
216    my $mode = $MODE_NORMAL;
217    if ($MODE eq 'bootstrapped') { $mode = $MODE_BOOTSTRAPPED; }
218    elsif ($MODE eq 'optimized') { $mode = $MODE_OPTIMIZED; }
219    elsif ($MODE ne 'normal') { die "Unexpected mode '$MODE' (accepted: 'normal', 'bootstrapped', 'optimized')"; }
220
221    my $calc_consense = 0;
222    if ($CONSENSE eq 'consense') { $calc_consense = 1; }
223    elsif ($CONSENSE ne 'import') { die "Unknown value '$CONSENSE' (expected 'import' or 'consense')"; }
224
225    findTrees($RUNNAME,$mode,$NUMBEROFRUNS,$TAKETREES,%likelyhood);
226
227    my $createdTrees = scalar(keys %likelyhood);
228    print "Found ".someWhat($createdTrees,'tree').":\n";
229
230    if ($TAKETREES > $createdTrees) {
231      arb_message("Cant take more trees (=$TAKETREES) than calculated (=$createdTrees) .. using all");
232      $TAKETREES = $createdTrees;
233    }
234
235    my @sortedTrees = sort { $likelyhood{$b} <=> $likelyhood{$a}; } keys %likelyhood;
236    foreach (@sortedTrees) { print "  $_ = ".$likelyhood{$_}."\n"; }
237
238    @treesToTake = splice(@sortedTrees,0,$TAKETREES);
239
240    my $treesToTake = scalar(@treesToTake);
241    if ($treesToTake==0) { die "failed to detect RAxML output trees"; }
242
243    if ($calc_consense and $treesToTake<2) {
244      arb_message("Need to take at least 2 trees to create a consensus tree - importing..");
245      $calc_consense = 0;
246    }
247
248    my $treename = 'tree_RAxML_'.$$;
249    my $infofile = 'RAxML_info.'.$RUNNAME;
250
251    if ($calc_consense==0) {
252      print 'Importing '.someWhat($treesToTake,'tree').":\n";
253      my $count = undef;
254      if ($treesToTake>1) { $count = 1; }
255
256      foreach (@treesToTake) {
257        print "  $_ = ".$likelyhood{$_}."\n";
258        my $currTreename = $treename;
259        if (defined $count) {
260          $currTreename .= '_'.$count;
261          $count++;
262        }
263        my $command = 'arb_read_tree '.$currTreename.' '.$_.' "'.$COMMENT."\n".'likelyhood='.$likelyhood{$_}.'"';
264        if (-f $infofile) { $command .= ' -commentFromFile '.$infofile; }
265
266        system($command)==0 || die "can't execute '$command' (Reason: $?)";
267      }
268    }
269    else { # calc consense tree
270      my $minLH  = undef;
271      my $maxLH  = undef;
272      my $meanLH = 0;
273
274      print 'Consensing '.someWhat($treesToTake,'tree').":\n";
275      open(INTREE,'>intree') || die "can't write 'intree' (Reason: $!)";
276      foreach (@treesToTake) {
277        my $LH = $likelyhood{$_};
278        print "  $_ = $LH\n";
279        if (not defined $minLH) {
280          $minLH = $maxLH = $LH;
281        }
282        else {
283          if ($LH < $minLH) { $minLH = $LH; }
284          if ($LH > $maxLH) { $maxLH = $LH; }
285        }
286        $meanLH += $LH;
287
288        open(RAXMLTREE,'<'.$_) || die "can't read '$_' (Reason: $!)";
289        foreach (<RAXMLTREE>) {
290          print INTREE $_;
291        }
292        close(RAXMLTREE);
293        print INTREE "\n";
294      }
295      close(INTREE);
296
297      $meanLH /= $treesToTake;
298
299      my $command = 'arb_echo y | consense';
300      system($command)==0 || die "can't execute '$command' (Reason: $?)";
301
302      if (not -f 'outtree') {
303        die "Consense failed (no 'outtree' generated)";
304      }
305
306      my $comment = "$COMMENT\nConsensus tree of $treesToTake trees\nLikelyhood: min=$minLH mean=$meanLH max=$maxLH";
307      $command = 'arb_read_tree -consense '.$treesToTake.' '.$treename.' outtree "'.$comment.'"';
308      if (-f $infofile) { $command .= ' -commentFromFile '.$infofile; }
309      system($command)==0 || die "can't execute '$command' (Reason: $?)";
310    }
311  };
312  if ($@) { error($@); }
313}
314main();
Note: See TracBrowser for help on using the repository browser.