4 CXGN::Marker::PCR::Experiment
8 John Binns <zombieite@gmail.com>
12 PCR experiment object for both retrieving and inserting marker experiment data.
17 package CXGN
::Marker
::PCR
::Experiment
;
21 use CXGN
::Tools
::Text
;
23 use CXGN
::DB
::SQLWrappers
;
24 use CXGN
::Marker
::Tools
;
25 use CXGN
::DB
::Connection
;
29 my $experiment_for_viewing=CXGN::Marker::PCR::Experiment->new($dbh,$pcr_experiment_id);
30 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))
45 croak
("'$dbh' is not a valid dbh");
47 if($pcr_experiment_id)
51 my $pcr_query=$self->{dbh
}->prepare
54 marker_experiment.marker_id,
55 marker_experiment.location_id,
56 pcr_experiment.pcr_experiment_id,
69 left join marker_experiment using (pcr_experiment_id)
73 $pcr_query->execute($pcr_experiment_id);
74 my $pcr_hashref=$pcr_query->fetchrow_hashref();
76 # This was causing the page to die for markers 9654 and 9615. Not sure why this problem should
77 # suddenly turn up. These markers had entries in pcr_experiment but not in marker_experiment,
78 # so John considered them valid, but "orphan" experiments. There is a query in CXGN/Marker.pm
79 # that specifically queries for orphan experiments. That's fine, but then the following check
80 # fails. For now I'm just changing the field it checks. This shouldn't break anything. -beth, 2007-03-21
81 # unless($pcr_hashref->{marker_id})
82 unless($pcr_hashref->{pcr_experiment_id
})
84 croak
"Orphan PCR experiment object created with ID of '$pcr_experiment_id'--there is no marker_experiment entry for this experiment";
86 unless($pcr_hashref->{pcr_experiment_id
})
88 croak
"PCR experiment not found with ID of '$pcr_experiment_id'";
90 while(my($key,$value)=each %$pcr_hashref)
94 $self->{predicted
}?
$self->{predicted
}='t':$self->{predicted
}='f';
96 #get primers, if they are present
97 my $q=$dbh->prepare('select sequence from sequence where sequence_id=?');
98 $q->execute($self->{primer_id_fwd
});
99 ($self->{fwd_primer
})=$q->fetchrow_array();
100 $q->execute($self->{primer_id_rev
});
101 ($self->{rev_primer
})=$q->fetchrow_array();
104 $q->execute($self->{primer_id_pd
});
105 ($self->{dcaps_primer
})=$q->fetchrow_array();
110 $q=$dbh->prepare("SELECT accession.accession_id,band_size,multiple_flag FROM pcr_exp_accession inner join pcr_product using(pcr_exp_accession_id) inner join accession on(pcr_exp_accession.accession_id=accession.accession_id) WHERE enzyme_id is null and pcr_experiment_id=?");
111 $q->execute($self->{pcr_experiment_id
});
112 $sizes=$q->fetchall_arrayref();
113 if($sizes->[0]){$self->{pcr_bands
}=$self->query_results_to_bands_hash($sizes);}
114 $q=$dbh->prepare("SELECT accession.accession_id,band_size,multiple_flag FROM pcr_exp_accession inner join pcr_product using(pcr_exp_accession_id) inner join accession on(pcr_exp_accession.accession_id=accession.accession_id) WHERE enzyme_id is not null and pcr_experiment_id=?");
115 $q->execute($self->{pcr_experiment_id
});
116 $sizes=$q->fetchall_arrayref();
117 if($sizes->[0]){$self->{pcr_digest_bands
}=$self->query_results_to_bands_hash($sizes);}
120 $q=$dbh->prepare("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=?");
121 $q->execute($self->{pcr_experiment_id
});
122 ($self->{enzyme_id
},$self->{enzyme
})=$q->fetchrow_array();#only fetching one row, because they all should be the same. there should be both db and api constraints ensuring that.
124 else#else we're creating and empty object
126 #initialize empty object--we want some things to have a default value, so the object it will be consistent
127 #and able to be worked with even if you haven't set its predicted field, for instance
128 $self->{predicted
}='f';
134 =head2 pcr_experiment_id
136 my $id=$experiment->pcr_experiment_id();
138 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.
142 #this function cannot be used as a setter, since this id is assigned by the database
143 sub pcr_experiment_id
146 return $self->{pcr_experiment_id
};
151 my $experiment=CXGN::Marker::PCR::Experiment->new($dbh,$pcr_experiment_id);
152 my $experiment_for_comparison=CXGN::Marker::PCR::Experiment->new($dbh,$possible_match_id);
153 if($experiment->equals($experiment_for_comparison)){print"They are the same!";}
157 ##########################################
158 # compare this pcr experiment with another
159 ##########################################
161 sub check_pcr_band_arrays
{
162 my ($accession, $pcr_hash_1, $pcr_hash_2) = @_;
164 my $comp = Array
::Compare
->new();
166 my $croaking = "PCR bands (or digest bands) entry for accession '$accession' does not appear to be array ref";
168 unless ($pcr_hash_1->{$accession} and $pcr_hash_2->{$accession}) { return 0 }
169 unless ((ref($pcr_hash_1->{$accession}) eq 'ARRAY')) { croak
$croaking }
170 unless ((ref($pcr_hash_2->{$accession}) eq 'ARRAY')) { croak
$croaking }
171 # Array::Compare::perm returns true if lists are the same or permutations of each other (bands may have been stored in any order)
172 unless ($comp->perm($pcr_hash_1->{$accession}, $pcr_hash_2->{$accession})) { return 0 }
181 unless ($other->isa('CXGN::Marker::PCR::Experiment')) { croak
"Must send in a PCR experiment object to equals function" }
182 unless ($self->marker_id() and $other->marker_id()) {
183 croak
"Must set both PCR experiment objects' marker IDs before comparing\n-----\nself:\n".
184 $self->as_string()."-----\nother:\n".$other->as_string()
186 unless ($self->protocol() and $other->protocol()) { croak
"Must set both PCR experiment objects' protocols before comparing" }
187 unless ($self->predicted() eq 'f' or $self->predicted() eq 't') {
188 croak
"Can't check for equality; invalid predicted field for self:\n".$self->as_string();
190 unless ($other->predicted() eq 'f' or $other->predicted() eq 't') {
191 croak
"Can't check for equality; invalid predicted field for other object:\n".$other->as_string();
193 if ($self->marker_id() ne $other->marker_id()) { return 0 }
194 if ($self->fwd_primer() ne $other->fwd_primer()) { return 0 }
195 if ($self->rev_primer() ne $other->rev_primer()) { return 0 }
196 if ($self->primer_type() ne $other->primer_type()) { return 0 }
197 if ($self->enzyme() ne $other->enzyme()) { return 0 }
198 if ($self->predicted() ne $other->predicted()) { return 0 }
199 if ($self->protocol eq 'RFLP' and $other->protocol ne 'RFLP') { return 0 }
200 if ($self->protocol ne 'RFLP' and $other->protocol eq 'RFLP') { return 0 }
202 my $pcr_hash_1 = $self->{pcr_bands
};
203 my $pcr_hash_2 = $other->{pcr_bands
};
205 for my $k (keys(%{$pcr_hash_1})) { delete $pcr_hash_1->{$k} if (@
{$pcr_hash_1->{$k}} == 0) }
206 for my $k (keys(%{$pcr_hash_2})) { delete $pcr_hash_2->{$k} if (@
{$pcr_hash_2->{$k}} == 0) }
208 # check pcr band arrays for all accessions in first object
209 for my $accession (keys(%{$pcr_hash_1})) { unless (&check_pcr_band_arrays
($accession, $pcr_hash_1, $pcr_hash_2)) { return 0 } }
211 # then check pcr band arrays for all accessions in second object, in case the second has accessions the first doesn't
212 for my $accession (keys(%{$pcr_hash_2})) { unless (&check_pcr_band_arrays
($accession, $pcr_hash_1, $pcr_hash_2)) { return 0 } }
214 $pcr_hash_1 = $self->{pcr_digest_bands
};
215 $pcr_hash_2 = $other->{pcr_digest_bands
};
217 for my $k (keys(%{$pcr_hash_1})) { delete $pcr_hash_1->{$k} if (@
{$pcr_hash_1->{$k}} == 0) }
218 for my $k (keys(%{$pcr_hash_2})) { delete $pcr_hash_2->{$k} if (@
{$pcr_hash_2->{$k}} == 0) }
219 # check pcr digest band arrays for all accessions in first object
220 for my $accession (keys(%{$pcr_hash_1})) { unless (&check_pcr_band_arrays
($accession, $pcr_hash_1, $pcr_hash_2)) { return 0 } }
221 # then check pcr digest band arrays for all accessions in second object, in case the second has accessions the first doesn't
222 for my $accession (keys(%{$pcr_hash_2})) { unless (&check_pcr_band_arrays
($accession, $pcr_hash_1, $pcr_hash_2)) { return 0 } }
224 #only compare mg and temp IF they are present in BOTH objects... see note below
225 if (($self->mg_conc() and $other->mg_conc()) and ($self->mg_conc() != $other->mg_conc())) { return 0 }
226 if (($self->temp() and $other->temp()) and ($self->temp() != $other->temp())) { return 0 }
229 #we did not compare missing temperature or mg concentration values, because yimin says experiments that are so similar
230 #that the only difference is that one is missing a temp or mg conc are the same experiment
231 #we did not compare additional_enzymes, because this is just a long text notes field, not essential data for the experiment,
232 #and frequently subject to minor changes in its text. this is just feinan's extra COSII PCR data field.
239 Returns its pcr_experiment_id if it already exists in the database, or undef if not.
249 unless($self->{marker_id
})
251 croak
"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";
253 unless($self->{protocol
})
255 croak
"I doubt an experiment like this one exists, since it has no experiment protocol. Set to unknown if necessary.";
257 if($self->{pcr_experiment_id
})
259 #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}";
260 return $self->{pcr_experiment_id
};
262 unless($self->predicted() eq 'f' or $self->predicted() eq 't'){croak
"Can't check for existence; invalid predicted field for self:\n".$self->as_string();}
263 my $possible_matches_query=$self->{dbh
}->prepare
271 and pcr_experiment_id is not null
273 $possible_matches_query->execute($self->marker_id());
274 while(my($possible_match_id)=$possible_matches_query->fetchrow_array())
276 #print"possible match id: $possible_match_id\n";
277 my $experiment_for_comparison=CXGN
::Marker
::PCR
::Experiment
->new($self->{dbh
},$possible_match_id);
278 if($self->equals($experiment_for_comparison))
280 $self->{pcr_experiment_id
}=$experiment_for_comparison->{pcr_experiment_id
};#ok, we've been found to already exist, so set our pcr_experiment_id
281 return $self->{pcr_experiment_id
};
287 =head2 store_unless_exists
289 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.
293 sub store_unless_exists
{
296 if ($self->exists()) { return }
298 unless ($self->{marker_id
}) { croak
"Cannot store experiment without marker ID" }
299 unless ($self->{protocol
}) { croak
"Cannot store experiment without protocol. Use 'unknown' if necessary." }
300 unless ($self->predicted() eq 'f' or $self->predicted() eq 't') { croak
"Can't store; invalid predicted field for self:\n".$self->as_string() }
301 if ($self->{pcr_experiment_id
}) { croak
"This experiment appears to have been stored already or created from an existing database entry" }
302 ##################### TODO #########################
303 #if we already have a PCR experiment ID, and someone
304 #calls 'store_unless_exists', this is a perfectly
305 #reasonable use case, but i have not implemented it yet.
306 #they might want to modify an existing experiment. for
307 #instance, it is common that someone might add digested
308 #bands later, after having loaded an experiment with
309 #only regular pcr bands a few months before. this object cannot yet handle this
310 #situation. that is why it croaks here. if you need to add
311 #this functionality, add it here. it would consist of some
312 #kind of object integrity checking and checking for values
313 #which have been added or modified and adding or modifying
314 #those same values in the database. alternatively, you may
315 #just want to write another class--CXGN::Marker::PCR::Experiment::Modfiable
316 #or something like that which has fewer checks and just
317 #directly accesses data in the database using an object
318 #like lukas's modifiable form object.
319 if ($self->{pcr_digest_bands
}) {
320 unless ($self->{enzyme_id
}) { croak
"Must have an enzyme set to store digest bands" }
323 my $dbh = $self->{dbh
};
324 my $sql = CXGN
::DB
::SQLWrappers
->new($self->{dbh
});
326 if ($self->fwd_primer()) {
327 my $fwd_info = $sql->insert_unless_exists('sequence',{'sequence'=>$self->fwd_primer()});
328 $self->{fwd_primer_id
} = $fwd_info->{id
};
330 if($self->rev_primer()) {
331 my $rev_info = $sql->insert_unless_exists('sequence',{'sequence'=>$self->rev_primer()});
332 $self->{rev_primer_id
} = $rev_info->{id
};
335 #print"INSERTING:\n".$self->as_string();
337 my $pcr_exp_insert = $self->{dbh
}->prepare ('
338 insert into sgn.pcr_experiment (
347 values (?,?,?,?,?,?,?)
349 $pcr_exp_insert->execute (
350 $self->{mg_concentration
},
351 $self->{annealing_temp
},
352 $self->{fwd_primer_id
},
353 $self->{rev_primer_id
},
354 $self->{primer_type
},
355 $self->{additional_enzymes
},
358 $self->{pcr_experiment_id
} =$self->{dbh
}->last_insert_id('pcr_experiment') or croak
"Could not get last_insert_id from pcr_experiment";
361 for my $accession(keys(%{$self->{pcr_bands
}}),keys(%{$self->{pcr_digest_bands
}})) { $accessions{$accession} = 0 }
362 # dummy value for now, until we get a pcr_exp_accession_id
364 my $exp_acc_insert = $self->{dbh
}->prepare('insert into sgn.pcr_exp_accession (pcr_experiment_id,accession_id) values (?,?)');
365 my $pcr_band_insert= $self->{dbh
}->prepare('insert into sgn.pcr_product (pcr_exp_accession_id,enzyme_id,multiple_flag,band_size,predicted) values (?,?,?,?,?)');
367 for my $accession_id(keys(%accessions)) {
368 $exp_acc_insert->execute($self->{pcr_experiment_id
}, $accession_id);
369 $accessions{$accession_id} = $self->{dbh
}->last_insert_id('pcr_exp_accession') or croak
"Could not get last_insert_id from pcr_exp_accession";
371 my @accession_pcr_bands;
372 my @accession_pcr_digest_bands;
373 if ($self->{pcr_bands
}->{$accession_id}) { @accession_pcr_bands = @
{$self->{pcr_bands
}->{$accession_id}} }
374 if ($self->{pcr_digest_bands
}->{$accession_id}) { @accession_pcr_digest_bands = @
{$self->{pcr_digest_bands
}->{$accession_id}} }
375 if ($accession_pcr_bands[0]) { #if there is at least one value in the pcr bands list for this accession
376 for my $band(@accession_pcr_bands) {
377 #if the band entry starts with an m, it means multiple bands, so set the multiple flag. no enzyme insert for regular pcr bands.
378 if($band=~/^m/i) { $pcr_band_insert->execute($accessions{$accession_id},undef,1,undef,$self->{predicted
}) }
379 else { $pcr_band_insert->execute($accessions{$accession_id},undef,undef,$band,$self->{predicted
}) }
382 if($accession_pcr_digest_bands[0]) { # if there is at least one value in the pcr digest bands list for this accession
383 #if the band entry starts with an m, it means multiple bands, so set the multiple flag.
384 for my $band(@accession_pcr_digest_bands) {
385 if ($band=~/^m/i) { $pcr_band_insert->execute($accessions{$accession_id},$self->{enzyme_id
},1,undef,$self->{predicted
}) }
386 else { $pcr_band_insert->execute($accessions{$accession_id},$self->{enzyme_id
},undef,$band,$self->{predicted
}) }
391 #and now for a final test of this object
392 if(my $oops_id=$self->store_unless_exists()) {
393 my $croaking = "Oops, this object isn't working correctly. Immediately after being stored with ID "
394 . "'$self->{pcr_experiment_id}', it tried to store itself again as a test, and succeeded with ID '$oops_id' "
395 . "(it should have failed, because it was already inserted!)";
399 return $self->{pcr_experiment_id
};
402 =head2 update_additional_enzymes
404 #this will actually update the pcr experiment entry in the database
405 $experiment->update_additional_enzymes('All possible enzymes for blah blah blah are blah blah blah....');
409 #storing function for additional_enzymes field. this data is not essential to the experiment. it is just a text field with
410 #notes that feinan wants to show up for cosii markers, so it has no special checks or anything.
411 sub update_additional_enzymes
414 my($additional_enzymes)=@_;
415 if(length($additional_enzymes)>1023)
417 croak
"Additional enzymes field contents size limit is exceeded by string '$additional_enzymes'";
419 unless($self->{pcr_experiment_id
})
421 croak
"This experiment object does not appear to have been loaded or inserted into the database yet, so you cannot update its enzymes";
423 my $sth=$self->{dbh
}->prepare('update pcr_experiment set additional_enzymes=? where pcr_experiment_id=?');
424 $sth->execute($additional_enzymes,$self->{pcr_experiment_id
});
429 #print out the whole experiment, for debugging, or for loading script output
430 print $experiment->as_string();
434 #######################
435 # display for debugging
436 #######################
441 $string.="<pcr_experiment>\n";
443 if($self->{marker_id
})
445 @marker_names=CXGN
::Marker
->new($self->{dbh
},$self->{marker_id
})->name_that_marker();
449 @marker_names=('<no marker associated yet>');
451 $string.="\tMarker: @marker_names\n";
452 $string.="\tPCR experiment ID: $self->{pcr_experiment_id}\n";
453 if($self->{location_id
})
455 $string.="\tThis is a mapping experiment; location ID: $self->{location_id}\n";
459 $string.="\tThis experiment does not yet have a map location associated with it in the marker_experiment table\n";
461 $string.="\tProtocol: $self->{protocol}\n";
462 $string.="\tPrimers: $self->{fwd_primer} (fwd)\t\t$self->{rev_primer} (rev)\n";
463 my $pt=$self->{primer_type
};
465 $string.="\tPrimer type: $pt\n";
466 my $mg=$self->{mg_concentration
};
468 my $temp=$self->{annealing_temp
};
470 $string.="\tConditions: $mg MG - $temp C\n";
471 if($self->{enzyme
}){$string.="\tEnzyme: $self->{enzyme}\n";}
472 $string.="\tBands:\n";
473 my $bands=$self->pcr_bands_hash_of_strings();
474 if($bands and %{$bands})
476 for my $accession(keys(%{$bands}))
478 $string.="\t".CXGN
::Accession
->new($self->{dbh
},$accession)->extra_verbose_name().": ".$bands->{$accession}."\n";
481 $string.="\tDigest bands:\n";
482 $bands=$self->pcr_digest_bands_hash_of_strings();
483 if($bands and %{$bands})
485 for my $accession(keys(%{$bands}))
487 $string.="\t".CXGN
::Accession
->new($self->{dbh
},$accession)->extra_verbose_name().": ".$bands->{$accession}."\n";
490 $string.="\tPredicted: $self->{predicted}\n";
491 $string.="</pcr_experiment>\n";
494 =head2 query_results_to_bands_hash
496 For internal use. Converts bands query results into a form that can be stored easily.
500 ###########################################
501 # helpful functions mainly for internal use
502 ###########################################
503 sub query_results_to_bands_hash
508 for my $row(@
{$sizes})
510 my($accession,$band_size,$multiple_flag)=@
{$row};
511 if($accession and ($band_size or $multiple_flag))
516 $insert_value=$band_size;
518 elsif($multiple_flag)
520 $insert_value='Multiple';
522 push(@
{$bands{$accession}},$insert_value);
526 croak
"Unable to load bands hash";
532 =head2 join_bands_hash
534 For internal use. Converts bands into a more useful form.
542 my %expected_structure;
543 for my $accession(keys(%{$bands_hash}))
545 $expected_structure{$accession}=join('+',@
{$bands_hash->{$accession}});
547 if(keys(%expected_structure))#if there are values to return, return them
549 return \
%expected_structure;
559 my $id=$experiment->marker_id();
561 Gets the marker_id of marker which is involved in this experiment.
563 $experiment->marker_id($marker_id);
565 Sets the marker_id of marker which is involved in this experiment.
578 unless($value=~/^\d+$/)
580 croak
"Marker ID must be a number, not '$value'";
582 unless(CXGN
::Marker
::Tools
::is_valid_marker_id
($self->{dbh
},$value))
584 croak
"Marker ID '$value' does not exist in the database";
586 $self->{marker_id
}=$value;
588 return $self->{marker_id
};
593 Returns or sets the forward primer.
603 $value=$self->test_and_clean_primer($value);
604 $self->{fwd_primer
}=$value;
606 return $self->{fwd_primer
};
611 Returns or sets the reverse primer.
624 $value=$self->test_and_clean_primer($value);
625 $self->{rev_primer
}=$value;
627 return $self->{rev_primer
};
638 $value=$self->test_and_clean_primer($value);
639 $self->{dcaps_primer
}=$value;
641 return $self->{dcaps_primer
};
647 Returns or sets the primer type.
657 unless($value eq 'iUPA' or $value eq 'eUPA')
659 croak
"'$value' is not a valid primer type";
661 $self->{primer_type
}=$value;
663 return $self->{primer_type
};
668 Returns or sets the magnesium concentration.
678 unless(CXGN
::Tools
::Text
::is_number
($value))
680 croak
"'$value' is not a valid number for mg concentration";
682 $self->{mg_concentration
}=$value;
684 return $self->{mg_concentration
};
689 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.
699 unless($value=~/^(\d*?\.?\d*?)[cf]?$/i)
701 croak
"'$value' is an invalid anneal temp";
703 $value=~s/C$//i;#strip C for Celsius
704 if($value=~s/F$//i)#if it was an F for Fahrenheit, convert it to Celsius
706 $value=($value+40)*5/9;
708 $self->{annealing_temp
}=$value;
710 return $self->{annealing_temp
};
715 Returns or sets the experiment protocol.
725 unless($protocol eq 'AFLP' or $protocol eq 'CAPS' or $protocol eq 'RAPD' or $protocol eq 'SNP' or $protocol eq 'SSR' or $protocol eq 'RFLP' or $protocol eq 'PCR' or $protocol eq 'unknown' or $protocol =~ /Indel/i)
727 croak
"Protocol '$protocol' is invalid.";
729 if($protocol eq 'RFLP')
731 croak
"RFLP is not a valid PCR experiment protocol";
733 $self->{protocol
}=$protocol;
735 return $self->{protocol
};
740 Returns or sets the enzyme used to get the digest bands.
750 $enzyme=~s/\s//g unless $enzyme=~/and/; #clear whitespace
751 $enzyme=~s/(1+)$/'I' x length($1)/e; #1 -> I
753 # this isn't working for some reason
755 if ($enzyme eq 'PCR') { $enzyme = 'amplicon difference' }
756 # TODO: change this to undef once everything is working
757 elsif ($enzyme eq 'SNP') { $enzyme = 'unknown' }
758 elsif (!$enzyme) { $enzyme = 'unknown' }
760 unless($self->{enzyme_id
}=CXGN
::Marker
::Tools
::get_enzyme_id
($self->{dbh
},$enzyme)) {
761 croak
"'$enzyme' is not a valid enzyme (you may need to add it to the enzyme table)";
764 $self->{enzyme
}=$enzyme;
767 return $self->{enzyme
};
770 =head2 additional_enzymes
772 Returns or sets Feinan^s COSII additional_enzymes field.
776 sub additional_enzymes
780 if($value){$self->{additional_enzymes
}=$value;}
781 return $self->{additional_enzymes
};
786 Returns or sets whether or not the band sizes stored in this object are predicted.
797 unless($value eq 't' or $value eq 'f')
799 croak
"Predicted must be either 't' or 'f'";
801 $self->{predicted
}=$value;
803 return $self->{predicted
};
806 =head2 add_pcr_bands_for_accession
808 $experiment->add_pcr_bands_for_accession('250+400','LA716');
812 #example use: $created_experiment->add_pcr_bands_string_for_accession('750+900','LA925');
813 sub add_pcr_bands_for_accession
816 my($bands_string,$accession)=@_;
817 my $accession_object=CXGN
::Accession
->new($self->{dbh
},$accession);
818 unless($accession_object)
820 croak
"Accession '$accession' not found\n";
822 my $accession_id=$accession_object->accession_id();
823 unless($accession_id){croak
("Accession '$accession' not found");}
824 my @bands=split(/\+/,$bands_string);
825 $self->{pcr_bands
}->{$accession_id}=\
@bands;
826 $self->{pcr_bands
}=$self->test_and_clean_bands($self->{pcr_bands
});
829 =head2 add_pcr_digest_bands_for_accession
831 $experiment->add_pcr_digest_bands_for_accession('250+400','LA716');
835 #example use: $created_experiment->add_pcr_digest_bands_string_for_accession('multiple','LA716');
836 sub add_pcr_digest_bands_for_accession
839 my($bands_string,$accession)=@_;
840 my $accession_object=CXGN
::Accession
->new($self->{dbh
},$accession);
841 unless($accession_object)
843 croak
"Accession '$accession' not found\n";
845 my $accession_id=$accession_object->accession_id();
846 unless($accession_id){croak
("Accession '$accession' not found");}
847 my @bands=split(/\+/,$bands_string);
848 $self->{pcr_digest_bands
}->{$accession_id}=\
@bands;
849 $self->{pcr_digest_bands
}=$self->test_and_clean_bands($self->{pcr_digest_bands
});
852 ######################
853 # convenient accessors
854 ######################
856 =head2 pcr_bands_hash_of_strings
858 Get PCR bands in a form that CXGN::Marker::PCR likes.
862 sub pcr_bands_hash_of_strings
865 return $self->join_bands_hash($self->{pcr_bands
});
868 =head2 pcr_digest_bands_hash_of_strings
870 Get PCR digest bands in a form that CXGN::Marker::PCR likes.
874 sub pcr_digest_bands_hash_of_strings
877 return $self->join_bands_hash($self->{pcr_digest_bands
});
880 =head2 test_and_clean_primer
889 sub test_and_clean_primer
896 unless($primer=~/[ATGCatgc]+/)#primers are known base pairs start to finish
898 croak
"'$primer' is not a valid primer";
900 return uc($primer);#uppercase sequence data
903 =head2 test_and_clean_bands
909 #bands must look like this: {'LA716'=>['Multiple'],'LA925'=>[750,900]}
910 sub test_and_clean_bands
914 unless(ref($bands) eq 'HASH')
916 croak
"Bands must be hash ref";
918 for my $accession_id(keys(%{$bands}))
920 unless(CXGN
::Accession
->new($self->{dbh
},$accession_id)->accession_id()){croak
"Accession '$accession_id' not found";}
921 unless(ref($bands->{$accession_id}) eq 'ARRAY')
923 croak
"Bands hash ref must contain array refs";
925 my @bands_array=@
{$bands->{$accession_id}};#copy this array out to make the following code more readable, maybe
926 for my $index(0..$#bands_array)
928 $bands_array[$index]=CXGN
::Tools
::Text
::remove_all_whitespaces
(lc($bands_array[$index]));
930 if($bands_array[$index]=~/^m/i){$bands_array[$index]='Multiple';}
932 unless ($bands_array[$index] eq 'Multiple'){
933 $bands_array[$index] = int($bands_array[$index]);
936 unless(($bands_array[$index] eq 'Multiple') or (CXGN
::Tools
::Text
::is_number
($bands_array[$index])))
938 croak
"'$bands_array[$index]' is an invalid band size";
941 $bands->{$accession_id}=\
@bands_array;#copy this array back in
946 ##store the primers, or any other sequnces linked, in the sequence table, and link to pcr_experiment##
948 =head2 store_sequence
950 Usage: $self->store_sequence($sequence_name, $sequence);
951 Desc: store a primer, or any other sequence type, of the pcr_experiment in the sequence table ,
952 and link to the experiment using pcr_experiment_sequence table.
954 Args: a string with sequence type, and the sequence string
955 sequence types should be listed in the cvterm table with cv_name =
956 'sgn sequence type' (See L<Bio::Chado::Schema::Cv::Cvterm>->create_with for adding new sequence types)
957 Side Effects: store a new sequence in sgn.sequence, if one does not exist.
958 Sequences are converted to all upper-case.
961 my $id = $self->store_sequence('forward primer','ATCCGTGACGTAC');
967 my $sequence_type = shift;
968 my $seq = shift || die 'No sequence for type $sequence_type passed to store_sequence function! \n';
970 #find if the type is stored in the database
971 my $q = "SELECT cvterm_id FROM public.cvterm
972 WHERE name ilike ? AND cv_id =
973 (SELECT cv_id FROM public.cv WHERE cv.name ilike ?) ";
974 my $sth=$self->{dbh
}->prepare($q);
975 $sth->execute($sequence_type,'sgn sequence type');
976 my ($type_id) = $sth->fetchrow_array();
977 die "Sequence type $sequence_type does not exist in the database!\n Expected to find cvterm $sequence_type with cv_name 'sgn sequence type'!\n Please check your databae\n " if !$type_id;
980 unless($seq=~/[ATGCatgc]+/) {
981 croak
"'$seq' is not a valid sequence";
983 $seq = uc($seq);#uppercase sequence data
985 my $sql = CXGN
::DB
::SQLWrappers
->new( $self->{dbh
} );
986 my $sequence = $sql->insert_unless_exists('sequence',{'sequence'=>$seq });
988 $q = "Insert INTO sgn.pcr_experiment_sequence (sequence_id, pcr_experiment_id, type_id)
989 VALUES (?,?,?) RETURNING pcr_experiment_sequence_id";
990 $sth=$self->{dbh
}->prepare($q);
991 $sth->execute( $sequence->{id
} , $self->{pcr_experiment_id
} , $type_id );
992 #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 } );
993 return ($sth->fetchrow_array());
997 ##get the associated sequences and their types from pcr_experiment_sequence##
1001 Usage: $self->get_sequences
1002 Desc: find the sequences associated with the marker, and their types
1003 Ret: hashref {$sequence_type => [$seq1, $seq2] }
1011 my $q = "SELECT cvterm.name, sequence FROM sgn.pcr_experiment
1012 JOIN sgn.pcr_experiment_sequence USING (pcr_experiment_id)
1013 JOIN sgn.sequence USING (sequence_id)
1014 JOIN public.cvterm on cvterm_id = sgn.pcr_experiment_sequence.type_id
1015 WHERE pcr_experiment.pcr_experiment_id = ?";
1016 my $sth = $self->{dbh
}->prepare($q);
1017 $sth->execute($self->{pcr_experiment_id
});
1019 while ( my ($sequence_type, $sequence) = $sth->fetchrow_array() ) {
1020 push @
{$HoA{$sequence_type} }, $sequence ;