File Coverage

blib/lib/Bio/Tools/Phylo/PAML.pm
Criterion Covered Total %
statement 739 847 87.2
branch 360 456 78.9
condition 109 161 67.7
subroutine 34 36 94.4
pod 2 2 100.0
total 1244 1502 82.8


line stmt bran cond sub pod time code
1             package Bio::Tools::Phylo::PAML;
2             $Bio::Tools::Phylo::PAML::VERSION = '1.7.2';
3 2     2   226531 use utf8;
  2         6  
  2         15  
4 2     2   71 use strict;
  2         7  
  2         59  
5 2     2   14 use warnings;
  2         6  
  2         75  
6              
7 2     2   10 use vars qw($RSTFILENAME);
  2         5  
  2         112  
8              
9 2     2   13 use base qw(Bio::Root::Root Bio::Root::IO Bio::AnalysisParserI);
  2         4  
  2         733  
10              
11 2     2   50542 use IO::String;
  2         3704  
  2         55  
12 2     2   12 use File::Spec;
  2         6  
  2         36  
13 2     2   256 use Bio::TreeIO;
  2         13335  
  2         60  
14 2     2   835 use Bio::Tools::Phylo::PAML::Result;
  2         7  
  2         69  
15 2     2   435 use Bio::LocatableSeq;
  2         43482  
  2         47  
16 2     2   12 use Bio::PrimarySeq;
  2         4  
  2         32  
17 2     2   535 use Bio::Matrix::PhylipDist;
  2         3441  
  2         67  
18 2     2   651 use Bio::Tools::Phylo::PAML::ModelResult;
  2         4  
  2         60  
19              
20             # ABSTRACT: Parses output from the PAML programs codeml, baseml, basemlg, codemlsites and yn00
21             # AUTHOR: Jason Stajich
22             # AUTHOR: Aaron Mackey
23             # OWNER: Jason Stajich
24             # OWNER: Aaron Mackey
25             # LICENSE: Perl_5
26              
27             # AUTHOR: Albert Vilella
28             # AUTHOR: Sendu Bala
29             # AUTHOR: Dave Messina
30              
31              
32             BEGIN {
33 2     2   18089 $RSTFILENAME = 'rst'; # where to get the RST data from
34             }
35              
36              
37             sub new {
38              
39 21     21 1 31188 my ( $class, @args ) = @_;
40              
41 21         121 my $self = $class->SUPER::new(@args);
42 21         642 $self->_initialize_io(@args);
43 21         3752 my ($dir) = $self->_rearrange( [qw(DIR)], @args );
44 21 100       477 $self->{_dir} = $dir if defined $dir;
45 21         83 return $self;
46             }
47              
48              
49              
50             sub next_result {
51              
52 20     20 1 3387 my ($self) = @_;
53 20         34 my %data;
54              
55             # parse the RST file, if it doesn't exist or if dir is not set
56             # this will just skip the parsing
57 20         83 $self->_parse_rst();
58 20         136 my $idlookup; # a hashreference to SEQID (number) ==> 'SEQUENCENAME'
59             # get the various codon and other sequence summary data, if necessary:
60             $self->_parse_summary
61 20 50 33     108 unless ( $self->{'_summary'} && !$self->{'_summary'}->{'multidata'} );
62              
63             # OK, depending on seqtype and runmode now, one of a few things can happen:
64 20         283 my $seqtype = $self->{'_summary'}->{'seqtype'};
65 20 100 100     81 if ( $seqtype eq 'CODONML' || $seqtype eq 'AAML' ) {
    100          
    50          
66 16         27 my $has_model_line = 0;
67 16         40 while ( defined( $_ = $self->_readline ) ) {
68 73 100 100     2631 if ( $seqtype eq 'CODONML'
    100 100        
    100 100        
    100 100        
    100 100        
    50 66        
    50          
    50          
69             && m/^pairwise comparison, codon frequencies:/ )
70             {
71              
72             # runmode = -2, CODONML
73 8         53 $self->debug("pairwise Ka/Ks\n");
74 8         203 $self->_pushback($_);
75 8         87 %data = $self->_parse_PairwiseCodon;
76 8         20 last;
77             }
78             elsif ( $seqtype eq 'AAML' && m/^ML distances of aa seqs\.$/ ) {
79 1         8 $self->_pushback($_);
80              
81             # get AA distances
82 1         10 %data = ( '-AAMLdistmat' => $self->_parse_aa_dists() );
83              
84             # $self->_pushback($_);
85             # %data = $self->_parse_PairwiseAA;
86             # last;
87             }
88             elsif (
89             m/^Model\s+(\d+)/
90             || ( ( !$has_model_line && m/^TREE/ )
91             && $seqtype eq 'CODONML'
92             && ($self->{'_summary'}->{'version'} !~ /4/))
93             # last bit to keep PAML >= 4 from being caught here
94             # bug 2482. Not sure this is the right fix, but tests
95             # pass and the bug's test case passes.
96             )
97             {
98 9         29 $self->_pushback($_);
99 9         85 my $model = $self->_parse_NSsitesBatch;
100 9         18 push @{ $data{'-NSsitesresults'} }, $model;
  9         26  
101 9         35 $has_model_line = 1;
102             }
103             elsif (m/for each branch/) {
104 2         8 my %branch_dnds = $self->_parse_branch_dnds;
105 2 50       8 if ( !defined $data{'-trees'} ) {
106 0         0 $self->warn(
107             "No trees have been loaded, can't do anything\n");
108 0         0 next;
109             }
110 2         5 my ($tree) = @{ $data{'-trees'} };
  2         5  
111 2 50 33     17 if ( !$tree
      33        
112             || !ref($tree)
113             || !$tree->isa('Bio::Tree::Tree') )
114             {
115 0         0 $self->warn("no tree object already stored!\n");
116 0         0 next;
117             }
118              
119             # These need to be added to the Node/branches
120 2         8 while ( my ( $k, $v ) = each %branch_dnds ) {
121              
122             # we can probably do better by caching at some point
123 22         207 my @nodes;
124 22         54 for my $id ( split( /\.\./, $k ) ) {
125             my @nodes_L =
126 98         20070 map { $tree->find_node( -id => $_ ) }
127 44         60 @{ $idlookup->{$id} };
  44         81  
128 44 100       16139 my $n =
129             @nodes_L < 2
130             ? shift(@nodes_L)
131             : $tree->get_lca(@nodes_L);
132 44 50       25445 if ( !$n ) {
133 0         0 $self->warn("no node for $n\n");
134             }
135 44 100 66     87 unless ( $n->is_Leaf && $n->id ) {
136 30         247 $n->id($id);
137             }
138 44         376 push @nodes, $n;
139             }
140 22         38 my ( $parent, $child ) = @nodes;
141 22         84 while ( my ( $kk, $vv ) = each %$v ) {
142 198         1680 $child->add_tag_value( $kk, $vv );
143             }
144             }
145             }
146             elsif (m/^TREE/) {
147              
148             # runmode = 0
149 3         12 $self->_pushback($_);
150 3         32 ( $data{'-trees'}, $idlookup ) = $self->_parse_Forestry;
151              
152             #last;
153             }
154             elsif (m/Heuristic tree search by stepwise addition$/) {
155              
156             # runmode = 3
157 0         0 $self->throw(
158             -class => 'Bio::Root::NotImplemented',
159             -text => "StepwiseAddition not yet implemented!"
160             );
161              
162             # $self->_pushback($_);
163             # %data = $self->_parse_StepwiseAddition;
164             # last;
165              
166             }
167             elsif (m/Heuristic tree search by NNI perturbation$/) {
168              
169             # runmode = 4
170 0         0 $self->throw(
171             -class => 'Bio::Root::NotImplemented',
172             -text => "NNI Perturbation not yet implemented!"
173             );
174              
175             # $self->_pushback($_);
176             # %data = $self->_parse_Perturbation;
177             # last;
178              
179             }
180             elsif (m/^stage 0:/) {
181              
182             # runmode = (1 or 2)
183 0         0 $self->throw(
184             -class => 'Bio::Root::NotImplemented',
185             -text => "StarDecomposition not yet implemented!"
186             );
187              
188 0         0 $self->_pushback($_);
189 0         0 %data = $self->_parse_StarDecomposition;
190 0         0 last;
191             }
192             }
193             }
194             elsif ( $seqtype eq 'BASEML' ) {
195 2         6 while ( defined( $_ = $self->_readline ) ) {
196 3 100       62 if (/^Distances:/) {
    50          
197 2         7 $self->_pushback($_);
198 2         21 my ( $kappa, $alpha ) = $self->_parse_nt_dists();
199 2         381 %data = (
200             '-kappa_distmat' => $kappa,
201             '-alpha_distmat' => $alpha
202             );
203             }
204             elsif (/^TREE/) {
205 1         5 $self->_pushback($_);
206 1         10 ( $data{'-trees'}, $idlookup ) = $self->_parse_Forestry;
207             }
208             }
209             }
210             elsif ( $seqtype eq 'YN00' ) {
211 2         6 while ( $_ = $self->_readline ) {
212 3 100       55 if (
213             m/^Estimation by the method|\(B\) Yang & Nielsen \(2000\) method/
214             )
215             {
216 2         8 $self->_pushback($_);
217 2         19 %data = $self->_parse_YN_Pairwise;
218 2         4 last;
219             }
220             }
221             }
222 20 50       336 if (%data) {
223 20         53 $data{'-version'} = $self->{'_summary'}->{'version'};
224 20         40 $data{'-seqs'} = $self->{'_summary'}->{'seqs'};
225 20         44 $data{'-patterns'} = $self->{'_summary'}->{'patterns'};
226 20         40 $data{'-ngmatrix'} = $self->{'_summary'}->{'ngmatrix'};
227 20         33 $data{'-codonpos'} = $self->{'_summary'}->{'codonposition'};
228 20         34 $data{'-codonfreq'} = $self->{'_summary'}->{'codonfreqs'};
229 20         49 $data{'-model'} = $self->{'_summary'}->{'model'};
230 20         46 $data{'-seqfile'} = $self->{'_summary'}->{'seqfile'};
231 20         40 $data{'-aadistmat'} = $self->{'_summary'}->{'aadistmat'};
232 20         39 $data{'-stats'} = $self->{'_summary'}->{'stats'};
233 20         27 $data{'-aafreq'} = $self->{'_summary'}->{'aafreqs'};
234 20         37 $data{'-ntfreq'} = $self->{'_summary'}->{'ntfreqs'};
235 20         31 $data{'-input_params'} = $self->{'_summary'}->{'inputparams'};
236 20         48 $data{'-rst'} = $self->{'_rst'}->{'rctrted_seqs'};
237 20         41 $data{'-rst_persite'} = $self->{'_rst'}->{'persite'};
238 20         33 $data{'-rst_trees'} = $self->{'_rst'}->{'trees'};
239 20         234 return Bio::Tools::Phylo::PAML::Result->new(%data);
240             }
241             else {
242 0         0 return;
243             }
244             }
245              
246             sub _parse_summary {
247 20     20   38 my ($self) = @_;
248              
249             # Depending on whether verbose > 0 or not, and whether the result
250             # set comes from a multi-data run, the first few lines could be
251             # various things; we're going to throw away any sequence data
252             # here, since we'll get it later anyways
253              
254             # multidata ? : \n\nData set 1\n
255             # verbose ? : cleandata ? : \nBefore deleting alignment gaps. \d sites\n
256             # [ sequence printout ]
257             # \nAfter deleting gaps. \d sites\n"
258             # : [ sequence printout ]
259             # CODONML (in paml 3.12 February 2002) <<-- what we want to see!
260              
261 20         102 my $SEQTYPES = qr( (?: (?: CODON | AA | BASE | CODON2AA ) ML ) | YN00 )x;
262 20         33 my $line;
263 20 50       61 $self->{'_already_parsed_seqs'} = $self->{'_already_parsed_seqs'} ? 1 : 0;
264 20         40 my @lines;
265 20         68 while ( $_ = $self->_readline ) {
266 185         3866 push @lines, $_;
267 185 100 100     2513 if (m/^($SEQTYPES) \s+ # seqtype: CODONML, AAML, BASEML, CODON2AAML, YN00, etc
    100 100        
    100 66        
    50          
    100          
    50          
268             (?: \(in \s+ ([^\)]+?) \s* \) \s* )? # version: "paml 3.12 February 2002"; not present < 3.1 or YN00
269             (\S+) \s* # tree filename
270             (?: (.+?) )? # model description (not there in YN00)
271             \s* $ # trim any trailing space
272             /ox
273             )
274             {
275 20         51 @{ $self->{'_summary'} }{qw(seqtype version seqfile model)} =
  20         156  
276             ( $1, $2, $3, $4 );
277              
278             # in 4.3, the model is on its own line
279 20 100       71 if ( !defined $self->{'_summary'}->{'model'} ) {
280 8         25 my $model_line = $self->_readline;
281 8         152 chomp $model_line;
282 8 100       46 if ($model_line =~ /^Model:/) {
283 6         15 $self->{'_summary'}->{'model'} = $model_line;
284             }
285             }
286              
287             defined $self->{'_summary'}->{'model'}
288 20 100       111 && $self->{'_summary'}->{'model'} =~ s/Model:\s+//;
289             $self->_pushback($_)
290 20 50       64 if $self->{'_summary'}->{'seqtype'} eq 'AAMODEL';
291 20         40 last;
292             }
293             elsif ((m/\s+?\d+?\s+?\d+?/) && ( $self->{'_already_parsed_seqs'} != 1 )) {
294 6         27 $self->_parse_seqs;
295             }
296             elsif (m/^Data set \d$/) {
297 1         5 $self->{'_summary'} = {};
298 1         7 $self->{'_summary'}->{'multidata'}++;
299             }
300             elsif (m/^Before\s+deleting\s+alignment\s+gaps/) { #Gap
301 0         0 my ($phylip_header) = $self->_readline;
302 0         0 $self->_parse_seqs;
303             }
304             elsif ( ( @lines >= 3 ) && ( $self->{'_already_parsed_seqs'} != 1 ) )
305             { #No gap
306             # don't start parsing seqs yet if we're on a blank line
307             # (gives another opportunity to match one of the other regexes)
308 5 100       27 unless (/^\n$/) {
309 2         7 $self->_parse_seqs;
310             }
311             }
312             elsif ( (/Printing out site pattern counts/)
313             && ( $self->{'_already_parsed_seqs'} != 1 ) ) {
314 0         0 $self->_parse_patterns;
315             }
316             }
317              
318 20 50       61 unless ( defined $self->{'_summary'}->{'seqtype'} ) {
319 0         0 $self->throw(
320             -class => 'Bio::Root::NotImplemented',
321             -text => 'Unknown format of PAML output did not see seqtype'
322             );
323             }
324 20         44 my $seqtype = $self->{'_summary'}->{'seqtype'};
325 20 100       93 if ( $seqtype eq "CODONML" ) {
    100          
    50          
    100          
    50          
326 14         53 $self->_parse_inputparams(); # settings from the .ctl file
327             # that get printed
328 14         56 $self->_parse_patterns(); # codon patterns - not very interesting
329 14         53 $self->_parse_seqs(); # the sequences data used for analysis
330 14         41 $self->_parse_codoncts(); # counts and distributions of codon/nt
331             # usage
332 14         47 $self->_parse_codon_freqs(); # codon frequencies
333 14         50 $self->_parse_distmat(); # NG distance matrices
334             }
335             elsif ( $seqtype eq "AAML" ) {
336 2         7 $self->_parse_inputparams;
337 2         8 $self->_parse_patterns();
338 2         6 $self->_parse_seqs(); # the sequences data used for analysis
339 2         9 $self->_parse_aa_freqs(); # AA frequencies
340             # get AA distances
341 2         7 $self->{'_summary'}->{'aadistmat'} = $self->_parse_aa_dists();
342              
343             }
344             elsif ( $seqtype eq "CODON2AAML" ) {
345 0         0 $self->throw(
346             -class => 'Bio::Root::NotImplemented',
347             -text => 'CODON2AAML parsing not yet implemented!'
348             );
349             }
350             elsif ( $seqtype eq "BASEML" ) {
351 2         9 $self->_parse_patterns();
352 2         8 $self->_parse_seqs();
353 2         8 $self->_parse_nt_freqs();
354              
355             }
356             elsif ( $seqtype eq "YN00" ) {
357 2         6 $self->_parse_codon_freqs();
358 2         7 $self->_parse_codoncts();
359 2         6 $self->_parse_distmat(); # NG distance matrices
360             }
361             else {
362 0         0 $self->throw(
363             -class => 'Bio::Root::NotImplemented',
364             -text => 'Unknown seqtype, not yet implemented!',
365             -value => $seqtype
366             );
367             }
368              
369             }
370              
371             sub _parse_inputparams {
372 16     16   39 my ($self) = @_;
373 16         44 while ( defined( $_ = $self->_readline ) ) {
374 39 100 66     876 if (/^((?:Codon frequencies)|(?:Site-class models))\s*:\s+(.+)/) {
    100          
    100          
375 10         33 my ( $param, $val ) = ( $1, $2 );
376 10         43 $self->{'_summary'}->{'inputparams'}->{$param} = $val;
377             }
378             elsif (/^\s+$/) {
379 4         9 next;
380             }
381             elsif ( /^ns\s+=\s+/ || /^Frequencies/ ) {
382 16         67 $self->_pushback($_);
383 16         170 last;
384             }
385             }
386             }
387              
388             sub _parse_codon_freqs {
389 16     16   29 my ($self) = @_;
390 16         37 my ( $okay, $done ) = ( 0, 0 );
391              
392 16         40 while ( defined( $_ = $self->_readline ) ) {
393 1495 100       33326 if (/^Nei|\(A\) Nei/) { $self->_pushback($_); last }
  2         7  
  2         21  
394 1493 100       2279 last if ($done);
395 1479 100       3110 next if (/^\s+/);
396             next
397 922 100 100     2813 unless ( $okay || /^Codon position x base \(3x4\) table\, overall/ );
398 56         86 $okay = 1;
399 56 100       226 if (s/^position\s+(\d+):\s+//) {
400 42         105 my $pos = $1;
401 42         168 s/\s+$//;
402 42         125 my @bases = split;
403 42         77 foreach my $str (@bases) {
404 168         372 my ( $base, $freq ) = split( /:/, $str, 2 );
405 168         491 $self->{'_summary'}->{'codonposition'}->[ $pos - 1 ]->{$base} =
406             $freq;
407             }
408 42 100       154 $done = 1 if $pos == 3;
409             }
410             }
411 16         29 $done = 0;
412 16         37 while ( defined( $_ = $self->_readline ) ) {
413 37 100       710 if (/^Nei\s\&\sGojobori|\(A\)\sNei-Gojobori/) {
414 8         24 $self->_pushback($_);
415 8         78 last;
416             }
417 29 100       58 last if ($done);
418 21 100       70 if (/^Codon frequencies under model, for use in evolver/) {
419 8         24 while ( defined( $_ = $self->_readline ) ) {
420 136 100       2406 last if (/^\s+$/);
421 128         308 s/^\s+//;
422 128         363 s/\s+$//;
423 128         180 push @{ $self->{'_summary'}->{'codonfreqs'} }, [split];
  128         534  
424             }
425 8         20 $done = 1;
426             }
427             }
428             }
429              
430             sub _parse_aa_freqs {
431 2     2   4 my ($self) = @_;
432 2         4 my ( $okay, $done, $header ) = ( 0, 0, 0 );
433 2         4 my (@bases);
434 2 50       3 my $numseqs = scalar @{ $self->{'_summary'}->{'seqs'} || [] };
  2         7  
435 2         5 while ( defined( $_ = $self->_readline ) ) {
436 34 100 66     611 if ( /^TREE/ || /^AA distances/ ) {
437 1         4 $self->_pushback($_);
438 1         9 last;
439             }
440 33 100       48 last if ($done);
441 32 100 100     107 next if ( /^\s+$/ || /^\(Ambiguity/ );
442 20 100       66 if (/^Frequencies\./) {
    50          
    100          
    100          
    100          
443 2         5 $okay = 1;
444             }
445             elsif ( !$okay ) { # skip till we see 'Frequencies.
446 0         0 next;
447             }
448             elsif ( !$header ) {
449 2         6 s/^\s+//; # remove leading whitespace
450 2         14 @bases = split; # get an array of the all the aa names
451 2         4 $header = 1;
452 2         4 $self->{'_summary'}->{'aafreqs'} = {}; # reset/clear values
453 2         6 next;
454             }
455             elsif (
456             /^\#\s+constant\s+sites\:\s+
457             (\d+)\s+ # constant sites
458             \(\s*([\d\.]+)\s*\%\s*\)/x
459             )
460             {
461 2         8 $self->{'_summary'}->{'stats'}->{'constant_sites'} = $1;
462 2         6 $self->{'_summary'}->{'stats'}->{'constant_sites_percentage'} = $2;
463             }
464             elsif (/^ln\s+Lmax\s+\(unconstrained\)\s+\=\s+(\S+)/x) {
465 1         3 $self->{'_summary'}->{'stats'}->{'loglikelihood'} = $1;
466 1         3 $done = 1; # done for sure
467             }
468             else {
469 13         55 my ( $seqname, @freqs ) = split;
470 13         21 my $basect = 0;
471 13         16 foreach my $f (@freqs) {
472              
473             # this will also store 'Average'
474             $self->{'_summary'}->{'aafreqs'}->{$seqname}
475 260         461 ->{ $bases[ $basect++ ] } = $f;
476             }
477             }
478             }
479             }
480              
481             # This is for parsing the automatic tree output
482              
483             sub _parse_StarDecomposition {
484 0     0   0 my ($self) = @_;
485 0         0 my %data;
486              
487 0         0 return %data;
488             }
489              
490             sub _parse_aa_dists {
491 3     3   6 my ($self) = @_;
492 3         5 my ( $okay, $seen, $done ) = ( 0, 0, 0 );
493 3         4 my ( %matrix, @names, @values );
494 3 50       4 my $numseqs = scalar @{ $self->{'_summary'}->{'seqs'} || [] };
  3         9  
495 3         4 my $type = '';
496 3         8 while ( defined( $_ = $self->_readline ) ) {
497 23 100       391 last if $done;
498 21 50       40 if (/^TREE/) { $self->_pushback($_); last; }
  0         0  
  0         0  
499 21 100       50 if (/^\s+$/) {
500 2 50       5 last if ($seen);
501 2         5 next;
502             }
503 19 100       35 if (/^(AA|ML) distances/) {
504 3         5 $okay = 1;
505 3         6 $type = $1;
506 3         7 next;
507             }
508 16         53 s/\s+$//g; # remove trailing space
509 16 50       30 if ($okay) {
510 16         39 my ( $seqname, @vl ) = split;
511 16         24 $seen = 1;
512 16         19 my $i = 0;
513              
514             # hacky workaround to problem with 3.14 aaml
515 16 50 100     46 if (
      66        
516             $type eq 'ML'
517             && !@names
518             && # first entry
519             @vl
520             )
521             { # not empty
522 0         0 push @names, $self->{'_summary'}->{'seqs'}->[0]->display_id;
523             }
524 16         25 for my $s (@names) {
525 35 50       46 last unless @vl;
526 35         83 $matrix{$seqname}->{$s} = $matrix{$s}->{$seqname} = shift @vl;
527             }
528 16         29 push @names, $seqname;
529              
530 16         31 $matrix{$seqname}->{$seqname} = 0;
531             }
532 16 100       42 $done = 1 if ( scalar @names == $numseqs );
533             }
534 3         23 my %dist;
535 3         3 my $i = 0;
536 3         5 @values = ();
537 3         6 foreach my $lname (@names) {
538 16         17 my @row;
539 16         16 my $j = 0;
540 16         23 foreach my $rname (@names) {
541 86         115 my $v = $matrix{$lname}->{$rname};
542 86 50       116 $v = $matrix{$rname}->{$lname} unless defined $v;
543 86         114 push @row, $v;
544 86         153 $dist{$lname}{$rname} = [ $i, $j++ ];
545             }
546 16         18 $i++;
547 16         27 push @values, \@row;
548             }
549             return new Bio::Matrix::PhylipDist(
550 3         23 -program => $self->{'_summary'}->{'seqtype'},
551             -matrix => \%dist,
552             -names => \@names,
553             -values => \@values
554             );
555             }
556              
557             sub _parse_patterns {
558 18     18   34 my ($self) = @_;
559 18         31 my ( $patternct, @patterns, $ns, $ls );
560 18 50       47 return if exists $self->{'_summary'}->{'patterns'};
561              
562 18         52 while ( defined( $_ = $self->_readline ) ) {
563 99 100 66     2345 if ( /^Codon\s+(usage|position)/ || /Model/ ) {
    100          
    100          
    100          
564 11         34 $self->_pushback($_);
565 11         91 last;
566             }
567             elsif ($patternct) {
568              
569             # last unless ( @patterns == $patternct );
570 52 100       139 last if (/^\s+$/);
571 45         115 s/^\s+//;
572 45         245 push @patterns, split;
573             }
574             elsif (/^ns\s+\=\s*(\d+)\s+ls\s+\=\s*(\d+)/) {
575 18         73 ( $ns, $ls ) = ( $1, $2 );
576             }
577             elsif (/^\# site patterns \=\s*(\d+)/) {
578 7         20 $patternct = $1;
579             }
580             else {
581              
582             # $self->debug("Unknown line: $_");
583             }
584             }
585 18         110 $self->{'_summary'}->{'patterns'} = {
586             -patterns => \@patterns,
587             -ns => $ns,
588             -ls => $ls
589             };
590             }
591              
592             sub _parse_seqs {
593              
594             # this should in fact be packed into a Bio::SimpleAlign object instead of
595             # an array but we'll stay with this for now
596 26     26   54 my ($self) = @_;
597              
598             # Use this flag to deal with paml 4 vs 3 differences
599             # In PAML 4 the sequences precede the CODONML|BASEML|AAML
600             # while in PAML3 the files start off with this
601 26 100       82 return 1 if $self->{'_already_parsed_seqs'};
602 18         34 my ( @firstseq, @seqs );
603 18         43 while ( defined( $_ = $self->_readline ) ) {
604 91 100       16999 if (/^(Printing|After|TREE|Codon)/) {
605 5         16 $self->_pushback($_);
606 5         34 last;
607             }
608 86 100 100     345 last if ( /^\s+$/ && @seqs > 0 );
609 73 100       169 next if (/^\s+$/);
610 67 100       197 next if (/^\d+\s+$/);
611              
612             # we are reading PHYLIP format
613 66         264 my ( $name, $seqstr ) = split( /\s+/, $_, 2 );
614 66         3882 $seqstr =~ s/\s+//g; # remove whitespace
615 66 100       181 unless (@firstseq) {
616 13         793 @firstseq = split( //, $seqstr );
617 13         115 push @seqs,
618             Bio::LocatableSeq->new(
619             -display_id => $name,
620             -seq => $seqstr
621             );
622             }
623             else {
624              
625 53         73 my $i = 0;
626 53         66 my $v;
627 53         153 while ( ( $v = index( $seqstr, '.', $i ) ) >= $i ) {
628              
629             # replace the '.' with the correct seq from the
630 2741         3251 substr( $seqstr, $v, 1, $firstseq[$v] );
631 2741         3970 $i = $v;
632             }
633 53         177 push @seqs,
634             Bio::LocatableSeq->new(
635             -display_id => $name,
636             -seq => $seqstr
637             );
638             }
639             }
640 18 100       56 if ( @seqs > 0 ) {
641 13         42 $self->{'_summary'}->{'seqs'} = \@seqs;
642 13         25 $self->{'_already_parsed_seqs'} = 1;
643             }
644 18         381 1;
645             }
646              
647       16     sub _parse_codoncts { }
648              
649             sub _parse_distmat {
650 16     16   32 my ($self) = @_;
651 16         29 my @results;
652 16         36 my $ver = 3.14;
653 16         23 my $firstseq, my $secondseq;
654              
655 16         34 while ( defined( $_ = $self->_readline ) ) {
656 24 100       478 next if /^\s+$/;
657              
658             # We need to get the names of the sequences if this is from YN00:
659 16 100       44 if (/^\(A\)\sNei-Gojobori\s\(1986\)\smethod/) {
660 1         2 $ver = 3.15;
661 1         3 while ( defined( $_ = $self->_readline ) ) {
662 9 100       191 if ($_ =~ m/.*\d+?\.\d+?\s*\(.*/) {
663 1         2 $secondseq = $_;
664 1         2 last;
665             }
666 8         20 $firstseq = $_;
667             }
668             }
669 16         28 last;
670             }
671              
672             #return unless (/^Nei\s*\&\s*Gojobori/);
673              
674             # skip the next 3 lines
675 16 100       52 if ( $self->{'_summary'}->{'seqtype'} eq 'CODONML' ) {
676 14         52 $self->_readline;
677 14         244 $self->_readline;
678 14         211 $self->_readline;
679             }
680 16         228 my $seqct = 0;
681 16         22 my @seqs;
682 16 100       45 if ( $self->{'_summary'}->{'seqtype'} eq 'YN00' ) {
683 2 100       6 if ($firstseq) {
684 1         5 $firstseq =~ s/(.+?)\s+.*/$1/;
685 1         4 $secondseq =~ s/(.+?)\s+.*/$1/;
686 1         3 chomp $firstseq;
687 1         2 chomp $secondseq;
688 1         9 push @seqs, Bio::PrimarySeq->new( -display_id => $firstseq );
689 1         95 push @seqs, Bio::PrimarySeq->new( -display_id => $secondseq );
690             }
691             }
692 16         107 while ( defined( $_ = $self->_readline ) ) {
693 98 50 66     1997 last if ( /^\s+$/ && exists $self->{'_summary'}->{'ngmatrix'} );
694 82 50 33     304 next if ( /^\s+$/ || /^NOTE:/i );
695 82         144 chomp;
696              
697 82         109 my ( $seq, $rest );
698 82 100       158 if ( $self->{'_summary'}->{'seqtype'} eq 'YN00' ) {
699 12         41 ( $seq, $rest ) = split( /\s+/, $_, 2 );
700             }
701             else {
702 70         320 $_ =~ m/(.+?)\s*(-*\d+?\.\d+?.*)/;
703 70         127 $seq = $1;
704 70         123 $rest = $2;
705             }
706 82 100       150 $rest = '' unless defined $rest; # get rid of empty messages
707 82         108 my $j = 0;
708 82 100       153 if ( $self->{'_summary'}->{'seqtype'} eq 'YN00' ) {
709 12         36 push @seqs, Bio::PrimarySeq->new( -display_id => $seq );
710             }
711 82   100     1313 while ($rest
712             && $rest =~
713             /(\-?\d+(\.\d+)?)\s*\(\-?(\d+(\.\d+)?)\s+(\-?\d+(\.\d+)?)\)/g )
714             {
715 218         1561 $self->{'_summary'}->{'ngmatrix'}->[ $j++ ]->[$seqct] = {
716             'omega' => $1,
717             'dN' => $3,
718             'dS' => $5
719             };
720             }
721 82         221 $seqct++;
722             }
723 16 100 66     60 if ( $self->{'_summary'}->{'seqtype'} eq 'YN00' && @seqs ) {
724 2         5 $self->{'_summary'}->{'seqs'} = \@seqs;
725             }
726              
727 16         103 1;
728             }
729              
730             sub _parse_PairwiseCodon {
731 8     8   15 my ($self) = @_;
732 8         18 my @result;
733 8         12 my ( $a, $b, $log, $model, $t, $kappa, $omega, $fixedkappa );
734             # check to see if we have a fixed kappa:
735 8 100       28 if ( $self->{'_summary'}->{'model'} =~ /kappa = (\d+?\.\d+?) fixed/) {
736 1         3 $fixedkappa = $1;
737             }
738 8         20 while ( defined( $_ = $self->_readline ) ) {
739 680 100       12635 if (/^pairwise comparison, codon frequencies\:\s*(\S+)\./) {
    100          
    100          
    100          
    50          
    0          
740 8         26 $model = $1;
741             }
742             # 1st line of a pair block, e.g.
743             # 2 (all_c7259) ... 1 (all_s57600)
744             elsif (/^(\d+)\s+\((\S+)\)\s+\.\.\.\s+(\d+)\s+\((\S+)\)/) {
745 112         376 ( $a, $b ) = ( $1, $3 );
746             }
747             # 2nd line of a pair block, e.g.
748             # lnL = -126.880601
749             elsif (/^lnL\s+\=\s*(\-?\d+(\.\d+)?)/) {
750 112         225 $log = $1;
751 112 50       183 if ( defined( $_ = $self->_readline ) ) {
752             # 3rd line of a pair block, e.g.
753             # 0.19045 2.92330 0.10941
754 112         1964 s/^\s+//;
755 112         316 ( $t, $kappa, $omega ) = split;
756             # if there was a fixed kappa, there will only be two values here ($t, $omega) and $kappa = $fixedkappa.
757 112 100       303 if ($omega eq "") {
758 1         2 $omega = $kappa;
759 1         3 $kappa = $fixedkappa;
760             }
761             }
762             }
763             # 5th line of a pair block, e.g.
764             # t= 0.1904 S= 5.8 N= 135.2 dN/dS= 0.1094 dN= 0.0476 dS= 0.4353
765             # OR lines like (note last field; this includes a fix for bug #3040)
766             # t= 0.0439 S= 0.0 N= 141.0 dN/dS= 0.1626 dN= 0.0146 dS= nan
767             elsif (m/^t\=\s*(\d+(\.\d+)?)\s+/)
768             {
769             # Breaking out each piece individually so that you can see
770             # what each regexp actually looks for
771 112         156 my $parse_string = $_;
772 112         316 $parse_string =~ m/.*t\s*\=\s*(\d+?\.\d+?)\s/;
773 112         203 my $temp_t = $1;
774 112         272 $parse_string =~ m/\sS\s*\=\s*(\d+?\.\d+?)\s/;
775 112         191 my $temp_S = $1;
776 112         235 $parse_string =~ m/\sN\s*\=\s*(\d+?\.\d+?)\s/;
777 112         185 my $temp_N = $1;
778 112         253 $parse_string =~ m/\sdN\/dS\s*\=\s*(\d+?\.\d+?)\s/;
779 112         168 my $temp_omega = $1;
780 112         269 $parse_string =~ m/\sdN\s*\=\s*(\d+?\.\d+?)\s/;
781 112         182 my $temp_dN = $1;
782 112         264 $parse_string =~ m/\sdS\s*\=\s*(.+)\s/;
783 112         194 my $temp_dS = $1;
784 112 50 33     1057 $result[ $b - 1 ]->[ $a - 1 ] = {
    50 33        
785             'lnL' => $log,
786             't' => defined $t && length($t) ? $t : $temp_t,
787             'S' => $temp_S,
788             'N' => $temp_N,
789             'kappa' => $kappa,
790             'omega' => defined $omega && length($omega) ? $omega : $temp_omega,
791             'dN' => $temp_dN,
792             'dS' => $temp_dS
793             };
794             }
795             # 4th line of a pair block (which is blank)
796             elsif (/^\s+$/) {
797 336         631 next;
798             }
799             elsif (/^\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)/) {
800             }
801             else {
802 0         0 $self->debug("unknown line: $_");
803             }
804             }
805 8         230 return ( -mlmatrix => \@result );
806             }
807              
808             sub _parse_YN_Pairwise {
809 2     2   6 my ($self) = @_;
810 2         2 my @result;
811 2         7 while ( defined( $_ = $self->_readline ) ) {
812 11 100       190 last if (/^seq\.\s+seq\./);
813             }
814 2         6 while ( defined( $_ = $self->_readline ) ) {
815 51 100       1135 if (
    100          
    100          
816             m/^\s+(\d+)\s+ # seq #
817             (\d+)\s+ # seq #
818             (\d+(\.\d+))\s+ # S
819             (\d+(\.\d+))\s+ # N
820             (\d+(\.\d+))\s+ # t
821             (\d+(\.\d+))\s+ # kappa
822             (\d+(\.\d+))\s+ # omega
823             \-??(\d+(\.\d+))\s+ # dN
824             \+\-\s+
825             \-??(\d+(\.\d+))\s+ # dN SE
826             \-??(\d+(\.\d+))\s+ # dS
827             \+\-\s+
828             \-??(\d+(\.\d+))\s+ # dS SE
829             /ox
830             )
831             {
832              
833 43         332 $result[ $2 - 1 ]->[ $1 - 1 ] = {
834             'S' => $3,
835             'N' => $5,
836             't' => $7,
837             'kappa' => $9,
838             'omega' => $11,
839             'dN' => $13,
840             'dN_SE' => $15,
841             'dS' => $17,
842             'dS_SE' => $19,
843             };
844             }
845             elsif (/^\s+$/) {
846 4         10 next;
847             }
848             elsif (/^\(C\) LWL85, LPB93 & LWLm methods/) {
849 1         5 $self->_pushback($_);
850 1         8 last;
851             }
852             }
853 2         26 return ( -mlmatrix => \@result );
854             }
855              
856             sub _parse_Forestry {
857 13     13   25 my ($self) = @_;
858 13         41 my ( $instancecount, $num_param, $loglikelihood, $score, $done,
859             $treelength ) = ( 0, 0, 0, 0, 0, 0 );
860 13         25 my $okay = 0;
861 13         22 my ( @ids, %match, @branches, @trees );
862 13         26 while ( defined( $_ = $self->_readline ) ) {
863 175 50       11541 last if $done;
864 175 100 33     1695 if (s/^TREE\s+\#\s*\d+:\s+//) {
    100 33        
    100 33        
    100 66        
    100          
    100          
    100          
865 13         74 ($score) = (s/MP\s+score\:\s+(\S+)\s+$//);
866 13         107 @ids = /(\d+)[\,\)]/g;
867             }
868             elsif (/^Node\s+\&/
869             || /^\s+N37/
870             || /^(CODONML|AAML|YN00|BASEML)/
871             || /^\*\*/
872             || /^Detailed output identifying parameters/ )
873             {
874 11         47 $self->_pushback($_);
875 11         95 $done = 1;
876 11         26 last;
877             }
878             elsif (/^tree\s+length\s+\=\s+(\S+)/) {
879 13         43 $treelength = $1; # not going to store this for now
880             # as it is directly calculated from
881             # $tree->total_branch_length;
882             }
883             elsif (/^\s*lnL\(.+np\:\s*(\d+)\)\:\s+(\S+)/) {
884              
885             # elsif( /^\s*lnL\(.+\)\:\s+(\S+)/ ) {
886 13         68 ( $num_param, $loglikelihood ) = ( $1, $2 );
887             }
888             elsif (/^\(/) {
889 26         298 s/([\,:])\s+/$1/g;
890 26         233 my $treestr = IO::String->new($_);
891 26         1318 my $treeio = Bio::TreeIO->new(
892             -fh => $treestr,
893             -format => 'newick'
894             );
895 26         20560 my $tree = $treeio->next_tree;
896 26 50       154833 if ($tree) {
897 26         81 $tree->score($loglikelihood);
898 26         227 $tree->id("num_param:$num_param");
899 26 100       246 if ( $okay > 0 ) {
900              
901             # we don't save the trees with the number labels
902 13 50 33     75 if ( !%match && @ids ) {
903 13         27 my $i = 0;
904 13         166 for my $m (/([^():,]+):/g) {
905 66         174 $match{ shift @ids } = [$m];
906             }
907 13         30 my %grp;
908 13         48 while ( my $br = shift @branches ) {
909 120         211 my ( $parent, $child ) = @$br;
910 120 100       193 if ( $match{$child} ) {
911 93         109 push @{ $match{$parent} }, @{ $match{$child} };
  93         161  
  93         241  
912             }
913             else {
914 27         68 push @branches, $br;
915             }
916             }
917 13 50       46 if ( $self->verbose > 1 ) {
918 0         0 for my $k ( sort { $a <=> $b } keys %match ) {
  0         0  
919             $self->debug( "$k -> ",
920 0         0 join( ",", @{ $match{$k} } ), "\n" );
  0         0  
921             }
922             }
923             }
924              
925             # Associate SEs to nodes using tags
926 13 100       144 if ( defined( $self->{_SEs} ) ) {
927 3         17 my @SEs = split( " ", $self->{_SEs} );
928 3         5 my $i = 0;
929 3         13 foreach my $parent_id ( map { /\d+\.\.(\d+)/ }
  33         83  
930             split( " ", $self->{_branch_ids} ) )
931             {
932 33         42 my @nodes;
933 33         35 my @node_ids = @{ $match{$parent_id} };
  33         68  
934             my @nodes_L =
935 33         50 map { $tree->find_node( -id => $_ ) } @node_ids;
  48         5491  
936 33 100       11778 my $n =
937             @nodes_L < 2
938             ? shift(@nodes_L)
939             : $tree->get_lca(@nodes_L);
940 33 50       10152 if ( !$n ) {
941 0         0 $self->warn(
942             "no node could be found for node in SE assignation (no lca?)"
943             );
944             }
945 33         80 $n->add_tag_value( 'SE', $SEs[$i] );
946 33         341 $i++;
947             }
948             }
949 13         34 push @trees, $tree;
950             }
951             }
952 26         108 $okay++;
953             }
954             elsif (/^SEs for parameters/) {
955 3         10 my $se_line = $self->_readline;
956 3         54 $se_line =~ s/\n//;
957 3         9 $self->{_SEs} = $se_line;
958             }
959             elsif (/^\s*\d+\.\.\d+/) {
960 13         54 push @branches, map { [ split( /\.\./, $_ ) ] } split;
  93         289  
961 13         34 my $ids = $_;
962 13         43 $ids =~ s/\n//;
963 13         43 $self->{_branch_ids} = $ids;
964             }
965             }
966 13         218 return \@trees, \%match;
967             }
968              
969             sub _parse_NSsitesBatch {
970 9     9   16 my $self = shift;
971 9         16 my ( %data, $idlookup );
972 9         17 my ( $okay, $done ) = ( 0, 0 );
973 9         20 while ( defined( $_ = $self->_readline ) ) {
974 120 100       2318 last if $done;
975 115 100       365 next if /^\s+$/;
976 68 50 100     176 next unless ( $okay || /^Model\s+\d+/ || /^TREE/ );
      66        
977              
978 68 100       491 if (/^Model\s+(\d+)/) {
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    100          
979 7 50       19 if ($okay) {
980              
981             # this only happens if $okay was already 1 and
982             # we hit a Model line
983 0         0 $self->_pushback($_);
984 0         0 $done = 1;
985             }
986             else {
987 7         20 chomp;
988 7         23 $data{'-model_num'} = $1;
989 7         40 ( $data{'-model_description'} ) = (/\:\s+(.+)/);
990 7         19 $okay = 1;
991             }
992             }
993             elsif (/^Time used\:\s+(\S+)/) {
994 7         30 $data{'-time_used'} = $1;
995 7         20 $done = 1;
996             }
997             elsif (/^kappa\s+\(ts\/tv\)\s+\=\s+(\S+)/) {
998 9         36 $data{'-kappa'} = $1;
999             }
1000             elsif (/^TREE/) {
1001 9         30 $self->_pushback($_);
1002 9         87 ( $data{'-trees'}, $idlookup ) = $self->_parse_Forestry;
1003 9 50 50     35 if ( defined $data{'-trees'}
1004 9         35 && scalar @{ $data{'-trees'} } )
1005             {
1006 9         30 $data{'-likelihood'} = $data{'-trees'}->[0]->score;
1007             }
1008 9         65 $okay = 1;
1009             }
1010             elsif (/^omega\s+\(dn\/ds\)\s+\=\s+(\S+)/i) {
1011              
1012             # for M0 (single ratio for the entire tree)
1013             # explicitly put '1.00000' rather than '1', because \d+\.\d{5}
1014             # is reported in all other cases.
1015 1         3 my @p = (q/1.00000/); # since there is only one class,
1016 1         4 my @w = $1;
1017 1         5 $data{'-dnds_site_classes'} = {
1018             'p' => \@p,
1019             'w' => \@w
1020             };
1021              
1022             # since no K=X is provided, put 1 here
1023 1         3 $data{q/-num_site_classes/} = 1;
1024             }
1025             elsif (
1026             /^(Naive Empirical Bayes)|(Bayes Empirical Bayes)|(Positively\sselected\ssites)/i
1027             )
1028             {
1029 6         24 $self->_pushback($_);
1030 6         63 my ( $sites, $neb, $beb ) = $self->_parse_Pos_selected_sites;
1031 6         16 $data{'-pos_sites'} = $sites;
1032 6         13 $data{'-neb_sites'} = $neb;
1033 6         19 $data{'-beb_sites'} = $beb;
1034             }
1035             elsif (/^dN/i) {
1036 15 100       57 if (/K\=(\d+)/) {
    50          
1037 7         25 $data{'-num_site_classes'} = $1;
1038 7         24 while ( $_ = $self->_readline ) {
1039 12 100       235 unless ( $_ =~ /^\s+$/ ) {
1040 7         26 $self->_pushback($_);
1041 7         49 last;
1042             }
1043             }
1044 7 100       19 if (/^site class/) {
1045 1         4 $self->_readline;
1046 1         17 my $tmp = $self->_readline;
1047 1         21 my @p = $tmp =~ /(\d+\.\d{5})/g;
1048 1         23 $tmp = $self->_readline;
1049 1         25 my @b_w = $tmp =~ /(\d+\.\d{5})/g;
1050 1         3 $tmp = $self->_readline;
1051 1         21 my @f_w = $tmp =~ /(\d+\.\d{5})/g;
1052 1         2 my @w;
1053              
1054 1         3 foreach my $i ( 0 .. $#b_w ) {
1055 4         10 push @w,
1056             {
1057             q/background/ => $b_w[$i],
1058             q/foreground/ => $f_w[$i]
1059             };
1060             }
1061 1         7 $data{'-dnds_site_classes'} = {
1062             q/p/ => \@p,
1063             q/w/ => \@w
1064             };
1065             }
1066             else {
1067 6         15 my $tmp = $self->_readline;
1068 6         132 my @p = $tmp =~ /(\d+\.\d{5})/g;
1069 6         15 $tmp = $self->_readline;
1070 6         120 my @w = $tmp =~ /(\d+\.\d{5})/g;
1071 6         33 $data{'-dnds_site_classes'} = {
1072             'p' => \@p,
1073             'w' => \@w
1074             };
1075             }
1076             }
1077             elsif (/for each branch/) {
1078 8         30 my %branch_dnds = $self->_parse_branch_dnds;
1079 8 50       30 if ( !defined $data{'-trees'} ) {
1080 0         0 $self->warn(
1081             "No trees have been loaded, can't do anything\n");
1082 0         0 next;
1083             }
1084 8         17 my ($tree) = @{ $data{'-trees'} };
  8         16  
1085 8 50 33     65 if ( !$tree
      33        
1086             || !ref($tree)
1087             || !$tree->isa('Bio::Tree::Tree') )
1088             {
1089 0         0 $self->warn("no tree object already stored!\n");
1090 0         0 next;
1091             }
1092              
1093             # These need to be added to the Node/branches
1094 8         29 while ( my ( $k, $v ) = each %branch_dnds ) {
1095              
1096             # we can probably do better by caching at some point
1097 56         524 my @nodes;
1098 56         153 for my $id ( split( /\.\./, $k ) ) {
1099             my @nodes_L =
1100 241         41448 map { $tree->find_node( -id => $_ ) }
1101 112         146 @{ $idlookup->{$id} };
  112         217  
1102 112 100       34991 my $n =
1103             @nodes_L < 2
1104             ? shift(@nodes_L)
1105             : $tree->get_lca(@nodes_L);
1106 112 50       55598 if ( !$n ) {
1107 0         0 $self->warn(
1108             "no node could be found for $id (no lca?)");
1109             }
1110 112 100 66     245 unless ( $n->is_Leaf && $n->id ) {
1111 72         600 $n->id($id);
1112             }
1113 112         1012 push @nodes, $n;
1114             }
1115 56         109 my ( $parent, $child ) = @nodes;
1116 56         226 while ( my ( $kk, $vv ) = each %$v ) {
1117 504         4509 $child->add_tag_value( $kk, $vv );
1118             }
1119             }
1120             }
1121             }
1122             elsif (/^Parameters in beta:/) {
1123 0         0 $_ = $self->_readline; # need the next line
1124 0 0       0 if (/p\=\s+(\S+)\s+q\=\s+(\S+)/) {
1125 0         0 $data{'-shape_params'} = {
1126             'shape' => 'beta',
1127             'p' => $1,
1128             'q' => $2
1129             };
1130             }
1131             else {
1132 0         0 $self->warn("unparseable beta parameters: $_");
1133             }
1134             }
1135             elsif (/^Parameters in beta\&w\>1:/) {
1136              
1137             # Parameters in beta&w>1:
1138             # p0= 1.00000 p= 0.07642 q= 0.85550
1139             # (p1= 0.00000) w= 1.00000
1140 0         0 $_ = $self->_readline; # need the next line
1141 0         0 my ( $p0, $p, $q, $p1, $w );
1142 0 0       0 if (/p0\=\s+(\S+)\s+p\=\s+(\S+)\s+q\=\s+(\S+)/) {
1143 0         0 $p0 = $1;
1144 0         0 $p = $2;
1145 0         0 $q = $3;
1146             }
1147             else {
1148 0         0 $self->warn("unparseable beta parameters: $_");
1149             }
1150 0         0 $_ = $self->_readline; # need the next line
1151 0 0       0 if (/\(p1\=\s+(\S+)\)\s+w\=\s*(\S+)/) {
1152 0         0 $p1 = $1;
1153 0         0 $w = $2;
1154 0         0 $data{'-shape_params'} = {
1155             'shape' => 'beta',
1156             'p0' => $p0,
1157             'p' => $p,
1158             'q' => $q,
1159             'p1' => $p1,
1160             'w' => $w
1161             };
1162             }
1163             else {
1164 0         0 $self->warn("unparseable beta parameters: $_");
1165             }
1166             }
1167             elsif (/^alpha\s+\(gamma\)\s+\=\s+(\S+)/) {
1168 3         8 my $gamma = $1;
1169 3         9 $_ = $self->_readline;
1170 3         50 my ( @r, @f );
1171 3 50       15 if (s/^r\s+\(\s*\d+\)\:\s+//) {
1172 3         9 @r = split;
1173             }
1174 3         9 $_ = $self->_readline;
1175 3 50       56 if (s/^f\s*\:\s+//) {
1176 3         8 @f = split;
1177             }
1178 3         19 $data{'-shape_params'} = {
1179             'shape' => 'alpha',
1180             'gamma' => $gamma,
1181             'r' => \@r,
1182             'f' => \@f
1183             };
1184             }
1185             }
1186 9         188 return new Bio::Tools::Phylo::PAML::ModelResult(%data);
1187             }
1188              
1189             sub _parse_Pos_selected_sites {
1190 6     6   11 my $self = shift;
1191 6         11 my $okay = 0;
1192 6         26 my (%sites) = (
1193             'default' => [],
1194             'neb' => [],
1195             'beb' => []
1196             );
1197 6         12 my $type = 'default';
1198 6         16 while ( defined( $_ = $self->_readline ) ) {
1199 116 100 100     2345 next if ( /^\s+$/ || /^\s+Pr\(w\>1\)/ );
1200 80 100 66     212 if ( /^Time used/ || /^TREE/ ) {
1201 4         12 $self->_pushback($_);
1202 4         31 last;
1203             }
1204 76 100 100     522 if (/^Naive Empirical Bayes/i) {
    100 100        
    100 100        
    100          
    100          
    100          
1205 5         15 $type = 'neb';
1206             }
1207             elsif (/^Bayes Empirical Bayes/i) {
1208 2         6 $type = 'beb';
1209             }
1210             elsif (/^Positively selected sites/) {
1211 4         10 $okay = 1;
1212             }
1213             elsif ( $okay
1214             && /^\s+(\d+)\s+(\S+)\s+(\-?\d+(?:\.\d+)?)(\**)\s+(\-?\d+(?:\.\d+)?)\s+\+\-\s+(\-?\d+(?:\.\d+)?)/
1215             )
1216             {
1217 9         22 my $signif = $4;
1218 9 50       16 $signif = '' unless defined $signif;
1219 9         12 push @{ $sites{$type} }, [ $1, $2, $3, $signif, $5, $6 ];
  9         54  
1220             }
1221             elsif ( $okay
1222             && /^\s+(\d+)\s+(\S+)\s+(\-?\d*(?:.\d+))(\**)\s+(\-?\d+(?:\.\d+)?)/
1223             )
1224             {
1225 8         19 my $signif = $4;
1226 8 50       15 $signif = '' unless defined $signif;
1227 8         11 push @{ $sites{$type} }, [ $1, $2, $3, $signif, $5 ];
  8         45  
1228             }
1229             elsif ( $okay && /^\s+(\d+)\s+(\S)\s+([\d\.\-\+]+)(\**)/ ) {
1230 8         18 my $signif = $4;
1231 8 50       14 $signif = '' unless defined $signif;
1232 8         13 push @{ $sites{$type} }, [ $1, $2, $3, $signif ];
  8         33  
1233             }
1234             }
1235 6         65 return ( $sites{'default'}, $sites{'neb'}, $sites{'beb'} );
1236             }
1237              
1238             sub _parse_branch_dnds {
1239 10     10   21 my $self = shift;
1240 10         21 my ($okay) = (0);
1241 10         18 my %branch_dnds;
1242             my @header;
1243 10         24 while ( defined( $_ = $self->_readline ) ) {
1244 136 100       2593 next if (/^\s+$/);
1245 98 50 66     222 next unless ( $okay || /^\s+branch\s+t/ );
1246 98 100       310 if (/^\s+branch\s+(.+)/) {
    100          
1247 10         36 s/^\s+//;
1248 10         71 @header = split( /\s+/, $_ );
1249 10         30 $okay = 1;
1250             }
1251             elsif (/^\s*(\d+\.\.\d+)/) {
1252 78         146 my $branch = $1;
1253 78         178 s/^\s+//;
1254 78         106 my $i = 0;
1255              
1256             # fancyness just maps the header names like 't' or 'dN'
1257             # into the hash so we get at the end of the day
1258             # 't' => 0.067
1259             # 'dN'=> 0.001
1260 78         215 $branch_dnds{$branch} = { map { $header[ $i++ ] => $_ } split };
  702         1546  
1261             }
1262             else {
1263 10         30 $self->_pushback($_);
1264 10         111 last;
1265             }
1266             }
1267 10         63 return %branch_dnds;
1268             }
1269              
1270             #baseml stuff
1271             sub _parse_nt_freqs {
1272 2     2   6 my ($self) = @_;
1273 2         4 my ( $okay, $done, $header ) = ( 0, 0, 0 );
1274 2         4 my (@bases);
1275 2 50       3 my $numseqs = scalar @{ $self->{'_summary'}->{'seqs'} || [] };
  2         9  
1276 2         7 while ( defined( $_ = $self->_readline ) ) {
1277 28 50 33     522 if ( /^TREE/ || /^Distances/ ) { $self->_pushback($_); last }
  0         0  
  0         0  
1278 28 100       50 last if ($done);
1279 26 100 66     92 next if ( /^\s+$/ || /^\(Ambiguity/ );
1280 16 100       59 if (/^Frequencies\./) {
    50          
    100          
    100          
    100          
1281 2         5 $okay = 1;
1282             }
1283             elsif ( !$okay ) { # skip till we see 'Frequencies.
1284 0         0 next;
1285             }
1286             elsif ( !$header ) {
1287 2         8 s/^\s+//; # remove leading whitespace
1288 2         6 @bases = split; # get an array of the all the aa names
1289 2         4 $header = 1;
1290 2         5 $self->{'_summary'}->{'ntfreqs'} = {}; # reset/clear values
1291 2         4 next;
1292             }
1293             elsif (
1294             /^\#\s+constant\s+sites\:\s+
1295             (\d+)\s+ # constant sites
1296             \(\s*([\d\.]+)\s*\%\s*\)/ox
1297             )
1298             {
1299 2         11 $self->{'_summary'}->{'stats'}->{'constant_sites'} = $1;
1300 2         12 $self->{'_summary'}->{'stats'}->{'constant_sites_percentage'} = $2;
1301             }
1302             elsif (/^ln\s+Lmax\s+\(unconstrained\)\s+\=\s+(\S+)/ox) {
1303 2         5 $self->{'_summary'}->{'stats'}->{'loglikelihood'} = $1;
1304 2         5 $done = 1; # done for sure
1305             }
1306             else {
1307 8         21 my ( $seqname, @freqs ) = split;
1308 8         13 my $basect = 0;
1309 8         14 foreach my $f (@freqs) {
1310              
1311             # this will also store 'Average'
1312             $self->{'_summary'}->{'ntfreqs'}->{$seqname}
1313 32         72 ->{ $bases[ $basect++ ] } = $f;
1314             }
1315             }
1316             }
1317             }
1318              
1319             sub _parse_nt_dists {
1320 2     2   6 my ($self) = @_;
1321 2         5 my ( $okay, $seen, $done ) = ( 0, 0, 0 );
1322 2         4 my ( %matrix, @names );
1323 2 50       3 my $numseqs = scalar @{ $self->{'_summary'}->{'seqs'} || [] };
  2         9  
1324 2         5 my $type = '';
1325 2         5 while ( defined( $_ = $self->_readline ) ) {
1326 13 50       231 if (/^TREE/) { $self->_pushback($_); last; }
  0         0  
  0         0  
1327 13 100       19 last if $done;
1328 12 100       24 next if (/^This matrix is not used in later/);
1329 10 100       27 if (/^\s+$/) {
1330 2 50       5 last if ($seen);
1331 2         6 next;
1332             }
1333 8 100       20 if (/^Distances:(\S+)\s+\(([^\)]+)\)\s+\(alpha set at (\-?\d+\.\d+)\)/)
1334             {
1335 2         4 $okay = 1;
1336 2         5 $type = $1;
1337 2         4 next;
1338             }
1339 6         22 s/\s+$//g; # remove trailing space
1340 6 50       11 if ($okay) {
1341 6         18 my ( $seqname, $vl ) = split( /\s+/, $_, 2 );
1342 6         9 $seen = 1;
1343 6         9 my $i = 0;
1344 6 100       10 if ( defined $vl ) {
1345 4         20 while ( $vl =~ /(\-?\d+\.\d+)\s*\(\s*(\-?\d+\.\d+)\s*\)\s*/g ) {
1346 6         26 my ( $kappa, $alpha ) = ( $1, $2 );
1347             $matrix{$seqname}{ $names[$i] } =
1348 6         20 $matrix{ $names[$i] }{$seqname} = [ $kappa, $alpha ];
1349              
1350 6         18 $i++;
1351             }
1352 4 50       8 unless ($i) {
1353 0         0 $self->warn("no matches for $vl\n");
1354             }
1355             }
1356 6         11 push @names, $seqname;
1357 6         15 $matrix{$seqname}->{$seqname} = [ 0, 0 ];
1358             }
1359 6 100       19 $done = 1 if ( scalar @names == $numseqs );
1360             }
1361 2         21 my %dist;
1362 2         4 my $i = 0;
1363 2         5 my ( @kvalues, @avalues );
1364 2         4 foreach my $lname (@names) {
1365 6         7 my ( @arow, @krow );
1366 6         8 my $j = 0;
1367 6         9 foreach my $rname (@names) {
1368 18         23 my $v = $matrix{$lname}{$rname};
1369              
1370 18         25 push @krow, $v->[0]; # kappa values
1371 18         25 push @arow, $v->[1]; # alpha
1372 18         38 $dist{$lname}{$rname} = [ $i, $j++ ];
1373             }
1374 6         9 $i++;
1375 6         9 push @kvalues, \@krow;
1376 6         11 push @avalues, \@arow;
1377             }
1378             return (
1379             Bio::Matrix::PhylipDist->new(
1380             -program => $self->{'_summary'}->{'seqtype'},
1381             -matrix => \%dist,
1382             -names => \@names,
1383             -values => \@kvalues
1384             ),
1385             Bio::Matrix::PhylipDist->new(
1386 2         23 -program => $self->{'_summary'}->{'seqtype'},
1387             -matrix => \%dist,
1388             -names => \@names,
1389             -values => \@avalues
1390             )
1391             );
1392             }
1393              
1394             # BASEML
1395             sub _parse_rate_parametes {
1396 0     0   0 my $self = shift;
1397 0         0 my (%rate_parameters);
1398 0         0 while ( defined( $_ = $self->_readline ) ) {
1399 0 0       0 if (/^Rate\s+parameters:\s+/) {
    0          
    0          
    0          
    0          
1400 0         0 s/\s+$//;
1401 0         0 $rate_parameters{'rate_parameters'} = [ split( /\s+/, $_ ) ];
1402             }
1403             elsif (/^Base\s+frequencies:\s+/) {
1404 0         0 s/\s+$//;
1405 0         0 $rate_parameters{'base_frequencies'} = [ split( /\s+/, $_ ) ];
1406             }
1407             elsif (
1408             m/^Rate\s+matrix\s+Q,\s+Average\s+Ts\/Tv\s+(\([^\)+]+\))?\s*\=\s+
1409             (\-?\d+\.\d+)/x
1410             )
1411             {
1412 0         0 $rate_parameters{'average_TsTv'} = $1;
1413 0         0 while ( defined( $_ = $self->_readline ) ) {
1414              
1415             # short circuit
1416 0 0       0 last if (/^\s+$/);
1417 0 0       0 if (/^alpha/) {
1418 0         0 $self->_pushback($_);
1419 0         0 last;
1420             }
1421 0         0 s/^\s+//;
1422 0         0 s/\s+$//;
1423 0         0 push @{ $rate_parameters{'rate_matrix_Q'} }, [split];
  0         0  
1424             }
1425             }
1426             elsif (/^alpha\s+\(gamma,\s+K=\s*(\d+)\s*\)\s*\=\s*(\-?\d+\.\d+)/) {
1427 0         0 $rate_parameters{'K'} = $1;
1428 0         0 $rate_parameters{'alpha'} = $2;
1429             }
1430             elsif (s/^(r|f):\s+//) {
1431 0         0 my ($p) = $1;
1432 0         0 s/\s+$//;
1433 0         0 $rate_parameters{$p} = [split];
1434             }
1435             }
1436             }
1437              
1438             # RST parsing
1439             sub _parse_rst {
1440 20     20   49 my ($self) = @_;
1441 20 50 66     92 return unless $self->{'_dir'} && -d $self->{'_dir'} && -r $self->{'_dir'};
      66        
1442              
1443 1         11 my $rstfile = File::Spec->catfile( $self->{'_dir'}, $RSTFILENAME );
1444 1 50 33     22 return unless -e $rstfile && !-z $rstfile;
1445 1         7 my $rstio = Bio::Root::IO->new( -file => $rstfile );
1446              
1447             # define whatever data structures you need to store the data
1448             # key points are to reuse existing bioperl objs (like Bio::Seq)
1449             # where appropriate
1450 1         142 my ( @firstseq, @seqs, @trees, @per_site_prob );
1451 1         0 my $count;
1452 1         3 while ( defined( $_ = $rstio->_readline ) ) {
1453              
1454             # implement the parsing here
1455 616 100 66     11352 if (/^TREE\s+\#\s+(\d+)/) {
    100          
    100          
    50          
    100          
1456 1         3 while ( defined( $_ = $rstio->_readline ) ) {
1457 10 100       167 if (/tree\s+with\s+node\s+labels\s+for/) {
1458 1         3 my $tree = Bio::TreeIO->new(
1459             -noclose => 1,
1460             -fh => $rstio->_fh,
1461             -format => 'newick'
1462             )->next_tree;
1463              
1464             # cleanup leading/trailing whitespace
1465 1         9968 for my $n ( $tree->get_nodes ) {
1466 12         626 my $id = $n->id;
1467 12         63 $id =~ s/^\s+//;
1468 12         26 $id =~ s/\s+$//;
1469 12         24 $n->id($id);
1470 12 100       67 if ( defined( my $blen = $n->branch_length ) ) {
1471 11         56 $blen =~ s/^\s+//;
1472 11         16 $blen =~ s/\s+$//;
1473 11         19 $n->branch_length($blen);
1474             }
1475             }
1476 1         32 push @trees, $tree;
1477 1         4 last;
1478             }
1479             }
1480             }
1481             elsif (/^Prob\sof\sbest\scharacter\sat\seach\snode,\slisted\sby\ssite/)
1482             {
1483 1         3 $self->{'_rst'}->{'persite'} = [];
1484 1         4 while ( defined( $_ = $rstio->_readline ) ) {
1485 135 100 100     2888 next if ( /^Site/i || /^\s+$/ );
1486 131 100       606 if (s/^\s+(\d+)\s+(\d+)\s+([^:]+)\s*:\s*(.+)//) {
    50          
1487 130         366 my ( $sitenum, $freq, $extant, $ancestral ) =
1488             ( $1, $2, $3, $4 );
1489 130         167 my ( @anc_site, @extant_site );
1490 130         267 @extant_site = {};
1491 130         447 while ( $extant =~ s/^([A-Z\-]{3})\s+\(([A-Z*])\)\s+//g ) {
1492 910         4065 push @extant_site, { 'codon' => $1, 'aa' => $2 };
1493             }
1494 130         476 while (
1495             $ancestral =~ s/^([A-Z\-]{3})\s+([A-Z*])\s+ # codon AA
1496             (\S+)\s+ # Prob
1497             \(([A-Z*])\s+(\S+)\)\s*//xg # AA Prob
1498             )
1499             {
1500 650         3934 push @anc_site,
1501             {
1502             'codon' => $1,
1503             'aa' => $2,
1504             'prob' => $3,
1505             'Yang95_aa' => $4,
1506             'Yang95_aa_prob' => $5
1507             };
1508             }
1509              
1510             # saving persite
1511 130         587 $self->{'_rst'}->{'persite'}->[$sitenum] =
1512             [ @extant_site, @anc_site ];
1513             }
1514             elsif (/^Summary\sof\schanges\salong\sbranches\./) {
1515 1         4 last;
1516             }
1517             }
1518             }
1519             elsif (/^Check\sroot\sfor\sdirections\sof\schange\./
1520             || /^Summary\sof\schanges\salong\sbranches\./ )
1521             {
1522 1         3 my ( @branches, @branch2node, $branch, $node );
1523 1         3 my $tree = $trees[-1];
1524 1 50       4 if ( !$tree ) {
1525 0         0 $self->warn("No tree built before parsing Branch changes\n");
1526 0         0 last;
1527             }
1528             my @nodes = (
1529 12         16 map { $_->[0] }
1530 30         47 sort { $a->[1] <=> $b->[1] }
1531 1         6 map { [ $_, $_->id =~ /^(\d+)\_?/ ] } $tree->get_nodes
  12         377  
1532             );
1533 1         9 unshift @nodes,
1534             undef; # fake first node so that index will match nodeid
1535 1         5 while ( defined( $_ = $rstio->_readline ) ) {
1536 93 100       2024 next if /^\s+$/;
1537 57 100       229 if (m/^List\sof\sextant\sand\sreconstructed\ssequences/) {
    100          
    50          
1538 1         4 $rstio->_pushback($_);
1539 1         12 last;
1540             }
1541             elsif (/^Branch\s+(\d+):\s+(\d+)\.\.(\d+)\s+/) {
1542 11         14 my ( $left, $right );
1543 11         25 ( $branch, $left, $right ) = ( $1, $2, $3 );
1544 11         20 ($node) = $nodes[$right];
1545 11 50       16 if ( !$node ) {
1546 0         0 $self->warn(
1547             "cannot find $right in $tree ($branch $left..$right)\n"
1548             );
1549 0         0 last;
1550             }
1551 11 50       35 if (/\(n=\s*(\S+)\s+s=\s*(\S+)\)/) {
1552 11         29 $node->add_tag_value( 'n', $1 );
1553 11         120 $node->add_tag_value( 's', $2 );
1554             }
1555 11         109 $branch2node[$branch] = $right;
1556             }
1557             elsif (
1558             /^\s+(\d+)\s+([A-Z*])\s+(\S+)\s+\-\>\s+([A-Z*])\s+(\S+)?/)
1559             {
1560 45         115 my ( $site, $anc, $aprob, $derived, $dprob ) =
1561             ( $1, $2, $3, $4, $5 );
1562 45 50       68 if ( !$node ) {
1563 0         0 $self->warn("no branch line was previously parsed!");
1564 0         0 next;
1565             }
1566 45         143 my %c = (
1567             'site' => $site,
1568             'anc_aa' => $anc,
1569             'anc_prob' => $aprob,
1570             'derived_aa' => $derived,
1571             );
1572 45 100       81 $c{'derived_prob'} = $dprob if defined $dprob;
1573 45         94 $node->add_tag_value( 'changes', \%c );
1574             }
1575             }
1576             }
1577             elsif (
1578             /^Overall\s+accuracy\s+of\s+the\s+(\d+)\s+ancestral\s+sequences:/)
1579             {
1580 0         0 my $line = $rstio->_readline;
1581 0         0 $line =~ s/^\s+//;
1582 0         0 $line =~ s/\s+$//;
1583 0         0 my @overall_site = split( /\s+/, $line );
1584              
1585             # skip next 2 lines, want the third
1586 0         0 for ( 1 .. 3 ) {
1587 0         0 $line = $rstio->_readline;
1588             }
1589 0         0 $line =~ s/^\s+//;
1590 0         0 $line =~ s/\s+$//;
1591 0         0 my @overall_seq = split( /\s+/, $line );
1592 0 0 0     0 if ( @overall_seq != @overall_site
1593             || @overall_seq != @seqs )
1594             {
1595 0         0 $self->warn(
1596             "out of sync somehow seqs, site scores don't match\n");
1597 0         0 $self->warn("@seqs @overall_seq @overall_site\n");
1598             }
1599 0         0 for (@seqs) {
1600 0         0 $_->description(
1601             sprintf(
1602             "overall_accuracy_site=%s overall_accuracy_seq=%s",
1603             shift @overall_site,
1604             shift @overall_seq
1605             )
1606             );
1607             }
1608             }
1609             elsif (m/^List of extant and reconstructed sequences/o) {
1610 3         6 my $seqcount = 0;
1611 3         10 while ( defined( $_ = $rstio->_readline ) ) {
1612 311 100       9216 last if (/^Overall accuracy of the/);
1613 309 100       654 if (/^\s+$/) {
1614 61 50 33     100 last if $seqcount && $seqcount == @seqs;
1615 61         108 next;
1616             }
1617 248 50       579 if (/^\s*(\d+)\s+(\d+)\s+$/) { $seqcount = $1; next }
  0         0  
  0         0  
1618              
1619             # runmode = (0)
1620             # this should in fact be packed into a Bio::SimpleAlign object
1621             # instead of an array but we'll stay with this for now
1622 248 100       500 if (/^node/) {
1623 20         79 my ( $name, $num, $seqstr ) = split( /\s+/, $_, 3 );
1624 20         38 $name .= $num;
1625 20         685 $seqstr =~ s/\s+//g; # remove whitespace
1626 20 100       41 unless (@firstseq) {
1627 1         48 @firstseq = split( //, $seqstr );
1628 1         13 push @seqs,
1629             Bio::LocatableSeq->new(
1630             -display_id => $name,
1631             -seq => $seqstr
1632             );
1633             }
1634             else {
1635 19         26 my $i = 0;
1636 19         23 my $v;
1637 19         60 while ( ( $v = index( $seqstr, '.', $i ) ) >= $i ) {
1638              
1639             # replace the '.' with the correct seq from the
1640 0         0 substr( $seqstr, $v, 1, $firstseq[$v] );
1641 0         0 $i = $v;
1642             }
1643 19         84 $self->debug("adding seq $seqstr\n");
1644 19         371 push @seqs,
1645             Bio::LocatableSeq->new(
1646             -display_id => $name,
1647             -seq => $seqstr
1648             );
1649             }
1650             }
1651             }
1652 3         27 $self->{'_rst'}->{'rctrted_seqs'} = \@seqs;
1653             }
1654             else {
1655             }
1656             }
1657 1         16 $self->{'_rst'}->{'trees'} = \@trees;
1658 1         26 return;
1659             }
1660              
1661             1;
1662              
1663             __END__