File Coverage

Bio/SeqIO/scf.pm
Criterion Covered Total %
statement 372 518 71.8
branch 77 142 54.2
condition 5 14 35.7
subroutine 26 37 70.2
pod 5 6 83.3
total 485 717 67.6


line stmt bran cond sub pod time code
1             #
2             # Copyright (c) 1997-2001 bioperl, Chad Matsalla. All Rights Reserved.
3             # This module is free software; you can redistribute it and/or
4             # modify it under the same terms as Perl itself.
5             #
6             # Copyright Chad Matsalla
7             #
8             # You may distribute this module under the same terms as perl itself
9              
10             # POD documentation - main docs before the code
11              
12             =head1 NAME
13              
14             Bio::SeqIO::scf - .scf file input/output stream
15              
16             =head1 SYNOPSIS
17              
18             Do not use this module directly. Use it via the Bio::SeqIO class, see
19             L for more information.
20              
21             =head1 DESCRIPTION
22              
23             This object can transform .scf files to and from Bio::Seq::SequenceTrace
24             objects. Mechanisms are present to retrieve trace data from scf
25             files.
26              
27             =head1 FEEDBACK
28              
29             =head2 Mailing Lists
30              
31             User feedback is an integral part of the evolution of this and other
32             Bioperl modules. Send your comments and suggestions preferably to one
33             of the Bioperl mailing lists. Your participation is much appreciated.
34              
35             bioperl-l@bioperl.org - General discussion
36             http://bioperl.org/wiki/Mailing_lists - About the mailing lists
37              
38             =head2 Support
39              
40             Please direct usage questions or support issues to the mailing list:
41              
42             I
43              
44             rather than to the module maintainer directly. Many experienced and
45             reponsive experts will be able look at the problem and quickly
46             address it. Please include a thorough description of the problem
47             with code and data examples if at all possible.
48              
49             =head2 Reporting Bugs
50              
51             Report bugs to the Bioperl bug tracking system to help us keep track
52             the bugs and their resolution. Bug reports can be submitted via
53             the web:
54              
55             https://github.com/bioperl/bioperl-live/issues
56              
57             =head1 AUTHOR Chad Matsalla
58              
59             Chad Matsalla
60             bioinformatics@dieselwurks.com
61              
62             =head1 CONTRIBUTORS
63              
64             Jason Stajich, jason@bioperl.org
65             Tony Cox, avc@sanger.ac.uk
66             Heikki Lehvaslaiho, heikki-at-bioperl-dot-org
67             Nancy Hansen, nhansen at mail.nih.gov
68              
69             =head1 APPENDIX
70              
71             The rest of the documentation details each of the object
72             methods. Internal methods are usually preceded with a _
73              
74             =cut
75              
76             # Let the code begin...
77              
78             package Bio::SeqIO::scf;
79 1     1   606 use vars qw($DEFAULT_QUALITY);
  1         2  
  1         43  
80 1     1   4 use strict;
  1         2  
  1         19  
81 1     1   208 use Bio::Seq::SeqFactory;
  1         3  
  1         31  
82 1     1   347 use Bio::Seq::SequenceTrace;
  1         4  
  1         57  
83 1     1   379 use Bio::Annotation::Comment;
  1         3  
  1         24  
84 1     1   6 use Dumpvalue;
  1         2  
  1         35  
85              
86             my $dumper = Dumpvalue->new();
87             $dumper->veryCompact(1);
88              
89             BEGIN {
90 1     1   16 $DEFAULT_QUALITY= 10;
91             }
92              
93 1     1   6 use base qw(Bio::SeqIO);
  1         1  
  1         309  
94              
95             sub _initialize {
96 25     25   78 my($self,@args) = @_;
97 25         106 $self->SUPER::_initialize(@args);
98 25 50       133 if( ! defined $self->sequence_factory ) {
99 25         122 $self->sequence_factory(Bio::Seq::SeqFactory->new
100             (-verbose => $self->verbose(),
101             -type => 'Bio::Seq::Quality'));
102             }
103 25         87 binmode $self->_fh; # for the Win32/Mac crowds
104             }
105              
106             =head2 next_seq()
107              
108             Title : next_seq()
109             Usage : $scf = $stream->next_seq()
110             Function: returns the next scf sequence in the stream
111             Returns : a Bio::Seq::SequenceTrace object
112             Args : NONE
113             Notes : Fills the interface specification for SeqIO.
114             The SCF specification does not provide for having more then
115             one sequence in a given scf. So once the filehandle has been open
116             and passed to SeqIO do not expect to run this function more then
117             once on a given scf unless you embraced and extended the SCF
118             standard. SCF comments are accessible through the Bio::SeqI
119             interface method annotation().
120              
121             =cut
122              
123             #'
124             sub next_seq {
125 15     15 1 100 my ($self) = @_;
126 15         58 my ($seq, $seqc, $fh, $buffer, $offset, $length, $read_bytes, @read,
127             %names);
128             # set up a filehandle to read in the scf
129 15 50       56 return if $self->{_readfile};
130 15         54 $fh = $self->_fh();
131 15 50       45 unless ($fh) { # simulate the <> function
132 0 0 0     0 if ( !fileno(ARGV) or eof(ARGV) ) {
133 0 0       0 return unless my $ARGV = shift;
134 0 0       0 open(ARGV,$ARGV) or
135             $self->throw("Could not open $ARGV for SCF stream reading $!");
136             }
137 0         0 $fh = \*ARGV;
138             }
139 15 50       307 return unless read $fh, $buffer, 128; # no exception; probably end of file
140             # now, the master data structure will be the creator
141 15         36 my $creator;
142             # he first thing to do is parse the header. This is common
143             # among all versions of scf.
144             # the rest of the the information is different between the
145             # the different versions of scf.
146              
147 15         71 $creator->{header} = $self->_get_header($buffer);
148 15 100       76 if ($creator->{header}->{'version'} lt "3.00") {
149 4         23 $self->debug("scf.pm is working with a version 2 scf.\n");
150             # first gather the trace information
151             $length = $creator->{header}->{'samples'} *
152 4         15 $creator->{header}->{sample_size}*4;
153             $buffer = $self->read_from_buffer($fh, $buffer, $length,
154 4         21 $creator->{header}->{samples_offset});
155             # @read = unpack "n$length",$buffer;
156             # these traces need to be split
157             # returns a reference to a hash
158             $creator->{traces} = $self->_parse_v2_traces(
159 4         23 $buffer,$creator->{header}->{sample_size});
160             # now go and get the base information
161 4         39 $offset = $creator->{header}->{bases_offset};
162 4         18 $length = ($creator->{header}->{bases} * 12);
163 4         74 seek $fh,$offset,0;
164 4         50 $buffer = $self->read_from_buffer($fh,$buffer,$length,$creator->{header}->{bases_offset});
165             # now distill the information into its fractions.
166             # the old way : $self->_set_v2_bases($buffer);
167             # ref to an array, ref to a hash, string
168             ($creator->{peak_indices},
169             $creator->{qualities},
170             $creator->{sequence},
171 4         28 $creator->{accuracies}) = $self->_parse_v2_bases($buffer);
172              
173             } else {
174 11         67 $self->debug("scf.pm is working with a version 3+ scf.\n");
175 11         20 my $transformed_read;
176 11         30 my $current_read_position = $creator->{header}->{sample_offset};
177             $length = $creator->{header}->{'samples'}*
178 11         35 $creator->{header}->{sample_size};
179             # $dumper->dumpValue($creator->{header});
180 11         38 foreach (qw(a c g t)) {
181 44         411 $buffer = $self->read_from_buffer($fh,$buffer,$length,$current_read_position);
182 44         143 my $byte = "n";
183 44 50       198 if ($creator->{header}->{sample_size} == 1) {
184 0         0 $byte = "c";
185             }
186 44         28102 @read = unpack "${byte}${length}",$buffer;
187             # this little spurt of nonsense is because
188             # the trace values are given in the binary
189             # file as unsigned shorts but they really
190             # are signed deltas. 30000 is an arbitrary number
191             # (will there be any traces with a given
192             # point greater then 30000? I hope not.
193             # once the read is read, it must be changed
194             # from relative
195 44         2175 foreach (@read) {
196 424924 100       497301 if ($_ > 30000) {
197 142333         138597 $_ -= 65536;
198             }
199             }
200 44         561 $transformed_read = $self->_delta(\@read,"backward");
201             # For 8-bit data we need to emulate a signed/unsigned
202             # cast that is implicit in the C implementations.....
203 44 50       381 if ($creator->{header}->{sample_size} == 1) {
204 0         0 foreach (@{$transformed_read}) {
  0         0  
205 0 0       0 $_ += 256 if ($_ < 0);
206             }
207             }
208 44         89 $current_read_position += $length;
209 44         128 $creator->{'traces'}->{$_} = join(' ',@{$transformed_read});
  44         68360  
210             }
211            
212             # now go and get the peak index information
213 11         66 $offset = $creator->{header}->{bases_offset};
214 11         31 $length = ($creator->{header}->{bases} * 4);
215 11         95 $buffer = $self->read_from_buffer($fh,$buffer,$length,$offset);
216 11         54 $creator->{peak_indices} = $self->_get_v3_peak_indices($buffer);
217 11         27 $offset += $length;
218             # now go and get the accuracy information
219 11         35 $buffer = $self->read_from_buffer($fh,$buffer,$length,$offset);
220 11         47 $creator->{accuracies} = $self->_get_v3_base_accuracies($buffer);
221             # OK, now go and get the base information.
222 11         23 $offset += $length;
223 11         23 $length = $creator->{header}->{bases};
224 11         46 $buffer = $self->read_from_buffer($fh,$buffer,$length,$offset);
225 11         63 $creator->{'sequence'} = unpack("a$length",$buffer);
226             # now, finally, extract the calls from the accuracy information.
227             $creator->{qualities} = $self->_get_v3_quality(
228 11         42 $creator->{'sequence'},$creator->{accuracies});
229             }
230             # now go and get the comment information
231 15         74 $offset = $creator->{header}->{comments_offset};
232 15         177 seek $fh,$offset,0;
233 15         38 $length = $creator->{header}->{comment_size};
234 15         116 $buffer = $self->read_from_buffer($fh,$buffer,$length);
235 15         77 $creator->{comments} = $self->_get_comments($buffer);
236 74         114 my @name_comments = grep {$_->tagname() eq 'NAME'}
237 15         76 $creator->{comments}->get_Annotations('comment');
238 15         31 my $name_comment;
239 15 100       38 if (@name_comments){
240 7         27 $name_comment = $name_comments[0]->as_text();
241 7         42 $name_comment =~ s/^Comment:\s+//;
242             }
243              
244             my $swq = Bio::Seq::Quality->new(
245             -seq => $creator->{'sequence'},
246 15         162 -qual => $creator->{'qualities'},
247             -id => $name_comment
248             );
249             my $returner = Bio::Seq::SequenceTrace->new(
250             -swq => $swq,
251             -trace_a => $creator->{'traces'}->{'a'},
252             -trace_t => $creator->{'traces'}->{'t'},
253             -trace_g => $creator->{'traces'}->{'g'},
254             -trace_c => $creator->{'traces'}->{'c'},
255             -accuracy_a => $creator->{'accuracies'}->{'a'},
256             -accuracy_t => $creator->{'accuracies'}->{'t'},
257             -accuracy_g => $creator->{'accuracies'}->{'g'},
258             -accuracy_c => $creator->{'accuracies'}->{'c'},
259 15         310 -peak_indices => $creator->{'peak_indices'}
260             );
261              
262 15         127 $returner->annotation($creator->{'comments'}); # add SCF comments
263 15         35 $self->{'_readfile'} = 1;
264 15         3618 return $returner;
265             }
266              
267              
268             =head2 _get_v3_quality()
269              
270             Title : _get_v3_quality()
271             Usage : $self->_get_v3_quality()
272             Function: Set the base qualities from version3 scf
273             Returns : Nothing. Alters $self.
274             Args : None.
275             Notes :
276              
277             =cut
278              
279             #'
280             sub _get_v3_quality {
281 11     11   36 my ($self,$sequence,$accuracies) = @_;
282 11         786 my @bases = split//,$sequence;
283 11         31 my (@qualities,$currbase,$currqual,$counter);
284 11         52 for ($counter=0; $counter <= $#bases ; $counter++) {
285 7639         7657 $currbase = lc($bases[$counter]);
286 7639 100       10013 if ($currbase eq "a") { $currqual = $accuracies->{'a'}->[$counter]; }
  1733 100       1759  
    100          
    50          
287 2691         2729 elsif ($currbase eq "c") { $currqual = $accuracies->{'c'}->[$counter]; }
288 1227         1310 elsif ($currbase eq "g") { $currqual = $accuracies->{'g'}->[$counter]; }
289 1988         1978 elsif ($currbase eq "t") { $currqual = $accuracies->{'t'}->[$counter]; }
290 0         0 else { $currqual = "unknown"; }
291 7639         10351 push @qualities,$currqual;
292             }
293 11         6186 return \@qualities;
294             }
295              
296             =head2 _get_v3_peak_indices($buffer)
297              
298             Title : _get_v3_peak_indices($buffer)
299             Usage : $self->_get_v3_peak_indices($buffer);
300             Function: Unpacks the base accuracies for version3 scf
301             Returns : Nothing. Alters $self
302             Args : A scalar containing binary data.
303             Notes :
304              
305             =cut
306              
307             sub _get_v3_peak_indices {
308 11     11   29 my ($self,$buffer) = @_;
309 11         21 my $length = length($buffer);
310 11         331 my @read = unpack "N$length",$buffer;
311 11         1516 return join(' ',@read);
312             }
313              
314             =head2 _get_v3_base_accuracies($buffer)
315              
316             Title : _get_v3_base_accuracies($buffer)
317             Usage : $self->_get_v3_base_accuracies($buffer)
318             Function: Set the base accuracies for version 3 scf's
319             Returns : Nothing. Alters $self.
320             Args : A scalar containing binary data.
321             Notes :
322              
323             =cut
324              
325             #'
326             sub _get_v3_base_accuracies {
327 11     11   28 my ($self,$buffer) = @_;
328 11         16 my $length = length($buffer);
329 11         33 my $qlength = $length/4;
330 11         18 my $offset = 0;
331 11         19 my (@qualities,@sorter,$counter,$round,$last_base,$accuracies,$currbase);
332 11         28 foreach $currbase (qw(a c g t)) {
333 44         54 my @read;
334 44         62 $last_base = $offset + $qlength;
335 44         67 for (;$offset < $last_base; $offset += $qlength) {
336             # a bioperler (perhaps me?) changed the unpack string to include 'n' rather than 'C'
337             # on 040322 I think that 'C' is correct. please email chad if you would like to accuse me of being incorrect
338 44         956 @read = unpack "C$qlength", substr($buffer,$offset,$qlength);
339 44         230 $accuracies->{$currbase} = \@read;
340             }
341             }
342 11         45 return $accuracies;
343             }
344              
345              
346             =head2 _get_comments($buffer)
347              
348             Title : _get_comments($buffer)
349             Usage : $self->_get_comments($buffer);
350             Function: Gather the comments section from the scf and parse it into its
351             components.
352             Returns : a Bio::Annotation::Collection object
353             Args : The buffer. It is expected that the buffer contains a binary
354             string for the comments section of an scf file according to
355             the scf file specifications.
356             Notes :
357              
358             =cut
359              
360             sub _get_comments {
361 15     15   60 my ($self,$buffer) = @_;
362 15         259 my $comments = Bio::Annotation::Collection->new();
363 15         38 my $size = length($buffer);
364 15         101 my $comments_retrieved = unpack "a$size",$buffer;
365 15         148 $comments_retrieved =~ s/\0//;
366 15         108 my @comments_split = split/\n/,$comments_retrieved;
367 15 100       56 if (@comments_split) {
368 13         37 foreach (@comments_split) {
369 100         446 /(\w+)=(.*)/;
370 100 100 66     440 if ($1 && $2) {
371 74         172 my ($tagname, $text) = ($1, $2);
372 74         274 my $comment_obj = Bio::Annotation::Comment->new(
373             -text => $text,
374             -tagname => $tagname);
375              
376 74         203 $comments->add_Annotation('comment', $comment_obj);
377             }
378             }
379             }
380 15         47 $self->{'comments'} = $comments;
381 15         63 return $comments;
382             }
383              
384             =head2 _get_header()
385              
386             Title : _get_header($buffer)
387             Usage : $self->_get_header($buffer);
388             Function: Gather the header section from the scf and parse it into its
389             components.
390             Returns : Reference to a hash containing the header components.
391             Args : The buffer. It is expected that the buffer contains a binary
392             string for the header section of an scf file according to the
393             scf file specifications.
394             Notes : None.
395              
396             =cut
397              
398             sub _get_header {
399 15     15   39 my ($self,$buffer) = @_;
400 15         25 my $header;
401             ($header->{'scf'},
402             $header->{'samples'},
403             $header->{'sample_offset'},
404             $header->{'bases'},
405             $header->{'bases_left_clip'},
406             $header->{'bases_right_clip'},
407             $header->{'bases_offset'},
408             $header->{'comment_size'},
409             $header->{'comments_offset'},
410             $header->{'version'},
411             $header->{'sample_size'},
412             $header->{'code_set'},
413 15         271 @{$header->{'header_spare'}} ) = unpack "a4 NNNNNNNN a4 NN N20", $buffer;
  15         75  
414              
415 15         47 $self->{'header'} = $header;
416 15         47 return $header;
417             }
418              
419             =head2 _parse_v2_bases($buffer)
420              
421             Title : _parse_v2_bases($buffer)
422             Usage : $self->_parse_v2_bases($buffer);
423             Function: Gather the bases section from the scf and parse it into its
424             components.
425             Returns :
426             Args : The buffer. It is expected that the buffer contains a binary
427             string for the bases section of an scf file according to the
428             scf file specifications.
429             Notes : None.
430              
431             =cut
432              
433             sub _parse_v2_bases {
434 4     4   14 my ($self,$buffer) = @_;
435 4         8 my $length = length($buffer);
436 4         17 my ($offset2,$currbuff,$currbase,$currqual,$sequence,@qualities,@indices);
437 4         0 my (@read,$harvester,$accuracies);
438 4         19 for ($offset2=0;$offset2<$length;$offset2+=12) {
439 3734         13551 @read = unpack "N C C C C a C3", substr($buffer,$offset2,$length);
440 3734         4642 push @indices,$read[0];
441 3734         4260 $currbase = lc($read[5]);
442 3734 100       5647 if ($currbase eq "a") { $currqual = $read[1]; }
  828 100       842  
    100          
    50          
443 1238         1168 elsif ($currbase eq "c") { $currqual = $read[2]; }
444 710         665 elsif ($currbase eq "g") { $currqual = $read[3]; }
445 958         899 elsif ($currbase eq "t") { $currqual = $read[4]; }
446 0         0 else { $currqual = "UNKNOWN"; }
447 3734         3083 push @{$accuracies->{"a"}},$read[1];
  3734         4589  
448 3734         3614 push @{$accuracies->{"c"}},$read[2];
  3734         4057  
449 3734         3370 push @{$accuracies->{"g"}},$read[3];
  3734         3908  
450 3734         3392 push @{$accuracies->{"t"}},$read[4];
  3734         3764  
451              
452 3734         3964 $sequence .= $currbase;
453 3734         5821 push @qualities,$currqual;
454             }
455 4         91 return (\@indices,\@qualities,$sequence,$accuracies)
456             }
457              
458             =head2 _parse_v2_traces(\@traces_array)
459              
460             Title : _pares_v2_traces(\@traces_array)
461             Usage : $self->_parse_v2_traces(\@traces_array);
462             Function: Parses an scf Version2 trace array into its base components.
463             Returns : Nothing. Modifies $self.
464             Args : A reference to an array of the unpacked traces section of an
465             scf version2 file.
466              
467             =cut
468              
469             sub _parse_v2_traces {
470 4     4   10 my ($self,$buffer,$sample_size) = @_;
471 4         6 my $byte;
472 4 50       13 if ($sample_size == 1) { $byte = "c"; }
  0         0  
473 4         8 else { $byte = "n"; }
474 4         7 my $length = CORE::length($buffer);
475 4         10474 my @read = unpack "${byte}${length}",$buffer;
476             # this will be an array to the reference holding the array
477 8         957 my $traces;
478 8         10 my $array = 0;
479 8         28 for (my $offset2 = 0; $offset2< scalar(@read); $offset2+=4) {
480 46000         39130 push @{$traces->{'a'}},$read[$offset2];
  46000         51610  
481 46000         39605 push @{$traces->{'c'}},$read[$offset2+1];
  46000         51876  
482 46000         40103 push @{$traces->{'g'}},$read[$offset2+3];
  46000         54373  
483 46000         40073 push @{$traces->{'t'}},$read[$offset2+2];
  46000         72964  
484             }
485 8         6194 return $traces;
486             }
487              
488              
489       0 0   sub get_trace_deprecated_use_the_sequencetrace_object_instead {
490             # my ($self,$base_channel,$traces) = @_;
491             # $base_channel =~ tr/a-z/A-Z/;
492             # if ($base_channel !~ /A|T|G|C/) {
493             # $self->throw("You tried to ask for a base channel that wasn't A,T,G, or C. Ask for one of those next time.");
494             ##} elsif ($base_channel) {
495             # my @temp = split(' ',$self->{'traces'}->{$base_channel});
496             #return \@temp;
497             #}
498             }
499              
500             sub _deprecated_get_peak_indices_deprecated_use_the_sequencetrace_object_instead {
501 0     0   0 my ($self) = shift;
502 0         0 my @temp = split(' ',$self->{'parsed'}->{'peak_indices'});
503 0         0 return \@temp;
504             }
505              
506              
507             =head2 get_header()
508              
509             Title : get_header()
510             Usage : %header = %{$obj->get_header()};
511             Function: Return the header for this scf.
512             Returns : A reference to a hash containing the header for this scf.
513             Args : None.
514             Notes :
515              
516             =cut
517              
518             sub get_header {
519 1     1 1 661 my ($self) = shift;
520 1         23 return $self->{'header'};
521             }
522              
523             =head2 get_comments()
524              
525             Title : get_comments()
526             Usage : %comments = %{$obj->get_comments()};
527             Function: Return the comments for this scf.
528             Returns : A Bio::Annotation::Collection object
529             Args : None.
530             Notes :
531              
532             =cut
533              
534             sub get_comments {
535 1     1 1 6 my ($self) = shift;
536 1         6 return $self->{'comments'};
537             }
538              
539             sub _dump_traces_outgoing_deprecated_use_the_sequencetrace_object {
540 0     0   0 my ($self,$transformed) = @_;
541 0         0 my (@sA,@sT,@sG,@sC);
542 0 0       0 if ($transformed) {
543 0         0 @sA = @{$self->{'text'}->{'t_samples_a'}};
  0         0  
544 0         0 @sC = @{$self->{'text'}->{'t_samples_c'}};
  0         0  
545 0         0 @sG = @{$self->{'text'}->{'t_samples_g'}};
  0         0  
546 0         0 @sT = @{$self->{'text'}->{'t_samples_t'}};
  0         0  
547             }
548             else {
549 0         0 @sA = @{$self->{'text'}->{'samples_a'}};
  0         0  
550 0         0 @sC = @{$self->{'text'}->{'samples_c'}};
  0         0  
551 0         0 @sG = @{$self->{'text'}->{'samples_g'}};
  0         0  
552 0         0 @sT = @{$self->{'text'}->{'samples_t'}};
  0         0  
553             }
554 0         0 print ("Count\ta\tc\tg\tt\n");
555 0         0 for (my $curr=0; $curr < scalar(@sG); $curr++) {
556 0         0 print("$curr\t$sA[$curr]\t$sC[$curr]\t$sG[$curr]\t$sT[$curr]\n");
557             }
558 0         0 return;
559             }
560              
561       0     sub _dump_traces_incoming_deprecated_use_the_sequencetrace_object {
562             # my ($self) = @_;
563             # my (@sA,@sT,@sG,@sC);
564             # @sA = @{$self->{'traces'}->{'A'}};
565             # @sC = @{$self->{'traces'}->{'C'}};
566             # @sG = @{$self->{'traces'}->{'G'}};
567             # @sT = @{$self->{'traces'}->{'T'}};
568             # @sA = @{$self->get_trace('A')};
569             # @sC = @{$self->get_trace('C')};
570             # @sG = @{$self->get_trace('G')};
571             # @sT = @{$self->get_trace('t')};
572             # print ("Count\ta\tc\tg\tt\n");
573             # for (my $curr=0; $curr < scalar(@sG); $curr++) {
574             # print("$curr\t$sA[$curr]\t$sC[$curr]\t$sG[$curr]\t$sT[$curr]\n");
575             #}
576             #return;
577             }
578              
579             =head2 write_seq
580              
581             Title : write_seq(-target => $swq, )
582             Usage : $obj->write_seq(
583             -target => $swq,
584             -version => 2,
585             -CONV => "Bioperl-Chads Mighty SCF writer.");
586             Function: Write out an scf.
587             Returns : Nothing.
588             Args : Requires: a reference to a Bio::Seq::Quality object to form the
589             basis for the scf.
590             if -version is provided, it should be "2" or "3". A SCF of that
591             version will be written.
592             Any other arguments are assumed to be comments and are put into
593             the comments section of the scf. Read the specifications for scf
594             to decide what might be good to put in here.
595              
596             Notes :
597             For best results, use a SequenceTrace object.
598             The things that you need to write an scf:
599             a) sequence
600             b) quality
601             c) peak indices
602             d) traces
603             - You _can_ write an scf with just a and b by passing in a
604             Bio::Seq::Quality object- false traces will be synthesized
605             for you.
606              
607             =cut
608              
609             sub write_seq {
610 10     10 1 2821 my ($self,%args) = @_;
611 10         24 my %comments;
612 10         23 my ($label,$arg);
613 10         77 my ($swq) = $self->_rearrange([qw(TARGET)], %args);
614 10         33 my $writer_fodder;
615 10 50       90 if (ref($swq) =~ /Bio::Seq::SequenceTrace|Bio::Seq::Quality/) {
616 10 100       40 if (ref($swq) eq "Bio::Seq::Quality") {
617             # this means that the object *has no trace data*
618             # we might as well synthesize some now, ok?
619 2         16 $swq = Bio::Seq::SequenceTrace->new(
620             -swq => $swq
621             );
622             }
623             }
624             else {
625 0         0 $self->throw("You must pass a Bio::Seq::Quality or a Bio::Seq::SequenceTrace object to write_seq as a parameter named \"target\"");
626             }
627             # all of the rest of the arguments are comments for the scf
628 10         68 foreach $arg (sort keys %args) {
629 23 100       94 next if ($arg =~ /target/i);
630 13         52 ($label = $arg) =~ s/^\-//;
631 13         40 $writer_fodder->{comments}->{$label} = $args{$arg};
632             }
633 10 50       44 if (!$comments{'NAME'}) { $comments{'NAME'} = $swq->id(); }
  10         43  
634             # HA! Bwahahahaha.
635 10 50       52 $writer_fodder->{comments}->{'CONV'} = "Bioperl-Chads Mighty SCF writer." unless defined $comments{'CONV'};
636             # now deal with the version of scf they want to write
637 10 100       33 if ($writer_fodder->{comments}->{version}) {
638 1 50 33     18 if ($writer_fodder->{comments}->{version} != 2 && $writer_fodder->{comments}->{version} != 3) {
    50          
639 0         0 $self->warn("This module can only write version 2.0 or 3.0 scf's. Writing a version 2.0 scf by default.");
640 0         0 $writer_fodder->{header}->{version} = "2.00";
641             }
642             elsif ($writer_fodder->{comments}->{'version'} > 2) {
643 0         0 $writer_fodder->{header}->{'version'} = "3.00";
644             }
645             else {
646 1         4 $writer_fodder->{header}->{version} = "2";
647             }
648             }
649             else {
650 9         34 $writer_fodder->{header}->{'version'} = "3.00";
651             }
652             # set a few things in the header
653 10         26 $writer_fodder->{'header'}->{'magic'} = ".scf";
654 10         25 $writer_fodder->{'header'}->{'sample_size'} = "2";
655 10         37 $writer_fodder->{'header'}->{'bases'} = length($swq->seq());
656 10         49 $writer_fodder->{'header'}->{'bases_left_clip'} = "0";
657 10         24 $writer_fodder->{'header'}->{'bases_right_clip'} = "0";
658 10         20 $writer_fodder->{'header'}->{'sample_size'} = "2";
659 10         30 $writer_fodder->{'header'}->{'code_set'} = "9";
660 10         28 @{$writer_fodder->{'header'}->{'spare'}} = qw(0 0 0 0 0 0 0 0 0 0
  10         86  
661             0 0 0 0 0 0 0 0 0 0);
662 10         25 $writer_fodder->{'header'}->{'samples_offset'} = "128";
663 10         47 $writer_fodder->{'header'}->{'samples'} = $swq->trace_length();
664             # create the binary for the comments and file it in writer_fodder
665             $writer_fodder->{comments} = $self->_get_binary_comments(
666 10         56 $writer_fodder->{comments});
667             # create the binary and the strings for the traces, bases,
668             # offsets (if necessary), and accuracies (if necessary)
669             $writer_fodder->{traces} = $self->_get_binary_traces(
670             $writer_fodder->{'header'}->{'version'},
671 10         56 $swq,$writer_fodder->{'header'}->{'sample_size'});
672 10         33 my ($b_base_offsets,$b_base_accuracies,$samples_size,$bases_size);
673             #
674             # version 2
675             #
676 10 100       99 if ($writer_fodder->{'header'}->{'version'} == 2) {
677             $writer_fodder->{bases} = $self->_get_binary_bases(
678             2,
679             $swq,
680 1         11 $writer_fodder->{'header'}->{'sample_size'});
681 1         6 $samples_size = CORE::length($writer_fodder->{traces}->{'binary'});
682 1         5 $bases_size = CORE::length($writer_fodder->{bases}->{binary});
683 1         7 $writer_fodder->{'header'}->{'bases_offset'} = 128 + $samples_size;
684 1         7 $writer_fodder->{'header'}->{'comments_offset'} = 128 +
685             $samples_size + $bases_size;
686             $writer_fodder->{'header'}->{'comments_size'} =
687 1         6 length($writer_fodder->{'comments'}->{binary});
688 1         9 $writer_fodder->{'header'}->{'private_size'} = "0";
689             $writer_fodder->{'header'}->{'private_offset'} = 128 +
690             $samples_size + $bases_size +
691 1         6 $writer_fodder->{'header'}->{'comments_size'};
692             $writer_fodder->{'header'}->{'binary'} =
693 1         9 $self->_get_binary_header($writer_fodder->{header});
694 1 50       14 $dumper->dumpValue($writer_fodder) if $self->verbose > 0;
695 1 50       12 $self->_print ($writer_fodder->{'header'}->{'binary'})
696             or print("Could not write binary header...\n");
697 1 50       8 $self->_print ($writer_fodder->{'traces'}->{'binary'})
698             or print("Could not write binary traces...\n");
699 1 50       10 $self->_print ($writer_fodder->{'bases'}->{'binary'})
700             or print("Could not write binary base structures...\n");
701 1 50       7 $self->_print ($writer_fodder->{'comments'}->{'binary'})
702             or print("Could not write binary comments...\n");
703             }
704             else {
705             ($writer_fodder->{peak_indices},
706             $writer_fodder->{accuracies},
707             $writer_fodder->{bases},
708             $writer_fodder->{reserved} ) =
709             $self->_get_binary_bases(
710             3,
711             $swq,
712 9         74 $writer_fodder->{'header'}->{'sample_size'}
713             );
714             $writer_fodder->{'header'}->{'bases_offset'} = 128 +
715 9         48 length($writer_fodder->{'traces'}->{'binary'});
716             $writer_fodder->{'header'}->{'comments_size'} =
717 9         30 length($writer_fodder->{'comments'}->{'binary'});
718             # this is:
719             # bases_offset + base_offsets + accuracies + called_bases +
720             # reserved
721 9         20 $writer_fodder->{'header'}->{'private_size'} = "0";
722              
723             $writer_fodder->{'header'}->{'comments_offset'} =
724             128+length($writer_fodder->{'traces'}->{'binary'})+
725             length($writer_fodder->{'peak_indices'}->{'binary'})+
726             length($writer_fodder->{'accuracies'}->{'binary'})+
727             length($writer_fodder->{'bases'}->{'binary'})+
728 9         54 length($writer_fodder->{'reserved'}->{'binary'});
729             $writer_fodder->{'header'}->{'private_offset'} =
730             $writer_fodder->{'header'}->{'comments_offset'} +
731 9         26 $writer_fodder->{'header'}->{'comments_size'};
732             $writer_fodder->{'header'}->{'spare'}->[1] =
733             $writer_fodder->{'header'}->{'comments_offset'} +
734 9         35 length($writer_fodder->{'comments'}->{'binary'});
735             $writer_fodder->{header}->{binary} =
736 9         39 $self->_get_binary_header($writer_fodder->{header});
737 9 50       83 $self->_print ($writer_fodder->{'header'}->{'binary'})
738             or print("Couldn't write header\n");
739 9 50       34 $self->_print ($writer_fodder->{'traces'}->{'binary'})
740             or print("Couldn't write samples\n");
741 9 50       30 $self->_print ($writer_fodder->{'peak_indices'}->{'binary'})
742             or print("Couldn't write peak offsets\n");
743 9 50       35 $self->_print ($writer_fodder->{'accuracies'}->{'binary'})
744             or print("Couldn't write accuracies\n");
745 9 50       27 $self->_print ($writer_fodder->{'bases'}->{'binary'})
746             or print("Couldn't write called_bases\n");
747 9 50       31 $self->_print ($writer_fodder->{'reserved'}->{'binary'})
748             or print("Couldn't write reserved\n");
749 9 50       29 $self->_print ($writer_fodder->{'comments'}->{'binary'})
750             or print ("Couldn't write comments\n");
751             }
752              
753             # kinda unnecessary, given the close() below, but maybe that'll go
754             # away someday.
755 10 50 33     54 $self->flush if $self->_flush_on_write && defined $self->_fh;
756              
757 10         59 $self->close();
758 10         10018 return 1;
759             }
760              
761              
762              
763              
764              
765             =head2 _get_binary_header()
766              
767             Title : _get_binary_header();
768             Usage : $self->_get_binary_header();
769             Function: Provide the binary string that will be used as the header for
770             a scfv2 document.
771             Returns : A binary string.
772             Args : None. Uses the entries in the $self->{'header'} hash. These
773             are set on construction of the object (hopefully correctly!).
774             Notes :
775              
776             =cut
777              
778             sub _get_binary_header {
779 10     10   24 my ($self,$header) = @_;
780             my $binary = pack "a4 NNNNNNNN a4 NN N20",
781             (
782             $header->{'magic'},
783             $header->{'samples'},
784             $header->{'samples_offset'},
785             $header->{'bases'},
786             $header->{'bases_left_clip'},
787             $header->{'bases_right_clip'},
788             $header->{'bases_offset'},
789             $header->{'comments_size'},
790             $header->{'comments_offset'},
791             $header->{'version'},
792             $header->{'sample_size'},
793             $header->{'code_set'},
794 10         60 @{$header->{'spare'}}
  10         134  
795             );
796 10         50 return $binary;
797             }
798              
799             =head2 _get_binary_traces($version,$ref)
800              
801             Title : _set_binary_tracesbases($version,$ref)
802             Usage : $self->_set_binary_tracesbases($version,$ref);
803             Function: Constructs the trace and base strings for all scfs
804             Returns : Nothing. Alters self.
805             Args : $version - "2" or "3"
806             $sequence - a scalar containing arbitrary sequence data
807             $ref - a reference to either a SequenceTraces or a
808             SequenceWithQuality object.
809             Notes : This is a really complicated thing.
810              
811             =cut
812              
813             sub _get_binary_traces {
814 10     10   40 my ($self,$version,$ref,$sample_size) = @_;
815             # ref _should_ be a Bio::Seq::SequenceTrace, but might be a
816             # Bio::Seq::Quality
817 10         17 my $returner;
818 10         49 my $sequence = $ref->seq();
819 10         17 my $sequence_length = length($sequence);
820             # first of all, do we need to synthesize the trace?
821             # if so, call synthesize_base
822 10         21 my ($traceobj,@traces,$current);
823 10 50       40 if ( ref($ref) eq "Bio::Seq::Quality" ) {
824 0         0 $traceobj = Bio::Seq::Quality->new(
825             -target => $ref
826             );
827 0         0 $traceobj->_synthesize_traces();
828             }
829             else {
830 10         19 $traceobj = $ref;
831 10 100       63 if ($version eq "2") {
    50          
832 1         4 my $trace_length = $traceobj->trace_length();
833 1         6 for ($current = 1; $current <= $trace_length; $current++) {
834 14107         20277 foreach (qw(a c g t)) {
835 56428         100184 push @traces,$traceobj->trace_value_at($_,$current);
836             }
837             }
838             }
839             elsif ($version == 3) {
840 9         24 foreach my $current_trace (qw(a c g t)) {
841 36         172 my @trace = @{$traceobj->trace($current_trace)};
  36         277  
842 36         165 foreach (@trace) {
843 245300 50       333556 if ($_ > 30000) {
844 0         0 $_ -= 65536;
845             }
846             }
847 36         332 my $transformed = $self->_delta(\@trace,"forward");
848 36 50       150 if($sample_size == 1){
849 0         0 foreach (@{$transformed}) {
  0         0  
850 0 0       0 $_ += 256 if ($_ < 0);
851             }
852             }
853 36         57 push @traces,@{$transformed};
  36         50625  
854             }
855             }
856             }
857 10         133 $returner->{version} = $version;
858 10         44 $returner->{string} = \@traces;
859 10         24 my $length_of_traces = scalar(@traces);
860 10         14 my $byte;
861 10 50       40 if ($sample_size == 1) { $byte = "c"; } else { $byte = "n"; }
  0         0  
  10         29  
862             # an unsigned integer should be I, but this is too long
863             #
864 10         8818 $returner->{binary} = pack "n${length_of_traces}",@traces;
865 10         69 $returner->{length} = CORE::length($returner->{binary});
866 10         83 return $returner;
867             }
868              
869              
870             sub _get_binary_bases {
871 10     10   42 my ($self,$version,$trace,$sample_size) = @_;
872 10         13 my $byte;
873 10 50       26 if ($sample_size == 1) { $byte = "c"; } else { $byte = "n"; }
  0         0  
  10         26  
874 10         26 my ($returner,@current_row,$current_base,$string,$binary);
875 10         81 my $length = $trace->length();
876 10 100       39 if ($version == 2) {
877 1         6 $returner->{'version'} = "2";
878 1         8 for (my $current_base =1; $current_base <= $length; $current_base++) {
879 1106         1304 my @current_row;
880 1106         2221 push @current_row,$trace->peak_index_at($current_base);
881 1106         2078 push @current_row,$trace->accuracy_at("a",$current_base);
882 1106         1910 push @current_row,$trace->accuracy_at("c",$current_base);
883 1106         1760 push @current_row,$trace->accuracy_at("g",$current_base);
884 1106         1697 push @current_row,$trace->accuracy_at("t",$current_base);
885 1106         1980 push @current_row,$trace->baseat($current_base);
886 1106         1576 push @current_row,0,0,0;
887 1106         1103 push @{$returner->{string}},@current_row;
  1106         2858  
888 1106         4642 $returner->{binary} .= pack "N C C C C a C3",@current_row;
889             }
890 1         12 return $returner;
891             }
892             else {
893 9         36 $returner->{'version'} = "3.00";
894 9         37 $returner->{peak_indices}->{string} = $trace->peak_indices();
895 9         20 my $length = scalar(@{$returner->{peak_indices}->{string}});
  9         23  
896             $returner->{peak_indices}->{binary} =
897 9         29 pack "N$length",@{$returner->{peak_indices}->{string}};
  9         676  
898             $returner->{peak_indices}->{length} =
899 9         34 CORE::length($returner->{peak_indices}->{binary});
900 9         17 my @accuracies;
901 9         31 foreach my $base (qw(a c g t)) {
902 36         107 $returner->{accuracies}->{$base} = $trace->accuracies($base);
903 36         51 push @accuracies,@{$trace->accuracies($base)};
  36         55  
904             }
905 9         44 $returner->{sequence} = $trace->seq();
906 9         42 $length = scalar(@accuracies);
907             # this really is "c" for samplesize == 2
908 9         398 $returner->{accuracies}->{binary} = pack "C${length}",@accuracies;
909             $returner->{accuracies}->{length} =
910 9         25 CORE::length($returner->{accuracies}->{binary});
911 9         28 $length = $trace->seq_obj()->length();
912 9         35 for (my $count=0; $count< $length; $count++) {
913 4629         3877 push @{$returner->{reserved}->{string}},0,0,0;
  4629         8523  
914             }
915             }
916 9         30 $length = scalar(@{$returner->{reserved}->{string}});
  9         49  
917             # this _must_ be "c"
918             $returner->{'reserved'}->{'binary'} =
919 9         32 pack "c$length",@{$returner->{reserved}->{string}};
  9         527  
920             $returner->{'reserved'}->{'length'} =
921 9         37 CORE::length($returner->{'reserved'}->{'binary'});
922             # $returner->{'bases'}->{'string'} = $trace->seq();
923 9         174 my @bases = split('',$trace->seq());
924 9         42 $length = $trace->length();
925 9         33 $returner->{'bases'}->{'binary'} = $trace->seq();
926             # print("Returning this:\n");
927             # $dumper->dumpValue($returner);
928             return ($returner->{peak_indices},
929             $returner->{accuracies},
930             $returner->{bases},
931 9         265 $returner->{reserved});
932              
933             }
934              
935              
936             =head2 _make_trace_string($version)
937              
938             Title : _make_trace_string($version)
939             Usage : $self->_make_trace_string($version)
940             Function: Merges trace data for the four bases to produce an scf
941             trace string. _requires_ $version
942             Returns : Nothing. Alters $self.
943             Args : $version - a version number. "2" or "3"
944             Notes :
945              
946             =cut
947              
948             sub _make_trace_string {
949 0     0   0 my ($self,$version) = @_;
950 0         0 my @traces;
951             my @traces_view;
952 0         0 my @as = @{$self->{'text'}->{'samples_a'}};
  0         0  
953 0         0 my @cs = @{$self->{'text'}->{'samples_c'}};
  0         0  
954 0         0 my @gs = @{$self->{'text'}->{'samples_g'}};
  0         0  
955 0         0 my @ts = @{$self->{'text'}->{'samples_t'}};
  0         0  
956 0 0       0 if ($version == 2) {
    0          
957 0         0 for (my $curr=0; $curr < scalar(@as); $curr++) {
958 0 0       0 $as[$curr] = $DEFAULT_QUALITY unless defined $as[$curr];
959 0 0       0 $cs[$curr] = $DEFAULT_QUALITY unless defined $cs[$curr];
960 0 0       0 $gs[$curr] = $DEFAULT_QUALITY unless defined $gs[$curr];
961 0 0       0 $ts[$curr] = $DEFAULT_QUALITY unless defined $ts[$curr];
962 0         0 push @traces,($as[$curr],$cs[$curr],$gs[$curr],$ts[$curr]);
963             }
964             }
965             elsif ($version == 3) {
966 0         0 @traces = (@as,@cs,@gs,@ts);
967             }
968             else {
969 0         0 $self->throw("No idea what version required to make traces here. You gave #$version# Bailing.");
970             }
971 0         0 my $length = scalar(@traces);
972 0         0 $self->{'text'}->{'samples_all'} = \@traces;
973              
974             }
975              
976             =head2 _get_binary_comments(\@comments)
977              
978             Title : _get_binary_comments(\@comments)
979             Usage : $self->_get_binary_comments(\@comments);
980             Function: Provide a binary string that will be the comments section of
981             the scf file. See the scf specifications for detailed
982             specifications for the comments section of an scf file. Hint:
983             CODE=something\nBODE=something\n\0
984             Returns :
985             Args : A reference to an array containing comments.
986             Notes : None.
987              
988             =cut
989              
990             sub _get_binary_comments {
991 10     10   25 my ($self,$rcomments) = @_;
992 10         20 my $returner;
993 10         20 my $comments_string = '';
994 10         56 my %comments = %$rcomments;
995 10         48 foreach my $key (sort keys %comments) {
996 21   50     65 $comments{$key} ||= '';
997 21         66 $comments_string .= "$key=$comments{$key}\n";
998             }
999 10         24 $comments_string .= "\n\0";
1000 10         27 my $length = CORE::length($comments_string);
1001 10         25 $returner->{length} = $length;
1002 10         22 $returner->{string} = $comments_string;
1003 10         89 $returner->{binary} = pack "A$length",$comments_string;
1004 10         40 return $returner;
1005             }
1006              
1007             #=head2 _fill_missing_data($swq)
1008             #
1009             # Title : _fill_missing_data($swq)
1010             # Usage : $self->_fill_missing_data($swq);
1011             # Function: If the $swq with quality has no qualities, set all qualities
1012             # to 0.
1013             # If the $swq has no sequence, set the sequence to N's.
1014             # Returns : Nothing. Modifies the Bio::Seq::Quality that was passed as an
1015             # argument.
1016             # Args : A reference to a Bio::Seq::Quality
1017             # Notes : None.
1018             #
1019             #=cut
1020             #
1021             ##'
1022             #sub _fill_missing_data {
1023             # my ($self,$swq) = @_;
1024             # my $qual_obj = $swq->qual_obj();
1025             # my $seq_obj = $swq->seq_obj();
1026             # if ($qual_obj->length() == 0 && $seq_obj->length() != 0) {
1027             # my $fake_qualities = ("$DEFAULT_QUALITY ")x$seq_obj->length();
1028             # $swq->qual($fake_qualities);
1029             # }
1030             # if ($seq_obj->length() == 0 && $qual_obj->length != 0) {
1031             # my $sequence = ("N")x$qual_obj->length();
1032             # $swq->seq($sequence);
1033             # }
1034             #}
1035              
1036             =head2 _delta(\@trace_data,$direction)
1037              
1038             Title : _delta(\@trace_data,$direction)
1039             Usage : $self->_delta(\@trace_data,$direction);
1040             Function:
1041             Returns : A reference to an array containing modified trace values.
1042             Args : A reference to an array containing trace data and a string
1043             indicating the direction of conversion. ("forward" or
1044             "backward").
1045             Notes : This code is taken from the specification for SCF3.2.
1046             http://www.mrc-lmb.cam.ac.uk/pubseq/manual/formats_unix_4.html
1047              
1048             =cut
1049              
1050              
1051             sub _delta {
1052 80     80   470 my ($self,$rsamples,$direction) = @_;
1053 80         56444 my @samples = @$rsamples;
1054             # /* If job == DELTA_IT:
1055             # * change a series of sample points to a series of delta delta values:
1056             # * ie change them in two steps:
1057             # * first: delta = current_value - previous_value
1058             # * then: delta_delta = delta - previous_delta
1059             # * else
1060             # * do the reverse
1061             # */
1062             # int i;
1063             # uint_2 p_delta, p_sample;
1064              
1065 80         410 my ($i,$num_samples,$p_delta,$p_sample,@samples_converted,$p_sample1,$p_sample2);
1066 80         154 my $SLOW_BUT_CLEAR = 0;
1067 80         204 $num_samples = scalar(@samples);
1068             # c-programmers are funny people with their single-letter variables
1069              
1070 80 100       467 if ( $direction eq "forward" ) {
    50          
1071 36 50       111 if($SLOW_BUT_CLEAR){
1072 0         0 $p_delta = 0;
1073 0         0 for ($i=0; $i < $num_samples; $i++) {
1074 0         0 $p_sample = $samples[$i];
1075 0         0 $samples[$i] = $samples[$i] - $p_delta;
1076 0         0 $p_delta = $p_sample;
1077             }
1078 0         0 $p_delta = 0;
1079 0         0 for ($i=0; $i < $num_samples; $i++) {
1080 0         0 $p_sample = $samples[$i];
1081 0         0 $samples[$i] = $samples[$i] - $p_delta;
1082 0         0 $p_delta = $p_sample;
1083             }
1084             } else {
1085 36         179 for ($i = $num_samples-1; $i > 1; $i--){
1086 245228         376398 $samples[$i] = $samples[$i] - 2*$samples[$i-1] + $samples[$i-2];
1087             }
1088 36         89 $samples[1] = $samples[1] - 2*$samples[0];
1089             }
1090             }
1091             elsif ($direction eq "backward") {
1092 44 50       134 if($SLOW_BUT_CLEAR){
1093 0         0 $p_sample = 0;
1094 0         0 for ($i=0; $i < $num_samples; $i++) {
1095 0         0 $samples[$i] = $samples[$i] + $p_sample;
1096 0         0 $p_sample = $samples[$i];
1097             }
1098 0         0 $p_sample = 0;
1099 0         0 for ($i=0; $i < $num_samples; $i++) {
1100 0         0 $samples[$i] = $samples[$i] + $p_sample;
1101 0         0 $p_sample = $samples[$i];
1102             }
1103             } else {
1104 44         106 $p_sample1 = $p_sample2 = 0;
1105 44         183 for ($i = 0; $i < $num_samples; $i++){
1106 424924         394285 $p_sample1 = $p_sample1 + $samples[$i];
1107 424924         382703 $samples[$i] = $p_sample1 + $p_sample2;
1108 424924         541347 $p_sample2 = $samples[$i];
1109             }
1110              
1111             }
1112             }
1113             else {
1114 0         0 $self->warn("Bad direction. Use \"forward\" or \"backward\".");
1115             }
1116 80         24213 return \@samples;
1117             }
1118              
1119             =head2 _unpack_magik($buffer)
1120              
1121             Title : _unpack_magik($buffer)
1122             Usage : $self->_unpack_magik($buffer)
1123             Function: What unpack specification should be used? Try them all.
1124             Returns : Nothing.
1125             Args : A buffer containing arbitrary binary data.
1126             Notes : Eliminate the ambiguity and the guesswork. Used in the
1127             adaptation of _delta(), mostly.
1128              
1129             =cut
1130              
1131             sub _unpack_magik {
1132 0     0   0 my ($self,$buffer) = @_;
1133 0         0 my $length = length($buffer);
1134 0         0 my (@read,$counter);
1135 0         0 foreach (qw(c C s S i I l L n N v V)) {
1136 0         0 @read = unpack "$_$length", $buffer;
1137 0         0 for ($counter=0; $counter < 20; $counter++) {
1138 0         0 print("$read[$counter]\n");
1139             }
1140             }
1141             }
1142              
1143             =head2 read_from_buffer($filehandle,$buffer,$length)
1144              
1145             Title : read_from_buffer($filehandle,$buffer,$length)
1146             Usage : $self->read_from_buffer($filehandle,$buffer,$length);
1147             Function: Read from the buffer.
1148             Returns : $buffer, containing a read of $length
1149             Args : a filehandle, a buffer, and a read length
1150             Notes : I just got tired of typing
1151             "unless (length($buffer) == $length)" so I put it here.
1152              
1153             =cut
1154              
1155             sub read_from_buffer {
1156 100     100 1 465 my ($self,$fh,$buffer,$length,$start_position) = @_;
1157             # print("Reading from a buffer!!! length($length) ");
1158 100 100       434 if ($start_position) {
1159             # print(" startposition($start_position)(".sprintf("%X", $start_position).")\n");
1160             }
1161             # print("\n");
1162 100 100       249 if ($start_position) {
1163             # print("seeking to this position in the file: (".$start_position.")\n");
1164 81         765 seek ($fh,$start_position,0);
1165             # print("done. here is where I am now: (".tell($fh).")\n");
1166             }
1167             else {
1168             # print("You did not specify a start position. Going from this position (the current position) (".tell($fh).")\n");
1169             }
1170 100         3076 read $fh, $buffer, $length;
1171 100 50       376 unless (length($buffer) == $length) {
1172 0         0 $self->warn("The read was incomplete! Trying harder.");
1173 0         0 my $missing_length = $length - length($buffer);
1174 0         0 my $buffer2;
1175 0         0 read $fh,$buffer2,$missing_length;
1176 0         0 $buffer .= $buffer2;
1177 0 0       0 if (length($buffer) != $length) {
1178 0         0 $self->throw("Unexpected end of file while reading from SCF file. I should have read $length but instead got ".length($buffer)."! Current file position is ".tell($fh).".");
1179             }
1180             }
1181              
1182 100         452 return $buffer;
1183             }
1184              
1185             =head2 _dump_keys()
1186              
1187             Title : _dump_keys()
1188             Usage : &_dump_keys($a_reference_to_some_hash)
1189             Function: Dump out the keys in a hash.
1190             Returns : Nothing.
1191             Args : A reference to a hash.
1192             Notes : A debugging method.
1193              
1194             =cut
1195              
1196             sub _dump_keys {
1197 0     0     my $rhash = shift;
1198 0 0         if ($rhash !~ /HASH/) {
1199 0           print("_dump_keys: that was not a hash.\nIt was #$rhash# which was this reference:".ref($rhash)."\n");
1200 0           return;
1201             }
1202 0           print("_dump_keys: The keys for $rhash are:\n");
1203 0           foreach (sort keys %$rhash) {
1204 0           print("$_\n");
1205             }
1206             }
1207              
1208             =head2 _dump_base_accuracies()
1209              
1210             Title : _dump_base_accuracies()
1211             Usage : $self->_dump_base_accuracies();
1212             Function: Dump out the v3 base accuracies in an easy to read format.
1213             Returns : Nothing.
1214             Args : None.
1215             Notes : A debugging method.
1216              
1217             =cut
1218              
1219             sub _dump_base_accuracies {
1220 0     0     my $self = shift;
1221 0           print("Dumping base accuracies! for v3\n");
1222 0           print("There are this many elements in a,c,g,t:\n");
1223 0           print(scalar(@{$self->{'text'}->{'v3_base_accuracy_a'}}).",".scalar(@{$self->{'text'}->{'v3_base_accuracy_c'}}).",".scalar(@{$self->{'text'}->{'v3_base_accuracy_g'}}).",".scalar(@{$self->{'text'}->{'v3_base_accuracy_t'}})."\n");
  0            
  0            
  0            
  0            
1224 0           my $number_traces = scalar(@{$self->{'text'}->{'v3_base_accuracy_a'}});
  0            
1225 0           for (my $counter=0; $counter < $number_traces; $counter++ ) {
1226 0           print("$counter\t");
1227 0           print $self->{'text'}->{'v3_base_accuracy_a'}->[$counter]."\t";
1228 0           print $self->{'text'}->{'v3_base_accuracy_c'}->[$counter]."\t";
1229 0           print $self->{'text'}->{'v3_base_accuracy_g'}->[$counter]."\t";
1230 0           print $self->{'text'}->{'v3_base_accuracy_t'}->[$counter]."\t";
1231 0           print("\n");
1232             }
1233             }
1234              
1235             =head2 _dump_peak_indices_incoming()
1236              
1237             Title : _dump_peak_indices_incoming()
1238             Usage : $self->_dump_peak_indices_incoming();
1239             Function: Dump out the v3 peak indices in an easy to read format.
1240             Returns : Nothing.
1241             Args : None.
1242             Notes : A debugging method.
1243              
1244             =cut
1245              
1246             sub _dump_peak_indices_incoming {
1247 0     0     my $self = shift;
1248 0           print("Dump peak indices incoming!\n");
1249 0           my $length = $self->{'bases'};
1250 0           print("The length is $length\n");
1251 0           for (my $count=0; $count < $length; $count++) {
1252 0           print("$count\t$self->{parsed}->{peak_indices}->[$count]\n");
1253             }
1254             }
1255              
1256             =head2 _dump_base_accuracies_incoming()
1257              
1258             Title : _dump_base_accuracies_incoming()
1259             Usage : $self->_dump_base_accuracies_incoming();
1260             Function: Dump out the v3 base accuracies in an easy to read format.
1261             Returns : Nothing.
1262             Args : None.
1263             Notes : A debugging method.
1264              
1265             =cut
1266              
1267             sub _dump_base_accuracies_incoming {
1268 0     0     my $self = shift;
1269 0           print("Dumping base accuracies! for v3\n");
1270             # print("There are this many elements in a,c,g,t:\n");
1271             # print(scalar(@{$self->{'parsed'}->{'v3_base_accuracy_a'}}).",".scalar(@{$self->{'text'}->{'v3_base_accuracy_c'}}).",".scalar(@{$self->{'text'}->{'v3_base_accuracy_g'}}).",".scalar(@{$self->{'text'}->{'v3_base_accuracy_t'}})."\n");
1272 0           my $number_traces = $self->{'bases'};
1273 0           for (my $counter=0; $counter < $number_traces; $counter++ ) {
1274 0           print("$counter\t");
1275 0           foreach (qw(A T G C)) {
1276 0           print $self->{'parsed'}->{'base_accuracies'}->{$_}->[$counter]."\t";
1277             }
1278 0           print("\n");
1279             }
1280             }
1281              
1282              
1283             =head2 _dump_comments()
1284              
1285             Title : _dump_comments()
1286             Usage : $self->_dump_comments();
1287             Function: Debug dump the comments section from the scf.
1288             Returns : Nothing.
1289             Args : Nothing.
1290             Notes : None.
1291              
1292             =cut
1293              
1294             sub _dump_comments {
1295 0     0     my ($self) = @_;
1296 0           warn ("SCF comments:\n");
1297 0           foreach my $k (keys %{$self->{'comments'}}) {
  0            
1298 0           warn ("\t {$k} ==> ", $self->{'comments'}->{$k}, "\n");
1299             }
1300             }
1301              
1302              
1303              
1304             1;
1305             __END__