diff --git a/modules/nf-core/nirvana/environment.yml b/modules/nf-core/nirvana/environment.yml new file mode 100644 index 000000000000..45854d1f9210 --- /dev/null +++ b/modules/nf-core/nirvana/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::nirvana=3.18.1 diff --git a/modules/nf-core/nirvana/main.nf b/modules/nf-core/nirvana/main.nf new file mode 100644 index 000000000000..9a62a954b589 --- /dev/null +++ b/modules/nf-core/nirvana/main.nf @@ -0,0 +1,43 @@ +process NIRVANA { + tag "${meta.id}" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container 'community.wave.seqera.io/library/nirvana:3.18.1--51c5bd56fef22808' + + input: + tuple val(meta) , path(vcf) + tuple val(meta2), path(reference) + tuple val(meta3), path(cache), val(cache_prefix) + tuple val(meta4), path(supplementary_annotations) + + output: + tuple val(meta), path("*.json.gz"), emit: json + tuple val(meta), path("*.json.gz.jsi"), emit: jsi + tuple val("${task.process}"), val('nirvana'), eval("Nirvana -v 2>&1 | awk '{print \$2}' | cut -d'-' -f1"), topic: versions, emit: versions_nirvana + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def cache_command = cache ? "-c ${cache}/${cache_prefix}" : "" + def sa_command = supplementary_annotations ? "--sd ${supplementary_annotations}" : "" + """ + Nirvana \\ + -i ${vcf} \\ + -r ${reference} \\ + ${cache_command} \\ + ${sa_command} \\ + ${args} \\ + -o ${prefix} + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + echo "" | gzip > ${prefix}.json.gz + touch ${prefix}.json.gz.jsi + """ +} diff --git a/modules/nf-core/nirvana/meta.yml b/modules/nf-core/nirvana/meta.yml new file mode 100644 index 000000000000..552f3729217e --- /dev/null +++ b/modules/nf-core/nirvana/meta.yml @@ -0,0 +1,109 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json +name: "nirvana" +description: Clinical-grade annotation of genomic variants including SNVs, MNVs, insertions, deletions, indels, and SVs +keywords: + - annotation + - variant annotation + - vcf + - genomics + - clinical annotation +tools: + - "nirvana": + description: "Clinical-grade annotation of genomic variants (SNVs, MNVs, insertions, + deletions, indels, and SVs)" + homepage: "https://illumina.github.io/NirvanaDocumentation/" + documentation: "https://illumina.github.io/NirvanaDocumentation/" + tool_dev_url: "https://github.com/Illumina/Nirvana" + licence: ["GPL v3"] + identifier: biotools:nirvana + +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - vcf: + type: file + description: Input VCF file to annotate + pattern: "*.{vcf,vcf.gz}" + ontologies: + - edam: "http://edamontology.org/format_3016" # VCF + - - meta2: + type: map + description: | + Groovy Map containing reference information + e.g. `[ id:'genome' ]` + - reference: + type: file + description: Compressed Nirvana reference sequence file + pattern: "*.dat" + - - meta3: + type: map + description: | + Groovy Map containing cache information + e.g. `[ id:'cache' ]` + - cache: + type: directory + description: Nirvana cache directory + - cache_prefix: + type: string + description: Prefix for cache files (e.g., 'SARS-CoV-2' for files like SARS-CoV-2.transcripts.ndb) + - - meta4: + type: map + description: | + Groovy Map containing supplementary annotation information + e.g. `[ id:'sa' ]` + - supplementary_annotations: + type: directory + description: Nirvana supplementary annotation directory (optional) + +output: + json: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*.json.gz": + type: file + description: Gzip-compressed JSON file with variant annotations + pattern: "*.json.gz" + ontologies: + - edam: "http://edamontology.org/format_3464" # JSON + jsi: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*.json.gz.jsi": + type: file + description: JSON index file for the annotations + pattern: "*.json.gz.jsi" + versions_nirvana: + - - "${task.process}": + type: string + description: The name of the process + - "nirvana": + type: string + description: The name of the tool + - "Nirvana -v 2>&1 | awk '{print $2}' | cut -d'-' -f1": + type: eval + description: The expression to obtain the version of the tool + +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - nirvana: + type: string + description: The name of the tool + - "Nirvana -v 2>&1 | awk '{print $2}' | cut -d'-' -f1": + type: eval + description: The expression to obtain the version of the tool +authors: + - "@FriederikeHanssen" +maintainers: + - "@FriederikeHanssen" diff --git a/modules/nf-core/nirvana/tests/main.nf.test b/modules/nf-core/nirvana/tests/main.nf.test new file mode 100644 index 000000000000..4c7a5e0a5531 --- /dev/null +++ b/modules/nf-core/nirvana/tests/main.nf.test @@ -0,0 +1,108 @@ +nextflow_process { + + name "Test Process NIRVANA" + script "../main.nf" + process "NIRVANA" + + tag "modules" + tag "modules_nfcore" + tag "nirvana" + tag "untar" + + setup { + run("UNTAR", alias: "UNTAR_CACHE") { + script "../../untar/main.nf" + process { + """ + input[0] = [ + [ id:'Cache' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/nirvana/Cache.tar', checkIfExists: true) + ] + """ + } + } + + run("UNTAR", alias: "UNTAR_SA") { + script "../../untar/main.nf" + process { + """ + input[0] = [ + [ id:'SupplementaryAnnotation' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/nirvana/SupplementaryAnnotation.tar', checkIfExists: true) + ] + """ + } + } + } + + test("sarscov2 - vcf") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/vcf/test.vcf.gz', checkIfExists: true) + ] + input[1] = [ + [ id:'reference' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/nirvana/SARS-CoV-2.ASM985889v3.dat', checkIfExists: true) + ] + input[2] = UNTAR_CACHE.out.untar.map { meta, dir -> + [ meta, dir, 'SARS-CoV-2' ] + } + input[3] = UNTAR_SA.out.untar + """ + } + } + + then { + assertAll( + { assert process.success }, + // Remove creationTime field from JSON and snapshot the rest + { assert snapshot( + path(process.out.json[0][1]).linesGzip.collect { + it.replaceAll(/"creationTime":"[^"]*",?/, '') + } + ).match("json_content") }, + // Just check JSI exists + { assert path(process.out.jsi[0][1]).exists() }, + { assert snapshot(process.out.versions_nirvana).match() } + ) + } + + } + + test("sarscov2 - vcf - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/vcf/test.vcf.gz', checkIfExists: true) + ] + input[1] = [ + [ id:'reference' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/nirvana/SARS-CoV-2.ASM985889v3.dat', checkIfExists: true) + ] + input[2] = UNTAR_CACHE.out.untar.map { meta, dir -> + [ meta, dir, 'SARS-CoV-2' ] + } + input[3] = UNTAR_SA.out.untar + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/nf-core/nirvana/tests/main.nf.test.snap b/modules/nf-core/nirvana/tests/main.nf.test.snap new file mode 100644 index 000000000000..55c81f3a1850 --- /dev/null +++ b/modules/nf-core/nirvana/tests/main.nf.test.snap @@ -0,0 +1,97 @@ +{ + "json_content": { + "content": [ + [ + "{\"header\":{\"annotator\":\"Nirvana 3.18.1\",\"genomeAssembly\":\"SARSCoV2\",\"schemaVersion\":6,\"dataVersion\":\"0.27.66\",\"dataSources\":[{\"name\":\"RefSeq\",\"version\":\"NC_045512.2\",\"description\":\"Severe acute respiratory syndrome coronavirus 2 (SARS-CoV2)\",\"releaseDate\":\"2020-03-20\"},{\"name\":\"alleleFrequency\",\"version\":\"SARS-COV-2_AllFreq.tsv\",\"releaseDate\":\"2020-05-08\"},{\"name\":\"proteinDomains\",\"version\":\"SARS-CoV-2_ProteinDomains.tsv\",\"releaseDate\":\"2020-05-08\"},{\"name\":\"MitochondrialHeteroplasmy\",\"version\":\"20180410\",\"description\":\"Variant read frequency percentiles for the Mitochondrial reference\",\"releaseDate\":\"2020-05-21\"}],\"samples\":[\"test\"]},\"positions\":[", + "{\"chromosome\":\"MT192765.1\",\"position\":197,\"refAllele\":\"G\",\"altAlleles\":[\"T\"],\"quality\":7.3081,\"filters\":[\"LowQual\"],\"mappingQuality\":60,\"samples\":[{\"genotype\":\"1/1\"}],\"variants\":[{\"vid\":\"MT192765.1-197-G-T\",\"chromosome\":\"MT192765.1\",\"begin\":197,\"end\":197,\"refAllele\":\"G\",\"altAllele\":\"T\",\"variantType\":\"SNV\",\"hgvsg\":\"MT192765.1:g.197G>T\"}]},", + "{\"chromosome\":\"MT192765.1\",\"position\":4788,\"refAllele\":\"C\",\"altAlleles\":[\"T\"],\"quality\":7.3081,\"filters\":[\"LowQual\"],\"mappingQuality\":60,\"samples\":[{\"genotype\":\"1/1\"}],\"variants\":[{\"vid\":\"MT192765.1-4788-C-T\",\"chromosome\":\"MT192765.1\",\"begin\":4788,\"end\":4788,\"refAllele\":\"C\",\"altAllele\":\"T\",\"variantType\":\"SNV\",\"hgvsg\":\"MT192765.1:g.4788C>T\"}]},", + "{\"chromosome\":\"MT192765.1\",\"position\":8236,\"refAllele\":\"C\",\"altAlleles\":[\"A\"],\"quality\":7.3081,\"filters\":[\"LowQual\"],\"mappingQuality\":60,\"samples\":[{\"genotype\":\"1/1\"}],\"variants\":[{\"vid\":\"MT192765.1-8236-C-A\",\"chromosome\":\"MT192765.1\",\"begin\":8236,\"end\":8236,\"refAllele\":\"C\",\"altAllele\":\"A\",\"variantType\":\"SNV\",\"hgvsg\":\"MT192765.1:g.8236C>A\"}]},", + "{\"chromosome\":\"MT192765.1\",\"position\":10506,\"refAllele\":\"TTATGACTGTGTCTCTTTTTGTTACATGCACCATATG\",\"altAlleles\":[\"TTATG\"],\"quality\":18.4617,\"filters\":[\"LowQual\"],\"mappingQuality\":60,\"samples\":[{\"genotype\":\"0/1\"}],\"variants\":[{\"vid\":\"MT192765.1-10510-NACTGTGTCTCTTTTTGTTACATGCACCATATG-N\",\"chromosome\":\"MT192765.1\",\"begin\":10511,\"end\":10542,\"refAllele\":\"ACTGTGTCTCTTTTTGTTACATGCACCATATG\",\"altAllele\":\"-\",\"variantType\":\"deletion\",\"hgvsg\":\"MT192765.1:g.10511_10542del\"}]},", + "{\"chromosome\":\"MT192765.1\",\"position\":11037,\"refAllele\":\"T\",\"altAlleles\":[\"C\"],\"quality\":7.3081,\"filters\":[\"LowQual\"],\"mappingQuality\":60,\"samples\":[{\"genotype\":\"1/1\"}],\"variants\":[{\"vid\":\"MT192765.1-11037-T-C\",\"chromosome\":\"MT192765.1\",\"begin\":11037,\"end\":11037,\"refAllele\":\"T\",\"altAllele\":\"C\",\"variantType\":\"SNV\",\"hgvsg\":\"MT192765.1:g.11037T>C\"}]},", + "{\"chromosome\":\"MT192765.1\",\"position\":15009,\"refAllele\":\"G\",\"altAlleles\":[\"A\"],\"quality\":30.4183,\"filters\":[\"LowQual\"],\"mappingQuality\":60,\"samples\":[{\"genotype\":\"1/1\"}],\"variants\":[{\"vid\":\"MT192765.1-15009-G-A\",\"chromosome\":\"MT192765.1\",\"begin\":15009,\"end\":15009,\"refAllele\":\"G\",\"altAllele\":\"A\",\"variantType\":\"SNV\",\"hgvsg\":\"MT192765.1:g.15009G>A\"}]},", + "{\"chromosome\":\"MT192765.1\",\"position\":18807,\"refAllele\":\"T\",\"altAlleles\":[\"C\"],\"quality\":136,\"filters\":[\"LowQual\"],\"mappingQuality\":60,\"samples\":[{\"genotype\":\"1/1\"}],\"variants\":[{\"vid\":\"MT192765.1-18807-T-C\",\"chromosome\":\"MT192765.1\",\"begin\":18807,\"end\":18807,\"refAllele\":\"T\",\"altAllele\":\"C\",\"variantType\":\"SNV\",\"hgvsg\":\"MT192765.1:g.18807T>C\"}]},", + "{\"chromosome\":\"MT192765.1\",\"position\":23813,\"refAllele\":\"T\",\"altAlleles\":[\"C\"],\"quality\":4.3847,\"filters\":[\"LowQual\"],\"mappingQuality\":60,\"samples\":[{\"genotype\":\"1/1\"}],\"variants\":[{\"vid\":\"MT192765.1-23813-T-C\",\"chromosome\":\"MT192765.1\",\"begin\":23813,\"end\":23813,\"refAllele\":\"T\",\"altAllele\":\"C\",\"variantType\":\"SNV\",\"hgvsg\":\"MT192765.1:g.23813T>C\"}]},", + "{\"chromosome\":\"MT192765.1\",\"position\":24103,\"refAllele\":\"A\",\"altAlleles\":[\"G\"],\"quality\":30.4183,\"filters\":[\"LowQual\"],\"mappingQuality\":60,\"samples\":[{\"genotype\":\"1/1\"}],\"variants\":[{\"vid\":\"MT192765.1-24103-A-G\",\"chromosome\":\"MT192765.1\",\"begin\":24103,\"end\":24103,\"refAllele\":\"A\",\"altAllele\":\"G\",\"variantType\":\"SNV\",\"hgvsg\":\"MT192765.1:g.24103A>G\"}]}", + "]}" + ] + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-01-12T09:27:01.830246" + }, + "sarscov2 - vcf": { + "content": [ + [ + [ + "NIRVANA", + "nirvana", + "Nirvana 3.18.1" + ] + ] + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-01-12T09:27:01.842455" + }, + "sarscov2 - vcf - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.json.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + [ + { + "id": "test" + }, + "test.json.gz.jsi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + "NIRVANA", + "nirvana", + "Nirvana 3.18.1" + ] + ], + "jsi": [ + [ + { + "id": "test" + }, + "test.json.gz.jsi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "json": [ + [ + { + "id": "test" + }, + "test.json.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions_nirvana": [ + [ + "NIRVANA", + "nirvana", + "Nirvana 3.18.1" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-01-12T09:27:21.144398" + } +} \ No newline at end of file