4 CXGN::Marker::PCR::Experiment
8 John Binns <zombieite@gmail.com>
12 PCR experiment object for both retrieving and inserting marker experiment data.
18 package CXGN
::Marker
::PCR
::Experiment
;
21 ###use CXGN::Accession;
22 use CXGN
::Tools
::Text
;
24 use CXGN
::DB
::SQLWrappers
;
25 use CXGN
::Marker
::Tools
;
26 use CXGN
::DB
::Connection
;
30 my $experiment_for_viewing=CXGN::Marker::PCR::Experiment->new($dbh,$pcr_experiment_id);
31 my $experiment_for_storing=CXGN::Marker::PCR::Experiment->new($dbh);
37 my ( $dbh, $pcr_experiment_id ) = @_;
38 my $self = bless( {}, $class );
39 if ( CXGN
::DB
::Connection
::is_valid_dbh
($dbh) ) {
43 croak
("'$dbh' is not a valid dbh");
45 if ($pcr_experiment_id) {
48 my $pcr_query = $self->{dbh
}->prepare( "
50 marker_experiment.marker_id,
51 marker_experiment.location_id,
52 pcr_experiment.pcr_experiment_id,
65 left join marker_experiment using (pcr_experiment_id)
69 $pcr_query->execute($pcr_experiment_id);
70 my $pcr_hashref = $pcr_query->fetchrow_hashref();
72 # This was causing the page to die for markers 9654 and 9615. Not sure why this problem should
73 # suddenly turn up. These markers had entries in pcr_experiment but not in marker_experiment,
74 # so John considered them valid, but "orphan" experiments. There is a query in CXGN/Marker.pm
75 # that specifically queries for orphan experiments. That's fine, but then the following check
76 # fails. For now I'm just changing the field it checks. This shouldn't break anything. -beth, 2007-03-21
77 # unless($pcr_hashref->{marker_id})
78 unless ( $pcr_hashref->{pcr_experiment_id
} ) {
80 "Orphan PCR experiment object created with ID of '$pcr_experiment_id'--there is no marker_experiment entry for this experiment";
82 unless ( $pcr_hashref->{pcr_experiment_id
} ) {
83 croak
"PCR experiment not found with ID of '$pcr_experiment_id'";
85 while ( my ( $key, $value ) = each %$pcr_hashref ) {
86 $self->{$key} = $value;
88 $self->{predicted
} ?
$self->{predicted
} = 't' : $self->{predicted
} =
91 #get primers, if they are present
93 $dbh->prepare('select sequence from sequence where sequence_id=?');
94 $q->execute( $self->{primer_id_fwd
} );
95 ( $self->{fwd_primer
} ) = $q->fetchrow_array();
96 $q->execute( $self->{primer_id_rev
} );
97 ( $self->{rev_primer
} ) = $q->fetchrow_array();
99 $q->execute( $self->{primer_id_pd
} );
100 ( $self->{dcaps_primer
} ) = $q->fetchrow_array();
105 "SELECT stock.stock_id,band_size,multiple_flag FROM pcr_exp_accession inner join pcr_product using(pcr_exp_accession_id) inner join stock on(pcr_exp_accession.stock_id=stock.stock_id) WHERE enzyme_id is null and pcr_experiment_id=?"
107 $q->execute( $self->{pcr_experiment_id
} );
108 $sizes = $q->fetchall_arrayref();
110 $self->{pcr_bands
} = $self->query_results_to_bands_hash($sizes);
113 "SELECT stock.stock_id,band_size,multiple_flag FROM pcr_exp_accession inner join pcr_product using(pcr_exp_accession_id) inner join stock on(pcr_exp_accession.stock_id=stock.stock_id) WHERE enzyme_id is not null and pcr_experiment_id=?"
115 $q->execute( $self->{pcr_experiment_id
} );
116 $sizes = $q->fetchall_arrayref();
118 $self->{pcr_digest_bands
} =
119 $self->query_results_to_bands_hash($sizes);
124 "SELECT enzyme_id,enzyme_name FROM pcr_exp_accession inner join pcr_product using(pcr_exp_accession_id) inner join enzymes using(enzyme_id) where pcr_experiment_id=?"
126 $q->execute( $self->{pcr_experiment_id
} );
127 ( $self->{enzyme_id
}, $self->{enzyme
} ) = $q->fetchrow_array()
128 ; #only fetching one row, because they all should be the same. there should be both db and api constraints ensuring that.
130 else #else we're creating and empty object
133 #initialize empty object--we want some things to have a default value, so the object it will be consistent
134 #and able to be worked with even if you haven't set its predicted field, for instance
135 $self->{predicted
} = 'f';
141 =head2 pcr_experiment_id
143 my $id=$experiment->pcr_experiment_id();
145 Returns the PCR experiment ID for this experiment. This cannot be set. It is set when the object is initially retrieved, or when it is stored.
149 #this function cannot be used as a setter, since this id is assigned by the database
150 sub pcr_experiment_id
{
152 return $self->{pcr_experiment_id
};
157 my $experiment=CXGN::Marker::PCR::Experiment->new($dbh,$pcr_experiment_id);
158 my $experiment_for_comparison=CXGN::Marker::PCR::Experiment->new($dbh,$possible_match_id);
159 if($experiment->equals($experiment_for_comparison)){print"They are the same!";}
163 ##########################################
164 # compare this pcr experiment with another
165 ##########################################
167 sub check_pcr_band_arrays
{
168 my ( $stock, $pcr_hash_1, $pcr_hash_2 ) = @_;
170 my $comp = Array
::Compare
->new();
173 "PCR bands (or digest bands) entry for stock '$stock' does not appear to be array ref";
175 unless ( $pcr_hash_1->{$stock} and $pcr_hash_2->{$stock} ) { return 0 }
176 unless ( ( ref( $pcr_hash_1->{$stock} ) eq 'ARRAY' ) ) { croak
$croaking }
177 unless ( ( ref( $pcr_hash_2->{$stock} ) eq 'ARRAY' ) ) { croak
$croaking }
179 # Array::Compare::perm returns true if lists are the same or permutations of each other (bands may have been stored in any order)
180 unless ( $comp->perm( $pcr_hash_1->{$stock}, $pcr_hash_2->{$stock} ) ) {
191 unless ( $other->isa('CXGN::Marker::PCR::Experiment') ) {
192 croak
"Must send in a PCR experiment object to equals function";
194 unless ( $self->marker_id() and $other->marker_id() ) {
196 "Must set both PCR experiment objects' marker IDs before comparing\n-----\nself:\n"
199 . $other->as_string();
201 unless ( $self->protocol() and $other->protocol() ) {
203 "Must set both PCR experiment objects' protocols before comparing";
205 unless ( $self->predicted() eq 'f' or $self->predicted() eq 't' ) {
206 croak
"Can't check for equality; invalid predicted field for self:\n"
207 . $self->as_string();
209 unless ( $other->predicted() eq 'f' or $other->predicted() eq 't' ) {
211 "Can't check for equality; invalid predicted field for other object:\n"
212 . $other->as_string();
214 if ( $self->marker_id() ne $other->marker_id() ) { return 0 }
215 if ( $self->fwd_primer() ne $other->fwd_primer() ) { return 0 }
216 if ( $self->rev_primer() ne $other->rev_primer() ) { return 0 }
217 if ( $self->primer_type() ne $other->primer_type() ) { return 0 }
218 if ( $self->enzyme() ne $other->enzyme() ) { return 0 }
219 if ( $self->predicted() ne $other->predicted() ) { return 0 }
220 if ( $self->protocol eq 'RFLP' and $other->protocol ne 'RFLP' ) { return 0 }
221 if ( $self->protocol ne 'RFLP' and $other->protocol eq 'RFLP' ) { return 0 }
223 my $pcr_hash_1 = $self->{pcr_bands
};
224 my $pcr_hash_2 = $other->{pcr_bands
};
227 for my $k ( keys( %{$pcr_hash_1} ) ) {
228 delete $pcr_hash_1->{$k} if ( @
{ $pcr_hash_1->{$k} } == 0 );
230 for my $k ( keys( %{$pcr_hash_2} ) ) {
231 delete $pcr_hash_2->{$k} if ( @
{ $pcr_hash_2->{$k} } == 0 );
234 # check pcr band arrays for all stocks in first object
235 for my $stock ( keys( %{$pcr_hash_1} ) ) {
236 unless ( &check_pcr_band_arrays
( $stock, $pcr_hash_1, $pcr_hash_2 ) ) {
241 # then check pcr band arrays for all stocks in second object, in case the second has stocks the first doesn't
242 for my $stock ( keys( %{$pcr_hash_2} ) ) {
243 unless ( &check_pcr_band_arrays
( $stock, $pcr_hash_1, $pcr_hash_2 ) ) {
248 $pcr_hash_1 = $self->{pcr_digest_bands
};
249 $pcr_hash_2 = $other->{pcr_digest_bands
};
252 for my $k ( keys( %{$pcr_hash_1} ) ) {
253 delete $pcr_hash_1->{$k} if ( @
{ $pcr_hash_1->{$k} } == 0 );
255 for my $k ( keys( %{$pcr_hash_2} ) ) {
256 delete $pcr_hash_2->{$k} if ( @
{ $pcr_hash_2->{$k} } == 0 );
259 # check pcr digest band arrays for all stocks in first object
260 for my $stock ( keys( %{$pcr_hash_1} ) ) {
261 unless ( &check_pcr_band_arrays
( $stock, $pcr_hash_1, $pcr_hash_2 ) ) {
266 # then check pcr digest band arrays for all accessions in second object, in case the second has accessions the first doesn't
267 for my $stock ( keys( %{$pcr_hash_2} ) ) {
268 unless ( &check_pcr_band_arrays
( $stock, $pcr_hash_1, $pcr_hash_2 ) ) {
273 #only compare mg and temp IF they are present in BOTH objects... see note below
274 if ( ( $self->mg_conc() and $other->mg_conc() )
275 and ( $self->mg_conc() != $other->mg_conc() ) )
279 if ( ( $self->temp() and $other->temp() )
280 and ( $self->temp() != $other->temp() ) )
286 #we did not compare missing temperature or mg concentration values, because yimin says experiments that are so similar
287 #that the only difference is that one is missing a temp or mg conc are the same experiment
288 #we did not compare additional_enzymes, because this is just a long text notes field, not essential data for the experiment,
289 #and frequently subject to minor changes in its text. this is just feinan's extra COSII PCR data field.
296 Returns its pcr_experiment_id if it already exists in the database, or undef if not.
305 unless ( $self->{marker_id
} ) {
307 "Cannot test for an experiment's existence without knowing which marker it goes with--store marker and set experiment's marker ID before storing experiments";
309 unless ( $self->{protocol
} ) {
311 "I doubt an experiment like this one exists, since it has no experiment protocol. Set to unknown if necessary.";
313 if ( $self->{pcr_experiment_id
} ) {
315 #warn"I think it's pretty obvious that this experiment exists, since it seems to have been loaded from the database, or recently stored to the database--it already has an id of $self->{pcr_experiment_id}";
316 return $self->{pcr_experiment_id
};
318 unless ( $self->predicted() eq 'f' or $self->predicted() eq 't' ) {
319 croak
"Can't check for existence; invalid predicted field for self:\n"
320 . $self->as_string();
322 my $possible_matches_query = $self->{dbh
}->prepare( "
329 and pcr_experiment_id is not null
331 $possible_matches_query->execute( $self->marker_id() );
332 while ( my ($possible_match_id) =
333 $possible_matches_query->fetchrow_array() )
336 #print"possible match id: $possible_match_id\n";
337 my $experiment_for_comparison =
338 CXGN
::Marker
::PCR
::Experiment
->new( $self->{dbh
},
339 $possible_match_id );
340 if ( $self->equals($experiment_for_comparison) ) {
341 $self->{pcr_experiment_id
} = $experiment_for_comparison
342 ->{pcr_experiment_id
}; #ok, we've been found to already exist, so set our pcr_experiment_id
343 return $self->{pcr_experiment_id
};
349 =head2 store_unless_exists
351 Stores this experiment in the database, as long as it does not exist. If it does not exist and it is stored, this function will return its new pcr_experiment_id. If the experiment does exists, it will set the pcr_experiment_id but NOT return it.
355 sub store_unless_exists
{
358 if ( $self->exists() ) { return }
360 unless ( $self->{marker_id
} ) {
361 croak
"Cannot store experiment without marker ID";
363 unless ( $self->{protocol
} ) {
365 "Cannot store experiment without protocol. Use 'unknown' if necessary.";
367 unless ( $self->predicted() eq 'f' or $self->predicted() eq 't' ) {
368 croak
"Can't store; invalid predicted field for self:\n"
369 . $self->as_string();
371 if ( $self->{pcr_experiment_id
} ) {
373 "This experiment appears to have been stored already or created from an existing database entry";
375 ##################### TODO #########################
376 #if we already have a PCR experiment ID, and someone
377 #calls 'store_unless_exists', this is a perfectly
378 #reasonable use case, but i have not implemented it yet.
379 #they might want to modify an existing experiment. for
380 #instance, it is common that someone might add digested
381 #bands later, after having loaded an experiment with
382 #only regular pcr bands a few months before. this object cannot yet handle this
383 #situation. that is why it croaks here. if you need to add
384 #this functionality, add it here. it would consist of some
385 #kind of object integrity checking and checking for values
386 #which have been added or modified and adding or modifying
387 #those same values in the database. alternatively, you may
388 #just want to write another class--CXGN::Marker::PCR::Experiment::Modfiable
389 #or something like that which has fewer checks and just
390 #directly accesses data in the database using an object
391 #like lukas's modifiable form object.
392 if ( $self->{pcr_digest_bands
} ) {
393 unless ( $self->{enzyme_id
} ) {
394 croak
"Must have an enzyme set to store digest bands";
398 my $dbh = $self->{dbh
};
399 my $sql = CXGN
::DB
::SQLWrappers
->new( $self->{dbh
} );
401 if ( $self->fwd_primer() ) {
403 $sql->insert_unless_exists( 'sequence',
404 { 'sequence' => $self->fwd_primer() } );
405 $self->{fwd_primer_id
} = $fwd_info->{id
};
407 if ( $self->rev_primer() ) {
409 $sql->insert_unless_exists( 'sequence',
410 { 'sequence' => $self->rev_primer() } );
411 $self->{rev_primer_id
} = $rev_info->{id
};
414 #print"INSERTING:\n".$self->as_string();
416 my $pcr_exp_insert = $self->{dbh
}->prepare( '
417 insert into sgn.pcr_experiment (
426 values (?,?,?,?,?,?,?)
428 $pcr_exp_insert->execute(
429 $self->{mg_concentration
}, $self->{annealing_temp
},
430 $self->{fwd_primer_id
}, $self->{rev_primer_id
},
431 $self->{primer_type
}, $self->{additional_enzymes
},
434 $self->{pcr_experiment_id
} = $self->{dbh
}->last_insert_id('pcr_experiment')
435 or croak
"Could not get last_insert_id from pcr_experiment";
439 keys( %{ $self->{pcr_bands
} } ),
440 keys( %{ $self->{pcr_digest_bands
} } )
446 # dummy value for now, until we get a pcr_exp_accession_id
449 $self->{dbh
}->prepare(
450 'insert into sgn.pcr_exp_accession (pcr_experiment_id,stock_id) values (?,?)'
452 my $pcr_band_insert =
453 $self->{dbh
}->prepare(
454 'insert into sgn.pcr_product (pcr_exp_accession_id,enzyme_id,multiple_flag,band_size,predicted) values (?,?,?,?,?)'
457 for my $stock_id ( keys(%stocks) ) {
458 $exp_acc_insert->execute( $self->{pcr_experiment_id
}, $stock_id );
459 $stocks{$stock_id} = $self->{dbh
}->last_insert_id('pcr_exp_accession')
460 or croak
"Could not get last_insert_id from pcr_exp_accession";
463 my @stock_pcr_digest_bands;
464 if ( $self->{pcr_bands
}->{$stock_id} ) {
465 @stock_pcr_bands = @
{ $self->{pcr_bands
}->{$stock_id} };
467 if ( $self->{pcr_digest_bands
}->{$stock_id} ) {
468 @stock_pcr_digest_bands =
469 @
{ $self->{pcr_digest_bands
}->{$stock_id} };
471 if ( $stock_pcr_bands[0] ) { #if there is at least one value in the pcr bands list for this stock
472 for my $band (@stock_pcr_bands) {
474 #if the band entry starts with an m, it means multiple bands, so set the multiple flag. no enzyme insert for regular pcr bands.
475 if ( $band =~ /^m/i ) {
476 $pcr_band_insert->execute( $stocks{$stock_id}, undef, 1,
477 undef, $self->{predicted
} );
480 $pcr_band_insert->execute( $stocks{$stock_id}, undef, undef,
481 $band, $self->{predicted
} );
485 if ( $stock_pcr_digest_bands[0] ) {
486 # if there is at least one value in the pcr digest bands list for this stock
487 #if the band entry starts with an m, it means multiple bands, so set the multiple flag.
488 for my $band (@stock_pcr_digest_bands) {
489 if ( $band =~ /^m/i ) {
490 $pcr_band_insert->execute( $stocks{$stock_id},
491 $self->{enzyme_id
}, 1, undef, $self->{predicted
} );
494 $pcr_band_insert->execute( $stocks{$stock_id},
495 $self->{enzyme_id
}, undef, $band, $self->{predicted
} );
501 #and now for a final test of this object
502 if ( my $oops_id = $self->store_unless_exists() ) {
504 "Oops, this object isn't working correctly. Immediately after being stored with ID "
505 . "'$self->{pcr_experiment_id}', it tried to store itself again as a test, and succeeded with ID '$oops_id' "
506 . "(it should have failed, because it was already inserted!)";
510 return $self->{pcr_experiment_id
};
513 =head2 update_additional_enzymes
515 #this will actually update the pcr experiment entry in the database
516 $experiment->update_additional_enzymes('All possible enzymes for blah blah blah are blah blah blah....');
520 #storing function for additional_enzymes field. this data is not essential to the experiment. it is just a text field with
521 #notes that feinan wants to show up for cosii markers, so it has no special checks or anything.
522 sub update_additional_enzymes
{
524 my ($additional_enzymes) = @_;
525 if ( length($additional_enzymes) > 1023 ) {
527 "Additional enzymes field contents size limit is exceeded by string '$additional_enzymes'";
529 unless ( $self->{pcr_experiment_id
} ) {
531 "This experiment object does not appear to have been loaded or inserted into the database yet, so you cannot update its enzymes";
534 $self->{dbh
}->prepare(
535 'update pcr_experiment set additional_enzymes=? where pcr_experiment_id=?'
537 $sth->execute( $additional_enzymes, $self->{pcr_experiment_id
} );
542 #print out the whole experiment, for debugging, or for loading script output
543 print $experiment->as_string();
547 #######################
548 # display for debugging
549 #######################
553 $string .= "<pcr_experiment>\n";
555 if ( $self->{marker_id
} ) {
557 CXGN
::Marker
->new( $self->{dbh
}, $self->{marker_id
} )
558 ->name_that_marker();
561 @marker_names = ('<no marker associated yet>');
563 $string .= "\tMarker: @marker_names\n";
564 $string .= "\tPCR experiment ID: $self->{pcr_experiment_id}\n";
565 if ( $self->{location_id
} ) {
567 "\tThis is a mapping experiment; location ID: $self->{location_id}\n";
571 "\tThis experiment does not yet have a map location associated with it in the marker_experiment table\n";
573 $string .= "\tProtocol: $self->{protocol}\n";
575 "\tPrimers: $self->{fwd_primer} (fwd)\t\t$self->{rev_primer} (rev)\n";
576 my $pt = $self->{primer_type
};
578 $string .= "\tPrimer type: $pt\n";
579 my $mg = $self->{mg_concentration
};
581 my $temp = $self->{annealing_temp
};
583 $string .= "\tConditions: $mg MG - $temp C\n";
584 if ( $self->{enzyme
} ) { $string .= "\tEnzyme: $self->{enzyme}\n"; }
585 $string .= "\tBands:\n";
586 my $bands = $self->pcr_bands_hash_of_strings();
588 if ( $bands and %{$bands} ) {
589 for my $stock ( keys( %{$bands} ) ) {
591 #$string.="\t".CXGN::Accession->new($self->{dbh},$accession)->extra_verbose_name().": ".$bands->{$accession}."\n";
592 $string .= "\t$stock : " . $bands->{$stock} . "\n";
595 $string .= "\tDigest bands:\n";
596 $bands = $self->pcr_digest_bands_hash_of_strings();
597 if ( $bands and %{$bands} ) {
598 for my $stock ( keys( %{$bands} ) ) {
599 $string .= "\t$stock : " . $bands->{$stock} . "\n";
602 $string .= "\tPredicted: $self->{predicted}\n";
603 $string .= "</pcr_experiment>\n";
606 =head2 query_results_to_bands_hash
608 For internal use. Converts bands query results into a form that can be stored easily.
612 ###########################################
613 # helpful functions mainly for internal use
614 ###########################################
615 sub query_results_to_bands_hash
{
619 for my $row ( @
{$sizes} ) {
620 my ( $stock, $band_size, $multiple_flag ) = @
{$row};
621 if ( $stock and ( $band_size or $multiple_flag ) ) {
624 $insert_value = $band_size;
626 elsif ($multiple_flag) {
627 $insert_value = 'Multiple';
629 push( @
{ $bands{$stock} }, $insert_value );
632 croak
"Unable to load bands hash";
638 =head2 join_bands_hash
640 For internal use. Converts bands into a more useful form.
644 sub join_bands_hash
{
646 my ($bands_hash) = @_;
647 my %expected_structure;
648 for my $stock ( keys( %{$bands_hash} ) ) {
649 $expected_structure{$stock} = join( '+', @
{ $bands_hash->{$stock} } );
651 if ( keys(%expected_structure) ) #if there are values to return, return them
653 return \
%expected_structure;
662 my $id=$experiment->marker_id();
664 Gets the marker_id of marker which is involved in this experiment.
666 $experiment->marker_id($marker_id);
668 Sets the marker_id of marker which is involved in this experiment.
679 unless ( $value =~ /^\d+$/ ) {
680 croak
"Marker ID must be a number, not '$value'";
683 CXGN
::Marker
::Tools
::is_valid_marker_id
( $self->{dbh
}, $value ) )
685 croak
"Marker ID '$value' does not exist in the database";
687 $self->{marker_id
} = $value;
689 return $self->{marker_id
};
694 Returns or sets the forward primer.
702 $value = $self->test_and_clean_primer($value);
703 $self->{fwd_primer
} = $value;
705 return $self->{fwd_primer
};
710 Returns or sets the reverse primer.
718 $value = $self->test_and_clean_primer($value);
719 $self->{rev_primer
} = $value;
721 return $self->{rev_primer
};
728 $value = $self->test_and_clean_primer($value);
729 $self->{dcaps_primer
} = $value;
731 return $self->{dcaps_primer
};
736 Returns or sets the primer type.
744 unless ( $value eq 'iUPA' or $value eq 'eUPA' ) {
745 croak
"'$value' is not a valid primer type";
747 $self->{primer_type
} = $value;
749 return $self->{primer_type
};
754 Returns or sets the magnesium concentration.
762 unless ( CXGN
::Tools
::Text
::is_number
($value) ) {
763 croak
"'$value' is not a valid number for mg concentration";
765 $self->{mg_concentration
} = $value;
767 return $self->{mg_concentration
};
772 Returns or sets the temperature. If you send in Fahrenheit you must have an 'F' after the degrees. It will convert it to Celsius for you.
780 unless ( $value =~ /^(\d*?\.?\d*?)[cf]?$/i ) {
781 croak
"'$value' is an invalid anneal temp";
783 $value =~ s/C$//i; #strip C for Celsius
785 s/F$//i ) #if it was an F for Fahrenheit, convert it to Celsius
787 $value = ( $value + 40 ) * 5 / 9;
789 $self->{annealing_temp
} = $value;
791 return $self->{annealing_temp
};
796 Returns or sets the experiment protocol.
804 unless ( $protocol eq 'AFLP'
805 or $protocol eq 'CAPS'
806 or $protocol eq 'RAPD'
807 or $protocol eq 'SNP'
808 or $protocol eq 'SSR'
809 or $protocol eq 'RFLP'
810 or $protocol eq 'PCR'
811 or $protocol eq 'unknown'
812 or $protocol =~ /Indel/i )
814 croak
"Protocol '$protocol' is invalid.";
816 if ( $protocol eq 'RFLP' ) {
817 croak
"RFLP is not a valid PCR experiment protocol";
819 $self->{protocol
} = $protocol;
821 return $self->{protocol
};
826 Returns or sets the enzyme used to get the digest bands.
834 $enzyme =~ s/\s//g unless $enzyme =~ /and/; #clear whitespace
835 $enzyme =~ s/(1+)$/'I' x length($1)/e; #1 -> I
837 # this isn't working for some reason
839 if ( $enzyme eq 'PCR' ) { $enzyme = 'amplicon difference' }
841 # TODO: change this to undef once everything is working
842 elsif ( $enzyme eq 'SNP' ) { $enzyme = 'unknown' }
843 elsif ( !$enzyme ) { $enzyme = 'unknown' }
845 unless ( $self->{enzyme_id
} =
846 CXGN
::Marker
::Tools
::get_enzyme_id
( $self->{dbh
}, $enzyme ) )
849 "'$enzyme' is not a valid enzyme (you may need to add it to the enzyme table)";
852 $self->{enzyme
} = $enzyme;
855 return $self->{enzyme
};
858 =head2 additional_enzymes
860 Returns or sets Feinan^s COSII additional_enzymes field.
864 sub additional_enzymes
{
867 if ($value) { $self->{additional_enzymes
} = $value; }
868 return $self->{additional_enzymes
};
873 Returns or sets whether or not the band sizes stored in this object are predicted.
882 unless ( $value eq 't' or $value eq 'f' ) {
883 croak
"Predicted must be either 't' or 'f'";
885 $self->{predicted
} = $value;
887 return $self->{predicted
};
890 =head2 add_pcr_bands_for_stock
892 $experiment->add_pcr_bands_for_stock('250+400','LA716');
894 Note: add_pcr_bands_for_accession is deprecated.
898 #example use: $created_experiment->add_pcr_bands_string_for_accession('750+900','LA925');
900 sub add_pcr_bands_for_accession
{
901 warn "add_pcr_bands_for_accession is deprecated\n";
902 shift->add_pcr_bands_for_stock(@_);
905 sub add_pcr_bands_for_stock
{
907 my ( $bands_string, $stock_name ) = @_;
909 # my $accession_object=CXGN::Accession->new($self->{dbh},$accession);
910 # unless($accession_object)
912 # croak"Accession '$stock_name' not found\n";
915 my $stock_id = $self->get_stock_id_with_stock_name($stock_name);
917 #my $accession_id=$accession_object->accession_id();
918 unless ($stock_id) { croak
("Accession '$stock_name' not found"); }
919 my @bands = split( /\+/, $bands_string );
920 $self->{pcr_bands
}->{$stock_id} = \
@bands;
921 $self->{pcr_bands
} = $self->test_and_clean_bands( $self->{pcr_bands
} );
924 =head2 add_pcr_digest_bands_for_stock
926 $experiment->add_pcr_digest_bands_for_stock('250+400','LA716');
928 Side effect: Dies if the stock is not valid.
929 Note: add_pcr_digest_bands_for_accession is deprecated.
933 sub add_pcr_digest_bands_for_accession
{
934 warn "add_pcr_digest_bands_for_accession is deprecated.\n";
935 shift->add_pcr_digest_bands_for_stock(@_);
938 #example use: $created_experiment->add_pcr_digest_bands_string_for_accession('multiple','LA716');
939 sub add_pcr_digest_bands_for_accession
{
941 my ( $bands_string, $stock_name ) = @_;
943 # my $accession_object=CXGN::Accession->new($self->{dbh},$accession);
944 # unless($accession_object)
946 # croak"Accession '$accession' not found\n";
948 # my $accession_id=$accession_object->accession_id();
950 my $stock_id = $self->get_stock_id_with_stock_name($stock_name);
952 unless ($stock_id) { croak
("Accession '$stock_name' not found"); }
953 my @bands = split( /\+/, $bands_string );
954 $self->{pcr_digest_bands
}->{$stock_id} = \
@bands;
955 $self->{pcr_digest_bands
} =
956 $self->test_and_clean_bands( $self->{pcr_digest_bands
} );
959 sub get_stock_id_with_stock_name
{
961 my $stock_name = shift;
964 $self->{dbh
}->prepare("SELECT stock_id FROM stock where stock_name=?");
965 $sth->execute($stock_name);
967 my ($stock_id) = $sth->fetchrow_array();
971 ######################
972 # convenient accessors
973 ######################
975 =head2 pcr_bands_hash_of_strings
977 Get PCR bands in a form that CXGN::Marker::PCR likes.
981 sub pcr_bands_hash_of_strings
{
983 return $self->join_bands_hash( $self->{pcr_bands
} );
986 =head2 pcr_digest_bands_hash_of_strings
988 Get PCR digest bands in a form that CXGN::Marker::PCR likes.
992 sub pcr_digest_bands_hash_of_strings
{
994 return $self->join_bands_hash( $self->{pcr_digest_bands
} );
997 =head2 test_and_clean_primer
1006 sub test_and_clean_primer
{
1013 $primer =~ /[ATGCatgc]+/ ) #primers are known base pairs start to finish
1015 croak
"'$primer' is not a valid primer";
1017 return uc($primer); #uppercase sequence data
1020 =head2 test_and_clean_bands
1026 #bands must look like this: {'LA716'=>['Multiple'],'LA925'=>[750,900]}
1027 sub test_and_clean_bands
{
1030 unless ( ref($bands) eq 'HASH' ) {
1031 croak
"Bands must be hash ref";
1033 for my $stock_id ( keys( %{$bands} ) ) {
1035 # unless(CXGN::Accession->new($self->{dbh},$accession_id)->accession_id()){croak"Accession '$accession_id' not found";}
1037 unless ( $self->valid_stock_id($stock_id) ) {
1038 croak
"stock_id $stock_id is not valid!";
1041 unless ( ref( $bands->{$stock_id} ) eq 'ARRAY' ) {
1042 croak
"Bands hash ref must contain array refs";
1045 @
{ $bands->{$stock_id}
1046 }; #copy this array out to make the following code more readable, maybe
1047 for my $index ( 0 .. $#bands_array ) {
1048 $bands_array[$index] = CXGN
::Tools
::Text
::remove_all_whitespaces
(
1049 lc( $bands_array[$index] ) );
1051 if ( $bands_array[$index] =~ /^m/i ) {
1052 $bands_array[$index] = 'Multiple';
1055 unless ( $bands_array[$index] eq 'Multiple' ) {
1056 $bands_array[$index] = int( $bands_array[$index] );
1059 unless ( ( $bands_array[$index] eq 'Multiple' )
1060 or ( CXGN
::Tools
::Text
::is_number
( $bands_array[$index] ) ) )
1062 croak
"'$bands_array[$index]' is an invalid band size";
1065 $bands->{$stock_id} = \
@bands_array; #copy this array back in
1070 sub _valid_stock_id
{
1072 my $stock_id = shift;
1074 $self->{dbh
}->prepare("SELECT stock_id FROM stock WHERE stock_id=?");
1075 $sth->execute($stock_id);
1076 my ($stock_id) = $sth->fetchrow_array();
1080 ##store the primers, or any other sequnces linked, in the sequence table, and link to pcr_experiment##
1082 =head2 store_sequence
1084 Usage: $self->store_sequence($sequence_name, $sequence);
1085 Desc: store a primer, or any other sequence type, of the pcr_experiment in the sequence table ,
1086 and link to the experiment using pcr_experiment_sequence table.
1088 Args: a string with sequence type, and the sequence string
1089 sequence types should be listed in the cvterm table with cv_name =
1090 'sequence' (this is the namespace for SO http://song.cvs.sourceforge.net/viewvc/song/ontology/so.obo?view=log )
1091 Side Effects: store a new sequence in sgn.sequence, if one does not exist.
1092 Sequences are converted to all upper-case.
1095 my $id = $self->store_sequence('forward_primer','ATCCGTGACGTAC');
1099 sub store_sequence
{
1101 my $sequence_type = shift;
1104 'No sequence for type $sequence_type passed to store_sequence function! \n';
1106 #find if the type is stored in the database
1107 my $q = "SELECT cvterm_id FROM public.cvterm
1108 WHERE name ilike ? AND cv_id =
1109 (SELECT cv_id FROM public.cv WHERE cv.name ilike ?) ";
1110 my $sth = $self->{dbh
}->prepare($q);
1111 $sth->execute( $sequence_type, 'sequence' );
1112 my ($type_id) = $sth->fetchrow_array();
1114 "Sequence type $sequence_type does not exist in the database!\n Expected to find cvterm $sequence_type with cv_name 'sequence'!\n Please check your databae, and make sure Sequence Ontology is up-to-date\n "
1118 unless ( $seq =~ /[ATGCatgc]+/ ) {
1119 croak
"'$seq' is not a valid sequence";
1121 $seq = uc($seq); #uppercase sequence data
1123 my $sql = CXGN
::DB
::SQLWrappers
->new( $self->{dbh
} );
1125 $sql->insert_unless_exists( 'sequence', { 'sequence' => $seq } );
1127 #does the link exist?
1128 my @ids = $sql->select(
1129 'pcr_experiment_sequence',
1131 sequence_id
=> $sequence->{id
},
1132 pcr_experiment_id
=> $self->{pcr_experiment_id
},
1140 "Insert INTO sgn.pcr_experiment_sequence (sequence_id, pcr_experiment_id, type_id)
1141 VALUES (?,?,?) RETURNING pcr_experiment_sequence_id";
1142 $sth = $self->{dbh
}->prepare($q);
1143 $sth->execute( $sequence->{id
}, $self->{pcr_experiment_id
}, $type_id );
1144 return ( $sth->fetchrow_array() );
1147 warn("link exists , ids = @ids\n");
1151 #my $pcr_seq = $sql->insert_unless_exists('pcr_experiment_sequence' , { 'sequence_id' => $sequence->{id} , 'pcr_experiment_id' => $self->{pcr_experiment_id} , 'type_id' => $type_id } );
1155 ##get the associated sequences and their types from pcr_experiment_sequence##
1157 =head2 get_sequences
1159 Usage: $self->get_sequences
1160 Desc: find the sequences associated with the marker, and their types
1161 Ret: hashref {$sequence_type => [$seq1, $seq2] }
1169 my $q = "SELECT cvterm.name, sequence FROM sgn.pcr_experiment
1170 JOIN sgn.pcr_experiment_sequence USING (pcr_experiment_id)
1171 JOIN sgn.sequence USING (sequence_id)
1172 JOIN public.cvterm on cvterm_id = sgn.pcr_experiment_sequence.type_id
1173 WHERE pcr_experiment.pcr_experiment_id = ?";
1174 my $sth = $self->{dbh
}->prepare($q);
1175 $sth->execute( $self->{pcr_experiment_id
} );
1177 while ( my ( $sequence_type, $sequence ) = $sth->fetchrow_array() ) {
1178 push @
{ $HoA{$sequence_type} }, $sequence;