diff --git a/modules/nf-core/fgumi/sort/environment.yml b/modules/nf-core/fgumi/sort/environment.yml new file mode 100644 index 000000000000..a271e6a0e69a --- /dev/null +++ b/modules/nf-core/fgumi/sort/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: + - bioconda::fgumi=0.1.2 + - conda-forge::r-base=4.5.3 + - conda-forge::r-ggplot2=4.0.2 + - conda-forge::r-scales=1.4.0 diff --git a/modules/nf-core/fgumi/sort/main.nf b/modules/nf-core/fgumi/sort/main.nf new file mode 100644 index 000000000000..a58f52a49e98 --- /dev/null +++ b/modules/nf-core/fgumi/sort/main.nf @@ -0,0 +1,44 @@ +process FGUMI_SORT { + tag "${meta.id}" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/95/954170443a820787c9e02ef2135ebb8ec29c6b03633b0d61b5fafa98c59a1cce/data' + : 'community.wave.seqera.io/library/fgumi_r-base_r-ggplot2_r-scales:09c99070b82c1c28'}" + + input: + tuple val(meta), path(bam) + + output: + tuple val(meta), path("*.bam"), emit: bam + tuple val(meta), path("*.bam.bai"), emit: bai, optional: true + tuple val("${task.process}"), val('fgumi'), eval("fgumi --version | sed -n 's/^fgumi //p'"), topic: versions, emit: versions_fgumi + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + fgumi sort \\ + ${args} \\ + --threads ${task.cpus} \\ + --tmp-dir \$PWD \\ + --input ${bam} \\ + --output ${prefix}.bam + + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + echo ${args} + + touch ${prefix}.bam + """ +} diff --git a/modules/nf-core/fgumi/sort/meta.yml b/modules/nf-core/fgumi/sort/meta.yml new file mode 100644 index 000000000000..17687e8482cd --- /dev/null +++ b/modules/nf-core/fgumi/sort/meta.yml @@ -0,0 +1,79 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json +name: "fgumi_sort" +description: Sort a BAM file using high-performance external merge-sort +keywords: + - sort + - bam + - sam +tools: + - "fgumi": + description: "High-performance tools for UMI-tagged sequencing data." + homepage: "https://github.com/fulcrumgenomics/fgumi/blob/v0.1.2/README.md" + documentation: "https://github.com/fulcrumgenomics/fgumi/blob/v0.1.2/README.md" + tool_dev_url: "https://github.com/fulcrumgenomics/fgumi" + licence: ["MIT"] + +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - bam: + type: file + description: Unsorted BAM file + pattern: "*.{bam}" + ontologies: + - edam: "http://edamontology.org/format_2572" # BAM + +output: + bam: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*.bam": + type: file + description: Sorted BAM file + pattern: "*.{bam}" + ontologies: + - edam: "http://edamontology.org/format_2572" # BAM + bai: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*.bam.bai": + type: file + description: BAM index file + pattern: "*.bam.bai" + ontologies: + - edam: "http://edamontology.org/format_2573" # BAM index + versions_fgumi: + - - "${task.process}": + type: string + description: The name of the process + - "fgumi": + type: string + description: The name of the tool + - "fgumi --version | sed -n 's/^fgumi //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 + - fgumi: + type: string + description: The name of the tool + - fgumi --version | sed -n 's/^fgumi //p': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@matthdsm" +maintainers: + - "@matthdsm" diff --git a/modules/nf-core/fgumi/sort/tests/main.nf.test b/modules/nf-core/fgumi/sort/tests/main.nf.test new file mode 100644 index 000000000000..4a99af326440 --- /dev/null +++ b/modules/nf-core/fgumi/sort/tests/main.nf.test @@ -0,0 +1,97 @@ +nextflow_process { + + name "Test Process FGUMI_SORT" + script "../main.nf" + process "FGUMI_SORT" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "fgumi" + tag "fgumi/sort" + + test("bam - coordinate sort - index") { + + when { + params { + fgumi_args = '--order coordinate --write-index' + } + process { + """ + input[0] = [ + [ id:'test', single_end:false ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/umi/test.paired_end.duplex_umi_mapped.bam', checkIfExists: true) + ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + process.out, + path(process.out.versions[0]).yaml + ).match() } + ) + } + } + + test("bam - queryname sort - no index") { + + when { + params { + fgumi_args = '--order queryname' + } + process { + """ + input[0] = [ + [ id:'test', single_end:false ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/umi/test.paired_end.duplex_umi_mapped.bam', checkIfExists: true) + ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + process.out, + path(process.out.versions[0]).yaml + ).match() } + ) + } + } + + test("bam - coordinate sort - stub") { + + options "-stub" + + when { + params { + fgumi_args = '--order coordinate --write-index' + } + process { + """ + input[0] = [ + [ id:'test', single_end:false ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/umi/test.paired_end.duplex_umi_mapped.bam', checkIfExists: true) + ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + process.out, + path(process.out.versions[0]).yaml + ).match() } + ) + } + + } + +} diff --git a/modules/nf-core/fgumi/sort/tests/nextflow.config b/modules/nf-core/fgumi/sort/tests/nextflow.config new file mode 100644 index 000000000000..cdd1016ef08f --- /dev/null +++ b/modules/nf-core/fgumi/sort/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: FGUMI_SORT { + ext.args = params.fgumi_args + } +} diff --git a/modules/nf-core/fgumi/zipper/environment.yml b/modules/nf-core/fgumi/zipper/environment.yml new file mode 100644 index 000000000000..a271e6a0e69a --- /dev/null +++ b/modules/nf-core/fgumi/zipper/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: + - bioconda::fgumi=0.1.2 + - conda-forge::r-base=4.5.3 + - conda-forge::r-ggplot2=4.0.2 + - conda-forge::r-scales=1.4.0 diff --git a/modules/nf-core/fgumi/zipper/main.nf b/modules/nf-core/fgumi/zipper/main.nf new file mode 100644 index 000000000000..5336be610c65 --- /dev/null +++ b/modules/nf-core/fgumi/zipper/main.nf @@ -0,0 +1,43 @@ +process FGUMI_ZIPPER { + tag "${meta.id}" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/95/954170443a820787c9e02ef2135ebb8ec29c6b03633b0d61b5fafa98c59a1cce/data' + : 'community.wave.seqera.io/library/fgumi_r-base_r-ggplot2_r-scales:09c99070b82c1c28'}" + + input: + tuple val(meta), path(mapped, stageAs: "mapped/*"), path(unmapped, stageAs: "unmapped/*") + tuple val(meta2), path(fasta), path(fasta_index), path(fasta_dict) + + output: + tuple val(meta), path("*.bam"), emit: bam + tuple val("${task.process}"), val('fgumi'), eval("fgumi --version | sed -n 's/^fgumi //p'"), topic: versions, emit: versions_fgumi + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + fgumi zipper \\ + ${args} \\ + --input ${mapped} \\ + --unmapped ${unmapped} \\ + --reference ${fasta} \\ + --threads ${task.cpus} \\ + --output ${prefix}.bam + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + echo ${args} + + touch ${prefix}.bam + """ +} diff --git a/modules/nf-core/fgumi/zipper/meta.yml b/modules/nf-core/fgumi/zipper/meta.yml new file mode 100644 index 000000000000..ce524a50c7ea --- /dev/null +++ b/modules/nf-core/fgumi/zipper/meta.yml @@ -0,0 +1,98 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json +name: "fgumi_zipper" +description: Merge unmapped and mapped BAM files, transferring tags and metadata. +keywords: + - fgbio + - umi + - unmapped + - ubam + - zipperbams +tools: + - "fgumi": + description: "High-performance tools for UMI-tagged sequencing data." + homepage: "https://github.com/fulcrumgenomics/fgumi/blob/v0.1.2/README.md" + documentation: "https://github.com/fulcrumgenomics/fgumi/blob/v0.1.2/README.md" + tool_dev_url: "https://github.com/fulcrumgenomics/fgumi" + licence: ["MIT"] + +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - mapped: + type: file + description: mapped BAM/SAM file + pattern: "*.{bam, sam}" + ontologies: + - edam: "http://edamontology.org/format_2572" # BAM + - edam: "http://edamontology.org/format_3462" # SAM + - unmapped: + type: file + description: unmapped BAM file + pattern: "*.bam" + ontologies: + - edam: "http://edamontology.org/format_2572" # BAM + - - meta2: + type: map + description: | + Groovy Map containing reference information + e.g. `[ id:'GRCh38' ]` + - fasta: + type: file + description: fasta file containing genomic sequence information + pattern: "*.{fasta,fna,fa}" + ontologies: + - edam: "http://edamontology.org/format_1929" # FASTA + - fasta_index: + type: file + description: fasta index file + pattern: "*.fai" + ontologies: + - edam: "http://edamontology.org/format_2573" # BAM index + - fasta_dict: + type: file + description: dict file containing a sequence dictionary for the fasta file + pattern: "*.dict" + ontologies: [] + +output: + bam: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*.bam": + type: file + description: Merged BAM file + pattern: "*.{bam}" + ontologies: + - edam: "http://edamontology.org/format_2572" # BAM + versions_fgumi: + - - "${task.process}": + type: string + description: The name of the process + - "fgumi": + type: string + description: The name of the tool + - "fgumi --version | sed -n 's/^fgumi //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 + - fgumi: + type: string + description: The name of the tool + - fgumi --version | sed -n 's/^fgumi //p': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@matthdsm" +maintainers: + - "@matthdsm" diff --git a/modules/nf-core/fgumi/zipper/tests/main.nf.test b/modules/nf-core/fgumi/zipper/tests/main.nf.test new file mode 100644 index 000000000000..49707d785c30 --- /dev/null +++ b/modules/nf-core/fgumi/zipper/tests/main.nf.test @@ -0,0 +1,103 @@ +nextflow_process { + + name "Test Process FGUMI_ZIPPER" + script "../main.nf" + process "FGUMI_ZIPPER" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "fgumi" + tag "fgumi/sort" + tag "fgumi/zipper" + + setup { + run("FGUMI_SORT", alias: "FGUMI_SORT_MAPPED") { + script "../../sort/main.nf" + process { + """ + input[0] = [ + [ id:'test', single_end:false ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/umi/test.paired_end.duplex_umi_mapped.bam', checkIfExists: true) + ] + """ + } + } + run("FGUMI_SORT", alias: "FGUMI_SORT_UNMAPPED") { + script "../../sort/main.nf" + process { + """ + input[0] = [ + [ id:'test', single_end:false ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/umi/test.paired_end.duplex_umi_unmapped.bam', checkIfExists: true) + ] + """ + } + } + } + + test("homo_sapiens - bam") { + when { + params { + fgumi_args = '--tags-to-reverse Consensus --tags-to-revcomp Consensus' + } + process { + """ + input[0] = FGUMI_SORT_MAPPED.out.bam.join(FGUMI_SORT_UNMAPPED.out.bam) + input[1] = [ + [ id:'genome'], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.dict', checkIfExists: true) + ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + process.out, + path(process.out.versions[0]).yaml + ).match() } + ) + } + + } + + test("homo_sapiens - bam - stub") { + options "-stub" + when { + params { + fgumi_args = '--tags-to-reverse Consensus --tags-to-revcomp Consensus' + } + process { + """ + input[0] = [ + [ id:'test', single_end:false ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/umi/test.paired_end.duplex_umi_mapped.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/umi/test.paired_end.duplex_umi_unmapped.bam', checkIfExists: true) + ] + input[1] = [ + [ id:'genome'], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.dict', checkIfExists: true) + ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + process.out, + path(process.out.versions[0]).yaml + ).match() } + ) + } + + } +} diff --git a/modules/nf-core/fgumi/zipper/tests/nextflow.config b/modules/nf-core/fgumi/zipper/tests/nextflow.config new file mode 100644 index 000000000000..602fb9c84403 --- /dev/null +++ b/modules/nf-core/fgumi/zipper/tests/nextflow.config @@ -0,0 +1,9 @@ +process { + withName: 'FGUMI_SORT.*' { + ext.args = "--order queryname" + } + + withName: FGUMI_ZIPPER { + ext.args = params.fgumi_args + } +}