diff --git a/.gitignore b/.gitignore index e5289c5..3621fb1 100644 --- a/.gitignore +++ b/.gitignore @@ -334,3 +334,5 @@ fabric.properties .nf-test/ .nf-test/* .nf-test* + +null/ diff --git a/conf/hpc.config b/conf/hpc.config index 83b92a4..e03d604 100644 --- a/conf/hpc.config +++ b/conf/hpc.config @@ -18,6 +18,8 @@ params { ref_flat = "${params.dx_tracks_path}/rna/${params.gencode_version_name}.ref_annot.gtf.refflat" rrna_intervals = "${params.dx_tracks_path}/rna/GRCh38_rRNA_genbank.interval_list" + // dbSNP + dbsnp = "/hpc/diaggen/data/databases/dbSNP/dbSNP_v156.vcf.gz" // Fusion config starfusion_ref = params.genome_base @@ -66,4 +68,6 @@ params { ] ] + cache_dir = "/hpc/diaggen/data/databases/Nextflow_cache/DxNextflowRNA/" + } diff --git a/conf/modules.config b/conf/modules.config index 28a2906..6088c20 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -70,6 +70,70 @@ process { scratch = true } + withName: GATK4_BEDTOINTERVALLIST { + ext.args = '--DROP_MISSING_CONTIGS TRUE' + storeDir = params.cache_dir ? "${params.cache_dir}/gatk4/bedtointervallist" : null + } + + withName: GATK4_CREATESEQUENCEDICTIONARY { + storeDir = params.cache_dir ? "${params.cache_dir}/gatk4/createsequencedictionary" : null + } + + withName: GATK4_INTERVALLISTTOOLS { + ext.args = { [ + "--SUBDIVISION_MODE BALANCING_WITHOUT_INTERVAL_SUBDIVISION_WITH_OVERFLOW", + "--UNIQUE true", + "--SORT true", + "--SCATTER_COUNT ${params.scatter_size}" + ].join(' ').trim() } + storeDir = params.cache_dir ? "${params.cache_dir}/gatk4/intervallisttools" : null + } + + withName: GATK4_HAPLOTYPECALLER { + cpus = 2 + memory = { 8.GB * task.attempt } + time = { 4.h * task.attempt } + array = params.scatter_size + + ext.args = { [ + "--dont-use-soft-clipped-bases", + "--standard-min-confidence-threshold-for-calling ${params.min_confidence_threshold}", + "--emit-ref-confidence GVCF" + ].join(' ').trim() } + } + + withName: GATK4_SPLITNCIGARREADS { + cpus = 2 + memory = { 16.GB * task.attempt } + time = { 4.h * task.attempt } + array = params.scatter_size + + ext.args = '--create-output-bam-index false' + ext.prefix = { "${meta.id}.splitncigarreads" } + } + + withName: GATK4_VARIANTFILTRATION { + cpus = 1 + memory = { 6.GB * task.attempt } + time = { 2.h * task.attempt } + + ext.prefix = { "${meta.id}.hc.filtered" } + ext.args = { [ + params.gatk_vf_window_size ? "--cluster-window-size ${params.gatk_vf_window_size}" : '', + params.gatk_vf_cluster_size ? "--cluster-size ${params.gatk_vf_cluster_size}" : '', + params.gatk_vf_fs_filter ? "--filter-name \"FS\" --filter-expression \"FS > ${params.gatk_vf_fs_filter}\" " : '', + params.gatk_vf_qd_filter ? "--filter-name \"QD\" --filter-expression \"QD < ${params.gatk_vf_qd_filter}\" " : '', + ].join(' ').trim() } + publishDir = [ + path: { "${params.outdir}/variant_calling/" }, + mode: params.publish_dir_mode + ] + } + + withName: BEDOPS_GTF2BED { + storeDir = params.cache_dir ? "${params.cache_dir}/gtf2bed" : null + } + withName: HGNC_DOWNLOAD { cpus = 1 memory = { 1.GB } @@ -82,10 +146,10 @@ process { time = { 15.m * task.attempt } ext.args = { params.multiqc_title ? "--title \"${params.multiqc_title}\"" : "--title \"${params.analysis_id}\"" } - ext.prefix = { $ { params.analysis_id } } + ext.prefix = { params.analysis_id } publishDir = [ [ - path: "${params.outdir}/QC", + path: { "${params.outdir}/QC" }, mode: params.publish_dir_mode, ] ] @@ -311,7 +375,7 @@ process { path: "${params.outdir}/QC/star_align", mode: params.publish_dir_mode, saveAs: { filename -> - filename.endsWith('.bam') || filename.endsWith(".fastq.gz") : null ? filename + filename.endsWith('.bam') || filename.endsWith(".fastq.gz") ? null : filename } ] ] diff --git a/modules.json b/modules.json index d231cd1..3f89f4b 100644 --- a/modules.json +++ b/modules.json @@ -10,6 +10,17 @@ "git_sha": "025a6f75e1f72e4ab60abb4bd65b3f289d4ad910", "installed_by": ["modules"] }, + "bcftools/index": { + "branch": "master", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "installed_by": ["modules"] + }, + "bedops/gtf2bed": { + "branch": "master", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "installed_by": ["modules"], + "patch": "modules/nf-core/bedops/gtf2bed/bedops-gtf2bed.diff" + }, "fastqc": { "branch": "master", "git_sha": "dc94b6ee04a05ddb9f7ae050712ff30a13149164", @@ -25,6 +36,41 @@ "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, + "gatk4/bedtointervallist": { + "branch": "master", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "installed_by": ["modules"] + }, + "gatk4/createsequencedictionary": { + "branch": "master", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "installed_by": ["modules"] + }, + "gatk4/haplotypecaller": { + "branch": "master", + "git_sha": "b73338eca19d798eb0ef6ed112ef4d27a30d2871", + "installed_by": ["modules"] + }, + "gatk4/intervallisttools": { + "branch": "master", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "installed_by": ["modules"] + }, + "gatk4/mergevcfs": { + "branch": "master", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "installed_by": ["modules"] + }, + "gatk4/splitncigarreads": { + "branch": "master", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "installed_by": ["modules"] + }, + "gatk4/variantfiltration": { + "branch": "master", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "installed_by": ["modules"] + }, "multiqc": { "branch": "master", "git_sha": "cf17ca47590cc578dfb47db1c2a44ef86f89976d", diff --git a/modules/nf-core/bcftools/index/environment.yml b/modules/nf-core/bcftools/index/environment.yml new file mode 100644 index 0000000..01193fd --- /dev/null +++ b/modules/nf-core/bcftools/index/environment.yml @@ -0,0 +1,10 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + # renovate: datasource=conda depName=bioconda/htslib + - bioconda::htslib=1.23.1 + # renovate: datasource=conda depName=bioconda/bcftools + - bioconda::bcftools=1.23.1 diff --git a/modules/nf-core/bcftools/index/main.nf b/modules/nf-core/bcftools/index/main.nf new file mode 100644 index 0000000..757fa7c --- /dev/null +++ b/modules/nf-core/bcftools/index/main.nf @@ -0,0 +1,40 @@ +process BCFTOOLS_INDEX { + tag "${meta.id}" + label 'process_low' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/0b/0b4d52ca9a56d07be3f78a12af654e5116f5112908dba277e6796fd9dfb83fe5/data' + : 'community.wave.seqera.io/library/bcftools_htslib:1.23.1--9f08ec665533d64a'}" + + input: + tuple val(meta), path(vcf) + + output: + tuple val(meta), path("*.csi"), emit: csi, optional: true + tuple val(meta), path("*.tbi"), emit: tbi, optional: true + tuple val("${task.process}"), val('bcftools'), eval("bcftools --version | sed '1!d; s/^.*bcftools //'"), topic: versions, emit: versions_bcftools + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + + """ + bcftools \\ + index \\ + ${args} \\ + --threads ${task.cpus} \\ + ${vcf} + """ + + stub: + def args = task.ext.args ?: '' + def extension = args.contains("--tbi") || args.contains("-t") + ? "tbi" + : "csi" + """ + touch ${vcf}.${extension} + """ +} diff --git a/modules/nf-core/bcftools/index/meta.yml b/modules/nf-core/bcftools/index/meta.yml new file mode 100644 index 0000000..4e4bdc8 --- /dev/null +++ b/modules/nf-core/bcftools/index/meta.yml @@ -0,0 +1,82 @@ +name: bcftools_index +description: Index VCF tools +keywords: + - vcf + - index + - bcftools + - csi + - tbi +tools: + - bcftools: + description: BCFtools is a set of utilities that manipulate variant calls in the + Variant Call Format (VCF) and its binary counterpart BCF. All commands work + transparently with both VCFs and BCFs, both uncompressed and BGZF-compressed. Most + commands accept VCF, bgzipped VCF and BCF with filetype detected automatically + even when streaming from a pipe. Indexed VCF and BCF will work in all situations. + Un-indexed VCF and BCF and streams will work in most, but not all situations. + homepage: https://samtools.github.io/bcftools/ + documentation: https://samtools.github.io/bcftools/howtos/index.html + tool_dev_url: https://github.com/samtools/bcftools + doi: "10.1093/gigascience/giab008" + licence: ["MIT", "GPL-3.0-or-later"] + identifier: biotools:bcftools +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - vcf: + type: file + description: VCF file (optionally GZIPPED) + pattern: "*.{vcf,vcf.gz}" + ontologies: [] +output: + csi: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.csi": + type: file + description: Default VCF file index file + pattern: "*.csi" + ontologies: [] + tbi: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.tbi": + type: file + description: Alternative VCF file index file for larger files (activated with + -t parameter) + pattern: "*.tbi" + ontologies: [] + versions_bcftools: + - - ${task.process}: + type: string + description: The process the versions were collected from + - bcftools: + type: string + description: The tool name + - "bcftools --version | sed '1!d; s/^.*bcftools //'": + type: string + description: The command used to generate the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: The process the versions were collected from + - bcftools: + type: string + description: The tool name + - "bcftools --version | sed '1!d; s/^.*bcftools //'": + type: string + description: The command used to generate the version of the tool +authors: + - "@jfy133" +maintainers: + - "@jfy133" diff --git a/modules/nf-core/bcftools/index/tests/main.nf.test b/modules/nf-core/bcftools/index/tests/main.nf.test new file mode 100644 index 0000000..b38c6ad --- /dev/null +++ b/modules/nf-core/bcftools/index/tests/main.nf.test @@ -0,0 +1,108 @@ +nextflow_process { + + name "Test Process BCFTOOLS_INDEX" + script "../main.nf" + process "BCFTOOLS_INDEX" + + tag "modules" + tag "modules_nfcore" + tag "bcftools" + tag "bcftools/index" + + test("sarscov2 - vcf - csi") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/vcf/test.vcf.gz', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } }, + process.out.findAll { key, val -> key.startsWith("versions") }).match() + } + ) + } + } + + test("sarscov2 - vcf - tbi") { + + config "./nextflow.config" + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/vcf/test.vcf.gz', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.tbi.collect { it.collect { it instanceof Map ? it : file(it).name } }, + process.out.findAll { key, val -> key.startsWith("versions") }).match() + } + ) + } + } + + test("sarscov2 - vcf - csi - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/vcf/test.vcf.gz', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 - vcf - tbi - stub") { + + config "./nextflow.config" + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/vcf/test.vcf.gz', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } +} diff --git a/modules/nf-core/bcftools/index/tests/main.nf.test.snap b/modules/nf-core/bcftools/index/tests/main.nf.test.snap new file mode 100644 index 0000000..cce1c79 --- /dev/null +++ b/modules/nf-core/bcftools/index/tests/main.nf.test.snap @@ -0,0 +1,148 @@ +{ + "sarscov2 - vcf - csi - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.vcf.gz.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + + ], + "2": [ + [ + "BCFTOOLS_INDEX", + "bcftools", + "1.23.1" + ] + ], + "csi": [ + [ + { + "id": "test" + }, + "test.vcf.gz.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "tbi": [ + + ], + "versions_bcftools": [ + [ + "BCFTOOLS_INDEX", + "bcftools", + "1.23.1" + ] + ] + } + ], + "timestamp": "2026-03-20T18:02:30.863066697", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } + }, + "sarscov2 - vcf - tbi": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.vcf.gz.tbi" + ] + ], + { + "versions_bcftools": [ + [ + "BCFTOOLS_INDEX", + "bcftools", + "1.23.1" + ] + ] + } + ], + "timestamp": "2026-03-20T18:02:23.639599735", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } + }, + "sarscov2 - vcf - tbi - stub": { + "content": [ + { + "0": [ + + ], + "1": [ + [ + { + "id": "test" + }, + "test.vcf.gz.tbi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + "BCFTOOLS_INDEX", + "bcftools", + "1.23.1" + ] + ], + "csi": [ + + ], + "tbi": [ + [ + { + "id": "test" + }, + "test.vcf.gz.tbi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_bcftools": [ + [ + "BCFTOOLS_INDEX", + "bcftools", + "1.23.1" + ] + ] + } + ], + "timestamp": "2026-03-20T18:02:38.300964104", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } + }, + "sarscov2 - vcf - csi": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.vcf.gz.csi" + ] + ], + { + "versions_bcftools": [ + [ + "BCFTOOLS_INDEX", + "bcftools", + "1.23.1" + ] + ] + } + ], + "timestamp": "2026-03-20T18:02:16.523585018", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/bcftools/index/tests/nextflow.config b/modules/nf-core/bcftools/index/tests/nextflow.config new file mode 100644 index 0000000..db83f7e --- /dev/null +++ b/modules/nf-core/bcftools/index/tests/nextflow.config @@ -0,0 +1,3 @@ +process { + ext.args = '--tbi' +} diff --git a/modules/nf-core/bedops/gtf2bed/bedops-gtf2bed.diff b/modules/nf-core/bedops/gtf2bed/bedops-gtf2bed.diff new file mode 100644 index 0000000..b086e75 --- /dev/null +++ b/modules/nf-core/bedops/gtf2bed/bedops-gtf2bed.diff @@ -0,0 +1,18 @@ +Changes in component 'nf-core/bedops/gtf2bed' +'modules/nf-core/bedops/gtf2bed/environment.yml' is unchanged +'modules/nf-core/bedops/gtf2bed/meta.yml' is unchanged +Changes in 'bedops/gtf2bed/main.nf': +--- modules/nf-core/bedops/gtf2bed/main.nf ++++ modules/nf-core/bedops/gtf2bed/main.nf +@@ -27,6 +27,7 @@ + | gtf2bed \\ + $args \\ + --attribute-key=exon_id \\ ++ | awk -F'\t' '\$8 == "exon" ' \\ + > ${prefix}.bed + """ + + +'modules/nf-core/bedops/gtf2bed/tests/main.nf.test.snap' is unchanged +'modules/nf-core/bedops/gtf2bed/tests/main.nf.test' is unchanged +************************************************************ diff --git a/modules/nf-core/bedops/gtf2bed/environment.yml b/modules/nf-core/bedops/gtf2bed/environment.yml new file mode 100644 index 0000000..79a9bce --- /dev/null +++ b/modules/nf-core/bedops/gtf2bed/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::bedops=2.4.42 diff --git a/modules/nf-core/bedops/gtf2bed/main.nf b/modules/nf-core/bedops/gtf2bed/main.nf new file mode 100644 index 0000000..07880dd --- /dev/null +++ b/modules/nf-core/bedops/gtf2bed/main.nf @@ -0,0 +1,40 @@ +process BEDOPS_GTF2BED { + tag "$gtf" + label 'process_low' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/bedops:2.4.42--h9948957_0': + 'quay.io/biocontainers/bedops:2.4.42--h9948957_0' }" + + input: + tuple val(meta), path(gtf) + + output: + tuple val(meta), path('*.bed'), emit: bed + tuple val("${task.process}"), val("bedops"), eval('bedops --version | sed -n "s/.*version: *\\([^ ]*\\).*/\\1/p"'), emit: versions_bedops, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${gtf.baseName}" + + """ + cat \\ + $gtf \\ + | gtf2bed \\ + $args \\ + --attribute-key=exon_id \\ + | awk -F'\t' '\$8 == "exon" ' \\ + > ${prefix}.bed + """ + + stub: + def prefix = task.ext.prefix ?: "${gtf.baseName}" + """ + touch ${prefix}.bed + """ + +} diff --git a/modules/nf-core/bedops/gtf2bed/meta.yml b/modules/nf-core/bedops/gtf2bed/meta.yml new file mode 100644 index 0000000..eb9c509 --- /dev/null +++ b/modules/nf-core/bedops/gtf2bed/meta.yml @@ -0,0 +1,64 @@ +name: "bedops_gtf2bed" +description: Convert gtf format to bed format +keywords: + - gtf + - bed + - conversion +tools: + - gtf2bed: + description: The gtf2bed script converts 1-based, closed [start, end] Gene + Transfer Format v2.2 (GTF2.2) to sorted, 0-based, half-open [start-1, end) + extended BED-formatted data. + homepage: https://bedops.readthedocs.io/en/latest/content/reference/file-management/conversion/gtf2bed.html + documentation: https://bedops.readthedocs.io/en/latest/content/reference/file-management/conversion/gtf2bed.html + tool_dev_url: https://github.com/bedops/bedops + doi: 10.1093/bioinformatics/bts277 + licence: + - "GPL v2" + identifier: biotools:bedops +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1', single_end:false ]` + - gtf: + type: file + description: A reference file in GTF format + pattern: "*.{gtf,gtf.gz}" + ontologies: [] +output: + bed: + - - meta: + type: file + description: A reference file in BED format + pattern: "*.{bed}" + ontologies: [] + - "*.bed": + type: file + description: A reference file in BED format + pattern: "*.{bed}" + ontologies: [] + versions_bedops: + - - ${task.process}: + type: string + description: "The name of the process" + - bedops: + type: string + description: The name of the tool + - 'bedops --version | sed -n "s/.*version: *\([^ ]*\).*/\1/p"': + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: "The name of the process" + - bedops: + type: string + description: The name of the tool + - 'bedops --version | sed -n "s/.*version: *\([^ ]*\).*/\1/p"': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@davidecarlson" diff --git a/modules/nf-core/bedops/gtf2bed/tests/main.nf.test b/modules/nf-core/bedops/gtf2bed/tests/main.nf.test new file mode 100644 index 0000000..c6f4ed2 --- /dev/null +++ b/modules/nf-core/bedops/gtf2bed/tests/main.nf.test @@ -0,0 +1,56 @@ +nextflow_process { + + name "Test Process BEDOPS_GTF2BED" + script "../main.nf" + process "BEDOPS_GTF2BED" + + tag "modules" + tag "modules_nfcore" + tag "bedops" + tag "bedops/gtf2bed" + + test("homo sapiens") { + + when { + process { + """ + input[0] = [[ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("homo sapiens - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [[ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/nf-core/bedops/gtf2bed/tests/main.nf.test.snap b/modules/nf-core/bedops/gtf2bed/tests/main.nf.test.snap new file mode 100644 index 0000000..b86b437 --- /dev/null +++ b/modules/nf-core/bedops/gtf2bed/tests/main.nf.test.snap @@ -0,0 +1,84 @@ +{ + "homo sapiens": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "genome.bed:md5,783257789b0c59a1a5391f7f2b9ac08a" + ] + ], + "1": [ + [ + "BEDOPS_GTF2BED", + "bedops", + "2.4.42" + ] + ], + "bed": [ + [ + { + "id": "test" + }, + "genome.bed:md5,783257789b0c59a1a5391f7f2b9ac08a" + ] + ], + "versions_bedops": [ + [ + "BEDOPS_GTF2BED", + "bedops", + "2.4.42" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.04.3" + }, + "timestamp": "2026-02-17T10:50:08.652816984" + }, + "homo sapiens - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "genome.bed:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + "BEDOPS_GTF2BED", + "bedops", + "2.4.42" + ] + ], + "bed": [ + [ + { + "id": "test" + }, + "genome.bed:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_bedops": [ + [ + "BEDOPS_GTF2BED", + "bedops", + "2.4.42" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.04.3" + }, + "timestamp": "2026-02-17T10:50:16.813347554" + } +} \ No newline at end of file diff --git a/modules/nf-core/gatk4/bedtointervallist/environment.yml b/modules/nf-core/gatk4/bedtointervallist/environment.yml new file mode 100644 index 0000000..67e0eb8 --- /dev/null +++ b/modules/nf-core/gatk4/bedtointervallist/environment.yml @@ -0,0 +1,10 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + # renovate: datasource=conda depName=bioconda/gatk4 + - bioconda::gatk4=4.6.2.0 + # renovate: datasource=conda depName=bioconda/gcnvkernel + - bioconda::gcnvkernel=0.9 diff --git a/modules/nf-core/gatk4/bedtointervallist/main.nf b/modules/nf-core/gatk4/bedtointervallist/main.nf new file mode 100644 index 0000000..8a86bf7 --- /dev/null +++ b/modules/nf-core/gatk4/bedtointervallist/main.nf @@ -0,0 +1,47 @@ +process GATK4_BEDTOINTERVALLIST { + tag "${meta.id}" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/ce/ced519873646379e287bc28738bdf88e975edd39a92e7bc6a34bccd37153d9d0/data' + : 'community.wave.seqera.io/library/gatk4_gcnvkernel:edb12e4f0bf02cd3'}" + + input: + tuple val(meta), path(bed) + tuple val(meta2), path(dict) + + output: + tuple val(meta), path('*.interval_list'), emit: interval_list + tuple val("${task.process}"), val('gatk4'), eval("gatk --version | sed -n '/GATK.*v/s/.*v//p'"), topic: versions, emit: versions_gatk4 + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + def avail_mem = 3072 + if (!task.memory) { + log.info('[GATK BedToIntervalList] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.') + } + else { + avail_mem = (task.memory.mega * 0.8).intValue() + } + """ + gatk --java-options "-Xmx${avail_mem}M -XX:-UsePerfData" \\ + BedToIntervalList \\ + --INPUT ${bed} \\ + --OUTPUT ${prefix}.interval_list \\ + --SEQUENCE_DICTIONARY ${dict} \\ + --TMP_DIR . \\ + ${args} + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.interval_list + """ +} diff --git a/modules/nf-core/gatk4/bedtointervallist/meta.yml b/modules/nf-core/gatk4/bedtointervallist/meta.yml new file mode 100644 index 0000000..a3e2f23 --- /dev/null +++ b/modules/nf-core/gatk4/bedtointervallist/meta.yml @@ -0,0 +1,78 @@ +name: gatk4_bedtointervallist +description: Creates an interval list from a bed file and a reference dict +keywords: + - bed + - bedtointervallist + - gatk4 + - interval list +tools: + - gatk4: + description: | + Developed in the Data Sciences Platform at the Broad Institute, the toolkit offers a wide variety of tools + with a primary focus on variant discovery and genotyping. Its powerful processing engine + and high-performance computing features make it capable of taking on projects of any size. + homepage: https://gatk.broadinstitute.org/hc/en-us + documentation: https://gatk.broadinstitute.org/hc/en-us/categories/360002369672s + doi: 10.1158/1538-7445.AM2017-3590 + licence: ["Apache-2.0"] + identifier: "" +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test'] + - bed: + type: file + description: Input bed file + pattern: "*.bed" + ontologies: [] + - - meta2: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'genome' ] + - dict: + type: file + description: Sequence dictionary + pattern: "*.dict" + ontologies: [] +output: + interval_list: + - - meta: + type: file + description: gatk interval list file + pattern: "*.interval_list" + ontologies: [] + - "*.interval_list": + type: file + description: gatk interval list file + pattern: "*.interval_list" + ontologies: [] + versions_gatk4: + - - ${task.process}: + type: string + description: The name of the process + - gatk4: + type: string + description: The name of the tool + - gatk --version | sed -n '/GATK.*v/s/.*v//p': + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - gatk4: + type: string + description: The name of the tool + - gatk --version | sed -n '/GATK.*v/s/.*v//p': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@kevinmenden" + - "@ramprasadn" +maintainers: + - "@kevinmenden" + - "@ramprasadn" diff --git a/modules/nf-core/gatk4/bedtointervallist/tests/main.nf.test b/modules/nf-core/gatk4/bedtointervallist/tests/main.nf.test new file mode 100644 index 0000000..8d318e9 --- /dev/null +++ b/modules/nf-core/gatk4/bedtointervallist/tests/main.nf.test @@ -0,0 +1,61 @@ +nextflow_process { + + name "Test Process GATK4_BEDTOINTERVALLIST" + script "../main.nf" + process "GATK4_BEDTOINTERVALLIST" + + tag "modules" + tag "modules_nfcore" + tag "gatk4" + tag "gatk4/bedtointervallist" + + test("test_gatk4_bedtointervallist") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + [file(params.modules_testdata_base_path + + 'genomics/sarscov2/genome/bed/test.bed', checkIfExists: true) ] + ] + input[1] = [ [ id:'dict' ], // meta map + [file(params.modules_testdata_base_path + + 'genomics/sarscov2/genome/genome.dict', checkIfExists: true) ] + ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot(process.out).match() } + ) + } + } + + test("test_gatk4_bedtointervallist - stub") { + options "-stub" + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + [file(params.modules_testdata_base_path + + 'genomics/sarscov2/genome/bed/test.bed', checkIfExists: true) ] + ] + input[1] = [ [ id:'dict' ], // meta map + [file(params.modules_testdata_base_path + + 'genomics/sarscov2/genome/genome.dict', checkIfExists: true) ] + ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot(process.out).match() } + ) + } + } +} diff --git a/modules/nf-core/gatk4/bedtointervallist/tests/main.nf.test.snap b/modules/nf-core/gatk4/bedtointervallist/tests/main.nf.test.snap new file mode 100644 index 0000000..5544250 --- /dev/null +++ b/modules/nf-core/gatk4/bedtointervallist/tests/main.nf.test.snap @@ -0,0 +1,84 @@ +{ + "test_gatk4_bedtointervallist - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.interval_list:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + "GATK4_BEDTOINTERVALLIST", + "gatk4", + "4.6.2.0" + ] + ], + "interval_list": [ + [ + { + "id": "test" + }, + "test.interval_list:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_gatk4": [ + [ + "GATK4_BEDTOINTERVALLIST", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-01-22T09:52:55.698969373" + }, + "test_gatk4_bedtointervallist": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.interval_list:md5,e51101c9357fb2d59fd30e370eefa39c" + ] + ], + "1": [ + [ + "GATK4_BEDTOINTERVALLIST", + "gatk4", + "4.6.2.0" + ] + ], + "interval_list": [ + [ + { + "id": "test" + }, + "test.interval_list:md5,e51101c9357fb2d59fd30e370eefa39c" + ] + ], + "versions_gatk4": [ + [ + "GATK4_BEDTOINTERVALLIST", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-01-22T09:52:46.629308651" + } +} \ No newline at end of file diff --git a/modules/nf-core/gatk4/createsequencedictionary/environment.yml b/modules/nf-core/gatk4/createsequencedictionary/environment.yml new file mode 100644 index 0000000..67e0eb8 --- /dev/null +++ b/modules/nf-core/gatk4/createsequencedictionary/environment.yml @@ -0,0 +1,10 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + # renovate: datasource=conda depName=bioconda/gatk4 + - bioconda::gatk4=4.6.2.0 + # renovate: datasource=conda depName=bioconda/gcnvkernel + - bioconda::gcnvkernel=0.9 diff --git a/modules/nf-core/gatk4/createsequencedictionary/main.nf b/modules/nf-core/gatk4/createsequencedictionary/main.nf new file mode 100644 index 0000000..98ad30c --- /dev/null +++ b/modules/nf-core/gatk4/createsequencedictionary/main.nf @@ -0,0 +1,43 @@ +process GATK4_CREATESEQUENCEDICTIONARY { + tag "${fasta}" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/ce/ced519873646379e287bc28738bdf88e975edd39a92e7bc6a34bccd37153d9d0/data' + : 'community.wave.seqera.io/library/gatk4_gcnvkernel:edb12e4f0bf02cd3'}" + + input: + tuple val(meta), path(fasta) + + output: + tuple val(meta), path('*.dict'), emit: dict + tuple val("${task.process}"), val('gatk4'), eval("gatk --version | sed -n '/GATK.*v/s/.*v//p'"), topic: versions, emit: versions_gatk4 + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + + def avail_mem = 6144 + if (!task.memory) { + log.info('[GATK CreateSequenceDictionary] Available memory not known - defaulting to 6GB. Specify process memory requirements to change this.') + } + else { + avail_mem = (task.memory.mega * 0.8).intValue() + } + """ + gatk --java-options "-Xmx${avail_mem}M -XX:-UsePerfData" \\ + CreateSequenceDictionary \\ + --REFERENCE ${fasta} \\ + --URI ${fasta} \\ + --TMP_DIR . \\ + ${args} + """ + + stub: + """ + touch ${fasta.baseName}.dict + """ +} diff --git a/modules/nf-core/gatk4/createsequencedictionary/meta.yml b/modules/nf-core/gatk4/createsequencedictionary/meta.yml new file mode 100644 index 0000000..5fdfcc2 --- /dev/null +++ b/modules/nf-core/gatk4/createsequencedictionary/meta.yml @@ -0,0 +1,68 @@ +name: gatk4_createsequencedictionary +description: Creates a sequence dictionary for a reference sequence +keywords: + - createsequencedictionary + - dictionary + - fasta + - gatk4 +tools: + - gatk: + description: | + Developed in the Data Sciences Platform at the Broad Institute, the toolkit offers a wide variety of tools + with a primary focus on variant discovery and genotyping. Its powerful processing engine + and high-performance computing features make it capable of taking on projects of any size. + homepage: https://gatk.broadinstitute.org/hc/en-us + documentation: https://gatk.broadinstitute.org/hc/en-us/categories/360002369672s + doi: 10.1158/1538-7445.AM2017-3590 + licence: ["Apache-2.0"] + identifier: "" +input: + - - meta: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'genome' ] + - fasta: + type: file + description: Input fasta file + pattern: "*.{fasta,fa}" + ontologies: [] +output: + dict: + - - meta: + type: file + description: gatk dictionary file + pattern: "*.{dict}" + ontologies: [] + - "*.dict": + type: file + description: gatk dictionary file + pattern: "*.{dict}" + ontologies: [] + versions_gatk4: + - - ${task.process}: + type: string + description: The name of the process + - gatk4: + type: string + description: The name of the tool + - gatk --version | sed -n '/GATK.*v/s/.*v//p': + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - gatk4: + type: string + description: The name of the tool + - gatk --version | sed -n '/GATK.*v/s/.*v//p': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@maxulysse" + - "@ramprasadn" +maintainers: + - "@maxulysse" + - "@ramprasadn" diff --git a/modules/nf-core/gatk4/createsequencedictionary/tests/main.nf.test b/modules/nf-core/gatk4/createsequencedictionary/tests/main.nf.test new file mode 100644 index 0000000..076eb0d --- /dev/null +++ b/modules/nf-core/gatk4/createsequencedictionary/tests/main.nf.test @@ -0,0 +1,53 @@ +nextflow_process { + + name "Test Process GATK4_CREATESEQUENCEDICTIONARY" + script "../main.nf" + process "GATK4_CREATESEQUENCEDICTIONARY" + + tag "modules" + tag "modules_nfcore" + tag "gatk4" + tag "gatk4/createsequencedictionary" + + test("sarscov2 - fasta") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 - fasta - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot(process.out).match() } + ) + } + } +} diff --git a/modules/nf-core/gatk4/createsequencedictionary/tests/main.nf.test.snap b/modules/nf-core/gatk4/createsequencedictionary/tests/main.nf.test.snap new file mode 100644 index 0000000..357cd58 --- /dev/null +++ b/modules/nf-core/gatk4/createsequencedictionary/tests/main.nf.test.snap @@ -0,0 +1,84 @@ +{ + "sarscov2 - fasta - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "genome.dict:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + "GATK4_CREATESEQUENCEDICTIONARY", + "gatk4", + "4.6.2.0" + ] + ], + "dict": [ + [ + { + "id": "test" + }, + "genome.dict:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_gatk4": [ + [ + "GATK4_CREATESEQUENCEDICTIONARY", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-01-21T16:01:50.146061464" + }, + "sarscov2 - fasta": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "genome.dict:md5,7362679f176e0f52add03c08f457f646" + ] + ], + "1": [ + [ + "GATK4_CREATESEQUENCEDICTIONARY", + "gatk4", + "4.6.2.0" + ] + ], + "dict": [ + [ + { + "id": "test" + }, + "genome.dict:md5,7362679f176e0f52add03c08f457f646" + ] + ], + "versions_gatk4": [ + [ + "GATK4_CREATESEQUENCEDICTIONARY", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-01-21T16:01:38.694508582" + } +} \ No newline at end of file diff --git a/modules/nf-core/gatk4/haplotypecaller/environment.yml b/modules/nf-core/gatk4/haplotypecaller/environment.yml new file mode 100644 index 0000000..67e0eb8 --- /dev/null +++ b/modules/nf-core/gatk4/haplotypecaller/environment.yml @@ -0,0 +1,10 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + # renovate: datasource=conda depName=bioconda/gatk4 + - bioconda::gatk4=4.6.2.0 + # renovate: datasource=conda depName=bioconda/gcnvkernel + - bioconda::gcnvkernel=0.9 diff --git a/modules/nf-core/gatk4/haplotypecaller/main.nf b/modules/nf-core/gatk4/haplotypecaller/main.nf new file mode 100644 index 0000000..ff69f6c --- /dev/null +++ b/modules/nf-core/gatk4/haplotypecaller/main.nf @@ -0,0 +1,68 @@ +process GATK4_HAPLOTYPECALLER { + tag "${meta.id}" + label 'process_low' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/ce/ced519873646379e287bc28738bdf88e975edd39a92e7bc6a34bccd37153d9d0/data' + : 'community.wave.seqera.io/library/gatk4_gcnvkernel:edb12e4f0bf02cd3'}" + + input: + tuple val(meta), path(input), path(input_index), path(intervals), path(dragstr_model) + tuple val(meta2), path(fasta) + tuple val(meta3), path(fai) + tuple val(meta4), path(dict) + tuple val(meta5), path(dbsnp) + tuple val(meta6), path(dbsnp_tbi) + + output: + tuple val(meta), path("*.vcf.gz"), emit: vcf + tuple val(meta), path("*.tbi"), emit: tbi, optional: true + tuple val(meta), path("*.realigned.bam"), emit: bam, optional: true + tuple val("${task.process}"), val('gatk4'), eval("gatk --version | sed -n '/GATK.*v/s/.*v//p'"), topic: versions, emit: versions_gatk4 + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def dbsnp_command = dbsnp ? "--dbsnp ${dbsnp}" : "" + def interval_command = intervals ? "--intervals ${intervals}" : "" + def dragstr_command = dragstr_model ? "--dragstr-params-path ${dragstr_model}" : "" + def bamout_command = args.contains("--bam-writer-type") ? "--bam-output ${prefix.replaceAll('.g\\s*$', '')}.realigned.bam" : "" + + def avail_mem = 3072 + if (!task.memory) { + log.info('[GATK HaplotypeCaller] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.') + } + else { + avail_mem = (task.memory.mega * 0.8).intValue() + } + """ + gatk --java-options "-Xmx${avail_mem}M -XX:-UsePerfData" \\ + HaplotypeCaller \\ + --input ${input} \\ + --output ${prefix}.vcf.gz \\ + --reference ${fasta} \\ + --native-pair-hmm-threads ${task.cpus} \\ + ${dbsnp_command} \\ + ${interval_command} \\ + ${dragstr_command} \\ + ${bamout_command} \\ + --tmp-dir . \\ + ${args} + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def bamout_command = args.contains("--bam-writer-type") ? "--bam-output ${prefix.replaceAll('.g\\s*$', '')}.realigned.bam" : "" + + def stub_realigned_bam = bamout_command ? "touch ${prefix.replaceAll('.g\\s*$', '')}.realigned.bam" : "" + """ + echo | gzip > ${prefix}.vcf.gz + touch ${prefix}.vcf.gz.tbi + ${stub_realigned_bam} + """ +} diff --git a/modules/nf-core/gatk4/haplotypecaller/meta.yml b/modules/nf-core/gatk4/haplotypecaller/meta.yml new file mode 100644 index 0000000..29a29ba --- /dev/null +++ b/modules/nf-core/gatk4/haplotypecaller/meta.yml @@ -0,0 +1,153 @@ +name: gatk4_haplotypecaller +description: Call germline SNPs and indels via local re-assembly of haplotypes +keywords: + - gatk4 + - haplotype + - haplotypecaller +tools: + - gatk4: + description: | + Developed in the Data Sciences Platform at the Broad Institute, the toolkit offers a wide variety of tools + with a primary focus on variant discovery and genotyping. Its powerful processing engine + and high-performance computing features make it capable of taking on projects of any size. + homepage: https://gatk.broadinstitute.org/hc/en-us + documentation: https://gatk.broadinstitute.org/hc/en-us/categories/360002369672s + doi: 10.1158/1538-7445.AM2017-3590 + licence: ["Apache-2.0"] + identifier: "" +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - input: + type: file + description: BAM/CRAM file from alignment + pattern: "*.{bam,cram}" + ontologies: [] + - input_index: + type: file + description: BAI/CRAI file from alignment + pattern: "*.{bai,crai}" + ontologies: [] + - intervals: + type: file + description: Bed file with the genomic regions included in the library (optional) + ontologies: [] + - dragstr_model: + type: file + description: Text file containing the DragSTR model of the used BAM/CRAM file + (optional) + pattern: "*.txt" + ontologies: [] + - - meta2: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'test_reference' ] + - fasta: + type: file + description: The reference fasta file + pattern: "*.fasta" + ontologies: [] + - - meta3: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'test_reference' ] + - fai: + type: file + description: Index of reference fasta file + pattern: "fasta.fai" + ontologies: [] + - - meta4: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'test_reference' ] + - dict: + type: file + description: GATK sequence dictionary + pattern: "*.dict" + ontologies: [] + - - meta5: + type: map + description: | + Groovy Map containing dbsnp information + e.g. [ id:'test_dbsnp' ] + - dbsnp: + type: file + description: VCF file containing known sites (optional) + ontologies: [] + - - meta6: + type: map + description: | + Groovy Map containing dbsnp information + e.g. [ id:'test_dbsnp' ] + - dbsnp_tbi: + type: file + description: VCF index of dbsnp (optional) + ontologies: [] +output: + vcf: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.vcf.gz": + type: file + description: Compressed VCF file + pattern: "*.vcf.gz" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + tbi: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.tbi": + type: file + description: Index of VCF file + pattern: "*.vcf.gz.tbi" + ontologies: [] + bam: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.realigned.bam": + type: file + description: Assembled haplotypes and locally realigned reads + pattern: "*.realigned.bam" + ontologies: [] + versions_gatk4: + - - ${task.process}: + type: string + description: The name of the process + - gatk4: + type: string + description: The name of the tool + - gatk --version | sed -n '/GATK.*v/s/.*v//p': + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - gatk4: + type: string + description: The name of the tool + - gatk --version | sed -n '/GATK.*v/s/.*v//p': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@suzannejin" + - "@FriederikeHanssen" +maintainers: + - "@suzannejin" + - "@FriederikeHanssen" diff --git a/modules/nf-core/gatk4/haplotypecaller/tests/main.nf.test b/modules/nf-core/gatk4/haplotypecaller/tests/main.nf.test new file mode 100644 index 0000000..32b106e --- /dev/null +++ b/modules/nf-core/gatk4/haplotypecaller/tests/main.nf.test @@ -0,0 +1,145 @@ +// nf-core modules test gatk4/haplotypecaller +nextflow_process { + + name "Test Process GATK4_HAPLOTYPECALLER" + script "../main.nf" + process "GATK4_HAPLOTYPECALLER" + + tag "modules" + tag "modules_nfcore" + tag "gatk4" + tag "gatk4/haplotypecaller" + + test("homo_sapiens - [bam, bai] - fasta - fai - dict") { + + when { + process { + """ + input[0] = [ + [ id:'test_bam' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true), + [], + [] + ] + input[1] = [ [ id:'test_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + input[2] = [ [ id:'test_fai' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) ] + input[3] = [ [ id:'test_dict' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.dict', checkIfExists: true) ] + input[4] = [ [], [] ] + input[5] = [ [], [] ] + + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.vcf[0][1]).name, + file(process.out.tbi[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match() } + ) + } + } + + test("homo_sapiens - [cram, crai] - fasta - fai - dict") { + + when { + process { + """ + input[0] = [ + [ id:'test_cram' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram.crai', checkIfExists: true), + [], + [] + ] + input[1] = [ [ id:'test_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + input[2] = [ [ id:'test_fai' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) ] + input[3] = [ [ id:'test_dict' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.dict', checkIfExists: true) ] + input[4] = [ [], [] ] + input[5] = [ [], [] ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.vcf[0][1]).name, + file(process.out.tbi[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match() } + ) + } + } + + test("homo_sapiens - [cram, crai] - fasta - fai - dict - sites - sites_tbi") { + + when { + process { + """ + input[0] = [ + [ id:'test_cram_sites' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram.crai', checkIfExists: true), + [], + [] + ] + input[1] = [ [ id:'test_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + input[2] = [ [ id:'test_fai' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) ] + input[3] = [ [ id:'test_dict' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.dict', checkIfExists: true) ] + input[4] = [ [ id:'test_sites' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/vcf/dbsnp_146.hg38.vcf.gz', checkIfExists: true) ] + input[5] = [ [ id:'test_sites_tbi' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/vcf/dbsnp_146.hg38.vcf.gz.tbi', checkIfExists: true) ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.vcf[0][1]).name, + file(process.out.tbi[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match() } + ) + } + } + + test("homo_sapiens - [cram, crai, dragstr_model] - fasta - fai - dict - sites - sites_tbi") { + + when { + process { + """ + input[0] = [ + [ id:'test_cram_sites_dragstr' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram.crai', checkIfExists: true), + [], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/gatk/test_paired_end_sorted_dragstrmodel.txt', checkIfExists: true) + ] + input[1] = [ [ id:'test_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + input[2] = [ [ id:'test_fai' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) ] + input[3] = [ [ id:'test_dict' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.dict', checkIfExists: true) ] + input[4] = [ [ id:'test_sites' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/vcf/dbsnp_146.hg38.vcf.gz', checkIfExists: true) ] + input[5] = [ [ id:'test_sites_tbi' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/vcf/dbsnp_146.hg38.vcf.gz.tbi', checkIfExists: true) ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.vcf[0][1]).name, + file(process.out.tbi[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match() } + ) + } + } +} diff --git a/modules/nf-core/gatk4/haplotypecaller/tests/main.nf.test.snap b/modules/nf-core/gatk4/haplotypecaller/tests/main.nf.test.snap new file mode 100644 index 0000000..180ad2b --- /dev/null +++ b/modules/nf-core/gatk4/haplotypecaller/tests/main.nf.test.snap @@ -0,0 +1,82 @@ +{ + "homo_sapiens - [cram, crai] - fasta - fai - dict": { + "content": [ + "test_cram.vcf.gz", + "test_cram.vcf.gz.tbi", + { + "versions_gatk4": [ + [ + "GATK4_HAPLOTYPECALLER", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.3" + }, + "timestamp": "2026-02-05T16:28:30.201888121" + }, + "homo_sapiens - [cram, crai] - fasta - fai - dict - sites - sites_tbi": { + "content": [ + "test_cram_sites.vcf.gz", + "test_cram_sites.vcf.gz.tbi", + { + "versions_gatk4": [ + [ + "GATK4_HAPLOTYPECALLER", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.3" + }, + "timestamp": "2026-02-05T16:28:39.948711806" + }, + "homo_sapiens - [bam, bai] - fasta - fai - dict": { + "content": [ + "test_bam.vcf.gz", + "test_bam.vcf.gz.tbi", + { + "versions_gatk4": [ + [ + "GATK4_HAPLOTYPECALLER", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.3" + }, + "timestamp": "2026-02-05T16:28:20.2518415" + }, + "homo_sapiens - [cram, crai, dragstr_model] - fasta - fai - dict - sites - sites_tbi": { + "content": [ + "test_cram_sites_dragstr.vcf.gz", + "test_cram_sites_dragstr.vcf.gz.tbi", + { + "versions_gatk4": [ + [ + "GATK4_HAPLOTYPECALLER", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.3" + }, + "timestamp": "2026-02-05T16:28:49.357679232" + } +} \ No newline at end of file diff --git a/modules/nf-core/gatk4/intervallisttools/environment.yml b/modules/nf-core/gatk4/intervallisttools/environment.yml new file mode 100644 index 0000000..67e0eb8 --- /dev/null +++ b/modules/nf-core/gatk4/intervallisttools/environment.yml @@ -0,0 +1,10 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + # renovate: datasource=conda depName=bioconda/gatk4 + - bioconda::gatk4=4.6.2.0 + # renovate: datasource=conda depName=bioconda/gcnvkernel + - bioconda::gcnvkernel=0.9 diff --git a/modules/nf-core/gatk4/intervallisttools/main.nf b/modules/nf-core/gatk4/intervallisttools/main.nf new file mode 100644 index 0000000..289964f --- /dev/null +++ b/modules/nf-core/gatk4/intervallisttools/main.nf @@ -0,0 +1,64 @@ +process GATK4_INTERVALLISTTOOLS { + tag "${meta.id}" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/ce/ced519873646379e287bc28738bdf88e975edd39a92e7bc6a34bccd37153d9d0/data' + : 'community.wave.seqera.io/library/gatk4_gcnvkernel:edb12e4f0bf02cd3'}" + + input: + tuple val(meta), path(intervals) + + output: + tuple val(meta), path("*_split/*/*.interval_list"), emit: interval_list + tuple val("${task.process}"), val('gatk4'), eval("gatk --version | sed -n '/GATK.*v/s/.*v//p'"), topic: versions, emit: versions_gatk4 + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + def avail_mem = 3072 + if (!task.memory) { + log.info('[GATK IntervalListTools] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.') + } + else { + avail_mem = (task.memory.mega * 0.8).intValue() + } + """ + mkdir ${prefix}_split + + gatk --java-options "-Xmx${avail_mem}M -XX:-UsePerfData" \\ + IntervalListTools \\ + --INPUT ${intervals} \\ + --OUTPUT ${prefix}_split \\ + --TMP_DIR . \\ + ${args} + + python3 < "--INPUT ${vcf_}" }.join(' ') + def reference_command = dict ? "--SEQUENCE_DICTIONARY ${dict}" : "" + + def avail_mem = 3072 + if (!task.memory) { + log.info('[GATK MergeVcfs] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.') + } + else { + avail_mem = (task.memory.mega * 0.8).intValue() + } + """ + gatk --java-options "-Xmx${avail_mem}M -XX:-UsePerfData" \\ + MergeVcfs \\ + ${input_list} \\ + --OUTPUT ${prefix}.vcf.gz \\ + ${reference_command} \\ + --TMP_DIR . \\ + ${args} + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + echo "" | gzip > ${prefix}.vcf.gz + touch ${prefix}.vcf.gz.tbi + """ +} diff --git a/modules/nf-core/gatk4/mergevcfs/meta.yml b/modules/nf-core/gatk4/mergevcfs/meta.yml new file mode 100644 index 0000000..146eaf8 --- /dev/null +++ b/modules/nf-core/gatk4/mergevcfs/meta.yml @@ -0,0 +1,88 @@ +name: gatk4_mergevcfs +description: Merges several vcf files +keywords: + - gatk4 + - merge + - vcf +tools: + - gatk4: + description: | + Developed in the Data Sciences Platform at the Broad Institute, the toolkit offers a wide variety of tools + with a primary focus on variant discovery and genotyping. Its powerful processing engine + and high-performance computing features make it capable of taking on projects of any size. + homepage: https://gatk.broadinstitute.org/hc/en-us + documentation: https://gatk.broadinstitute.org/hc/en-us/categories/360002369672s + doi: 10.1158/1538-7445.AM2017-3590 + licence: ["Apache-2.0"] + identifier: "" +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test'] + - vcf: + type: list + description: Two or more VCF files + pattern: "*.{vcf,vcf.gz}" + - - meta2: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'genome'] + - dict: + type: file + description: Optional Sequence Dictionary as input + pattern: "*.dict" + ontologies: [] +output: + vcf: + - - meta: + type: file + description: merged vcf file + pattern: "*.vcf.gz" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + - "*.vcf.gz": + type: file + description: merged vcf file + pattern: "*.vcf.gz" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + tbi: + - - meta: + type: file + description: merged vcf file + pattern: "*.vcf.gz" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + - "*.tbi": + type: file + description: index files for the merged vcf files + pattern: "*.tbi" + ontologies: [] + versions_gatk4: + - - ${task.process}: + type: string + description: The name of the process + - gatk4: + type: string + description: The name of the tool + - gatk --version | sed -n '/GATK.*v/s/.*v//p': + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - gatk4: + type: string + description: The name of the tool + - gatk --version | sed -n '/GATK.*v/s/.*v//p': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@kevinmenden" +maintainers: + - "@kevinmenden" diff --git a/modules/nf-core/gatk4/mergevcfs/tests/main.nf.test b/modules/nf-core/gatk4/mergevcfs/tests/main.nf.test new file mode 100644 index 0000000..fd9972b --- /dev/null +++ b/modules/nf-core/gatk4/mergevcfs/tests/main.nf.test @@ -0,0 +1,80 @@ +nextflow_process { + + name "Test Process GATK4_MERGEVCFS" + script "../main.nf" + process "GATK4_MERGEVCFS" + + tag "modules" + tag "modules_nfcore" + tag "gatk4" + tag "gatk4/mergevcfs" + + test("test_gatk4_mergevcfs") { + when { + process { + """ + input[0] = [ [ id:'test' ], [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/vcf/dbsnp_146.hg38.vcf.gz', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/vcf/gnomAD.r2.1.1.vcf.gz', checkIfExists: true) ]] + input[1] = [ [], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.dict', checkIfExists: true)] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.vcf[0][1]).name, + file(process.out.tbi[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match() }, + ) + } + } + + test("test_gatk4_mergevcfs_no_dict") { + when { + process { + """ + input[0] = [ [ id:'test' ], [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/vcf/dbsnp_146.hg38.vcf.gz', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/vcf/gnomAD.r2.1.1.vcf.gz', checkIfExists: true) ]] + input[1] = [ [],[]] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.vcf[0][1]).name, + file(process.out.tbi[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match() }, + ) + } + } + + test("test_gatk4_mergevcfs_no_dict_stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ [ id:'test' ], [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/vcf/dbsnp_146.hg38.vcf.gz', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/vcf/gnomAD.r2.1.1.vcf.gz', checkIfExists: true) ]] + input[1] = [ [],[]] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.vcf[0][1]).name, + file(process.out.tbi[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match() }, + ) + } + } +} diff --git a/modules/nf-core/gatk4/mergevcfs/tests/main.nf.test.snap b/modules/nf-core/gatk4/mergevcfs/tests/main.nf.test.snap new file mode 100644 index 0000000..38e5555 --- /dev/null +++ b/modules/nf-core/gatk4/mergevcfs/tests/main.nf.test.snap @@ -0,0 +1,62 @@ +{ + "test_gatk4_mergevcfs_no_dict_stub": { + "content": [ + "test.vcf.gz", + "test.vcf.gz.tbi", + { + "versions_gatk4": [ + [ + "GATK4_MERGEVCFS", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.3" + }, + "timestamp": "2026-02-05T16:40:17.349813218" + }, + "test_gatk4_mergevcfs": { + "content": [ + "test.vcf.gz", + "test.vcf.gz.tbi", + { + "versions_gatk4": [ + [ + "GATK4_MERGEVCFS", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.3" + }, + "timestamp": "2026-02-05T16:40:03.274024419" + }, + "test_gatk4_mergevcfs_no_dict": { + "content": [ + "test.vcf.gz", + "test.vcf.gz.tbi", + { + "versions_gatk4": [ + [ + "GATK4_MERGEVCFS", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.3" + }, + "timestamp": "2026-02-05T16:40:10.948156303" + } +} \ No newline at end of file diff --git a/modules/nf-core/gatk4/splitncigarreads/environment.yml b/modules/nf-core/gatk4/splitncigarreads/environment.yml new file mode 100644 index 0000000..67e0eb8 --- /dev/null +++ b/modules/nf-core/gatk4/splitncigarreads/environment.yml @@ -0,0 +1,10 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + # renovate: datasource=conda depName=bioconda/gatk4 + - bioconda::gatk4=4.6.2.0 + # renovate: datasource=conda depName=bioconda/gcnvkernel + - bioconda::gcnvkernel=0.9 diff --git a/modules/nf-core/gatk4/splitncigarreads/main.nf b/modules/nf-core/gatk4/splitncigarreads/main.nf new file mode 100644 index 0000000..3be9818 --- /dev/null +++ b/modules/nf-core/gatk4/splitncigarreads/main.nf @@ -0,0 +1,52 @@ +process GATK4_SPLITNCIGARREADS { + tag "${meta.id}" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/ce/ced519873646379e287bc28738bdf88e975edd39a92e7bc6a34bccd37153d9d0/data' + : 'community.wave.seqera.io/library/gatk4_gcnvkernel:edb12e4f0bf02cd3'}" + + input: + tuple val(meta), path(bam), path(bai), path(intervals) + tuple val(meta2), path(fasta) + tuple val(meta3), path(fai) + tuple val(meta4), path(dict) + + output: + tuple val(meta), path('*.bam'), emit: bam + tuple val("${task.process}"), val('gatk4'), eval("gatk --version | sed -n '/GATK.*v/s/.*v//p'"), topic: versions, emit: versions_gatk4 + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def interval_command = intervals ? "--intervals ${intervals}" : "" + + def avail_mem = 3072 + if (!task.memory) { + log.info('[GATK SplitNCigarReads] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.') + } + else { + avail_mem = (task.memory.mega * 0.8).intValue() + } + """ + gatk --java-options "-Xmx${avail_mem}M -XX:-UsePerfData" \\ + SplitNCigarReads \\ + --input ${bam} \\ + --output ${prefix}.bam \\ + --reference ${fasta} \\ + ${interval_command} \\ + --tmp-dir . \\ + ${args} + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + touch ${prefix}.bam + """ +} diff --git a/modules/nf-core/gatk4/splitncigarreads/meta.yml b/modules/nf-core/gatk4/splitncigarreads/meta.yml new file mode 100644 index 0000000..8260903 --- /dev/null +++ b/modules/nf-core/gatk4/splitncigarreads/meta.yml @@ -0,0 +1,102 @@ +name: gatk4_splitncigarreads +description: Splits reads that contain Ns in their cigar string +keywords: + - gatk4 + - merge + - vcf +tools: + - gatk4: + description: | + Developed in the Data Sciences Platform at the Broad Institute, the toolkit offers a wide variety of tools + with a primary focus on variant discovery and genotyping. Its powerful processing engine + and high-performance computing features make it capable of taking on projects of any size. + homepage: https://gatk.broadinstitute.org/hc/en-us + documentation: https://gatk.broadinstitute.org/hc/en-us/categories/360002369672s + doi: 10.1158/1538-7445.AM2017-3590 + licence: ["Apache-2.0"] + identifier: "" +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test'] + - bam: + type: list + description: BAM/SAM/CRAM file containing reads + pattern: "*.{bam,sam,cram}" + - bai: + type: list + description: BAI/SAI/CRAI index file (optional) + pattern: "*.{bai,sai,crai}" + - intervals: + type: file + description: Bed file with the genomic regions included in the library (optional) + ontologies: [] + - - meta2: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'reference' ] + - fasta: + type: file + description: The reference fasta file + pattern: "*.fasta" + ontologies: [] + - - meta3: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'reference' ] + - fai: + type: file + description: Index of reference fasta file + pattern: "*.fasta.fai" + ontologies: [] + - - meta4: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'reference' ] + - dict: + type: file + description: GATK sequence dictionary + pattern: "*.dict" + ontologies: [] +output: + bam: + - - meta: + type: file + description: Output file with split reads (BAM/SAM/CRAM) + pattern: "*.{bam,sam,cram}" + ontologies: [] + - "*.bam": + type: file + description: Output file with split reads (BAM/SAM/CRAM) + pattern: "*.{bam,sam,cram}" + ontologies: [] + versions_gatk4: + - - ${task.process}: + type: string + description: The name of the process + - gatk4: + type: string + description: The name of the tool + - gatk --version | sed -n '/GATK.*v/s/.*v//p': + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - gatk4: + type: string + description: The name of the tool + - gatk --version | sed -n '/GATK.*v/s/.*v//p': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@kevinmenden" +maintainers: + - "@kevinmenden" diff --git a/modules/nf-core/gatk4/splitncigarreads/tests/main.nf.test b/modules/nf-core/gatk4/splitncigarreads/tests/main.nf.test new file mode 100644 index 0000000..09f431e --- /dev/null +++ b/modules/nf-core/gatk4/splitncigarreads/tests/main.nf.test @@ -0,0 +1,88 @@ +nextflow_process { + + name "Test Process GATK4_SPLITNCIGARREADS" + script "../main.nf" + process "GATK4_SPLITNCIGARREADS" + + tag "modules" + tag "modules_nfcore" + tag "gatk4" + tag "gatk4/splitncigarreads" + + test("test_gatk4_splitncigarreads") { + + when { + process { + """ + input[0] = [ [ id:'test' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true), []] + input[1] = [ [ id:'reference' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] + input[2] = [ [ id:'reference' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) ] + input[3] = [ [ id:'reference' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.dict', checkIfExists: true) ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.bam[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match() + } + ) + } + } + + test("test_gatk4_splitncigarreads_intervals") { + + when { + process { + """ + input[0] = [ [ id:'test' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/bed/test.bed', checkIfExists: true)] + input[1] = [ [ id:'reference' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] + input[2] = [ [ id:'reference' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) ] + input[3] = [ [ id:'reference' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.dict', checkIfExists: true) ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.bam[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match() + } + ) + } + } + + test("test_gatk4_splitncigarreads_stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ [ id:'test' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true), [], []] + input[1] = [ [ id:'reference' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] + input[2] = [ [ id:'reference' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) ] + input[3] = [ [ id:'reference' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.dict', checkIfExists: true) ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.bam[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match() + } + ) + } + } +} diff --git a/modules/nf-core/gatk4/splitncigarreads/tests/main.nf.test.snap b/modules/nf-core/gatk4/splitncigarreads/tests/main.nf.test.snap new file mode 100644 index 0000000..2281192 --- /dev/null +++ b/modules/nf-core/gatk4/splitncigarreads/tests/main.nf.test.snap @@ -0,0 +1,59 @@ +{ + "test_gatk4_splitncigarreads_intervals": { + "content": [ + "test.bam", + { + "versions_gatk4": [ + [ + "GATK4_SPLITNCIGARREADS", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.3" + }, + "timestamp": "2026-02-05T18:01:00.303332906" + }, + "test_gatk4_splitncigarreads_stub": { + "content": [ + "test.bam", + { + "versions_gatk4": [ + [ + "GATK4_SPLITNCIGARREADS", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.3" + }, + "timestamp": "2026-02-05T18:01:06.852378451" + }, + "test_gatk4_splitncigarreads": { + "content": [ + "test.bam", + { + "versions_gatk4": [ + [ + "GATK4_SPLITNCIGARREADS", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.3" + }, + "timestamp": "2026-02-05T18:00:52.006171566" + } +} \ No newline at end of file diff --git a/modules/nf-core/gatk4/variantfiltration/environment.yml b/modules/nf-core/gatk4/variantfiltration/environment.yml new file mode 100644 index 0000000..67e0eb8 --- /dev/null +++ b/modules/nf-core/gatk4/variantfiltration/environment.yml @@ -0,0 +1,10 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + # renovate: datasource=conda depName=bioconda/gatk4 + - bioconda::gatk4=4.6.2.0 + # renovate: datasource=conda depName=bioconda/gcnvkernel + - bioconda::gcnvkernel=0.9 diff --git a/modules/nf-core/gatk4/variantfiltration/main.nf b/modules/nf-core/gatk4/variantfiltration/main.nf new file mode 100644 index 0000000..58283b1 --- /dev/null +++ b/modules/nf-core/gatk4/variantfiltration/main.nf @@ -0,0 +1,64 @@ +process GATK4_VARIANTFILTRATION { + tag "${meta.id}" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/ce/ced519873646379e287bc28738bdf88e975edd39a92e7bc6a34bccd37153d9d0/data' + : 'community.wave.seqera.io/library/gatk4_gcnvkernel:edb12e4f0bf02cd3'}" + + input: + tuple val(meta), path(vcf), path(tbi) + tuple val(meta2), path(fasta) + tuple val(meta3), path(fai) + tuple val(meta4), path(dict) + tuple val(meta5), path(gzi) + + output: + tuple val(meta), path("*.vcf.gz"), emit: vcf + tuple val(meta), path("*.tbi"), emit: tbi + tuple val("${task.process}"), val('gatk4'), eval("gatk --version | sed -n '/GATK.*v/s/.*v//p'"), topic: versions, emit: versions_gatk4 + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + // Infer .dict file name that gatk expects, even if ends in .fasta.gz + def dict_name = fasta.getBaseName() + if (dict_name ==~ /^.*\.(fasta|fna|fa)$/) { + dict_name = dict_name.replaceAll(/\.(fasta|fna|fa)$/, "") + } + dict_name = "${dict_name}.dict" + + def avail_mem = 3072 + if (!task.memory) { + log.info('[GATK VariantFiltration] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.') + } + else { + avail_mem = (task.memory.mega * 0.8).intValue() + } + """ + # Make sure the .dict file is named correctly + if [[ ${dict_name} != ${dict} ]]; then + ln -s ${dict} ${dict_name} + fi + + gatk --java-options "-Xmx${avail_mem}M -XX:-UsePerfData" \\ + VariantFiltration \\ + --variant ${vcf} \\ + --output ${prefix}.vcf.gz \\ + --reference ${fasta} \\ + --tmp-dir . \\ + ${args} + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + echo "" | gzip > ${prefix}.vcf.gz + touch ${prefix}.vcf.gz.tbi + """ +} diff --git a/modules/nf-core/gatk4/variantfiltration/meta.yml b/modules/nf-core/gatk4/variantfiltration/meta.yml new file mode 100644 index 0000000..4177a70 --- /dev/null +++ b/modules/nf-core/gatk4/variantfiltration/meta.yml @@ -0,0 +1,126 @@ +name: gatk4_variantfiltration +description: Filter variants +keywords: + - filter + - gatk4 + - variantfiltration + - vcf +tools: + - gatk4: + description: | + Developed in the Data Sciences Platform at the Broad Institute, the toolkit offers a wide variety of tools + with a primary focus on variant discovery and genotyping. Its powerful processing engine + and high-performance computing features make it capable of taking on projects of any size. + homepage: https://gatk.broadinstitute.org/hc/en-us + documentation: https://gatk.broadinstitute.org/hc/en-us/categories/360002369672s + doi: 10.1158/1538-7445.AM2017-3590 + licence: ["Apache-2.0"] + identifier: "" +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test'] + - vcf: + type: list + description: List of VCF(.gz) files + pattern: "*.{vcf,vcf.gz}" + - tbi: + type: list + description: List of VCF file indexes + pattern: "*.{tbi}" + - - meta2: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'genome' ] + - fasta: + type: file + description: Fasta file of reference genome + pattern: "*.fasta" + ontologies: [] + - - meta3: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'genome' ] + - fai: + type: file + description: Index of fasta file + pattern: "*.fasta.fai" + ontologies: [] + - - meta4: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'genome' ] + - dict: + type: file + description: Sequence dictionary of fastea file + pattern: "*.dict" + ontologies: [] + - - meta5: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'genome' ] + - gzi: + type: file + description: Genome index file only needed when the genome file was compressed + with the BGZF algorithm. + pattern: "*.gzi" + ontologies: [] +output: + vcf: + - - meta: + type: file + description: Compressed VCF file + pattern: "*.vcf.gz" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + - "*.vcf.gz": + type: file + description: Compressed VCF file + pattern: "*.vcf.gz" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + tbi: + - - meta: + type: file + description: Compressed VCF file + pattern: "*.vcf.gz" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + - "*.tbi": + type: file + description: Index of VCF file + pattern: "*.vcf.gz.tbi" + ontologies: [] + versions_gatk4: + - - ${task.process}: + type: string + description: The name of the process + - gatk4: + type: string + description: The name of the tool + - gatk --version | sed -n '/GATK.*v/s/.*v//p': + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - gatk4: + type: string + description: The name of the tool + - gatk --version | sed -n '/GATK.*v/s/.*v//p': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@kevinmenden" + - "@ramprasadn" +maintainers: + - "@kevinmenden" + - "@ramprasadn" diff --git a/modules/nf-core/gatk4/variantfiltration/tests/main.nf.test b/modules/nf-core/gatk4/variantfiltration/tests/main.nf.test new file mode 100644 index 0000000..cbb647c --- /dev/null +++ b/modules/nf-core/gatk4/variantfiltration/tests/main.nf.test @@ -0,0 +1,137 @@ +nextflow_process { + + name "Test Process GATK4_VARIANTFILTRATION" + script "../main.nf" + process "GATK4_VARIANTFILTRATION" + + tag "modules" + tag "modules_nfcore" + tag "gatk4" + tag "gatk4/variantfiltration" + + test("gatk4_variantfiltration - human - vcf - fasta") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/gvcf/test.genome.vcf', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/gvcf/test.genome.vcf.idx', checkIfExists: true) + ] + input[1] = [ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ] + input[2] = [ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) + ] + input[3] = [ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.dict', checkIfExists: true) + ] + input[4] = [ + [ id:'genome' ], // meta map + [] + ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + path(process.out.vcf[0][1]).vcf.variantsMD5, + file(process.out.tbi[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match() } + ) + } + } + + test("gatk4_variantfiltration - human - vcf - fasta.gz") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/gvcf/test.genome.vcf', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/gvcf/test.genome.vcf.idx', checkIfExists: true) + ] + input[1] = [ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) + ] + input[2] = [ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz.fai', checkIfExists: true) + ] + input[3] = [ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.dict', checkIfExists: true) + ] + input[4] = [ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz.gzi', checkIfExists: true) + ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + path(process.out.vcf[0][1]).vcf.variantsMD5, + file(process.out.tbi[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match() } + ) + } + } + + test("gatk4_variantfiltration - human - vcf.gz - fasta") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/gvcf/test.genome.vcf.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/gvcf/test.genome.vcf.gz.tbi', checkIfExists: true) + ] + input[1] = [ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ] + input[2] = [ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) + ] + input[3] = [ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.dict', checkIfExists: true) + ] + input[4] = [ + [ id:'genome' ], // meta map + [] + ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + path(process.out.vcf[0][1]).vcf.variantsMD5, + file(process.out.tbi[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match() } + ) + } + } +} diff --git a/modules/nf-core/gatk4/variantfiltration/tests/main.nf.test.snap b/modules/nf-core/gatk4/variantfiltration/tests/main.nf.test.snap new file mode 100644 index 0000000..e1a3c78 --- /dev/null +++ b/modules/nf-core/gatk4/variantfiltration/tests/main.nf.test.snap @@ -0,0 +1,62 @@ +{ + "gatk4_variantfiltration - human - vcf - fasta.gz": { + "content": [ + "cf0477cc14953b16caacbf5be507b88", + "test.vcf.gz.tbi", + { + "versions_gatk4": [ + [ + "GATK4_VARIANTFILTRATION", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.3" + }, + "timestamp": "2026-02-05T18:03:01.467326216" + }, + "gatk4_variantfiltration - human - vcf.gz - fasta": { + "content": [ + "cf0477cc14953b16caacbf5be507b88", + "test.vcf.gz.tbi", + { + "versions_gatk4": [ + [ + "GATK4_VARIANTFILTRATION", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.3" + }, + "timestamp": "2026-02-05T18:03:09.049097033" + }, + "gatk4_variantfiltration - human - vcf - fasta": { + "content": [ + "cf0477cc14953b16caacbf5be507b88", + "test.vcf.gz.tbi", + { + "versions_gatk4": [ + [ + "GATK4_VARIANTFILTRATION", + "gatk4", + "4.6.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.3" + }, + "timestamp": "2026-02-05T18:02:52.913618285" + } +} \ No newline at end of file diff --git a/nextflow.config b/nextflow.config index e830fb1..f32b3a7 100644 --- a/nextflow.config +++ b/nextflow.config @@ -28,6 +28,14 @@ params { gtf = null star_index = null + // Variant Calling options + dbsnp = null + scatter_size = 40 + min_confidence_threshold = 20 + gatk_vf_window_size = 35 + gatk_vf_cluster_size = 3 + gatk_vf_fs_filter = 30.0 + gatk_vf_qd_filter = 2.0 starfusion_ref = null arriba_base = null @@ -41,8 +49,10 @@ params { dx_tracks_path = null // Run options - run_outrider = true + run_outrider = false run_umitools_dedup = true + run_gene_fusion = true + run_variant_calling = true // Custom reference files GRCh38 gene_bed = null @@ -92,6 +102,8 @@ params { validate_params = true cluster_options = "--mail-user ${params.email} --mail-type FAIL --account=diaggen" + // Nextflow process cache dir + cache_dir = null } // Load base.config by default for all pipelines diff --git a/nf-test.config b/nf-test.config index 1727ee7..db8dfdf 100644 --- a/nf-test.config +++ b/nf-test.config @@ -13,5 +13,6 @@ config { plugins { load "nft-csv@0.1.0" + load "nft-vcf@1.0.7" } } diff --git a/subworkflows/local/bam_variant_calling/main.nf b/subworkflows/local/bam_variant_calling/main.nf new file mode 100644 index 0000000..6d0fa8b --- /dev/null +++ b/subworkflows/local/bam_variant_calling/main.nf @@ -0,0 +1,114 @@ +include { BCFTOOLS_INDEX } from '../../../modules/nf-core/bcftools/index/main' +include { GATK4_HAPLOTYPECALLER } from '../../../modules/nf-core/gatk4/haplotypecaller/main' +include { GATK4_MERGEVCFS } from '../../../modules/nf-core/gatk4/mergevcfs/main' +include { GATK4_SPLITNCIGARREADS } from '../../../modules/nf-core/gatk4/splitncigarreads/main' +include { GATK4_VARIANTFILTRATION } from '../../../modules/nf-core/gatk4/variantfiltration/main' +include { SAMTOOLS_MERGE } from '../../../modules/nf-core/samtools/merge/main' +include { SAMTOOLS_INDEX } from '../../../modules/nf-core/samtools/index/main' + + +// workflow adapted from github.com/nf-core/rnavar +workflow BAM_VARIANT_CALLING { + take: + ch_bam_bai + ch_fasta_fai + ch_dict + interval_list_split + ch_dbsnp + ch_dbsnp_tbi + + + main: + ch_fasta = ch_fasta_fai.map { meta, fasta, _fai -> [meta, fasta] } + ch_fai = ch_fasta_fai.map { meta, _fasta, fai -> [meta, fai] } + + + def bam_interval = ch_bam_bai + .combine(interval_list_split) + .map { meta, bam, bai, intervals -> + def new_meta = meta + [interval_count: intervals.size()] + [new_meta, bam, bai, intervals] + } + .transpose(by: 3) + .map { meta, bam, bai, interval -> + [meta + [id: "${meta.id}_${interval.baseName}", sample: meta.id], bam, bai, interval] + } + + GATK4_SPLITNCIGARREADS( + bam_interval, + ch_fasta, + ch_fai, + ch_dict, + ) + + def bam_splitncigar_interval = GATK4_SPLITNCIGARREADS.out.bam + .map { meta, bam -> + def new_meta = meta + [id: meta.sample] - meta.subMap('sample') - meta.subMap('interval_count') + [groupKey(new_meta, meta.interval_count), bam] + } + .groupTuple() + + SAMTOOLS_MERGE( + bam_splitncigar_interval, + ch_fasta, + ch_fai + ) + + def splitncigar_merged_bam = SAMTOOLS_MERGE.out.bam + + SAMTOOLS_INDEX(splitncigar_merged_bam) + + def splitncigar_merged_bam_indices = SAMTOOLS_INDEX.out.bai + .mix(SAMTOOLS_INDEX.out.csi) + .mix(SAMTOOLS_INDEX.out.crai) + + def splitncigar_merged_bam_bai = splitncigar_merged_bam.join(splitncigar_merged_bam_indices, failOnDuplicate: true, failOnMismatch: true) + + def haplotypecaller_interval_bam = splitncigar_merged_bam_bai + .combine(interval_list_split) + .map { meta, bam, bai, interval_lists -> + [meta + [interval_count: interval_lists.size()], bam, bai, interval_lists] + } + .transpose(by: 3) + .map { meta, bam, bai, interval_list_ -> + [meta + [id: meta.id + "_" + interval_list_.baseName, sample: meta.id, variantcaller: 'haplotypecaller'], bam, bai, interval_list_, []] + } + + GATK4_HAPLOTYPECALLER( + haplotypecaller_interval_bam, + ch_fasta, + ch_fai, + ch_dict, + ch_dbsnp, + ch_dbsnp_tbi, + ) + + def ch_vcf_tbi = GATK4_HAPLOTYPECALLER.out.vcf + .join(GATK4_HAPLOTYPECALLER.out.tbi, failOnMismatch: true, failOnDuplicate: true) + .map { meta, vcf, tbi -> + [groupKey(meta + [id: meta.sample] - meta.subMap('sample', "interval_count"), meta.interval_count), vcf, tbi] + } + .groupTuple() + + GATK4_MERGEVCFS( + ch_vcf_tbi.map { meta, vcfs, _tbis -> [meta, vcfs] }, + ch_dict, + ) + + BCFTOOLS_INDEX(GATK4_MERGEVCFS.out.vcf) + + GATK4_VARIANTFILTRATION( + GATK4_MERGEVCFS.out.vcf.join(BCFTOOLS_INDEX.out.tbi), + ch_fasta, + ch_fai, + ch_dict, + [[],[]] + ) + + + emit: + ch_vcf_tbi_unfiltered = ch_vcf_tbi + ch_vcf_filtered = GATK4_VARIANTFILTRATION.out.vcf + ch_tbi_filtered = GATK4_VARIANTFILTRATION.out.tbi + +} diff --git a/subworkflows/local/bam_variant_calling/tests/main.nf.test b/subworkflows/local/bam_variant_calling/tests/main.nf.test new file mode 100644 index 0000000..b3ac9a1 --- /dev/null +++ b/subworkflows/local/bam_variant_calling/tests/main.nf.test @@ -0,0 +1,61 @@ +nextflow_workflow { + name "Test Subworkflow BAM_VARIANT_CALLING" + script "../main.nf" + workflow "BAM_VARIANT_CALLING" + + tag "subworkflows/local" + tag "subworkflows" + tag "local" + tag "variant_calling" + + test ("Test scatter and merge") { + + setup { + run("PREPARE_REFERENCES") { + script "../../prepare_references/main.nf" + workflow { + """ + input[0] = channel.of([ + [ id:'minigenome_fasta' ], + file(params.nfcore_modules_testdata + 'genomics/homo_sapiens/genome/chr21/sequence/genome.fasta'), + file(params.nfcore_modules_testdata + 'genomics/homo_sapiens/genome/chr21/sequence/genome.fasta.fai') + ]).first() + input[1] = channel.of([ + [ id:'minigenome_gtf' ], + file(params.nfcore_modules_testdata + 'genomics/homo_sapiens/genome/chr21/sequence/chr21_gencode.gtf') + ]).first() + """ + } + } + } + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'sampleA' ], + file(params.nfcore_modules_testdata + 'genomics/homo_sapiens/illumina/bam/NA12878.chr21_22.bam'), + file(params.nfcore_modules_testdata + 'genomics/homo_sapiens/illumina/bam/NA12878.chr21_22.bam.bai') + ]) + input[1] = channel.of([ + [ id:'minigenome_fasta' ], + file(params.nfcore_modules_testdata + 'genomics/homo_sapiens/genome/chr21/sequence/genome.fasta'), + file(params.nfcore_modules_testdata + 'genomics/homo_sapiens/genome/chr21/sequence/genome.fasta.fai') + ]).first() + input[2] = PREPARE_REFERENCES.out.dict + input[3] = PREPARE_REFERENCES.out.interval_list_split + input[4] = [[:],[]] + input[5] = [[:],[]] + """ + } + } + then { + assertAll( + { assert workflow.success }, + { assert snapshot( + workflow.out.ch_vcf_filtered + ).match() } + ) + } + } +} diff --git a/subworkflows/local/bam_variant_calling/tests/main.nf.test.snap b/subworkflows/local/bam_variant_calling/tests/main.nf.test.snap new file mode 100644 index 0000000..b4722bf --- /dev/null +++ b/subworkflows/local/bam_variant_calling/tests/main.nf.test.snap @@ -0,0 +1,14 @@ +{ + "Test scatter and merge": { + "content": [ + [ + + ] + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.4" + }, + "timestamp": "2026-05-26T14:31:27.300922" + } +} \ No newline at end of file diff --git a/subworkflows/local/prepare_references/main.nf b/subworkflows/local/prepare_references/main.nf new file mode 100644 index 0000000..dfe9c8f --- /dev/null +++ b/subworkflows/local/prepare_references/main.nf @@ -0,0 +1,30 @@ +include { GATK4_BEDTOINTERVALLIST } from '../../../modules/nf-core/gatk4/bedtointervallist/main' +include { GATK4_CREATESEQUENCEDICTIONARY } from '../../../modules/nf-core/gatk4/createsequencedictionary/main' +include { GATK4_INTERVALLISTTOOLS } from '../../../modules/nf-core/gatk4/intervallisttools/main' +include { BEDOPS_GTF2BED } from '../../../modules/nf-core/bedops/gtf2bed/main' + +workflow PREPARE_REFERENCES { + take: + ch_fasta_fai + ch_gtf + + main: + + + GATK4_CREATESEQUENCEDICTIONARY(ch_fasta_fai.map { meta, fasta, _fai -> [meta, fasta] }) + def ch_dict = GATK4_CREATESEQUENCEDICTIONARY.out.dict + + BEDOPS_GTF2BED(ch_gtf) + GATK4_BEDTOINTERVALLIST(BEDOPS_GTF2BED.out.bed.collect(), ch_dict) + + // Scatter one interval-list into many interval-files using GATK4 IntervalListTools + GATK4_INTERVALLISTTOOLS(GATK4_BEDTOINTERVALLIST.out.interval_list) + + + emit: + dict = ch_dict + bed = BEDOPS_GTF2BED.out.bed.collect() + interval_list = GATK4_BEDTOINTERVALLIST.out.interval_list + interval_list_split = GATK4_INTERVALLISTTOOLS.out.interval_list.map { _meta, bed -> [bed] }.collect() + +} diff --git a/subworkflows/local/prepare_references/tests/main.nf.test b/subworkflows/local/prepare_references/tests/main.nf.test new file mode 100644 index 0000000..ec4c776 --- /dev/null +++ b/subworkflows/local/prepare_references/tests/main.nf.test @@ -0,0 +1,41 @@ +nextflow_workflow { + name "Test Subworkflow PREPARE_REFERENCES" + script "../main.nf" + workflow "PREPARE_REFERENCES" + + tag "subworkflows/local" + tag "subworkflows" + tag "local" + tag "prepare_references" + + test ("Test intervals and scatters") { + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'minigenome_fasta' ], + file(params.nfcore_modules_testdata + 'genomics/homo_sapiens/genome/chr21/sequence/genome.fasta'), + file(params.nfcore_modules_testdata + 'genomics/homo_sapiens/genome/chr21/sequence/genome.fasta.fai') + ]).first() + input[1] = channel.of([ + [ id:'minigenome_gtf' ], + file(params.nfcore_modules_testdata + 'genomics/homo_sapiens/genome/chr21/sequence/chr21_gencode.gtf') + ]).first() + """ + } + + } + then { + assertAll( + { assert workflow.success }, + { assert snapshot( + workflow.out.dict, + workflow.out.bed, + workflow.out.interval_list, + workflow.out.interval_list_split + ).match() } + ) + } + } +} diff --git a/subworkflows/local/prepare_references/tests/main.nf.test.snap b/subworkflows/local/prepare_references/tests/main.nf.test.snap new file mode 100644 index 0000000..f2d45b3 --- /dev/null +++ b/subworkflows/local/prepare_references/tests/main.nf.test.snap @@ -0,0 +1,43 @@ +{ + "Test intervals and scatters": { + "content": [ + [ + [ + { + "id": "minigenome_fasta" + }, + "genome.dict:md5,de4ff13287d28c1679a11ae989a3a980" + ] + ], + [ + [ + { + "id": "minigenome_gtf" + }, + "chr21_gencode.bed:md5,6018f980c6ee0e8da905b50d6838ea40" + ] + ], + [ + [ + { + "id": "minigenome_gtf" + }, + "minigenome_gtf.interval_list:md5,f49045d215e5fc1dfcd4f6f79a8da0b5" + ] + ], + [ + [ + [ + "1scattered.interval_list:md5,7ade4bf4b27da132228553b59323db6e", + "2scattered.interval_list:md5,0f3322aa6497f446b43b74144e6fbada" + ] + ] + ] + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.4" + }, + "timestamp": "2026-06-03T13:58:43.674297" + } +} \ No newline at end of file diff --git a/tests/main.nf.test b/tests/main.nf.test index 36d1db9..7b58df6 100644 --- a/tests/main.nf.test +++ b/tests/main.nf.test @@ -30,7 +30,7 @@ nextflow_pipeline { } - + when { params { input = "${launchDir}/input/" @@ -45,7 +45,7 @@ nextflow_pipeline { } then { - assert workflow.trace.succeeded().size() == 27 // check if all steps are executed + assert workflow.trace.succeeded().size() == 37 // check if all steps are executed assert workflow.success } } diff --git a/tests/nextflow.config b/tests/nextflow.config index afced7c..55e4810 100644 --- a/tests/nextflow.config +++ b/tests/nextflow.config @@ -9,6 +9,8 @@ params { config_profile_name = "Test Profile" config_profile_description = "Minimal pipeline test" + scatter_size = 2 + seq_platform = "Illumina" seq_center = "UMCU Genetics" @@ -21,10 +23,12 @@ params { gene_bed = "gencode.ref_annot.gtf.bed" ref_flat = "gencode.ref_annot.gtf.refflat" rrna_intervals = "GRCh38_rRNA_genbank.interval_list" + dbsnp = "dbsnp.vcf.gz" run_outrider = true run_gene_fusion = true + run_variant_calling = true arriba_base = "./" arriba_blacklist = [] @@ -32,7 +36,7 @@ params { arriba_protein = [] arriba_known_fusions = [] - + outrider_reference_base = "./" outrider_refs = null conditions = ['chx'] @@ -47,6 +51,7 @@ process { queue = 'cpu' withName: ".*" { + array = 0 cpus = 1 memory = 3.GB time = 10.m diff --git a/workflows/dxnextflowrna.nf b/workflows/dxnextflowrna.nf index a9cfb25..87ba3d7 100644 --- a/workflows/dxnextflowrna.nf +++ b/workflows/dxnextflowrna.nf @@ -8,10 +8,12 @@ include { MULTIQC } from '../modules/nf-core/multiqc/main' // SUBWORKFLOWS include { BAM_QUANTIFICATION_FEATURECOUNTS } from '../subworkflows/local/bam_quantification_featurecounts' +include { BAM_VARIANT_CALLING } from '../subworkflows/local/bam_variant_calling/main' include { FASTQ_BAM_QC } from '../subworkflows/local/fastq_bam_qc' include { FASTQ_TRIM_FILTER_ALIGN_DEDUP } from '../subworkflows/local/fastq_trim_filter_align_dedup/main' include { GENE_EXON_OUTRIDER } from '../subworkflows/local/gene_exon_outrider/main' include { BAM_GENE_FUSION } from '../subworkflows/local/bam_gene_fusion/main' +include { PREPARE_REFERENCES } from '../subworkflows/local/prepare_references/main' // FUNCTIONS include { methodsDescriptionText } from '../subworkflows/local/utils_umcugenetics_dxnextflowrna_pipeline' include { paramsSummaryMap } from 'plugin/nf-schema' @@ -60,6 +62,21 @@ workflow DXNEXTFLOWRNA { .map(createMetaWithIdSimpleName) .first() + ch_dbsnp = channel + .fromPath(params.dbsnp) + .map(createMetaWithIdSimpleName) + .first() + ch_dbsnp_tbi = channel + .fromPath("${params.dbsnp}.{tbi,csi}") + .map(createMetaWithIdSimpleName) + .first() + + + PREPARE_REFERENCES( + ch_fasta_fai, + ch_gtf + ) + // Input channel ch_fastq = Channel .fromFilePairs("${params.input}/*_R{1,2}_001.fastq.gz") @@ -140,7 +157,7 @@ workflow DXNEXTFLOWRNA { // SUBWORKFLOW: Run bam_quantification_featurecounts // - + BAM_QUANTIFICATION_FEATURECOUNTS( FASTQ_TRIM_FILTER_ALIGN_DEDUP.out.ch_bam_bai, ch_gtf @@ -157,8 +174,8 @@ workflow DXNEXTFLOWRNA { if (params.run_gene_fusion){ ch_starfusion_ref = Channel.fromPath(params.starfusion_ref).collect() - - + + BAM_GENE_FUSION( FASTQ_TRIM_FILTER_ALIGN_DEDUP.out.star_align_junction, ch_starfusion_ref, @@ -168,11 +185,11 @@ workflow DXNEXTFLOWRNA { params.arriba_blacklist, params.arriba_known_fusions, params.arriba_cytobands, - params.arriba_protein + params.arriba_protein ) } - - + + // // SUBWORKFLOW: Run bam_outrider for genes and exons // @@ -188,6 +205,16 @@ workflow DXNEXTFLOWRNA { } + if (params.run_variant_calling) { + BAM_VARIANT_CALLING( + FASTQ_TRIM_FILTER_ALIGN_DEDUP.out.ch_bam_bai, + ch_fasta_fai, + PREPARE_REFERENCES.out.dict, + PREPARE_REFERENCES.out.interval_list_split, + ch_dbsnp, + ch_dbsnp_tbi + ) + } // // Collate and save software versions