1=head1 NAME
2
3Bio::Tools::Run::Phylo::Hyphy::BatchFile - Wrapper for custom execution of Hyphy batch files
4
5=head1 SYNOPSIS
6
7my $aln = Bio::Align::AlignI->new();
8my $treeio = Bio::TreeIO->new(-format => "nexus", -file => "$tree_file");
9my $tree = $treeio->next_tree();
10my $bf_exec = Bio::Tools::Run::Phylo::Hyphy::BatchFile->new(-params => {'bf' => "hyphybatchfile.bf", 'order' => ["Universal", "Custom", $aln, "001001", $tree]});
11$bf_exec->set_parameter('3', "012012");
12my ($rc,$parser) = $bf_exec->run();
13
14=head1 DESCRIPTION
15
16This module creates a generic interface to processing of HBL files in HyPhy ([Hy]pothesis
17Testing Using [Phy]logenies), a package by Sergei Kosakowsky Pond,
18Spencer V. Muse, Simon D.W. Frost and Art Poon.  See
19http://www.hyphy.org for more information.
20
21Instances of this module require only a link to the batch file and an ordered list of
22parameters, as described in the HyPhy documentation "SelectionAnalyses.pdf."
23
24
25=head1 FEEDBACK
26
27=head2 Mailing Lists
28
29User feedback is an integral part of the evolution of this and other
30Bioperl modules. Send your comments and suggestions preferably to
31the Bioperl mailing list.  Your participation is much appreciated.
32
33  bioperl-l@bioperl.org                  - General discussion
34  http://bioperl.org/wiki/Mailing_lists  - About the mailing lists
35
36=head2 Support
37
38Please direct usage questions or support issues to the mailing list:
39
40I<bioperl-l@bioperl.org>
41
42rather than to the module maintainer directly. Many experienced and
43reponsive experts will be able look at the problem and quickly
44address it. Please include a thorough description of the problem
45with code and data examples if at all possible.
46
47=head2 Reporting Bugs
48
49Report bugs to the Bioperl bug tracking system to help us keep track
50of the bugs and their resolution. Bug reports can be submitted via the
51web:
52
53  http://redmine.open-bio.org/projects/bioperl/
54
55=head1 AUTHOR - Daisie Huang
56
57Email daisieh@zoology.ubc.ca
58
59=head1 CONTRIBUTORS
60
61Additional contributors names and emails here
62
63=cut
64
65package Bio::Tools::Run::Phylo::Hyphy::BatchFile;
66use strict;
67use Bio::Root::Root;
68use Bio::AlignIO;
69use Bio::TreeIO;
70use Bio::Tools::Run::Phylo::Hyphy::Base;
71use Bio::Tools::Run::WrapperBase;
72
73use base qw(Bio::Root::Root Bio::Tools::Run::Phylo::Hyphy::Base);
74
75=head2 valid_values
76
77 Title   : valid_values
78 Usage   : $factory->valid_values()
79 Function: returns the possible parameters
80 Returns:  an array holding all possible parameters. The default
81values are always the first one listed.  These descriptions are
82essentially lifted from the python wrapper or provided by the author.
83 Args    : None
84
85=cut
86
87
88sub valid_values {
89    return (
90        {'geneticCode' => [ "Universal","VertebratemtDNA","YeastmtDNA","Mold/ProtozoanmtDNA",
91                         "InvertebratemtDNA","CiliateNuclear","EchinodermmtDNA","EuplotidNuclear",
92                         "Alt.YeastNuclear","AscidianmtDNA","FlatwormmtDNA","BlepharismaNuclear"]},
93        {'tempalnfile' => undef }, # aln file goes here
94        {'temptreefile' => undef }, # tree file goes here
95    );
96}
97
98=head2 new
99
100 Title   : new
101 Usage   : my $obj = Bio::Tools::Run::Phylo::Hyphy::BatchFile->new();
102 Function: Builds a new Bio::Tools::Run::Phylo::Hyphy::BatchFile object
103 Returns : Bio::Tools::Run::Phylo::Hyphy::BatchFile
104 Args    : -alignment => the Bio::Align::AlignI object
105           -save_tempfiles => boolean to save the generated tempfiles and
106                              NOT cleanup after onesself (default FALSE)
107           -tree => the Bio::Tree::TreeI object
108           -params => a hashref of parameters (all passed to set_parameter)
109                      this hashref should include   'bf' => custombatchfile.bf
110                                                    'order' => [array of ordered parameters]
111           -executable => where the hyphy executable resides
112
113See also: L<Bio::Tree::TreeI>, L<Bio::Align::AlignI>
114
115=cut
116
117sub new {
118    my($class,@args) = @_;
119
120    my $self = $class->SUPER::new(@args);
121    my ($aln, $tree, $st, $params, $exe) = $self->_rearrange([qw(ALIGNMENT TREE SAVE_TEMPFILES PARAMS EXECUTABLE)], @args);
122    defined $aln && $self->alignment($aln);
123    defined $tree && $self->tree($tree);
124    defined $st  && $self->save_tempfiles($st);
125    defined $exe && $self->executable($exe);
126
127    $self->set_default_parameters();
128    if( defined $params ) {
129        if( ref($params) !~ /HASH/i ) {
130            $self->warn("Must provide a valid hash ref for parameter -FLAGS");
131        } else {
132            map { $self->set_parameter($_, $$params{$_}) } keys %$params;
133        }
134    }
135    return $self;
136}
137
138=head2 update_ordered_parameters
139
140 Title   : update_ordered_parameters
141 Usage   : $BatchFile->update_ordered_parameters();
142 Function: updates all of the parameters needed for the ordered input redirect in HBL.
143 Returns : nothing
144 Args    : none
145
146=cut
147
148sub update_ordered_parameters {
149    my ($self) = @_;
150    unless (defined ($self->{'_params'}{'order'})) {
151        $self->throw("No ordered parameters for HYPHY were defined.");
152    }
153    for (my $i=0; $i< scalar @{$self->{'_params'}{'order'}}; $i++) {
154        my $item = @{$self->{'_params'}{'order'}}[$i];
155        #FIXME: update_ordered_parameters should be more flexible. It should be able to tell what type of object $item is and, if necessary, create a temp file for it.
156        if (ref ($item) =~ m/Bio::SimpleAlign/) {
157            $item = $self->{'_params'}{'tempalnfile'};
158        } elsif (ref ($item) =~ m/Bio::Tree::Tree/) {
159            $item = $self->{'_params'}{'temptreefile'};
160        }
161        $self->{'_orderedparams'}[$i] = {$i, $item};
162    }
163    $self->SUPER::update_ordered_parameters();
164}
165
166=head2 run
167
168 Title   : run
169 Usage   : my ($rc,$results) = $BatchFile->run();
170 Function: run the Hyphy analysis using the specified batchfile and its ordered parameters
171 Returns : Return code, Hash
172 Args    : none
173
174
175=cut
176
177sub run {
178    my $self = shift;
179    my ($rc, $results) = $self->SUPER::run();
180    my $outfile = $self->outfile_name();
181    open(OUTFILE, ">", $outfile) or $self->throw("cannot open $outfile for writing");
182    print OUTFILE $results;
183    close(OUTFILE);
184    return ($rc,$results);
185}
186
187
188=head2 create_wrapper
189
190 Title   : create_wrapper
191 Usage   : $self->create_wrapper
192 Function: Creates the wrapper file for the batchfile specified in the hash, saves it to the hash as '_wrapper'.
193 Returns : nothing
194 Args    : none
195
196
197=cut
198
199sub create_wrapper {
200    my $self = shift;
201    my $batchfile = $self->batchfile;
202    unless (defined($batchfile)) {
203        $self->throw("No batchfile specified, couldn't create wrapper.");
204    }
205
206    unless (-f $batchfile) {
207        # check to see if maybe this batchfile is a template batchfile
208        my $new_bf = $self->io->catfile($self->hyphy_lib_dir,"TemplateBatchFiles",$batchfile);
209        $new_bf =~ s/\"//g;
210        if (-f $new_bf) {
211            $self->batchfile($new_bf);
212        } else {
213            $self->throw ("Specified batchfile $batchfile not found.");
214            return;
215        }
216    }
217    $self->SUPER::create_wrapper('"' . $self->batchfile . '"');
218}
219
220=head2 set_parameter
221
222Title   :  set_parameter
223Usage   :  $hyphy->set_parameter($param,$val);
224Function:  Sets the named parameter $param to $val if it is a non-numeric parameter
225           If $param is a number, sets the corresponding value of the ordered redirect array (starts from 1).
226Returns :  boolean if set was successful
227Args    :  $param => name of the parameter
228           $value => value to set the parameter to
229
230=cut
231
232
233sub set_parameter {
234    my ($self,$param,$value) = @_;
235    if ($param =~ /\d+/) {
236        $self->{'_params'}{'order'}[$param-1] = $value;
237    } else {
238        $self->{'_params'}{$param} = $value;
239    }
240    return 1;
241}
242
243=head2 batchfile
244
245Title   :  batchfile
246Usage   :  $hyphy->batchfile($bf_name);
247Function:  Gets/sets the batchfile that is run by $hyphy.
248Returns :  The batchfile path.
249Args    :  $bf_name => path of new batchfile
250
251=cut
252
253sub batchfile {
254    my ($self,$bf) = @_;
255    if (defined $bf) {
256        $self->set_parameter('bf', $bf);
257    }
258
259    if ($self->{'_params'}{'bf'}) {
260        return $self->{'_params'}{'bf'};
261    } else {
262        $self->warn ("Batchfile was requested but no batchfile was found.");
263    }
264    return;
265}
266
267=head2 make_batchfile_with_contents
268
269Title   :  make_batchfile_with_contents
270Usage   :  $hyphy->make_batchfile_with_contents($bf_string);
271Function:  Creates a temporary file with the specified string of contents for the batchfile.
272Returns :  The batchfile path.
273Args    :  $bf_string => contents for the batchfile
274
275=cut
276
277sub make_batchfile_with_contents {
278    my ($self,$bf_string) = @_;
279    my $temp_bf = $self->io->catfile($self->tempdir,"temp.bf");
280    open (BF, ">", $temp_bf) or $self->throw("cannot open $temp_bf for writing");
281    print BF "$bf_string\n";
282    close BF;
283    return $self->batchfile($temp_bf);
284}
285
286
287=head2 set_default_parameters
288
289 Title   : set_default_parameters
290 Usage   : $BatchFile->set_default_parameters(0);
291 Function: (Re)set the default parameters from the defaults
292           (the first value in each array in the
293            valid_values)
294 Returns : none
295 Args    : boolean: keep existing parameter values
296
297
298=cut
299
300sub set_default_parameters {
301    my ($self,$keepold) = @_;
302    unless (defined $keepold) {
303        $keepold = 0;
304    }
305    my @validvals = $self->valid_values();
306    for (my $i=0; $i< scalar (@validvals); $i++) {
307        my $elem = $validvals[$i];
308        keys %$elem; #reset hash iterator
309        my ($param,$val) = each %$elem;
310        # skip if we want to keep old values and it is already set
311        if (ref($val)=~/ARRAY/i ) {
312            $self->{'_orderedparams'}[$i] = {$param, $val->[0]};
313        } else {
314            $self->{'_orderedparams'}[$i] = {$param, $val};
315        }
316        #FIXME: for alignment and treefile, this should default to the ones in params.
317    }
318}
319
3201;
321