From fcddec691591243eec1e149af4f8f09afed860b6 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 1 Jul 2024 09:00:58 -0700 Subject: [PATCH 01/60] Update CODEOWNERS --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index cdbfd10..520b43b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,2 @@ # Default owner(s) -* @tyamaguchi-ucla @yashpatel6 @zhuchcn @uclahs-cds/software-wg +* @uclahs-cds/nextflow-wg From 195b2b9a4bf82b38935ec05f568b0cd9e97ed773 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 1 Jul 2024 12:06:26 -0700 Subject: [PATCH 02/60] Add parameters for docker images --- config/default.config | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/config/default.config b/config/default.config index 2e67a46..31f3a37 100644 --- a/config/default.config +++ b/config/default.config @@ -11,25 +11,33 @@ params { docker_container_registry = "ghcr.io/uclahs-cds" // Docker images - // REPLACE WITH TOOLS USED - tool_a_version = 'x.x.x' // Docker version for tool a - docker_image_tool_a = "${-> params.docker_container_registry}/tool_a:${params.tool_a_version}" + bcftools_version = '1.20' + bedtools_version = '2.31.0' + gatk_version = '4.2.4.1' + pipeval_version = '5.0.0-rc.3' + samtools_version = '1.20' + stablelift_version = 'x.x.x' // FIXME + + docker_image_bcftools = "${-> params.docker_container_registry}/bcftools:${params.bcftools_version}" + docker_image_bedtools = "${-> params.docker_container_registry}/bedtools:${params.bedtools_version}" + docker_image_gatk = "broadinstitute/gatk:${params.gatk_version}" + docker_image_pipeval = "${-> params.docker_container_registry}/pipeval:${params.pipeval_version}" + docker_image_samtools = "${-> params.docker_container_registry}/samtools:${params.samtools_version}" + docker_image_stablelift = "${-> params.docker_container_registry}/stablelift:${params.stablelift_version}" } // Process specific scope process { // Process results are stored to local cache. - // If pipeline is launched with the 'resume' option, existing cache results will be used when available - // rather than re-executing processes + // If pipeline is launched with the 'resume' option, existing cache results + // will be used when available rather than re-executing processes cache = true // Forward process 'stdout' to shell terminal and, consequently, the log file echo = true executor = 'local' - // Other directives or options that should apply for every process - - // total amount of resources avaible to the pipeline + // Total amount of resources available to the pipeline cpus = params.max_cpus memory = params.max_memory } From 0c31af58fb831e93b90bd9ba67b1fd9defb53a56 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 1 Jul 2024 12:13:24 -0700 Subject: [PATCH 03/60] Add variables to template.config --- config/template.config | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/config/template.config b/config/template.config index 1002616..adafde4 100644 --- a/config/template.config +++ b/config/template.config @@ -8,18 +8,23 @@ includeConfig "${projectDir}/nextflow.config" // Inputs/parameters of the pipeline params { - dataset_id = '' - blcds_registered_dataset = false // if you want the output to be registered - - variable_name = 'foo-bar' - // input/output locations output_dir = 'where/to/save/outputs/' - // Tool-specific temp dirs here - // Using other directories, like /hot or /tmp, can cause latency and disk space issues - // tool_temp_dir = '/scratch' // Default is scratch - // Add other inputs/parameters here + // Choices: ["Mutect2", "HaplotypeCaller"] + variant_caller = "Mutect2" + + input_vcf = "" + rf_model = "" + + // Reference files + fasta_ref_37 = "/hot/ref/reference/GRCh37-EBI-hs37d5/hs37d5.fa" + fasta_ref_38 = "/hot/ref/reference/GRCh38-BI-20160721/Homo_sapiens_assembly38.fasta" + + // FIXME Are these standard reference files, or should these be templatized as well? + chain_file = "/hot/resource/genomics/liftover_chain_files/hg19ToHg38.over.chain" + repeat_bed = "/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/intervals/GRCh38_RepeatMasker_intervals.bed" + funcotator_sources = "/hot/ref/tool-specific-input/Funcotator/somatic/funcotator_dataSources.v1.7.20200521s" } // Setup the pipeline config. DO NOT REMOVE THIS LINE! From e17e407a1749eb42a9aa4b063e3caba9d677e508 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 1 Jul 2024 12:25:00 -0700 Subject: [PATCH 04/60] Begin standardizing methods.config --- config/methods.config | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/config/methods.config b/config/methods.config index 761fd3b..065f849 100644 --- a/config/methods.config +++ b/config/methods.config @@ -2,6 +2,7 @@ includeConfig "${projectDir}/external/pipeline-Nextflow-config/config/methods/common_methods.config" includeConfig "${projectDir}/external/pipeline-Nextflow-config/config/schema/schema.config" includeConfig "${projectDir}/external/pipeline-Nextflow-config/config/bam/bam_parser.config" +includeConfig "${projectDir}/external/pipeline-Nextflow-config/config/store_object_as_json/store_object_as_json.config" methods { get_ids_from_bams = { @@ -21,26 +22,12 @@ methods { } } } - // Set the output and log output dirs here. + // Set the output and log output dirs here. set_output_dir = { - - tz = TimeZone.getTimeZone('UTC') - def date = new Date().format("yyyyMMdd'T'HHmmss'Z'", tz) - - params.dataset_registry_prefix = '/hot/data' + def date = new Date().format("yyyyMMdd'T'HHmmss'Z'", TimeZone.getTimeZone('UTC')) - if (params.blcds_registered_dataset == true) { - if ("${params.dataset_id.length()}" != 11) { - throw new Exception("Dataset id must be eleven characters long") - } - def disease = "${params.dataset_id.substring(0,4)}" - // Need to fill in analyte, technology, raw_od_aligned, genome, pipeline-name - params.output_log_directory = "${params.dataset_registry_prefix}/$disease/${params.dataset_id}/${patient}/${sample}/analyte/technology,raw_or_aligned/genome/log/pipeline-name/$date" - params.disease = "${disease}" - } else { - params.output_dir_base = "${params.output_dir}/${manifest.name}-${manifest.version}/${params.sample_name.replace(' ', '_')}" - params.log_output_dir = "${params.output_dir_base}/log-${manifest.name}-${manifest.version}-${date}" - } + params.output_dir_base = "${params.output_dir}/${manifest.name}-${manifest.version}/${params.sample_id.replace(' ', '_')}" + params.log_output_dir = "${params.output_dir_base}/log-${manifest.name}-${manifest.version}-${date}" } set_pipeline_logs = { @@ -68,9 +55,8 @@ methods { } setup = { -// add this file and uncomment if needed -// schema.load_custom_types("${projectDir}/config/custom_schema_types.config") methods.set_output_dir() + schema.validate() methods.set_resources_allocation() methods.modify_base_allocations() methods.set_pipeline_logs() @@ -78,5 +64,10 @@ methods { methods.get_ids_from_bams() methods.setup_docker_cpus() methods.setup_process_afterscript() + + json_extractor.store_object_as_json( + params, + new File("${params.log_output_dir}/nextflow-log/params.json") + ) } } From 644d65138f7f763bd5119e50ac16a72934f7e056 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 1 Jul 2024 12:30:39 -0700 Subject: [PATCH 05/60] Add schema.yaml and input/template.yaml --- config/default.config | 3 ++ config/schema.yaml | 71 +++++++++++++++++++++++++++++++++++ input/template-input-BAM.yaml | 9 ----- input/template.yaml | 5 +++ 4 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 config/schema.yaml delete mode 100644 input/template-input-BAM.yaml create mode 100644 input/template.yaml diff --git a/config/default.config b/config/default.config index 31f3a37..6d9380e 100644 --- a/config/default.config +++ b/config/default.config @@ -7,6 +7,9 @@ params { min_cpus = 1 min_memory = 1.MB + dataset_id = '' + blcds_registered_dataset = false + ucla_cds = true docker_container_registry = "ghcr.io/uclahs-cds" diff --git a/config/schema.yaml b/config/schema.yaml new file mode 100644 index 0000000..8b74a1b --- /dev/null +++ b/config/schema.yaml @@ -0,0 +1,71 @@ +--- +dataset_id: + type: 'String' + required: true + help: 'Dataset identifier' +blcds_registered_dataset: + type: 'Bool' + required: true + help: 'Enable to have output be registered' + default: false +sample_id: + type: 'String' + required: true + help: 'sample id supplied from input yaml' +algorithm: + type: 'List' + required: true + help: 'List of Annotation Algorithms to apply' + default: + - SnpEff + - Funcotator + - VEP + choices: + - SnpEff + - Funcotator + - VEP +save_intermediate_files: + type: 'Bool' + required: true + default: false + help: 'Enable to store intermediate files' +output_dir: + type: 'Path' + mode: 'w' + required: true + help: 'absolute path to directory to store output' +fasta_ref_37: + type: 'Path' + mode: 'r' + required: true + help: 'GRCh37 reference FASTA file' +fasta_ref_38: + type: 'Path' + mode: 'r' + required: true + help: 'GRCh38 reference FASTA file' +chain_file: + type: 'Path' + mode: 'r' + required: true + help: 'FIXME ???' +repeat_bed: + type: 'Path' + mode: 'r' + required: true + help: 'FIXME ???' +funcotator_sources: + type: 'Path' + mode: 'r' + required: true + help: 'FIXME ???' +input: + type: 'Namespace' + required: true + help: 'Input sample' + elements: + vcf: + type: 'Path' + mode: 'r' + required: true + help: 'Input dataset supplied by input yaml' diff --git a/input/template-input-BAM.yaml b/input/template-input-BAM.yaml deleted file mode 100644 index 624f9c1..0000000 --- a/input/template-input-BAM.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -patient_id: 'patient_id' -input: - normal: - - id: normal_sample_id - path: /path/to/normal.bam - tumor: - - id: tumor_sample_id - path: /path/to/tumor.bam diff --git a/input/template.yaml b/input/template.yaml new file mode 100644 index 0000000..4a0f49b --- /dev/null +++ b/input/template.yaml @@ -0,0 +1,5 @@ +--- +sample_id: "" +input: + vcf: + - /path/to/file.vcf From 4f41d9adaadf6f9ce4014616f56ecad6f2ec36a3 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Tue, 2 Jul 2024 14:06:13 -0700 Subject: [PATCH 06/60] Use custom schema type --- config/custom_schema_types.config | 49 +++++++++++++++++++++++++++++ config/methods.config | 22 ++----------- config/schema.yaml | 51 +++++++++++++++---------------- config/template.config | 21 ++++++++++--- input/template.yaml | 3 +- 5 files changed, 95 insertions(+), 51 deletions(-) create mode 100644 config/custom_schema_types.config diff --git a/config/custom_schema_types.config b/config/custom_schema_types.config new file mode 100644 index 0000000..bcf24fc --- /dev/null +++ b/config/custom_schema_types.config @@ -0,0 +1,49 @@ +import nextflow.Nextflow + +/** +* This custom schema namespace implements a custom type for Funcotator data sources. +*/ +custom_schema_types { + + /** + * Check that input refers to a properly configured Funcotator data source + * directory + */ + check_funcotator_data_source = { Map options, String name, Map properties -> + if (!(options[name] in Map)) { + throw new Exception("${name} should be a Map, not ${options[name].getClass()}.") + } + + options[name].each { entry -> + def entry_as_map = [:] + entry_as_map[entry.key] = entry.value + schema.validate_parameter(entry_as_map, entry.key, properties.elements[entry.key]) + } + + /* + Confirm that the destination reference sequence ID is a valid subfolder + in at least _one_ of the data sources. A reference-specific data source + directory requires a .config file at a path like: + + dataSourcesFolder//hg19/.config + dataSourcesFolder//hg38/.config + + There can be mulitple folders, but there should be only + one config per reference-specific subfolder. + */ + config_glob = [ + options[name].data_source, + "*", + options[name].dest_reference_id, + "*.config" + ].join("/") + + if (!Nextflow.file(config_glob)) { + throw new Exception("${name} is improperly configured - no files found matching '${config_glob}'") + } + } + + types = [ + 'FuncotatorDataSource': custom_schema_types.check_funcotator_data_source + ] +} diff --git a/config/methods.config b/config/methods.config index 065f849..7cbf874 100644 --- a/config/methods.config +++ b/config/methods.config @@ -5,23 +5,6 @@ includeConfig "${projectDir}/external/pipeline-Nextflow-config/config/bam/bam_pa includeConfig "${projectDir}/external/pipeline-Nextflow-config/config/store_object_as_json/store_object_as_json.config" methods { - get_ids_from_bams = { - params.samples_to_process = [] as Set - params.input.BAM.each { k, v -> - v.each { bam_path -> - def bam_header = bam_parser.parse_bam_header(bam_path) - def sm_tags = bam_header['read_group'].collect{ it['SM'] }.unique() - if (sm_tags.size() != 1) { - throw new Exception("${bam_path} contains multiple samples! Please run pipeline with single sample BAMs.") - } - if (alreadyExists == params.samples_to_process.any { it.orig_id == sm_tags[0] }) { - throw new Exception("Sample ${sm_tags[0]} was found in multiple BAMs. Please provide only one BAM per sample") - } - new_sm_tag = methods.sanitize_string(sm_tags[0]) - params.samples_to_process.add(['orig_id': sm_tags[0], 'id': new_sm_tag, 'path': bam_path, 'sample_type': k]) - } - } - } // Set the output and log output dirs here. set_output_dir = { def date = new Date().format("yyyyMMdd'T'HHmmss'Z'", TimeZone.getTimeZone('UTC')) @@ -55,13 +38,14 @@ methods { } setup = { - methods.set_output_dir() + schema.load_custom_types("${projectDir}/config/custom_schema_types.config") schema.validate() + + methods.set_output_dir() methods.set_resources_allocation() methods.modify_base_allocations() methods.set_pipeline_logs() methods.set_env() - methods.get_ids_from_bams() methods.setup_docker_cpus() methods.setup_process_afterscript() diff --git a/config/schema.yaml b/config/schema.yaml index 8b74a1b..a9e24a0 100644 --- a/config/schema.yaml +++ b/config/schema.yaml @@ -1,29 +1,8 @@ --- -dataset_id: - type: 'String' - required: true - help: 'Dataset identifier' -blcds_registered_dataset: - type: 'Bool' - required: true - help: 'Enable to have output be registered' - default: false sample_id: type: 'String' required: true help: 'sample id supplied from input yaml' -algorithm: - type: 'List' - required: true - help: 'List of Annotation Algorithms to apply' - default: - - SnpEff - - Funcotator - - VEP - choices: - - SnpEff - - Funcotator - - VEP save_intermediate_files: type: 'Bool' required: true @@ -34,16 +13,16 @@ output_dir: mode: 'w' required: true help: 'absolute path to directory to store output' -fasta_ref_37: +src_fasta_ref: type: 'Path' mode: 'r' required: true - help: 'GRCh37 reference FASTA file' -fasta_ref_38: + help: 'Source reference sequence (FASTA)' +dest_fasta_ref: type: 'Path' mode: 'r' required: true - help: 'GRCh38 reference FASTA file' + help: 'Destination reference sequence (FASTA)' chain_file: type: 'Path' mode: 'r' @@ -54,7 +33,27 @@ repeat_bed: mode: 'r' required: true help: 'FIXME ???' -funcotator_sources: +funcotator_data: + type: 'FuncotatorDataSource' + required: true + help: 'Funcotator data source and reference sample IDs' + elements: + data_source: + type: 'Path' + mode: 'r' + required: true + help: 'Root data source folder for Funcotator' + src_reference_id: + type: 'String' + mode: 'r' + required: true + help: 'Reference build ID for the source sequence' + dest_reference_id: + type: 'String' + mode: 'r' + required: true + help: 'Reference build ID for the destination sequence' +rf_model: type: 'Path' mode: 'r' required: true diff --git a/config/template.config b/config/template.config index adafde4..da08964 100644 --- a/config/template.config +++ b/config/template.config @@ -13,18 +13,31 @@ params { // Choices: ["Mutect2", "HaplotypeCaller"] variant_caller = "Mutect2" + save_intermediate_files = false - input_vcf = "" rf_model = "" // Reference files - fasta_ref_37 = "/hot/ref/reference/GRCh37-EBI-hs37d5/hs37d5.fa" - fasta_ref_38 = "/hot/ref/reference/GRCh38-BI-20160721/Homo_sapiens_assembly38.fasta" + funcotator_data { + data_source = "/hot/ref/tool-specific-input/Funcotator/somatic/funcotator_dataSources.v1.7.20200521s" + src_reference_id = "hg19" + dest_reference_id = "hg38" + } + + // The source reference sequence (FASTA) + src_fasta_ref = "/hot/ref/reference/GRCh37-EBI-hs37d5/hs37d5.fa" + // An identifier for the source sequence (e.g. hg19, hg38, b37). Only used to + // construct filenames. + + // The destination reference sequence (FASTA) + dest_fasta_ref = "/hot/ref/reference/GRCh38-BI-20160721/Homo_sapiens_assembly38.fasta" + // An identifier for the destination sequence. This must be a valid + // subdirectory of the funcotator_source directory (e.g. hg19, hg38, b37) + dest_fasta_id = "hg38" // FIXME Are these standard reference files, or should these be templatized as well? chain_file = "/hot/resource/genomics/liftover_chain_files/hg19ToHg38.over.chain" repeat_bed = "/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/intervals/GRCh38_RepeatMasker_intervals.bed" - funcotator_sources = "/hot/ref/tool-specific-input/Funcotator/somatic/funcotator_dataSources.v1.7.20200521s" } // Setup the pipeline config. DO NOT REMOVE THIS LINE! diff --git a/input/template.yaml b/input/template.yaml index 4a0f49b..c968d97 100644 --- a/input/template.yaml +++ b/input/template.yaml @@ -1,5 +1,4 @@ --- sample_id: "" input: - vcf: - - /path/to/file.vcf + vcf: /path/to/file.vcf From 2e56fe8c1bcfe355f59730befa04cef61b0ce534 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Tue, 2 Jul 2024 15:11:56 -0700 Subject: [PATCH 07/60] Working through PipeVal stage --- main.nf | 80 ++++++++++++++++++------------------------------- nextflow.config | 6 ++-- 2 files changed, 32 insertions(+), 54 deletions(-) diff --git a/main.nf b/main.nf index bae2734..0d0b0b1 100644 --- a/main.nf +++ b/main.nf @@ -3,17 +3,12 @@ nextflow.enable.dsl=2 // Include processes and workflows here -include { run_validate_PipeVal } from './external/pipeline-Nextflow-module/modules/PipeVal/validate/main.nf' addParams( +include { run_validate_PipeVal_with_metadata } from './external/pipeline-Nextflow-module/modules/PipeVal/validate/main.nf' addParams( options: [ docker_image_version: params.pipeval_version, main_process: "./" //Save logs in /process-log/run_validate_PipeVal ] ) -include { generate_standard_filename } from './external/pipeline-Nextflow-module/modules/common/generate_standardized_filename/main.nf' -include { tool_name_command_name } from './module/module-name' addParams( - workflow_output_dir: "${params.output_dir_base}/ToolName-${params.toolname_version}", - workflow_log_output_dir: "${params.log_output_dir}/process-log/ToolName-${params.toolname_version}" - ) // Log info here log.info """\ @@ -60,54 +55,37 @@ def indexFile(bam_or_vcf) { } } -// Channels here -Channel - .fromList(params.samples_to_process) - .map { sample -> - return tuple(sample.orig_id, sample.id, sample.path, sample.sample_type) - } - .set { samplesToProcessChannel } - -Channel - .fromList(params.samples_to_process) - .map{ it -> [it['path'], indexFile(it['path'])] } - .flatten() - .set { files_to_validate_ch } - -// Possible reference channel -Channel - .from( - params.reference, - params.reference_index, - params.reference_dict - ) - .set { reference_ch } - -// Decription of input channel -Channel - .fromPath(params.variable_name) - .ifEmpty { error "Cannot find: ${params.variable_name}" } - .set { input_ch_variable_name } - -files_to_validate_ch = files_to_validate_ch - .mix(reference_ch) - .mix(input_ch_variable_name) - // Main workflow here workflow { - // Validation process - run_validate_PipeVal( - files_to_validate_ch - ) - run_validate_PipeVal.out.val_file.collectFile( - name: 'input_validation.txt', newLine: true, - storeDir: "${params.output_dir_base}/validation" + // Currently this is written for a single sample_id and VCF file, but + // abstract that away + Channel.of ([ + vcf: params.input.vcf, + index: indexFile(params.input.vcf), + sample_id: params.sample_id + ]).set { vcf_with_index } + + // Run the input VCF and TBI files through PipeVal + vcf_with_index + .flatMap { sample -> + [ + [sample.vcf, [[sample_id: sample.sample_id], "vcf"]], + [sample.index, [[sample_id: sample.sample_id], "index"]] + ] + } | run_validate_PipeVal_with_metadata + + // Save the validation result + run_validate_PipeVal_with_metadata.out.validation_result + .collectFile( + name: 'input_validation.txt', + newLine: true, + storeDir: "${params.output_dir_base}/validation" ) - // Workflow or process - tool_name_command_name( - samplesToProcessChannel, - input_ch_variable_name - ) + run_validate_PipeVal_with_metadata.out.validated_file + .map { filename, metadata -> [metadata[0].sample_id, metadata[0] + [(metadata[1]): filename]] } + .groupTuple() + .map { it[1].inject([:]) { result, i -> result + i } } + .set { validated_vcf_with_index } } diff --git a/nextflow.config b/nextflow.config index bfd2628..82d031d 100644 --- a/nextflow.config +++ b/nextflow.config @@ -1,7 +1,7 @@ // Metadata manifest { - name = 'pipeline-name-nf' - author = 'Authors Name' + name = 'pipeline-StableLift' + author = 'Nicholas Wiltsie' description = 'A template for Nextflow pipelines' - version = 'Version Number' + version = '0.1.0' } From 0295fe300c4cbc5efb9c212b4f6092df7b47feda Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Wed, 3 Jul 2024 11:31:11 -0700 Subject: [PATCH 08/60] Working bcftools +liftover process --- main.nf | 24 ++++++++++++++++ module/liftover.nf | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 module/liftover.nf diff --git a/main.nf b/main.nf index 0d0b0b1..6bb4c78 100644 --- a/main.nf +++ b/main.nf @@ -10,6 +10,8 @@ include { run_validate_PipeVal_with_metadata } from './external/pipeline-Nextflo ] ) +include { raw_liftover } from './module/liftover.nf' + // Log info here log.info """\ ====================================== @@ -55,6 +57,14 @@ def indexFile(bam_or_vcf) { } } +Channel + .value( [params.funcotator_data.src_reference_id, params.src_fasta_ref] ) + .set { input_ch_src_sequence } + +Channel + .value( [params.funcotator_data.dest_reference_id, params.dest_fasta_ref] ) + .set { input_ch_dest_sequence } + // Main workflow here workflow { @@ -66,6 +76,8 @@ workflow { sample_id: params.sample_id ]).set { vcf_with_index } + // The values of vcf_with_index are maps with keys vcf, index, and sample_id. + // Run the input VCF and TBI files through PipeVal vcf_with_index .flatMap { sample -> @@ -88,4 +100,16 @@ workflow { .groupTuple() .map { it[1].inject([:]) { result, i -> result + i } } .set { validated_vcf_with_index } + + // The values of validated_vcf_with_index are maps with keys vcf, index, and sample_id. + raw_liftover( + validated_vcf_with_index.map { [it.sample_id, it.vcf, it.index] }, + input_ch_src_sequence, + input_ch_dest_sequence, + Channel.value(params.chain_file), + // FIXME This is not the correct approach + Channel.value("${projectDir}/input/liftover.so") + ) + + } diff --git a/module/liftover.nf b/module/liftover.nf new file mode 100644 index 0000000..96cca55 --- /dev/null +++ b/module/liftover.nf @@ -0,0 +1,68 @@ +/* +* Module/process description here +* +* @input +* @params +* @output +*/ + +// include { generate_standard_filename } from '../external/pipeline-Nextflow-module/modules/common/generate_standardized_filename/main.nf' + +process raw_liftover { + container params.docker_image_bcftools + + publishDir path: "${intermediate_path}", + pattern: "reject.vcf.gz", + mode: "copy", + enabled: params.save_intermediate_files, + saveAs: { "${slug}-reject.vcf.gz" } + + publishDir path: "${intermediate_path}", + pattern: "liftover.vcf.gz", + mode: "copy", + enabled: params.save_intermediate_files, + saveAs: { "${slug}.vcf.gz" } + + publishDir path: "${intermediate_path}", + pattern: "liftover.vcf.gz.tbi", + mode: "copy", + enabled: params.save_intermediate_files, + saveAs: { "${slug}.vcf.gz.tbi" } + + input: + tuple val(sample_id), path(vcf), path(index) + tuple val(src_fasta_id), path(src_fasta_ref) + tuple val(dest_fasta_id), path(dest_fasta_ref) + path (chain_file) + // FIXME This is not the correct approach + path liftover_plugin, stageAs: 'bcf_plugins/liftover.so' + + output: + tuple val(sample_id), path('liftover.vcf.gz'), path('liftover.vcf.gz.tbi'), emit: liftover_file + + script: + // FIXME Use a more standard path + intermediate_path = "${params.output_dir_base}/${params.bcftools_version}/intermediate/${task.process}" + + slug = "LiftOver-${sample_id}-${src_fasta_id}-to-${dest_fasta_id}" + + """ + export BCFTOOLS_PLUGINS="\$(pwd)/bcf_plugins" + bcftools +liftover \ + --output-type u \ + "${vcf}" \ + -- \ + --src-fasta-ref "${src_fasta_ref}" \ + --fasta-ref "${dest_fasta_ref}" \ + --chain "${chain_file}" \ + --reject-type z \ + --reject "reject.vcf.gz" | \ + bcftools view \ + --output-type u \ + -e 'REF="." | ALT="."' | \ + bcftools sort \ + --output-type z \ + --write-index=tbi \ + --output "liftover.vcf.gz" + """ +} From a644c34c2fba6408ff3584cbb8c1a410210579f1 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Fri, 5 Jul 2024 08:56:35 -0700 Subject: [PATCH 09/60] Start work on funcotator, bundle liftover.so --- config/default.config | 9 +++++++++ config/schema.yaml | 20 ++++++++++++++++++++ input/liftover.so | Bin 0 -> 224016 bytes main.nf | 26 ++++++++++++++++++++++++-- module/funcotator.nf | 42 ++++++++++++++++++++++++++++++++++++++++++ module/liftover.nf | 6 +++--- 6 files changed, 98 insertions(+), 5 deletions(-) create mode 100755 input/liftover.so create mode 100644 module/funcotator.nf diff --git a/config/default.config b/config/default.config index 6d9380e..e85d40c 100644 --- a/config/default.config +++ b/config/default.config @@ -1,4 +1,5 @@ import nextflow.util.SysHelper +import nextflow.Nextflow // Default inputs/parameters of the pipeline params { @@ -27,6 +28,14 @@ params { docker_image_pipeval = "${-> params.docker_container_registry}/pipeval:${params.pipeval_version}" docker_image_samtools = "${-> params.docker_container_registry}/samtools:${params.samtools_version}" docker_image_stablelift = "${-> params.docker_container_registry}/stablelift:${params.stablelift_version}" + + // These are the index files associated with the source and destination + // reference sequences + src_fasta_fai = "${ -> params.src_fasta_ref}.fai" + dest_fasta_fai = "${ -> params.dest_fasta_ref}.fai" + + src_fasta_dict = "${ -> Nextflow.file(params.src_fasta_ref).resolveSibling(Nextflow.file(params.src_fasta_ref).getBaseName() + '.dict') }" + dest_fasta_dict = "${ -> Nextflow.file(params.dest_fasta_ref).resolveSibling(Nextflow.file(params.dest_fasta_ref).getBaseName() + '.dict') }" } // Process specific scope diff --git a/config/schema.yaml b/config/schema.yaml index a9e24a0..7d2645b 100644 --- a/config/schema.yaml +++ b/config/schema.yaml @@ -18,11 +18,31 @@ src_fasta_ref: mode: 'r' required: true help: 'Source reference sequence (FASTA)' +src_fasta_fai: + type: 'Path' + mode: 'r' + required: true + help: 'Source reference sequence index file' +src_fasta_dict: + type: 'Path' + mode: 'r' + required: true + help: 'Source reference sequence dictionary' dest_fasta_ref: type: 'Path' mode: 'r' required: true help: 'Destination reference sequence (FASTA)' +dest_fasta_fai: + type: 'Path' + mode: 'r' + required: true + help: 'Destination reference sequence index file' +dest_fasta_dict: + type: 'Path' + mode: 'r' + required: true + help: 'Destination reference sequence dictionary' chain_file: type: 'Path' mode: 'r' diff --git a/input/liftover.so b/input/liftover.so new file mode 100755 index 0000000000000000000000000000000000000000..1dbea79518283e137fbb7c407b70fd8f6f7901e0 GIT binary patch literal 224016 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 z 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 [ @@ -111,5 +126,12 @@ workflow { Channel.value("${projectDir}/input/liftover.so") ) + funcotator_input = raw_liftover.out.liftover_vcf_with_index + run_funcotator( + // raw_liftover.out.liftover_vcf_with_index, + funcotator_input, + input_ch_dest_sequence, + Channel.value(params.funcotator_data.data_source) + ) } diff --git a/module/funcotator.nf b/module/funcotator.nf new file mode 100644 index 0000000..cbb7b15 --- /dev/null +++ b/module/funcotator.nf @@ -0,0 +1,42 @@ +/* +* Module/process description here +* +* @input +* @params +* @output +*/ + +include { generate_standard_filename } from '../external/pipeline-Nextflow-module/modules/common/generate_standardized_filename/main.nf' + +process run_funcotator { + container params.docker_image_gatk + + publishDir path: "${intermediate_filepath}", + pattern: "output.vcf.gz", + mode: "copy", + enabled: params.save_intermediate_files, + saveAs: "${slug}.vcf.gz" + + input: + tuple val(sample_id), path(vcf), path(index) + tuple val(dest_fasta_id), path(dest_fasta_ref), path(dest_fasta_fai), path(dest_fasta_dict) + path (funcotator_sources) + + output: + tuple val(sample_id), path('output.vcf.gz'), emit: funcotator_vcf + + script: + intermediate_filepath = "${params.output_dir_base}/GATK-${params.gatk_version}/intermediate/${task.process}" + + slug = "Funcotator-${sample_id}-${dest_fasta_id}" + + """ + gatk Funcotator \ + --variant "${vcf}" \ + --reference "${dest_fasta_ref}" \ + --ref-version "${dest_fasta_id}" \ + --data-sources-path "${funcotator_sources}" \ + --output-file-format VCF \ + --output "output.vcf.gz" + """ +} diff --git a/module/liftover.nf b/module/liftover.nf index 96cca55..9508e0a 100644 --- a/module/liftover.nf +++ b/module/liftover.nf @@ -31,14 +31,14 @@ process raw_liftover { input: tuple val(sample_id), path(vcf), path(index) - tuple val(src_fasta_id), path(src_fasta_ref) - tuple val(dest_fasta_id), path(dest_fasta_ref) + tuple val(src_fasta_id), path(src_fasta_ref), path(src_fasta_fai), path(src_fasta_dict) + tuple val(dest_fasta_id), path(dest_fasta_ref), path(dest_fasta_fai), path(dest_fasta_dict) path (chain_file) // FIXME This is not the correct approach path liftover_plugin, stageAs: 'bcf_plugins/liftover.so' output: - tuple val(sample_id), path('liftover.vcf.gz'), path('liftover.vcf.gz.tbi'), emit: liftover_file + tuple val(sample_id), path('liftover.vcf.gz'), path('liftover.vcf.gz.tbi'), emit: liftover_vcf_with_index script: // FIXME Use a more standard path From 82d35591bb45f5b2a2c53851a7b35d8455ddf7dc Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Fri, 5 Jul 2024 14:03:55 -0700 Subject: [PATCH 10/60] Bugfixes --- main.nf | 4 ---- module/funcotator.nf | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/main.nf b/main.nf index e9fdfe3..fc8ac51 100644 --- a/main.nf +++ b/main.nf @@ -90,10 +90,6 @@ workflow { // The values of vcf_with_index are maps with keys vcf, index, and sample_id. // Run the input VCF and TBI files through PipeVal - if (params.skip_validation) { - vcf_with_index.set { validated_vcf_with_index } - } else { - vcf_with_index .flatMap { sample -> [ diff --git a/module/funcotator.nf b/module/funcotator.nf index cbb7b15..a845d6e 100644 --- a/module/funcotator.nf +++ b/module/funcotator.nf @@ -15,7 +15,7 @@ process run_funcotator { pattern: "output.vcf.gz", mode: "copy", enabled: params.save_intermediate_files, - saveAs: "${slug}.vcf.gz" + saveAs: { "${slug}.vcf.gz" } input: tuple val(sample_id), path(vcf), path(index) From 445f427c32511b0fb3811f17753b48cda568d596 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 8 Jul 2024 12:32:51 -0700 Subject: [PATCH 11/60] Add annotations workflow --- config/F72.config | 23 ------ main.nf | 6 ++ module/annotations.nf | 184 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+), 23 deletions(-) create mode 100644 module/annotations.nf diff --git a/config/F72.config b/config/F72.config index 21ae4b0..e69de29 100644 --- a/config/F72.config +++ b/config/F72.config @@ -1,23 +0,0 @@ -// Static process resource allocation here -// Specific for each node type - F72 here -process { - withName: process_name { - cpus = - memory = - // Other process-specific allocations here - } - withName: process_name_2 { - cpus = - memory = - // Other process-specific allocations here - } - withName: process_name_3 { - cpus = - memory = - // Other process-specific allocations here - } - withName: example_process { - cpus = 2 - memory = 5.GB - } -} diff --git a/main.nf b/main.nf index fc8ac51..13c497f 100644 --- a/main.nf +++ b/main.nf @@ -12,6 +12,7 @@ include { run_validate_PipeVal_with_metadata } from './external/pipeline-Nextflo include { raw_liftover } from './module/liftover.nf' include { run_funcotator } from './module/funcotator.nf' +include { apply_annotations } from './module/annotations.nf' // Log info here log.info """\ @@ -130,4 +131,9 @@ workflow { input_ch_dest_sequence, Channel.value(params.funcotator_data.data_source) ) + + apply_annotations( + run_funcotator.out.funcotator_vcf, + input_ch_dest_sequence + ) } diff --git a/module/annotations.nf b/module/annotations.nf new file mode 100644 index 0000000..50a6dc7 --- /dev/null +++ b/module/annotations.nf @@ -0,0 +1,184 @@ +process run_repeatmasker { + container params.docker_image_bcftools + + publishDir path: "${intermediate_filepath}", + pattern: "output.vcf.gz", + mode: "copy", + enabled: params.save_intermediate_files, + saveAs: { "${slug}.vcf.gz" } + + input: + tuple val(sample_id), path(vcf) + path(repeat_bed) + + output: + tuple val(sample_id), path('output.vcf.gz'), emit: repeatmasker_vcf + + script: + intermediate_filepath = "${params.output_dir_base}/bcftools-${params.bcftools_version}/intermediate/${task.process}" + + slug = "RepeatMasker-${sample_id}" + + """ + bcftools annotate \ + -a "${repeat_bed}" \ + -c CHROM,FROM,TO,REPEAT \ + -h <(echo '##INFO=') \ + -o "output.vcf.gz" \ + "${vcf}" + """ +} + +process run_trinucleotide_context { + container params.docker_image_bedtools + + publishDir path: "${intermediate_filepath}", + pattern: "output.bed", + mode: "copy", + enabled: params.save_intermediate_files, + saveAs: { "${slug}.bed" } + + publishDir path: "${intermediate_filepath}", + pattern: "output.tsv", + mode: "copy", + enabled: params.save_intermediate_files, + saveAs: { "${slug}-full.tsv" } + + publishDir path: "${intermediate_filepath}", + pattern: "partial.tsv", + mode: "copy", + enabled: params.save_intermediate_files, + saveAs: { "${slug}-partial.tsv" } + + input: + tuple val(sample_id), path(vcf) + tuple val(dest_fasta_id), path(dest_fasta_ref), path(dest_fasta_fai), path(dest_fasta_dict) + + output: + tuple val(sample_id), path('output.tsv'), emit: trinucleotide_tsv + tuple val(sample_id), path('output.bed'), emit: trinucleotide_bed + + script: + intermediate_filepath = "${params.output_dir_base}/bedtools-${params.bedtools_version}/intermediate/${task.process}" + + slug = "Trinucleotide-${sample_id}" + + """ + zcat ${vcf} \ + | grep -v "^#" \ + | awk '{if (length(\$4) == 1 && length(\$5) == 1) print \$1"\t"(\$2-2)"\t"(\$2+1)"\t"\$2}' \ + > "output.bed" + + bedtools getfasta \ + -fi ${dest_fasta_ref} \ + -bed "output.bed" \ + -fo "partial.tsv" \ + -name \ + -tab + + paste -d '\t' \ + <(cut -f 1,4 "output.bed") \ + <(cut -f 2 "partial.tsv") \ + > "output.tsv" + """ +} + +process run_compress_and_index { + container params.docker_image_samtools + + publishDir path: "${intermediate_filepath}", + pattern: "output.tsv.gz", + mode: "copy", + enabled: params.save_intermediate_files + + publishDir path: "${intermediate_filepath}", + pattern: "output.tsv.gz.tbi", + mode: "copy", + enabled: params.save_intermediate_files + + input: + tuple val(sample_id), path(tsv) + + output: + tuple val(sample_id), path('output.tsv.gz'), path('output.tsv.gz.tbi'), emit: compressed_tsv_with_index + + script: + intermediate_filepath = "${params.output_dir_base}/samtools-${params.bcftools_version}/intermediate/${task.process}" + + slug = "Trinucleotide-${sample_id}" + + """ + bgzip ${tsv} --output output.tsv.gz + + tabix \ + --sequence 1 \ + --begin 2 \ + --end 2 \ + output.tsv.gz + """ +} + + +process run_trinucleotide_annotate { + container params.docker_image_bcftools + + publishDir path: "${intermediate_filepath}", + pattern: "output.vcf.gz", + mode: "copy", + enabled: params.save_intermediate_files, + saveAs: { "${slug}.vcf.gz" } + + input: + tuple val(sample_id), path(vcf), path(tsv), path(tsv_tbi) + + // FIXME Should this process also emit the index file? It seems like + // bcftools won't produce it without the --write-index flag + output: + tuple val(sample_id), path('output.vcf.gz'), emit: trinucleotide_vcf + + script: + intermediate_filepath = "${params.output_dir_base}/bcftools-${params.bcftools_version}/intermediate/${task.process}" + + slug = "Trinucleotide-${sample_id}" + + """ + bcftools annotate \ + --annotations ${tsv} \ + --columns CHROM,POS,TRINUCLEOTIDE \ + --header-lines <(echo '##INFO=') \ + --output output.vcf.gz \ + ${vcf} + """ +} + + + +workflow apply_annotations { + take: + vcf_with_sample_id + dest_fasta_data + + main: + run_repeatmasker( + vcf_with_sample_id, + Channel.value(params.repeat_bed) + ) + + run_trinucleotide_context( + run_repeatmasker.out.repeatmasker_vcf, + dest_fasta_data + ) + + run_compress_and_index(run_trinucleotide_context.out.trinucleotide_tsv) + + run_trinucleotide_annotate( + run_repeatmasker.out.repeatmasker_vcf.join( + run_compress_and_index.out.compressed_tsv_with_index, + failOnDuplicate: true, + failOnMismatch: true + ) + ) + + emit: + annotated_vcf = run_trinucleotide_annotate.out.trinucleotide_vcf +} From d92b58ccb49671b5e14d9d43c476bfd2756409d2 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 8 Jul 2024 13:39:13 -0700 Subject: [PATCH 12/60] Add feature extraction process --- main.nf | 5 + module/extract_features.nf | 37 ++++ module/scripts/extract-vcf-features.R | 265 ++++++++++++++++++++++++++ 3 files changed, 307 insertions(+) create mode 100644 module/extract_features.nf create mode 100644 module/scripts/extract-vcf-features.R diff --git a/main.nf b/main.nf index 13c497f..35d339b 100644 --- a/main.nf +++ b/main.nf @@ -13,6 +13,7 @@ include { run_validate_PipeVal_with_metadata } from './external/pipeline-Nextflo include { raw_liftover } from './module/liftover.nf' include { run_funcotator } from './module/funcotator.nf' include { apply_annotations } from './module/annotations.nf' +include { extract_features} from './module/extract_features.nf' // Log info here log.info """\ @@ -136,4 +137,8 @@ workflow { run_funcotator.out.funcotator_vcf, input_ch_dest_sequence ) + + extract_features( + apply_annotations.out.annotated_vcf + ) } diff --git a/module/extract_features.nf b/module/extract_features.nf new file mode 100644 index 0000000..c0da938 --- /dev/null +++ b/module/extract_features.nf @@ -0,0 +1,37 @@ +process run_extract_vcf_features { + container params.docker_image_stablelift + containerOptions "-v ${moduleDir}:${moduleDir}" + + input: + tuple val(sample_id), path(vcf) + + output: + tuple val(sample_id), path('output.Rds'), emit: r_annotations + + script: + intermediate_filepath = "${params.output_dir_base}/stablelift-${params.stablelift_version}/intermediate/${task.process}" + + slug = "stablelift-${sample_id}" + + """ + Rscript "${moduleDir}/scripts/extract-vcf-features.R" \ + --input-vcf "${vcf}" \ + --variant-caller ${params.variant_caller} \ + --output-rds "output.Rds" + """ +} + +workflow extract_features { + take: + vcf_with_sample_id + + main: + if (params.variant_caller == "HaplotypeCaller") { + error "HaplotypeCaller is not supported yet" + } else { + run_extract_vcf_features(vcf_with_sample_id) + } + + emit: + r_annotations = run_extract_vcf_features.out.r_annotations +} diff --git a/module/scripts/extract-vcf-features.R b/module/scripts/extract-vcf-features.R new file mode 100644 index 0000000..5aa3d75 --- /dev/null +++ b/module/scripts/extract-vcf-features.R @@ -0,0 +1,265 @@ +#!/usr/bin/env Rscript +# extract-vcf-features.R +#################################################################################################### +# +# Extract features from vcf +# Extract Funcotator annotations if present +# Annotate with RepeatMasker regions if intersect file is provided +# +#################################################################################################### + +suppressPackageStartupMessages({ + library(vcfR); + library(data.table); + library(argparse); + library(doParallel); + library(foreach); + }); + +################################################################################################### +# Input +################################################################################################### +# Define command line arguments +parser <- ArgumentParser(); +parser$add_argument('--input-vcf', type = 'character', help = 'GRCh37 vcf lifted to GRCh38 for feature extraction'); +parser$add_argument('--input-dir', type = 'character', help = 'Directory with vcf subsets'); +parser$add_argument('--output-rds', type = 'character', help = 'Rds output for use in RF model'); +parser$add_argument('--variant-caller', type = 'character', help = ''); +parser$add_argument('--ncore', type = 'integer', help = 'Number of cores to use for parallelizing features extraction', default = 1); +args <- parser$parse_args(); + +# Save command line arguments +for (arg in names(args)) { + assign(gsub('_', '.', arg), args[[arg]]); + } + +# Set parameters for interactive runs +if (interactive()) { + variant.caller <- 'Strelka2'; + input.vcf <- '/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/gSNP/stableLift/validate_TCGA-SARC_WXS/TCGA-SARC_WXS_HaplotypeCaller_LiftOver-GRCh38_annotated_exome.vcf.gz'; + vcf.subset <- input.vcf; + } + +if (!is.null(input.dir)) { + vcf.subsets <- list.files(input.dir, full.names = TRUE, pattern = '(\\.vcf.gz|\\.vcf)$'); + output.path <- output.rds; +} else if (!is.null(input.vcf)) { + vcf.subsets <- input.vcf; + output.path <- ifelse(is.null(output.rds), sub('\\..*$', '.Rds', input.vcf), output.rds); +} else { + stop('Either `--input-vcf` or `--input-dir` must be provided'); + } + +################################################################################################### +# Functions +################################################################################################### +vcf.info.to.dt <- function(vcf.info) { + # Split each string by semicolon and convert to a list of key-value pairs + vcf.info <- strsplit(vcf.info, ';'); + vcf.info <- lapply(vcf.info, function(x) { + x <- strsplit(x, '='); + as.list(stats::setNames(sapply(x, `[`, 2), sapply(x, `[`, 1))); + }) + + # Combine the list of key-value pairs into a data table + rbindlist(vcf.info, fill = TRUE); + } + +sum.MAF <- function(x) { + x <- unlist(strsplit(x, ',')); + x <- 1 - as.numeric(x[1]); + if (is.na(x)) 0 else x; + } + +################################################################################################### +# Extract RF features from Funcotator vcf +################################################################################################### +start.extract <- Sys.time(); + +registerDoParallel(cores = ncore); +features.dt.subsets <- foreach(vcf.subset = vcf.subsets) %dopar% { + start.subset <- Sys.time(); + cat('Processing:', basename(vcf.subset), '\n'); + + input.vcf <- read.vcfR( + file = vcf.subset + ); + + # Parse info column + info <- vcf.info.to.dt(input.vcf@fix[, 'INFO']); + + # Aggregate per sample metrics, average depth per GT called + info$DP <- apply(extract.gt(input.vcf, element = 'DP', as.numeric = TRUE), 1, mean, na.rm = TRUE); + if (variant.caller == 'HaplotypeCaller') { + # Take mean of genotype quality and remove cohort allele frequency + info$GQ <- apply(extract.gt(input.vcf, element = 'GQ', as.numeric = TRUE), 1, mean, na.rm = TRUE); + info[, AF := NULL]; + } else if (variant.caller == 'Mutect2') { + # Get metric for ALT allele + info$MBQ <- sapply(extract.info(input.vcf, element = 'MBQ'), function(x) as.numeric(unlist(strsplit(x, ','))[2])); + info$MFRL <- sapply(extract.info(input.vcf, element = 'MFRL'), function(x) as.numeric(unlist(strsplit(x, ','))[2])); + info$MMQ <- sapply(extract.info(input.vcf, element = 'MMQ'), function(x) as.numeric(unlist(strsplit(x, ','))[2])); + # Take max of somatic variant allele frequencies + info$AF <- apply(extract.gt(input.vcf, element = 'AF', as.numeric = TRUE), 1, max, na.rm = TRUE); + } else if (variant.caller == 'Muse2') { + # Calculate VAF from allelic depths + info$AF <- apply(extract.gt(input.vcf, element = 'AD'), 1, function(x) mean(sapply(strsplit(x, ','), function(y) as.numeric(y[2]) / (as.numeric(y[1]) + as.numeric(y[2]))), na.rm = TRUE)); + info$BQ <- apply(extract.gt(input.vcf, element = 'BQ'), 1, function(x) mean(sapply(strsplit(x, ','), function(y) as.numeric(y[2])), na.rm = TRUE)); + } else if (variant.caller == 'Strelka2') { + # Calculate VAF from allelic depths + info[input.vcf@fix[, 'REF'] == 'A', REFCOUNTS := apply(extract.gt(input.vcf, element = 'AU')[input.vcf@fix[, 'REF'] == 'A', ], 1, function(x) mean(sapply(strsplit(x, ','), function(y) as.numeric(y[1])), na.rm = TRUE))]; + info[input.vcf@fix[, 'ALT'] == 'A', ALTCOUNTS := apply(extract.gt(input.vcf, element = 'AU')[input.vcf@fix[, 'ALT'] == 'A', ], 1, function(x) mean(sapply(strsplit(x, ','), function(y) as.numeric(y[1])), na.rm = TRUE))]; + info[input.vcf@fix[, 'REF'] == 'T', REFCOUNTS := apply(extract.gt(input.vcf, element = 'TU')[input.vcf@fix[, 'REF'] == 'T', ], 1, function(x) mean(sapply(strsplit(x, ','), function(y) as.numeric(y[1])), na.rm = TRUE))]; + info[input.vcf@fix[, 'ALT'] == 'T', ALTCOUNTS := apply(extract.gt(input.vcf, element = 'TU')[input.vcf@fix[, 'ALT'] == 'T', ], 1, function(x) mean(sapply(strsplit(x, ','), function(y) as.numeric(y[1])), na.rm = TRUE))]; + info[input.vcf@fix[, 'REF'] == 'C', REFCOUNTS := apply(extract.gt(input.vcf, element = 'CU')[input.vcf@fix[, 'REF'] == 'C', ], 1, function(x) mean(sapply(strsplit(x, ','), function(y) as.numeric(y[1])), na.rm = TRUE))]; + info[input.vcf@fix[, 'ALT'] == 'C', ALTCOUNTS := apply(extract.gt(input.vcf, element = 'CU')[input.vcf@fix[, 'ALT'] == 'C', ], 1, function(x) mean(sapply(strsplit(x, ','), function(y) as.numeric(y[1])), na.rm = TRUE))]; + info[input.vcf@fix[, 'REF'] == 'G', REFCOUNTS := apply(extract.gt(input.vcf, element = 'GU')[input.vcf@fix[, 'REF'] == 'G', ], 1, function(x) mean(sapply(strsplit(x, ','), function(y) as.numeric(y[1])), na.rm = TRUE))]; + info[input.vcf@fix[, 'ALT'] == 'G', ALTCOUNTS := apply(extract.gt(input.vcf, element = 'GU')[input.vcf@fix[, 'ALT'] == 'G', ], 1, function(x) mean(sapply(strsplit(x, ','), function(y) as.numeric(y[1])), na.rm = TRUE))]; + info[, AF := ALTCOUNTS / (REFCOUNTS + ALTCOUNTS)]; + } + + # Get funcotation fields + funcotator.fields <- grep('ID=FUNCOTATION', input.vcf@meta, value = TRUE); + funcotator.fields <- sub('.*Funcotation fields are: (.*)\\".*', '\\1', funcotator.fields); + funcotator.fields <- strsplit(funcotator.fields, split = '\\|')[[1]]; + + # Parse funcotation field from info column + funcotation <- sapply(info$FUNCOTATION, function(x) unlist(strsplit(x, split = ','))[1]); + names(funcotation) <- NULL; + funcotation <- gsub('\\[|\\]', '', funcotation); + funcotation <- lapply(funcotation, function(x) { + x <- unlist(strsplit(x, split = '\\|')); + x <- as.list(x[seq_along(funcotator.fields)]); + names(x) <- funcotator.fields; + return(x); + }); + features.dt <- rbindlist(funcotation, use.names = TRUE, fill = TRUE); + rm(funcotation); + + # names(features.dt) <- funcotator.fields; + funcotator.fields.keep <- c( + 'GC Content' = 'Gencode_34_gcContent', + 'GENCODE Variant Classification' = 'Gencode_34_variantClassification', + 'GENCODE Variant Type' = 'Gencode_34_variantType', + 'HGNC Locus Group' = 'HGNC_Locus_Group', + '1KG AF' = 'dbSNP_CAF', + 'TOPMED AF' = 'dbSNP_TOPMED' + ); + features.dt <- features.dt[, ..funcotator.fields.keep]; + + # Replace ascii character codes + features.dt <- as.data.table(lapply(features.dt, function(x) gsub('_%7C_', ';', x, fixed = TRUE))); + features.dt <- as.data.table(lapply(features.dt, function(x) gsub('_%2C_', ',', x, fixed = TRUE))); + features.dt <- as.data.table(lapply(features.dt, function(x) gsub('_%20_', ' ', x, fixed = TRUE))); + features.dt <- as.data.table(lapply(features.dt, function(x) gsub('_%3D_', '=', x, fixed = TRUE))); + + # Aggregate minor allele frequencies + features.dt[, dbSNP_CAF := sapply(dbSNP_CAF, sum.MAF)]; + features.dt[, dbSNP_TOPMED := sapply(dbSNP_TOPMED, sum.MAF)]; + + # Aggregate flattened fields + features.dt <- cbind(input.vcf@fix[, 1:7], info[, -c('FUNCOTATION')], features.dt); + + # Collapse trinucleotide reverse complements + features.dt[Gencode_34_variantType != 'SNP', TRINUCLEOTIDE := '']; + features.dt[Gencode_34_variantType == 'SNP', TRINUCLEOTIDE := sapply(TRINUCLEOTIDE, function(x) { + x <- as.character(x); + if (substr(x, 2, 2) %in% c('A', 'G')) { + x <- chartr('ATGC', 'TACG', x); + paste(rev(unlist(strsplit(x, ''))), collapse = ''); + } else { + x; + } + })]; + features.dt[Gencode_34_variantType == 'SNP', TRINUCLEOTIDE_SEQ := TRINUCLEOTIDE]; + # Add substitution base + features.dt[Gencode_34_variantType == 'SNP', ALT := sapply(ALT, function(x) unlist(strsplit(x, ','))[1])]; + features.dt[Gencode_34_variantType == 'SNP' & REF %in% c('A', 'G'), ALT := chartr('ATGC', 'TACG', ALT)]; + features.dt[Gencode_34_variantType == 'SNP' & TRINUCLEOTIDE != '', TRINUCLEOTIDE := paste0(TRINUCLEOTIDE, '->', substr(TRINUCLEOTIDE, 1, 1), ALT, substr(TRINUCLEOTIDE, 3, 3))]; + + cat(format(Sys.time() - start.subset, nsmall = 2), '\n'); + return(features.dt); + } + +features.dt <- rbindlist(features.dt.subsets, use.names = TRUE, fill = TRUE); +rm(features.dt.subsets); +gc(); +cat(format(Sys.time() - start.extract, nsmall = 2), '\n'); + +################################################################################################### +# Format features for RF +################################################################################################### +continuous.features <- c( + 'Chromosome Position (POS)' = 'POS', + 'Local GC Content' = 'Gencode_34_gcContent', # + '1000 Genomes Allele Frequency' = 'dbSNP_CAF', # + 'TOPMED Allele Frequency' = 'dbSNP_TOPMED', # + 'Sequencing Depth (DP)' = 'DP', + 'Variant Frequency (AF)' = 'AF' + ); +if (variant.caller == 'HaplotypeCaller') continuous.features <- c(continuous.features, + 'Variant Quality (QUAL)' = 'QUAL', + 'ExcessHet' = 'ExcessHet', + "Fisher's Strand Bias (FS)" = 'FS', + 'Mapping Quality (MQ)' = 'MQ', + 'Quality by Depth (QD)' = 'QD', + 'Strand Bias Odds Ratio (SOR)' = 'SOR', + 'VQSR Log Odds (VQSLOD)' = 'VQSLOD', + 'Genotype Quality (GQ)' = 'GQ' + ); +if (variant.caller == 'Mutect2') continuous.features <- c(continuous.features, + 'Tumor Variant Log Odds (TLOD)' = 'TLOD', + 'Events in Haplotype (ECNT)' = 'ECNT', + 'Germline Quality (GERMQ)' = 'GERMQ', + 'Median Distance to Read End (MPOS)' = 'MPOS', + 'Normal Artifact Log Odds (NALOD)' = 'NALOD', + 'Normal Variant Log Odds (NLOD)' = 'NLOD', + 'Read Orientation Artifact (ROQ)' = 'ROQ', + 'Median Base Quality (MBQ)' = 'MBQ', + 'Median Fragment Length (MFRL)' = 'MFRL', + 'Median Mapping Quality (MMQ)' = 'MMQ' + ); +if (variant.caller == 'Strelka2') continuous.features <- c(continuous.features, + 'Mapping Quality (MQ)' = 'MQ', + 'MQ0 Reads (MQ0)' = 'MQ0', + 'Empirical Variant Score (SomaticEVS)' = 'SomaticEVS', + 'Quality Score Somatic (QSS)' = 'QSS', + 'Quality Score Joint (QSS_NT)' = 'QSS_NT', + 'ReadPosRankSum' + ); +if (variant.caller == 'Muse2') continuous.features <- c(continuous.features, + 'Variant Base Quality (BQ)' = 'BQ' + ); + +categorical.features <- c( + 'Chromosome (CHR)' = 'CHROM', + 'GENCODE Variant Type' = 'Gencode_34_variantType', # + 'GENCODE Variant Type' = 'Gencode_34_variantClassification', # + 'HGNC Locus Group' = 'HGNC_Locus_Group', # + 'Repeat Class' = 'REPEAT', ## + 'Trinucleotide Substitution' = 'TRINUCLEOTIDE', ## + 'Trinucleotide Context' = 'TRINUCLEOTIDE_SEQ', ## + 'VQSR Culprit' = 'culprit', # HaplotypeCaller + 'Somatic Genotype (SGT)' = 'SGT' # Strelka2 + ); + +# Extract features and format +continuous.features <- continuous.features[continuous.features %in% names(features.dt)]; +categorical.features <- categorical.features[categorical.features %in% names(features.dt)]; +all.features <- c(continuous.features, categorical.features); + +features.dt <- features.dt[, ..all.features]; +features.dt[, (continuous.features) := lapply(.SD, as.numeric), .SDcols = continuous.features]; +features.dt[, (categorical.features) := lapply(.SD, function(x) ifelse(is.na(x), '', x)), .SDcols = categorical.features]; +features.dt[, (categorical.features) := lapply(.SD, as.factor), .SDcols = categorical.features]; +names(features.dt) <- make.names(names(features.dt)); + +# Remove rows with NA +features.dt.rows <- nrow(features.dt); +features.dt <- features.dt[apply(features.dt, 1, function(x) !any(is.na(x))), ]; +cat('Removed', features.dt.rows - nrow(features.dt), 'rows with missing data\n'); + +################################################################################################### +# Save features.dt for input to RF +################################################################################################### +saveRDS(features.dt, output.path); From 9b0b4e1195926ef1f6543e7f8991ffd71d7e8dea Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 8 Jul 2024 13:43:24 -0700 Subject: [PATCH 13/60] Add workflow to build docker image --- .github/workflows/docker-build-release.yaml | 33 +++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/docker-build-release.yaml diff --git a/.github/workflows/docker-build-release.yaml b/.github/workflows/docker-build-release.yaml new file mode 100644 index 0000000..20bf0b4 --- /dev/null +++ b/.github/workflows/docker-build-release.yaml @@ -0,0 +1,33 @@ +--- +name: Update image in GHCR + +run-name: > + ${{ + github.event_name == 'delete' && format( + 'Delete `{0}{1}`', + github.event.ref_type == 'branch' && 'branch-' || '', + github.event.ref + ) + || github.ref == 'refs/heads/main' && 'Update `dev`' + || format( + 'Update `{0}{1}`', + !startsWith(github.ref, 'refs/tags') && 'branch-' || '', + github.ref_name + ) + }} docker tag + +on: + push: + branches-ignore: ['gh-pages'] + tags: ['v*'] + delete: + +jobs: + push-or-delete-image: + runs-on: ubuntu-latest + name: Update GitHub Container Registry + permissions: + contents: read + packages: write + steps: + - uses: uclahs-cds/tool-Docker-action@nwiltsie-tag-lifecycle From ae88d858200622817a8a1b843d8bbd54a72d621b Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 8 Jul 2024 16:18:42 -0700 Subject: [PATCH 14/60] Add dockerfile to run stablelift scripts --- Dockerfile | 38 ++++++++++++++++++++++++++++++++++++++ metadata.yaml | 1 + 2 files changed, 39 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c664abf --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ +ARG R_VERSION=4.3.1 + +# FROM rocker/tidyverse:${R_VERSION} AS build +FROM rocker/r-ver:${R_VERSION} AS build + +RUN R --quiet --no-save < Date: Mon, 8 Jul 2024 16:31:07 -0700 Subject: [PATCH 15/60] Update package testing version --- config/default.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/default.config b/config/default.config index e85d40c..24e0a87 100644 --- a/config/default.config +++ b/config/default.config @@ -20,7 +20,7 @@ params { gatk_version = '4.2.4.1' pipeval_version = '5.0.0-rc.3' samtools_version = '1.20' - stablelift_version = 'x.x.x' // FIXME + stablelift_version = 'branch-nwiltsie-bootstrap' // FIXME docker_image_bcftools = "${-> params.docker_container_registry}/bcftools:${params.bcftools_version}" docker_image_bedtools = "${-> params.docker_container_registry}/bedtools:${params.bedtools_version}" From 070cfb193f2eec1e97fbe6edd91a54de9ad0b603 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Tue, 9 Jul 2024 09:46:11 -0700 Subject: [PATCH 16/60] Install python3 into the docker image --- Dockerfile | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c664abf..20892c2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,5 @@ ARG R_VERSION=4.3.1 -# FROM rocker/tidyverse:${R_VERSION} AS build FROM rocker/r-ver:${R_VERSION} AS build RUN R --quiet --no-save < Date: Tue, 9 Jul 2024 09:52:44 -0700 Subject: [PATCH 17/60] Fix version pin --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 20892c2..ee928bb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,7 +40,7 @@ COPY --from=build /tmp/userlib /usr/local/lib/R/site-library # let's pin it for stability. RUN apt-get update \ && apt-get install -y --no-install-recommends \ - python3=3.10 \ + python3=3.10.6-1~22.04 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* From 48c02356e0dbf986b9a5ec83f08c27a0b819fe5b Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Tue, 9 Jul 2024 14:11:20 -0700 Subject: [PATCH 18/60] Avoid collisions between input and output files --- module/annotations.nf | 14 ++++++-------- module/funcotator.nf | 5 ++++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/module/annotations.nf b/module/annotations.nf index 50a6dc7..5466d63 100644 --- a/module/annotations.nf +++ b/module/annotations.nf @@ -8,7 +8,7 @@ process run_repeatmasker { saveAs: { "${slug}.vcf.gz" } input: - tuple val(sample_id), path(vcf) + tuple val(sample_id), path(vcf, stageAs: 'inputs/*') path(repeat_bed) output: @@ -44,12 +44,6 @@ process run_trinucleotide_context { enabled: params.save_intermediate_files, saveAs: { "${slug}-full.tsv" } - publishDir path: "${intermediate_filepath}", - pattern: "partial.tsv", - mode: "copy", - enabled: params.save_intermediate_files, - saveAs: { "${slug}-partial.tsv" } - input: tuple val(sample_id), path(vcf) tuple val(dest_fasta_id), path(dest_fasta_ref), path(dest_fasta_fai), path(dest_fasta_dict) @@ -129,7 +123,11 @@ process run_trinucleotide_annotate { saveAs: { "${slug}.vcf.gz" } input: - tuple val(sample_id), path(vcf), path(tsv), path(tsv_tbi) + tuple + val(sample_id), + path(vcf, stageAs: 'inputs/*'), + path(tsv, stageAs: 'inputs/*'), + path(tsv_tbi, stageAs: 'inputs/*') // FIXME Should this process also emit the index file? It seems like // bcftools won't produce it without the --write-index flag diff --git a/module/funcotator.nf b/module/funcotator.nf index a845d6e..16d9341 100644 --- a/module/funcotator.nf +++ b/module/funcotator.nf @@ -18,7 +18,10 @@ process run_funcotator { saveAs: { "${slug}.vcf.gz" } input: - tuple val(sample_id), path(vcf), path(index) + tuple + val(sample_id), + path(vcf, stageAs: 'inputs/*'), + path(index, stageAs: 'inputs/*') tuple val(dest_fasta_id), path(dest_fasta_ref), path(dest_fasta_fai), path(dest_fasta_dict) path (funcotator_sources) From c4480cf04d31f9e07ddb4cb1fb50286c4cb25ed6 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Tue, 9 Jul 2024 15:10:41 -0700 Subject: [PATCH 19/60] Add original predict-liftover-stability.R script --- module/annotations.nf | 3 +- module/funcotator.nf | 3 +- module/scripts/predict-liftover-stability.R | 279 ++++++++++++++++++++ 3 files changed, 281 insertions(+), 4 deletions(-) create mode 100644 module/scripts/predict-liftover-stability.R diff --git a/module/annotations.nf b/module/annotations.nf index 5466d63..5bfea31 100644 --- a/module/annotations.nf +++ b/module/annotations.nf @@ -123,8 +123,7 @@ process run_trinucleotide_annotate { saveAs: { "${slug}.vcf.gz" } input: - tuple - val(sample_id), + tuple val(sample_id), path(vcf, stageAs: 'inputs/*'), path(tsv, stageAs: 'inputs/*'), path(tsv_tbi, stageAs: 'inputs/*') diff --git a/module/funcotator.nf b/module/funcotator.nf index 16d9341..aa9a21d 100644 --- a/module/funcotator.nf +++ b/module/funcotator.nf @@ -18,8 +18,7 @@ process run_funcotator { saveAs: { "${slug}.vcf.gz" } input: - tuple - val(sample_id), + tuple val(sample_id), path(vcf, stageAs: 'inputs/*'), path(index, stageAs: 'inputs/*') tuple val(dest_fasta_id), path(dest_fasta_ref), path(dest_fasta_fai), path(dest_fasta_dict) diff --git a/module/scripts/predict-liftover-stability.R b/module/scripts/predict-liftover-stability.R new file mode 100644 index 0000000..6ce6601 --- /dev/null +++ b/module/scripts/predict-liftover-stability.R @@ -0,0 +1,279 @@ +#!/usr/bin/env Rscript +# predict-liftover-stability.R +#################################################################################################### +# +# Apply random forest model to predict variant LiftOver stability +# Validate results and plot model performance with discordance file +# +#################################################################################################### + +suppressPackageStartupMessages({ + library(caret); + library(ranger); + library(argparse); + library(ROCR); + library(data.table); + library(BoutrosLab.plotting.general); + }); + +################################################################################################### +# Set parameters +################################################################################################### +# Define command line arguments +parser <- ArgumentParser(); +parser$add_argument('--features-dt', type = 'character'); +parser$add_argument('--rf-model', type = 'character'); +parser$add_argument('--variant-caller', type = 'character'); +parser$add_argument('--discordance-file', type = 'character'); +parser$add_argument('--specificity', type = 'numeric', help = 'Target specificity, overrides `--threshold`'); +parser$add_argument('--threshold', type = 'numeric', help = 'Stability score threshold', default = 0.5); +args <- parser$parse_args(); + +# Save command line arguments +for (arg in names(args)) { + assign(gsub('_', '.', arg), args[[arg]]); + } + +# Set parameters for interactive runs +if (interactive()) { + variant.caller <- 'Mutect2'; + # features.dt <- '/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/sSNV/stableLift/validate_TCGA-SARC_WGS_Mutect2/TCGA-SARC_WGS_Mutect2_LiftOver-GRCh38_annotated.Rds'; + # discordance.file <- '/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/sSNV/stableLift/validate_TCGA-SARC_WGS_Mutect2/TCGA-SARC_WGS_Mutect2_bcftools-stats-verbose_PSD.txt'; + features.dt <- '/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/sSNV/stableLift/validate_TCGA-SARC_WXS_Mutect2/TCGA-SARC_WXS_Mutect2_LiftOver-GRCh38_annotated.Rds'; + discordance.file <- '/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/sSNV/stableLift/validate_TCGA-SARC_WXS_Mutect2/TCGA-SARC_WXS_Mutect2_bcftools-stats-verbose_PSD.txt'; + rf.model <- '/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/sSNV/stableLift/train_CPCG-40QC_Mutect2/RF-train_Mutect2_ntree1000_nodesize5_classratio0.Rds'; + specificity = 0.99; + } + +################################################################################################### +# Load data +################################################################################################### +features.dt.path <- features.dt; +features.dt <- readRDS(features.dt.path); +rf.model.path <- rf.model; +rf.model <- readRDS(rf.model); + +#################################################################################################### +# Feature engineering +#################################################################################################### +if (variant.caller == 'HaplotypeCaller') { + normalize.features <- c('FS', 'VQSLOD', 'QD', 'SOR'); + features.dt[, (normalize.features) := lapply(.SD, scale), .SDcols = normalize.features]; + features.dt[, c('QUAL', 'GQ', 'DP') := NULL]; +} else if (variant.caller == 'Mutect2') { + features.dt[, c('TRINUCLEOTIDE') := NULL]; + features.dt <- features.dt[Gencode_34_variantType != 'SNP']; + features.dt[, c('Gencode_34_variantType') := NULL]; +} else if (variant.caller == 'Muse2') { + features.dt[, c('TRINUCLEOTIDE', 'Gencode_34_variantType') := NULL]; +} else if (variant.caller == 'Strelka2') { + features.dt[, c('TRINUCLEOTIDE_SEQ', 'DP', 'Gencode_34_variantType') := NULL]; +} else if (variant.caller == 'Delly2') { + normalize.features <- c('SR', 'SRQ', 'DV'); + features.dt[, (normalize.features) := lapply(.SD, scale), .SDcols = normalize.features]; + } + +dim(features.dt); + +################################################################################################### +# Combine with NRD for validation +################################################################################################### +if (!is.null(discordance.file)) { + if (variant.caller != 'Delly2') { + site.discordance <- fread( + discordance.file, + select = c(2, 3, 4, 5, 6) + ); + + # Format data + names(site.discordance) <- c('CHROM', 'POS', 'n.match', 'n.mismatch', 'NRD'); + site.discordance[, NRD := 1 - (n.match / (n.match + n.mismatch))]; + site.discordance <- unique(site.discordance, by = c('CHROM', 'POS')); + + # Merge with all funcotator variants since bcftools stats only reports PSD for shared variants + features.dt <- merge( + x = features.dt, + y = site.discordance[, c('CHROM', 'POS', 'NRD')], + by = c('CHROM', 'POS'), + all.x = TRUE + ); + + features.dt[is.na(NRD), NRD := 1]; + } else { + site.discordance <- read.vcfR(discordance.file); + site.discordance.info <- vcf.info.to.dt(site.discordance@fix[, 'INFO']); + site.discordance.fix <- as.data.table(site.discordance@fix); + site.discordance <- cbind(site.discordance.fix[, -c('INFO')], site.discordance.info); + + site.discordance[is.na(NON_REF_GENOTYPE_CONCORDANCE), NON_REF_GENOTYPE_CONCORDANCE := 0]; + site.discordance[, NRD := 1 - as.numeric(NON_REF_GENOTYPE_CONCORDANCE)]; + + features.dt <- merge( + x = features.dt, + y = site.discordance[, c('ID', 'NRD')], + by = c('ID'), + all.x = TRUE + ); + features.dt[, ID := NULL]; + } + + # Dichotomize NRD based on threshold + NRD.threshold <- ifelse(variant.caller == 'Delly2', 0.2, 0.1); + features.dt[, NRD := as.factor(as.numeric(NRD > NRD.threshold))]; + } + +################################################################################################### +# Apply random forest model +################################################################################################### +cat('\nPredicting liftover stability with', basename(rf.model.path), '\n'); +stability <- predict(rf.model, data = features.dt); + +if (!is.null(specificity) && is.numeric(specificity)) { + cat('Target specificity =', specificity, '\n'); + operating.index <- max(which(unlist(rf.model$performance@x.values) < 1 - specificity)); + sensitivity <- unlist(rf.model$performance@y.values)[operating.index]; + cat('Projected sensitivity =', round(sensitivity, 3), '\n'); + threshold <- 1 - unlist(rf.model$performance@alpha.values)[operating.index]; + cat('Stability score threshold =', round(threshold, 3), '\n'); +} else { + cat('Target threshold =', threshold, '\n'); + operating.index <- min(which(unlist(rf.model$performance@alpha.values) <= 1 - threshold)); + specificity <- 1 - unlist(rf.model$performance@x.values)[operating.index]; + sensitivity <- unlist(rf.model$performance@y.values)[operating.index]; + cat('Projected specificity =', round(specificity, 3), '\n'); + cat('Projected sensitivity =', round(sensitivity, 3), '\n'); + } + +stability.classification <- ifelse(stability$predictions[, 1] < threshold, 1, 0); +stability.classification <- as.factor(stability.classification); +cat('Proportion predicted unstable =', round(mean(as.numeric(as.character(stability.classification))), 3), '\n'); + +################################################################################################### +# Calculate and plot performance +################################################################################################### +if (!is.null(discordance.file)) { + # Print confusion matrix + print(confusionMatrix(stability.classification, features.dt$NRD, positive = '1')); + + # Calculate prediction performance + stability.prediction <- prediction(stability$predictions[, 2], features.dt$NRD); + stability.performance <- performance(stability.prediction, 'tpr', 'fpr'); + + # Calculate AUC + stability.auc <- performance(stability.prediction, 'auc')@y.values[[1]]; + cat('AUC =', round(stability.auc, 4), '\n'); + + # Plot ROC curve + this.data <- data.table(TPR = unlist(stability.performance@y.values), FPR = unlist(stability.performance@x.values)); + this.filename <- sub('_LiftOver-GRCh38_annotated.Rds', '_stableLift-GRCh38_ROC.png', features.dt.path); + create.scatterplot( + filename = this.filename, + formula = TPR ~ FPR, + data = this.data, + type = 's', + lwd = 3, + xlimits = c(-0.03, 1.03), + ylimits = c(-0.03, 1.03), + add.xyline = TRUE, + xyline.col = 'gray', + xyline.lty = 2, + add.text = TRUE, + text.labels = paste0('AUC = ', format(round(stability.auc, 3), nsmall = 3)), + text.x = 0.63, + text.y = 0.07, + text.cex = 1.7, + height = 4, + width = 4 + ); + + # Plot stability score distribution + this.data <- data.table( + StabilityScore = stability$predictions[, 1], + DiscordanceStatus = factor(ifelse(features.dt$NRD == 1, 'Discordant', 'Concordant'), levels = c('Concordant', 'Discordant')) + ); + this.filename <- sub('_LiftOver-GRCh38_annotated.Rds', '_stableLift-GRCh38_stability-score-histogram.png', features.dt.path); + bins <- seq(0, 1, 0.05); + colors <- c(Concordant = 'darkgreen', Discordant = 'darkred'); + labels <- c( + paste0('bold("Concordant (', round(mean(this.data$DiscordanceStatus == 'Concordant') * 100, 1), '%)")'), + paste0('bold("Discordant (', round(mean(this.data$DiscordanceStatus == 'Discordant') * 100, 1), '%)")') + ); + + this.plot <- list(); + for (group in levels(this.data$DiscordanceStatus)) { + this.axis <- cut(this.data[DiscordanceStatus == group, StabilityScore], breaks = bins, include.lowest = TRUE) |> table(); + this.axis <- auto.axis(this.axis, log.scaled = FALSE); + if (group == 'Concordant') { + this.legend <- list( + inside = list( + fun = draw.key, + args = list( + key = list( + points = list( + pch = 22, + col = 'black', + fill = colors, + cex = 2.2 + ), + text = list( + lab = parse(text = labels), + cex = 1.2 + ), + padding.text = 2.2 + ) + ), + x = 0.02, + y = 0.95 + ) + ); + } else { + this.legend <- NULL; + } + + this.plot[[group]] <- create.histogram( + x = this.data[DiscordanceStatus == group, StabilityScore], + xaxis.lab = if (group == 'Discordant') TRUE else NULL, + xlab.lab = if (group == 'Discordant') 'Stability Score' else NULL, + xlab.cex = 1.5, + ylab.cex = 1.5, + yaxis.cex = 1.5, + xaxis.tck = c(1, 0), + breaks = bins, + yat = this.axis$at, + yaxis.lab = this.axis$axis.lab, + col = colors[group], + type = 'count', + legend = this.legend, + height = 3, + width = 5 + ); + } + + create.multipanelplot( + filename = this.filename, + plot.objects = this.plot, + ylab.label = expression(bold(' Variant Count')), + ylab.cex = 1.7, + ylab.axis.padding = -5.5, + xlab.axis.padding = 0.5, + left.padding = 0.3, + top.padding = -2.1, + bottom.padding = -1.7, + right.padding = -1.5, + y.spacing = -1.5, + height = 5.5, + width = 5 + ); + } + +################################################################################################### +# Output stability scores +################################################################################################### +this.filename <- sub('_LiftOver-GRCh38_annotated.Rds', '_stableLift-GRCh38_stability-scores.tsv', features.dt.path); +annotation.dt <- data.table( + CHROM = features.dt$CHROM, + POS = features.dt$POS, + STABILITY_SCORE = format(round(stability$predictions[, 1], 4), nsmall = 4), + STABILITY = ifelse(stability.classification == '1', 'UNSTABLE', 'STABLE') + ); +fwrite(annotation.dt, file = this.filename, sep = '\t', col.names = TRUE); From 8f7530d8c7715315959412e5e7ae57c2670e1221 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Tue, 9 Jul 2024 15:14:42 -0700 Subject: [PATCH 20/60] Remove logic involving discordance file --- module/scripts/predict-liftover-stability.R | 179 -------------------- 1 file changed, 179 deletions(-) diff --git a/module/scripts/predict-liftover-stability.R b/module/scripts/predict-liftover-stability.R index 6ce6601..be4623d 100644 --- a/module/scripts/predict-liftover-stability.R +++ b/module/scripts/predict-liftover-stability.R @@ -11,9 +11,7 @@ suppressPackageStartupMessages({ library(caret); library(ranger); library(argparse); - library(ROCR); library(data.table); - library(BoutrosLab.plotting.general); }); ################################################################################################### @@ -24,7 +22,6 @@ parser <- ArgumentParser(); parser$add_argument('--features-dt', type = 'character'); parser$add_argument('--rf-model', type = 'character'); parser$add_argument('--variant-caller', type = 'character'); -parser$add_argument('--discordance-file', type = 'character'); parser$add_argument('--specificity', type = 'numeric', help = 'Target specificity, overrides `--threshold`'); parser$add_argument('--threshold', type = 'numeric', help = 'Stability score threshold', default = 0.5); args <- parser$parse_args(); @@ -34,17 +31,6 @@ for (arg in names(args)) { assign(gsub('_', '.', arg), args[[arg]]); } -# Set parameters for interactive runs -if (interactive()) { - variant.caller <- 'Mutect2'; - # features.dt <- '/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/sSNV/stableLift/validate_TCGA-SARC_WGS_Mutect2/TCGA-SARC_WGS_Mutect2_LiftOver-GRCh38_annotated.Rds'; - # discordance.file <- '/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/sSNV/stableLift/validate_TCGA-SARC_WGS_Mutect2/TCGA-SARC_WGS_Mutect2_bcftools-stats-verbose_PSD.txt'; - features.dt <- '/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/sSNV/stableLift/validate_TCGA-SARC_WXS_Mutect2/TCGA-SARC_WXS_Mutect2_LiftOver-GRCh38_annotated.Rds'; - discordance.file <- '/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/sSNV/stableLift/validate_TCGA-SARC_WXS_Mutect2/TCGA-SARC_WXS_Mutect2_bcftools-stats-verbose_PSD.txt'; - rf.model <- '/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/sSNV/stableLift/train_CPCG-40QC_Mutect2/RF-train_Mutect2_ntree1000_nodesize5_classratio0.Rds'; - specificity = 0.99; - } - ################################################################################################### # Load data ################################################################################################### @@ -75,53 +61,6 @@ if (variant.caller == 'HaplotypeCaller') { dim(features.dt); -################################################################################################### -# Combine with NRD for validation -################################################################################################### -if (!is.null(discordance.file)) { - if (variant.caller != 'Delly2') { - site.discordance <- fread( - discordance.file, - select = c(2, 3, 4, 5, 6) - ); - - # Format data - names(site.discordance) <- c('CHROM', 'POS', 'n.match', 'n.mismatch', 'NRD'); - site.discordance[, NRD := 1 - (n.match / (n.match + n.mismatch))]; - site.discordance <- unique(site.discordance, by = c('CHROM', 'POS')); - - # Merge with all funcotator variants since bcftools stats only reports PSD for shared variants - features.dt <- merge( - x = features.dt, - y = site.discordance[, c('CHROM', 'POS', 'NRD')], - by = c('CHROM', 'POS'), - all.x = TRUE - ); - - features.dt[is.na(NRD), NRD := 1]; - } else { - site.discordance <- read.vcfR(discordance.file); - site.discordance.info <- vcf.info.to.dt(site.discordance@fix[, 'INFO']); - site.discordance.fix <- as.data.table(site.discordance@fix); - site.discordance <- cbind(site.discordance.fix[, -c('INFO')], site.discordance.info); - - site.discordance[is.na(NON_REF_GENOTYPE_CONCORDANCE), NON_REF_GENOTYPE_CONCORDANCE := 0]; - site.discordance[, NRD := 1 - as.numeric(NON_REF_GENOTYPE_CONCORDANCE)]; - - features.dt <- merge( - x = features.dt, - y = site.discordance[, c('ID', 'NRD')], - by = c('ID'), - all.x = TRUE - ); - features.dt[, ID := NULL]; - } - - # Dichotomize NRD based on threshold - NRD.threshold <- ifelse(variant.caller == 'Delly2', 0.2, 0.1); - features.dt[, NRD := as.factor(as.numeric(NRD > NRD.threshold))]; - } - ################################################################################################### # Apply random forest model ################################################################################################### @@ -148,124 +87,6 @@ stability.classification <- ifelse(stability$predictions[, 1] < threshold, 1, 0) stability.classification <- as.factor(stability.classification); cat('Proportion predicted unstable =', round(mean(as.numeric(as.character(stability.classification))), 3), '\n'); -################################################################################################### -# Calculate and plot performance -################################################################################################### -if (!is.null(discordance.file)) { - # Print confusion matrix - print(confusionMatrix(stability.classification, features.dt$NRD, positive = '1')); - - # Calculate prediction performance - stability.prediction <- prediction(stability$predictions[, 2], features.dt$NRD); - stability.performance <- performance(stability.prediction, 'tpr', 'fpr'); - - # Calculate AUC - stability.auc <- performance(stability.prediction, 'auc')@y.values[[1]]; - cat('AUC =', round(stability.auc, 4), '\n'); - - # Plot ROC curve - this.data <- data.table(TPR = unlist(stability.performance@y.values), FPR = unlist(stability.performance@x.values)); - this.filename <- sub('_LiftOver-GRCh38_annotated.Rds', '_stableLift-GRCh38_ROC.png', features.dt.path); - create.scatterplot( - filename = this.filename, - formula = TPR ~ FPR, - data = this.data, - type = 's', - lwd = 3, - xlimits = c(-0.03, 1.03), - ylimits = c(-0.03, 1.03), - add.xyline = TRUE, - xyline.col = 'gray', - xyline.lty = 2, - add.text = TRUE, - text.labels = paste0('AUC = ', format(round(stability.auc, 3), nsmall = 3)), - text.x = 0.63, - text.y = 0.07, - text.cex = 1.7, - height = 4, - width = 4 - ); - - # Plot stability score distribution - this.data <- data.table( - StabilityScore = stability$predictions[, 1], - DiscordanceStatus = factor(ifelse(features.dt$NRD == 1, 'Discordant', 'Concordant'), levels = c('Concordant', 'Discordant')) - ); - this.filename <- sub('_LiftOver-GRCh38_annotated.Rds', '_stableLift-GRCh38_stability-score-histogram.png', features.dt.path); - bins <- seq(0, 1, 0.05); - colors <- c(Concordant = 'darkgreen', Discordant = 'darkred'); - labels <- c( - paste0('bold("Concordant (', round(mean(this.data$DiscordanceStatus == 'Concordant') * 100, 1), '%)")'), - paste0('bold("Discordant (', round(mean(this.data$DiscordanceStatus == 'Discordant') * 100, 1), '%)")') - ); - - this.plot <- list(); - for (group in levels(this.data$DiscordanceStatus)) { - this.axis <- cut(this.data[DiscordanceStatus == group, StabilityScore], breaks = bins, include.lowest = TRUE) |> table(); - this.axis <- auto.axis(this.axis, log.scaled = FALSE); - if (group == 'Concordant') { - this.legend <- list( - inside = list( - fun = draw.key, - args = list( - key = list( - points = list( - pch = 22, - col = 'black', - fill = colors, - cex = 2.2 - ), - text = list( - lab = parse(text = labels), - cex = 1.2 - ), - padding.text = 2.2 - ) - ), - x = 0.02, - y = 0.95 - ) - ); - } else { - this.legend <- NULL; - } - - this.plot[[group]] <- create.histogram( - x = this.data[DiscordanceStatus == group, StabilityScore], - xaxis.lab = if (group == 'Discordant') TRUE else NULL, - xlab.lab = if (group == 'Discordant') 'Stability Score' else NULL, - xlab.cex = 1.5, - ylab.cex = 1.5, - yaxis.cex = 1.5, - xaxis.tck = c(1, 0), - breaks = bins, - yat = this.axis$at, - yaxis.lab = this.axis$axis.lab, - col = colors[group], - type = 'count', - legend = this.legend, - height = 3, - width = 5 - ); - } - - create.multipanelplot( - filename = this.filename, - plot.objects = this.plot, - ylab.label = expression(bold(' Variant Count')), - ylab.cex = 1.7, - ylab.axis.padding = -5.5, - xlab.axis.padding = 0.5, - left.padding = 0.3, - top.padding = -2.1, - bottom.padding = -1.7, - right.padding = -1.5, - y.spacing = -1.5, - height = 5.5, - width = 5 - ); - } - ################################################################################################### # Output stability scores ################################################################################################### From 9bfd13227ce157459e0260b00f9bfa6578481a44 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Tue, 9 Jul 2024 16:11:20 -0700 Subject: [PATCH 21/60] Add --output-tsv argument --- module/scripts/predict-liftover-stability.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/scripts/predict-liftover-stability.R b/module/scripts/predict-liftover-stability.R index be4623d..e510fa0 100644 --- a/module/scripts/predict-liftover-stability.R +++ b/module/scripts/predict-liftover-stability.R @@ -24,6 +24,7 @@ parser$add_argument('--rf-model', type = 'character'); parser$add_argument('--variant-caller', type = 'character'); parser$add_argument('--specificity', type = 'numeric', help = 'Target specificity, overrides `--threshold`'); parser$add_argument('--threshold', type = 'numeric', help = 'Stability score threshold', default = 0.5); +parser$add_argument('--output-tsv', type = 'character', help = 'TSV output file'); args <- parser$parse_args(); # Save command line arguments @@ -90,11 +91,10 @@ cat('Proportion predicted unstable =', round(mean(as.numeric(as.character(stabil ################################################################################################### # Output stability scores ################################################################################################### -this.filename <- sub('_LiftOver-GRCh38_annotated.Rds', '_stableLift-GRCh38_stability-scores.tsv', features.dt.path); annotation.dt <- data.table( CHROM = features.dt$CHROM, POS = features.dt$POS, STABILITY_SCORE = format(round(stability$predictions[, 1], 4), nsmall = 4), STABILITY = ifelse(stability.classification == '1', 'UNSTABLE', 'STABLE') ); -fwrite(annotation.dt, file = this.filename, sep = '\t', col.names = TRUE); +fwrite(annotation.dt, file = output.tsv, sep = '\t', col.names = TRUE); From 4c74d550b070593da150baea6373cfc45a8b2220 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Tue, 9 Jul 2024 16:13:39 -0700 Subject: [PATCH 22/60] Add process to predict stability --- module/extract_features.nf | 50 +++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/module/extract_features.nf b/module/extract_features.nf index c0da938..3a02382 100644 --- a/module/extract_features.nf +++ b/module/extract_features.nf @@ -1,12 +1,20 @@ +include { generate_standard_filename } from '../external/pipeline-Nextflow-module/modules/common/generate_standardized_filename/main.nf' + process run_extract_vcf_features { container params.docker_image_stablelift containerOptions "-v ${moduleDir}:${moduleDir}" + publishDir path: "${intermediate_filepath}", + pattern: "features.Rds", + mode: "copy", + enabled: params.save_intermediate_files, + saveAs: { "${slug}.${file(it).getExtension()}" } + input: tuple val(sample_id), path(vcf) output: - tuple val(sample_id), path('output.Rds'), emit: r_annotations + tuple val(sample_id), path('features.Rds'), emit: r_annotations script: intermediate_filepath = "${params.output_dir_base}/stablelift-${params.stablelift_version}/intermediate/${task.process}" @@ -17,7 +25,35 @@ process run_extract_vcf_features { Rscript "${moduleDir}/scripts/extract-vcf-features.R" \ --input-vcf "${vcf}" \ --variant-caller ${params.variant_caller} \ - --output-rds "output.Rds" + --output-rds "features.Rds" + """ +} + +process predict_variant_stability { + container params.docker_image_stablelift + containerOptions "-v ${moduleDir}:${moduleDir}" + + publishDir path: "${params.output_dir_base}/output", + pattern: "${output_file_name}", + mode: "copy" + + input: + tuple val(sample_id), path(features_rds) + path(rf_model) + + output: + tuple val(sample_id), path(output_file_name), emit: stability_tsv + + script: + slug = generate_standard_filename("stablelift", "", sample_id, [:]) + output_file_name = "${slug}.tsv" + + """ + Rscript "${moduleDir}/scripts/predict-liftover-stability.R" \ + --features-dt "${features_rds}" \ + --rf-model "${rf_model}" \ + --variant-caller "${params.variant_caller}" \ + --output-tsv "${output_file_name}" """ } @@ -30,8 +66,14 @@ workflow extract_features { error "HaplotypeCaller is not supported yet" } else { run_extract_vcf_features(vcf_with_sample_id) + run_extract_vcf_features.out.r_annotations.set { ch_annotations } } - emit: - r_annotations = run_extract_vcf_features.out.r_annotations + predict_variant_stability( + ch_annotations, + Channel.value(params.rf_model) + ) + + emit: + r_annotations = predict_variant_stability.out.stability_tsv } From 3ffc99791dfe24fdb407c604f9d8101d7b31c3e3 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Tue, 9 Jul 2024 16:22:11 -0700 Subject: [PATCH 23/60] Don't use generate_standard_filename --- module/extract_features.nf | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/module/extract_features.nf b/module/extract_features.nf index 3a02382..25c97d5 100644 --- a/module/extract_features.nf +++ b/module/extract_features.nf @@ -1,5 +1,3 @@ -include { generate_standard_filename } from '../external/pipeline-Nextflow-module/modules/common/generate_standardized_filename/main.nf' - process run_extract_vcf_features { container params.docker_image_stablelift containerOptions "-v ${moduleDir}:${moduleDir}" @@ -45,8 +43,7 @@ process predict_variant_stability { tuple val(sample_id), path(output_file_name), emit: stability_tsv script: - slug = generate_standard_filename("stablelift", "", sample_id, [:]) - output_file_name = "${slug}.tsv" + output_file_name = "stablelift-${sample_id}.tsv" """ Rscript "${moduleDir}/scripts/predict-liftover-stability.R" \ From 9f9605f72efd608e601959a69a913bde61ca37ff Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Wed, 10 Jul 2024 11:01:07 -0700 Subject: [PATCH 24/60] Switch to using bcftools-score --- config/default.config | 4 ++-- input/liftover.so | Bin 224016 -> 0 bytes main.nf | 9 ++------- module/liftover.nf | 5 +---- 4 files changed, 5 insertions(+), 13 deletions(-) delete mode 100755 input/liftover.so diff --git a/config/default.config b/config/default.config index 24e0a87..542432f 100644 --- a/config/default.config +++ b/config/default.config @@ -15,14 +15,14 @@ params { docker_container_registry = "ghcr.io/uclahs-cds" // Docker images - bcftools_version = '1.20' + bcftools_version = 'branch-nwiltsie-bootstrap' // FIXME bedtools_version = '2.31.0' gatk_version = '4.2.4.1' pipeval_version = '5.0.0-rc.3' samtools_version = '1.20' stablelift_version = 'branch-nwiltsie-bootstrap' // FIXME - docker_image_bcftools = "${-> params.docker_container_registry}/bcftools:${params.bcftools_version}" + docker_image_bcftools = "${-> params.docker_container_registry}/bcftools-score:${params.bcftools_version}" docker_image_bedtools = "${-> params.docker_container_registry}/bedtools:${params.bedtools_version}" docker_image_gatk = "broadinstitute/gatk:${params.gatk_version}" docker_image_pipeval = "${-> params.docker_container_registry}/pipeval:${params.pipeval_version}" diff --git a/input/liftover.so b/input/liftover.so deleted file mode 100755 index 1dbea79518283e137fbb7c407b70fd8f6f7901e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224016 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 z 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 Date: Wed, 10 Jul 2024 13:37:58 -0700 Subject: [PATCH 25/60] Update to released version of docker action --- .github/workflows/docker-build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-build-release.yaml b/.github/workflows/docker-build-release.yaml index 20bf0b4..486d726 100644 --- a/.github/workflows/docker-build-release.yaml +++ b/.github/workflows/docker-build-release.yaml @@ -30,4 +30,4 @@ jobs: contents: read packages: write steps: - - uses: uclahs-cds/tool-Docker-action@nwiltsie-tag-lifecycle + - uses: uclahs-cds/tool-Docker-action@v2.0.0 From cc2cc061c005237962292df1d385ae5654e036e7 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Wed, 10 Jul 2024 13:49:02 -0700 Subject: [PATCH 26/60] Add incomplete NFTest case --- config/F16.config | 0 config/F2.config | 0 config/F32.config | 0 nftest.yml | 13 +++++++++++++ test/nftest.config | 33 +++++++++++++++++++++++++++++++++ test/nftest.yaml | 4 ++++ 6 files changed, 50 insertions(+) create mode 100644 config/F16.config create mode 100644 config/F2.config create mode 100644 config/F32.config create mode 100644 nftest.yml create mode 100644 test/nftest.config create mode 100644 test/nftest.yaml diff --git a/config/F16.config b/config/F16.config new file mode 100644 index 0000000..e69de29 diff --git a/config/F2.config b/config/F2.config new file mode 100644 index 0000000..e69de29 diff --git a/config/F32.config b/config/F32.config new file mode 100644 index 0000000..e69de29 diff --git a/nftest.yml b/nftest.yml new file mode 100644 index 0000000..32644f5 --- /dev/null +++ b/nftest.yml @@ -0,0 +1,13 @@ +--- +global: + temp_dir: test/work + remove_temp: true + clean_logs: true + nf_config: test/nftest.config + +cases: + - name: Example test + nf_script: ./main.nf + params_file: test/nftest.yaml + skip: false + verbose: true diff --git a/test/nftest.config b/test/nftest.config new file mode 100644 index 0000000..5afa955 --- /dev/null +++ b/test/nftest.config @@ -0,0 +1,33 @@ +includeConfig "${projectDir}/config/default.config" +includeConfig "${projectDir}/config/methods.config" +includeConfig "${projectDir}/nextflow.config" + +params { + // Choices: ["Mutect2", "HaplotypeCaller"] + variant_caller = "Mutect2" + save_intermediate_files = true + + ucla_cds = false + + rf_model = "/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/sSNV/stableLift/train_CPCG-40QC_Mutect2/RF-train_Mutect2_ntree100_nodesize5_classratio0.Rds" + + // Reference files + funcotator_data { + data_source = "/hot/ref/tool-specific-input/Funcotator/somatic/funcotator_dataSources.v1.7.20200521s" + src_reference_id = "hg19" + dest_reference_id = "hg38" + } + + // The source reference sequence (FASTA) + src_fasta_ref = "/hot/ref/reference/GRCh37-EBI-hs37d5/hs37d5.fa" + + // The destination reference sequence (FASTA) + dest_fasta_ref = "/hot/ref/reference/GRCh38-BI-20160721/Homo_sapiens_assembly38.fasta" + + chain_file = "/hot/resource/genomics/liftover_chain_files/hg19ToHg38.over.chain" + + repeat_bed = "/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/intervals/GRCh38_RepeatMasker_intervals.bed" +} + +// Setup the pipeline config. DO NOT REMOVE THIS LINE! +methods.setup() diff --git a/test/nftest.yaml b/test/nftest.yaml new file mode 100644 index 0000000..dd3d6f7 --- /dev/null +++ b/test/nftest.yaml @@ -0,0 +1,4 @@ +--- +sample_id: ExampleID +input: + vcf: /hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/validation/TCGA-SARC_WGS/GRCh37/Mutect2/TCGA-SARC_WGS_Mutect2_merge.vcf.gz From c16f5cefdd442a5fcdce1efadbd44df72f7d5618 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Thu, 11 Jul 2024 11:27:24 -0700 Subject: [PATCH 27/60] Update to new rf_model for test --- test/nftest.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/nftest.config b/test/nftest.config index 5afa955..0c86e67 100644 --- a/test/nftest.config +++ b/test/nftest.config @@ -9,7 +9,7 @@ params { ucla_cds = false - rf_model = "/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/sSNV/stableLift/train_CPCG-40QC_Mutect2/RF-train_Mutect2_ntree100_nodesize5_classratio0.Rds" + rf_model = "/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/sSNV/stableLift/train_CPCG-40QC_Mutect2/RF-train_Mutect2_ntree2000_nodesize5_classratio0.Rds" // Reference files funcotator_data { From 315fd913c068022105c52e834dab5b404bbb7a32 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Thu, 11 Jul 2024 11:32:57 -0700 Subject: [PATCH 28/60] Update predict-liftover-stability.R from reference --- module/scripts/predict-liftover-stability.R | 70 ++++++++++++++------- 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/module/scripts/predict-liftover-stability.R b/module/scripts/predict-liftover-stability.R index e510fa0..2a3bded 100644 --- a/module/scripts/predict-liftover-stability.R +++ b/module/scripts/predict-liftover-stability.R @@ -19,9 +19,9 @@ suppressPackageStartupMessages({ ################################################################################################### # Define command line arguments parser <- ArgumentParser(); +parser$add_argument('--variant-caller', type = 'character'); parser$add_argument('--features-dt', type = 'character'); parser$add_argument('--rf-model', type = 'character'); -parser$add_argument('--variant-caller', type = 'character'); parser$add_argument('--specificity', type = 'numeric', help = 'Target specificity, overrides `--threshold`'); parser$add_argument('--threshold', type = 'numeric', help = 'Stability score threshold', default = 0.5); parser$add_argument('--output-tsv', type = 'character', help = 'TSV output file'); @@ -49,18 +49,19 @@ if (variant.caller == 'HaplotypeCaller') { features.dt[, c('QUAL', 'GQ', 'DP') := NULL]; } else if (variant.caller == 'Mutect2') { features.dt[, c('TRINUCLEOTIDE') := NULL]; - features.dt <- features.dt[Gencode_34_variantType != 'SNP']; - features.dt[, c('Gencode_34_variantType') := NULL]; } else if (variant.caller == 'Muse2') { features.dt[, c('TRINUCLEOTIDE', 'Gencode_34_variantType') := NULL]; } else if (variant.caller == 'Strelka2') { features.dt[, c('TRINUCLEOTIDE_SEQ', 'DP', 'Gencode_34_variantType') := NULL]; +} else if (variant.caller == 'SomaticSniper') { + features.dt[, c('DP', 'BQ', 'GQ', 'MQ', 'SSC', 'Gencode_34_variantType', 'TRINUCLEOTIDE', 'TRINUCLEOTIDE_SEQ', 'Gencode_34_variantClassification', 'Gencode_34_gcContent', 'dbSNP_CAF') := NULL]; } else if (variant.caller == 'Delly2') { normalize.features <- c('SR', 'SRQ', 'DV'); features.dt[, (normalize.features) := lapply(.SD, scale), .SDcols = normalize.features]; } -dim(features.dt); +cat('Input data dimensions:\n'); +print(dim(features.dt)); ################################################################################################### # Apply random forest model @@ -68,25 +69,52 @@ dim(features.dt); cat('\nPredicting liftover stability with', basename(rf.model.path), '\n'); stability <- predict(rf.model, data = features.dt); -if (!is.null(specificity) && is.numeric(specificity)) { - cat('Target specificity =', specificity, '\n'); - operating.index <- max(which(unlist(rf.model$performance@x.values) < 1 - specificity)); - sensitivity <- unlist(rf.model$performance@y.values)[operating.index]; - cat('Projected sensitivity =', round(sensitivity, 3), '\n'); - threshold <- 1 - unlist(rf.model$performance@alpha.values)[operating.index]; - cat('Stability score threshold =', round(threshold, 3), '\n'); -} else { - cat('Target threshold =', threshold, '\n'); - operating.index <- min(which(unlist(rf.model$performance@alpha.values) <= 1 - threshold)); - specificity <- 1 - unlist(rf.model$performance@x.values)[operating.index]; - sensitivity <- unlist(rf.model$performance@y.values)[operating.index]; - cat('Projected specificity =', round(specificity, 3), '\n'); - cat('Projected sensitivity =', round(sensitivity, 3), '\n'); - } +# if (!is.null(specificity) && is.numeric(specificity)) { +# cat('Target specificity =', specificity, '\n'); +# operating.index <- max(which(unlist(rf.model$performance@x.values) < 1 - specificity)); +# sensitivity <- unlist(rf.model$performance@y.values)[operating.index]; +# cat('Projected sensitivity =', round(sensitivity, 3), '\n'); +# threshold <- 1 - unlist(rf.model$performance@alpha.values)[operating.index]; +# cat('Stability score threshold =', round(threshold, 3), '\n'); +# } else if (!is.null(threshold) && is.numeric(threshold)) { +# cat('Target threshold =', threshold, '\n'); +# operating.index <- min(which(unlist(rf.model$performance@alpha.values) <= 1 - threshold)); +# specificity <- 1 - unlist(rf.model$performance@x.values)[operating.index]; +# sensitivity <- unlist(rf.model$performance@y.values)[operating.index]; +# cat('Projected specificity =', round(specificity, 3), '\n'); +# cat('Projected sensitivity =', round(sensitivity, 3), '\n'); +# } else { +# performance.acc <- performance(prediction$train, measure = 'f'); #F1-score +# index <- which.max(unlist(performance.acc@y.values)); +# cutoff <- unlist(performance.acc@x.values)[index]; +# metric <- unlist(performance.acc@y.values)[index]; +# specificity <- 1 - unlist(performance$train@x.values)[index]; +# sensitivity <- unlist(performance$train@y.values)[index]; +# cat(sprintf('Projected F[0.5]-score = %.3f\n', metric)); +# cat(sprintf('Projected sensitivity = %.3f\n', sensitivity)); +# cat(sprintf('Projected specificity = %.3f\n', specificity)); +# } + +performance.f <- performance(rf.model$prediction, measure = 'f'); +index <- which.max(unlist(performance.f@y.values)); +threshold <- unlist(performance.f@x.values)[index]; +# f.score <- unlist(performance.f@y.values)[index]; + +performance <- performance(rf.model$prediction, 'sens', 'spec'); + +sensitivity <- unlist(performance@y.values)[index]; +specificity <- unlist(performance@x.values)[index]; + +# cat(sprintf('Max F1-score = %.3f\n', f.score)); +# Convert to stability units +threshold.stability <- 1 - threshold; +cat(sprintf('Threshold = %.3f\n', threshold.stability)); +cat(sprintf('Training sensitivity = %.3f\n', sensitivity)); +cat(sprintf('Training specificity = %.3f\n', specificity)); -stability.classification <- ifelse(stability$predictions[, 1] < threshold, 1, 0); +stability.classification <- ifelse(stability$predictions[, 1] < threshold.stability, 1, 0); +cat(sprintf('Proportion predicted unstable = %.3f\n\n', mean(stability.classification))); stability.classification <- as.factor(stability.classification); -cat('Proportion predicted unstable =', round(mean(as.numeric(as.character(stability.classification))), 3), '\n'); ################################################################################################### # Output stability scores From a451ccf869878d001aaec2829329e4b3a1df4544 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Thu, 11 Jul 2024 11:51:44 -0700 Subject: [PATCH 29/60] Add ROCR into stablelift image --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index ee928bb..855aac2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,7 @@ localdir <- '/tmp/userlib' dir.create(localdir) dependencies <- c( + 'ROCR' = '1.0-11', 'argparse' = '2.2.2', 'caret' = '6.0-94', 'data.table' = '1.14.8', From 1fc7551530c226eaad07090dd4f023d872292797 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Thu, 11 Jul 2024 13:22:46 -0700 Subject: [PATCH 30/60] Add ROCR back into script --- module/scripts/predict-liftover-stability.R | 1 + 1 file changed, 1 insertion(+) diff --git a/module/scripts/predict-liftover-stability.R b/module/scripts/predict-liftover-stability.R index 2a3bded..12892b9 100644 --- a/module/scripts/predict-liftover-stability.R +++ b/module/scripts/predict-liftover-stability.R @@ -11,6 +11,7 @@ suppressPackageStartupMessages({ library(caret); library(ranger); library(argparse); + library(ROCR); library(data.table); }); From a25956b23eafc6b0b2d64c74e5f2fefc183c641e Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Thu, 11 Jul 2024 13:59:32 -0700 Subject: [PATCH 31/60] Rename workflow to match ruleset --- .github/workflows/static-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 608753d..ccfdabb 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -10,7 +10,7 @@ on: - main jobs: - CICD-base: + static-analysis: runs-on: ubuntu-latest steps: From 482f7c79ac6eee5b3dcf1a075592b775b019719d Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Thu, 11 Jul 2024 14:05:42 -0700 Subject: [PATCH 32/60] Dockerlint doesn't like HEREDOCs --- Dockerfile | 30 ++---------------------------- docker/install-stablelift.R | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 28 deletions(-) create mode 100644 docker/install-stablelift.R diff --git a/Dockerfile b/Dockerfile index 855aac2..16c25fd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,34 +2,8 @@ ARG R_VERSION=4.3.1 FROM rocker/r-ver:${R_VERSION} AS build -RUN R --quiet --no-save < Date: Fri, 12 Jul 2024 09:40:57 -0700 Subject: [PATCH 33/60] Compress and index the stability tsv --- module/annotations.nf | 8 +++++--- module/extract_features.nf | 6 ++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/module/annotations.nf b/module/annotations.nf index 5bfea31..bbe8a7f 100644 --- a/module/annotations.nf +++ b/module/annotations.nf @@ -77,7 +77,7 @@ process run_trinucleotide_context { """ } -process run_compress_and_index { +process run_compress_and_index_tsv { container params.docker_image_samtools publishDir path: "${intermediate_filepath}", @@ -166,11 +166,13 @@ workflow apply_annotations { dest_fasta_data ) - run_compress_and_index(run_trinucleotide_context.out.trinucleotide_tsv) + run_compress_and_index_tsv( + run_trinucleotide_context.out.trinucleotide_tsv + ) run_trinucleotide_annotate( run_repeatmasker.out.repeatmasker_vcf.join( - run_compress_and_index.out.compressed_tsv_with_index, + run_compress_and_index_tsv.out.compressed_tsv_with_index, failOnDuplicate: true, failOnMismatch: true ) diff --git a/module/extract_features.nf b/module/extract_features.nf index 25c97d5..6f8eafa 100644 --- a/module/extract_features.nf +++ b/module/extract_features.nf @@ -1,3 +1,5 @@ +include { run_compress_and_index_tsv } from './annotations.nf' + process run_extract_vcf_features { container params.docker_image_stablelift containerOptions "-v ${moduleDir}:${moduleDir}" @@ -71,6 +73,10 @@ workflow extract_features { Channel.value(params.rf_model) ) + run_compress_and_index_tsv( + predict_variant_stability.out.stability_tsv + ) + emit: r_annotations = predict_variant_stability.out.stability_tsv } From a2a7c139bc2743ccf84fa6d6fbab14a72335cc9d Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Fri, 12 Jul 2024 10:18:54 -0700 Subject: [PATCH 34/60] Apply the stability annotations --- module/extract_features.nf | 64 +++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/module/extract_features.nf b/module/extract_features.nf index 6f8eafa..a4e9a9b 100644 --- a/module/extract_features.nf +++ b/module/extract_features.nf @@ -56,6 +56,59 @@ process predict_variant_stability { """ } +process run_apply_stability_annotations { + container params.docker_image_bcftools + + publishDir path: "${params.output_dir_base}/output", + pattern: "*.vcf.*", + mode: "copy" + + input: + tuple val(sample_id), + path(annotated_vcf, stageAs: 'inputs/*'), + // FIXME Should there be an annotated_vcf_tbi? + path(stability_tsv, stageAs: 'inputs/*'), + path(stability_tsv_tbi, stageAs: 'inputs/*') + + output: + tuple val(sample_id), + path(stability_vcf), + path(stability_vcf_tbi), + emit: stability_vcf + tuple val(sample_id), + path(filtered_vcf), + path(filtered_vcf_tbi), + emit: filtered_vcf + + script: + slug = "${sample_id}_LiftOver" + + stability_vcf = "${slug}_stability.vcf.gz" + stability_vcf_tbi = "${annotated_vcf}.tbi" + + filtered_vcf = "${slug}_filtered.vcf.gz" + filtered_vcf_tbi = "${filtered_vcf}.tbi" + + """ + bcftools annotate \ + -a "${stability_tsv}" \ + -c CHROM,POS,STABILITY_SCORE,STABILITY \ + -h <(echo '##INFO= +##INFO=') \ + -o "${stability_vcf}" \ + "${annotated_vcf}" + + bcftools index -t "${stability_vcf}" + + bcftools filter \ + -i 'INFO/STABILITY="STABLE"' \ + -o "${filtered_vcf}" \ + "${stability_vcf}" + + bcftools index -t "${filtered_vcf}" + """ +} + workflow extract_features { take: vcf_with_sample_id @@ -77,6 +130,15 @@ workflow extract_features { predict_variant_stability.out.stability_tsv ) + run_apply_stability_annotations( + vcf_with_sample_id.join( + run_compress_and_index_tsv.out.compressed_tsv_with_index, + failOnDuplicate: true, + failOnMismatch: true + ) + ) + emit: - r_annotations = predict_variant_stability.out.stability_tsv + stability_vcf = run_apply_stability_annotations.out.stability_vcf + filtered_vcf = run_apply_stability_annotations.out.filtered_vcf } From 34e1b428db4ce5fea6ff2bbfa7587d4751872f5e Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Fri, 12 Jul 2024 10:19:04 -0700 Subject: [PATCH 35/60] Whitespace fixes --- module/annotations.nf | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/module/annotations.nf b/module/annotations.nf index bbe8a7f..a53e7eb 100644 --- a/module/annotations.nf +++ b/module/annotations.nf @@ -170,14 +170,14 @@ workflow apply_annotations { run_trinucleotide_context.out.trinucleotide_tsv ) - run_trinucleotide_annotate( - run_repeatmasker.out.repeatmasker_vcf.join( - run_compress_and_index_tsv.out.compressed_tsv_with_index, - failOnDuplicate: true, - failOnMismatch: true - ) - ) - - emit: - annotated_vcf = run_trinucleotide_annotate.out.trinucleotide_vcf + run_trinucleotide_annotate( + run_repeatmasker.out.repeatmasker_vcf.join( + run_compress_and_index_tsv.out.compressed_tsv_with_index, + failOnDuplicate: true, + failOnMismatch: true + ) + ) + + emit: + annotated_vcf = run_trinucleotide_annotate.out.trinucleotide_vcf } From 4fc4fe933180081f63d9b194bd94ca73e00de6d9 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Fri, 12 Jul 2024 15:26:32 -0700 Subject: [PATCH 36/60] Bugfix --- config/default.config | 2 +- module/extract_features.nf | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config/default.config b/config/default.config index 542432f..4848a43 100644 --- a/config/default.config +++ b/config/default.config @@ -15,7 +15,7 @@ params { docker_container_registry = "ghcr.io/uclahs-cds" // Docker images - bcftools_version = 'branch-nwiltsie-bootstrap' // FIXME + bcftools_version = '1.20_score-1.20-20240505' bedtools_version = '2.31.0' gatk_version = '4.2.4.1' pipeval_version = '5.0.0-rc.3' diff --git a/module/extract_features.nf b/module/extract_features.nf index a4e9a9b..514cbe9 100644 --- a/module/extract_features.nf +++ b/module/extract_features.nf @@ -74,17 +74,17 @@ process run_apply_stability_annotations { tuple val(sample_id), path(stability_vcf), path(stability_vcf_tbi), - emit: stability_vcf + emit: stability_vcf_with_index tuple val(sample_id), path(filtered_vcf), path(filtered_vcf_tbi), - emit: filtered_vcf + emit: filtered_vcf_with_index script: slug = "${sample_id}_LiftOver" stability_vcf = "${slug}_stability.vcf.gz" - stability_vcf_tbi = "${annotated_vcf}.tbi" + stability_vcf_tbi = "${stability_vcf}.tbi" filtered_vcf = "${slug}_filtered.vcf.gz" filtered_vcf_tbi = "${filtered_vcf}.tbi" @@ -139,6 +139,6 @@ workflow extract_features { ) emit: - stability_vcf = run_apply_stability_annotations.out.stability_vcf - filtered_vcf = run_apply_stability_annotations.out.filtered_vcf + stability_vcf = run_apply_stability_annotations.out.stability_vcf_with_index + filtered_vcf = run_apply_stability_annotations.out.filtered_vcf_with_index } From f13d505dc302a793cc2ee7921e8b2e4add3d65a8 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:25:21 -0700 Subject: [PATCH 37/60] Make python version a Dockerfile ARG --- Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 16c25fd..007ec77 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,9 +13,11 @@ COPY --from=build /tmp/userlib /usr/local/lib/R/site-library # Install python (required for argparse). The version is not important, but # let's pin it for stability. +ARG PYTHON_VERSION=3.10.6-1~22.04 + RUN apt-get update \ && apt-get install -y --no-install-recommends \ - python3=3.10.6-1~22.04 \ + python3=${PYTHON_VERSION} \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* From a010f1b0b42d4d18179f4ee1d0a783e8d6a24cf1 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:27:17 -0700 Subject: [PATCH 38/60] Point to standard chain_file path --- config/template.config | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/template.config b/config/template.config index da08964..9ffc1ab 100644 --- a/config/template.config +++ b/config/template.config @@ -35,8 +35,9 @@ params { // subdirectory of the funcotator_source directory (e.g. hg19, hg38, b37) dest_fasta_id = "hg38" - // FIXME Are these standard reference files, or should these be templatized as well? - chain_file = "/hot/resource/genomics/liftover_chain_files/hg19ToHg38.over.chain" + chain_file = "/hot/ref/tool-specific-input/liftOver/hg19ToHg38.over.chain" + + // FIXME Update to a stable path under /hot/ref/database repeat_bed = "/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/intervals/GRCh38_RepeatMasker_intervals.bed" } From 9a9b492b1ba56b5ffdf7db57fa2465fffa5d7793 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:28:54 -0700 Subject: [PATCH 39/60] s/raw_liftover/run_liftover_BCFtools --- main.nf | 6 +++--- module/liftover.nf | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/main.nf b/main.nf index 040da72..a3541be 100644 --- a/main.nf +++ b/main.nf @@ -10,7 +10,7 @@ include { run_validate_PipeVal_with_metadata } from './external/pipeline-Nextflo ] ) -include { raw_liftover } from './module/liftover.nf' +include { run_liftover_BCFtools } from './module/liftover.nf' include { run_funcotator } from './module/funcotator.nf' include { apply_annotations } from './module/annotations.nf' include { extract_features} from './module/extract_features.nf' @@ -115,7 +115,7 @@ workflow { .set { validated_vcf_with_index } // The values of validated_vcf_with_index are maps with keys vcf, index, and sample_id. - raw_liftover( + run_liftover_BCFtools( validated_vcf_with_index.map { [it.sample_id, it.vcf, it.index] }, input_ch_src_sequence, input_ch_dest_sequence, @@ -123,7 +123,7 @@ workflow { ) run_funcotator( - raw_liftover.out.liftover_vcf_with_index, + run_liftover_BCFtools.out.liftover_vcf_with_index, input_ch_dest_sequence, Channel.value(params.funcotator_data.data_source) ) diff --git a/module/liftover.nf b/module/liftover.nf index f2ac140..9647ec5 100644 --- a/module/liftover.nf +++ b/module/liftover.nf @@ -8,7 +8,7 @@ // include { generate_standard_filename } from '../external/pipeline-Nextflow-module/modules/common/generate_standardized_filename/main.nf' -process raw_liftover { +process run_liftover_BCFtools { container params.docker_image_bcftools publishDir path: "${intermediate_path}", From 2ba1715ba3fdfefde354cbee0b483eb6c7661b58 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:29:43 -0700 Subject: [PATCH 40/60] s/run_funcotator/run_Funcotator_GATK --- main.nf | 6 +++--- module/funcotator.nf | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/main.nf b/main.nf index a3541be..fbd2501 100644 --- a/main.nf +++ b/main.nf @@ -11,7 +11,7 @@ include { run_validate_PipeVal_with_metadata } from './external/pipeline-Nextflo ) include { run_liftover_BCFtools } from './module/liftover.nf' -include { run_funcotator } from './module/funcotator.nf' +include { run_Funcotator_GATK } from './module/funcotator.nf' include { apply_annotations } from './module/annotations.nf' include { extract_features} from './module/extract_features.nf' @@ -122,14 +122,14 @@ workflow { Channel.value(params.chain_file) ) - run_funcotator( + run_Funcotator_GATK( run_liftover_BCFtools.out.liftover_vcf_with_index, input_ch_dest_sequence, Channel.value(params.funcotator_data.data_source) ) apply_annotations( - run_funcotator.out.funcotator_vcf, + run_Funcotator_GATK.out.funcotator_vcf, input_ch_dest_sequence ) diff --git a/module/funcotator.nf b/module/funcotator.nf index aa9a21d..1917ae0 100644 --- a/module/funcotator.nf +++ b/module/funcotator.nf @@ -8,7 +8,7 @@ include { generate_standard_filename } from '../external/pipeline-Nextflow-module/modules/common/generate_standardized_filename/main.nf' -process run_funcotator { +process run_Funcotator_GATK { container params.docker_image_gatk publishDir path: "${intermediate_filepath}", From 91cb18a17155c6efd108a43b4b213f5e8339e56c Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:30:14 -0700 Subject: [PATCH 41/60] Delete template module --- module/module-name.nf | 60 ------------------------------------------- 1 file changed, 60 deletions(-) delete mode 100644 module/module-name.nf diff --git a/module/module-name.nf b/module/module-name.nf deleted file mode 100644 index 33d2ea4..0000000 --- a/module/module-name.nf +++ /dev/null @@ -1,60 +0,0 @@ -/* -* Module/process description here -* -* @input -* @params -* @output -*/ - -include { generate_standard_filename } from '../external/pipeline-Nextflow-module/modules/common/generate_standardized_filename/main.nf' - -process tool_name_command_name { - container params.docker_image_name - - // if setting resources via label (see base.config), set label here - label "resource_allocation_tool_name_command_name" - - // remove task.index extension if not needed - publishDir path: "${params.workflow_output_dir}/output", - pattern: "", - mode: "copy", - enabled: true - - // Process logs (the `.command.*` files) will be automatically saved as - // `tool_name_command_name/log.command.*` due to - // methods.setup_process_afterscript(). The folder can be customized - // per-process to add a suffix distinguishing multiple runs of the same - // process: - - // ext log_dir_suffix: { "-${variable_name}" } - - // Additional directives here - - input: - tuple val(orig_id), val(id), path(path), val(sample_type) - val(variable_name) - - output: - path("${variable_name}.command_name.file_extension"), emit: output_tag - - script: - output_filename = generate_standard_filename("Samtools-${params.samtools_version}", - params.dataset_id, - id, - [:]) - - """ - # make sure to specify pipefail to make sure process correctly fails on error - set -euo pipefail - - # the script should ideally only have call to a single tool - # to make the command more human readable: - # - seperate components of the call out on different lines - # - when possible be explict with command options, spelling out their long names - tool_name \ - command_name \ - --option_1_long_name ${id} \ - --input ${path} \ - --output ${variable_name}.command_name.file_extension - """ -} From 9c5bec715b28ddca8a01ff5c0c0c05c731f37f00 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:32:14 -0700 Subject: [PATCH 42/60] s/apply_annotations/workflow_apply_annotations --- main.nf | 6 +++--- module/annotations.nf | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/main.nf b/main.nf index fbd2501..75da34b 100644 --- a/main.nf +++ b/main.nf @@ -12,7 +12,7 @@ include { run_validate_PipeVal_with_metadata } from './external/pipeline-Nextflo include { run_liftover_BCFtools } from './module/liftover.nf' include { run_Funcotator_GATK } from './module/funcotator.nf' -include { apply_annotations } from './module/annotations.nf' +include { workflow_apply_annotations } from './module/annotations.nf' include { extract_features} from './module/extract_features.nf' // Log info here @@ -128,12 +128,12 @@ workflow { Channel.value(params.funcotator_data.data_source) ) - apply_annotations( + workflow_apply_annotations( run_Funcotator_GATK.out.funcotator_vcf, input_ch_dest_sequence ) extract_features( - apply_annotations.out.annotated_vcf + workflow_apply_annotations.out.annotated_vcf ) } diff --git a/module/annotations.nf b/module/annotations.nf index a53e7eb..c7a9fcb 100644 --- a/module/annotations.nf +++ b/module/annotations.nf @@ -150,7 +150,7 @@ process run_trinucleotide_annotate { -workflow apply_annotations { +workflow workflow_apply_annotations { take: vcf_with_sample_id dest_fasta_data From ead80c1d46d3981c2f6965abcfd0f3eb060e1310 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:32:31 -0700 Subject: [PATCH 43/60] s/extract_features/workflow_extract_features --- main.nf | 4 ++-- module/extract_features.nf | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/main.nf b/main.nf index 75da34b..241012b 100644 --- a/main.nf +++ b/main.nf @@ -13,7 +13,7 @@ include { run_validate_PipeVal_with_metadata } from './external/pipeline-Nextflo include { run_liftover_BCFtools } from './module/liftover.nf' include { run_Funcotator_GATK } from './module/funcotator.nf' include { workflow_apply_annotations } from './module/annotations.nf' -include { extract_features} from './module/extract_features.nf' +include { workflow_extract_features} from './module/extract_features.nf' // Log info here log.info """\ @@ -133,7 +133,7 @@ workflow { input_ch_dest_sequence ) - extract_features( + workflow_extract_features( workflow_apply_annotations.out.annotated_vcf ) } diff --git a/module/extract_features.nf b/module/extract_features.nf index 514cbe9..2997a57 100644 --- a/module/extract_features.nf +++ b/module/extract_features.nf @@ -109,7 +109,7 @@ process run_apply_stability_annotations { """ } -workflow extract_features { +workflow workflow_extract_features { take: vcf_with_sample_id From 5a510a7fed6e3e61f43c43dae7e57b4544c7d6c2 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:33:24 -0700 Subject: [PATCH 44/60] s/run_repeatmasker/annotate_RepeatMasker_BCFtools --- module/annotations.nf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/module/annotations.nf b/module/annotations.nf index c7a9fcb..a9d91bd 100644 --- a/module/annotations.nf +++ b/module/annotations.nf @@ -1,4 +1,4 @@ -process run_repeatmasker { +process annotate_RepeatMasker_BCFtools { container params.docker_image_bcftools publishDir path: "${intermediate_filepath}", @@ -156,13 +156,13 @@ workflow workflow_apply_annotations { dest_fasta_data main: - run_repeatmasker( + annotate_RepeatMasker_BCFtools( vcf_with_sample_id, Channel.value(params.repeat_bed) ) run_trinucleotide_context( - run_repeatmasker.out.repeatmasker_vcf, + annotate_RepeatMasker_BCFtools.out.repeatmasker_vcf, dest_fasta_data ) @@ -171,7 +171,7 @@ workflow workflow_apply_annotations { ) run_trinucleotide_annotate( - run_repeatmasker.out.repeatmasker_vcf.join( + annotate_RepeatMasker_BCFtools.out.repeatmasker_vcf.join( run_compress_and_index_tsv.out.compressed_tsv_with_index, failOnDuplicate: true, failOnMismatch: true From f160ce0507addce1cacfa250c1419352915b44d8 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:34:54 -0700 Subject: [PATCH 45/60] s/run_trinucleotide_context/extract_TrinucleotideContext_BEDTools --- module/annotations.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/annotations.nf b/module/annotations.nf index a9d91bd..06f37dc 100644 --- a/module/annotations.nf +++ b/module/annotations.nf @@ -29,7 +29,7 @@ process annotate_RepeatMasker_BCFtools { """ } -process run_trinucleotide_context { +process extract_TrinucleotideContext_BEDTools { container params.docker_image_bedtools publishDir path: "${intermediate_filepath}", @@ -161,13 +161,13 @@ workflow workflow_apply_annotations { Channel.value(params.repeat_bed) ) - run_trinucleotide_context( + extract_TrinucleotideContext_BEDTools( annotate_RepeatMasker_BCFtools.out.repeatmasker_vcf, dest_fasta_data ) run_compress_and_index_tsv( - run_trinucleotide_context.out.trinucleotide_tsv + extract_TrinucleotideContext_BEDTools.out.trinucleotide_tsv ) run_trinucleotide_annotate( From edb2a8018efb0a33f82eb4b652530e0cf13bc7f4 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:36:55 -0700 Subject: [PATCH 46/60] s/run_compress_and_index_tsv/compress_and_index_HTSlib --- module/annotations.nf | 6 +++--- module/extract_features.nf | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/module/annotations.nf b/module/annotations.nf index 06f37dc..7ba2ca4 100644 --- a/module/annotations.nf +++ b/module/annotations.nf @@ -77,7 +77,7 @@ process extract_TrinucleotideContext_BEDTools { """ } -process run_compress_and_index_tsv { +process compress_and_index_HTSlib { container params.docker_image_samtools publishDir path: "${intermediate_filepath}", @@ -166,13 +166,13 @@ workflow workflow_apply_annotations { dest_fasta_data ) - run_compress_and_index_tsv( + compress_and_index_HTSlib( extract_TrinucleotideContext_BEDTools.out.trinucleotide_tsv ) run_trinucleotide_annotate( annotate_RepeatMasker_BCFtools.out.repeatmasker_vcf.join( - run_compress_and_index_tsv.out.compressed_tsv_with_index, + compress_and_index_HTSlib.out.compressed_tsv_with_index, failOnDuplicate: true, failOnMismatch: true ) diff --git a/module/extract_features.nf b/module/extract_features.nf index 2997a57..51126b0 100644 --- a/module/extract_features.nf +++ b/module/extract_features.nf @@ -1,4 +1,4 @@ -include { run_compress_and_index_tsv } from './annotations.nf' +include { compress_and_index_HTSlib } from './annotations.nf' process run_extract_vcf_features { container params.docker_image_stablelift @@ -126,13 +126,13 @@ workflow workflow_extract_features { Channel.value(params.rf_model) ) - run_compress_and_index_tsv( + compress_and_index_HTSlib( predict_variant_stability.out.stability_tsv ) run_apply_stability_annotations( vcf_with_sample_id.join( - run_compress_and_index_tsv.out.compressed_tsv_with_index, + compress_and_index_HTSlib.out.compressed_tsv_with_index, failOnDuplicate: true, failOnMismatch: true ) From 1e950efcc13337a53ed09217402d620e45b21c22 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:45:25 -0700 Subject: [PATCH 47/60] Use glob pattern to combined publishDirs --- module/annotations.nf | 7 +------ module/extract_features.nf | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/module/annotations.nf b/module/annotations.nf index 7ba2ca4..9d4234b 100644 --- a/module/annotations.nf +++ b/module/annotations.nf @@ -81,12 +81,7 @@ process compress_and_index_HTSlib { container params.docker_image_samtools publishDir path: "${intermediate_filepath}", - pattern: "output.tsv.gz", - mode: "copy", - enabled: params.save_intermediate_files - - publishDir path: "${intermediate_filepath}", - pattern: "output.tsv.gz.tbi", + pattern: "output.tsv.gz{,.tbi}", mode: "copy", enabled: params.save_intermediate_files diff --git a/module/extract_features.nf b/module/extract_features.nf index 51126b0..bb903b8 100644 --- a/module/extract_features.nf +++ b/module/extract_features.nf @@ -60,7 +60,7 @@ process run_apply_stability_annotations { container params.docker_image_bcftools publishDir path: "${params.output_dir_base}/output", - pattern: "*.vcf.*", + pattern: "*.vcf.gz{,.tbi}", mode: "copy" input: From e3e4267dd40b4b67de5f91b2d2eb63a1b8dbba86 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:52:08 -0700 Subject: [PATCH 48/60] s/run_trinucleotide_annotate/annotate_trinucleotide_BCFtools --- module/annotations.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/annotations.nf b/module/annotations.nf index 9d4234b..abcc1cb 100644 --- a/module/annotations.nf +++ b/module/annotations.nf @@ -108,7 +108,7 @@ process compress_and_index_HTSlib { } -process run_trinucleotide_annotate { +process annotate_trinucleotide_BCFtools { container params.docker_image_bcftools publishDir path: "${intermediate_filepath}", @@ -165,7 +165,7 @@ workflow workflow_apply_annotations { extract_TrinucleotideContext_BEDTools.out.trinucleotide_tsv ) - run_trinucleotide_annotate( + annotate_trinucleotide_BCFtools( annotate_RepeatMasker_BCFtools.out.repeatmasker_vcf.join( compress_and_index_HTSlib.out.compressed_tsv_with_index, failOnDuplicate: true, @@ -174,5 +174,5 @@ workflow workflow_apply_annotations { ) emit: - annotated_vcf = run_trinucleotide_annotate.out.trinucleotide_vcf + annotated_vcf = annotate_trinucleotide_BCFtools.out.trinucleotide_vcf } From 89d8fd4aa4d72a29fe96411981906c10cfbb8d98 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:53:29 -0700 Subject: [PATCH 49/60] Remove FIXME comment - index is not required --- module/annotations.nf | 2 -- 1 file changed, 2 deletions(-) diff --git a/module/annotations.nf b/module/annotations.nf index abcc1cb..0ec0385 100644 --- a/module/annotations.nf +++ b/module/annotations.nf @@ -123,8 +123,6 @@ process annotate_trinucleotide_BCFtools { path(tsv, stageAs: 'inputs/*'), path(tsv_tbi, stageAs: 'inputs/*') - // FIXME Should this process also emit the index file? It seems like - // bcftools won't produce it without the --write-index flag output: tuple val(sample_id), path('output.vcf.gz'), emit: trinucleotide_vcf From 88b7c43223b747d61796281e7254dfb9112b48d1 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:53:48 -0700 Subject: [PATCH 50/60] s/run_extract_vcf_features/extract_VCF_features_StableLift --- module/extract_features.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/extract_features.nf b/module/extract_features.nf index bb903b8..ce08480 100644 --- a/module/extract_features.nf +++ b/module/extract_features.nf @@ -1,6 +1,6 @@ include { compress_and_index_HTSlib } from './annotations.nf' -process run_extract_vcf_features { +process extract_VCF_features_StableLift { container params.docker_image_stablelift containerOptions "-v ${moduleDir}:${moduleDir}" @@ -117,8 +117,8 @@ workflow workflow_extract_features { if (params.variant_caller == "HaplotypeCaller") { error "HaplotypeCaller is not supported yet" } else { - run_extract_vcf_features(vcf_with_sample_id) - run_extract_vcf_features.out.r_annotations.set { ch_annotations } + extract_VCF_features_StableLift(vcf_with_sample_id) + extract_VCF_features_StableLift.out.r_annotations.set { ch_annotations } } predict_variant_stability( From 4c92f2af274c2f58438a41a05f010f753c2c0880 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 11:54:54 -0700 Subject: [PATCH 51/60] s/predict_variant_stability/predict_stability_StableLift --- module/extract_features.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/extract_features.nf b/module/extract_features.nf index ce08480..d5b385f 100644 --- a/module/extract_features.nf +++ b/module/extract_features.nf @@ -29,7 +29,7 @@ process extract_VCF_features_StableLift { """ } -process predict_variant_stability { +process predict_stability_StableLift { container params.docker_image_stablelift containerOptions "-v ${moduleDir}:${moduleDir}" @@ -121,13 +121,13 @@ workflow workflow_extract_features { extract_VCF_features_StableLift.out.r_annotations.set { ch_annotations } } - predict_variant_stability( + predict_stability_StableLift( ch_annotations, Channel.value(params.rf_model) ) compress_and_index_HTSlib( - predict_variant_stability.out.stability_tsv + predict_stability_StableLift.out.stability_tsv ) run_apply_stability_annotations( From 24c1548e704a99933a5f4d6daf202d126f93f309 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 12:14:53 -0700 Subject: [PATCH 52/60] Capitalize BCFtools in output directories --- module/annotations.nf | 4 ++-- module/liftover.nf | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/module/annotations.nf b/module/annotations.nf index 0ec0385..ebbcb50 100644 --- a/module/annotations.nf +++ b/module/annotations.nf @@ -15,7 +15,7 @@ process annotate_RepeatMasker_BCFtools { tuple val(sample_id), path('output.vcf.gz'), emit: repeatmasker_vcf script: - intermediate_filepath = "${params.output_dir_base}/bcftools-${params.bcftools_version}/intermediate/${task.process}" + intermediate_filepath = "${params.output_dir_base}/BCFtools-${params.bcftools_version}/intermediate/${task.process}" slug = "RepeatMasker-${sample_id}" @@ -127,7 +127,7 @@ process annotate_trinucleotide_BCFtools { tuple val(sample_id), path('output.vcf.gz'), emit: trinucleotide_vcf script: - intermediate_filepath = "${params.output_dir_base}/bcftools-${params.bcftools_version}/intermediate/${task.process}" + intermediate_filepath = "${params.output_dir_base}/BCFtools-${params.bcftools_version}/intermediate/${task.process}" slug = "Trinucleotide-${sample_id}" diff --git a/module/liftover.nf b/module/liftover.nf index 9647ec5..5e8f09c 100644 --- a/module/liftover.nf +++ b/module/liftover.nf @@ -40,7 +40,7 @@ process run_liftover_BCFtools { script: // FIXME Use a more standard path - intermediate_path = "${params.output_dir_base}/bcftools-${params.bcftools_version}/intermediate/${task.process}" + intermediate_path = "${params.output_dir_base}/BCFtools-${params.bcftools_version}/intermediate/${task.process}" slug = "LiftOver-${sample_id}-${src_fasta_id}-to-${dest_fasta_id}" From f31761edd22b895987d7690750ba8647cb261acd Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 12:16:12 -0700 Subject: [PATCH 53/60] Capitalize SAMtools in output directories --- module/annotations.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/annotations.nf b/module/annotations.nf index ebbcb50..018cdfb 100644 --- a/module/annotations.nf +++ b/module/annotations.nf @@ -92,7 +92,7 @@ process compress_and_index_HTSlib { tuple val(sample_id), path('output.tsv.gz'), path('output.tsv.gz.tbi'), emit: compressed_tsv_with_index script: - intermediate_filepath = "${params.output_dir_base}/samtools-${params.bcftools_version}/intermediate/${task.process}" + intermediate_filepath = "${params.output_dir_base}/SAMtools-${params.samtools_version}/intermediate/${task.process}" slug = "Trinucleotide-${sample_id}" From 9ef1a69ad34ab948ccadd7aecb0b48715b3710a5 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 12:16:58 -0700 Subject: [PATCH 54/60] Capitalize BEDtools in output directories --- module/annotations.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/annotations.nf b/module/annotations.nf index 018cdfb..2295c79 100644 --- a/module/annotations.nf +++ b/module/annotations.nf @@ -53,7 +53,7 @@ process extract_TrinucleotideContext_BEDTools { tuple val(sample_id), path('output.bed'), emit: trinucleotide_bed script: - intermediate_filepath = "${params.output_dir_base}/bedtools-${params.bedtools_version}/intermediate/${task.process}" + intermediate_filepath = "${params.output_dir_base}/BEDtools-${params.bedtools_version}/intermediate/${task.process}" slug = "Trinucleotide-${sample_id}" From cf0a904d49f6e03cca2ab513cff074baae660b5b Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 14:15:30 -0700 Subject: [PATCH 55/60] Remove defunct parameter, update parameter comments --- config/template.config | 13 +++---- main.nf | 87 +++++++++++++++++++++++++++--------------- 2 files changed, 63 insertions(+), 37 deletions(-) diff --git a/config/template.config b/config/template.config index 9ffc1ab..c146259 100644 --- a/config/template.config +++ b/config/template.config @@ -24,17 +24,16 @@ params { dest_reference_id = "hg38" } - // The source reference sequence (FASTA) + // The source reference sequence (FASTA). Must correspond with + // params.funcotator_data.src_reference_id src_fasta_ref = "/hot/ref/reference/GRCh37-EBI-hs37d5/hs37d5.fa" - // An identifier for the source sequence (e.g. hg19, hg38, b37). Only used to - // construct filenames. - // The destination reference sequence (FASTA) + // The destination reference sequence (FASTA). Must correspond with + // params.funcotator_data.dest_reference_id dest_fasta_ref = "/hot/ref/reference/GRCh38-BI-20160721/Homo_sapiens_assembly38.fasta" - // An identifier for the destination sequence. This must be a valid - // subdirectory of the funcotator_source directory (e.g. hg19, hg38, b37) - dest_fasta_id = "hg38" + // The liftover chain file between the source and destination FASTAS + // references chain_file = "/hot/ref/tool-specific-input/liftOver/hg19ToHg38.over.chain" // FIXME Update to a stable path under /hot/ref/database diff --git a/main.nf b/main.nf index 241012b..1e45a85 100644 --- a/main.nf +++ b/main.nf @@ -17,36 +17,63 @@ include { workflow_extract_features} from './module/extract_features.nf' // Log info here log.info """\ - ====================================== - T E M P L A T E - N F P I P E L I N E - ====================================== - Boutros Lab - - Current Configuration: - - pipeline: - name: ${workflow.manifest.name} - version: ${workflow.manifest.version} - - - input: - input a: ${params.variable_name} - ... - - - output: - output a: ${params.output_path} - ... - - - options: - option a: ${params.option_name} - ... - - Tools Used: - tool a: ${params.docker_image_name} - - ------------------------------------ - Starting workflow... - ------------------------------------ - """ - .stripIndent() + ===================================== + S T A B L E L I F T P I P E L I N E + ===================================== + Boutros Lab + + Current Configuration: + - pipeline: + name: ${workflow.manifest.name} + version: ${workflow.manifest.version} + + - input: + dataset_id: ${params.dataset_id} + variant_caller: ${params.variant_caller} + rf_model: ${params.rf_model} + + src_fasta_ref: ${params.src_fasta_ref} + src_fasta_fai: ${params.src_fasta_fai} + src_fasta_dict: ${params.src_fasta_dict} + + dest_fasta_ref: ${params.dest_fasta_ref} + dest_fasta_fai: ${params.dest_fasta_fai} + dest_fasta_dict: ${params.dest_fasta_dict} + + chain_file: ${params.chain_file} + repeat_bed: ${params.repeat_bed} + + funcotator_data: + data_source: ${params.funcotator_data.data_source} + src_reference_id: ${params.funcotator_data.src_reference_id} + dest_reference_id: ${params.funcotator_data.dest_reference_id} + + - output: + output_dir_base: ${params.output_dir_base} + + - options: + blcds_registered_dataset: ${params.blcds_registered_dataset} + ucla_cds: ${params.ucla_cds} + + min_cpus: ${params.min_cpus} + max_cpus: ${params.max_cpus} + + min_memory: ${params.min_memory} + max_memory: ${params.max_memory} + + Tools Used: + BCFtools: ${params.docker_image_bcftools} + BEDtools: ${params.docker_image_bedtools} + PipeVal: ${params.docker_image_pipeval} + SAMTools: ${params.docker_image_samtools} + StableLift: ${params.docker_image_stablelift} + GATK: ${params.docker_image_gatk} + + ------------------------------------ + Starting workflow... + ------------------------------------ + """ + .stripIndent() def indexFile(bam_or_vcf) { if(bam_or_vcf.endsWith('.bam')) { From ff151c8f2eb3ea90dc9e2b668685fd1ea6c1f484 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Mon, 15 Jul 2024 14:36:32 -0700 Subject: [PATCH 56/60] Update comments and filepaths for chain_file and repeat_bed --- config/template.config | 6 +++--- test/nftest.config | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/config/template.config b/config/template.config index c146259..121e4ee 100644 --- a/config/template.config +++ b/config/template.config @@ -32,12 +32,12 @@ params { // params.funcotator_data.dest_reference_id dest_fasta_ref = "/hot/ref/reference/GRCh38-BI-20160721/Homo_sapiens_assembly38.fasta" - // The liftover chain file between the source and destination FASTAS + // The liftover chain file between the source and destination FASTA // references chain_file = "/hot/ref/tool-specific-input/liftOver/hg19ToHg38.over.chain" - // FIXME Update to a stable path under /hot/ref/database - repeat_bed = "/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/intervals/GRCh38_RepeatMasker_intervals.bed" + // FIXME How to describe this file? + repeat_bed = "/hot/ref/database/RepeatMasker-v3.1.0/processed/GRCh38/GRCh38_RepeatMasker_intervals.bed" } // Setup the pipeline config. DO NOT REMOVE THIS LINE! diff --git a/test/nftest.config b/test/nftest.config index 0c86e67..4fc4c2b 100644 --- a/test/nftest.config +++ b/test/nftest.config @@ -18,15 +18,19 @@ params { dest_reference_id = "hg38" } - // The source reference sequence (FASTA) + // The source reference sequence (FASTA). Must correspond with + // params.funcotator_data.src_reference_id src_fasta_ref = "/hot/ref/reference/GRCh37-EBI-hs37d5/hs37d5.fa" - // The destination reference sequence (FASTA) + // The destination reference sequence (FASTA). Must correspond with + // params.funcotator_data.dest_reference_id dest_fasta_ref = "/hot/ref/reference/GRCh38-BI-20160721/Homo_sapiens_assembly38.fasta" - chain_file = "/hot/resource/genomics/liftover_chain_files/hg19ToHg38.over.chain" + // The liftover chain file between the source and destination FASTA + // references + chain_file = "/hot/ref/tool-specific-input/liftOver/hg19ToHg38.over.chain" - repeat_bed = "/hot/project/method/AlgorithmEvaluation/BNCH-000142-GRCh37v38/intervals/GRCh38_RepeatMasker_intervals.bed" + repeat_bed = "/hot/ref/database/RepeatMasker-v3.1.0/processed/GRCh38/GRCh38_RepeatMasker_intervals.bed" } // Setup the pipeline config. DO NOT REMOVE THIS LINE! From 5d5b371e8f9205430e9562e7347f6f14a5db43ec Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Thu, 11 Jul 2024 14:07:38 -0700 Subject: [PATCH 57/60] Add a USER to the Dockerfile --- Dockerfile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Dockerfile b/Dockerfile index 007ec77..3b95730 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,5 +21,12 @@ RUN apt-get update \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* +# Add a new user/group called bldocker +RUN groupadd -g 500001 bldocker && \ + useradd -l -r -u 500001 -g bldocker bldocker + +# Change the default user to bldocker from root +USER bldocker + LABEL maintainer="Nicholas Wiltsie Date: Tue, 16 Jul 2024 14:33:35 -0700 Subject: [PATCH 58/60] Partially fill-in README --- README.md | 120 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 79 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 50f4efe..6d1ed5c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Pipeline Name +# StableLift - [Pipeline Name](#pipeline-name) - [Overview](#overview) @@ -17,7 +17,9 @@ - [References](#references) - [Discussions](#discussions) - [Contributors](#contributors) - - [License](#license) + - [License](#license) + + ## Overview A 3-4 sentence summary of the pipeline, including the pipeline's purpose, the type of expected scientific inputs/outputs of the pipeline (e.g: FASTQs and BAMs), and a list of tools/steps in the pipeline. @@ -26,11 +28,12 @@ A 3-4 sentence summary of the pipeline, including the pipeline's purpose, the ty ## How To Run -1. Update the params section of the .config file - -2. Update the input yaml +1. Copy [`./config/template.config`](./config/template.config) (e.g. `project.config`) and fill in all required parameters. +2. For each input sample: + 1. Copy [`./input/template.yaml`](./input/template.yaml) (e.g. `sample-002.yaml`) and update with the sample ID and VCF path. + 2. Start the sample-specific pipeline run with `nextflow run -c project.config -params-file sample-002.yaml main.nf` -3. See the submission script, [here](https://github.com/uclahs-cds/tool-submit-nf), to submit your pipeline +If you are using the UCLA Azure cluster, please use the [submission script](https://github.com/uclahs-cds/tool-submit-nf) to submit your pipeline rather than calling `nextflow` directly. --- @@ -46,56 +49,93 @@ A directed acyclic graph of your pipeline. The [PlantUML](https://plantuml.com/) ### 1. Step/Process 1 -> A 2-3 sentence description of each step/proccess in your pipeline that includes the purpose of the step/process, the tool(s) being used and their version, and the expected scientific inputs/outputs (e.g: FASTQs and BAMs) of the pipeline. +> A 2-3 sentence description of each step/process in your pipeline that includes the purpose of the step/process, the tool(s) being used and their version, and the expected scientific inputs/outputs (e.g: FASTQs and BAMs) of the pipeline. ### 2. Step/Process 2 -> A 2-3 sentence description of each step/proccess in your pipeline that includes the purpose of the step/process, the tool(s) being used and their version, and the expected scientific inputs/outputs (e.g: FASTQs and BAMs) of the pipeline. +> A 2-3 sentence description of each step/process in your pipeline that includes the purpose of the step/process, the tool(s) being used and their version, and the expected scientific inputs/outputs (e.g: FASTQs and BAMs) of the pipeline. ### 3. Step/Process n -> A 2-3 sentence description of each step/proccess in your pipeline that includes the purpose of the step/process, the tool(s) being used and their version, and the expected scientific inputs/outputs (e.g: FASTQs and BAMs) of the pipeline. +> A 2-3 sentence description of each step/process in your pipeline that includes the purpose of the step/process, the tool(s) being used and their version, and the expected scientific inputs/outputs (e.g: FASTQs and BAMs) of the pipeline. --- ## Inputs +UCLA pipelines have a hierarchical configuration structure to reduce code repetition: + +* `config/default.config`: Parameters with sensible defaults that may be overridden in `myconfig.config`. +* `config/template.config -> myconfig.config`: Required sample-agnostic parameters. Often shared for many samples. +* `input/template.yaml -> mysample.yaml`: Required sample-specific parameters. + ### Input YAML -> include an example of the organization structure within the YAML. Example: ```yaml -input 1: 'patient_id' +--- +sample_id: "" # Identifying string for the input sample input: - normal: - - id: - BAM: - tumor: - - id: - BAM: + vcf: "" # Path to the sample's VCF file ``` -### Config - -| Field | Type | Required | Description | -| ----- | ---- | ------------ | ------------------------ | -| param 1 | _type_ | yes/no | 1-2 sentence description of the parameter, including any defaults if any. | -| param 2 | _type_ | yes/no | 1-2 sentence description of the parameter, including any defaults if any. | -| param n | _type_ | yes/no | 1-2 sentence description of the parameter, including any defaults if any. | -| `work_dir` | path | no | Path of working directory for Nextflow. When included in the sample config file, Nextflow intermediate files and logs will be saved to this directory. With ucla_cds, the default is `/scratch` and should only be changed for testing/development. Changing this directory to `/hot` or `/tmp` can lead to high server latency and potential disk space limitations, respectively. | - -> Include the optional param `work_dir` in the inputs accompanied by a warning of the potentials dangers of using the param. Update the warning if necessary. +### Input Configuration + +| Required Parameter | Type | Description | +| ----------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------- | +| `output_dir` | path | Absolute path to the directory where the output files are to be saved. | +| `variant_caller` | string | ??? | +| `rf_model` | path | ??? | +| `funcotator_data.data_source` | path | ??? | +| `funcotator_data.src_reference_id` | string | ??? | +| `funcotator_data.dest_reference_id` | string | ??? | +| `src_fasta_ref` | path | Absolute path to the source reference sequence in FASTA format. Must correspond with `functotator_data.src_reference_id`. | +| `dest_fasta_ref` | path | Absolute path to the destination reference sequence in FASTA format. Must correspond with `functotator_data.dest_reference_id`. | +| `chain_file` | path | LiftOver chain file between the source and destination sequences. | +| `repeat_bed` | path | ??? | + + +| Optional Parameter | Type | Default | Description | +| --------------------------- | ----------------------------------------------------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `work_dir` | path | `/scratch/$SLURM_JOB_ID` | Path of working directory for Nextflow. When included in the sample config file, Nextflow intermediate files and logs will be saved to this directory. With `ucla_cds`, the default is `/scratch` and should only be changed for testing/development. Changing this directory to `/hot` or `/tmp` can lead to high server latency and potential disk space limitations, respectively. | +| `save_intermediate_files` | boolean | false | If set, save output files from intermediate pipeline processes. | +| `min_cpus` | int | 1 | Minimum number of CPUs that can be assigned to each process. | +| `max_cpus` | int | `SysHelper.getAvailCpus()` | Maximum number of CPUs that can be assigned to each process. | +| `min_memory` | [MemoryUnit](https://www.nextflow.io/docs/latest/script.html#implicit-classes-memoryunit) | `1.MB` | Minimum amount of memory that can be assigned to each process. | +| `max_memory` | [MemoryUnit](https://www.nextflow.io/docs/latest/script.html#implicit-classes-memoryunit) | `SysHelper.getAvailMemory()` | Maximum amount of memory that can be assigned to each process. | +| `dataset_id` | string | `""` | ??? | +| `blcds_registered_dataset` | boolean | false | Set to true when using BLCDS folder structure; use false for now. | +| `ucla_cds` | boolean | true | If set, overwrite default memory and CPU values by UCLA cluster-specific configs. | +| `src_fasta_fai` | path | Relative to `src_fasta_ref` | Index for source reference sequence. | +| `src_fasta_dict` | path | Relative to `src_fasta_ref` | Dictionary for source reference sequence. | +| `dest_fasta_fai` | path | Relative to `dest_fasta_ref` | Index for destination reference sequence. | +| `dest_fasta_dict` | path | Relative to `src_fasta_ref` | Dictionary for destination reference sequence. | +| `docker_container_registry` | string | `ghcr.io/uclahs-cds` | Container registry for the docker images in the following table. | + +The docker images in the following table are generally defined like `docker_image_pipeval = "${-> params.docker_container_registry}/pipeval:${params.pipeval_version}"`. As such, there are three ways to modify each image: + +* Change `params.docker_container_registry`. This will affect all of the images (except for GATK). +* Change `params._version`. This will pull a different version of the same image from the registry. +* Change `params.docker_image_`. This will explicitly set the image to use, ignoring `docker_container_registry` and `_version`, and thus requires that the docker tag be explicitly set (e.g. `broadinstitute/gatk:4.2.4.1`). + +| Tool Parameter | Version Parameter | Default | Notes | +| ------------------------ | -------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------- | +| `docker_image_bcftools` | `bcftools_version` | `ghcr.io/uclahs-cds/bcftools-score:1.20_score-1.20-20240505` | This image must have both BCFtools and the score plugins available. | +| `docker_image_bedtools` | `bedtools_version` | `ghcr.io/uclahs-cds/bedtools:2.31.0` | | +| `docker_image_gatk` | `gatk_version` | `broadinstitute/gatk:4.2.4.1` | | +| `docker_image_pipeval` | `pipeval_version` | `ghcr.io/uclahs-cds/pipeval:5.0.0-rc.3` | | +| `docker_image_samtools` | `samtools_version` | `ghcr.io/uclahs-cds/samtools:1.20` | | +| `doker_image_stablelift` | `stablelift_version` | `ghcr.io/uclahs-cds/stablelift:FIXME` | This image is built and maintained via this repository. | --- ## Outputs - - | Output | Description | | ------------ | ------------------------ | -| ouput 1 | 1 - 2 sentence description of the output. | -| ouput 2 | 1 - 2 sentence description of the output. | -| ouput n | 1 - 2 sentence description of the output. | +| `*_stability.vcf.gz` | ??? | +| `*_stability.vcf.gz.tbi` | ??? | +| `*_filtered.vcf.gz` | ??? | +| `*_filtered.vcf.gz.tbi` | ??? | --- @@ -107,8 +147,8 @@ A 2-3 sentence description of the test data set(s) used to validate and test thi ### Validation - Input/Output | Description | Result - | ------------ | ------------------------ | ------------------------ | +| Input/Output | Description | Result | +| ------------ | ------------------------ | ------------------------ | | metric 1 | 1 - 2 sentence description of the metric | quantifiable result | | metric 2 | 1 - 2 sentence description of the metric | quantifiable result | | metric n | 1 - 2 sentence description of the metric | quantifiable result | @@ -133,23 +173,21 @@ Included is a template for validating your input files. For more information on ## Discussions -- [Issue tracker]() to report errors and enhancement ideas. -- Discussions can take place in [ Discussions]() -- [ pull requests]() are also open for discussion +- [Issue tracker](https://github.com/uclahs-cds/pipeline-StableLift/issues) to report errors and enhancement ideas. +- Discussions can take place in [pipeline-StableLift Discussions](https://github.com/uclahs-cds/pipeline-StableLift/discussions) +- [pipeline-StableLift pull requests](https://github.com/uclahs-cds/pipeline-StableLift/pulls) are also open for discussion --- ## Contributors -> Update link to repo-specific URL for GitHub Insights Contributors page. - -Please see list of [Contributors](https://github.com/uclahs-cds/template-NextflowPipeline/graphs/contributors) at GitHub. +Please see list of [Contributors](https://github.com/uclahs-cds/pipeline-StableLift/graphs/contributors) at GitHub. --- ## License -[pipeline name] is licensed under the GNU General Public License version 2. See the file LICENSE for the terms of the GNU GPL license. +pipeline-StableLift is licensed under the GNU General Public License version 2. See the file LICENSE for the terms of the GNU GPL license. From 5f351ca9297b64ffead1ab0f3285ac3a67fa3901 Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Tue, 16 Jul 2024 14:33:47 -0700 Subject: [PATCH 59/60] Move 'save_intermediate_files' into default.config --- config/default.config | 2 ++ config/template.config | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config/default.config b/config/default.config index 4848a43..0ee67bd 100644 --- a/config/default.config +++ b/config/default.config @@ -8,6 +8,8 @@ params { min_cpus = 1 min_memory = 1.MB + save_intermediate_files = false + dataset_id = '' blcds_registered_dataset = false diff --git a/config/template.config b/config/template.config index 121e4ee..9fd15cf 100644 --- a/config/template.config +++ b/config/template.config @@ -13,7 +13,6 @@ params { // Choices: ["Mutect2", "HaplotypeCaller"] variant_caller = "Mutect2" - save_intermediate_files = false rf_model = "" From 65934311630d77969de6984f4ce0978b69c01d5f Mon Sep 17 00:00:00 2001 From: Nicholas Wiltsie Date: Fri, 19 Jul 2024 08:57:34 -0700 Subject: [PATCH 60/60] s/3.1.0/3.0.1/ --- config/template.config | 2 +- test/nftest.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/template.config b/config/template.config index 9fd15cf..06c8741 100644 --- a/config/template.config +++ b/config/template.config @@ -36,7 +36,7 @@ params { chain_file = "/hot/ref/tool-specific-input/liftOver/hg19ToHg38.over.chain" // FIXME How to describe this file? - repeat_bed = "/hot/ref/database/RepeatMasker-v3.1.0/processed/GRCh38/GRCh38_RepeatMasker_intervals.bed" + repeat_bed = "/hot/ref/database/RepeatMasker-v3.0.1/processed/GRCh38/GRCh38_RepeatMasker_intervals.bed" } // Setup the pipeline config. DO NOT REMOVE THIS LINE! diff --git a/test/nftest.config b/test/nftest.config index 4fc4c2b..2c9cbff 100644 --- a/test/nftest.config +++ b/test/nftest.config @@ -30,7 +30,7 @@ params { // references chain_file = "/hot/ref/tool-specific-input/liftOver/hg19ToHg38.over.chain" - repeat_bed = "/hot/ref/database/RepeatMasker-v3.1.0/processed/GRCh38/GRCh38_RepeatMasker_intervals.bed" + repeat_bed = "/hot/ref/database/RepeatMasker-v3.0.1/processed/GRCh38/GRCh38_RepeatMasker_intervals.bed" } // Setup the pipeline config. DO NOT REMOVE THIS LINE!