diff --git a/definitions/install_parameters.yaml b/definitions/install_parameters.yaml index 3d3b10faa..2f03a45fd 100644 --- a/definitions/install_parameters.yaml +++ b/definitions/install_parameters.yaml @@ -73,6 +73,7 @@ rd_dna: - cnvnator - cyrius - deepvariant + - deeptrio - delly - expansionhunter - fastqc diff --git a/definitions/rd_dna_initiation_map.yaml b/definitions/rd_dna_initiation_map.yaml index fed2259df..cd9837604 100644 --- a/definitions/rd_dna_initiation_map.yaml +++ b/definitions/rd_dna_initiation_map.yaml @@ -55,6 +55,7 @@ CHAIN_ALL: - PARALLEL: - CHAIN_DEEPVAR: - deepvariant + - deeptrio - glnexus_merge - GATK_HAPLOTYPECALLER: - gatk_haplotypecaller diff --git a/definitions/rd_dna_parameters.yaml b/definitions/rd_dna_parameters.yaml index 44e57632a..9819745a0 100755 --- a/definitions/rd_dna_parameters.yaml +++ b/definitions/rd_dna_parameters.yaml @@ -83,6 +83,7 @@ gpu_capable_executables: data_type: ARRAY default: - run_deepvariant + - run_deeptrio - call_variants type: mip ## HumanGenomeReference @@ -150,6 +151,7 @@ recipe_core_number: chromograph_rhoviz: 1 chromograph_upd: 1 cnvnator_ar: 13 + deeptrio: 36 deepvariant: 36 delly_call: 36 delly_reformat: 13 @@ -214,6 +216,7 @@ recipe_gpu_number: data_type: HASH default: deepvariant: 1 + deeptrio: 1 type: mip set_recipe_gpu_number: associated_recipe: @@ -279,6 +282,7 @@ recipe_time: chromograph_rhoviz: 1 chromograph_upd: 1 cnvnator_ar: 1 + deeptrio: 15 deepvariant: 10 delly_call: 20 delly_reformat: 7 @@ -511,6 +515,17 @@ deepvariant: program_executables: - run_deepvariant type: recipe +deeptrio: + analysis_mode: case + associated_recipe: + - mip + data_type: SCALAR + default: 1 + file_tag: _deeptrio + outfile_suffix: ".g.vcf.gz" + program_executables: + - run_deeptrio + type: recipe glnexus_merge: analysis_mode: case associated_recipe: diff --git a/lib/MIP/Cli/Mip/Install.pm b/lib/MIP/Cli/Mip/Install.pm index 4b2ba009c..1d73b5083 100644 --- a/lib/MIP/Cli/Mip/Install.pm +++ b/lib/MIP/Cli/Mip/Install.pm @@ -131,8 +131,8 @@ sub _build_usage { enum( [ qw{ arriba bedtools blobfish bootstrapann bwa bwakit bwa-mem2 cadd chanjo - chromograph cnvnator cyrius deepvariant delly expansionhunter fastqc gatk gatk4 - genmod gffcompare glnexus htslib manta mip mip_scripts multiqc peddy picard plink + chromograph cnvnator cyrius deeptrio deepvariant delly expansionhunter fastqc gatk + gatk4 genmod gffcompare glnexus htslib manta mip mip_scripts multiqc peddy picard plink preseq python rhocall rseqc rtg-tools salmon sambamba smncopynumbercaller star star-fusion stranger stringtie svdb telomerecat tiddit trim-galore ucsc upd utilities varg vcf2cytosure vcfanno vep vts } @@ -153,8 +153,8 @@ sub _build_usage { enum( [ qw{ arriba bedtools blobfish bootstrapann bwa bwakit bwa-mem2 cadd chanjo - chromograph cnvnator cyrius deepvariant delly expansionhunter fastqc gatk gatk4 - genmod gffcompare glnexus htslib manta mip mip_scripts multiqc peddy picard plink + chromograph cnvnator cyrius deeptrio deepvariant delly expansionhunter fastqc gatk + gatk4 genmod gffcompare glnexus htslib manta mip mip_scripts multiqc peddy picard plink preseq python rhocall rseqc rtg-tools salmon sambamba smncopynumbercaller star star-fusion stranger stringtie svdb telomerecat tiddit trim-galore ucsc upd utilities varg vcf2cytosure vcfanno vep vts } diff --git a/lib/MIP/Pedigree.pm b/lib/MIP/Pedigree.pm index 188c735ee..47f48a091 100644 --- a/lib/MIP/Pedigree.pm +++ b/lib/MIP/Pedigree.pm @@ -34,6 +34,7 @@ BEGIN { create_fam_file get_is_trio gatk_pedigree_flag + has_duo has_trio is_sample_proband_in_trio parse_pedigree @@ -47,6 +48,7 @@ BEGIN { } ## Constants +Readonly my $DUO_MEMBERS_COUNT => 2; Readonly my $TRIO_MEMBERS_COUNT => 3; sub check_founder_id { @@ -490,6 +492,62 @@ sub get_is_trio { return; } +sub has_duo { + +## Function : Check if case has a parent-child duo and child is affected +## Returns : 0 | 1 +## Arguments : $active_parameter_href => Active parameters for this analysis hash {REF} +## : $sample_info_href => Info on samples and case hash {REF} + + my ($arg_href) = @_; + + ## Flatten argument(s) + my $active_parameter_href; + my $sample_info_href; + + my $tmpl = { + active_parameter_href => { + default => {}, + defined => 1, + required => 1, + store => \$active_parameter_href, + strict_type => 1, + }, + sample_info_href => { + default => {}, + defined => 1, + required => 1, + store => \$sample_info_href, + strict_type => 1, + }, + }; + + check( $tmpl, $arg_href, 1 ) or croak q{Could not parse arguments!}; + + use MIP::Sample_info qw{ get_pedigree_sample_id_attributes }; + + ## Has two samples + return 0 + if ( scalar @{ $active_parameter_href->{sample_ids} } != $DUO_MEMBERS_COUNT ); + + SAMPLE_ID: + foreach my $sample_id ( @{ $active_parameter_href->{sample_ids} } ) { + + my %sample_attributes = get_pedigree_sample_id_attributes( + { + sample_id => $sample_id, + sample_info_href => $sample_info_href, + } + ); + + ## Find a child + next SAMPLE_ID if ( not( $sample_attributes{father} or $sample_attributes{mother} ) ); + + return 1 if ( $sample_attributes{phenotype} eq q{affected} ); + } + return 0; +} + sub has_trio { ## Function : Check if case has trio diff --git a/lib/MIP/Program/Deeptrio.pm b/lib/MIP/Program/Deeptrio.pm new file mode 100644 index 000000000..abb0798da --- /dev/null +++ b/lib/MIP/Program/Deeptrio.pm @@ -0,0 +1,249 @@ +package MIP::Program::Deeptrio; + +use 5.026; +use Carp; +use charnames qw{ :full :short }; +use English qw{ -no_match_vars }; +use open qw{ :encoding(UTF-8) :std }; +use Params::Check qw{ allow check last_error }; +use utf8; +use warnings; +use warnings qw{ FATAL utf8 }; + +## CPANM +use autodie qw{ :all }; + +## MIPs lib/ +use MIP::Constants qw{ $EQUALS $SPACE }; +use MIP::Environment::Executable qw{ get_executable_base_command }; +use MIP::Unix::Standard_streams qw{ unix_standard_streams }; +use MIP::Unix::Write_to_file qw{ unix_write_to_file }; + +BEGIN { + require Exporter; + use base qw{ Exporter }; + + # Functions and variables which can be optionally exported + our @EXPORT_OK = qw{ deeptrio }; +} + +sub deeptrio { + +## Function : Perl wrapper for generic commands module +## Returns : @commands +## Arguments: $bedfile => Bed file containing the list of regions we want to process +## : $filehandle => Filehandle to write to +## : $model_type => Type of model to use for variant calling. Allowed values WES, WGS, or PACBIO +## : $num_shards => Number of files the input is split into for the make examples step +## : $output_gvcf_child => Path to output gvcf file for the child in a duo or trio +## : $output_gvcf_parent1 => Path to output gvcf for a parent in a duo or a trio +## : $output_gvcf_parent2 => Path to output gvcf for a parent in trio +## : $output_vcf_child => Path to output vcf file for the child in a duo or trio +## : $output_vcf_parent1 => Path to output vcf for a parent in a duo or trio +## : $output_vcf_parent2 => Path to output vcf for a parent in trio +## : $reads_child => Path to input bam for the child in a duo or trio +## : $reads_parent1 => Path to input bam for a parent in a duo or trio +## : $reads_parent2 => Path to input bam for a parent in trio +## : $referencefile_path => Path to genome reference +## : $sample_name_child => Sample name for the child in a duo or trio +## : $sample_name_parent1 => Sample name for a parent in a duo or trio +## : $sample_name_parent2 => Sample name for a parent in trio +## : $stderrfile_path => Stderrfile path +## : $stderrfile_path_append => Append stderr info to file path +## : $stdinfile_path => Stdinfile path +## : $stdoutfile_path => Stdoutfile path + + my ($arg_href) = @_; + + ## Flatten argument(s) + my $bedfile; + my $filehandle; + my $model_type; + my $num_shards; + my $output_gvcf_child; + my $output_gvcf_parent1; + my $output_gvcf_parent2; + my $output_vcf_child; + my $output_vcf_parent1; + my $output_vcf_parent2; + my $reads_child; + my $reads_parent1; + my $reads_parent2; + my $referencefile_path; + my $sample_name_child; + my $sample_name_parent1; + my $sample_name_parent2; + my $stderrfile_path; + my $stderrfile_path_append; + my $stdinfile_path; + my $stdoutfile_path; + + my $tmpl = { + bedfile => { + defined => 1, + store => \$bedfile, + strict_type => 1, + }, + filehandle => { + store => \$filehandle, + }, + model_type => { + allow => [qw{ WES WGS PACBIO }], + defined => 1, + required => 1, + store => \$model_type, + strict_type => 1, + }, + num_shards => { + allow => qr/ \A \d+ \z /xms, + required => 1, + store => \$num_shards, + strict_type => 1, + }, + output_gvcf_child => { + defined => 1, + required => 1, + store => \$output_gvcf_child, + strict_type => 1, + }, + output_gvcf_parent1 => { + defined => 1, + required => 1, + store => \$output_gvcf_parent1, + strict_type => 1, + }, + output_gvcf_parent2 => { + store => \$output_gvcf_parent2, + strict_type => 1, + }, + output_vcf_child => { + defined => 1, + required => 1, + store => \$output_vcf_child, + strict_type => 1, + }, + output_vcf_parent1 => { + defined => 1, + required => 1, + store => \$output_vcf_parent1, + strict_type => 1, + }, + output_vcf_parent2 => { + store => \$output_vcf_parent2, + strict_type => 1, + }, + reads_child => { + defined => 1, + required => 1, + store => \$reads_child, + strict_type => 1, + }, + reads_parent1 => { + defined => 1, + required => 1, + store => \$reads_parent1, + strict_type => 1, + }, + reads_parent2 => { + store => \$reads_parent2, + strict_type => 1, + }, + referencefile_path => { + defined => 1, + required => 1, + store => \$referencefile_path, + strict_type => 1, + }, + sample_name_child => { + defined => 1, + required => 1, + store => \$sample_name_child, + strict_type => 1, + }, + sample_name_parent1 => { + defined => 1, + required => 1, + store => \$sample_name_parent1, + strict_type => 1, + }, + sample_name_parent2 => { + store => \$sample_name_parent2, + strict_type => 1, + }, + stderrfile_path => { + store => \$stderrfile_path, + strict_type => 1, + }, + stderrfile_path_append => { + store => \$stderrfile_path_append, + strict_type => 1, + }, + stdinfile_path => { + store => \$stdinfile_path, + strict_type => 1, + }, + stdoutfile_path => { + store => \$stdoutfile_path, + strict_type => 1, + }, + }; + + check( $tmpl, $arg_href, 1 ) or croak q{Could not parse arguments!}; + + my @commands = + ( get_executable_base_command( { base_command => q{run_deeptrio}, } ), ); + + push @commands, q{--model_type} . $SPACE . $model_type; + push @commands, q{--ref} . $SPACE . $referencefile_path; + push @commands, q{--num_shards} . $SPACE . $num_shards; + + ## Child + push @commands, q{--sample_name_child} . $SPACE . $sample_name_child; + push @commands, q{--reads_child} . $SPACE . $reads_child; + push @commands, q{--output_gvcf_child} . $SPACE . $output_gvcf_child; + push @commands, q{--output_vcf_child} . $SPACE . $output_vcf_child; + + ## Parent1 + push @commands, q{--sample_name_parent1} . $SPACE . $sample_name_parent1; + push @commands, q{--reads_parent1} . $SPACE . $reads_parent1; + push @commands, q{--output_gvcf_parent1} . $SPACE . $output_gvcf_parent1; + push @commands, q{--output_vcf_parent1} . $SPACE . $output_vcf_parent1; + + if ($sample_name_parent2) { + push @commands, q{--sample_name_parent2} . $SPACE . $sample_name_parent2; + } + if ($reads_parent2) { + push @commands, q{--reads_parent2} . $SPACE . $reads_parent2; + } + if ($output_gvcf_parent2) { + push @commands, q{--output_gvcf_parent2} . $SPACE . $output_gvcf_parent2; + } + if ($output_vcf_parent2) { + push @commands, q{--output_vcf_parent2} . $SPACE . $output_vcf_parent2; + } + if ($bedfile) { + push @commands, q{--regions} . $SPACE . $bedfile; + } + + push @commands, + unix_standard_streams( + { + stderrfile_path => $stderrfile_path, + stderrfile_path_append => $stderrfile_path_append, + stdinfile_path => $stdinfile_path, + stdoutfile_path => $stdoutfile_path, + } + ); + + unix_write_to_file( + { + commands_ref => \@commands, + filehandle => $filehandle, + separator => $SPACE, + + } + ); + return @commands; +} + +1; diff --git a/lib/MIP/Recipes/Analysis/Deeptrio.pm b/lib/MIP/Recipes/Analysis/Deeptrio.pm new file mode 100644 index 000000000..edd63feae --- /dev/null +++ b/lib/MIP/Recipes/Analysis/Deeptrio.pm @@ -0,0 +1,324 @@ +package MIP::Recipes::Analysis::Deeptrio; + +use 5.026; +use Carp; +use charnames qw{ :full :short }; +use English qw{ -no_match_vars }; +use File::Spec::Functions qw{ catdir catfile }; +use open qw{ :encoding(UTF-8) :std }; +use Params::Check qw{ allow check last_error }; +use utf8; +use warnings; +use warnings qw{ FATAL utf8 }; + +## MIPs lib/ +use MIP::Constants qw{ $LOG_NAME $NEWLINE $UNDERSCORE }; + +BEGIN { + + require Exporter; + use base qw{ Exporter }; + + # Functions and variables which can be optionally exported + our @EXPORT_OK = qw{ analysis_deeptrio }; + +} + +sub analysis_deeptrio { + +## Function : Returns vcfs and gvcfs from bam files using DeepVariant's deeptrio caller +## Returns : +## Arguments: $active_parameter_href => Active parameters for this analysis hash {REF} +## : $case_id => Family id +## : $file_info_href => File_info hash {REF} +## : $job_id_href => Job id hash {REF} +## : $parameter_href => Parameter hash {REF} +## : $profile_base_command => Submission profile base command +## : $recipe_name => Recipe name +## : $sample_info_href => Info on samples and case hash {REF} + + my ($arg_href) = @_; + + ## Flatten argument(s) + my $active_parameter_href; + my $file_info_href; + my $job_id_href; + my $parameter_href; + my $recipe_name; + my $sample_info_href; + + ## Default(s) + my $case_id; + my $profile_base_command; + + my $tmpl = { + active_parameter_href => { + default => {}, + defined => 1, + required => 1, + store => \$active_parameter_href, + strict_type => 1, + }, + case_id => { + default => $arg_href->{active_parameter_href}{case_id}, + store => \$case_id, + strict_type => 1, + }, + file_info_href => { + default => {}, + defined => 1, + required => 1, + store => \$file_info_href, + strict_type => 1, + }, + job_id_href => { + default => {}, + defined => 1, + required => 1, + store => \$job_id_href, + strict_type => 1, + }, + parameter_href => { + default => {}, + defined => 1, + required => 1, + store => \$parameter_href, + strict_type => 1, + }, + profile_base_command => { + default => q{sbatch}, + store => \$profile_base_command, + strict_type => 1, + }, + recipe_name => { + defined => 1, + required => 1, + store => \$recipe_name, + strict_type => 1, + }, + sample_info_href => { + default => {}, + defined => 1, + required => 1, + store => \$sample_info_href, + strict_type => 1, + }, + }; + + check( $tmpl, $arg_href, 1 ) or croak q{Could not parse arguments!}; + + use MIP::Get::File qw{ get_io_files }; + use MIP::Get::Parameter qw{ get_recipe_attributes get_recipe_resources }; + use MIP::Parse::File qw{ parse_io_outfiles }; + use MIP::Processmanagement::Processes qw{ submit_recipe }; + use MIP::Program::Deeptrio qw{ deeptrio }; + use MIP::Program::Gnu::Coreutils qw{ gnu_mkdir }; + use MIP::Sample_info + qw{ get_case_members_attributes_in_duos get_family_member_id set_recipe_metafile_in_sample_info set_recipe_outfile_in_sample_info }; + use MIP::Script::Setup_script qw{ setup_script }; + + ### PREPROCESSING: + + ## Retrieve logger object + my $log = Log::Log4perl->get_logger($LOG_NAME); + + my %case_members_id = + scalar @{ $active_parameter_href->{sample_ids} } == 2 + ? get_case_members_attributes_in_duos( { sample_info_href => $sample_info_href } ) + : get_family_member_id( { sample_info_href => $sample_info_href } ); + + ## Unpack parameters + my $job_id_chain = get_recipe_attributes( + { + attribute => q{chain}, + parameter_href => $parameter_href, + recipe_name => $recipe_name, + } + ); + + my $model_type = _consensus_analysis_type( + { + parameter_href => $parameter_href, + } + ); + + my $recipe_mode = $active_parameter_href->{$recipe_name}; + my %recipe_resource = get_recipe_resources( + { + active_parameter_href => $active_parameter_href, + recipe_name => $recipe_name, + } + ); + + my $infile_name_prefix; + + my @parents = grep { defined } @{ \%case_members_id }{qw{ father mother }}; + my @parents_filtered = grep { $_ ne '0' } @parents; + my $child_id = $case_members_id{children}[0]; + + my %iofile_parameter; + my @outfile_directories; + + SAMPLE_ID: + foreach my $sample_id ( @parents_filtered, $child_id ) { + my %sample_bam_io = get_io_files( + { + id => $sample_id, + file_info_href => $file_info_href, + parameter_href => $parameter_href, + recipe_name => q{markduplicates}, + stream => q{out}, + } + ); + $infile_name_prefix = $sample_bam_io{in}{file_name_prefix}; + + my %sample_vcf_io = ( + %sample_bam_io, + parse_io_outfiles( + { + chain_id => $job_id_chain, + id => $sample_id, + file_info_href => $file_info_href, + file_name_prefixes_ref => [$infile_name_prefix], + outdata_dir => $active_parameter_href->{outdata_dir}, + parameter_href => $parameter_href, + recipe_name => $recipe_name, + } + ) + ); + $iofile_parameter{$sample_id}{reads} = + $sample_bam_io{out}{file_path_prefix} . $sample_bam_io{out}{file_suffix}; + $iofile_parameter{$sample_id}{output_gvcf} = $sample_vcf_io{out}{file_path}; + $iofile_parameter{$sample_id}{output_vcf} = + $sample_vcf_io{out}{file_path_prefix} . q{.vcf.gz}; + $iofile_parameter{$sample_id}{sample_name} = $sample_id; + push @outfile_directories, $sample_vcf_io{out}{dir_path}; + } + + ## Filehandles + # Create anonymous filehandle + my $filehandle = IO::Handle->new(); + + ## Creates recipe directories (info & data & script), recipe script filenames and writes sbatch header + my ( $recipe_file_path, $recipe_info_path ) = setup_script( + { + active_parameter_href => $active_parameter_href, + core_number => $recipe_resource{core_number}, + directory_id => $case_id, + filehandle => $filehandle, + gpu_number => $recipe_resource{gpu_number}, + job_id_href => $job_id_href, + memory_allocation => $recipe_resource{memory}, + process_time => $recipe_resource{time}, + recipe_directory => $recipe_name, + recipe_name => $recipe_name, + } + ); + + ### SHELL: + + say {$filehandle} q{## Create output directories}; + foreach my $out_directory (@outfile_directories) { + gnu_mkdir( + { + filehandle => $filehandle, + indirectory_path => $out_directory, + parents => 1, + } + ); + say {$filehandle} $NEWLINE; + } + + say {$filehandle} q{## } . $recipe_name; + deeptrio( + { + filehandle => $filehandle, + model_type => $model_type, + num_shards => $recipe_resource{core_number}, + output_gvcf_child => $iofile_parameter{$child_id}{output_gvcf}, + output_gvcf_parent1 => $iofile_parameter{ $parents[0] }{output_gvcf}, + output_gvcf_parent2 => $iofile_parameter{ $parents[1] }{output_gvcf}, + output_vcf_child => $iofile_parameter{$child_id}{output_vcf}, + output_vcf_parent1 => $iofile_parameter{ $parents[0] }{output_vcf}, + output_vcf_parent2 => $iofile_parameter{ $parents[1] }{output_vcf}, + referencefile_path => $active_parameter_href->{human_genome_reference}, + reads_child => $iofile_parameter{$child_id}{reads}, + reads_parent1 => $iofile_parameter{ $parents[0] }{reads}, + reads_parent2 => $iofile_parameter{ $parents[1] }{reads}, + sample_name_child => $iofile_parameter{$child_id}{sample_name}, + sample_name_parent1 => $iofile_parameter{ $parents[0] }{sample_name}, + sample_name_parent2 => $iofile_parameter{ $parents[1] }{sample_name}, + } + ); + + ## Close filehandleS + close $filehandle or $log->logcroak(q{Could not close filehandle}); + + if ( $recipe_mode == 1 ) { + + ## Collect QC metadata info for later use + set_recipe_outfile_in_sample_info( + { + infile => $iofile_parameter{$child_id}{output_gvcf}, + recipe_name => $recipe_name, + sample_info_href => $sample_info_href, + } + ); + + submit_recipe( + { + base_command => $profile_base_command, + case_id => $case_id, + dependency_method => q{sample_to_case}, + job_id_chain => $job_id_chain, + job_id_href => $job_id_href, + job_reservation_name => $active_parameter_href->{job_reservation_name}, + log => $log, + max_parallel_processes_count_href => + $file_info_href->{max_parallel_processes_count}, + recipe_file_path => $recipe_file_path, + sample_ids_ref => \@{ $active_parameter_href->{sample_ids} }, + submission_profile => $active_parameter_href->{submission_profile}, + } + ); + } + return 1; +} + +sub _consensus_analysis_type { + +## Function : Determine model type from consensus analysis type +## Returns : +## Arguments: $parameter_href => Parameter hash {REF} + + my ($arg_href) = @_; + + ## Flatten argument(s) + my $parameter_href; + + my $tmpl = { + parameter_href => { + default => {}, + defined => 1, + required => 1, + store => \$parameter_href, + strict_type => 1, + }, + }; + + check( $tmpl, $arg_href, 1 ) or croak q{Could not parse arguments!}; + + use MIP::Parameter qw{ get_cache }; + + my %deepvar_consensus_analysis_type_map = + ( MIXED => q{WGS}, PANEL => q{WES}, WGS => q{WGS}, WES => q{WES} ); + my $consensus_analysis_type = get_cache( + { + parameter_href => $parameter_href, + parameter_name => q{consensus_analysis_type}, + } + ); + return $deepvar_consensus_analysis_type_map{ uc $consensus_analysis_type }; +} + +1; diff --git a/lib/MIP/Recipes/Pipeline/Analyse_rd_dna.pm b/lib/MIP/Recipes/Pipeline/Analyse_rd_dna.pm index 898c14506..817c5a5d0 100644 --- a/lib/MIP/Recipes/Pipeline/Analyse_rd_dna.pm +++ b/lib/MIP/Recipes/Pipeline/Analyse_rd_dna.pm @@ -117,8 +117,7 @@ sub parse_rd_dna { use MIP::Gatk qw{ check_gatk_sample_map_paths }; use MIP::Parameter qw{ get_cache }; use MIP::Parse::Gender qw{ parse_fastq_for_gender }; - use MIP::Reference - qw{ get_select_file_contigs parse_exome_target_bed parse_nist_parameters }; + use MIP::Reference qw{ get_select_file_contigs parse_exome_target_bed parse_nist_parameters }; use MIP::Sample_info qw{ set_parameter_in_sample_info }; use MIP::Vep qw{ check_vep_api_cache_versions @@ -127,11 +126,9 @@ sub parse_rd_dna { use MIP::Vcfanno qw{ parse_toml_config_parameters }; ## Constants - Readonly my @MIP_VEP_PLUGINS => qw{ sv_vep_plugin vep_plugin }; - Readonly my @ONLY_WGS_VARIANT_CALLER_RECIPES => - qw{ cnvnator_ar delly_reformat tiddit }; - Readonly my @ONLY_WGS_RECIPIES => - qw{ cnvnator_ar delly_call delly_reformat expansionhunter + Readonly my @MIP_VEP_PLUGINS => qw{ sv_vep_plugin vep_plugin }; + Readonly my @ONLY_WGS_VARIANT_CALLER_RECIPES => qw{ cnvnator_ar delly_reformat tiddit }; + Readonly my @ONLY_WGS_RECIPIES => qw{ cnvnator_ar delly_call delly_reformat expansionhunter samtools_subsample_mt smncopynumbercaller star_caller telomerecat_ar tiddit }; Readonly my @REMOVE_CONFIG_KEYS => qw{ associated_recipe }; @@ -155,11 +152,9 @@ sub parse_rd_dna { ## Update exome_target_bed files with human_genome_reference_source and human_genome_reference_version parse_exome_target_bed( { - exome_target_bed_file_href => $active_parameter_href->{exome_target_bed}, - human_genome_reference_source => - $file_info_href->{human_genome_reference_source}, - human_genome_reference_version => - $file_info_href->{human_genome_reference_version}, + exome_target_bed_file_href => $active_parameter_href->{exome_target_bed}, + human_genome_reference_source => $file_info_href->{human_genome_reference_source}, + human_genome_reference_version => $file_info_href->{human_genome_reference_version}, } ); @@ -442,7 +437,7 @@ sub pipeline_analyse_rd_dna { use MIP::Log::MIP_log4perl qw{ log_display_recipe_for_user }; use MIP::Parse::Reference qw{ parse_references }; use MIP::Set::Analysis - qw{ set_recipe_bwa_mem set_recipe_gatk_variantrecalibration set_recipe_on_analysis_type set_rankvariants_ar }; + qw{ set_recipe_bwa_mem set_recipe_deepvariant set_recipe_gatk_variantrecalibration set_recipe_on_analysis_type set_rankvariants_ar }; ## Recipes use MIP::Recipes::Analysis::Analysisrunstatus qw{ analysis_analysisrunstatus }; @@ -451,24 +446,22 @@ sub pipeline_analyse_rd_dna { use MIP::Recipes::Analysis::Chromograph qw{ analysis_chromograph_cov analysis_chromograph_rhoviz analysis_chromograph_upd }; use MIP::Recipes::Analysis::Cnvnator qw{ analysis_cnvnator }; + use MIP::Recipes::Analysis::Deeptrio qw { analysis_deeptrio }; use MIP::Recipes::Analysis::Deepvariant qw { analysis_deepvariant }; use MIP::Recipes::Analysis::Delly_call qw{ analysis_delly_call }; use MIP::Recipes::Analysis::Delly_reformat qw{ analysis_delly_reformat }; - use MIP::Recipes::Analysis::Endvariantannotationblock - qw{ analysis_endvariantannotationblock }; + use MIP::Recipes::Analysis::Endvariantannotationblock qw{ analysis_endvariantannotationblock }; use MIP::Recipes::Analysis::Expansionhunter qw{ analysis_expansionhunter }; use MIP::Recipes::Analysis::Fastqc qw{ analysis_fastqc }; use MIP::Recipes::Analysis::Frequency_filter qw{ analysis_frequency_filter }; - use MIP::Recipes::Analysis::Gatk_baserecalibration - qw{ analysis_gatk_baserecalibration }; + use MIP::Recipes::Analysis::Gatk_baserecalibration qw{ analysis_gatk_baserecalibration }; use MIP::Recipes::Analysis::Gatk_combinevariantcallsets qw{ analysis_gatk_combinevariantcallsets }; use MIP::Recipes::Analysis::Gatk_gathervcfs qw{ analysis_gatk_gathervcfs }; use MIP::Recipes::Analysis::Gatk_genotypegvcfs qw{ analysis_gatk_genotypegvcfs }; use MIP::Recipes::Analysis::Gatk_haplotypecaller qw{ analysis_gatk_haplotypecaller }; use MIP::Recipes::Analysis::Gatk_variantevalall qw{ analysis_gatk_variantevalall }; - use MIP::Recipes::Analysis::Gatk_variantevalexome - qw{ analysis_gatk_variantevalexome }; + use MIP::Recipes::Analysis::Gatk_variantevalexome qw{ analysis_gatk_variantevalexome }; use MIP::Recipes::Analysis::Glnexus qw{ analysis_glnexus }; use MIP::Recipes::Analysis::Gzip_fastq qw{ analysis_gzip_fastq }; use MIP::Recipes::Analysis::Manta qw{ analysis_manta }; @@ -487,21 +480,18 @@ sub pipeline_analyse_rd_dna { qw{ analysis_prepareforvariantannotationblock }; use MIP::Recipes::Analysis::Rankvariant qw{ analysis_rankvariant analysis_rankvariant_unaffected analysis_rankvariant_sv analysis_rankvariant_sv_unaffected }; - use MIP::Recipes::Analysis::Rhocall - qw{ analysis_rhocall_annotate analysis_rhocall_viz }; + use MIP::Recipes::Analysis::Rhocall qw{ analysis_rhocall_annotate analysis_rhocall_viz }; use MIP::Recipes::Analysis::Rtg_vcfeval qw{ analysis_rtg_vcfeval }; use MIP::Recipes::Analysis::Sacct qw{ analysis_sacct }; use MIP::Recipes::Analysis::Sambamba_depth qw{ analysis_sambamba_depth }; use MIP::Recipes::Analysis::Samtools_merge qw{ analysis_samtools_merge }; - use MIP::Recipes::Analysis::Samtools_subsample_mt - qw{ analysis_samtools_subsample_mt }; + use MIP::Recipes::Analysis::Samtools_subsample_mt qw{ analysis_samtools_subsample_mt }; use MIP::Recipes::Analysis::Smncopynumbercaller qw{ analysis_smncopynumbercaller }; use MIP::Recipes::Analysis::Split_fastq_file qw{ analysis_split_fastq_file }; use MIP::Recipes::Analysis::Star_caller qw{ analysis_star_caller }; use MIP::Recipes::Analysis::Sv_annotate qw{ analysis_sv_annotate }; use MIP::Recipes::Analysis::Sv_reformat qw{ analysis_reformat_sv }; - use MIP::Recipes::Analysis::Sv_combinevariantcallsets - qw{ analysis_sv_combinevariantcallsets }; + use MIP::Recipes::Analysis::Sv_combinevariantcallsets qw{ analysis_sv_combinevariantcallsets }; use MIP::Recipes::Analysis::Split_fastq_file qw{ analysis_split_fastq_file }; use MIP::Recipes::Analysis::Telomerecat qw{ analysis_telomerecat }; use MIP::Recipes::Analysis::Tiddit qw{ analysis_tiddit }; @@ -562,9 +552,10 @@ sub pipeline_analyse_rd_dna { chromograph_rhoviz => \&analysis_chromograph_rhoviz, chromograph_upd => \$sample_info_href->{has_trio} ? \&analysis_chromograph_upd - : undef, # Depends on pedigree + : undef, # Depends on pedigree cnvnator_ar => \&analysis_cnvnator, - deepvariant => \&analysis_deepvariant, + deeptrio => undef, + deepvariant => undef, delly_call => \&analysis_delly_call, delly_reformat => \&analysis_delly_reformat, endvariantannotationblock => \&analysis_endvariantannotationblock, @@ -578,48 +569,46 @@ sub pipeline_analyse_rd_dna { gatk_haplotypecaller => \&analysis_gatk_haplotypecaller, gatk_variantevalall => \&analysis_gatk_variantevalall, gatk_variantevalexome => \&analysis_gatk_variantevalexome, - gatk_variantrecalibration => - undef, # Depends on analysis type and/or number of samples - glnexus_merge => \&analysis_glnexus, - gzip_fastq => \&analysis_gzip_fastq, - manta => \&analysis_manta, - markduplicates => \&analysis_markduplicates, - multiqc_ar => \&analysis_multiqc, - peddy_ar => \&analysis_peddy, - picardtools_collecthsmetrics => \&analysis_picardtools_collecthsmetrics, - picardtools_collectmultiplemetrics => - \&analysis_picardtools_collectmultiplemetrics, - plink => \&analysis_plink, - prepareforvariantannotationblock => \&analysis_prepareforvariantannotationblock, - qccollect_ar => \&analysis_mip_qccollect, - rankvariant => undef, # Depends on sample features - rhocall_ar => \&analysis_rhocall_annotate, - rhocall_viz => \&analysis_rhocall_viz, - rtg_vcfeval => \&analysis_rtg_vcfeval, - sacct => \&analysis_sacct, - sambamba_depth => \&analysis_sambamba_depth, - samtools_merge => \&analysis_samtools_merge, + gatk_variantrecalibration => undef, # Depends on analysis type and/or number of samples + glnexus_merge => \&analysis_glnexus, + gzip_fastq => \&analysis_gzip_fastq, + manta => \&analysis_manta, + markduplicates => \&analysis_markduplicates, + multiqc_ar => \&analysis_multiqc, + peddy_ar => \&analysis_peddy, + picardtools_collecthsmetrics => \&analysis_picardtools_collecthsmetrics, + picardtools_collectmultiplemetrics => \&analysis_picardtools_collectmultiplemetrics, + plink => \&analysis_plink, + prepareforvariantannotationblock => \&analysis_prepareforvariantannotationblock, + qccollect_ar => \&analysis_mip_qccollect, + rankvariant => undef, # Depends on sample features + rhocall_ar => \&analysis_rhocall_annotate, + rhocall_viz => \&analysis_rhocall_viz, + rtg_vcfeval => \&analysis_rtg_vcfeval, + sacct => \&analysis_sacct, + sambamba_depth => \&analysis_sambamba_depth, + samtools_merge => \&analysis_samtools_merge, samtools_subsample_mt => \&analysis_samtools_subsample_mt, smncopynumbercaller => \&analysis_smncopynumbercaller, split_fastq_file => \&analysis_split_fastq_file, star_caller => \&analysis_star_caller, sv_annotate => \&analysis_sv_annotate, sv_combinevariantcallsets => \&analysis_sv_combinevariantcallsets, - sv_rankvariant => undef, # Depends on sample features + sv_rankvariant => undef, # Depends on sample features sv_reformat => \&analysis_reformat_sv, - sv_varianteffectpredictor => undef, # Depends on analysis type - sv_vcfparser => undef, # Depends on analysis type + sv_varianteffectpredictor => undef, # Depends on analysis type + sv_vcfparser => undef, # Depends on analysis type telomerecat_ar => \&analysis_telomerecat, tiddit => \&analysis_tiddit, - tiddit_coverage => \&analysis_tiddit_coverage, - upd_ar => $sample_info_href->{has_trio} ? \&analysis_upd : undef, - varg_ar => \&analysis_varg, - varianteffectpredictor => \&analysis_vep_wgs, - variant_annotation => \&analysis_variant_annotation, - version_collect_ar => \&analysis_mip_vercollect, - vcfparser_ar => \&analysis_mip_vcfparser, - vcf2cytosure_ar => \&analysis_vcf2cytosure, - vt_ar => \&analysis_vt, + tiddit_coverage => \&analysis_tiddit_coverage, + upd_ar => $sample_info_href->{has_trio} ? \&analysis_upd : undef, + varg_ar => \&analysis_varg, + varianteffectpredictor => \&analysis_vep_wgs, + variant_annotation => \&analysis_variant_annotation, + version_collect_ar => \&analysis_mip_vercollect, + vcfparser_ar => \&analysis_mip_vcfparser, + vcf2cytosure_ar => \&analysis_vcf2cytosure, + vt_ar => \&analysis_vt, ); ## Special case for rankvariants recipe @@ -642,10 +631,17 @@ sub pipeline_analyse_rd_dna { ## Set correct bwa_mem recipe depending on version and source of the human_genome_reference: Source (hg19 or grch) set_recipe_bwa_mem( + { + analysis_recipe_href => \%analysis_recipe, + human_genome_reference_version => $file_info_href->{human_genome_reference_version}, + } + ); + + ## Set deepvariant or deeptrio recipe depending on the presence of parent-child duo or a trio + set_recipe_deepvariant( { analysis_recipe_href => \%analysis_recipe, - human_genome_reference_version => - $file_info_href->{human_genome_reference_version}, + sample_info_href => $sample_info_href, } ); diff --git a/lib/MIP/Sample_info.pm b/lib/MIP/Sample_info.pm index 45cd58ae8..8a62bd291 100644 --- a/lib/MIP/Sample_info.pm +++ b/lib/MIP/Sample_info.pm @@ -27,6 +27,7 @@ BEGIN { # Functions and variables which can be optionally exported our @EXPORT_OK = qw{ + get_case_members_attributes_in_duos get_family_member_id get_read_group get_rg_header_line @@ -52,6 +53,62 @@ BEGIN { } +sub get_case_members_attributes_in_duos { + +## Function : Get the sample IDs and phenotypes of the family members +## Returns : %case_members_attributes +## Arguments: $sample_info_href => Sample info hash {REF} + + my ($arg_href) = @_; + + ## Flatten argument(s) + my $sample_info_href; + + my $tmpl = { + sample_info_href => { + default => {}, + defined => 1, + required => 1, + store => \$sample_info_href, + strict_type => 1, + }, + }; + + check( $tmpl, $arg_href, 1 ) or croak q{Could not parse arguments!}; + + my %case_members_attributes = ( + affected => [], + children => [], + father => 0, + mother => 0, + unknown => [], + ); + + SAMPLE_ID: + foreach my $sample_id ( keys %{ $sample_info_href->{sample} } ) { + + my %sample_attributes = get_pedigree_sample_id_attributes( + { + sample_id => $sample_id, + sample_info_href => $sample_info_href, + } + ); + + my $phenotype = $sample_attributes{phenotype}; + push @{ $case_members_attributes{$phenotype} }, $sample_id; + + next SAMPLE_ID if ( not( $sample_attributes{father} or $sample_attributes{mother} ) ); + + ## Append child + push @{ $case_members_attributes{children} }, $sample_id; + + $case_members_attributes{father} = $sample_attributes{father}; + $case_members_attributes{mother} = $sample_attributes{mother}; + } + + return %case_members_attributes; +} + sub get_family_member_id { ## Function : Get the sample IDs of the family members @@ -1525,7 +1582,7 @@ sub set_parameter_in_sample_info { check( $tmpl, $arg_href, 1 ) or croak q{Could not parse arguments!}; - use MIP::Pedigree qw{ has_trio }; + use MIP::Pedigree qw{ has_duo has_trio }; my %set_parameter_map = ( analysis_type => { @@ -1538,6 +1595,16 @@ sub set_parameter_in_sample_info { set_at => $sample_info_href, value => $active_parameter_href->{expected_coverage}, }, + has_duo => { + key => q{has_duo}, + set_at => $sample_info_href, + value => has_duo( + { + active_parameter_href => $active_parameter_href, + sample_info_href => $sample_info_href, + } + ), + }, has_trio => { key => q{has_trio}, set_at => $sample_info_href, diff --git a/lib/MIP/Set/Analysis.pm b/lib/MIP/Set/Analysis.pm index 88e265fb6..1bdd5b275 100644 --- a/lib/MIP/Set/Analysis.pm +++ b/lib/MIP/Set/Analysis.pm @@ -25,6 +25,7 @@ BEGIN { our @EXPORT_OK = qw{ set_rankvariants_ar set_recipe_bwa_mem + set_recipe_deepvariant set_recipe_gatk_variantrecalibration set_recipe_on_analysis_type set_recipe_star_aln @@ -78,6 +79,56 @@ sub set_recipe_bwa_mem { return; } +sub set_recipe_deepvariant { + +## Function : Set deeptrio or deepvariant recipe depending on the presence of parent-child duo or trio +## Returns : +## Arguments: $analysis_recipe_href => Analysis recipe hash {REF} +## : $sample_info_href => Sample info hash {HASH} + + my ($arg_href) = @_; + + ## Flatten argument(s) + my $analysis_recipe_href; + my $sample_info_href; + + my $tmpl = { + analysis_recipe_href => { + default => {}, + defined => 1, + required => 1, + store => \$analysis_recipe_href, + strict_type => 1, + }, + sample_info_href => { + default => {}, + defined => 1, + required => 1, + store => \$sample_info_href, + strict_type => 1, + }, + }; + + check( $tmpl, $arg_href, 1 ) or croak q{Could not parse arguments!}; + + use MIP::Recipes::Analysis::Deepvariant qw{ analysis_deepvariant }; + use MIP::Recipes::Analysis::Deeptrio qw{ analysis_deeptrio }; + + $analysis_recipe_href->{deepvariant} = \&analysis_deepvariant; + $analysis_recipe_href->{deeptrio} = undef; + + CONSTELLATION_STATE: + foreach my $constellation_state (qw{ has_duo has_trio }) { + + next CONSTELLATION_STATE if ( not $sample_info_href->{$constellation_state} ); + + $analysis_recipe_href->{deepvariant} = undef; + $analysis_recipe_href->{deeptrio} = \&analysis_deeptrio; + return; + } + return; +} + sub set_recipe_gatk_variantrecalibration { ## Function : Update which gatk variant recalibration to use depending on number of samples diff --git a/t/analysis_deeptrio.t b/t/analysis_deeptrio.t new file mode 100644 index 000000000..c8cb086e3 --- /dev/null +++ b/t/analysis_deeptrio.t @@ -0,0 +1,136 @@ +#!/usr/bin/env perl + +use 5.026; +use Carp; +use charnames qw{ :full :short }; +use English qw{ -no_match_vars }; +use File::Basename qw{ dirname }; +use File::Spec::Functions qw{ catdir catfile }; +use FindBin qw{ $Bin }; +use open qw{ :encoding(UTF-8) :std }; +use Params::Check qw{ allow check last_error }; +use Test::More; +use utf8; +use warnings qw{ FATAL utf8 }; + +## CPANM +use autodie qw { :all }; +use Modern::Perl qw{ 2018 }; +use Test::Trap; + +## MIPs lib/ +use lib catdir( dirname($Bin), q{lib} ); +use MIP::Constants qw{ $COLON $COMMA $SPACE }; +use MIP::Test::Fixtures qw{ test_add_io_for_recipe test_log test_mip_hashes }; + +BEGIN { + + use MIP::Test::Fixtures qw{ test_import }; + +### Check all internal dependency modules and imports +## Modules with import + my %perl_module = ( + q{MIP::Recipes::Analysis::Deepvariant} => [qw{ analysis_deepvariant }], + q{MIP::Test::Fixtures} => [qw{ test_add_io_for_recipe test_log test_mip_hashes }], + ); + + test_import( { perl_module_href => \%perl_module, } ); +} + +use MIP::Recipes::Analysis::Deeptrio qw{ analysis_deeptrio }; + +diag( q{Test analysis_deeptrio from Deeptrio.pm} + . $COMMA + . $SPACE . q{Perl} + . $SPACE + . $PERL_VERSION + . $SPACE + . $EXECUTABLE_NAME ); + +my $log = test_log( { log_name => q{MIP}, no_screen => 1, } ); + +## Given analysis parameters +my $recipe_name = q{deeptrio}; +my $slurm_mock_cmd = catfile( $Bin, qw{ data modules slurm-mock.pl } ); + +my %active_parameter = test_mip_hashes( + { + mip_hash_name => q{active_parameter}, + recipe_name => $recipe_name, + } +); + +$active_parameter{$recipe_name} = 1; +$active_parameter{recipe_core_number}{$recipe_name} = 1; +$active_parameter{recipe_gpu_number}{$recipe_name} = 1; +$active_parameter{recipe_time}{$recipe_name} = 1; + +my $case_id = $active_parameter{case_id}; + +my %file_info = test_mip_hashes( + { + mip_hash_name => q{file_info}, + recipe_name => $recipe_name, + } +); + +my %job_id; +my %parameter = test_mip_hashes( + { + mip_hash_name => q{recipe_parameter}, + recipe_name => $recipe_name, + } +); + +my @order_recipes = ( qw{ markduplicates }, $recipe_name ); + +SAMPLE_ID: +foreach my $sample_id ( @{ $active_parameter{sample_ids} } ) { + + test_add_io_for_recipe( + { + file_info_href => \%file_info, + id => $sample_id, + parameter_href => \%parameter, + recipe_name => q{markduplicates}, + step => q{bam}, + } + ); + test_add_io_for_recipe( + { + file_info_href => \%file_info, + id => $sample_id, + order_recipes_ref => \@order_recipes, + parameter_href => \%parameter, + recipe_name => $recipe_name, + step => q{vcf}, + } + ); +} + +$parameter{cache}{consensus_analysis_type} = q{WGS}; + +my %sample_info = test_mip_hashes( + { + mip_hash_name => q{qc_sample_info}, + recipe_name => $recipe_name, + } +); + +my $is_ok = analysis_deeptrio( + { + active_parameter_href => \%active_parameter, + case_id => $case_id, + file_info_href => \%file_info, + job_id_href => \%job_id, + parameter_href => \%parameter, + profile_base_command => $slurm_mock_cmd, + recipe_name => $recipe_name, + sample_info_href => \%sample_info, + } +); + +## Then return TRUE +ok( $is_ok, q{ Executed analysis recipe } . $recipe_name ); + +done_testing(); diff --git a/t/deeptrio.t b/t/deeptrio.t new file mode 100644 index 000000000..5fa96e6c3 --- /dev/null +++ b/t/deeptrio.t @@ -0,0 +1,163 @@ +#!/usr/bin/env perl + +use 5.026; +use Carp; +use charnames qw{ :full :short }; +use English qw{ -no_match_vars }; +use File::Basename qw{ dirname }; +use File::Spec::Functions qw{ catdir catfile }; +use FindBin qw{ $Bin }; +use open qw{ :encoding(UTF-8) :std }; +use Params::Check qw{ allow check last_error }; +use Test::More; +use utf8; +use warnings qw{ FATAL utf8 }; + +## CPANM +use autodie qw{ :all }; +use Modern::Perl qw{ 2018 }; + +## MIPs lib/ +use lib catdir( dirname($Bin), q{lib} ); +use MIP::Constants qw{ $COMMA $SPACE }; +use MIP::Test::Commands qw{ test_function }; + + +BEGIN { + + use MIP::Test::Fixtures qw{ test_import }; + +### Check all internal dependency modules and imports +## Modules with import + my %perl_module = ( + q{MIP::Program::Deeptrio} => [qw{ deeptrio }], +); + + test_import( { perl_module_href => \%perl_module, } ); +} + +use MIP::Program::Deeptrio qw{ deeptrio }; + +diag( q{Test deeptrio from Deeptrio.pm} + . $COMMA + . $SPACE . q{Perl} + . $SPACE + . $PERL_VERSION + . $SPACE + . $EXECUTABLE_NAME ); + +## Base arguments +my @function_base_commands = qw{ run_deeptrio }; + +my %base_argument = ( + filehandle => { + input => undef, + expected_output => \@function_base_commands, + }, + stderrfile_path => { + input => q{stderrfile.test}, + expected_output => q{2> stderrfile.test}, + }, + stderrfile_path_append => { + input => q{stderrfile.test}, + expected_output => q{2>> stderrfile.test}, + }, + stdoutfile_path => { + input => q{stdoutfile.test}, + expected_output => q{1> stdoutfile.test}, + }, +); + +## Can be duplicated with %base_argument and/or %specific_argument +## to enable testing of each individual argument +my %required_argument = ( + model_type => { + input => q{WES}, + expected_output => q{--model_type WES}, + }, + num_shards => { + input => q{36}, + expected_output => q{--num_shards 36}, + }, + output_gvcf_child => { + input => catfile(q{ dir outfile.g.vcf }), + expected_output => q{--output_gvcf_child } . catfile(q{ dir outfile.g.vcf }), + }, + output_gvcf_parent1 => { + input => catfile(q{ dir outfile.g.vcf }), + expected_output => q{--output_gvcf_parent1 } . catfile(q{ dir outfile.g.vcf }), + }, + output_vcf_child => { + input => catfile(q{ dir outfile.vcf }), + expected_output => q{--output_vcf_child } . catfile(q{ dir outfile.vcf }), + }, + output_vcf_parent1 => { + input => catfile(q{ dir outfile.vcf }), + expected_output => q{--output_vcf_parent1 } . catfile(q{ dir outfile.vcf }), + }, + reads_child => { + input => catfile(qw{ dir infile.bam }), + expected_output => q{--reads_child } . catfile(qw{ dir infile.bam }) , + }, + reads_parent1 => { + input => catfile(qw{ dir infile.bam }), + expected_output => q{--reads_parent1 } . catfile(qw{ dir infile.bam }), + }, + referencefile_path => { + input => q{test}, + expected_output => q{--ref test}, + }, + sample_name_child => { + input => q{child}, + expected_output => q{--sample_name_child } . q{child}, + }, + sample_name_parent1 => { + input => q{father}, + expected_output => q{--sample_name_parent1 } . q{father}, + }, +); + +my %specific_argument = ( + bedfile => { + input => catfile(qw{ dir infile.bed }), + expected_output => q{--regions } . catfile(qw{ dir infile.bed }), + }, + output_gvcf_parent2 => { + input => catfile(q{ dir outfile.g.vcf }), + expected_output => q{--output_gvcf_parent2 } . catfile(q{ dir outfile.g.vcf }), + }, + output_vcf_parent2 => { + input => catfile(q{ dir outfile.vcf }), + expected_output => q{--output_vcf_parent2 } . catfile(q{ dir outfile.vcf }), + }, + reads_parent2 => { + input => catfile(qw{ dir infile.bam }), + expected_output => q{--reads_parent2 } . catfile(qw{ dir infile.bam }), + }, + sample_name_parent2 => { + input => q{mother}, + expected_output => q{--sample_name_parent2 } . q{mother}, + }, +); + +## Coderef - enables generalized use of generate call +my $module_function_cref = \&deeptrio; + +## Test both base and function specific arguments +my @arguments = ( \%base_argument, \%specific_argument ); + +ARGUMENT_HASH_REF: +foreach my $argument_href (@arguments) { + + my @commands = test_function( + { + argument_href => $argument_href, + do_test_base_command => 1, + function_base_commands_ref => \@function_base_commands, + module_function_cref => $module_function_cref, + required_argument_href => \%required_argument, + } + ); +} + +done_testing(); diff --git a/t/get_case_members_attributes_in_duos.t b/t/get_case_members_attributes_in_duos.t new file mode 100644 index 000000000..d4278a2c6 --- /dev/null +++ b/t/get_case_members_attributes_in_duos.t @@ -0,0 +1,69 @@ +#!/usr/bin/env perl + +use 5.026; +use Carp; +use charnames qw{ :full :short }; +use English qw{ -no_match_vars }; +use File::Basename qw{ dirname }; +use File::Spec::Functions qw{ catdir }; +use FindBin qw{ $Bin }; +use open qw{ :encoding(UTF-8) :std }; +use Params::Check qw{ allow check last_error }; +use Test::More; +use utf8; +use warnings qw{ FATAL utf8 }; + +## CPANM +use autodie qw { :all }; +use Modern::Perl qw{ 2018 }; + +## MIPs lib/ +use lib catdir( dirname($Bin), q{lib} ); +use MIP::Constants qw{ $COMMA $SPACE }; +use MIP::Test::Fixtures qw{ test_mip_hashes }; + +BEGIN { + + use MIP::Test::Fixtures qw{ test_import }; + +### Check all internal dependency modules and imports +## Modules with import + my %perl_module = ( + q{MIP::Sample_info} => [qw{ get_case_members_attributes_in_duos }], + q{MIP::Test::Fixtures} => [qw{ test_mip_hashes }], + ); + + test_import( { perl_module_href => \%perl_module, } ); +} + +use MIP::Sample_info qw{ get_case_members_attributes_in_duos }; + +diag( q{Test get_case_members_attributes_in_duos from Sample_info.pm} + . $COMMA + . $SPACE . q{Perl} + . $SPACE + . $PERL_VERSION + . $SPACE + . $EXECUTABLE_NAME ); + +## Given sample_info hash +my %sample_info = test_mip_hashes( { mip_hash_name => q{qc_sample_info}, } ); +$sample_info{sample}{ADM1059A2}{phenotype} = q{unknown}; +$sample_info{sample}{ADM1059A1}{mother} = q{0}; + +delete $sample_info{sample}{ADM1059A3}; +my %family_member_id = + get_case_members_attributes_in_duos( { sample_info_href => \%sample_info, } ); + +## Then return family members id +my %expected = ( + affected => [qw{ ADM1059A1 }], + children => [qw{ ADM1059A1 }], + father => q{ADM1059A2}, + mother => q{0}, + unknown => [qw{ ADM1059A2 }], +); + +is_deeply( \%family_member_id, \%expected, q{Got family hash} ); + +done_testing(); diff --git a/t/has_duo.t b/t/has_duo.t new file mode 100644 index 000000000..884f82e8b --- /dev/null +++ b/t/has_duo.t @@ -0,0 +1,105 @@ +#!/usr/bin/env perl + +use 5.026; +use Carp; +use charnames qw{ :full :short }; +use English qw{ -no_match_vars }; +use File::Basename qw{ dirname }; +use File::Spec::Functions qw{ catdir }; +use FindBin qw{ $Bin }; +use open qw{ :encoding(UTF-8) :std }; +use Params::Check qw{ allow check last_error }; +use Test::More; +use utf8; +use warnings qw{ FATAL utf8 }; + +## CPANM +use autodie qw { :all }; +use Modern::Perl qw{ 2018 }; + +## MIPs lib/ +use lib catdir( dirname($Bin), q{lib} ); +use MIP::Constants qw{ $COMMA $SPACE }; +use MIP::Test::Fixtures qw{ test_mip_hashes }; + +BEGIN { + + use MIP::Test::Fixtures qw{ test_import }; + +### Check all internal dependency modules and imports +## Modules with import + my %perl_module = ( + q{MIP::Pedigree} => [qw{ has_duo }], + q{MIP::Test::Fixtures} => [qw{ test_mip_hashes }], + ); + + test_import( { perl_module_href => \%perl_module, } ); +} + +use MIP::Pedigree qw{ has_duo }; + +diag( q{Test has_duo from Pedigre.pm} + . $COMMA + . $SPACE . q{Perl} + . $SPACE + . $PERL_VERSION + . $SPACE + . $EXECUTABLE_NAME ); + +my %active_parameter = test_mip_hashes( { mip_hash_name => q{active_parameter}, } ); +my %sample_info = test_mip_hashes( { mip_hash_name => q{qc_sample_info}, } ); + +## Given a trio where a sample id has phenotype affected + +## When checking if case constellation is duo and has samples with phenotype "affected" +my $has_duo = has_duo( + { + active_parameter_href => \%active_parameter, + sample_info_href => \%sample_info, + } +); + +## Then return 0 +is( $has_duo, 0, q{Detected non duo constellation for trio} ); + +## Given a duo where a sample id has phenotype affected +@{ $active_parameter{sample_ids} } = (qw{ADM1059A1 ADM1059A2}); + +## When checking if case constellation is duo and has samples with phenotype "affected" +$has_duo = has_duo( + { + active_parameter_href => \%active_parameter, + sample_info_href => \%sample_info, + } +); + +## Then return 1 +ok( $has_duo, q{Detected duo constellation} ); + +$sample_info{sample}{ADM1059A1}{phenotype} = q{unaffected}; + +## When checking if case constellation is duo and has samples with phenotype "affected" +$has_duo = has_duo( + { + active_parameter_href => \%active_parameter, + sample_info_href => \%sample_info, + } +); + +## Then return 0 +is( $has_duo, 0, q{Detected no samples with phenotype affected} ); + +## Given a single sample case +@{ $active_parameter{sample_ids} } = (q{ADM1059A1}); + +## When checking if case constellation is duo and has samples with phenotype "affected" +$has_duo = has_duo( + { + active_parameter_href => \%active_parameter, + sample_info_href => \%sample_info, + } +); +## Then return 0 +is( $has_duo, 0, q{Detected non duo constellation for single sample} ); + +done_testing(); diff --git a/t/set_parameter_in_sample_info.t b/t/set_parameter_in_sample_info.t index 56d62ff77..e35f99d9a 100644 --- a/t/set_parameter_in_sample_info.t +++ b/t/set_parameter_in_sample_info.t @@ -90,9 +90,10 @@ my %expected_sample_info = ( $expected_sample_info{analysis_type} = $active_parameter{analysis_type}; %{ $expected_sample_info{expected_coverage} } = %{ $active_parameter{expected_coverage} }; $expected_sample_info{pedigree_file}{path} = $active_parameter{pedigree_file}; -$expected_sample_info{log_file_dir} = dirname( dirname( $active_parameter{log_file} ) ); -$expected_sample_info{last_log_file_path} = $active_parameter{log_file}; -$expected_sample_info{has_trio} = 0; +$expected_sample_info{log_file_dir} = dirname( dirname( $active_parameter{log_file} ) ); +$expected_sample_info{last_log_file_path} = $active_parameter{log_file}; +$expected_sample_info{has_trio} = 0; +$expected_sample_info{has_duo} = 0; ## Then these entries should be set in sample info is_deeply( \%sample_info, \%expected_sample_info, q{Set parameter in sample_info} ); diff --git a/t/set_recipe_deepvariant.t b/t/set_recipe_deepvariant.t new file mode 100644 index 000000000..ffe18bc08 --- /dev/null +++ b/t/set_recipe_deepvariant.t @@ -0,0 +1,105 @@ +#!/usr/bin/env perl + +use 5.026; +use Carp; +use charnames qw{ :full :short }; +use English qw{ -no_match_vars }; +use File::Basename qw{ dirname }; +use File::Spec::Functions qw{ catdir }; +use FindBin qw{ $Bin }; +use open qw{ :encoding(UTF-8) :std }; +use Params::Check qw{ allow check last_error }; +use Test::More; +use utf8; +use warnings qw{ FATAL utf8 }; + +## CPANM +use autodie qw { :all }; +use Modern::Perl qw{ 2018 }; + +## MIPs lib/ +use lib catdir( dirname($Bin), q{lib} ); +use MIP::Constants qw{ $COMMA $SPACE }; + +BEGIN { + + use MIP::Test::Fixtures qw{ test_import }; + +### Check all internal dependency modules and imports +## Modules with import + my %perl_module = ( + q{MIP::Recipes::Analysis::Deepvariant} => [qw{ analysis_deepvariant }], + q{MIP::Recipes::Analysis::Deeptrio} => [qw{ analysis_deeptrio }], + q{MIP::Set::Analysis} => [qw{ set_recipe_deepvariant }], + q{MIP::Test::Fixtures} => [qw{ test_mip_hashes }], + ); + + test_import( { perl_module_href => \%perl_module, } ); +} + +use MIP::Set::Analysis qw{ set_recipe_deepvariant }; +use MIP::Recipes::Analysis::Deeptrio qw{ analysis_deeptrio }; +use MIP::Recipes::Analysis::Deepvariant qw{ analysis_deepvariant }; +use MIP::Test::Fixtures qw{ test_mip_hashes }; + +diag( q{Test set_recipe_deepvariant from Analysis.pm} + . $COMMA + . $SPACE . q{Perl} + . $SPACE + . $PERL_VERSION + . $SPACE + . $EXECUTABLE_NAME ); + +my %sample_info = test_mip_hashes( { mip_hash_name => q{qc_sample_info} } ); +my %analysis_recipe; + +## When constellation state is a duo +$sample_info{has_duo} = 1; +$sample_info{has_trio} = 0; + +set_recipe_deepvariant( + { + analysis_recipe_href => \%analysis_recipe, + sample_info_href => \%sample_info, + } +); +my %expected_analysis_recipe = ( + deepvariant => undef, + deeptrio => \&analysis_deeptrio, +); + +## Then set deepvariant recipe +is_deeply( \%analysis_recipe, \%expected_analysis_recipe, q{Set deepvariant recipe for a duo} ); + +## When constellation state is a trio +$sample_info{has_duo} = 0; +$sample_info{has_trio} = 1; +set_recipe_deepvariant( + { + analysis_recipe_href => \%analysis_recipe, + sample_info_href => \%sample_info, + } +); +$expected_analysis_recipe{deeptrio} = \&analysis_deeptrio; +$expected_analysis_recipe{deepvariant} = undef; + +## Then set deepvariant recipe +is_deeply( \%analysis_recipe, \%expected_analysis_recipe, q{Set deepvariant recipe for a trio} ); + +## When constellation state is neither a duo or trio +$sample_info{has_duo} = 0; +$sample_info{has_trio} = 0; +set_recipe_deepvariant( + { + analysis_recipe_href => \%analysis_recipe, + sample_info_href => \%sample_info, + } +); +$expected_analysis_recipe{deeptrio} = undef; +$expected_analysis_recipe{deepvariant} = \&analysis_deepvariant; + +## Then set bwa mem recipe +is_deeply( \%analysis_recipe, \%expected_analysis_recipe, + q{Set deepvariant recipe when the case is neither a duo or a trio} ); + +done_testing(); diff --git a/templates/mip_install_config.yaml b/templates/mip_install_config.yaml index 6c24b48f9..584195743 100644 --- a/templates/mip_install_config.yaml +++ b/templates/mip_install_config.yaml @@ -68,7 +68,12 @@ container: call_variants: /opt/deepvariant/bin/call_variants postprocess_variants: /opt/deepvariant/bin/postprocess_variants gpu_support: 1 - uri: docker.io/google/deepvariant:1.0.0-gpu + uri: docker.io/google/deepvariant:1.1.0-gpu + deeptrio: + executable: + run_deeptrio: /opt/deepvariant/bin/deeptrio/run_deeptrio + gpu_support: 1 + uri: docker.io/google/deepvariant:deeptrio-1.1.0-gpu delly: executable: delly: diff --git a/templates/program_test_cmds.yaml b/templates/program_test_cmds.yaml index 9c8595564..9a9e524c1 100644 --- a/templates/program_test_cmds.yaml +++ b/templates/program_test_cmds.yaml @@ -32,6 +32,8 @@ cyrius: execution: 'star_caller.py --help' deepvariant: path: 'run_deepvariant' +deeptrio: + path: 'run_deeptrio' delly: execution: 'delly' expansionhunter: