File Coverage

blib/lib/Bio/MUST/Apps/TwoScalp/Seq2Seq.pm
Criterion Covered Total %
statement 48 110 43.6
branch 0 22 0.0
condition 0 6 0.0
subroutine 16 20 80.0
pod 0 2 0.0
total 64 160 40.0


line stmt bran cond sub pod time code
1             package Bio::MUST::Apps::TwoScalp::Seq2Seq;
2             # ABSTRACT: internal class for two-scalp tool
3             $Bio::MUST::Apps::TwoScalp::Seq2Seq::VERSION = '0.201810';
4 1     1   9 use Moose;
  1         4  
  1         9  
5 1     1   7486 use namespace::autoclean;
  1         3  
  1         12  
6              
7 1     1   99 use autodie;
  1         3  
  1         10  
8 1     1   5743 use feature qw(say);
  1         3  
  1         120  
9              
10 1     1   7 use Smart::Comments -ENV;
  1         3  
  1         12  
11              
12 1     1   2066 use List::AllUtils qw(part);
  1         3  
  1         72  
13              
14 1     1   8 use Bio::MUST::Core;
  1         3  
  1         31  
15 1     1   6 use Bio::MUST::Core::Constants qw(:gaps);
  1         4  
  1         177  
16 1     1   7 use Bio::MUST::Core::Utils qw(secure_outfile);
  1         3  
  1         49  
17 1     1   662 use Bio::MUST::Drivers;
  1         2210674  
  1         51  
18 1     1   10 use aliased 'Bio::MUST::Core::Ali';
  1         2  
  1         7  
19 1     1   220 use aliased 'Bio::MUST::Core::Ali::Temporary';
  1         3  
  1         5  
20 1     1   192 use aliased 'Bio::MUST::Core::Seq';
  1         3  
  1         5  
21 1     1   185 use aliased 'Bio::MUST::Core::SeqId';
  1         2  
  1         4  
22 1     1   190 use aliased 'Bio::MUST::Core::SeqMask';
  1         3  
  1         4  
23 1     1   205 use aliased 'Bio::MUST::Apps::SlaveAligner::Local';
  1         2  
  1         3  
24              
25              
26             has 'coverage_mul' => (
27             is => 'ro',
28             isa => 'Num',
29             default => 1.1,
30             );
31              
32              
33             has 'single_hsp' => (
34             is => 'ro',
35             isa => 'Bool',
36             default => 0,
37             );
38              
39              
40             has 'out_suffix' => (
41             is => 'ro',
42             isa => 'Maybe[Str]',
43             default => '-ts',
44             );
45              
46              
47             has 'ali' => (
48             is => 'ro',
49             isa => 'Bio::MUST::Core::Ali',
50             required => 1,
51             coerce => 1,
52             );
53              
54              
55             has 'lookup' => (
56             is => 'ro',
57             isa => 'Bio::MUST::Core::IdList',
58             init_arg => undef,
59             writer => '_set_lookup',
60             );
61              
62              
63             has 'new_ali' => (
64             is => 'ro',
65             isa => 'Bio::MUST::Core::Ali',
66             init_arg => undef,
67             writer => '_set_new_ali',
68             );
69              
70              
71             has 'integrator' => (
72             is => 'ro',
73             isa => 'Bio::MUST::Apps::SlaveAligner::Local',
74             init_arg => undef,
75             writer => '_set_integrator',
76             );
77              
78              
79             has 'blastdb' => (
80             is => 'ro',
81             isa => 'Bio::MUST::Drivers::Blast::Database::Temporary',
82             init_arg => undef,
83             writer => '_set_blastdb',
84             );
85              
86              
87             has 'query_seqs' => (
88             is => 'ro',
89             isa => 'Bio::MUST::Core::Ali::Temporary',
90             init_arg => undef,
91             writer => '_set_query_seqs',
92             );
93              
94              
95             sub _align_seqs {
96 0     0     my $self = shift;
97              
98 0           my $args->{-outfmt} = 5;
99 0           $args->{-max_target_seqs} = 5;
100              
101 0           my $blastdb = $self->blastdb;
102 0           my $query_seqs = $self->query_seqs;
103 0           my $parser = $blastdb->blast($query_seqs, $args);
104             #### [S2S] XML BLASTP/N: $parser->filename
105              
106 0           my $bo = $parser->blast_output;
107 0 0         return unless $bo;
108              
109 0 0         my $sort_method = $self->single_hsp ? 'score' : 'hit_start';
110              
111             QUERY:
112 0           for my $query ( $bo->all_iterations ) {
113              
114 0           my $query_id = $query_seqs->long_id_for( $query->query_def );
115             ##### [S2S] Aligning: $query_id
116              
117 0           my @templates;
118             my @template_seqs;
119 0           my $best_coverage = 0;
120              
121             TEMPLATE:
122 0           for my $template ( $query->all_hits ) {
123              
124             # compute query coverage by template HSPs
125 0           my $mask = SeqMask->empty_mask( $query->query_len );
126             $mask->mark_block( $_->query_start, $_->query_end )
127 0           for $template->all_hsps;
128 0           my $coverage = $mask->coverage;
129              
130 0 0         last TEMPLATE if $coverage
131             < $best_coverage * $self->coverage_mul;
132 0           $best_coverage = $coverage;
133              
134             # fetch template full_id
135 0           my $template_id = SeqId->new(
136             full_id => $blastdb->long_id_for( $template->def )
137             );
138              
139             ###### [S2S] template: $template_id->full_id
140             ###### [S2S] coverage: $coverage
141              
142             # fetch and cache aligned template seq from Ali
143 0           push @templates, $template;
144 0           push @template_seqs, $self->ali->get_seq(
145             $self->lookup->index_for( $template_id->full_id )
146             );
147             }
148              
149 0 0         unless (@templates) {
150             ##### [S2S] skipped alignment due to lack of suitable template
151 0           next QUERY;
152             }
153              
154 0 0         @templates = ( $templates[-1] ) if $self->single_hsp;
155              
156             TEMPLATE:
157 0           for my $template (@templates) {
158              
159             # use each template in turn for BLAST alignment
160 0           my $template_seq = shift @template_seqs;
161 0 0         last TEMPLATE unless $template_seq;
162              
163             # sort HSPs by descending start coordinate on template or by
164             # descending score depending on --single-hsp option
165             my @hsps = sort {
166 0           $b->$sort_method <=> $a->$sort_method
  0            
167             } $template->all_hsps;
168              
169             HSP:
170 0           for my $hsp (@hsps) {
171              
172             # build HSP id from query id (and template/HSP ranks)
173 0           my $hsp_id = $query_seqs->long_id_for( $query->query_def );
174 0 0         $hsp_id .= '.H' . $template->num . '.' . $hsp->num
175             unless $self->single_hsp;
176 0           $hsp_id .= '#NEW#';
177              
178             # build HSP seq from BLASTX report
179 0           (my $hsp_seq = $hsp->qseq) =~ s{\*}{$FRAMESHIFT}xmsg;
180 0           my $new_seq = Seq->new(
181             seq_id => $hsp_id,
182             seq => $hsp_seq
183             );
184              
185             # fetch aligned template seq from HSP (= subject)
186 0           my $subject_seq = Seq->new(
187             seq_id => $template_seq->seq_id,
188             seq => $hsp->hseq
189             );
190              
191             # reverse complement seqs if template on reverse in BLASTN
192 0 0 0       if ($query_seqs->type eq 'nucl' && $blastdb->type eq 'nucl'
      0        
193             && $hsp->hit_strand == -1) {
194 0           $new_seq = $new_seq->reverse_complemented_seq;
195 0           $subject_seq = $subject_seq->reverse_complemented_seq;
196             }
197              
198             # align new_seq on template_seq using subject_seq as a guide
199             $self->new_ali->add_seq(
200 0           $self->integrator->align(
201             new_seq => $new_seq,
202             subject => $subject_seq,
203             template => $template_seq,
204             start => $hsp->hit_start,
205             )
206             );
207              
208 0 0         last HSP if $self->single_hsp;
209             }
210             }
211             }
212              
213 0           return;
214             }
215              
216              
217             sub display { ## no critic (RequireArgUnpacking)
218 0     0 0   return join "\n--- ", q{}, @_
219             }
220              
221              
222             sub BUILD {
223 0     0 0   my $self = shift;
224              
225 0           my $ali = $self->ali;
226             #### [ALI] #seqs: $ali->count_seqs
227 0 0         unless ($ali->count_seqs) {
228             #### [ALI] empty file; skipping!
229 0           return;
230             }
231              
232             # Note: this class maintains DRY through a single BUILD
233             # hence the writers instead of the usual builders
234              
235 0           $self->_set_lookup( $ali->new_lookup );
236              
237             # TODO: fix bug with 'aligned' seqs only composed of trailing spaces
238             my ($unaligned_seqs, $aligned_seqs)
239 0 0   0     = part { $_->is_aligned ? 1 : 0 } $ali->all_seqs;
  0            
240             #### [S2S] seqs to align: display( map { $_->full_id } @{$unaligned_seqs} )
241              
242 0           $self->_set_blastdb( Bio::MUST::Drivers::Blast::Database::Temporary->new(
243             seqs => $aligned_seqs )
244             );
245 0           $self->_set_query_seqs( Temporary->new( seqs => $unaligned_seqs ) );
246              
247 0           my $new_ali = Ali->new( seqs => $aligned_seqs );
248 0           $self->_set_new_ali($new_ali);
249              
250 0           my $integrator = Local->new( ali => $new_ali );
251 0           $self->_set_integrator($integrator);
252              
253 0           $self->_align_seqs;
254              
255             #### [S2S] Making delayed indels...
256 0           $integrator->make_indels;
257              
258             #### [S2S] Writing updated file...
259 0           my $outfile = secure_outfile($ali->filename, $self->out_suffix);
260 0           $new_ali->store($outfile);
261              
262 0           return;
263             }
264              
265              
266             __PACKAGE__->meta->make_immutable;
267             1;
268              
269             __END__
270              
271             =pod
272              
273             =head1 NAME
274              
275             Bio::MUST::Apps::TwoScalp::Seq2Seq - internal class for two-scalp tool
276              
277             =head1 VERSION
278              
279             version 0.201810
280              
281             =head1 AUTHOR
282              
283             Denis BAURAIN <denis.baurain@uliege.be>
284              
285             =head1 COPYRIGHT AND LICENSE
286              
287             This software is copyright (c) 2013 by University of Liege / Unit of Eukaryotic Phylogenomics / Denis BAURAIN.
288              
289             This is free software; you can redistribute it and/or modify it under
290             the same terms as the Perl 5 programming language system itself.
291              
292             =cut