minor tweak of announcement.
[sgn.git] / cgi-bin / phenome / qtl_load.pl
bloba98ddb063addd907306f62739c30a6b1ad084292
1 package CXGN::Phenome::QtlLoadDetailPage;
2 use CatalystX::GlobalContext qw( $c );
4 =head1 DESCRIPTION
5 processes and loads qtl data obtained from the the web forms
6 (qtl_form.pl) on the user specific directory and the database.
9 =head1 AUTHOR
10 Isaak Y Tecle (iyt2@cornell.edu)
12 =cut
14 use strict;
15 use warnings;
17 my $qtl_load_detail_page = CXGN::Phenome::QtlLoadDetailPage->new();
19 use File::Spec;
20 use CXGN::DB::Connection;
21 use CXGN::Phenome::Qtl;
22 use CXGN::Phenome::Qtl::Tools;
23 use CXGN::Phenome::Population;
24 use CXGN::Phenome::UserTrait;
25 use CXGN::Chado::Phenotype;
26 use CXGN::Chado::Cvterm;
27 use CXGN::Chado::Organism;
28 use CXGN::Phenome::Individual;
29 use CXGN::Accession;
30 use CXGN::Map;
31 use CXGN::Map::Version;
32 use CXGN::Map::Tools;
33 use CXGN::LinkageGroup;
34 use List::MoreUtils qw /uniq/;
35 use CXGN::Marker::Modifiable;
36 use CXGN::Marker::Tools;
37 use CXGN::Marker::Location;
38 use CXGN::Phenome::GenotypeExperiment;
39 use CXGN::Phenome::Genotype;
40 use CXGN::Phenome::GenotypeRegion;
41 use CXGN::Login;
42 use CXGN::Contact;
43 use CXGN::People::Person;
44 use CXGN::Page;
45 use Bio::Chado::Schema;
46 use Storable qw /store retrieve/;
47 use CGI;
49 use CatalystX::GlobalContext qw( $c );
51 sub new {
52 my $class = shift;
53 my $self = bless {}, $class;
55 my $dbh = CXGN::DB::Connection->new();
56 my $login = CXGN::Login->new($dbh);
57 my $sp_person_id = $login->verify_session();
59 $self->set_sp_person_id($sp_person_id);
60 $self->set_dbh($dbh);
62 if ($sp_person_id) {
63 $self->process_data();
66 return $self;
69 sub process_data {
70 my $self = shift;
71 my $page = CXGN::Page->new( "SGN", "isaak" );
72 my $dbh = $self->get_dbh();
74 my $login = CXGN::Login->new($dbh);
75 my $sp_person_id = $login->verify_session();
76 my $referring_page = $c->req->base . 'qtl/form';
78 my %args = $page->get_all_encoded_arguments();
79 $args{pop_common_name_id} = $self->common_name_id();
81 my $type = $args{type};
82 my $pop_id = $args{pop_id};
83 my $args_ref = \%args;
85 my $qtl_obj = CXGN::Phenome::Qtl->new( $sp_person_id, $args_ref );
86 $qtl_obj->create_user_qtl_dir($c);
87 my $qtl_tools = CXGN::Phenome::Qtl::Tools->new();
89 if ($pop_id) {
90 $self->set_population_id($pop_id);
91 $qtl_obj->set_population_id($pop_id);
94 my ( $pop_name, $desc, $pop_detail, $message );
96 if ( $type eq 'begin' )
98 $self->show_pop_form();
101 elsif ( $type eq 'pop_form' )
103 $self->post_pop_form($qtl_obj, $qtl_tools);
106 elsif ( $type eq 'trait_form' )
108 $self->post_trait_form($qtl_obj, $args{'trait_file'}, $pop_id);
112 elsif ( $type eq 'pheno_form' )
114 $self->post_pheno_form($qtl_obj, $args{'pheno_file'}, $pop_id);
117 elsif ( $type eq 'geno_form' )
119 $self->post_geno_form($qtl_obj, $args{'geno_file'}, $pop_id);
122 elsif ( $type eq 'stat_form' )
124 $self->post_stat_form($args_ref);
128 sub pheno_upload {
129 my $self = shift;
130 my $qtl = shift;
131 my $p_file = shift;
133 my $safe_char = "a-zA-Z0-9_.-";
134 my ( $temp_pheno_file, $name );
136 $p_file =~ tr/ /_/;
137 $p_file =~ s/[^$safe_char]//g;
139 if ( $p_file =~ /^([$safe_char]+)$/ ) {
141 $p_file = $1;
144 else {
145 die "Phenotype file name contains invalid characters";
148 my $phe_upload = $c->req->upload('pheno_file');
150 if ( defined $phe_upload ) {
151 $name = $phe_upload->filename;
153 my ( $qtl_dir, $user_dir ) = $qtl->get_user_qtl_dir($c);
154 my $qtlfiles = retrieve("$user_dir/qtlfiles");
156 my $trait_file = $qtlfiles->{trait_file};
157 $self->compare_file_names( $name, $trait_file );
158 $qtlfiles->{pheno_file} = $name;
159 store $qtlfiles, "$user_dir/qtlfiles";
162 else {
163 die "Catalyst::Request::Upload object for phenotype file not defined.";
167 if ( $p_file eq $name ) {
168 $temp_pheno_file = $qtl->apache_upload_file( $phe_upload, $c );
169 return $temp_pheno_file;
172 else { return 0; }
176 sub geno_upload {
177 my $self = shift;
178 my $qtl = shift;
179 my $g_file = shift;
181 my ( $temp_geno_file, $name );
183 my $safe_char = "a-zA-Z0-9_.-";
185 $g_file =~ tr/ /_/;
186 $g_file =~ s/[^$safe_char]//g;
188 if ( $g_file =~ /^([$safe_char]+)$/ ) {
190 $g_file = $1;
193 else {
194 die "Genotype file name contains invalid characters";
197 my $gen_upload = $c->req->upload('geno_file');
199 if ( defined $gen_upload ) {
200 $name = $gen_upload->filename;
202 my ( $qtl_dir, $user_dir ) = $qtl->get_user_qtl_dir($c);
203 my $qtlfiles = retrieve("$user_dir/qtlfiles");
205 my $trait_file = $qtlfiles->{trait_file};
206 my $pheno_file = $qtlfiles->{pheno_file};
208 $self->compare_file_names( $name, $trait_file );
209 $self->compare_file_names( $name, $pheno_file );
211 $qtlfiles->{geno_file} = $name;
212 store $qtlfiles, "$user_dir/qtlfiles";
215 else {
216 die "Catalyst::Request::Upload object for genotype file not defined.";
220 if ( $g_file eq $name ) {
221 $temp_geno_file = $qtl->apache_upload_file( $gen_upload, $c );
222 return $temp_geno_file;
224 else { return 0; }
227 sub trait_upload {
228 my $self = shift;
229 my $qtl = shift;
230 my $c_file = shift;
232 my ( $temp_trait_file, $name );
234 print STDERR "Trait file: $c_file\n";
235 my $safe_char = "a-zA-Z0-9_.-";
237 $c_file =~ tr/ /_/;
238 $c_file =~ s/[^$safe_char]//g;
240 if ( $c_file =~ /^([$safe_char]+)$/ ) {
242 $c_file = $1;
245 else {
246 die "Trait file name contains invalid characters";
249 my $trait_upload = $c->req->upload('trait_file');
251 if ( defined $trait_upload )
253 $name = $trait_upload->filename;
254 my ( $qtl_dir, $user_dir ) = $qtl->get_user_qtl_dir($c);
255 my $qtlfiles = {};
256 $qtlfiles->{trait_file} = $name;
257 store( $qtlfiles, "$user_dir/qtlfiles" );
260 else
262 die "Catalyst::Request::Upload object for trait file not defined.";
266 if ( $c_file eq $name )
268 $temp_trait_file = $qtl->apache_upload_file( $trait_upload, $c );
269 return $temp_trait_file;
271 else { return 0; }
274 sub load_pop_details {
275 my $self = shift;
276 my $pop_args = shift;
277 my %pop_details = %{$pop_args};
279 my $org = $pop_details{organism};
280 my $name = $pop_details{pop_name};
281 my $desc = $pop_details{pop_desc};
282 my $cross_id = $pop_details{pop_type};
283 my $female = $pop_details{pop_female_parent};
284 my $male = $pop_details{pop_male_parent};
285 my $recurrent = $pop_details{pop_recurrent_parent};
286 my $donor = $pop_details{pop_donor_parent};
287 my $comment = $pop_details{pop_comment};
288 my $is_public = $pop_details{pop_is_public};
289 my $common_name_id = $pop_details{pop_common_name_id};
291 my $dbh = $self->get_dbh();
292 my $login = CXGN::Login->new($dbh);
293 my $sp_person_id = $login->verify_session();
295 my ( $female_id, $male_id, $recurrent_id, $donor_id );
297 my $population = CXGN::Phenome::Population->new_with_name( $dbh, $name );
298 my $population_id = $population->get_population_id();
299 if ($population_id) {
300 $self->population_exists( $population, $name );
303 print STDERR "storing parental accessions...\n";
305 if ($female) {
306 $female_id = $self->store_accession($female);
307 print STDERR "female: $female_id\n";
310 if ($male) {
311 $male_id = $self->store_accession($male);
312 print STDERR "male: $male_id\n";
315 if ($recurrent) {
316 $recurrent_id = $self->store_accession($recurrent);
319 if ($donor) {
320 $donor_id = $self->store_accession($donor);
323 my $pop = CXGN::Phenome::Population->new($dbh);
324 $pop->set_name($name);
325 $pop->set_description($desc);
326 $pop->set_sp_person_id($sp_person_id);
327 $pop->set_cross_type_id($cross_id);
328 $pop->set_female_parent_id($female_id);
329 $pop->set_male_parent_id($male_id);
330 $pop->set_recurrent_parent_id($recurrent_id);
331 $pop->set_donor_parent_id($donor_id);
332 $pop->set_comment($comment);
333 $pop->set_web_uploaded('t');
334 $pop->set_common_name_id($common_name_id);
335 $pop->store();
337 my $pop_id = $dbh->last_insert_id( "population", "phenome" );
339 $pop = CXGN::Phenome::Population->new( $dbh, $pop_id );
340 $pop->store_data_privacy($is_public);
342 return $pop_id, $name, $desc;
345 sub store_accession {
346 my $self = shift;
347 my $accession = shift;
348 my $dbh = $self->get_dbh();
350 print STDERR "organism_id: $accession\n";
351 my ( $species, $cultivar ) = split( /cv|var|cv\.|var\./, $accession );
352 $species =~ s/^\s+|\s+$//;
353 $cultivar =~ s/\.//;
354 $cultivar =~ s/^\s+|\s+$//;
355 $species = ucfirst($species);
357 print STDERR "$accession: species:$species, cultivar:$cultivar\n";
358 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
360 my $organism = CXGN::Chado::Organism->new_with_species( $schema, $species );
361 $self->check_organism( $organism, $species, $cultivar );
363 my $existing_organism_id = $organism->get_organism_id();
364 my $organism_name = $organism->get_species();
366 eval {
367 my $sth = $dbh->prepare(
368 "SELECT accession_id, chado_organism_id, common_name
369 FROM sgn.accession
370 WHERE common_name ILIKE ?"
372 $sth->execute($cultivar);
373 my ( $accession_id, $chado_organism_id, $common_name ) =
374 $sth->fetchrow_array();
375 print STDERR
376 "select existing accession: $accession_id, $chado_organism_id, $common_name\n";
378 if ($accession_id) {
379 unless ($chado_organism_id) {
380 $sth = $dbh->prepare(
381 "UPDATE sgn.accession
382 SET chado_organism_id = ?
383 WHERE accession_id = $accession_id"
385 $sth->execute($existing_organism_id);
388 elsif ( !$accession_id ) {
390 $sth = $dbh->prepare(
391 "INSERT INTO sgn.accession
392 (common_name, chado_organism_id)
393 VALUES (?,?)"
395 $sth->execute( $cultivar, $existing_organism_id );
396 $accession_id = $dbh->last_insert_id( "accession", "sgn" );
398 #my $accession = CXGN::Accession->new($dbh, $accession_id);
399 #$common_name = $accession->accession_common_name();
400 print STDERR
401 "inserted: $accession_id, $chado_organism_id, $common_name\n";
404 my ( $accession_names_id, $accession_name );
406 unless ( !$common_name ) {
407 $sth = $dbh->prepare(
408 "SELECT accession_name_id, accession_name
409 FROM sgn.accession_names
410 WHERE accession_name ILIKE ?"
412 $sth->execute($common_name);
414 ( $accession_names_id, $accession_name ) = $sth->fetchrow_array();
415 print STDERR
416 "selected existing accession_names: $accession_names_id, $accession_name\n";
418 unless ($accession_names_id) {
419 $sth = $dbh->prepare(
420 "INSERT INTO sgn.accession_names
421 (accession_name, accession_id)
422 VALUES (?, ?)"
424 $sth->execute( $common_name, $accession_id );
426 $accession_names_id =
427 $dbh->last_insert_id( "accession_names", "sgn" );
428 print STDERR
429 "inserted accession_names : $common_name, $accession_id\n";
433 unless ( !$accession_names_id ) {
434 $sth = $dbh->prepare(
435 "UPDATE sgn.accession
436 SET accession_name_id = ?
437 WHERE accession_id = ?"
439 $sth->execute( $accession_names_id, $accession_id );
440 print STDERR "updated accession: with $accession_names_id\n";
443 if (@_) {
444 print STDERR "@_\n";
445 $dbh->rollback();
446 return 0;
448 else {
449 $dbh->commit();
450 return $accession_id;
456 =head2 store_traits
458 Usage: my ($true_or_false) = $self->store_traits($file);
459 Desc: reads traits, their definition, and unit from
460 user submitted tab-delimited traits file and stores traits
461 that does not exist in the db or exist but with different units
462 Ret: true or false
463 Args: tab delimited trait file, with full path
464 Side Effects: accesses database
465 Example:
467 =cut
469 sub store_traits {
470 my $self = shift;
471 my $file = shift;
472 my $pop_id = $self->get_population_id();
473 my $sp_person_id = $self->get_sp_person_id();
474 my $dbh = $self->get_dbh();
476 open( F, "<$file" ) || die "Can't open file $file.";
478 my $header = <F>;
479 chomp($header);
480 my @fields = split /\t/, $header;
481 @fields = map { lc( $_ ) } @fields;
483 my ( $trait, $trait_id, $trait_name, $unit, $unit_id );
485 if ( $fields[0] !~ /trait|name/
486 || $fields[1] !~ /definition/
487 || $fields[2] !~ /unit/
490 my $error =
491 "Data columns in the traits file need to be in the order of:
492 <b>traits -> definition -> unit</b>. <br/>
493 Now they are in the order of <b><i>$fields[0] -> $fields[1]
494 -> $fields[2]</i></b>.\n";
496 $self->trait_columns($error);
498 else {
500 eval {
501 while (<F>)
503 chomp;
504 my (@values) = split /\t/;
506 $trait =
507 CXGN::Phenome::UserTrait->new_with_name( $dbh, $values[0] );
509 if ( !$trait ) {
510 $trait = CXGN::Phenome::UserTrait->new($dbh);
512 $trait->set_cv_id(17);
513 $trait->set_name( $values[0] );
514 $trait->set_definition( $values[1] );
515 $trait->set_sp_person_id($sp_person_id);
516 $trait_id = $trait->store();
518 $trait = CXGN::Phenome::UserTrait->new( $dbh, $trait_id );
519 $trait_id = $trait->get_user_trait_id();
521 unless ( !$values[2] ) {
522 $unit_id = $trait->get_unit_id( $values[2] );
523 if ( !$unit_id ) {
524 $unit_id = $trait->insert_unit( $values[2] );
528 if ( ($trait_id) && ($pop_id) && ($unit_id) ) {
529 $trait->insert_user_trait_unit( $trait_id, $unit_id,
530 $pop_id );
535 else {
537 unless ( !$values[2] ) {
538 $trait_id = $trait->get_user_trait_id();
539 $unit_id = $trait->get_unit_id( $values[2] );
540 if ( !$unit_id ) {
541 $unit_id = $trait->insert_unit( $values[2] );
544 if ( ($trait_id) && ($pop_id) && ($unit_id) ) {
545 $trait->insert_user_trait_unit( $trait_id, $unit_id,
546 $pop_id );
556 if ($@) {
557 print STDERR "An error occurred storing traits: $@\n";
558 $dbh->rollback();
559 return 0;
561 else {
562 print STDERR "Committing...traits\n";
563 return 1;
568 =head2 store_individual
570 Usage: $individual_id = $self->store_individual($dbh, $name, $pop_id, $sp_person_id);
571 Desc: stores individual genotypes is they don't
572 exist in the same pop in the db
573 Ret: individual id
574 Args: db handle, individual name, population id sp_person_id
575 Side Effects: accesses database
576 Example:
578 =cut
580 sub store_individual {
581 my $self = shift;
582 my $ind_name = shift;
583 my $pop_id = $self->get_population_id();
584 my $sp_person_id = $self->get_sp_person_id();
585 my $dbh = $self->get_dbh();
586 my $common_name_id = $self->common_name_id();
588 my ( $individual, $individual_id, $individual_name );
589 my @individuals =
590 CXGN::Phenome::Individual->new_with_name( $dbh, $ind_name, $pop_id );
592 eval {
593 if ( scalar(@individuals) == 0 )
595 $individual = CXGN::Phenome::Individual->new($dbh);
596 $individual->set_name($ind_name);
597 $individual->set_population_id($pop_id);
598 $individual->set_sp_person_id($sp_person_id);
599 $individual->set_common_name_id($common_name_id);
600 $individual_id = $individual->store();
602 $individual_name = $individual->get_name();
605 elsif ( scalar(@individuals) == 1 ) {
607 print STDERR "There is a genotype with name $ind_name
608 in the same population ($pop_id). \n";
609 die "There might be a phenotype data for the same trait
610 for the same genotype $ind_name. I can't store
611 duplicate phenotype data. So I am quitting..\n";
613 elsif ( scalar(@individuals) > 0 ) {
614 die "There are two genotypes with the same name ($ind_name)
615 in the population: $pop_id.\n";
618 if ($@) {
619 $dbh->rollback();
620 print STDERR "An error occurred storing individuals: $@\n";
621 return 0;
624 else {
625 $dbh->commit();
626 print STDERR "STORED individual $individual_name.\n";
627 return $individual;
631 =head2 store_trait_values
633 Usage: my ($true_or_false) = &store_trait_values($dbh, $file, $pop_id, $sp_person_id);
634 Desc: stores phenotype values for traits evaluated for individuals of a population.
635 Ret: true or false
636 Args: db handle, tab delimited phenotype file with full path, population id, sp_person_id
637 Side Effects: accesses database
638 Example:
640 =cut
642 sub store_trait_values {
643 my $self = shift;
644 my $file = shift;
645 my $pop_id = $self->get_population_id();
646 my $sp_person_id = $self->get_sp_person_id();
647 my $dbh = $c->dbc->dbh;
648 open( F, "<$file" ) || die "Can't open file $file.";
650 my $header = <F>;
651 chomp($header);
652 my @fields = split /\t/, $header;
654 my @trait = ();
655 my ( $trait_name, $trait_id );
657 for ( my $i = 1 ; $i < @fields ; $i++ )
659 $trait[$i] = CXGN::Phenome::UserTrait->new_with_name( $dbh, $fields[$i] );
660 $trait_name = $trait[$i]->get_name();
661 $trait_id = $trait[$i]->get_user_trait_id();
663 eval {
664 while (<F>)
666 chomp;
667 my (@values) = split /\t/;
669 my $individual = $self->store_individual( $values[0] );
671 die "The genotype does not exist in the database.
672 Therefore, it can not store the associated
673 phenotype data\n"
674 unless ($individual);
676 my $individual_id = $individual->get_individual_id();
677 my $individual_name = $individual->get_name();
679 for ( my $i = 1 ; $i < @values ; $i++ ) {
680 my $phenotype = CXGN::Chado::Phenotype->new($dbh);
681 $phenotype->set_unique_name(
682 qq | $individual_name $pop_id .":". $i |);
683 $phenotype->set_observable_id(
684 $trait[$i]->get_user_trait_id() );
685 if (!$values[$i]) {$values[$i] = undef;}
686 if ($values[$i] && $values[$i] =~ /NA|-|\s+/ig)
688 $values[$i] = undef;
690 $phenotype->set_value($values[$i]);
691 $phenotype->set_individual_id($individual_id);
692 $phenotype->set_sp_person_id($sp_person_id);
693 my $phenotype_id = $phenotype->store();
695 $trait[$i]->insert_phenotype_user_trait_ids(
696 $trait[$i]->get_user_trait_id(),
697 $phenotype_id );
703 if ($@) {
704 $dbh->rollback();
705 print STDERR "An error occurred storing trait values: $@\n";
706 return 0;
709 else {
710 print STDERR "Committing...trait values to tables public.phenotype
711 and user_trait_id and phenotype_id to phenotype_user_trait\n";
712 return 1;
718 =head2 store_map
720 Usage:
721 Desc:
722 Ret:
723 Args:
724 Side Effects:
725 Example:
727 =cut
729 sub store_map {
730 my $self = shift;
731 my $file = shift;
733 my $dbh = $self->get_dbh();
734 my $pop_id = $self->get_population_id();
736 my $pop = CXGN::Phenome::Population->new( $dbh, $pop_id );
737 my $pop_name = $pop->get_name();
738 my $parent_m = $pop->get_male_parent_id();
739 my $parent_f = $pop->get_female_parent_id();
740 my $desc = $pop->get_description();
742 my $acc = CXGN::Accession->new( $dbh, $parent_f );
743 my $female_name = $acc->accession_common_name();
744 my $chado_org_id_f = $acc->chado_organism_id();
746 $acc = CXGN::Accession->new( $dbh, $parent_m );
747 my $male_name = $acc->accession_common_name();
748 my $chado_org_id_m = $acc->chado_organism_id();
750 my $existing_map_id = CXGN::Map::Tools::population_map( $dbh, $pop_id );
752 my ( $map, $map_id, $map_version_id );
753 if ($existing_map_id) {
754 $map_version_id =
755 CXGN::Map::Version->map_version( $dbh, $existing_map_id );
756 $map = CXGN::Map->new( $dbh, { map_id => $existing_map_id } );
759 else {
760 $map = CXGN::Map->new_map( $dbh, $pop_name );
761 $map_version_id = $map->{map_version_id};
763 $map_id = $map->{map_id};
765 my $species_m = $self->species($chado_org_id_m);
766 my $species_f = $self->species($chado_org_id_f);
768 my $long_name =
769 $species_f . ' cv. '
770 . $female_name . ' x '
771 . $species_m . ' cv. '
772 . $male_name;
773 print STDERR "map long name: $long_name\n";
774 $map->{long_name} = $long_name;
775 $map->{map_type} = 'genetic';
776 $map->{parent_1} = $parent_f;
777 $map->{parent_2} = $parent_m;
778 $map->{abstract} = $desc;
779 $map->{population_id} = $pop_id;
780 $map_id = $map->store();
782 my $lg_result;
783 if ($map_version_id) {
784 $lg_result = $self->store_lg( $map_version_id, $file );
786 if ($lg_result) {
787 print STDERR " STORED LINKAGE GROUPS\n";
789 else {
790 print STDERR "FAILED STORING LINKAGE GROUPS\n";
794 if ( $map_id && $map_version_id && $lg_result ) {
795 return $map_id, $map_version_id;
797 else {
798 print STDERR "Either map or map_version or
799 linkage_groups storing did not work\n";
800 return 0;
805 =head2 species
807 Usage: my $species = $self->species($org_id)
808 Desc: when given the chado.organism_id, it returns the
809 genus and species name (in abbreviated format)
810 Ret: abbreviated species name
811 Args: chado organism id
812 Side Effects: access db
813 Example:
815 =cut
817 sub species {
818 my $self = shift;
819 my $org_id = shift;
820 my $dbh = $self->get_dbh();
822 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
824 my $org = CXGN::Chado::Organism->new( $schema, $org_id );
826 return my $species = $org->get_abbreviation();
830 =head2 store_lg
832 Usage:
833 Desc:
834 Ret:
835 Args:
836 Side Effects:
837 Example:
839 =cut
841 sub store_lg {
842 my $self = shift;
843 my ( $map_version_id, $file ) = @_;
844 my $dbh = $self->get_dbh();
846 open F, "<$file" or die "can't open $file\n";
847 my $markers = <F>;
848 my $chr = <F>;
849 chomp($chr);
850 close F;
852 my @chrs = split /\t/, $chr;
853 @chrs = uniq @chrs;
855 die "The first cell of 2nd row must be empty." unless !$chrs[0];
856 shift(@chrs);
858 my $lg = CXGN::LinkageGroup->new( $dbh, $map_version_id, \@chrs );
859 my $result = $lg->store();
861 if ($result) {
862 print STDERR "Succeeded storing linkage groups
863 on map_version_id $map_version_id\n";
865 else {
866 print STDERR "Failed storing linkage groups
867 on map_version_id $map_version_id\n";
872 =head2 store_markers
874 Usage:
875 Desc:
876 Ret:
877 Args:
878 Side Effects:
879 Example:
881 =cut
883 sub store_marker_and_position {
884 my $self = shift;
885 my ( $file, $map_version_id ) = @_;
886 my $dbh = $self->get_dbh();
887 open F, "<$file" or die "can't open $file\n";
889 my $markers = <F>;
890 my $chrs = <F>;
891 my $positions = <F>;
892 chomp( $markers, $chrs, $positions );
893 close F;
895 my @markers = split /\t/, $markers;
896 shift(@markers);
898 my @positions = split /\t/, $positions;
899 shift(@positions);
901 my @chromosomes = split /\t/, $chrs;
902 shift(@chromosomes);
904 eval {
905 for ( my $i = 0 ; $i < @markers ; $i++ )
907 print STDERR $markers[$i] . "\t" . $positions[$i] . "\n";
909 my ( $marker_name, $subs ) =
910 CXGN::Marker::Tools::clean_marker_name( $markers[$i] );
912 my @marker_ids =
913 CXGN::Marker::Tools::marker_name_to_ids( $dbh, $marker_name );
914 if ( @marker_ids > 1 ) {
915 die "Too many IDs found for marker '$marker_name'";
917 my ($marker_id) = @marker_ids;
919 my $marker_obj;
920 if ($marker_id) {
921 $marker_obj = CXGN::Marker::Modifiable->new( $dbh, $marker_id );
923 else {
924 $marker_obj = CXGN::Marker::Modifiable->new($dbh);
925 $marker_obj->set_marker_name($marker_name);
926 my $inserts = $marker_obj->store_new_data();
928 if ( $inserts and @{$inserts} ) {
930 else {
931 die "Oops, I thought I was inserting some new data";
933 $marker_id = $marker_obj->marker_id();
935 my $loc = $marker_obj->new_location();
936 my $pos = $positions[$i];
937 my $conf = 'uncalculated';
938 my $protocol = 'unknown';
939 $loc->marker_id($marker_id);
941 $loc->map_version_id($map_version_id);
942 $loc->lg_name( $chromosomes[$i] );
943 $loc->position($pos);
944 $loc->confidence($conf);
945 $loc->subscript($subs);
947 $marker_obj->add_experiment(
948 { location => $loc, protocol => $protocol } );
949 my $inserts = $marker_obj->store_new_data();
951 if ( $inserts and @{$inserts} ) {
955 else {
956 die "Oops, I thought I was inserting some new data";
961 if ($@) {
962 print STDERR $@;
963 print STDERR
964 "Failed loading markers and their positions; rolling back.\n";
965 $dbh->rollback();
966 return 0;
968 else {
969 print STDERR "Succeeded. loading markers and their position\n";
971 $dbh->commit();
972 return 1;
977 =head2 store_genotype
979 Usage:
980 Desc:
981 Ret:
982 Args:
983 Side Effects:
984 Example:
986 =cut
988 sub store_genotype {
989 my $self = shift;
990 my ( $file, $map_version_id ) = @_;
991 my $dbh = $self->get_dbh();
992 my $pop_id = $self->get_population_id();
994 open F, "<$file" or die "can't open $file\n";
996 my $markers = <F>;
997 my $chrs = <F>;
998 my $positions = <F>;
999 chomp( $markers, $chrs, $positions );
1001 my @markers = split /\t/, $markers;
1002 shift(@markers);
1004 my @chrs = split /\t/, $chrs;
1005 shift(@chrs);
1007 my $pop = CXGN::Phenome::Population->new( $dbh, $pop_id );
1008 my $pop_name = $pop->get_name();
1009 my $sp_person_id = $pop->get_sp_person_id();
1011 my $map = CXGN::Map->new( $dbh, { map_version_id => $map_version_id } );
1012 my $map_id = $map->get_map_id();
1014 my $linkage = CXGN::LinkageGroup->new( $dbh, $map_version_id );
1016 unless ($map_id) {
1017 die "I need a valid reference map before I can
1018 start loading the genotype data\n";
1021 eval {
1023 my $experiment = CXGN::Phenome::GenotypeExperiment->new($dbh);
1024 $experiment->set_background_accession_id(100);
1025 $experiment->set_experiment_name($pop_name);
1026 $experiment->set_reference_map_id($map_id);
1027 $experiment->set_sp_person_id($sp_person_id);
1028 $experiment->set_preferred(1);
1029 my $experiment_id = $experiment->store();
1031 while ( my $row = <F> ) {
1032 chomp($row);
1033 my @plant_genotype = split /\t/, $row;
1034 my $plant_name = shift(@plant_genotype);
1035 my @individual =
1036 CXGN::Phenome::Individual->new_with_name( $dbh, $plant_name,
1037 $pop_id );
1039 my $individual_id = $individual[0]->get_individual_id();
1041 die "There are two genotypes with the same name or no genotypes
1042 in the same population. Can't assign genotype values."
1043 unless ( scalar(@individual) == 1 );
1045 if ( $individual[0] ) {
1047 my $genotype = CXGN::Phenome::Genotype->new($dbh);
1049 $genotype->set_genotype_experiment_id($experiment_id);
1050 $genotype->set_individual_id($individual_id);
1052 #$genotype->set_experiment_name($pop_name);
1053 #$genotype->set_reference_map_id($map_id);
1054 #$genotype->set_sp_person_id($sp_person_id);
1055 my $genotype_id = $genotype->store();
1057 my $mapmaker_genotype;
1058 for ( my $i = 0 ; $i < @plant_genotype ; $i++ ) {
1059 my $genotype_region =
1060 CXGN::Phenome::GenotypeRegion->new($dbh);
1062 my $marker_name =
1063 CXGN::Marker::Tools::clean_marker_name( $markers[$i] );
1064 my $marker =
1065 CXGN::Marker->new_with_name( $dbh, $marker_name );
1066 my $c = $chrs[$i];
1067 my $lg_id = $linkage->get_lg_id( $chrs[$i] );
1069 if ( !$plant_genotype[$i]
1070 || ( $plant_genotype[$i] =~ /\-/ ) )
1072 next();
1075 $genotype_region->set_genotype_id($genotype_id);
1076 $genotype_region->set_marker_id_nn( $marker->marker_id() );
1077 $genotype_region->set_marker_id_ns( $marker->marker_id() );
1078 $genotype_region->set_marker_id_sn( $marker->marker_id() );
1079 $genotype_region->set_marker_id_ss( $marker->marker_id() );
1080 $genotype_region->set_lg_id($lg_id);
1081 $genotype_region->set_sp_person_id($sp_person_id);
1083 if ( $i == 0 ) {
1084 if ( $plant_genotype[$i] =~ /\d/ ) {
1085 $mapmaker_genotype = 1;
1087 elsif ( $plant_genotype[$i] =~ /\D/ ) {
1088 $mapmaker_genotype = undef;
1092 if ($mapmaker_genotype) {
1093 $genotype_region->set_mapmaker_zygocity_code(
1094 $plant_genotype[$i] );
1096 else {
1097 $genotype_region->set_zygocity_code(
1098 $plant_genotype[$i] );
1100 $genotype_region->set_type("map");
1101 $genotype_region->store();
1105 else {
1107 "There is mismatch between the list of genotypes/lines ($plant_genotype[0]
1108 in your phenotype and genotype datasets\n";
1114 if ($@) {
1115 $dbh->rollback();
1116 print STDERR "An error occurred loading genotype data:
1117 $@. ROLLED BACK CHANGES.\n";
1118 return undef;
1120 else {
1121 print STDERR "All is fine. Committing...genotype data\n";
1122 $dbh->commit();
1123 return 1;
1128 =head2 accessors get_sp_person_id, set_sp_person_id
1130 Usage:
1131 Desc:
1132 Property
1133 Side Effects:
1134 Example:
1136 =cut
1138 sub get_sp_person_id {
1139 my $self = shift;
1140 return $self->{sp_person_id};
1143 sub set_sp_person_id {
1144 my $self = shift;
1145 $self->{sp_person_id} = shift;
1148 =head2 accessors get_population_id, set_population_id
1150 Usage:
1151 Desc:
1152 Property
1153 Side Effects:
1154 Example:
1156 =cut
1158 sub get_population_id {
1159 my $self = shift;
1160 return $self->{population_id};
1163 sub set_population_id {
1164 my $self = shift;
1165 $self->{population_id} = shift;
1168 =head2 accessors get_dbh, set_dbh
1170 Usage:
1171 Desc:
1172 Property
1173 Side Effects:
1174 Example:
1176 =cut
1178 sub get_dbh {
1179 my $self = shift;
1180 return $self->{dbh};
1183 sub set_dbh {
1184 my $self = shift;
1185 $self->{dbh} = shift;
1188 =head2 common_name_id
1190 Usage:
1191 Desc:
1192 Ret:
1193 Args:
1194 Side Effects:
1195 Example:
1197 =cut
1199 sub common_name_id {
1200 my $self = shift;
1201 my $sp_person_id = $self->get_sp_person_id();
1202 my $qtl = CXGN::Phenome::Qtl->new($sp_person_id);
1203 my ( $qtl_dir, $user_qtl_dir ) = $qtl->get_user_qtl_dir($c);
1205 my $id;
1206 if ( -e "$user_qtl_dir/organism.txt" ) {
1207 open C, "<$user_qtl_dir/organism.txt" or die "Can't open file: !$\n";
1209 my $row = <C>;
1210 if ( $row =~ /(\d)/ ) {
1211 $id = $1;
1214 close C;
1216 return $id;
1218 else {
1219 return 0;
1224 =head2 error_page
1226 Usage: $self->error_page(@errors);
1227 Desc: when feed with error messages, it generates an
1228 error page with a list of the messages and a link
1229 back to the previous page where required data field(s)
1230 was/were not properly filled.
1231 Ret: page with the appropriate message
1232 Args: a list of messages to print...
1233 Side Effects:
1234 Example:
1236 =cut
1238 sub error_page {
1239 my $self = shift;
1240 my @error = @_;
1242 $c->forward_to_mason_view('/qtl/qtl_load/missing_data.mas',
1243 missing_data => \@error,
1244 guide => $self->guideline(),
1248 =head2 check_organism
1250 Usage: $self->check_organism($organism);
1251 Desc: checks if organism object is defined and if the
1252 the parental species is supported by sgn (chado.organism).
1253 in case organism object is not defined (a query to the chado.organism
1254 using a species name does not return a value, it generates
1255 a page with advise to check for the spelling of the scientific species name.
1256 Ret: a page with advice
1257 Args: organism object, species name, cultivar name
1258 Side Effects:
1259 Example:
1261 =cut
1263 sub check_organism {
1264 my ($self, $organism, $species, $cultivar) = @_ ;
1266 unless ( !$cultivar ) {
1267 $cultivar = " cv. $cultivar";
1270 if ( !$organism )
1272 $c->forward_to_mason_view('/qtl/qtl_load/check_organism.mas',
1273 species => $species,
1274 cultivar => $cultivar,
1275 guide => $self->guideline(),
1277 } else
1279 #do nothing..relax
1284 =head2 population_exists
1286 Usage: $self->population_exists($population, $population_name);
1287 Desc: checks if there is already a population with the same name
1288 and if so it generates a page with the appropriate advice to the user
1290 Ret: a page with advice
1291 Args: population object, population name
1292 Side Effects:
1293 Example:
1295 =cut
1297 sub population_exists {
1298 my ($self, $pop, $name) = @_;
1300 if ($pop) {
1302 $c->forward_to_mason_view('/qtl/qtl_load/population_exists.mas',
1303 name => $name,
1304 guide => $self->guideline()
1311 sub guideline {
1312 my $self = shift;
1313 return qq |<a href="/qtl/submission/guide">Guidelines</a> |;
1316 =head2 trait_columns
1318 Usage: $self->trait_columns($error);
1319 Desc: checks if the trait file has the right order
1320 of data columns and if not advises the submitter
1321 with the appropriate message
1323 Ret: a page with advice
1324 Args: text message
1325 Side Effects:
1326 Example:
1328 =cut
1330 sub trait_columns {
1331 my ($self, $trait_error) = @_;
1333 if ($trait_error) {
1334 $c->forward_to_mason_view('/qtl/qtl_load/trait_columns.mas',
1335 error => $trait_error,
1336 guide => $self->guideline()
1342 =head2 accessors compare_file_names
1344 Usage: $f = $self->compare_file_names($file1, $file2);
1345 Desc: useful for checking if data files submitted for the traits,
1346 phenotype and genotype are different. helpful to avoid indvertent
1347 uploading of the same file for different fields.
1349 Ret: a page with advice if the same files are uploaded
1350 Args: file names to compare
1351 Side Effects:
1352 Example:
1354 =cut
1356 sub compare_file_names {
1357 my ($self, $file1, $file2) = @_;
1359 unless ( $file1 ne $file2 ) {
1360 $c->forward_to_mason_view('/qtl/qtl_load/compare_file_names.mas',
1361 file1 => $file1,
1362 file2 => $file2,
1363 guide => $self->guideline()
1368 =head2 send_email
1370 Usage: $self->send_email($subj, $message, $pop_id);
1371 Desc: sends email at each step of the qtl data upload
1372 process..
1373 Ret: nothing
1374 Args: subject, message, population_id
1375 Side Effects:
1376 Example:
1378 =cut
1380 sub send_email {
1381 my $self = shift;
1382 my ( $subj, $message, $pop_id ) = @_;
1383 my $dbh = $self->get_dbh();
1384 my $sp_person_id = $self->get_sp_person_id();
1385 my $person = CXGN::People::Person->new( $dbh, $sp_person_id );
1387 my $user_profile =
1388 qq |http://solgenomics.net/solpeople/personal-info.pl?sp_person_id=$sp_person_id |;
1390 my $username = $person->get_first_name() . " " . $person->get_last_name();
1391 $message .=
1392 qq |\nQTL population id: $pop_id \nQTL data owner: $username ($user_profile) |;
1394 print STDERR "\n$subj\n$message\n";
1395 CXGN::Contact::send_email( $subj, $message,
1396 'sgn-db-curation@sgn.cornell.edu' );
1401 sub post_stat_form {
1402 my ($self, $args_ref) = @_;
1404 my $sp_person_id = $self->get_sp_person_id();
1405 my $qtl_obj = CXGN::Phenome::Qtl->new($sp_person_id, $args_ref );
1406 my $qtl_tools = CXGN::Phenome::Qtl::Tools->new();
1407 my $stat_param = $qtl_obj->user_stat_parameters();
1408 my @missing = $qtl_tools->check_stat_fields($stat_param);
1409 my $pop_id = $args_ref->{pop_id};
1411 my ($stat_file, $type);
1412 if (@missing) {
1413 $self->error_page(@missing);
1415 else {
1416 $stat_file = $qtl_obj->user_stat_file( $c, $pop_id );
1417 $type = 'confirm';
1420 if ($type eq 'confirm') {
1421 my $referer = $c->req->base . "qtl/form/stat_form/$pop_id";
1422 if (-e $stat_file && $c->req->referer eq $referer)
1424 my $qtlpage = $c->req->base . "qtl/population/$pop_id";
1425 my $message = qq | QTL statistical parameters set: Step 5 of 5.
1426 QTL data upload for<a href="$qtlpage">population
1427 $pop_id</a> is completed. |;
1429 $self->send_email( '[QTL upload: Step 5]', $message, $pop_id );
1430 $self->redirect_to_next_form($c->req->base . "qtl/form/confirm/$pop_id");
1433 else
1435 $c->res->redirect($c->req->referer);
1436 $c->detach();
1438 } else
1440 $c->res->redirect($c->req->referer);
1441 $c->detach();
1445 sub show_pop_form {
1446 my ( $self ) = @_;
1447 $self->send_email( '[QTL upload: Step 1]', 'A user is at the QTL data upload Step 1 of 5', 'NA' );
1448 $self->redirect_to_next_form($c->req->base . "qtl/form/pop_form");
1451 sub post_pop_form {
1452 my ($self, $qtl_obj, $qtl_tools) = @_;
1454 my $pop_detail = $qtl_obj->user_pop_details();
1455 my @error = $qtl_tools->check_pop_fields($pop_detail);
1457 my ( $pop_id, $pop_name, $desc );
1458 if (@error)
1460 $self->error_page(@error);
1462 else
1464 ( $pop_id, $pop_name, $desc ) =
1465 $self->load_pop_details($pop_detail);
1468 unless ( !$pop_id )
1470 $self->send_email( '[QTL upload: Step 1]', 'QTL population data uploaded: Step 1 of 5 completed', $pop_id );
1471 $self->redirect_to_next_form($c->req->base . "qtl/form/trait_form/$pop_id");
1475 sub post_trait_form {
1476 my ($self, $qtl_obj, $trait_file, $pop_id) = @_;
1478 if (!$trait_file)
1480 $self->error_page("Trait file");
1483 my $uploaded_file = $self->trait_upload($qtl_obj, $trait_file);
1485 my $traits_in_db;
1486 if ($uploaded_file)
1488 $traits_in_db = $self->store_traits($uploaded_file);
1491 if ($pop_id && $traits_in_db)
1493 $self->send_email('[QTL upload: Step 2]', 'QTL traits uploaded: Step 2 of 5', $pop_id);
1494 $self->redirect_to_next_form($c->req->base . "qtl/form/pheno_form/$pop_id");
1501 sub post_pheno_form {
1502 my ($self, $qtl_obj, $pheno_file, $pop_id) = @_;
1504 if (!$pheno_file)
1506 $self->error_page('Phenotype dataset file');
1509 my $uploaded_file = $self->pheno_upload($qtl_obj, $pheno_file);
1511 my $phenotype_in_db;
1512 if ($uploaded_file)
1514 $phenotype_in_db = $self->store_trait_values($uploaded_file);
1517 if ($phenotype_in_db && $pop_id)
1519 $self->send_email('[QTL upload: Step 3]', 'QTL phenotype data uploaded: Step 3 of 5', $pop_id);
1520 $self->redirect_to_next_form($c->req->base . "qtl/form/geno_form/$pop_id");
1525 sub post_geno_form {
1526 my ($self, $qtl_obj, $geno_file, $pop_id) = @_;
1528 if (!$geno_file)
1530 $self->error_page('Genotype dataset file');
1533 my ($map_id, $map_version_id);
1534 my $uploaded_file = $self->geno_upload( $qtl_obj, $geno_file);
1536 if ($uploaded_file)
1538 ( $map_id, $map_version_id ) = $self->store_map($uploaded_file);
1540 else
1542 $self->error_page('Genotype dataset file');
1545 my $genotype_uploaded;
1547 if ($map_version_id)
1549 my $result = $self->store_marker_and_position($uploaded_file, $map_version_id);
1551 unless ($result)
1553 $c->throw_404("Couldn't store markers and position.");
1556 my $genotype_uploaded = $self->store_genotype($uploaded_file, $map_version_id);
1558 if ($genotype_uploaded)
1560 $self->send_email( '[QTL upload: Step 4]', 'QTL genotype data uploaded : Step 4 of 5', $pop_id );
1561 $self->redirect_to_next_form($c->req->base . "qtl/form/stat_form/$pop_id");
1563 else
1565 $c->throw_404("failed storing genotype data.");
1570 sub redirect_to_next_form {
1571 my ($self, $next_form) = @_;
1572 $c->res->redirect("$next_form");
1573 $c->detach();