1 package CXGN
::Pedigree
::AddCrosses
;
5 CXGN::Pedigree::AddCrosses - a module to add cross.
9 my $cross_add = CXGN::Pedigree::AddCrosses->new({ schema => $schema, location => $location_name, program => $program_name, crosses => \@array_of_pedigree_objects} );
10 my $validated = $cross_add->validate_crosses(); #is true when all of the crosses are valid and the accessions they point to exist in the database.
11 $cross_add->add_crosses();
15 Adds an array of crosses. The parents used in the cross must already exist in the database, and the verify function does this check. This module is intended to be used in independent loading scripts and interactive dialogs.
19 Jeremy D. Edwards (jde22@cornell.edu)
20 Titima Tantikanjana (tt15@cornell.edu)
25 use MooseX
::FollowPBP
;
26 use Moose
::Util
::TypeConstraints
;
28 use Bio
::GeneticRelationships
::Pedigree
;
29 use Bio
::GeneticRelationships
::Individual
;
30 use CXGN
::Stock
::StockLookup
;
31 use CXGN
::BreedersToolbox
::Projects
;
33 use CXGN
::Trial
::Folder
;
34 use SGN
::Model
::Cvterm
;
36 use File
::Basename qw
| basename dirname
|;
40 class_type
'Pedigree', { class => 'Bio::GeneticRelationships::Pedigree' };
42 has
'chado_schema' => (
44 isa
=> 'DBIx::Class::Schema',
45 predicate
=> 'has_chado_schema',
49 has
'phenome_schema' => (
51 isa
=> 'DBIx::Class::Schema',
52 predicate
=> 'has_phenome_schema',
56 has
'metadata_schema' => (
58 isa
=> 'DBIx::Class::Schema',
59 predicate
=> 'has_metadata_schema',
65 predicate
=> 'has_dbh',
70 isa
=>'ArrayRef[Pedigree]',
72 predicate
=> 'has_crosses',
79 predicate
=> 'has_user_id',
83 has
'crossing_trial_id' => (
86 predicate
=> 'has_crossing_trial_id',
93 predicate
=> 'has_file_id',
100 my $chado_schema = $self->get_chado_schema();
101 my $phenome_schema = $self->get_phenome_schema();
102 my $metadata_schema = $self->get_metadata_schema();
103 my $crossing_trial_id = $self->get_crossing_trial_id();
104 my $owner_id = $self->get_user_id();
106 my $transaction_error;
110 if (!$self->validate_crosses()) {
111 print STDERR
"Invalid pedigrees in array. No crosses will be added\n";
115 #add all crosses in a single transaction
118 #get cvterms for parents
119 my $female_parent_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'female_parent', 'stock_relationship');
120 my $male_parent_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'male_parent', 'stock_relationship');
122 #get cvterm for cross_combination
123 my $cross_combination_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'cross_combination', 'stock_property');
125 #get cvterm for cross_experiment
126 my $cross_experiment_type_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'cross_experiment', 'experiment_type');
128 #get cvterm for stock type cross
129 my $cross_stock_type_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'cross', 'stock_type');
131 #get cvterm for female and male plots
132 my $female_plot_of_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'female_plot_of', 'stock_relationship');
133 my $male_plot_of_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'male_plot_of', 'stock_relationship');
135 #get cvterm for female and male plants
136 my $female_plant_of_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'female_plant_of', 'stock_relationship');
137 my $male_plant_of_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'male_plant_of', 'stock_relationship');
139 my $project_location_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'project location', 'project_property')->cvterm_id();
140 my $geolocation_rs = $chado_schema->resultset("Project::Projectprop")->find({project_id
=> $crossing_trial_id, type_id
=> $project_location_cvterm_id});
142 my $cross_identifier_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'cross_identifier', 'stock_property');
144 @crosses = @
{$self->get_crosses()};
145 foreach my $pedigree (@crosses) {
149 my $female_parent_name;
150 my $male_parent_name;
153 my $population_stock;
154 my $cross_type = $pedigree->get_cross_type();
155 my $cross_name = $pedigree->get_name();
156 my $cross_combination = $pedigree->get_cross_combination();
157 my $female_plot_name;
161 my $female_plant_name;
166 $cross_name =~ s/^\s+|\s+$//g; #trim whitespace from both ends
169 if ($pedigree->has_female_parent()) {
170 $female_parent_name = $pedigree->get_female_parent()->get_name();
171 if ($cross_type eq 'backcross') {
172 $female_parent = $self->_get_accession_or_cross($female_parent_name);
174 $female_parent = $self->_get_accession($female_parent_name);
178 if ($pedigree->has_male_parent()) {
179 $male_parent_name = $pedigree->get_male_parent()->get_name();
180 if ($cross_type eq 'backcross') {
181 $male_parent = $self->_get_accession_or_cross($male_parent_name);
183 $male_parent = $self->_get_accession($male_parent_name);
187 if ($pedigree->has_female_plot()) {
188 $female_plot_name = $pedigree->get_female_plot()->get_name();
189 $female_plot = $self->_get_plot($female_plot_name);
192 if ($pedigree->has_male_plot()) {
193 $male_plot_name = $pedigree->get_male_plot()->get_name();
194 $male_plot = $self->_get_plot($male_plot_name);
197 if ($pedigree->has_female_plant()) {
198 $female_plant_name = $pedigree->get_female_plant()->get_name();
199 $female_plant = $self->_get_plant($female_plant_name);
202 if ($pedigree->has_male_plant()) {
203 $male_plant_name = $pedigree->get_male_plant()->get_name();
204 $male_plant = $self->_get_plant($male_plant_name);
207 #organism of cross experiment will be the same as the female parent
208 if ($female_parent) {
209 $organism_id = $female_parent->organism_id();
211 $organism_id = $male_parent->organism_id();
214 my $previous_cross_stock_rs = $chado_schema->resultset("Stock::Stock")->search({
215 organism_id
=> $organism_id,
216 uniquename
=> $cross_name,
217 type_id
=> $cross_stock_type_cvterm->cvterm_id,
219 if ($previous_cross_stock_rs->count > 0){
220 #If cross already exists, just go to next cross
224 #create cross experiment
225 $experiment = $chado_schema->resultset('NaturalDiversity::NdExperiment')->create({
226 nd_geolocation_id
=> $geolocation_rs->value,
227 type_id
=> $cross_experiment_type_cvterm->cvterm_id,
229 my $nd_experiment_id = $experiment->nd_experiment_id();
230 $nd_experiments{$nd_experiment_id}++;
232 #create a stock of type cross
233 $cross_stock = $chado_schema->resultset("Stock::Stock")->find_or_create({
234 organism_id
=> $organism_id,
236 uniquename
=> $cross_name,
237 type_id
=> $cross_stock_type_cvterm->cvterm_id,
240 #add stock_id of cross to an array so that the owner can be associated in the phenome schema after the transaction on the chado schema completes
241 push (@added_stock_ids, $cross_stock->stock_id());
244 #link parents to the stock of type cross
245 if ($female_parent) {
246 $cross_stock->find_or_create_related('stock_relationship_objects', {
247 type_id
=> $female_parent_cvterm->cvterm_id(),
248 object_id
=> $cross_stock->stock_id(),
249 subject_id
=> $female_parent->stock_id(),
250 value
=> $cross_type,
255 $cross_stock->find_or_create_related('stock_relationship_objects', {
256 type_id
=> $male_parent_cvterm->cvterm_id(),
257 object_id
=> $cross_stock->stock_id(),
258 subject_id
=> $male_parent->stock_id(),
262 if ( ( $cross_type eq "self" || $cross_type eq "dihaploid_induction" || $cross_type eq "doubled_haploid") && $female_parent) {
263 $cross_stock->find_or_create_related('stock_relationship_objects', {
264 type_id
=> $male_parent_cvterm->cvterm_id(),
265 object_id
=> $cross_stock->stock_id(),
266 subject_id
=> $female_parent->stock_id(),
270 #link cross to female_plot
272 $cross_stock->find_or_create_related('stock_relationship_objects', {
273 type_id
=> $female_plot_of_cvterm->cvterm_id(),
274 object_id
=> $cross_stock->stock_id(),
275 subject_id
=> $female_plot->stock_id(),
279 #link cross to male_plot
281 $cross_stock->find_or_create_related('stock_relationship_objects', {
282 type_id
=> $male_plot_of_cvterm->cvterm_id(),
283 object_id
=> $cross_stock->stock_id(),
284 subject_id
=> $male_plot->stock_id(),
288 #link cross to female_plant
290 $cross_stock->find_or_create_related('stock_relationship_objects', {
291 type_id
=> $female_plant_of_cvterm->cvterm_id(),
292 object_id
=> $cross_stock->stock_id(),
293 subject_id
=> $female_plant->stock_id(),
297 #link cross to male_plant
299 $cross_stock->find_or_create_related('stock_relationship_objects', {
300 type_id
=> $male_plant_of_cvterm->cvterm_id(),
301 object_id
=> $cross_stock->stock_id(),
302 subject_id
=> $male_plant->stock_id(),
306 #link cross to cross_combination
307 if ($cross_combination) {
308 $cross_stock->create_stockprops({$cross_combination_cvterm->name() => $cross_combination});
311 #link the stock of type cross to the experiment
312 $experiment->find_or_create_related('nd_experiment_stocks' , {
313 stock_id
=> $cross_stock->stock_id(),
314 type_id
=> $cross_experiment_type_cvterm->cvterm_id(),
317 #link the experiment to the project
318 $experiment->find_or_create_related('nd_experiment_projects', {
319 project_id
=> $self->get_crossing_trial_id,
322 my $identifier_female_id;
323 my $identifier_male_id;
325 $identifier_female_id = $female_plant->stock_id();
326 } elsif ($female_plot){
327 $identifier_female_id = $female_plot->stock_id();
329 $identifier_female_id = $female_parent->stock_id();
333 $identifier_male_id = $male_plant->stock_id();
334 } elsif ($male_plot){
335 $identifier_male_id = $male_plot->stock_id();
336 } elsif ($male_parent) {
337 $identifier_male_id = $male_parent->stock_id();
339 $identifier_male_id = 'NA'
342 my $cross_identifier = $crossing_trial_id.'_'.$identifier_female_id.'_'.$identifier_male_id;
343 $cross_stock->create_stockprops({$cross_identifier_cvterm->name() => $cross_identifier});
344 print STDERR
"CROSS IDENTIFIER =".Dumper
($cross_identifier)."\n";
349 #try to add all crosses in a transaction
351 $chado_schema->txn_do($coderef);
353 $transaction_error = $_;
356 if ($transaction_error) {
357 print STDERR
"Transaction error creating a cross: $transaction_error\n";
361 foreach my $stock_id (@added_stock_ids) {
362 #add the owner for this stock
363 $phenome_schema->resultset("StockOwner")->find_or_create({
364 stock_id
=> $stock_id,
365 sp_person_id
=> $owner_id,
369 #link nd_experiments to file_id
370 my $file_id = $self->get_file_id;
371 # print STDERR "FILE ID =".Dumper($file_id)."\n";
373 foreach my $nd_experiment_id (keys %nd_experiments) {
374 my $nd_experiment_files = $phenome_schema->resultset("NdExperimentMdFiles")->create({
375 nd_experiment_id
=> $nd_experiment_id,
385 sub validate_crosses
{
387 my $chado_schema = $self->get_chado_schema();
388 my @crosses = @
{$self->get_crosses()};
389 my $invalid_cross_count = 0;
390 my $crossing_trial_lookup;
394 $crossing_trial_lookup = CXGN
::BreedersToolbox
::Projects
->new({ schema
=> $chado_schema});
395 $crossing_trial = $crossing_trial_lookup->get_crossing_trials($self->get_crossing_trial_id());
396 if (!$crossing_trial) {
397 print STDERR
"Crossing trial ". $self->get_crossing_trials() ." not found\n";
401 foreach my $cross (@crosses) {
402 my $validated_cross = $self->_validate_cross($cross);
404 if (!$validated_cross) {
405 $invalid_cross_count++;
410 if ($invalid_cross_count > 0) {
411 print STDERR
"There were $invalid_cross_count invalid crosses\n";
418 sub _validate_cross
{
420 my $pedigree = shift;
421 my $chado_schema = $self->get_chado_schema();
422 my $name = $pedigree->get_name();
423 my $cross_type = $pedigree->get_cross_type();
424 my $female_parent_name;
425 my $male_parent_name;
429 if ($cross_type eq "biparental") {
430 $female_parent_name = $pedigree->get_female_parent()->get_name();
431 $male_parent_name = $pedigree->get_male_parent()->get_name();
432 $female_parent = $self->_get_accession($female_parent_name);
433 $male_parent = $self->_get_accession($male_parent_name);
435 if (!$female_parent || !$male_parent) {
436 print STDERR
"Parent $female_parent_name or $male_parent_name in pedigree is not a stock\n";
440 } elsif ($cross_type eq "self" || $cross_type eq "dihaploid_induction" || $cross_type eq "doubled_haploid" ) {
441 $female_parent_name = $pedigree->get_female_parent()->get_name();
442 $female_parent = $self->_get_accession($female_parent_name);
444 if (!$female_parent) {
445 print STDERR
"Parent $female_parent_name in pedigree is not a stock\n";
449 } elsif ($cross_type eq "open") {
450 $female_parent_name = $pedigree->get_female_parent()->get_name();
451 $female_parent = $self->_get_accession($female_parent_name);
453 if (!$female_parent) {
454 print STDERR
"Parent $female_parent_name in pedigree is not a stock\n";
457 } elsif ($cross_type eq 'backcross') {
458 $female_parent_name = $pedigree->get_female_parent()->get_name();
459 $male_parent_name = $pedigree->get_male_parent()->get_name();
460 $female_parent = $self->_get_accession_or_cross($female_parent_name);
461 $male_parent = $self->_get_accession_or_cross($male_parent_name);
464 if (!$female_parent || !$male_parent) {
465 print STDERR
"Parent $female_parent_name or $male_parent_name in pedigree is not a stock\n";
471 #add support for other cross types here
482 my $accession_name = shift;
483 my $chado_schema = $self->get_chado_schema();
484 my $stock_lookup = CXGN
::Stock
::StockLookup
->new(schema
=> $chado_schema);
486 my $accession_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'accession', 'stock_type');
487 #not sure why vector_construct is in this function
488 my $vector_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'vector_construct', 'stock_type');
489 my $population_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'population', 'stock_type');
491 $stock_lookup->set_stock_name($accession_name);
492 $stock = $stock_lookup->get_stock_exact();
495 print STDERR
"Parent name is not a stock\n";
499 #not sure why vector_construct is in this function
500 if (($stock->type_id() != $accession_cvterm->cvterm_id()) && ($stock->type_id() != $population_cvterm->cvterm_id()) && ($stock->type_id() != $vector_cvterm->cvterm_id()) ) {
501 print STDERR
"Parent name is not a stock of type accession or population or vector_construct\n";
510 my $plot_name = shift;
511 my $chado_schema = $self->get_chado_schema();
512 my $stock_lookup = CXGN
::Stock
::StockLookup
->new(schema
=> $chado_schema);
514 my $plot_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'plot', 'stock_type');
516 $stock_lookup->set_stock_name($plot_name);
517 $stock = $stock_lookup->get_stock_exact();
520 print STDERR
"Parent name is not a stock\n";
524 if ($stock->type_id() != $plot_cvterm->cvterm_id()) {
525 print STDERR
"Parent name is not a stock of type plot\n";
534 my $plant_name = shift;
535 my $chado_schema = $self->get_chado_schema();
536 my $stock_lookup = CXGN
::Stock
::StockLookup
->new(schema
=> $chado_schema);
538 my $plant_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'plant', 'stock_type');
540 $stock_lookup->set_stock_name($plant_name);
541 $stock = $stock_lookup->get_stock_exact();
544 print STDERR
"Parent name is not a stock\n";
548 if ($stock->type_id() != $plant_cvterm->cvterm_id()) {
549 print STDERR
"Parent name is not a stock of type plant\n";
556 sub _get_accession_or_cross
{
558 my $parent_name = shift;
559 my $chado_schema = $self->get_chado_schema();
560 my $stock_lookup = CXGN
::Stock
::StockLookup
->new(schema
=> $chado_schema);
562 my $accession_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'accession', 'stock_type');
563 my $cross_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($chado_schema, 'cross', 'stock_type');
565 $stock_lookup->set_stock_name($parent_name);
566 $stock = $stock_lookup->get_stock_exact();
569 print STDERR
"Parent name is not a stock\n";
573 if (($stock->type_id() != $accession_cvterm->cvterm_id()) && ($stock->type_id() != $cross_cvterm->cvterm_id())) {
574 print STDERR
"Parent name is not a stock of type accession or cross \n";