From 3bc91df24685cfc5871a03252f82dd0c6f1844ac Mon Sep 17 00:00:00 2001 From: Barry digby Date: Mon, 12 Dec 2022 20:22:52 +0000 Subject: [PATCH 001/491] ch_versions.unique() --- workflows/circrna.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflows/circrna.nf b/workflows/circrna.nf index 7422dc54..d43b430e 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -208,7 +208,7 @@ workflow CIRCRNA { ch_versions = ch_versions.mix(DIFFERENTIAL_EXPRESSION.out.versions) CUSTOM_DUMPSOFTWAREVERSIONS ( - ch_versions.unique{ it.text }.collectFile(name: 'collated_versions.yml') + ch_versions.unique().collectFile(name: 'collated_versions.yml') ) // MODULE: MultiQC From b942c7eb7d30ead94d34ce2862bd8e4713035613 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Tue, 13 Dec 2022 10:28:09 +0000 Subject: [PATCH 002/491] release version --- CHANGELOG.md | 2 +- nextflow.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d24a1785..465d994c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## v1.0.0 - [date] +## v1.0.0 - [13/12/2022] Initial release of nf-core/circrna, created with the [nf-core](https://nf-co.re/) template. diff --git a/nextflow.config b/nextflow.config index 2120cb54..c33b8ce2 100644 --- a/nextflow.config +++ b/nextflow.config @@ -249,7 +249,7 @@ manifest { description = """Quantification, miRNA target prediction and differential expression analysis of circular RNAs""" mainScript = 'main.nf' nextflowVersion = '!>=22.10.1' - version = 'dev' + version = '1.0.0' doi = '' } From 2bc935a1b49de21b249a1d574bbde403f29785b5 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Tue, 13 Dec 2022 11:11:19 +0000 Subject: [PATCH 003/491] publishdir tweaks --- conf/modules.config | 48 ++++++++++++++----- .../deseq2/differential_expression/main.nf | 2 +- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index b44dd7c1..f535f691 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -75,7 +75,7 @@ if (!params.skip_trimming) { withName: BOWTIE_BUILD { ext.when = { params.fasta && !params.bowtie && params.tool.split(',').contains('mapsplice') && params.module.split(',').contains('circrna_discovery') } publishDir = [ - path: { "${params.outdir}/genome/index/bowtie" }, + path: { "${params.outdir}/references/index/bowtie" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_reference @@ -85,7 +85,7 @@ if (!params.skip_trimming) { withName: BOWTIE2_BUILD { ext.when = { params.fasta && !params.bowtie2 && params.tool.split(',').contains('find_circ') && params.module.split(',').contains('circrna_discovery') } publishDir = [ - path: { "${params.outdir}/genome/index" }, + path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_reference @@ -95,7 +95,7 @@ if (!params.skip_trimming) { withName: BWA_INDEX { ext.when = { params.fasta && !params.bwa && params.tool.split(',').contains('ciriquant') && params.module.split(',').contains('circrna_discovery') } publishDir = [ - path: { "${params.outdir}/genome/index" }, + path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_reference @@ -105,7 +105,7 @@ if (!params.skip_trimming) { withName: HISAT2_EXTRACTSPLICESITES { ext.when = { params.fasta && params.gtf && ( params.module.split(',').contains('differential_expression') || params.tool.split(',').contains('ciriquant') ) } publishDir = [ - path: { "${params.outdir}/genome/index/hisat2" }, + path: { "${params.outdir}/references/index/hisat2" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_reference @@ -115,7 +115,7 @@ if (!params.skip_trimming) { withName: HISAT2_BUILD { ext.when = { params.fasta && params.gtf && ( params.module.split(',').contains('differential_expression') || params.tool.split(',').contains('ciriquant') ) } publishDir = [ - path: { "${params.outdir}/genome/index/hisat2" }, + path: { "${params.outdir}/references/index/hisat2" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_reference @@ -128,7 +128,7 @@ if (!params.skip_trimming) { params.sjdboverhang ? "--sjdbOverhang ${params.sjdboverhang}" : '', ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/genome/index/star" }, + path: { "${params.outdir}/references/index/star" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_reference @@ -138,7 +138,7 @@ if (!params.skip_trimming) { withName: SEGEMEHL_INDEX { ext.when = { params.fasta && !params.segemehl && params.tool.split(',').contains('segemehl') && params.module.split(',').contains('circrna_discovery') } publishDir = [ - path: { "${params.outdir}/genome/index/segemehl" }, + path: { "${params.outdir}/references/index/segemehl" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_reference @@ -231,7 +231,7 @@ if (!params.skip_trimming) { "-geneNameAsName2" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/genome/circexplorer2" }, + path: { "${params.outdir}/references/circexplorer2" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_reference @@ -344,7 +344,7 @@ if (!params.skip_trimming) { withName: CIRIQUANT_YML { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('ciriquant') } publishDir = [ - path: { "${params.outdir}/genome/ciriquant" }, + path: { "${params.outdir}/references/ciriquant" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_reference @@ -546,7 +546,7 @@ if (!params.skip_trimming) { "-geneNameAsName2" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/genome/mapsplice" }, + path: { "${params.outdir}/references/mapsplice" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_reference @@ -636,12 +636,18 @@ withName: MAPSPLICE_PARSE { path: { "${params.outdir}/circrna_discovery/" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - pattern: "*.txt" + pattern: "count_matrix.txt" ] } withName: TARGETSCAN_DATABASE { ext.when = { params.module.split(',').contains('mirna_prediction') } + publishDir = [ + path: { "${params.outdir}/references/targetscan" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + pattern: "mature.txt" + ] } withName: TARGETSCAN { @@ -685,6 +691,12 @@ withName: MAPSPLICE_PARSE { "--dta", "--no-spliced-alignment" ].join(' ').trim() + publishDir = [ + path: { "${params.outdir}/differential_expression/intermediates/hisat2/" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + enabled: params.save_intermediates, + ] } withName: SAMTOOLS_SORT { @@ -729,8 +741,22 @@ withName: MAPSPLICE_PARSE { ] } + withName: PARENT_GENE { + ext.when = { params.module.split(',').contains('differential_expression') } + publishDir = [ + path: { "${params.outdir}/differential_expression/circular_linear_ratio_test" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + withName: PREPARE_CLR_TEST { ext.when = { params.module.split(',').contains('differential_expression') } + publishDir = [ + path: { "${params.outdir}/differential_expression/circular_linear_ratio_test" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] } withName: CIRCTEST { diff --git a/modules/local/deseq2/differential_expression/main.nf b/modules/local/deseq2/differential_expression/main.nf index 83bf6bca..f9b5dacc 100644 --- a/modules/local/deseq2/differential_expression/main.nf +++ b/modules/local/deseq2/differential_expression/main.nf @@ -17,7 +17,6 @@ process DESEQ2_DIFFERENTIAL_EXPRESSION { path "circRNA" , emit: circular_results path "RNA-Seq" , emit: linear_results path "DESeq2_QC" , emit: deseq2_qc - path "*.RData" , emit: rsession path "versions.yml", emit: versions when: @@ -33,6 +32,7 @@ process DESEQ2_DIFFERENTIAL_EXPRESSION { DEA.R $gene_matrix $phenotype $circrna_matrix $species ensembl_database_map.txt mv boxplots/ circRNA/ + mv *.RData DESeq2_QC/ cat <<-END_VERSIONS > versions.yml "${task.process}": From 134217d3d41d381ac907ca7142b605c1fb6bf2a6 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Mon, 19 Dec 2022 12:04:47 +0000 Subject: [PATCH 004/491] Template update for nf-core/tools version 2.7.2 --- .github/workflows/fix-linting.yml | 4 +- .github/workflows/linting_comment.yml | 2 +- README.md | 2 +- assets/email_template.html | 2 +- lib/WorkflowMain.groovy | 2 +- modules.json | 6 +- modules/local/samplesheet_check.nf | 2 +- .../custom/dumpsoftwareversions/main.nf | 2 +- .../templates/dumpsoftwareversions.py | 99 ++++++++++--------- modules/nf-core/fastqc/main.nf | 40 +++----- modules/nf-core/multiqc/main.nf | 2 +- nextflow.config | 5 +- nextflow_schema.json | 8 +- workflows/circrna.nf | 2 +- 14 files changed, 86 insertions(+), 92 deletions(-) mode change 100644 => 100755 modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py diff --git a/.github/workflows/fix-linting.yml b/.github/workflows/fix-linting.yml index 7e2c46b3..bdf7eb2c 100644 --- a/.github/workflows/fix-linting.yml +++ b/.github/workflows/fix-linting.yml @@ -34,9 +34,9 @@ jobs: id: prettier_status run: | if prettier --check ${GITHUB_WORKSPACE}; then - echo "name=result::pass" >> $GITHUB_OUTPUT + echo "result=pass" >> $GITHUB_OUTPUT else - echo "name=result::fail" >> $GITHUB_OUTPUT + echo "result=fail" >> $GITHUB_OUTPUT fi - name: Run 'prettier --write' diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index 39635186..0bbcd30f 100644 --- a/.github/workflows/linting_comment.yml +++ b/.github/workflows/linting_comment.yml @@ -18,7 +18,7 @@ jobs: - name: Get PR number id: pr_number - run: echo "name=pr_number::$(cat linting-logs/PR_number.txt)" >> $GITHUB_OUTPUT + run: echo "pr_number=$(cat linting-logs/PR_number.txt)" >> $GITHUB_OUTPUT - name: Post PR comment uses: marocchino/sticky-pull-request-comment@v2 diff --git a/README.md b/README.md index f3e31f4e..75428759 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ -**nf-core/circrna** is a bioinformatics best-practice analysis pipeline for circRNA quantification, differential expression analysis and miRNA target prediction of RNA-Seq data. +**nf-core/circrna** is a bioinformatics best-practice analysis pipeline for Quantification, miRNA target prediction and differential expression analysis of circular RNAs. The pipeline is built using [Nextflow](https://www.nextflow.io), a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It uses Docker/Singularity containers making installation trivial and results highly reproducible. The [Nextflow DSL2](https://www.nextflow.io/docs/latest/dsl2.html) implementation of this pipeline uses one container per process which makes it much easier to maintain and update software dependencies. Where possible, these processes have been submitted to and installed from [nf-core/modules](https://github.com/nf-core/modules) in order to make them available to all nf-core pipelines, and to everyone within the Nextflow community! diff --git a/assets/email_template.html b/assets/email_template.html index 0052d4b9..03b6ba6e 100644 --- a/assets/email_template.html +++ b/assets/email_template.html @@ -4,7 +4,7 @@ - + nf-core/circrna Pipeline Report diff --git a/lib/WorkflowMain.groovy b/lib/WorkflowMain.groovy index 04b19a7d..0d7be86b 100755 --- a/lib/WorkflowMain.groovy +++ b/lib/WorkflowMain.groovy @@ -72,7 +72,7 @@ class WorkflowMain { NfcoreTemplate.checkConfigProvided(workflow, log) // Check that conda channels are set-up correctly - if (params.enable_conda) { + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { Utils.checkCondaChannels(log) } diff --git a/modules.json b/modules.json index 221a73c6..5b7c59e8 100644 --- a/modules.json +++ b/modules.json @@ -7,17 +7,17 @@ "nf-core": { "custom/dumpsoftwareversions": { "branch": "master", - "git_sha": "5e34754d42cd2d5d248ca8673c0a53cdf5624905", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "fastqc": { "branch": "master", - "git_sha": "5e34754d42cd2d5d248ca8673c0a53cdf5624905", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "multiqc": { "branch": "master", - "git_sha": "5e34754d42cd2d5d248ca8673c0a53cdf5624905", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] } } diff --git a/modules/local/samplesheet_check.nf b/modules/local/samplesheet_check.nf index 33f77b6e..4e85a56e 100644 --- a/modules/local/samplesheet_check.nf +++ b/modules/local/samplesheet_check.nf @@ -2,7 +2,7 @@ process SAMPLESHEET_CHECK { tag "$samplesheet" label 'process_single' - conda (params.enable_conda ? "conda-forge::python=3.8.3" : null) + conda "conda-forge::python=3.8.3" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/python:3.8.3' : 'quay.io/biocontainers/python:3.8.3' }" diff --git a/modules/nf-core/custom/dumpsoftwareversions/main.nf b/modules/nf-core/custom/dumpsoftwareversions/main.nf index cebb6e05..3df21765 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/main.nf +++ b/modules/nf-core/custom/dumpsoftwareversions/main.nf @@ -2,7 +2,7 @@ process CUSTOM_DUMPSOFTWAREVERSIONS { label 'process_single' // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container - conda (params.enable_conda ? 'bioconda::multiqc=1.13' : null) + conda "bioconda::multiqc=1.13" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/multiqc:1.13--pyhdfd78af_0' : 'quay.io/biocontainers/multiqc:1.13--pyhdfd78af_0' }" diff --git a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py old mode 100644 new mode 100755 index 787bdb7b..e55b8d43 --- a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py +++ b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py @@ -1,5 +1,9 @@ #!/usr/bin/env python + +"""Provide functions to merge multiple versions.yml files.""" + + import platform from textwrap import dedent @@ -7,6 +11,7 @@ def _make_versions_html(versions): + """Generate a tabular HTML output of all versions for MultiQC.""" html = [ dedent( """\\ @@ -45,47 +50,53 @@ def _make_versions_html(versions): return "\\n".join(html) -versions_this_module = {} -versions_this_module["${task.process}"] = { - "python": platform.python_version(), - "yaml": yaml.__version__, -} - -with open("$versions") as f: - versions_by_process = yaml.load(f, Loader=yaml.BaseLoader) | versions_this_module - -# aggregate versions by the module name (derived from fully-qualified process name) -versions_by_module = {} -for process, process_versions in versions_by_process.items(): - module = process.split(":")[-1] - try: - if versions_by_module[module] != process_versions: - raise AssertionError( - "We assume that software versions are the same between all modules. " - "If you see this error-message it means you discovered an edge-case " - "and should open an issue in nf-core/tools. " - ) - except KeyError: - versions_by_module[module] = process_versions - -versions_by_module["Workflow"] = { - "Nextflow": "$workflow.nextflow.version", - "$workflow.manifest.name": "$workflow.manifest.version", -} - -versions_mqc = { - "id": "software_versions", - "section_name": "${workflow.manifest.name} Software Versions", - "section_href": "https://github.com/${workflow.manifest.name}", - "plot_type": "html", - "description": "are collected at run time from the software output.", - "data": _make_versions_html(versions_by_module), -} - -with open("software_versions.yml", "w") as f: - yaml.dump(versions_by_module, f, default_flow_style=False) -with open("software_versions_mqc.yml", "w") as f: - yaml.dump(versions_mqc, f, default_flow_style=False) - -with open("versions.yml", "w") as f: - yaml.dump(versions_this_module, f, default_flow_style=False) +def main(): + """Load all version files and generate merged output.""" + versions_this_module = {} + versions_this_module["${task.process}"] = { + "python": platform.python_version(), + "yaml": yaml.__version__, + } + + with open("$versions") as f: + versions_by_process = yaml.load(f, Loader=yaml.BaseLoader) | versions_this_module + + # aggregate versions by the module name (derived from fully-qualified process name) + versions_by_module = {} + for process, process_versions in versions_by_process.items(): + module = process.split(":")[-1] + try: + if versions_by_module[module] != process_versions: + raise AssertionError( + "We assume that software versions are the same between all modules. " + "If you see this error-message it means you discovered an edge-case " + "and should open an issue in nf-core/tools. " + ) + except KeyError: + versions_by_module[module] = process_versions + + versions_by_module["Workflow"] = { + "Nextflow": "$workflow.nextflow.version", + "$workflow.manifest.name": "$workflow.manifest.version", + } + + versions_mqc = { + "id": "software_versions", + "section_name": "${workflow.manifest.name} Software Versions", + "section_href": "https://github.com/${workflow.manifest.name}", + "plot_type": "html", + "description": "are collected at run time from the software output.", + "data": _make_versions_html(versions_by_module), + } + + with open("software_versions.yml", "w") as f: + yaml.dump(versions_by_module, f, default_flow_style=False) + with open("software_versions_mqc.yml", "w") as f: + yaml.dump(versions_mqc, f, default_flow_style=False) + + with open("versions.yml", "w") as f: + yaml.dump(versions_this_module, f, default_flow_style=False) + + +if __name__ == "__main__": + main() diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf index 05730368..9ae58381 100644 --- a/modules/nf-core/fastqc/main.nf +++ b/modules/nf-core/fastqc/main.nf @@ -2,7 +2,7 @@ process FASTQC { tag "$meta.id" label 'process_medium' - conda (params.enable_conda ? "bioconda::fastqc=0.11.9" : null) + conda "bioconda::fastqc=0.11.9" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/fastqc:0.11.9--0' : 'quay.io/biocontainers/fastqc:0.11.9--0' }" @@ -20,30 +20,22 @@ process FASTQC { script: def args = task.ext.args ?: '' - // Add soft-links to original FastQs for consistent naming in pipeline def prefix = task.ext.prefix ?: "${meta.id}" - if (meta.single_end) { - """ - [ ! -f ${prefix}.fastq.gz ] && ln -s $reads ${prefix}.fastq.gz - fastqc $args --threads $task.cpus ${prefix}.fastq.gz - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - fastqc: \$( fastqc --version | sed -e "s/FastQC v//g" ) - END_VERSIONS - """ - } else { - """ - [ ! -f ${prefix}_1.fastq.gz ] && ln -s ${reads[0]} ${prefix}_1.fastq.gz - [ ! -f ${prefix}_2.fastq.gz ] && ln -s ${reads[1]} ${prefix}_2.fastq.gz - fastqc $args --threads $task.cpus ${prefix}_1.fastq.gz ${prefix}_2.fastq.gz - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - fastqc: \$( fastqc --version | sed -e "s/FastQC v//g" ) - END_VERSIONS - """ - } + // Make list of old name and new name pairs to use for renaming in the bash while loop + def old_new_pairs = reads instanceof Path || reads.size() == 1 ? [[ reads, "${prefix}.${reads.extension}" ]] : reads.withIndex().collect { entry, index -> [ entry, "${prefix}_${index + 1}.${entry.extension}" ] } + def rename_to = old_new_pairs*.join(' ').join(' ') + def renamed_files = old_new_pairs.collect{ old_name, new_name -> new_name }.join(' ') + """ + printf "%s %s\\n" $rename_to | while read old_name new_name; do + [ -f "\${new_name}" ] || ln -s \$old_name \$new_name + done + fastqc $args --threads $task.cpus $renamed_files + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + fastqc: \$( fastqc --version | sed -e "s/FastQC v//g" ) + END_VERSIONS + """ stub: def prefix = task.ext.prefix ?: "${meta.id}" diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index a8159a57..68f66bea 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,7 +1,7 @@ process MULTIQC { label 'process_single' - conda (params.enable_conda ? 'bioconda::multiqc=1.13' : null) + conda "bioconda::multiqc=1.13" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/multiqc:1.13--pyhdfd78af_0' : 'quay.io/biocontainers/multiqc:1.13--pyhdfd78af_0' }" diff --git a/nextflow.config b/nextflow.config index 31883ad1..eabafb20 100644 --- a/nextflow.config +++ b/nextflow.config @@ -39,7 +39,6 @@ params { validate_params = true show_hidden_params = false schema_ignore_params = 'genomes' - enable_conda = false // Config options @@ -81,7 +80,6 @@ try { profiles { debug { process.beforeScript = 'echo $HOSTNAME' } conda { - params.enable_conda = true conda.enabled = true docker.enabled = false singularity.enabled = false @@ -90,7 +88,6 @@ profiles { charliecloud.enabled = false } mamba { - params.enable_conda = true conda.enabled = true conda.useMamba = true docker.enabled = false @@ -193,7 +190,7 @@ manifest { name = 'nf-core/circrna' author = """Barry Digby""" homePage = 'https://github.com/nf-core/circrna' - description = """circRNA quantification, differential expression analysis and miRNA target prediction of RNA-Seq data""" + description = """Quantification, miRNA target prediction and differential expression analysis of circular RNAs""" mainScript = 'main.nf' nextflowVersion = '!>=22.10.1' version = '1.0.0' diff --git a/nextflow_schema.json b/nextflow_schema.json index 45425578..b225d480 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -2,7 +2,7 @@ "$schema": "http://json-schema.org/draft-07/schema", "$id": "https://raw.githubusercontent.com/nf-core/circrna/master/nextflow_schema.json", "title": "nf-core/circrna pipeline parameters", - "description": "circRNA quantification, differential expression analysis and miRNA target prediction of RNA-Seq data", + "description": "Quantification, miRNA target prediction and differential expression analysis of circular RNAs", "type": "object", "definitions": { "input_output_options": { @@ -263,12 +263,6 @@ "description": "Show all params when using `--help`", "hidden": true, "help_text": "By default, parameters set as _hidden_ in the schema are not shown on the command line when a user runs with `--help`. Specifying this option will tell the pipeline to show all parameters." - }, - "enable_conda": { - "type": "boolean", - "description": "Run this workflow with Conda. You can also use '-profile conda' instead of providing this parameter.", - "hidden": true, - "fa_icon": "fas fa-bacon" } } } diff --git a/workflows/circrna.nf b/workflows/circrna.nf index 400c3a57..448b8fb1 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -82,7 +82,7 @@ workflow CIRCRNA { ch_versions = ch_versions.mix(FASTQC.out.versions.first()) CUSTOM_DUMPSOFTWAREVERSIONS ( - ch_versions.unique{ it.text }.collectFile(name: 'collated_versions.yml') + ch_versions.unique().collectFile(name: 'collated_versions.yml') ) // From 080056da97d8c50bd48b54da0de3be7b18ea012f Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Mon, 19 Dec 2022 12:04:47 +0000 Subject: [PATCH 005/491] Template update for nf-core/tools version 2.7.2 --- .github/workflows/fix-linting.yml | 4 ++-- .github/workflows/linting_comment.yml | 2 +- lib/WorkflowMain.groovy | 2 +- modules.json | 6 +++--- modules/local/samplesheet_check.nf | 2 +- modules/nf-core/custom/dumpsoftwareversions/main.nf | 2 +- .../dumpsoftwareversions/templates/dumpsoftwareversions.py | 3 ++- modules/nf-core/fastqc/main.nf | 2 +- modules/nf-core/multiqc/main.nf | 2 +- nextflow.config | 3 --- nextflow_schema.json | 6 ------ 11 files changed, 13 insertions(+), 21 deletions(-) diff --git a/.github/workflows/fix-linting.yml b/.github/workflows/fix-linting.yml index 7e2c46b3..bdf7eb2c 100644 --- a/.github/workflows/fix-linting.yml +++ b/.github/workflows/fix-linting.yml @@ -34,9 +34,9 @@ jobs: id: prettier_status run: | if prettier --check ${GITHUB_WORKSPACE}; then - echo "name=result::pass" >> $GITHUB_OUTPUT + echo "result=pass" >> $GITHUB_OUTPUT else - echo "name=result::fail" >> $GITHUB_OUTPUT + echo "result=fail" >> $GITHUB_OUTPUT fi - name: Run 'prettier --write' diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index 39635186..0bbcd30f 100644 --- a/.github/workflows/linting_comment.yml +++ b/.github/workflows/linting_comment.yml @@ -18,7 +18,7 @@ jobs: - name: Get PR number id: pr_number - run: echo "name=pr_number::$(cat linting-logs/PR_number.txt)" >> $GITHUB_OUTPUT + run: echo "pr_number=$(cat linting-logs/PR_number.txt)" >> $GITHUB_OUTPUT - name: Post PR comment uses: marocchino/sticky-pull-request-comment@v2 diff --git a/lib/WorkflowMain.groovy b/lib/WorkflowMain.groovy index 04b19a7d..0d7be86b 100755 --- a/lib/WorkflowMain.groovy +++ b/lib/WorkflowMain.groovy @@ -72,7 +72,7 @@ class WorkflowMain { NfcoreTemplate.checkConfigProvided(workflow, log) // Check that conda channels are set-up correctly - if (params.enable_conda) { + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { Utils.checkCondaChannels(log) } diff --git a/modules.json b/modules.json index 5e7f3bc3..d750d640 100644 --- a/modules.json +++ b/modules.json @@ -12,7 +12,7 @@ }, "bowtie/build": { "branch": "master", - "git_sha": "5e34754d42cd2d5d248ca8673c0a53cdf5624905", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "bowtie2/align": { @@ -32,7 +32,7 @@ }, "cat/fastq": { "branch": "master", - "git_sha": "5e34754d42cd2d5d248ca8673c0a53cdf5624905", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "circexplorer2/annotate": { @@ -77,7 +77,7 @@ }, "multiqc": { "branch": "master", - "git_sha": "5e34754d42cd2d5d248ca8673c0a53cdf5624905", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "samtools/index": { diff --git a/modules/local/samplesheet_check.nf b/modules/local/samplesheet_check.nf index 33f77b6e..4e85a56e 100644 --- a/modules/local/samplesheet_check.nf +++ b/modules/local/samplesheet_check.nf @@ -2,7 +2,7 @@ process SAMPLESHEET_CHECK { tag "$samplesheet" label 'process_single' - conda (params.enable_conda ? "conda-forge::python=3.8.3" : null) + conda "conda-forge::python=3.8.3" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/python:3.8.3' : 'quay.io/biocontainers/python:3.8.3' }" diff --git a/modules/nf-core/custom/dumpsoftwareversions/main.nf b/modules/nf-core/custom/dumpsoftwareversions/main.nf index cebb6e05..3df21765 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/main.nf +++ b/modules/nf-core/custom/dumpsoftwareversions/main.nf @@ -2,7 +2,7 @@ process CUSTOM_DUMPSOFTWAREVERSIONS { label 'process_single' // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container - conda (params.enable_conda ? 'bioconda::multiqc=1.13' : null) + conda "bioconda::multiqc=1.13" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/multiqc:1.13--pyhdfd78af_0' : 'quay.io/biocontainers/multiqc:1.13--pyhdfd78af_0' }" diff --git a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py index da033408..e55b8d43 100755 --- a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py +++ b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py @@ -4,10 +4,11 @@ """Provide functions to merge multiple versions.yml files.""" -import yaml import platform from textwrap import dedent +import yaml + def _make_versions_html(versions): """Generate a tabular HTML output of all versions for MultiQC.""" diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf index 47fd0e58..9ae58381 100644 --- a/modules/nf-core/fastqc/main.nf +++ b/modules/nf-core/fastqc/main.nf @@ -2,7 +2,7 @@ process FASTQC { tag "$meta.id" label 'process_medium' - conda (params.enable_conda ? "bioconda::fastqc=0.11.9" : null) + conda "bioconda::fastqc=0.11.9" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/fastqc:0.11.9--0' : 'quay.io/biocontainers/fastqc:0.11.9--0' }" diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index a8159a57..68f66bea 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,7 +1,7 @@ process MULTIQC { label 'process_single' - conda (params.enable_conda ? 'bioconda::multiqc=1.13' : null) + conda "bioconda::multiqc=1.13" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/multiqc:1.13--pyhdfd78af_0' : 'quay.io/biocontainers/multiqc:1.13--pyhdfd78af_0' }" diff --git a/nextflow.config b/nextflow.config index c33b8ce2..e0d5c68a 100644 --- a/nextflow.config +++ b/nextflow.config @@ -92,7 +92,6 @@ params { validate_params = true show_hidden_params = false schema_ignore_params = 'genomes' - enable_conda = false // Config options @@ -134,7 +133,6 @@ try { profiles { debug { process.beforeScript = 'echo $HOSTNAME' } conda { - params.enable_conda = true conda.enabled = true docker.enabled = false singularity.enabled = false @@ -143,7 +141,6 @@ profiles { charliecloud.enabled = false } mamba { - params.enable_conda = true conda.enabled = true conda.useMamba = true docker.enabled = false diff --git a/nextflow_schema.json b/nextflow_schema.json index 6b1deb4c..659d8f0d 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -526,12 +526,6 @@ "description": "Show all params when using `--help`", "hidden": true, "help_text": "By default, parameters set as _hidden_ in the schema are not shown on the command line when a user runs with `--help`. Specifying this option will tell the pipeline to show all parameters." - }, - "enable_conda": { - "type": "boolean", - "description": "Run this workflow with Conda. You can also use '-profile conda' instead of providing this parameter.", - "hidden": true, - "fa_icon": "fas fa-bacon" } } } From 51abcba8d5999a213f26c3e45e439767bc08f85a Mon Sep 17 00:00:00 2001 From: Barry digby Date: Mon, 19 Dec 2022 15:30:35 +0000 Subject: [PATCH 006/491] update remote & local modules --- modules.json | 42 +++++++++---------- .../local/annotation/full_annotation/main.nf | 2 +- modules/local/annotation/parent_gene/main.nf | 2 +- modules/local/circexplorer2/reference/main.nf | 2 +- modules/local/circrna_finder/filter/main.nf | 2 +- modules/local/circtest/prepare/main.nf | 2 +- modules/local/circtest/test/main.nf | 2 +- modules/local/ciriquant/ciriquant/main.nf | 2 +- modules/local/ciriquant/yml/main.nf | 2 +- modules/local/count_matrix/combined/main.nf | 2 +- .../local/count_matrix/merge_tools/main.nf | 2 +- modules/local/count_matrix/single/main.nf | 2 +- modules/local/dcc/dcc/main.nf | 2 +- .../deseq2/differential_expression/main.nf | 2 +- modules/local/fasta/main.nf | 2 +- modules/local/find_circ/anchors/main.nf | 2 +- modules/local/find_circ/filter/main.nf | 2 +- modules/local/find_circ/find_circ/main.nf | 2 +- modules/local/mapsplice/align/main.nf | 2 +- modules/local/mirna_targets/main.nf | 2 +- modules/local/stringtie/prepde/main.nf | 2 +- modules/local/targetscan/predict/main.nf | 2 +- modules/nf-core/bowtie/align/main.nf | 2 +- modules/nf-core/bowtie/build/main.nf | 2 +- modules/nf-core/bowtie2/align/main.nf | 2 +- modules/nf-core/bowtie2/build/main.nf | 2 +- modules/nf-core/bwa/index/main.nf | 2 +- modules/nf-core/cat/fastq/main.nf | 2 +- .../nf-core/circexplorer2/annotate/main.nf | 2 +- modules/nf-core/circexplorer2/parse/main.nf | 2 +- .../templates/dumpsoftwareversions.py | 3 +- modules/nf-core/hisat2/align/main.nf | 2 +- modules/nf-core/hisat2/build/main.nf | 2 +- .../nf-core/hisat2/extractsplicesites/main.nf | 2 +- modules/nf-core/miranda/main.nf | 2 +- modules/nf-core/samtools/index/main.nf | 2 +- modules/nf-core/samtools/sort/main.nf | 2 +- modules/nf-core/samtools/view/main.nf | 2 +- modules/nf-core/segemehl/align/main.nf | 2 +- modules/nf-core/segemehl/index/main.nf | 2 +- modules/nf-core/star/align/main.nf | 2 +- modules/nf-core/star/genomegenerate/main.nf | 2 +- modules/nf-core/stringtie/stringtie/main.nf | 2 +- modules/nf-core/trimgalore/main.nf | 2 +- 44 files changed, 64 insertions(+), 65 deletions(-) diff --git a/modules.json b/modules.json index d750d640..5b501b5f 100644 --- a/modules.json +++ b/modules.json @@ -7,7 +7,7 @@ "nf-core": { "bowtie/align": { "branch": "master", - "git_sha": "653588be2a4aadab487b530643dbc9baf7a485c4", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "bowtie/build": { @@ -17,17 +17,17 @@ }, "bowtie2/align": { "branch": "master", - "git_sha": "1a96d72a3a5079424bc9a9ac5c2ca72902af327f", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "bowtie2/build": { "branch": "master", - "git_sha": "e797efb47b0d3b2124753beb55dc83ab9512bceb", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "bwa/index": { "branch": "master", - "git_sha": "9518fa4f65f3fb8cde24fde7d40333b39ec8fd65", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "cat/fastq": { @@ -37,42 +37,42 @@ }, "circexplorer2/annotate": { "branch": "master", - "git_sha": "e3ae75b5e54042683d5a1889fc733a4bf51f6819", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "circexplorer2/parse": { "branch": "master", - "git_sha": "e3ae75b5e54042683d5a1889fc733a4bf51f6819", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "custom/dumpsoftwareversions": { "branch": "master", - "git_sha": "8022c68e7403eecbd8ba9c49496f69f8c49d50f0", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "fastqc": { "branch": "master", - "git_sha": "810e8f2603ec38401d49a4aaed06f6d058745552", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "hisat2/align": { "branch": "master", - "git_sha": "653588be2a4aadab487b530643dbc9baf7a485c4", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "hisat2/build": { "branch": "master", - "git_sha": "5e34754d42cd2d5d248ca8673c0a53cdf5624905", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "hisat2/extractsplicesites": { "branch": "master", - "git_sha": "5e34754d42cd2d5d248ca8673c0a53cdf5624905", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "miranda": { "branch": "master", - "git_sha": "270fc80f29c4dbb1a973ca1d7d748bdd56e97301", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "multiqc": { @@ -82,47 +82,47 @@ }, "samtools/index": { "branch": "master", - "git_sha": "cf5b9c30a2adacc581793afb79fae5f5b50bed01", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "samtools/sort": { "branch": "master", - "git_sha": "cf5b9c30a2adacc581793afb79fae5f5b50bed01", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "samtools/view": { "branch": "master", - "git_sha": "cf5b9c30a2adacc581793afb79fae5f5b50bed01", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "segemehl/align": { "branch": "master", - "git_sha": "a52cd7df53f3e88895362f2c8fd43cfe00fbf1a3", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "segemehl/index": { "branch": "master", - "git_sha": "a52cd7df53f3e88895362f2c8fd43cfe00fbf1a3", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "star/align": { "branch": "master", - "git_sha": "cf5b9c30a2adacc581793afb79fae5f5b50bed01", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "star/genomegenerate": { "branch": "master", - "git_sha": "cf5b9c30a2adacc581793afb79fae5f5b50bed01", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "stringtie/stringtie": { "branch": "master", - "git_sha": "d0e6f468af1d51ce3ea4ac4fb5e58723eac3938c", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "trimgalore": { "branch": "master", - "git_sha": "b51a69e30973c71950225c817ad07a3337d22c40", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] } } diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/full_annotation/main.nf index 87e4e435..c47bd561 100644 --- a/modules/local/annotation/full_annotation/main.nf +++ b/modules/local/annotation/full_annotation/main.nf @@ -2,7 +2,7 @@ process ANNOTATION { tag "${meta.id}:${meta.tool}" label 'process_high' - conda (params.enable_conda ? "bioconda::ucsc-gtftogenepred=377 bioconda::ucsc-genepredtobed=377 bioconda::bedtools=2.27.0" : null) + conda "bioconda::ucsc-gtftogenepred=377 bioconda::ucsc-genepredtobed=377 bioconda::bedtools=2.27.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' : 'quay.io/biocontainers/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' }" diff --git a/modules/local/annotation/parent_gene/main.nf b/modules/local/annotation/parent_gene/main.nf index 4edefbdd..c412ab8d 100644 --- a/modules/local/annotation/parent_gene/main.nf +++ b/modules/local/annotation/parent_gene/main.nf @@ -1,7 +1,7 @@ process PARENT_GENE { label 'process_high' - conda (params.enable_conda ? "bioconda::ucsc-gtftogenepred=377 bioconda::ucsc-genepredtobed=377 bioconda::bedtools=2.27.0" : null) + conda "bioconda::ucsc-gtftogenepred=377 bioconda::ucsc-genepredtobed=377 bioconda::bedtools=2.27.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' : 'quay.io/biocontainers/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' }" diff --git a/modules/local/circexplorer2/reference/main.nf b/modules/local/circexplorer2/reference/main.nf index c3097860..ed2b3537 100644 --- a/modules/local/circexplorer2/reference/main.nf +++ b/modules/local/circexplorer2/reference/main.nf @@ -2,7 +2,7 @@ process CIRCEXPLORER2_REFERENCE { tag "$gtf" label 'process_single' - conda (params.enable_conda ? "bioconda::ucsc-gtftogenepred=377 bioconda::ucsc-genepredtobed=377 bioconda::bedtools=2.27.0" : null) + conda "bioconda::ucsc-gtftogenepred=377 bioconda::ucsc-genepredtobed=377 bioconda::bedtools=2.27.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' : 'quay.io/biocontainers/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' }" diff --git a/modules/local/circrna_finder/filter/main.nf b/modules/local/circrna_finder/filter/main.nf index 423dee85..06d7cf5c 100644 --- a/modules/local/circrna_finder/filter/main.nf +++ b/modules/local/circrna_finder/filter/main.nf @@ -2,7 +2,7 @@ process CIRCRNA_FINDER_FILTER { tag "$meta.id" label 'process_low' - conda (params.enable_conda ? "bioconda::circrna_finder=1.2" : null) + conda "bioconda::circrna_finder=1.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/circrna_finder%3A1.2--pl5321hdfd78af_1' : 'quay.io/biocontainers/circrna_finder:1.2--pl5321hdfd78af_1' }" diff --git a/modules/local/circtest/prepare/main.nf b/modules/local/circtest/prepare/main.nf index 3b92e52d..47d74346 100644 --- a/modules/local/circtest/prepare/main.nf +++ b/modules/local/circtest/prepare/main.nf @@ -1,7 +1,7 @@ process PREPARE_CLR_TEST { label 'process_medium' - conda (params.enable_conda ? "r-base r-aod r-ggplot2 r-plyr" : null) + conda "r-base r-aod r-ggplot2 r-plyr" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' : 'quay.io/biocontainers/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' }" diff --git a/modules/local/circtest/test/main.nf b/modules/local/circtest/test/main.nf index 5999ddaa..43b23083 100644 --- a/modules/local/circtest/test/main.nf +++ b/modules/local/circtest/test/main.nf @@ -1,7 +1,7 @@ process CIRCTEST { label 'process_medium' - conda (params.enable_conda ? "r-base r-aod r-ggplot2 r-plyr" : null) + conda "r-base r-aod r-ggplot2 r-plyr" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' : 'quay.io/biocontainers/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' }" diff --git a/modules/local/ciriquant/ciriquant/main.nf b/modules/local/ciriquant/ciriquant/main.nf index 8e358aef..3ad0c34a 100644 --- a/modules/local/ciriquant/ciriquant/main.nf +++ b/modules/local/ciriquant/ciriquant/main.nf @@ -2,7 +2,7 @@ process CIRIQUANT { tag "$meta.id" label 'process_high' - conda (params.enable_conda ? "bioconda::ciriquant=1.1.2" : null) + conda "bioconda::ciriquant=1.1.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/ciriquant:1.1.2--pyhdfd78af_2' : 'quay.io/biocontainers/ciriquant:1.1.2--pyhdfd78af_2' }" diff --git a/modules/local/ciriquant/yml/main.nf b/modules/local/ciriquant/yml/main.nf index 3489a219..6718df4b 100644 --- a/modules/local/ciriquant/yml/main.nf +++ b/modules/local/ciriquant/yml/main.nf @@ -1,7 +1,7 @@ process CIRIQUANT_YML { label 'process_single' - conda (params.enable_conda ? "bioconda::ciriquant=1.1.2" : null) + conda "bioconda::ciriquant=1.1.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/ciriquant:1.1.2--pyhdfd78af_2' : 'quay.io/biocontainers/ciriquant:1.1.2--pyhdfd78af_2' }" diff --git a/modules/local/count_matrix/combined/main.nf b/modules/local/count_matrix/combined/main.nf index 1d27dfd2..65f430b5 100644 --- a/modules/local/count_matrix/combined/main.nf +++ b/modules/local/count_matrix/combined/main.nf @@ -1,7 +1,7 @@ process COUNTS_COMBINED { label 'process_low' - conda (params.enable_conda ? "r-base=3.6.3 python=2.7.15 r-argparser=0.6 r-dplyr=1.0.5" : null) + conda "r-base=3.6.3 python=2.7.15 r-argparser=0.6 r-dplyr=1.0.5" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' : 'quay.io/biocontainers/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' }" diff --git a/modules/local/count_matrix/merge_tools/main.nf b/modules/local/count_matrix/merge_tools/main.nf index 4bbe7192..fd3feb89 100644 --- a/modules/local/count_matrix/merge_tools/main.nf +++ b/modules/local/count_matrix/merge_tools/main.nf @@ -2,7 +2,7 @@ process MERGE_TOOLS { tag "$meta.id" label 'process_low' - conda (params.enable_conda ? "r-base=3.6.3 python=2.7.15 r-argparser=0.6 r-dplyr=1.0.5" : null) + conda "r-base=3.6.3 python=2.7.15 r-argparser=0.6 r-dplyr=1.0.5" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' : 'quay.io/biocontainers/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' }" diff --git a/modules/local/count_matrix/single/main.nf b/modules/local/count_matrix/single/main.nf index bf6976db..8ce82da8 100644 --- a/modules/local/count_matrix/single/main.nf +++ b/modules/local/count_matrix/single/main.nf @@ -2,7 +2,7 @@ process COUNTS_SINGLE { tag "${meta.tool}" label 'process_low' - conda (params.enable_conda ? "r-base=3.6.3 python=2.7.15 r-argparser=0.6 r-dplyr=1.0.5" : null) + conda "r-base=3.6.3 python=2.7.15 r-argparser=0.6 r-dplyr=1.0.5" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' : 'quay.io/biocontainers/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' }" diff --git a/modules/local/dcc/dcc/main.nf b/modules/local/dcc/dcc/main.nf index 60cb8b71..b8db483f 100644 --- a/modules/local/dcc/dcc/main.nf +++ b/modules/local/dcc/dcc/main.nf @@ -2,7 +2,7 @@ process DCC { tag "$meta.id" label 'process_high' - conda (params.enable_conda ? "bioconda::circtools=1.2.1" : null) + conda "bioconda::circtools=1.2.1" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/circtools:1.2.1--pyh7cba7a3_0' : 'quay.io/biocontainers/circtools:1.2.1--pyh7cba7a3_0' }" diff --git a/modules/local/deseq2/differential_expression/main.nf b/modules/local/deseq2/differential_expression/main.nf index f9b5dacc..67631ed5 100644 --- a/modules/local/deseq2/differential_expression/main.nf +++ b/modules/local/deseq2/differential_expression/main.nf @@ -1,7 +1,7 @@ process DESEQ2_DIFFERENTIAL_EXPRESSION { label 'process_medium' - conda (params.enable_conda ? "r-base=3.6.3 conda-forge::r-argparser=0.6 conda-forge::r-dplyr=1.0.5 conda-forge::r-ggplot2=3.3.3 r-ggpubr=0.4.0 conda-forge::r-gplots=3.1.1 conda-forge::r-pheatmap=1.0.12 r-plyr=1.8.6 r-pvclust=2.2_0 r-rcolorbrewer=1.1_2 conda-forge::r-circlize=0.4.12 bioconductor-biomart=2.42.0 bioconductor-complexheatmap=2.2.0 bioconductor-deseq2=1.26.0 bioconductor-enhancedvolcano=1.4.0 bioconductor-ihw=1.14.0 bioconductor-org.hs.eg.db=3.10.0 bioconductor-pcatools=1.2.0 bioconductor-tximport=1.14.0" : null) + conda "r-base=3.6.3 conda-forge::r-argparser=0.6 conda-forge::r-dplyr=1.0.5 conda-forge::r-ggplot2=3.3.3 r-ggpubr=0.4.0 conda-forge::r-gplots=3.1.1 conda-forge::r-pheatmap=1.0.12 r-plyr=1.8.6 r-pvclust=2.2_0 r-rcolorbrewer=1.1_2 conda-forge::r-circlize=0.4.12 bioconductor-biomart=2.42.0 bioconductor-complexheatmap=2.2.0 bioconductor-deseq2=1.26.0 bioconductor-enhancedvolcano=1.4.0 bioconductor-ihw=1.14.0 bioconductor-org.hs.eg.db=3.10.0 bioconductor-pcatools=1.2.0 bioconductor-tximport=1.14.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-04b2ef814c9c6ab8c196c3e372521b88160dc260:e0cb4046baee3fd35fdbf883ba8af34e3e8af2e8-0' : 'quay.io/biocontainers/mulled-v2-04b2ef814c9c6ab8c196c3e372521b88160dc260:e0cb4046baee3fd35fdbf883ba8af34e3e8af2e8-0' }" diff --git a/modules/local/fasta/main.nf b/modules/local/fasta/main.nf index 58c3f506..c2cd5ada 100644 --- a/modules/local/fasta/main.nf +++ b/modules/local/fasta/main.nf @@ -2,7 +2,7 @@ process FASTA { tag "${meta.id}:${meta.tool}" label 'process_single' - conda (params.enable_conda ? "bioconda::bedtools=2.30.0" : null) + conda "bioconda::bedtools=2.30.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/bedtools:2.30.0--h7d7f7ad_2': 'quay.io/biocontainers/bedtools:2.30.0--h7d7f7ad_2' }" diff --git a/modules/local/find_circ/anchors/main.nf b/modules/local/find_circ/anchors/main.nf index d357c45e..15b0650a 100644 --- a/modules/local/find_circ/anchors/main.nf +++ b/modules/local/find_circ/anchors/main.nf @@ -2,7 +2,7 @@ process FIND_CIRC_ANCHORS { tag "$meta.id" label "process_high" - conda (params.enable_conda ? "find_circ=1.2" : null) + conda "find_circ=1.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/find_circ%3A1.2--hdfd78af_0' : 'quay.io/biocontainers/find_circ:1.2--hdfd78af_0' }" diff --git a/modules/local/find_circ/filter/main.nf b/modules/local/find_circ/filter/main.nf index c2220884..7be0de57 100644 --- a/modules/local/find_circ/filter/main.nf +++ b/modules/local/find_circ/filter/main.nf @@ -2,7 +2,7 @@ process FIND_CIRC_FILTER { tag "$meta.id" label "process_low" - conda (params.enable_conda ? "find_circ=1.2" : null) + conda "find_circ=1.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/find_circ%3A1.2--hdfd78af_0' : 'quay.io/biocontainers/find_circ:1.2--hdfd78af_0' }" diff --git a/modules/local/find_circ/find_circ/main.nf b/modules/local/find_circ/find_circ/main.nf index 970c87e5..57bf656c 100644 --- a/modules/local/find_circ/find_circ/main.nf +++ b/modules/local/find_circ/find_circ/main.nf @@ -2,7 +2,7 @@ process FIND_CIRC { tag "$meta.id" label "process_high" - conda (params.enable_conda ? "find_circ=1.2 bowtie2" : null) + conda "find_circ=1.2 bowtie2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-c27e472038a09e49d9147bc52903e12836302c12:60ffb3b15a2c40c669f8d38382b1e6e4b065f5e4-0' : 'quay.io/biocontainers/mulled-v2-c27e472038a09e49d9147bc52903e12836302c12:60ffb3b15a2c40c669f8d38382b1e6e4b065f5e4-0' }" diff --git a/modules/local/mapsplice/align/main.nf b/modules/local/mapsplice/align/main.nf index 4aa91035..44c64d97 100644 --- a/modules/local/mapsplice/align/main.nf +++ b/modules/local/mapsplice/align/main.nf @@ -2,7 +2,7 @@ process MAPSPLICE_ALIGN { tag "$meta.id" label 'process_high' - conda (params.enable_conda ? "bioconda::mapsplice=2.2.1" : null) + conda "bioconda::mapsplice=2.2.1" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mapsplice:2.2.1--py27h07887db_0': 'quay.io/biocontainers/mapsplice:2.2.1--py27h07887db_0' }" diff --git a/modules/local/mirna_targets/main.nf b/modules/local/mirna_targets/main.nf index 7a9c0666..c6beaeff 100644 --- a/modules/local/mirna_targets/main.nf +++ b/modules/local/mirna_targets/main.nf @@ -2,7 +2,7 @@ process MIRNA_TARGETS { tag "$meta.id" label 'process_low' - conda (params.enable_conda ? "bioconda::bedtools=2.30.0" : null) + conda "bioconda::bedtools=2.30.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/bedtools:2.30.0--h7d7f7ad_2': 'quay.io/biocontainers/bedtools:2.30.0--h7d7f7ad_2' }" diff --git a/modules/local/stringtie/prepde/main.nf b/modules/local/stringtie/prepde/main.nf index e069cddd..da20b1a8 100644 --- a/modules/local/stringtie/prepde/main.nf +++ b/modules/local/stringtie/prepde/main.nf @@ -1,7 +1,7 @@ process STRINGTIE_PREPDE { label 'process_low' - conda (params.enable_conda ? "bioconda::stringtie=2.2.1" : null) + conda "bioconda::stringtie=2.2.1" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/stringtie:2.2.1--hecb563c_2' : 'quay.io/biocontainers/stringtie:2.2.1--hecb563c_2' }" diff --git a/modules/local/targetscan/predict/main.nf b/modules/local/targetscan/predict/main.nf index ae3de117..f6b37cb0 100644 --- a/modules/local/targetscan/predict/main.nf +++ b/modules/local/targetscan/predict/main.nf @@ -2,7 +2,7 @@ process TARGETSCAN { tag "$meta.id" label 'process_medium' - conda (params.enable_conda ? "bioconda::targetscan=7.0" : null) + conda "bioconda::targetscan=7.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/targetscan:7.0--pl5321hdfd78af_0' : 'quay.io/biocontainers/targetscan:7.0--pl5321hdfd78af_0' }" diff --git a/modules/nf-core/bowtie/align/main.nf b/modules/nf-core/bowtie/align/main.nf index 950c495e..4cb6ca7a 100644 --- a/modules/nf-core/bowtie/align/main.nf +++ b/modules/nf-core/bowtie/align/main.nf @@ -2,7 +2,7 @@ process BOWTIE_ALIGN { tag "$meta.id" label 'process_high' - conda (params.enable_conda ? 'bioconda::bowtie=1.3.0 bioconda::samtools=1.16.1' : null) + conda "bioconda::bowtie=1.3.0 bioconda::samtools=1.16.1" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-ffbf83a6b0ab6ec567a336cf349b80637135bca3:c84c7c55c45af231883d9ff4fe706ac44c479c36-0' : 'quay.io/biocontainers/mulled-v2-ffbf83a6b0ab6ec567a336cf349b80637135bca3:c84c7c55c45af231883d9ff4fe706ac44c479c36-0' }" diff --git a/modules/nf-core/bowtie/build/main.nf b/modules/nf-core/bowtie/build/main.nf index e01d9855..85314ec7 100644 --- a/modules/nf-core/bowtie/build/main.nf +++ b/modules/nf-core/bowtie/build/main.nf @@ -2,7 +2,7 @@ process BOWTIE_BUILD { tag "$fasta" label 'process_high' - conda (params.enable_conda ? 'bioconda::bowtie=1.3.0' : null) + conda "bioconda::bowtie=1.3.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/bowtie:1.3.0--py38hed8969a_1' : 'quay.io/biocontainers/bowtie:1.3.0--py38hed8969a_1' }" diff --git a/modules/nf-core/bowtie2/align/main.nf b/modules/nf-core/bowtie2/align/main.nf index 983a3ad3..3d851866 100644 --- a/modules/nf-core/bowtie2/align/main.nf +++ b/modules/nf-core/bowtie2/align/main.nf @@ -2,7 +2,7 @@ process BOWTIE2_ALIGN { tag "$meta.id" label "process_high" - conda (params.enable_conda ? "bioconda::bowtie2=2.4.4 bioconda::samtools=1.16.1 conda-forge::pigz=2.6" : null) + conda "bioconda::bowtie2=2.4.4 bioconda::samtools=1.16.1 conda-forge::pigz=2.6" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-ac74a7f02cebcfcc07d8e8d1d750af9c83b4d45a:a0ffedb52808e102887f6ce600d092675bf3528a-0' : 'quay.io/biocontainers/mulled-v2-ac74a7f02cebcfcc07d8e8d1d750af9c83b4d45a:a0ffedb52808e102887f6ce600d092675bf3528a-0' }" diff --git a/modules/nf-core/bowtie2/build/main.nf b/modules/nf-core/bowtie2/build/main.nf index 218c174a..551893af 100644 --- a/modules/nf-core/bowtie2/build/main.nf +++ b/modules/nf-core/bowtie2/build/main.nf @@ -2,7 +2,7 @@ process BOWTIE2_BUILD { tag "$fasta" label 'process_high' - conda (params.enable_conda ? 'bioconda::bowtie2=2.4.4' : null) + conda "bioconda::bowtie2=2.4.4" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/bowtie2:2.4.4--py39hbb4e92a_0' : 'quay.io/biocontainers/bowtie2:2.4.4--py39hbb4e92a_0' }" diff --git a/modules/nf-core/bwa/index/main.nf b/modules/nf-core/bwa/index/main.nf index 6d70fc15..7ccf3110 100644 --- a/modules/nf-core/bwa/index/main.nf +++ b/modules/nf-core/bwa/index/main.nf @@ -2,7 +2,7 @@ process BWA_INDEX { tag "$fasta" label 'process_single' - conda (params.enable_conda ? "bioconda::bwa=0.7.17" : null) + conda "bioconda::bwa=0.7.17" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/bwa:0.7.17--hed695b0_7' : 'quay.io/biocontainers/bwa:0.7.17--hed695b0_7' }" diff --git a/modules/nf-core/cat/fastq/main.nf b/modules/nf-core/cat/fastq/main.nf index 4fa365d3..8a0b5600 100644 --- a/modules/nf-core/cat/fastq/main.nf +++ b/modules/nf-core/cat/fastq/main.nf @@ -2,7 +2,7 @@ process CAT_FASTQ { tag "$meta.id" label 'process_single' - conda (params.enable_conda ? "conda-forge::sed=4.7" : null) + conda "conda-forge::sed=4.7" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : 'ubuntu:20.04' }" diff --git a/modules/nf-core/circexplorer2/annotate/main.nf b/modules/nf-core/circexplorer2/annotate/main.nf index bf836bbf..335723a8 100644 --- a/modules/nf-core/circexplorer2/annotate/main.nf +++ b/modules/nf-core/circexplorer2/annotate/main.nf @@ -2,7 +2,7 @@ process CIRCEXPLORER2_ANNOTATE { tag "$meta.id" label 'process_low' - conda (params.enable_conda ? "bioconda::circexplorer2=2.3.8" : null) + conda "bioconda::circexplorer2=2.3.8" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/circexplorer2:2.3.8--pyh864c0ab_1': 'quay.io/biocontainers/circexplorer2:2.3.8--pyh864c0ab_1' }" diff --git a/modules/nf-core/circexplorer2/parse/main.nf b/modules/nf-core/circexplorer2/parse/main.nf index 8d9dbb80..147a73f3 100644 --- a/modules/nf-core/circexplorer2/parse/main.nf +++ b/modules/nf-core/circexplorer2/parse/main.nf @@ -2,7 +2,7 @@ process CIRCEXPLORER2_PARSE { tag "$meta.id" label 'process_low' - conda (params.enable_conda ? "bioconda::circexplorer2=2.3.8" : null) + conda "bioconda::circexplorer2=2.3.8" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/circexplorer2:2.3.8--pyh864c0ab_1': 'quay.io/biocontainers/circexplorer2:2.3.8--pyh864c0ab_1' }" diff --git a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py index e55b8d43..da033408 100755 --- a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py +++ b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py @@ -4,11 +4,10 @@ """Provide functions to merge multiple versions.yml files.""" +import yaml import platform from textwrap import dedent -import yaml - def _make_versions_html(versions): """Generate a tabular HTML output of all versions for MultiQC.""" diff --git a/modules/nf-core/hisat2/align/main.nf b/modules/nf-core/hisat2/align/main.nf index 69717729..eefb5819 100644 --- a/modules/nf-core/hisat2/align/main.nf +++ b/modules/nf-core/hisat2/align/main.nf @@ -3,7 +3,7 @@ process HISAT2_ALIGN { label 'process_high' // WARN: Version information not provided by tool on CLI. Please update version string below when bumping container versions. - conda (params.enable_conda ? "bioconda::hisat2=2.2.1 bioconda::samtools=1.16.1" : null) + conda "bioconda::hisat2=2.2.1 bioconda::samtools=1.16.1" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-a97e90b3b802d1da3d6958e0867610c718cb5eb1:2cdf6bf1e92acbeb9b2834b1c58754167173a410-0' : 'quay.io/biocontainers/mulled-v2-a97e90b3b802d1da3d6958e0867610c718cb5eb1:2cdf6bf1e92acbeb9b2834b1c58754167173a410-0' }" diff --git a/modules/nf-core/hisat2/build/main.nf b/modules/nf-core/hisat2/build/main.nf index fee4064c..e0a7f652 100644 --- a/modules/nf-core/hisat2/build/main.nf +++ b/modules/nf-core/hisat2/build/main.nf @@ -4,7 +4,7 @@ process HISAT2_BUILD { label 'process_high_memory' // WARN: Version information not provided by tool on CLI. Please update version string below when bumping container versions. - conda (params.enable_conda ? 'bioconda::hisat2=2.2.1' : null) + conda "bioconda::hisat2=2.2.1" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/hisat2:2.2.1--h1b792b2_3' : 'quay.io/biocontainers/hisat2:2.2.1--h1b792b2_3' }" diff --git a/modules/nf-core/hisat2/extractsplicesites/main.nf b/modules/nf-core/hisat2/extractsplicesites/main.nf index 1423f25c..db6cbe6a 100644 --- a/modules/nf-core/hisat2/extractsplicesites/main.nf +++ b/modules/nf-core/hisat2/extractsplicesites/main.nf @@ -3,7 +3,7 @@ process HISAT2_EXTRACTSPLICESITES { label 'process_medium' // WARN: Version information not provided by tool on CLI. Please update version string below when bumping container versions. - conda (params.enable_conda ? 'bioconda::hisat2=2.2.1' : null) + conda "bioconda::hisat2=2.2.1" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/hisat2:2.2.1--h1b792b2_3' : 'quay.io/biocontainers/hisat2:2.2.1--h1b792b2_3' }" diff --git a/modules/nf-core/miranda/main.nf b/modules/nf-core/miranda/main.nf index a050c4b6..2f32f788 100644 --- a/modules/nf-core/miranda/main.nf +++ b/modules/nf-core/miranda/main.nf @@ -2,7 +2,7 @@ process MIRANDA { tag "$meta.id" label 'process_medium' - conda (params.enable_conda ? "bioconda::miranda=3.3a" : null) + conda "bioconda::miranda=3.3a" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/miranda:3.3a--h779adbc_3': 'quay.io/biocontainers/miranda:3.3a--h779adbc_3' }" diff --git a/modules/nf-core/samtools/index/main.nf b/modules/nf-core/samtools/index/main.nf index 8577dc9d..8b95687a 100644 --- a/modules/nf-core/samtools/index/main.nf +++ b/modules/nf-core/samtools/index/main.nf @@ -2,7 +2,7 @@ process SAMTOOLS_INDEX { tag "$meta.id" label 'process_low' - conda (params.enable_conda ? "bioconda::samtools=1.16.1" : null) + conda "bioconda::samtools=1.16.1" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/samtools:1.16.1--h6899075_1' : 'quay.io/biocontainers/samtools:1.16.1--h6899075_1' }" diff --git a/modules/nf-core/samtools/sort/main.nf b/modules/nf-core/samtools/sort/main.nf index ac43e67a..84c167cd 100644 --- a/modules/nf-core/samtools/sort/main.nf +++ b/modules/nf-core/samtools/sort/main.nf @@ -2,7 +2,7 @@ process SAMTOOLS_SORT { tag "$meta.id" label 'process_medium' - conda (params.enable_conda ? "bioconda::samtools=1.16.1" : null) + conda "bioconda::samtools=1.16.1" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/samtools:1.16.1--h6899075_1' : 'quay.io/biocontainers/samtools:1.16.1--h6899075_1' }" diff --git a/modules/nf-core/samtools/view/main.nf b/modules/nf-core/samtools/view/main.nf index 314c8b72..729c85e5 100644 --- a/modules/nf-core/samtools/view/main.nf +++ b/modules/nf-core/samtools/view/main.nf @@ -2,7 +2,7 @@ process SAMTOOLS_VIEW { tag "$meta.id" label 'process_low' - conda (params.enable_conda ? "bioconda::samtools=1.16.1" : null) + conda "bioconda::samtools=1.16.1" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/samtools:1.16.1--h6899075_1' : 'quay.io/biocontainers/samtools:1.16.1--h6899075_1' }" diff --git a/modules/nf-core/segemehl/align/main.nf b/modules/nf-core/segemehl/align/main.nf index 2253efac..3e7fe4c7 100644 --- a/modules/nf-core/segemehl/align/main.nf +++ b/modules/nf-core/segemehl/align/main.nf @@ -2,7 +2,7 @@ process SEGEMEHL_ALIGN { tag "$meta.id" label 'process_high' - conda (params.enable_conda ? "bioconda::segemehl=0.3.4" : null) + conda "bioconda::segemehl=0.3.4" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/segemehl:0.3.4--hc2ea5fd_5': 'quay.io/biocontainers/segemehl:0.3.4--hc2ea5fd_5' }" diff --git a/modules/nf-core/segemehl/index/main.nf b/modules/nf-core/segemehl/index/main.nf index 07cac955..f545c448 100644 --- a/modules/nf-core/segemehl/index/main.nf +++ b/modules/nf-core/segemehl/index/main.nf @@ -2,7 +2,7 @@ process SEGEMEHL_INDEX { tag "$fasta" label 'process_high' - conda (params.enable_conda ? "bioconda::segemehl=0.3.4" : null) + conda "bioconda::segemehl=0.3.4" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/segemehl:0.3.4--hc2ea5fd_5': 'quay.io/biocontainers/segemehl:0.3.4--hc2ea5fd_5' }" diff --git a/modules/nf-core/star/align/main.nf b/modules/nf-core/star/align/main.nf index 8b0f9d89..0e3bd713 100644 --- a/modules/nf-core/star/align/main.nf +++ b/modules/nf-core/star/align/main.nf @@ -2,7 +2,7 @@ process STAR_ALIGN { tag "$meta.id" label 'process_high' - conda (params.enable_conda ? "bioconda::star=2.7.10a bioconda::samtools=1.16.1 conda-forge::gawk=5.1.0" : null) + conda "bioconda::star=2.7.10a bioconda::samtools=1.16.1 conda-forge::gawk=5.1.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-1fa26d1ce03c295fe2fdcf85831a92fbcbd7e8c2:1df389393721fc66f3fd8778ad938ac711951107-0' : 'quay.io/biocontainers/mulled-v2-1fa26d1ce03c295fe2fdcf85831a92fbcbd7e8c2:1df389393721fc66f3fd8778ad938ac711951107-0' }" diff --git a/modules/nf-core/star/genomegenerate/main.nf b/modules/nf-core/star/genomegenerate/main.nf index 0fe88cbf..91462489 100644 --- a/modules/nf-core/star/genomegenerate/main.nf +++ b/modules/nf-core/star/genomegenerate/main.nf @@ -2,7 +2,7 @@ process STAR_GENOMEGENERATE { tag "$fasta" label 'process_high' - conda (params.enable_conda ? "bioconda::star=2.7.10a bioconda::samtools=1.16.1 conda-forge::gawk=5.1.0" : null) + conda "bioconda::star=2.7.10a bioconda::samtools=1.16.1 conda-forge::gawk=5.1.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-1fa26d1ce03c295fe2fdcf85831a92fbcbd7e8c2:1df389393721fc66f3fd8778ad938ac711951107-0' : 'quay.io/biocontainers/mulled-v2-1fa26d1ce03c295fe2fdcf85831a92fbcbd7e8c2:1df389393721fc66f3fd8778ad938ac711951107-0' }" diff --git a/modules/nf-core/stringtie/stringtie/main.nf b/modules/nf-core/stringtie/stringtie/main.nf index b403edee..2d5b035f 100644 --- a/modules/nf-core/stringtie/stringtie/main.nf +++ b/modules/nf-core/stringtie/stringtie/main.nf @@ -2,7 +2,7 @@ process STRINGTIE_STRINGTIE { tag "$meta.id" label 'process_medium' - conda (params.enable_conda ? "bioconda::stringtie=2.2.1" : null) + conda "bioconda::stringtie=2.2.1" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/stringtie:2.2.1--hecb563c_2' : 'quay.io/biocontainers/stringtie:2.2.1--hecb563c_2' }" diff --git a/modules/nf-core/trimgalore/main.nf b/modules/nf-core/trimgalore/main.nf index 5b45e4d7..ab8bb14e 100644 --- a/modules/nf-core/trimgalore/main.nf +++ b/modules/nf-core/trimgalore/main.nf @@ -2,7 +2,7 @@ process TRIMGALORE { tag "$meta.id" label 'process_high' - conda (params.enable_conda ? 'bioconda::trim-galore=0.6.7' : null) + conda "bioconda::trim-galore=0.6.7" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/trim-galore:0.6.7--hdfd78af_0' : 'quay.io/biocontainers/trim-galore:0.6.7--hdfd78af_0' }" From 61967557df5fd23ff7609e3372fd71fa9ff2efbf Mon Sep 17 00:00:00 2001 From: Barry digby Date: Fri, 27 Jan 2023 09:10:16 +0000 Subject: [PATCH 007/491] publication info --- README.md | 11 +++++++++-- docs/images/Genomics-Data-Science-original.png | Bin 0 -> 33528 bytes 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 docs/images/Genomics-Data-Science-original.png diff --git a/README.md b/README.md index 7ca6d3b5..48a7c220 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,9 @@ The nf-core/circrna pipeline comes with documentation about the pipeline [usage] nf-core/circrna was originally written by Barry Digby. -We thank the following people for their extensive assistance in the development of this pipeline: +## Acknowledgements + +![SFI](./docs/images/Genomics-Data-Science-original.png) ## Contributions and Support @@ -86,8 +88,13 @@ For further information or help, don't hesitate to get in touch on the [Slack `# ## Citations - +> **nf-core/circrna: a portable workflow for the quantification, miRNA target prediction and differential expression analysis of circular RNAs.** +> +> Barry Digby, Stephen P. Finn, & Pilib Ó Broin +> +> [BMC Bioinformatics 24, 27 (2023)](https://bmcbioinformatics.biomedcentral.com/articles/10.1186/s12859-022-05125-8) +> doi: [10.1186/s12859-022-05125-8](https://doi.org/10.1186/s12859-022-05125-8) An extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file. diff --git a/docs/images/Genomics-Data-Science-original.png b/docs/images/Genomics-Data-Science-original.png new file mode 100644 index 0000000000000000000000000000000000000000..50e9c02b733a2aceebc40726576b4a7e8718b217 GIT binary patch literal 33528 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 literal 0 HcmV?d00001 From 3b37a582285a55ccc7731b821958c03cd4ff6895 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Fri, 27 Jan 2023 09:13:22 +0000 Subject: [PATCH 008/491] prettier -_- --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 48a7c220..6e8ee225 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ For further information or help, don't hesitate to get in touch on the [Slack `# ## Citations + > **nf-core/circrna: a portable workflow for the quantification, miRNA target prediction and differential expression analysis of circular RNAs.** > > Barry Digby, Stephen P. Finn, & Pilib Ó Broin From ecfea066439195ade06c9df5f476b5b3f589c847 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Tue, 31 Jan 2023 13:07:47 +0000 Subject: [PATCH 009/491] first pass reviewer comments --- .github/workflows/ci.yml | 3 +- CITATIONS.md | 122 ++++++++++++---- README.md | 44 +++--- bin/DEA.R | 39 +---- bin/ID_to_BED.sh | 15 -- bin/annotate_outputs.sh | 7 +- bin/backsplice_gen.sh | 4 + bin/check_empty.sh | 2 + bin/check_samplesheet.py | 29 ---- bin/circRNA_counts_matrix.py | 9 +- bin/circ_test.R | 17 +-- bin/consolidate_algorithms_intersection.R | 8 +- bin/prepare_circ_test.R | 3 + bin/reformat_count_matrix.R | 4 + bin/targetscan_format.sh | 8 +- conf/modules.config | 64 ++++----- conf/test.config | 2 +- docs/output.md | 135 +++++++----------- docs/usage.md | 116 +++++---------- .../local/annotation/full_annotation/main.nf | 3 +- modules/local/annotation/parent_gene/main.nf | 12 +- modules/local/circexplorer2/filter/main.nf | 11 ++ modules/local/circexplorer2/reference/main.nf | 1 + modules/local/circrna_finder/filter/main.nf | 2 + modules/local/circtest/prepare/main.nf | 2 +- modules/local/circtest/test/main.nf | 2 +- modules/local/ciriquant/filter/main.nf | 11 ++ modules/local/count_matrix/combined/main.nf | 5 +- .../local/count_matrix/merge_tools/main.nf | 4 +- modules/local/count_matrix/single/main.nf | 5 +- modules/local/dcc/filter/main.nf | 11 ++ modules/local/fasta/main.nf | 1 + modules/local/mapsplice/align/main.nf | 12 +- modules/local/mirna_targets/main.nf | 1 + modules/local/segemehl/filter/main.nf | 14 +- modules/local/star/sjdb/main.nf | 11 ++ modules/local/stringtie/prepde/main.nf | 6 + modules/local/targetscan/database/main.nf | 2 +- modules/local/targetscan/predict/main.nf | 1 + nextflow.config | 2 +- nextflow_schema.json | 11 +- subworkflows/local/circrna_discovery.nf | 30 +++- subworkflows/local/differential_expression.nf | 1 + subworkflows/local/prepare_genome.nf | 32 +---- workflows/circrna.nf | 4 - 45 files changed, 418 insertions(+), 410 deletions(-) delete mode 100755 bin/ID_to_BED.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 98016682..181b2aea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,8 +26,7 @@ jobs: NXF_VER: - "22.10.1" - "latest-everything" - profile: - - "test" + steps: - name: Check out pipeline code uses: actions/checkout@v3 diff --git a/CITATIONS.md b/CITATIONS.md index 9b05020c..d0b737d9 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -10,73 +10,135 @@ ## Pipeline tools -- **bedtools** Quinlan, A.R. & Hall, I.M., (2010). BEDTools: a flexible suite of utilities for comparing genomic features. Bioinformatics , 26(6), pp.841–842. Available at: [http://dx.doi.org/10.1093/bioinformatics/btq033](http://dx.doi.org/10.1093/bioinformatics/btq033). Download: [https://github.com/arq5x/bedtools2/releases](https://github.com/arq5x/bedtools2/) +- [BEDTools](https://pubmed.ncbi.nlm.nih.gov/20110278/) -- **Bowite** Langmead, B., Trapnell, C., Pop, M. et al., (2009). Ultrafast and memory-efficient alignment of short DNA sequences to the human genome. Genome Biol 10, R25. Availabe at: [https://doi.org/10.1186/gb-2009-10-3-r25](https://doi.org/10.1186/gb-2009-10-3-r25). Download: [https://sourceforge.net/projects/bowtie-bio/](https://sourceforge.net/projects/bowtie-bio/) + > Quinlan AR, Hall IM. BEDTools: a flexible suite of utilities for comparing genomic features. Bioinformatics. 2010 Mar 15;26(6):841-2. doi: 10.1093/bioinformatics/btq033. Epub 2010 Jan 28. PubMed PMID: 20110278; PubMed Central PMCID: PMC2832824. -- **Bowtie2** Langmead, B. & Salzberg, S. L. (2012). Fast gapped-read alignment with Bowtie 2. Nature methods, 9(4), p. 357–359. Available at: [10.1038/nmeth.1923](https:/dx.doi.org/10.1038/nmeth.1923). Download: [http://bowtie-bio.sourceforge.net/bowtie2/index.shtml](http://bowtie-bio.sourceforge.net/bowtie2/index.shtml) +- [Bowtie](https://doi.org/10.1186/gb-2009-10-3-r25) -- **bwa** Li, H., & Durbin, R. (2009). Fast and accurate short read alignment with Burrows-Wheeler transform. Bioinformatics , 25(14), 1754–1760. Available at: [https://doi.org/10.1093/bioinformatics/btp324](https://doi.org/10.1093/bioinformatics/btp324). Download: [http://bio-bwa.sourceforge.net/bwa.shtml](http://bio-bwa.sourceforge.net/bwa.shtml). + > Langmead, B., Trapnell, C., Pop, M. et al., 2009. Ultrafast and memory-efficient alignment of short DNA sequences to the human genome. Genome Biol 10, R25. doi: 10.1186/gb-2009-10-3-r25 -- **CIRCexplorer2** Zhang XO, Dong R, Zhang Y, Zhang JL, Luo Z, Zhang J, Chen LL, Yang L. (2016). Diverse alternative back-splicing and alternative splicing landscape of circular RNAs. Genome Res. 2016 Sep;26(9):1277-87. Available at: [https://doi.org/10.1101/gr.202895.115](https://doi.org/10.1101/gr.202895.115). Download: [https://circexplorer2.readthedocs.io/en/latest/tutorial/setup/](https://circexplorer2.readthedocs.io/en/latest/tutorial/setup/) +- [Bowtie2](https:/dx.doi.org/10.1038/nmeth.1923) -- **circRNA finder** Westholm, J.O., Lai, E.C., et al. (2016). Genome-wide Analysis of Drosophila Circular RNAs Reveals Their Structural and Sequence Properties and Age-Dependent Neural Accumulation Westholm et al. Cell Reports. Available at: [https://doi.org/10.1016/j.celrep.2014.10.062](https://doi.org/10.1016/j.celrep.2014.10.062). Download: [https://github.com/orzechoj/circRNA_finder](https://github.com/orzechoj/circRNA_finder) + > Langmead, B. and Salzberg, S. L. 2012 Fast gapped-read alignment with Bowtie 2. Nature methods, 9(4), p. 357–359. doi: 10.1038/nmeth.1923. -- **CIRIquant** Zhang, J., Chen, S., Yang, J. et al. (2020). Accurate quantification of circular RNAs identifies extensive circular isoform switching events. Nat Commun 11, 90. Available at: [https://doi.org/10.1038/s41467-019-13840-9](https://doi.org/10.1038/s41467-019-13840-9). Download: [https://github.com/bioinfo-biols/CIRIquant](https://github.com/bioinfo-biols/CIRIquant) +- [BWA](https://www.ncbi.nlm.nih.gov/pubmed/19451168/) -- **DCC** Jun Cheng, Franziska Metge, Christoph Dieterich, (2016). Specific identification and quantification of circular RNAs from sequencing data, Bioinformatics, 32(7), 1094–1096. Available at: [https://doi.org/10.1093/bioinformatics/btv656](https://doi.org/10.1093/bioinformatics/btv656). Download: [https://github.com/dieterich-lab/DCC](https://github.com/dieterich-lab/DCC) + > Li H, Durbin R. Fast and accurate short read alignment with Burrows-Wheeler transform. Bioinformatics. 2009 Jul 15;25(14):1754-60. doi: 10.1093/bioinformatics/btp324. Epub 2009 May 18. PubMed PMID: 19451168; PubMed Central PMCID: PMC2705234. + +- [CIRCexplorer2](https://doi.org/10.1101/gr.202895.115) + + > Zhang XO, Dong R, Zhang Y, Zhang JL, Luo Z, Zhang J, Chen LL, Yang L. (2016). Diverse alternative back-splicing and alternative splicing landscape of circular RNAs. Genome Res. 2016 Sep;26(9):1277-87. + +- [circRNA finder](https://doi.org/10.1016/j.celrep.2014.10.062) + + > Westholm, J.O., Lai, E.C., et al. (2016). Genome-wide Analysis of Drosophila Circular RNAs Reveals Their Structural and Sequence Properties and Age-Dependent Neural Accumulation Westholm et al. Cell Reports. + +- [CIRIquant](https://doi.org/10.1038/s41467-019-13840-9) + + > Zhang, J., Chen, S., Yang, J. et al. (2020). Accurate quantification of circular RNAs identifies extensive circular isoform switching events. Nat Commun 11, 90. + +- [DCC](https://doi.org/10.1093/bioinformatics/btv656) + + > Jun Cheng, Franziska Metge, Christoph Dieterich, (2016). Specific identification and quantification of circular RNAs from sequencing data, Bioinformatics, 32(7), 1094–1096. - [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) -- **find circ** Memczak, S., Jens, M., Elefsinioti, A., Torti, F., Krueger, J., Rybak, A., Maier, L., Mackowiak, S. D., Gregersen, L. H., Munschauer, M., Loewer, A., Ziebold, U., Landthaler, M., Kocks, C., le Noble, F., & Rajewsky, N. (2013). Circular RNAs are a large class of animal RNAs with regulatory potency. Nature, 495(7441), 333–338. Available at: [https://doi.org/10.1038/nature11928](https://doi.org/10.1038/nature11928). Download: [https://github.com/marvin-jens/find_circ](https://github.com/marvin-jens/find_circ) +- [find circ](https://doi.org/10.1038/nature11928) -- **HISAT2** Kim, D., Paggi, J.M., Park, C. et al. (2019). Graph-based genome alignment and genotyping with HISAT2 and HISAT-genotype. Nat Biotechnol 37, 907–915 (2019). Available at: [https://doi.org/10.1038/s41587-019-0201-4](https://doi.org/10.1038/s41587-019-0201-4). Download: [http://daehwankimlab.github.io/hisat2/download/](http://daehwankimlab.github.io/hisat2/download/) + > Memczak, S., Jens, M., Elefsinioti, A., Torti, F., Krueger, J., Rybak, A., Maier, L., Mackowiak, S. D., Gregersen, L. H., Munschauer, M., Loewer, A., Ziebold, U., Landthaler, M., Kocks, C., le Noble, F., & Rajewsky, N. (2013). Circular RNAs are a large class of animal RNAs with regulatory potency. Nature, 495(7441), 333–338. -- **MapSplice2** Wang, K., Liu J., et al. (2010) MapSplice: Accurate mapping of RNA-seq reads for splice junction discovery, Nucleic Acids Research, 38(18), 178. Avaialable at: [https://doi.org/10.1093/nar/gkq622](https://doi.org/10.1093/nar/gkq622). Download: [http://www.netlab.uky.edu/p/bioinfo/MapSplice2Download](http://www.netlab.uky.edu/p/bioinfo/MapSplice2Download) +- [GATK](https://pubmed.ncbi.nlm.nih.gov/20644199/) -- **miRanda** Enright, A.J., John, B., Gaul, U. et al. (2003). MicroRNA targets in Drosophila. Genome Biol 5, R1. Available at: [https://doi.org/10.1186/gb-2003-5-1-r1](https://doi.org/10.1186/gb-2003-5-1-r1). Download: [http://cbio.mskcc.org/miRNA2003/miranda.html](http://cbio.mskcc.org/miRNA2003/miranda.html). + > McKenna A, Hanna M, Banks E, et al.: The Genome Analysis Toolkit: a MapReduce framework for analyzing next-generation DNA sequencing data. Genome Res. 2010 Sep;20(9):1297-303. doi: 10.1101/gr.107524.110. Epub 2010 Jul 19. PubMed PMID: 20644199; PubMed Central PMCID: PMC2928508. + +- [HISAT2](https://pubmed.ncbi.nlm.nih.gov/31375807/) + + > Kim D, Paggi JM, Park C, Bennett C, Salzberg SL. Graph-based genome alignment and genotyping with HISAT2 and HISAT-genotype Graph-based genome alignment and genotyping with HISAT2 and HISAT-genotype. Nat Biotechnol. 2019 Aug;37(8):907-915. doi: 10.1038/s41587-019-0201-4. Epub 2019 Aug 2. PubMed PMID: 31375807. + +- [MapSplice2](https://doi.org/10.1093/nar/gkq622) + + > Wang, K., Liu J., et al. (2010) MapSplice: Accurate mapping of RNA-seq reads for splice junction discovery, Nucleic Acids Research, 38(18), 178. + +- [miRanda](https://doi.org/10.1186/gb-2003-5-1-r1) + + > Enright, A.J., John, B., Gaul, U. et al. (2003). MicroRNA targets in Drosophila. Genome Biol 5, R1. - [MultiQC](https://pubmed.ncbi.nlm.nih.gov/27312411/) > Ewels P, Magnusson M, Lundin S, Käller M. MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics. 2016 Oct 1;32(19):3047-8. doi: 10.1093/bioinformatics/btw354. Epub 2016 Jun 16. PubMed PMID: 27312411; PubMed Central PMCID: PMC5039924. -- **R**: R Core Team (2020). R: A language and environment for statistical computing. R Foundation for Statistical Computing, Vienna, Austria. Download: [https://www.R-project.org/](https://www.R-project.org/). +- [R](https://www.R-project.org/) + + > R Core Team (2020). R: A language and environment for statistical computing. R Foundation for Statistical Computing, Vienna, Austria. + + - [biomaRt](https://doi.org/10.1038/nprot.2009.97) + + > Durinck S, Spellman PT, Birney E, Huber W. (2009). Mapping identifiers for the integration of genomic datasets with the R/Bioconductor package biomaRt. Nat Protoc. 4(8):1184-91. + + - [circlize](https://doi.org/10.1093/bioinformatics/btu393) + + > Zuguang Gu, Lei Gu, Roland Eils, Matthias Schlesner, Benedikt Brors (2014). circlize implements and enhances circular visualization in R , Bioinformatics, 30,(19) 2811–2812. + + - [DESeq2](https://doi.org/10.1186/s13059-014-0550-8) + + > Love, M.I., Huber, W. & Anders, S. (2014). Moderated estimation of fold change and dispersion for RNA-seq data with DESeq2. Genome Biol 15, 550. + + - [EnhancedVolcano](https://bioconductor.org/packages/release/bioc/html/EnhancedVolcano.html) + + > Blighe K, Rana S, Lewis M (2020). EnhancedVolcano: Publication-ready volcano plots with enhanced colouring and labeling. + + - [ggplot2](https://ggplot2.tidyverse.org) + + > Wickham H (2016). ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. ISBN 978-3-319-24277-4. + + - [ggpubr](https://rpkgs.datanovia.com/ggpubr/) + + > Kassambara A. (2020). ggpubr: 'ggplot2' Based Publication Ready Plots. + + - [ihw](https://doi.org/10.1038/nmeth.3885) + + > Ignatiadis, N., Klaus, B., Zaugg, J. et al. (2016). Data-driven hypothesis weighting increases detection power in genome-scale multiple testing. Nat Methods 13, 577–580. + + - [PCAtools](https://bioconductor.org/packages/release/bioc/html/PCAtools.html) + + > Blighe K, Lun A (2020). PCAtools: PCAtools: Everything Principal Components Analysis. - - **biomaRt** Durinck S, Spellman PT, Birney E, Huber W. (2009). Mapping identifiers for the integration of genomic datasets with the R/Bioconductor package biomaRt. Nat Protoc. 4(8):1184-91. Available at: [https://doi.org/10.1038/nprot.2009.97](https://doi.org/10.1038/nprot.2009.97). Download: [https://bioconductor.org/packages/release/bioc/html/biomaRt.html](https://bioconductor.org/packages/release/bioc/html/biomaRt.html) + - [pheatmap](https://cran.r-project.org/package=pheatmap) - - **circlize** Zuguang Gu, Lei Gu, Roland Eils, Matthias Schlesner, Benedikt Brors (2014). circlize implements and enhances circular visualization in R , Bioinformatics, 30,(19) 2811–2812. Available at: [https://doi.org/10.1093/bioinformatics/btu393](https://doi.org/10.1093/bioinformatics/btu393). Download: [https://cran.r-project.org/web/packages/circlize/index.html](https://cran.r-project.org/web/packages/circlize/index.html) + > Kolde, R. (2019) Pretty Heatmaps. - - **DESeq2** Love, M.I., Huber, W. & Anders, S. (2014). Moderated estimation of fold change and dispersion for RNA-seq data with DESeq2. Genome Biol 15, 550. Available at: [https://doi.org/10.1186/s13059-014-0550-8](https://doi.org/10.1186/s13059-014-0550-8). Download: [https://bioconductor.org/packages/release/bioc/html/DESeq2.html](https://bioconductor.org/packages/release/bioc/html/DESeq2.html) + - [pvclust](https://doi.org/10.1093/bioinformatics/btl117) - - **EnhancedVolcano** Blighe K, Rana S, Lewis M (2020). EnhancedVolcano: Publication-ready volcano plots with enhanced colouring and labeling. Download: [https://bioconductor.org/packages/release/bioc/html/EnhancedVolcano.html](https://bioconductor.org/packages/release/bioc/html/EnhancedVolcano.html) + > Suzuki R., Shimodaira H., (2006). Pvclust: an R package for assessing the uncertainty in hierarchical clustering, Bioinformatics, 22(12), 1540–1542. - - **ggplot2** Wickham H (2016). ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. ISBN 978-3-319-24277-4, Download: [https://ggplot2.tidyverse.org](https://ggplot2.tidyverse.org). +- [SAMtools](https://pubmed.ncbi.nlm.nih.gov/19505943/) - - **ggpubr** Kassambara A. (2020). ggpubr: 'ggplot2' Based Publication Ready Plots. Download: [https://rpkgs.datanovia.com/ggpubr/](https://rpkgs.datanovia.com/ggpubr/) + > Li H, Handsaker B, Wysoker A, Fennell T, Ruan J, Homer N, Marth G, Abecasis G, Durbin R; 1000 Genome Project Data Processing Subgroup. The Sequence Alignment/Map format and SAMtools. Bioinformatics. 2009 Aug 15;25(16):2078-9. doi: 10.1093/bioinformatics/btp352. Epub 2009 Jun 8. PubMed PMID: 19505943; PubMed Central PMCID: PMC2723002. - - **ihw** Ignatiadis, N., Klaus, B., Zaugg, J. et al. (2016). Data-driven hypothesis weighting increases detection power in genome-scale multiple testing. Nat Methods 13, 577–580. Available at: [https://doi.org/10.1038/nmeth.3885](https://doi.org/10.1038/nmeth.3885). Download: [https://bioconductor.org/packages/release/bioc/html/IHW.html](https://bioconductor.org/packages/release/bioc/html/IHW.html) +- [Segemehl](https://doi.org/10.1371/journal.pcbi.1000502) - - **PCAtools** Blighe K, Lun A (2020). PCAtools: PCAtools: Everything Principal Components Analysis. Download: [https://bioconductor.org/packages/release/bioc/html/PCAtools.html](https://bioconductor.org/packages/release/bioc/html/PCAtools.html) + > Hoffmann S, Otto C, Kurtz S, Sharma CM, Khaitovich P, Vogel J, Stadler PF, Hackermueller J: "Fast mapping of short sequences with mismatches, insertions and deletions using index structures", PLoS Comput Biol (2009) vol. 5 (9) pp. e1000502. - - **pheatmap** Kolde, R. (2019) Pretty Heatmaps. Download: [https://cran.r-project.org/package=pheatmap](https://cran.r-project.org/package=pheatmap) +- [STAR](https://pubmed.ncbi.nlm.nih.gov/23104886/) - - **pvclust** Suzuki R., Shimodaira H., (2006). Pvclust: an R package for assessing the uncertainty in hierarchical clustering, Bioinformatics, 22(12), 1540–1542. Available at: [https://doi.org/10.1093/bioinformatics/btl117](https://doi.org/10.1093/bioinformatics/btl117). Download: [https://cran.r-project.org/web/packages/pvclust/index.html](https://cran.r-project.org/web/packages/pvclust/index.html) + > Dobin A, Davis CA, Schlesinger F, Drenkow J, Zaleski C, Jha S, Batut P, Chaisson M, Gingeras TR. STAR: ultrafast universal RNA-seq aligner Bioinformatics. 2013 Jan 1;29(1):15-21. doi: 10.1093/bioinformatics/bts635. Epub 2012 Oct 25. PubMed PMID: 23104886; PubMed Central PMCID: PMC3530905. -- **SAMtools** Li, H., Handsaker, B., Wysoker, A., Fennell, T., Ruan, J., Homer, N., … 1000 Genome Project Data Processing Subgroup. (2009). The Sequence Alignment/Map format and SAMtools. Bioinformatics , 25(16), 2078–2079. [https://doi.org/10.1093/bioinformatics/btp352](https://doi.org/10.1093/bioinformatics/btp352). Download: [http://www.htslib.org/](http://www.htslib.org/) +- [StringTie2](https://pubmed.ncbi.nlm.nih.gov/31842956/) -- **Segemehl** Hoffmann S, Otto C, Kurtz S, Sharma CM, Khaitovich P, Vogel J, Stadler PF, Hackermueller J: "Fast mapping of short sequences with mismatches, insertions and deletions using index structures", PLoS Comput Biol (2009) vol. 5 (9) pp. e1000502. Available at: [https://doi.org/10.1371/journal.pcbi.1000502](https://doi.org/10.1371/journal.pcbi.1000502). Download: [https://www.bioinf.uni-leipzig.de/Software/segemehl/](https://www.bioinf.uni-leipzig.de/Software/segemehl/) + > Kovaka S, Zimin AV, Pertea GM, Razaghi R, Salzberg SL, Pertea M. Transcriptome assembly from long-read RNA-seq alignments with StringTie2 Genome Biol. 2019 Dec 16;20(1):278. doi: 10.1186/s13059-019-1910-1. PubMed PMID: 31842956; PubMed Central PMCID: PMC6912988. -- **STAR** Dobin, A., Davis, C. A., Schlesinger, F., Drenkow, J., Zaleski, C., Jha, S., Batut, P., Chaisson, M., & Gingeras, T. R. (2013). STAR: ultrafast universal RNA-seq aligner. Bioinformatics (Oxford, England), 29(1), 15–21. Available at: [https://doi.org/10.1093/bioinformatics/bts635](https://doi.org/10.1093/bioinformatics/bts635). Download: [https://github.com/alexdobin/STAR](https://github.com/alexdobin/STAR) +- [TargetScan](https://doi.org/10.7554/elife.05005) -- **StringTie** Pertea, M., Pertea, G., Antonescu, C. et al. (2015). StringTie enables improved reconstruction of a transcriptome from RNA-seq reads. Nat Biotechnol 33, 290–295. Available at: [https://doi.org/10.1038/nbt.3122](https://doi.org/10.1038/nbt.3122). Download: [https://ccb.jhu.edu/software/stringtie/](https://ccb.jhu.edu/software/stringtie/) + > Agarwal V, Bell GW, Nam JW, Bartel DP. (2015). Predicting effective microRNA target sites in mammalian mRNAs. Elife, 4:e05005. -- **TargetScan** Agarwal V, Bell GW, Nam JW, Bartel DP. (2015). Predicting effective microRNA target sites in mammalian mRNAs. Elife, 4:e05005. Available at: [https://doi.org/10.7554/elife.05005](https://doi.org/10.7554/elife.05005). Download: [http://www.targetscan.org/cgi-bin/targetscan/data_download.vert72.cgi](http://www.targetscan.org/cgi-bin/targetscan/data_download.vert72.cgi) +- [ViennaRNA](https://doi.org/10.1186/1748-7188-6-26) -- **ViennaRNA** Lorenz, R., Bernhart, S.H., Höner zu Siederdissen, C. et al. (2011). ViennaRNA Package 2.0. Algorithms Mol Biol 6, 26. Available at: [https://doi.org/10.1186/1748-7188-6-26](https://doi.org/10.1186/1748-7188-6-26). Download: [https://www.tbi.univie.ac.at/RNA/#download](https://www.tbi.univie.ac.at/RNA/#download) + > Lorenz, R., Bernhart, S.H., Höner zu Siederdissen, C. et al. (2011). ViennaRNA Package 2.0. Algorithms Mol Biol 6, 26. ## Test data References -Dong Cao (2021). An autoregulation loop in fust-1 for circular RNA regulation in Caenorhabditis elegans. Biorxiv. Available at: [https://doi.org/10.1101/2021.03.22.436400](https://doi.org/10.1101/2021.03.22.436400). + > Cao D. An autoregulation loop in fust-1 for circular RNA regulation in Caenorhabditis elegans. Genetics. 2021 Nov 5;219(3):iyab145. doi: 10.1093/genetics/iyab145. PMID: 34740247; PMCID: PMC8570788. ## Software packaging/containerisation tools diff --git a/README.md b/README.md index 6e8ee225..bd2c7b02 100644 --- a/README.md +++ b/README.md @@ -20,28 +20,28 @@ On release, automated continuous integration tests run the pipeline on a full-si ## Pipeline summary -1. Raw read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/)) -2. Adapter trimming ([`Trim Galore!`](https://www.bioinformatics.babraham.ac.uk/projects/trim_galore/)) -3. circRNA quantification - 1. [`CIRIquant`](https://github.com/Kevinzjy/CIRIquant) - 2. [`STAR 2-Pass mode`](https://github.com/alexdobin/STAR) - 1. [`CIRCexplorer2`](https://circexplorer2.readthedocs.io/en/latest/) - 2. [`circRNA finder`](https://github.com/orzechoj/circRNA_finder) - 3. [`DCC`](https://github.com/dieterich-lab/DCC) - 3. [`find circ`](https://github.com/marvin-jens/find_circ) - 4. [`MapSplice`](http://www.netlab.uky.edu/p/bioinfo/MapSplice2) - 5. [`Segemehl`](https://www.bioinf.uni-leipzig.de/Software/segemehl/) -4. circRNA annotation -5. Export mature spliced length as FASTA file -6. Annotate parent gene, underlying transcripts. -7. circRNA count matrix -8. miRNA target prediction - 1. [`miRanda`](http://cbio.mskcc.org/miRNA2003/miranda.html) - 2. [`TargetScan`](http://www.targetscan.org/cgi-bin/targetscan/data_download.vert72.cgi) - 3. Filter results, miRNAs must be called by both tools -9. Differential expression analysis [`DESeq2`](https://bioconductor.org/packages/release/bioc/html/DESeq2.html) -10. Circular - Linear ratio tests ['CircTest'](https://github.com/dieterich-lab/CircTest) -11. MultiQC report [`MultiQC`](http://multiqc.info/) +- Raw read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/)) +- Adapter trimming ([`Trim Galore!`](https://www.bioinformatics.babraham.ac.uk/projects/trim_galore/)) +- circRNA quantification +- [`CIRIquant`](https://github.com/Kevinzjy/CIRIquant) +- [`STAR 2-Pass mode`](https://github.com/alexdobin/STAR) + - [`CIRCexplorer2`](https://circexplorer2.readthedocs.io/en/latest/) + - [`circRNA finder`](https://github.com/orzechoj/circRNA_finder) + - [`DCC`](https://github.com/dieterich-lab/DCC) +- [`find circ`](https://github.com/marvin-jens/find_circ) +- [`MapSplice`](http://www.netlab.uky.edu/p/bioinfo/MapSplice2) +- [`Segemehl`](https://www.bioinf.uni-leipzig.de/Software/segemehl/) +- circRNA annotation +- Export mature spliced length as FASTA file +- Annotate parent gene, underlying transcripts. +- circRNA count matrix +- miRNA target prediction + - [`miRanda`](http://cbio.mskcc.org/miRNA2003/miranda.html) + - [`TargetScan`](http://www.targetscan.org/cgi-bin/targetscan/data_download.vert72.cgi) + - Filter results, miRNAs must be called by both tools +- Differential expression analysis [`DESeq2`](https://bioconductor.org/packages/release/bioc/html/DESeq2.html) +- Circular - Linear ratio tests ['CircTest'](https://github.com/dieterich-lab/CircTest) +- MultiQC report [`MultiQC`](http://multiqc.info/) ## Quick Start diff --git a/bin/DEA.R b/bin/DEA.R index 5e1658f7..83f3cccf 100755 --- a/bin/DEA.R +++ b/bin/DEA.R @@ -1,8 +1,7 @@ #!/usr/bin/env Rscript -# Automated differential expression analysis script for nf-core/circrna -# Relies on Stirngtie prepde.py outputs -# Would be fun to adapt to STAR + Kallisto for own use in future. +## Author: Barry Digby +## License: MIT get_args <- function(){ @@ -121,20 +120,6 @@ checkinputdata <- function(phenotype){ giveError("Not enough samples per condition to perform DE analysis!") } - # Rename sex to gender.. - if("sex" %in% names(pheno)){ - print("Renaming sex to gender in phenotype file") - rename <- gsub("sex", "gender", names(pheno)) - names(pheno) <- rename - } - - # Check gender is only male, female, unknown - if ("gender" %in% names(pheno)) { - if (! all(unique(pheno$gender) %in% c("m", "f", "u"))) { - giveError("SAMPLEINFO ERROR:\nOnly the values m [male], f [female] and u [unknown] are supported in field .\n") - } - } - ## check if all columns are factors. If numeric, convert to factor. factor_cols <- sapply(pheno, is.factor) if(all(factor_cols) == TRUE){ @@ -175,8 +160,6 @@ ens2symbol <- function(mat, inputdata){ ## designed to work on input gene_count_matrix.csv file ## everything else downstream no longer needs to be converted - ## figure out if working with ENS, or ENS IDs - mat <- as.data.frame(mat) map <- inputdata$map species <- inputdata$species @@ -367,12 +350,6 @@ getDESeqDEAbyContrast <- function(dds, contrast, reference, var, outdir, inputda res_df <- as.data.frame(res) - #if(outdir == "RNA-Seq/"){ - # ann_res <- ens2symbol(res_df, inputdata) - #}else{ - # ann_res <- res_df - #} - volcano_plot(res_df, contrast, outdir) pdf(file.path(dir, paste("DESeq2", contrast, "fold_change_distribution.pdf", sep="_")), width=8, height=8) @@ -623,29 +600,17 @@ make_boxplots <- function(de, cts, contrast){ options(error=function()traceback(2)) suppressPackageStartupMessages(library("argparser")) -#suppressPackageStartupMessages(library("BiocParallel")) suppressPackageStartupMessages(library("biomaRt")) suppressPackageStartupMessages(library("DESeq2")) suppressPackageStartupMessages(library("dplyr")) -#suppressPackageStartupMessages(library("edgeR")) suppressPackageStartupMessages(library("EnhancedVolcano")) -#suppressPackageStartupMessages(library("EnsDb.Hsapiens.v86")) -#suppressPackageStartupMessages(library("genefilter")) #for rowVars suppressPackageStartupMessages(library("ggplot2")) suppressPackageStartupMessages(library("ggpubr")) -#suppressPackageStartupMessages(library("ggrepel")) -#suppressPackageStartupMessages(library("ggfortify")) suppressPackageStartupMessages(library("gplots")) suppressPackageStartupMessages(library("IHW")) -#suppressPackageStartupMessages(library("limma")) -#suppressPackageStartupMessages(library("parallel")) suppressPackageStartupMessages(library("PCAtools")) suppressPackageStartupMessages(library("pheatmap")) suppressPackageStartupMessages(library("RColorBrewer")) -#suppressPackageStartupMessages(library("readr")) -#suppressPackageStartupMessages(library("Rsubread")) -#suppressPackageStartupMessages(library("tximport")) -#suppressPackageStartupMessages(library("VennDiagram")) arg <- get_args() diff --git a/bin/ID_to_BED.sh b/bin/ID_to_BED.sh deleted file mode 100755 index 432ef3b8..00000000 --- a/bin/ID_to_BED.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -file=$1 - -while IFS='' read -r line; do - - name=$(echo $line) - chr=$(echo $line | cut -d: -f1) - start=$(echo $line | cut -d- -f1 | cut -d: -f2) - stop=$(echo $line | cut -d- -f2 | cut -d: -f1) - sign=$(echo $line | cut -d: -f3) - - echo -e "$chr\t$start\t$stop\t$name\t0\t$sign" >> ${name}.bed - -done < $file diff --git a/bin/annotate_outputs.sh b/bin/annotate_outputs.sh index 92abc21b..3c2054f2 100755 --- a/bin/annotate_outputs.sh +++ b/bin/annotate_outputs.sh @@ -1,14 +1,11 @@ #!/usr/bin/env bash -## -## Expected Input: -## Chr Start Stop name count strand -## name= chr":"start"-"stop":"strand - echo "====================================================================================" echo "[nf-core/circrna]: circRNA annotation script " echo "[nf-core/circrna]: Author: Barry Digby " echo "[nf-core/circrna]: Institution: National University of Ireland, Galway " +echo "[nf-core/circrna]: " +echo "[nf-core/circrna]: MIT license " echo "====================================================================================" mkdir -p bed12 diff --git a/bin/backsplice_gen.sh b/bin/backsplice_gen.sh index 2801c52b..3134046b 100755 --- a/bin/backsplice_gen.sh +++ b/bin/backsplice_gen.sh @@ -1,5 +1,9 @@ #!/usr/bin/env bash +## Shell script to generate backsplice sequence from circRNA sequence. +## Author: Barry Digby +## License: MIT + ## .fa = backsplice .fasta = canonical to publish file_prefix=$(basename $1 .fa) diff --git a/bin/check_empty.sh b/bin/check_empty.sh index f45532d0..2f54d6da 100755 --- a/bin/check_empty.sh +++ b/bin/check_empty.sh @@ -2,6 +2,8 @@ ## When consolidating tool outputs for a sample, check if any are empty. ## This will prevent R from throwing errors +## Author: Barry Digby +## License: MIT for i in *bed; do diff --git a/bin/check_samplesheet.py b/bin/check_samplesheet.py index aea3b88b..339900f2 100755 --- a/bin/check_samplesheet.py +++ b/bin/check_samplesheet.py @@ -58,7 +58,6 @@ def check_samplesheet(file_in, file_out): ## Check header MIN_COLS = 2 ## edit by BDigby as not using strandedness yet. - # HEADER = ["sample", "fastq_1", "fastq_2", "strandedness"] HEADER = ["sample", "fastq_1", "fastq_2"] header = [x.strip('"') for x in fin.readline().strip().split(",")] if header[: len(HEADER)] != HEADER: @@ -87,7 +86,6 @@ def check_samplesheet(file_in, file_out): ) ## Check sample name entries - # sample, fastq_1, fastq_2, strandedness = lspl[: len(HEADER)] sample, fastq_1, fastq_2 = lspl[: len(HEADER)] if sample.find(" ") != -1: print(f"WARNING: Spaces have been replaced by underscores for sample: {sample}") @@ -107,29 +105,11 @@ def check_samplesheet(file_in, file_out): line, ) - ## Check strandedness - # strandednesses = ["unstranded", "forward", "reverse"] - # if strandedness: - # if strandedness not in strandednesses: - # print_error( - # f"Strandedness must be one of '{', '.join(strandednesses)}'!", - # "Line", - # line, - # ) - # else: - # print_error( - # f"Strandedness has not been specified! Must be one of {', '.join(strandednesses)}.", - # "Line", - # line, - # ) - ## Auto-detect paired-end/single-end sample_info = [] ## [single_end, fastq_1, fastq_2, strandedness] if sample and fastq_1 and fastq_2: ## Paired-end short reads - # sample_info = ["0", fastq_1, fastq_2, strandedness] sample_info = ["0", fastq_1, fastq_2] elif sample and fastq_1 and not fastq_2: ## Single-end short reads - # sample_info = ["1", fastq_1, fastq_2, strandedness] sample_info = ["1", fastq_1, fastq_2] else: print_error("Invalid combination of columns provided!", "Line", line) @@ -148,7 +128,6 @@ def check_samplesheet(file_in, file_out): out_dir = os.path.dirname(file_out) make_dir(out_dir) with open(file_out, "w") as fout: - # fout.write(",".join(["sample", "single_end", "fastq_1", "fastq_2", "strandedness"]) + "\n") fout.write(",".join(["sample", "single_end", "fastq_1", "fastq_2"]) + "\n") for sample in sorted(sample_mapping_dict.keys()): @@ -160,14 +139,6 @@ def check_samplesheet(file_in, file_out): sample, ) - ## Check that multiple runs of the same sample are of the same strandedness - # if not all(x[-1] == sample_mapping_dict[sample][0][-1] for x in sample_mapping_dict[sample]): - # print_error( - # f"Multiple runs of a sample must have the same strandedness!", - # "Sample", - # sample, - # ) - for idx, val in enumerate(sample_mapping_dict[sample]): fout.write(",".join([f"{sample}_T{idx+1}"] + val) + "\n") else: diff --git a/bin/circRNA_counts_matrix.py b/bin/circRNA_counts_matrix.py index bcd6ff96..07999b23 100755 --- a/bin/circRNA_counts_matrix.py +++ b/bin/circRNA_counts_matrix.py @@ -1,6 +1,14 @@ import sys, glob from collections import defaultdict +""" +Script to parse circRNA quantification bed files, creating a count matrix suitable for statistical analyses +requires python 2.7 +Author: Declan Bennett @declan93 +License: MIT +""" + + par = sys.argv hld = defaultdict(list) samps = defaultdict(list) @@ -31,7 +39,6 @@ def Diff(list1, list2): disj = Diff(tmp, [a_tuple[0] for a_tuple in v]) for val in disj: v.append((val, "0")) - # print(" ".join(k.split("_")),v) li = [] for h in tmp: for x in v: diff --git a/bin/circ_test.R b/bin/circ_test.R index 96a4f81e..3e9ea6af 100755 --- a/bin/circ_test.R +++ b/bin/circ_test.R @@ -4,7 +4,11 @@ require(aod) require(plyr) require(ggplot2) -# The CircTest devs never had containers in mind for their code. It is not published on any R channels, nor are there any stable releases on their github page. I have decided to take their source functions and roll with it instead. +## CircTest functions +## Package: CircTest (https://github.com/dieterich-lab/CircTest) +## Version: 0.1.1 +## Author(s): Jun Cheng, Tobias Jakobi +## License: GPL ## SUMMMARY @@ -140,7 +144,6 @@ Circ.ratioplot <- function(Circ,Linear,CircCoordinates = None,plotrow='1',size=2 theme(legend.text=element_text(size=size)) + theme(plot.title = element_text(size=size)) + theme(axis.text.y = element_text(margin=margin(5,5,10,5,"pt")))+ - #labs(list(title=paste("Annotation: ", genename, "\nChr ", toString(Circ[plotrow,circle_description]),sep=""),x=x,y=y)) + ggtitle(paste("Annotation: ", genename, "\nChr ", toString(Circ[plotrow,circle_description]),sep="")) + ylab("circRNA/(circRNA + Linear RNA)") + xlab("Sample") + @@ -179,7 +182,6 @@ Circ.ratioplot <- function(Circ,Linear,CircCoordinates = None,plotrow='1',size=2 Circ.lineplot <- function(Circ,Linear,CircCoordinates = None,plotrow='1',size=18,ncol=2,groupindicator1=NULL,groupindicator2=NULL,x='Conditions',y='Counts', circle_description = c(1:3), gene_column = None){ require(ggplot2) - #require(Rmisc) if( !is.null(groupindicator1) & length(groupindicator1) != ncol(Circ)-length(circle_description) ){ stop("If provided, the length of groupindicator1 should be equal to the number of samples.") @@ -376,21 +378,16 @@ Circ.test <- function(Circ, Linear, CircCoordinates=None, group, alpha=0.05, plo # test models a <- anova(fitNull,fitAlt) p.value <- a@anova.table[,11][2] - # print(predict(fitAlt,testdat, se.fit=T)) p.val <- c( p.val, p.value ) - # dir <- 1 # fitAlt@param[2][["group2"]] - # direction <- c(direction, dir) } message(paste(counter, "candidates processed in total")) Circ$direction <- direction - #names(Circ$direction ) <- c("direction") p.adj <- p.adjust(p.val,n=sum(!is.na(p.val)),'BH') # select significant ones sig_dat <- Circ[p.adj<=alpha & !is.na(p.adj),] sig_ratios <- tmp_df[p.adj<=alpha & !is.na(p.adj),] sig_p <- p.adj[p.adj<=alpha & !is.na(p.adj)] - # direction <- direction[p.adj<=alpha & !is.na(p.adj)] # sort by p-val sig_dat <- sig_dat[order(sig_p),] @@ -404,9 +401,6 @@ Circ.test <- function(Circ, Linear, CircCoordinates=None, group, alpha=0.05, plo rownames(summary_table) <- rownames(sig_dat) names(summary_table) <- c(names(sig_dat)[circle_description],"sig_p",names(sig_ratios)[circle_description]) } else { - # summary_table <- cbind(CircCoordinates[rownames(sig_dat),],sig_p,sig_dat$direction) - # colnames(summary_table) <- c(colnames(CircCoordinates),"sig_p","direction") - summary_table <- cbind(CircCoordinates[rownames(sig_dat),],sig_p,sig_ratios) colnames(summary_table) <- c(colnames(CircCoordinates),"sig_p",colnames(sig_ratios)) } @@ -420,7 +414,6 @@ Circ.test <- function(Circ, Linear, CircCoordinates=None, group, alpha=0.05, plo p.adj=p.adj, sig_p=sig_p, ratios=sig_ratios - # direction=direction ) ) } diff --git a/bin/consolidate_algorithms_intersection.R b/bin/consolidate_algorithms_intersection.R index a147c105..1fbd27b4 100755 --- a/bin/consolidate_algorithms_intersection.R +++ b/bin/consolidate_algorithms_intersection.R @@ -1,4 +1,10 @@ -#!/usr/bin/Rscript +#!/usr/bin/env Rscript + +## Script to consolidate circRNAs across multiple tools. Allow user +## to apply 'max' or 'mean' aggregate function to those called by multiple +## tools. +## Author: Barry Digby +## License: MIT get_args <- function(){ diff --git a/bin/prepare_circ_test.R b/bin/prepare_circ_test.R index 065119d5..f95b8f9c 100755 --- a/bin/prepare_circ_test.R +++ b/bin/prepare_circ_test.R @@ -1,5 +1,8 @@ #!/usr/bin/env Rscript +## Author: Barry Digby +## License: MIT + circ_mat = read.table("count_matrix.txt", header=T, sep="\t", check.names = FALSE, stringsAsFactors = F, row.names = "ID") gene_mat = read.table("gene_count_matrix.csv", sep=",", header=T, row.names="gene_id", stringsAsFactors = F) map = read.table("circrna_host-gene.txt", header = F, sep="\t", stringsAsFactors = F) diff --git a/bin/reformat_count_matrix.R b/bin/reformat_count_matrix.R index c78b48d7..8afabe6f 100755 --- a/bin/reformat_count_matrix.R +++ b/bin/reformat_count_matrix.R @@ -1,4 +1,8 @@ #!/usr/bin/env Rscript + +## Author: Barry Digby +## License: MIT + library(dplyr) mat <- read.table("circRNA_matrix.txt", sep="\t", header=T, stringsAsFactors=F) mat$ID <- with(mat, paste0(Chr, sep=":", Start, sep="-", Stop, sep=":", Strand)) diff --git a/bin/targetscan_format.sh b/bin/targetscan_format.sh index 2a23c9f6..9321221b 100755 --- a/bin/targetscan_format.sh +++ b/bin/targetscan_format.sh @@ -1,4 +1,7 @@ -#!/usr/bin/env +#!/usr/bin/env bash + +## Author: Barry Digby +## License: MIT ## Script that converts miRbase (mature.fa) file to ## TargetScan compatability. The motivation for doing @@ -15,7 +18,6 @@ ## Stage input mature.fa file, species MATURE="$1" -#GENOME_ID="$2" ## Uncompress if necessary if [ ${MATURE: -3} == ".gz" ]; then @@ -35,7 +37,7 @@ paste miR_ID seed_sequence > targetscan_tmp.txt ## Correct delimiter, add dummy species awk -v OFS="\t" '{print $1, $2, "0000"}' targetscan_tmp.txt > mature.txt -## Tidy the work dir (uncomment these for debugging scratch dirs) +## Tidy the work dir (comment these for debugging scratch dirs) rm -rf mature_sequence rm -rf miR_ID rm -rf targetscan_tmp.txt diff --git a/conf/modules.config b/conf/modules.config index f535f691..21b50e7e 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -38,7 +38,7 @@ process { ] } - // TRIMMING couresy of nf-core/rnaseq + // TRIMMING courtesy of nf-core/rnaseq if (!params.skip_trimming) { process { @@ -180,9 +180,9 @@ if (!params.skip_trimming) { "--outFilterType BySJout", "--outReadsUnmapped None", "--readFilesCommand zcat", - params.alignSJDBoverhangMin ? "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}" : "", - params.chimJunctionOverhangMin ? "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}" : "", - params.chimSegmentMin ? "--chimSegmentMin ${params.chimSegmentMin}" : "" + "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", + "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ path: { "${params.outdir}/circrna_discovery/star/1st_pass" }, @@ -205,16 +205,15 @@ if (!params.skip_trimming) { withName: STAR_2ND_PASS { ext.when = { params.module.split(',').contains('circrna_discovery') && ( params.tool.split(',').contains('circexplorer2') || params.tool.split(',').contains('circrna_finder') ) } ext.args = [ "", - // TODO: is this valid when both tools are run? params.tool.split(',').contains('circrna_finder') ? "--chimOutType Junctions SeparateSAMold" : "--chimOutType Junctions WithinBAM", "--outSAMunmapped Within", "--outFilterType BySJout", "--outReadsUnmapped None", "--readFilesCommand zcat", "--sjdbFileChrStartEnd dataset.SJ.out.tab", - params.alignSJDBoverhangMin ? "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}" : "--alignSJDBoverhangMin 10", - params.chimJunctionOverhangMin ? "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}" : "--chimJunctionOverhangMin 10", - params.chimSegmentMin ? "--chimSegmentMin ${params.chimSegmentMin}" : "--chimSegmentMin 10" + "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", + "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ path: { "${params.outdir}/circrna_discovery/star/2nd_pass" }, @@ -240,7 +239,6 @@ if (!params.skip_trimming) { withName: CIRCEXPLORER2_PARSE { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } - publishDir = [ path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates" }, mode: params.publish_dir_mode, @@ -380,9 +378,9 @@ if (!params.skip_trimming) { "--outFilterType BySJout", "--outReadsUnmapped None", "--readFilesCommand zcat", - params.alignSJDBoverhangMin ? "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}" : "", - params.chimJunctionOverhangMin ? "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}" : "", - params.chimSegmentMin ? "--chimSegmentMin ${params.chimSegmentMin}" : "" + "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", + "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/align/1st_pass" }, @@ -411,9 +409,9 @@ if (!params.skip_trimming) { "--outReadsUnmapped None", "--readFilesCommand zcat", "--sjdbFileChrStartEnd dataset.SJ.out.tab", - params.alignSJDBoverhangMin ? "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}" : "--alignSJDBoverhangMin 10", - params.chimJunctionOverhangMin ? "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}" : "--chimJunctionOverhangMin 10", - params.chimSegmentMin ? "--chimSegmentMin ${params.chimSegmentMin}" : "--chimSegmentMin 10" + "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", + "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/align/2nd_pass" }, @@ -432,9 +430,9 @@ if (!params.skip_trimming) { "--outFilterType BySJout", "--outReadsUnmapped None", "--readFilesCommand zcat", - params.alignSJDBoverhangMin ? "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}" : "", - params.chimJunctionOverhangMin ? "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}" : "", - params.chimSegmentMin ? "--chimSegmentMin ${params.chimSegmentMin}" : "" + "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", + "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate1/1st_pass" }, @@ -464,9 +462,9 @@ if (!params.skip_trimming) { "--outReadsUnmapped None", "--readFilesCommand zcat", "--sjdbFileChrStartEnd dataset.SJ.out.tab", - params.alignSJDBoverhangMin ? "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}" : "--alignSJDBoverhangMin 10", - params.chimJunctionOverhangMin ? "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}" : "--chimJunctionOverhangMin 10", - params.chimSegmentMin ? "--chimSegmentMin ${params.chimSegmentMin}" : "--chimSegmentMin 10" + "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", + "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate1/2nd_pass" }, @@ -485,9 +483,9 @@ if (!params.skip_trimming) { "--outFilterType BySJout", "--outReadsUnmapped None", "--readFilesCommand zcat", - params.alignSJDBoverhangMin ? "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}" : "", - params.chimJunctionOverhangMin ? "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}" : "", - params.chimSegmentMin ? "--chimSegmentMin ${params.chimSegmentMin}" : "" + "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", + "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate2/1st_pass" }, @@ -517,9 +515,9 @@ if (!params.skip_trimming) { "--outReadsUnmapped None", "--readFilesCommand zcat", "--sjdbFileChrStartEnd dataset.SJ.out.tab", - params.alignSJDBoverhangMin ? "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}" : "--alignSJDBoverhangMin 10", - params.chimJunctionOverhangMin ? "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}" : "--chimJunctionOverhangMin 10", - params.chimSegmentMin ? "--chimSegmentMin ${params.chimSegmentMin}" : "--chimSegmentMin 10" + "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", + "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate2/2nd_pass" }, @@ -556,11 +554,11 @@ if (!params.skip_trimming) { withName: MAPSPLICE_ALIGN { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } ext.args = [ "", - params.seglen ? "--seglen ${params.seglen}" : "--seglen 25", - params.min_intron ? "--min-intron ${params.min_intron}" : "--min-intron 20", - params.max_intron ? "--max-intron ${params.max_intron}" : "--max-intron 1000000", - params.min_map_len ? "--min-map-len ${params.min_map_len}" : "--min-map-len 40", - params.min_fusion_distance ? "--min-fusion-distance ${params.min_fusion_distance}" : "--min-fusion-distance 200", + "--seglen ${params.seglen}", + "--min-intron ${params.min_intron}", + "--max-intron ${params.max_intron}", + "--min-map-len ${params.min_map_len}", + "--min-fusion-distance ${params.min_fusion_distance}", "--fusion-non-canonical" ].join(' ').trim() publishDir = [ @@ -571,7 +569,7 @@ if (!params.skip_trimming) { ] } -withName: MAPSPLICE_PARSE { + withName: MAPSPLICE_PARSE { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } publishDir = [ path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates" }, diff --git a/conf/test.config b/conf/test.config index d778abc1..10095fa6 100644 --- a/conf/test.config +++ b/conf/test.config @@ -17,7 +17,7 @@ params { // Limit resources so that this can run on GitHub Actions max_cpus = 2 max_memory = 6.GB - max_time = 48.h + max_time = 6.h // Input data for test data input = 'https://raw.githubusercontent.com/nf-core/test-datasets/circrna/samples.csv' diff --git a/docs/output.md b/docs/output.md index a3ed45d6..27dd215f 100644 --- a/docs/output.md +++ b/docs/output.md @@ -20,60 +20,71 @@ A full run of the workflow will produce the following directory output structure The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes data using the following steps: -- [nf-core/circrna: Output](#nf-corecircrna-output) - - [Introduction](#introduction) - - [Pipeline Overview](#pipeline-overview) - - [Quality Control](#quality-control) - - [Sam to Fastq](#sam-to-fastq) - - [BBDUK](#bbduk) - - [DESeq2](#deseq2) - - [MultiQC](#multiqc) - - [Genome Index Files](#genome-index-files) - - [circRNA Quantification](#circrna-quantification) - - [CIRCexplorer2](#circexplorer2) - - [circRNA finder](#circrna-finder) - - [CIRIquant](#ciriquant) - - [DCC](#dcc) - - [Find circ](#find-circ) - - [MapSplice](#mapsplice) - - [STAR](#star) - - [Segemehl](#segemehl) - - [Count Matrix](#count-matrix) - - [miRNA Prediction](#mirna-prediction) - - [miRanda](#miranda) - - [TargetScan](#targetscan) - - [miRNA targets](#mirna-targets) - - [Circos Plot](#circos-plot) - - [Differential Expression Analysis](#differential-expression-analysis) - - [circRNA](#circrna) - - [Boxplots](#boxplots) - - [RNA-Seq](#rna-seq) +- Raw read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/)) +- Adapter trimming ([`Trim Galore!`](https://www.bioinformatics.babraham.ac.uk/projects/trim_galore/)) +- MultiQC report [`MultiQC`](http://multiqc.info/) +- circRNA quantification +- [`CIRIquant`](https://github.com/Kevinzjy/CIRIquant) +- [`STAR 2-Pass mode`](https://github.com/alexdobin/STAR) + - [`CIRCexplorer2`](https://circexplorer2.readthedocs.io/en/latest/) + - [`circRNA finder`](https://github.com/orzechoj/circRNA_finder) + - [`DCC`](https://github.com/dieterich-lab/DCC) +- [`find circ`](https://github.com/marvin-jens/find_circ) +- [`MapSplice`](http://www.netlab.uky.edu/p/bioinfo/MapSplice2) +- [`Segemehl`](https://www.bioinf.uni-leipzig.de/Software/segemehl/) +- circRNA annotation +- Export mature spliced length as FASTA file +- Annotate parent gene, underlying transcripts. +- circRNA count matrix +- miRNA target prediction + - [`miRanda`](http://cbio.mskcc.org/miRNA2003/miranda.html) + - [`TargetScan`](http://www.targetscan.org/cgi-bin/targetscan/data_download.vert72.cgi) + - Filter results, miRNAs must be called by both tools +- Differential expression analysis [`DESeq2`](https://bioconductor.org/packages/release/bioc/html/DESeq2.html) +- Circular - Linear ratio tests ['CircTest'](https://github.com/dieterich-lab/CircTest) ## Quality Control -### Sam to Fastq +### FastQC
Output files -- `quality_control/SamToFastq` - - `*_R{1,2}.fq.gz`: Paired end fastq files, generated using `VALIDATION_STRINGENCY=LENIENT`. +- `fastqc/` + - `*_fastqc.html`: FastQC report containing quality metrics. + - `*_fastqc.zip`: Zip archive containing the FastQC report, tab-delimited data file and plot images. + +> **NB:** The FastQC plots in this directory are generated relative to the raw, input reads. They may contain adapter sequence and regions of low quality. To see how your reads look after adapter and quality trimming please refer to the FastQC reports in the `trimgalore/fastqc/` directory.
-`nf-core/circrna` can accept input BAM files generated from paired end sequencing reads (e.g `TCGA`) by invoking [picard](https://broadinstitute.github.io/picard/) `SamToFastq`, converting BAM files to paired end fastq files. +[FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/) gives general quality metrics about your sequenced reads. It provides information about the quality score distribution across your reads, per base sequence content (%A/T/G/C), adapter contamination and overrepresented sequences. For further reading and documentation see the [FastQC help pages](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/). + +![MultiQC - FastQC sequence counts plot](images/mqc_fastqc_counts.png) + +![MultiQC - FastQC mean quality scores plot](images/mqc_fastqc_quality.png) + +![MultiQC - FastQC adapter content plot](images/mqc_fastqc_adapter.png) -### BBDUK +### TrimGalore
Output files -- `quality_control/BBDUK/` - - `*_r{1,2}.trim.fq.gz`: Processed paired end fastq files. +- `trimgalore/` + - `*.fq.gz`: If `--save_trimmed` is specified, FastQ files **after** adapter trimming will be placed in this directory. + - `*_trimming_report.txt`: Log file generated by Trim Galore!. +- `trimgalore/fastqc/` + - `*_fastqc.html`: FastQC report containing quality metrics for read 1 (_and read2 if paired-end_) **after** adapter trimming. + - `*_fastqc.zip`: Zip archive containing the FastQC report, tab-delimited data file and plot images.
-[BBDUK](https://jgi.doe.gov/data-and-tools/bbtools/bb-tools-user-guide/bbduk-guide/) (DUK - "Decontamination Using Kmers") is capable of performing adapter trimming, quality trimming/filtering and read length filtering (refer to BBDUK [parameter documentation](https://nf-co.re/circrna/dev/parameters#read-trimming--adapter-removal)) for the quality control of sequencing reads. `nf-core/circrna` will automatically output gzipped fastq files from `BBDUK` to minimise data usage. +[Trim Galore!](https://www.bioinformatics.babraham.ac.uk/projects/trim_galore/) is a wrapper tool around Cutadapt and FastQC to peform quality and adapter trimming on FastQ files. By default, Trim Galore! will automatically detect and trim the appropriate adapter sequence. + +> **NB:** TrimGalore! will only run using multiple cores if you are able to use more than > 5 and > 6 CPUs for single- and paired-end data, respectively. The total cores available to TrimGalore! will also be capped at 4 (7 and 8 CPUs in total for single- and paired-end data, respectively) because there is no longer a run-time benefit. See [release notes](https://github.com/FelixKrueger/TrimGalore/blob/master/Changelog.md#version-060-release-on-1-mar-2019) and [discussion whilst adding this logic to the nf-core/atacseq pipeline](https://github.com/nf-core/atacseq/pull/65). + +![MultiQC - cutadapt trimmed sequence length plot](images/mqc_cutadapt_trimmed.png) ### DESeq2 @@ -81,46 +92,36 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d Output files - `quality_control/DESeq2_QC` - - `circRNA/` - - `DESeq2_condition_PCA.pdf`: PCA plot of PC1 vs. PC2 displaying the highest amount of variation within the response variable `condition`.

circRNA PCA

- - `DESeq2_dispersion.pdf`: Plot of re-fitted genes + gene outliers after shrinkage estimation performed by gene-wide maximum likelihood estimates (red curve) & maximum a posteriori estimates of dispersion.

circRNA dispersion

- - `DESeq2_sample_dendogram.pdf`: Dendogram displaying sample distances using [pvclust](https://cran.r-project.org/web/packages/pvclust/index.html).

circRNA dendo

- - `DESeq2_sample_heatmap.pdf`: Heatmap displaying Manhattan distance between samples.

circRNA samplehm

- - `RNA-Seq/` - - `DESeq2_condition_PCA.pdf`: PCA plot of PC1 vs. PC2 displaying the highest amount of variation within the response variable `condition`.

circRNA PCA

- - `DESeq2_dispersion.pdf`: Plot of re-fitted genes + gene outliers after shrinkage estimation performed by gene-wide maximum likelihood estimates (red curve) & maximum a posteriori estimates of dispersion.

circRNA dispersion

- - `DESeq2_sample_dendogram.pdf`: Dendogram displaying sample distances using [pvclust](https://cran.r-project.org/web/packages/pvclust/index.html).

circRNA dendo

- - `DESeq2_sample_heatmap.pdf`: Heatmap displaying Manhattan distance between samples.

circRNA samplehm @@ -159,7 +160,7 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d -`nf-core/circrna` will save genome indices when `--save_reference true`. This is highly encouraged to reduce runtimes on redeployment of the workflow. +`nf-core/circrna` will save genome indices when `--save_reference true`. This is highly encouraged to reduce runtimes on redeployment of the workflow, as you can supply them to aligner in question via the aligner flag (for example `--star '/path/to/STAR/'`. Available: `bowtie`, `bowtie2`, `bwa`, `hisat2`, `star`, `segemehl`). Make sure to move the saved genome indicies to a different location before doing so. ## circRNA Quantification @@ -169,10 +170,8 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d

Output files - `circrna_discovery/CIRCexplorer2/intermediates/${sample_id}/` - - `*.STAR.junction.bed`: Intermediate file generated by `CIRCexplorer2 parse` module, identifying STAR fusion junctions for downstream annotation. - `*.txt`: Output files generated by `CIRCexplorer2 annotate` module, based on BED 12 format containing circRNA genomic location information, exon cassette composition and an additional 6 columns specifying circRNA annotations. Full descriptions of the 18 columns can be found in the `CIRCexplorer2` [documentation](https://circexplorer2.readthedocs.io/en/latest/modules/annotate/#output). - - `circrna_discovery/CIRCexplorer2/${sample_id}/` - `${sample_id}.bed`: Filtered, annotated circRNAs in customised BED12 format. - `fasta/`: Mature spliced length circRNA FASTA sequences. @@ -187,7 +186,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d Output files - `circrna_discovery/circRNA_Finder/intermediates/${sample_id}/` - - `*.Aligned.sortedByCoord.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). - `*.Chimeric.out.sam`: Chimeric alignments in SAM format. @@ -199,8 +197,7 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d - `*.filteredJunctions.bed`: A bed file with **all** circular junctions found by the pipeline. The score column indicates the number reads spanning each junction. - `*.s_filteredJunctions.bed`: A bed file with those junctions in `*.filteredJunctions.bed` that are flanked by GT-AG splice sites. The score column indicates the number reads spanning each junction. - `*.s_filteredJunctions_fw.bed`: A bed file with the same circular junctions as in file (b), but here the score column gives the average number of forward spliced reads at both splice sites around each circular junction. - -- `circrna_discovery/circRNA_Finder/${sample_id}/ +- `circrna_discovery/circRNA_Finder/${sample_id}/` - `${sample_id}.bed`: Filtered, annotated circRNAs in customised BED12 format. - `fasta/`: Mature spliced length circRNA FASTA sequences. @@ -214,7 +211,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d Output files - `circrna_discovery/CIRIquant/intermediates/${sample_id}/` - - `*.log`: A `CIRIerror.log` file which should be empty, and a `${sample_id}.log` file which contains the output log of `CIRIquant`. - `*.bed`: `CIRI2` output file in BED 6 format. - `*.gtf`: Output file from `CIRIquant` in GTF format. Full description of the columns available in the `CIRIquant` [documentation](https://ciriquant-cookbook.readthedocs.io/en/latest/quantification.html#output-format). @@ -225,7 +221,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d - `*_denovo.sorted.{bam, bam.bai}`: (Sorted and indexed) bam file from `BWA` alignment of candidate circular reads to the pseudo reference. - `*_index.*.ht2`: `BWA` index files of the pseudo reference. - `*_index.fa`: Reference FASTA file of candidate circular reads. - - `circrna_discovery/CIRIquant/${sample_id}/`` - `${sample_id}.bed`: Filtered, annotated circRNAs in customised BED12 format. - `fasta/`: Mature spliced length circRNA FASTA sequences. @@ -268,13 +263,11 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d Output files - `circrna_discovery/find_circ/intermediates/${sample_id}/` - - `*_anchors.qfa.gz`: 20mer anchors extracted from unmapped reads. - `*_unmapped.bam`: Unmapped RNA-Seq reads to reference genome. - `*.sites.bed`: Output from `find_circ`, first six columns are in standard BED format. A description of the remaining columns is available in the `find_circ` [documentation](https://github.com/marvin-jens/find_circ#output-format). - `*.sites.log`: Summary statistics of candidate circular reads in the sample. - `*.sites.reads`: Tab delimited file containing circRNA ID & sequence. - - `circrna_discovery/find_circ/${sample_id}/` - `${sample_id}.bed`: Filtered, annotated circRNAs in customised BED12 format. - `fasta/`: Mature spliced length circRNA FASTA sequences. @@ -295,7 +288,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d Output files - `circrna_discovery/MapSplice/intermediates/${sample_id}/` - - `alignments.bam`: Bam file containing aligned reads and fusion alignments. - `deletions.txt`: Report of deletions. - `Fusion output files`: @@ -307,7 +299,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d - `insertions.txt`: Report of Insertions. - `junctions.txt`: Reported splice junctions. - `stats.txt`: Read alignment, Junction statistics. - - `circrna_discovery/MapSplice/${sample_id}/` - `${sample_id}.bed`: Filtered, annotated circRNAs in customised BED12 format. - `fasta/`: Mature spliced length circRNA FASTA sequences. @@ -330,9 +321,7 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). - - `circrna_discovery/STAR/2nd_Pass/${sample_id}/` - - `*.Aligned.sortedByCoord.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). - `*.Chimeric.out.sam`: Chimeric alignments in SAM format. @@ -340,7 +329,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). - - `circrna_discovery/STAR/SJFile/` - `*.SJFile.tab`: Chromosome, start, end & strand coordinates of novel splice junctions. @@ -463,42 +451,31 @@ _N.B:_ In the phenotype file the response variable must be called `condition`, t Output files - `differential_expression/circRNA/` - - `DESeq2_log2_transformed_counts.txt`: _log2(Normalised counts + 1)_ - - `DESeq2_normalized_counts.txt`: Normalised circRNA counts. - - `control_vs_lung/` - - `DESeq2_{control_vs_lung}_Adj_pvalue_distribution.pdf`: Histogram of Adj pvalues from `results(dds)` displaying the distribution of circRNAs that reject the null hypothesis (padj <= 0.05).

circRNA adj-p histogram

- - `DESeq2_{control_vs_lung}_down_regulated_differential_expression.txt`: DESeq2 `results()` output filtered to include down regulated circRNAs (fold change <= -1, pvalue <= 0.05) in `condition` with respect to `control`. - - `DESeq2_{control_vs_lung}_fold_change_distribution.pdf`: Histogram of fold-change values for differentially expressed circRNAs.

circRNA FC histogram

- - `DESeq2_{control_vs_lung}_heatmap.pdf`: Heatmap of all differentially expressed circRNAs.

circRNA heatmap

- - `DESeq2_{control_vs_lung}_MA_plot.pdf`: Plot of the relationship between intensity and difference between the contrast made by `DESeq2`.

circRNA heatmap

- - `DESeq2_{control_vs_lung}_pvalue_distribution.pdf`: Histogram of pvalues from `results(dds)` displaying the distribution of circRNAs that reject the null hypothesis (pvalue <= 0.05).

circRNA pval dist

- - `DESeq2_{condition_vs_lung}_up_regulated_differential_expression.txt`: DEseq2 `results()` ouput filtered to include up regulated circRNAs (fold change >= 1, pvalue <= 0.05) in `condition` with respect to `control`. - - `DESeq2_{condition_vs_lung}_volcano_plot.pdf`: Volcano plot of differentially expressed circRNAs from DESeq2 `results()` using [EnhancedVolcano](https://www.bioconductor.org/packages/release/bioc/vignettes/EnhancedVolcano/inst/doc/EnhancedVolcano.html).

circRNA volcano @@ -516,14 +493,11 @@ _Note:_ The test dataset produces sparsely populated plots due to aggressive sub

Output files - `differential_expression/boxplots/` - - `control_vs_lung` - - `*boxplot.pdf`: Boxplot of differentially expressed circRNAs in `control_vs_lung`.

circRNA boxplot

- - `control_vs_lung` - `*boxplot.pdf`: Boxplot of differentially expressed circRNAs in `control_vs_melanoma`.

@@ -542,42 +516,31 @@ _Note:_ The output files give examples for `control_vs_lung` and `control_vs_mel

Output files - `differential_expression/RNA-Seq/` - - `DESeq2_log2_transformed_counts.txt`: _log2(Normalised counts + 1)_ - - `DESeq2_normalized_counts.txt`: Normalised RNA-Seq counts. - - `control_vs_lung/` - - `DESeq2_{control_vs_lung}_Adj_pvalue_distribution.pdf`: Histogram of Adj pvalues from `results(dds)` displaying the distribution of genes that reject the null hypothesis (padj <= 0.05).

circRNA adj-p histogram

- - `DESeq2_{control_vs_lung}_down_regulated_differential_expression.txt`: DESeq2 `results()` output filtered to include down regulated genes (fold change <= -1, pvalue <= 0.05) in `condition` with respect to `control`. - - `DESeq2_{control_vs_lung}_fold_change_distribution.pdf`: Histogram of fold-change values for differentially expressed genes.

circRNA FC histogram

- - `DESeq2_{control_vs_lung}_heatmap.pdf`: Heatmap of all differentially expressed genes.

circRNA heatmap

- - `DESeq2_{control_vs_lung}_MA_plot.pdf`: Plot of the relationship between intensity and difference between the contrast made by `DESeq2`.

circRNA heatmap

- - `DESeq2_{control_vs_lung}_pvalue_distribution.pdf`: Histogram of pvalues from `results(dds)` displaying the distribution of genes that reject the null hypothesis (pvalue <= 0.05).

circRNA pval dist

- - `DESeq2_{condition_vs_lung}_up_regulated_differential_expression.txt`: DEseq2 `results()` ouput filtered to include up regulated genes (fold change >= 1, pvalue <= 0.05) in `condition` with respect to `control`. - - `DESeq2_{condition_vs_lung}_volcano_plot.pdf`: Volcano plot of differentially expressed genes from DESeq2 `results()` using [EnhancedVolcano](https://www.bioconductor.org/packages/release/bioc/vignettes/EnhancedVolcano/inst/doc/EnhancedVolcano.html).

circRNA volcano diff --git a/docs/usage.md b/docs/usage.md index 953fb337..f1f0ab39 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -2,29 +2,28 @@ It is recommended that first time users run `nf-core/circrna` with the minimal test dataset either locally or on a HPC, referring to the [output documentation](https://nf-co.re/circrna/dev/output) before running a full analysis. -```console +```bash nextflow run nf-core/circrna -profile test, ``` -## Running the pipeline +# Running the pipeline A typical command for running the pipeline is as follows: -```console +```bash nextflow run nf-core/circrna \ -profile \ --genome 'GRCh37' \ - --input 'samples.csv' \ - --input_type 'fastq' + --input 'samples.csv' ``` By default, `nf-core/circrna` runs the circRNA discovery analysis module using `CIRCexplorer2`. The above command will perform circRNA quantification using these tools on ENSEMBL GRCh37 reference annotation files as defined in the iGenomes config. -### Updating the pipeline +## Updating the pipeline To make sure that you're running the latest version of the pipeline, make sure that you regularly update the cached version of the pipeline: -```console +```bash nextflow pull nf-core/circrna ``` @@ -38,63 +37,28 @@ First, go to the [nf-core/circrna releases page](https://github.com/nf-core/circ This version number will be logged in reports when you run the pipeline, so that you'll know what you used when you look back in the future. For example, at the bottom of the MultiQC reports. -## Input specifications - -Input data can be passed to `nf-core/circrna` in two possible ways using the `--input` parameter. - -### `--input ""` - -The simplest way to pass input data to `nf-core/circrna` is by providing the path to the input data with a suitable wildcard glob pattern: - -#### fastq - -```console ---input "/data/*_r{1,2}.fastq.gz" -``` - -##### bam - -```console ---input "/data/*.bam" -``` +# Input specifications -> Beware that providing a path to input data will result in samples being named according to the common tuple key based on the glob pattern supplied. Take this into consideration when designing your phenotype file for differential expression analysis. +Input data can be passed to `nf-core/circrna` using a CSV file containing the absolute paths to input fastq files. -### `--input samples.csv` +The headers of the CSV file must be: `sample,fastq_1,fastq_2`. -Alternatively, the user may wish to provide a CSV file containing the absolute paths to input fastq/bam files. +Valid examples for fastq input data in a CSV file is given below: -The headers of the CSV file must be: `Sample_ID,Read1,Read2,Bam`. - -> This approach is recommended for most real life situations, where in-house sequencing facilities file naming convention requires the user to manually match file names to metadata. The below input files use `TCGA` identifiers as proof of concept. - -Valid examples for fastq/bam input data in a CSV file is given below: - -| Sample_ID | Read1 | Read2 | Bam | -| ---------------- | :---------------------------------------------------------------------- | ----------------------------------------------------------------------- | --- | -| TCGA-EJ-7783-11A | /data/f4c1b2b1-ba1f-4355-a1ac-3e952cf351a5_gdc_realn_rehead_R1.fastq.gz | /data/f4c1b2b1-ba1f-4355-a1ac-3e952cf351a5_gdc_realn_rehead_R2.fastq.gz | NA | -| TCGA-G9-6365-11A | /data/8a36555b-9e27-40ee-a8df-4b15d6580a02_gdc_realn_rehead_R1.fastq.gz | /data/8a36555b-9e27-40ee-a8df-4b15d6580a02_gdc_realn_rehead_R2.fastq.gz | NA | -| TCGA-EJ-7782-11A | /data/8b3d4a3d-2bfa-48f8-b31f-901f49a5bf6b_gdc_realn_rehead_R1.fastq.gz | /data/8b3d4a3d-2bfa-48f8-b31f-901f49a5bf6b_gdc_realn_rehead_R2.fastq.gz | NA | -| TCGA-CH-5772-01A | /data/b6546f66-3c13-4390-9643-d1fb3d660a2f_gdc_realn_rehead_R1.fastq.gz | /data/b6546f66-3c13-4390-9643-d1fb3d660a2f_gdc_realn_rehead_R2.fastq.gz | NA | -| TCGA-EJ-5518-01A | /data/afbbc370-5970-43d3-b9f8-f40f8e649bb6_gdc_realn_rehead_R1.fastq.gz | /data/afbbc370-5970-43d3-b9f8-f40f8e649bb6_gdc_realn_rehead_R2.fastq.gz | NA | -| TCGA-KK-A8I4-01A | /data/81254692-ee1e-4985-bd0a-4929eed4c620_gdc_realn_rehead_R1.fastq.gz | /data/81254692-ee1e-4985-bd0a-4929eed4c620_gdc_realn_rehead_R2.fastq.gz | NA | - ---- - -| Sample_ID | Read1 | Read2 | Bam | -| :--------------- | ----- | ----- | :-------------------------------------------------------------- | -| TCGA-EJ-7783-11A | NA | NA | /data/f4c1b2b1-ba1f-4355-a1ac-3e952cf351a5_gdc_realn_rehead.bam | -| TCGA-G9-6365-11A | NA | NA | /data/8a36555b-9e27-40ee-a8df-4b15d6580a02_gdc_realn_rehead.bam | -| TCGA-EJ-7782-11A | NA | NA | /data/8b3d4a3d-2bfa-48f8-b31f-901f49a5bf6b_gdc_realn_rehead.bam | -| TCGA-CH-5772-01A | NA | NA | /data/b6546f66-3c13-4390-9643-d1fb3d660a2f_gdc_realn_rehead.bam | -| TCGA-EJ-5518-01A | NA | NA | /data/afbbc370-5970-43d3-b9f8-f40f8e649bb6_gdc_realn_rehead.bam | -| TCGA-KK-A8I4-01A | NA | NA | /data/81254692-ee1e-4985-bd0a-4929eed4c620_gdc_realn_rehead.bam | +| sample | fastq_1 | fastq_2 | +| ---------------- | :---------------------------------------------------------------------- | ----------------------------------------------------------------------- | +| TCGA-EJ-7783-11A | /data/f4c1b2b1-ba1f-4355-a1ac-3e952cf351a5_gdc_realn_rehead_R1.fastq.gz | /data/f4c1b2b1-ba1f-4355-a1ac-3e952cf351a5_gdc_realn_rehead_R2.fastq.gz | +| TCGA-G9-6365-11A | /data/8a36555b-9e27-40ee-a8df-4b15d6580a02_gdc_realn_rehead_R1.fastq.gz | /data/8a36555b-9e27-40ee-a8df-4b15d6580a02_gdc_realn_rehead_R2.fastq.gz | +| TCGA-EJ-7782-11A | /data/8b3d4a3d-2bfa-48f8-b31f-901f49a5bf6b_gdc_realn_rehead_R1.fastq.gz | /data/8b3d4a3d-2bfa-48f8-b31f-901f49a5bf6b_gdc_realn_rehead_R2.fastq.gz | +| TCGA-CH-5772-01A | /data/b6546f66-3c13-4390-9643-d1fb3d660a2f_gdc_realn_rehead_R1.fastq.gz | /data/b6546f66-3c13-4390-9643-d1fb3d660a2f_gdc_realn_rehead_R2.fastq.gz | +| TCGA-EJ-5518-01A | /data/afbbc370-5970-43d3-b9f8-f40f8e649bb6_gdc_realn_rehead_R1.fastq.gz | /data/afbbc370-5970-43d3-b9f8-f40f8e649bb6_gdc_realn_rehead_R2.fastq.gz | +| TCGA-KK-A8I4-01A | /data/81254692-ee1e-4985-bd0a-4929eed4c620_gdc_realn_rehead_R1.fastq.gz | /data/81254692-ee1e-4985-bd0a-4929eed4c620_gdc_realn_rehead_R2.fastq.gz | > Do not leave any cell empty in the CSV file. -### `--phenotype` +## Phenotype file -When running the differential expression analysis module, an input `phenotype.csv` file is required to specify levels for `DESeq2`. At a minimum, the user must supply one column of levels for `DESeq2` which **must be called condition**. This should be the primary contrast of interest in your experiment (e.g case vs. control). If additional columns are supplied to the phenotype file, they will be controlled for in the linear mixed model. A brief proof of concept is given below in R notation: +When running the differential expression analysis module via the `--module differential_expression` parameter, an input `phenotype.csv` file is required to specify levels for `DESeq2`. At a minimum, the user must supply one column of levels for `DESeq2` which **must be called condition**. This should be the primary contrast of interest in your experiment (e.g case vs. control). If additional columns are supplied to the phenotype file, they will be controlled for in the linear mixed model. A brief proof of concept is given below in R notation: ```R colnames(phenotype) @@ -112,9 +76,9 @@ print(dds$design) [1] ' ~ location + replicates + condition' ``` -It is recommended to use an input CSV file in conjunction with your phenotype file as the `Sample_ID` column **must match** the first column of the `phenotype.csv` file. +It is recommended to construct your input CSV file in conjunction with your phenotype file as the first column denoting sample names **must match** the first column of the `phenotype.csv` file. -A valid example of a `phenotype.csv` file (matching the TCGA example input CSV file above) is given below: +A valid example of a `phenotype.csv` file (matching the TCGA example input CSV file above) is given: | Sample_ID | condition | | ---------------- | --------- | @@ -125,7 +89,7 @@ A valid example of a `phenotype.csv` file (matching the TCGA example input CSV f | TCGA-EJ-5518-01A | tumor | | TCGA-KK-A8I4-01A | tumor | -## Analysis modules +# Analysis modules `nf-core/circrna` provides 3 analysis modules to the user: @@ -133,18 +97,17 @@ A valid example of a `phenotype.csv` file (matching the TCGA example input CSV f 2. miRNA target prediction. 3. Differential circRNA expression analysis. -### circRNA discovery +## circRNA discovery The core module of `nf-core/circrna`, a user can utilise up to seven circRNA quantification tools to fully characterise the circRNA profile in samples. Currently, supported tools include `CIRCexplorer2`, `circRNA finder`, `CIRIquant`, `DCC`, `find circ` , `MapSplice` & `Segemehl` however, the authors of `nf-core/circrna` welcome contributions from authors of novel quantification tools to keep the workflow current. By default, `nf-core/circrna` runs the circRNA discovery analysis module. -```console +```bash nextflow run nf-core/circrna \ -profile \ --genome 'GRCh37' \ --input 'samples.csv' \ - --input_type 'fastq' \ --module 'circrna_discovery' ``` @@ -152,38 +115,36 @@ To view the outputs of the module, please see the output [documentation](https:/ > Please note that this module must be included for every run of the workflow -#### Tool selection +### Tool selection The user may use one, all or any combination of circRNA quantification tools listed above in the analysis. To select which tools to use for the analysis, specify the `--tool` parameter in the configuration profile or pass it via the command line when running the workflow: -```console +```bash nextflow run nf-core/circrna \ -profile \ --genome 'GRCh37' \ --input 'samples.csv' \ - --input_type 'fastq' \ --module 'circrna_discovery' \ --tool 'ciriquant,dcc,find_circ' ``` > When providing multiple tools, separate each entry with a comma. -#### circRNA filtering +### circRNA filtering `nf-core/circrna` offers robust filtering of each called circRNA to reduce the number of spurious calls within the dataset. -##### BSJ reads +#### BSJ reads The user can specify the minimum number of reads spanning the back-splice junction site required for a circRNA to be considered for further analysis. circRNAs with counts below this value will be filtered to remove from the results. To apply this filtering method, specify the `--bsj_reads` parameter in the configuration profile or pass it via the command line when running the workflow: -```console +```bash nextflow run nf-core/circrna \ -profile \ --genome 'GRCh37' \ --input 'samples.csv' \ - --input_type 'fastq' \ --phenotype 'phenotype.csv' \ --module 'circrna_discovery' \ --tool 'ciriquant, dcc, find_circ' \ @@ -192,7 +153,7 @@ nextflow run nf-core/circrna \ Disable the filter by setting the value to 0. -##### Multiple tool filtering +#### Multiple tool filtering When more than one tool has been provided using the `--tool` parameter, the user can specify the minimum number of tools circRNAs must be called by using `--tool_filter`. Setting this parameter to 0 or 1 will result in the union being output, i.e no filtering is applied. Setting this parameter to 2 will output circRNAs that have been called by at least 2 quantification tools and so on. @@ -200,12 +161,11 @@ When more than one tool has been provided using the `--tool` parameter, the user To apply this filtering method, specify the `--tool_filter` parameter in the configuration profile or pass it via the command line when running the workflow: -```console +```bash nextflow run nf-core/circrna \ -profile \ --genome 'GRCh37' \ --input 'samples.csv' \ - --input_type 'fastq' \ --module 'circrna_discovery' \ --tool 'ciriquant, dcc, find_circ' \ --bsj_reads 2 \ @@ -214,39 +174,37 @@ nextflow run nf-core/circrna \ > This filtering method is reflected in the circRNA count matrix. Per tool circRNA annotations are subject to back-splice read filtering only. -##### Handling duplicate circRNAs +#### Handling duplicate circRNAs In the event a circRNA has been called by more than one quantification tool, the user can specify which aggregate function to apply to the duplicated circRNA. The accepted values are 'mean' and 'max', which are passed to the workflow using the `--duplicates_fun` parameter. -### miRNA prediction +## miRNA prediction The second module of `nf-core/circrna`, `mirna_prediction` analyses the mature spliced sequences of circRNAs to test for the presence of miRNA response elements using both `miRanda` and `TargetScan`. Results from both tools are consolidated and filtering methods are applied to produce robust miRNA target predictions of circRNAs in the dataset. To invoke the module, specify the `--module` parameter via the configuration profile or pass it via the command line when running the workflow: -```console +```bash nextflow run nf-core/circrna \ -profile \ --genome 'GRCh37' \ --input 'samples.csv' \ - --input_type 'fastq' \ --module 'circrna_discovery, mirna_prediction' ``` To view the outputs of the module, please see the output [documentation](https://nf-co.re/circrna/dev/output#mirna-prediction). -### Differential circRNA analysis +## Differential circRNA analysis The third and final module of `nf-core/circrna` performs differential expression analysis of circRNAs, returning `DESeq2` result outputs, plots and diagnostic plots for the user. In order to run this module, it is essential that your `phenotype.csv` file is in the correct format - please refer to the input [specifications](https://nf-co.re/circrna/dev/usage#differential-expression-analysis). To invoke the module, specify the `--module` parameter via the configuration profile or pass it via the command line when running the workflow: -```console +```bash nextflow run nf-core/circrna \ -profile \ --genome 'GRCh37' \ --input 'samples.csv' \ - --input_type 'fastq' \ --phenotype 'phenotype.csv' \ --module 'circrna_discovery, differential_expression' ``` diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/full_annotation/main.nf index c47bd561..4d751d66 100644 --- a/modules/local/annotation/full_annotation/main.nf +++ b/modules/local/annotation/full_annotation/main.nf @@ -25,7 +25,7 @@ process ANNOTATION { prefix = task.ext.prefix ?: "${meta.id}" def VERSION = '377' """ - grep -vf ${workflow.projectDir}/bin/unwanted_biotypes.txt $gtf > filt.gtf + grep -vf unwanted_biotypes.txt $gtf > filt.gtf mv $bed circs.bed annotate_outputs.sh $exon_boundary &> ${prefix}.log @@ -38,6 +38,7 @@ process ANNOTATION { cat <<-END_VERSIONS > versions.yml "${task.process}": + awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) bedtools: \$(bedtools --version | sed -e "s/bedtools v//g") ucsc: $VERSION END_VERSIONS diff --git a/modules/local/annotation/parent_gene/main.nf b/modules/local/annotation/parent_gene/main.nf index c412ab8d..023bed74 100644 --- a/modules/local/annotation/parent_gene/main.nf +++ b/modules/local/annotation/parent_gene/main.nf @@ -26,7 +26,17 @@ process PARENT_GENE { # generate circrna BED file. tail -n +2 $circrna_matrix | awk '{print \$1}' > IDs.txt - ID_to_BED.sh IDs.txt + + # ID_to_BED + while IFS='' read -r line; do + name=\$(echo \$line) + chr=\$(echo \$line | cut -d: -f1) + start=\$(echo \$line | cut -d- -f1 | cut -d: -f2) + stop=\$(echo \$line | cut -d- -f2 | cut -d: -f1) + sign=\$(echo \$line | cut -d: -f3) + echo -e "\$chr\t\$start\t\$stop\t\$name\t0\t\$sign" >> \${name}.bed + done < IDs.txt + cat *.bed > merged.txt && rm IDs.txt && rm *.bed && mv merged.txt circs.bed # Re-use annotation script to identify the host gene. diff --git a/modules/local/circexplorer2/filter/main.nf b/modules/local/circexplorer2/filter/main.nf index 3594ac95..fece7a46 100644 --- a/modules/local/circexplorer2/filter/main.nf +++ b/modules/local/circexplorer2/filter/main.nf @@ -2,6 +2,11 @@ process CIRCEXPLORER2_FILTER { tag "$meta.id" label 'process_single' + conda "bioconda::gawk=5.1.0" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/gawk%3A5.1.0' : + 'quay.io/biocontainers/gawk:5.1.0' }" + input: tuple val(meta), path(txt) val(bsj_reads) @@ -9,6 +14,7 @@ process CIRCEXPLORER2_FILTER { output: tuple val(meta), path("${prefix}_${meta.tool}_circs.bed"), emit: results tuple val(meta), path("${prefix}_${meta.tool}.bed") , emit: matrix + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -20,5 +26,10 @@ process CIRCEXPLORER2_FILTER { awk '{if(\$13 >= ${bsj_reads}) print \$0}' ${prefix}.txt | awk -v OFS="\t" '{print \$1,\$2,\$3,\$6,\$13}' > ${prefix}_${meta.tool}.bed awk -v OFS="\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_${meta.tool}.bed > ${prefix}_${meta.tool}_circs.bed + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) + END_VERSIONS """ } diff --git a/modules/local/circexplorer2/reference/main.nf b/modules/local/circexplorer2/reference/main.nf index ed2b3537..6bb46f78 100644 --- a/modules/local/circexplorer2/reference/main.nf +++ b/modules/local/circexplorer2/reference/main.nf @@ -31,6 +31,7 @@ process CIRCEXPLORER2_REFERENCE { cat <<-END_VERSIONS > versions.yml "${task.process}": + awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) ucsc: $VERSION END_VERSIONS """ diff --git a/modules/local/circrna_finder/filter/main.nf b/modules/local/circrna_finder/filter/main.nf index 06d7cf5c..e5198cfb 100644 --- a/modules/local/circrna_finder/filter/main.nf +++ b/modules/local/circrna_finder/filter/main.nf @@ -34,6 +34,8 @@ process CIRCRNA_FINDER_FILTER { cat <<-END_VERSIONS > versions.yml "${task.process}": + awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) + cat: \$(cat --version | head -n 1 | sed -e 's/cat (GNU coreutils) //') circRNA_finder: $VERSION END_VERSIONS """ diff --git a/modules/local/circtest/prepare/main.nf b/modules/local/circtest/prepare/main.nf index 47d74346..2fecd7b0 100644 --- a/modules/local/circtest/prepare/main.nf +++ b/modules/local/circtest/prepare/main.nf @@ -1,7 +1,7 @@ process PREPARE_CLR_TEST { label 'process_medium' - conda "r-base r-aod r-ggplot2 r-plyr" + conda "conda-forge::r-base=4.2.2 conda-forge::r-aod=1.3.2 conda-forge::r-ggplot2=3.4.0 conda-forge::r-plyr=1.8.8" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' : 'quay.io/biocontainers/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' }" diff --git a/modules/local/circtest/test/main.nf b/modules/local/circtest/test/main.nf index 43b23083..1d1e4df3 100644 --- a/modules/local/circtest/test/main.nf +++ b/modules/local/circtest/test/main.nf @@ -1,7 +1,7 @@ process CIRCTEST { label 'process_medium' - conda "r-base r-aod r-ggplot2 r-plyr" + conda "conda-forge::r-base=4.2.2 conda-forge::r-aod=1.3.2 conda-forge::r-ggplot2=3.4.0 conda-forge::r-plyr=1.8.8" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' : 'quay.io/biocontainers/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' }" diff --git a/modules/local/ciriquant/filter/main.nf b/modules/local/ciriquant/filter/main.nf index a1341a94..253d6d2b 100644 --- a/modules/local/ciriquant/filter/main.nf +++ b/modules/local/ciriquant/filter/main.nf @@ -2,6 +2,11 @@ process CIRIQUANT_FILTER { tag "$meta.id" label 'process_single' + conda "bioconda::gawk=5.1.0" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/gawk%3A5.1.0' : + 'quay.io/biocontainers/gawk:5.1.0' }" + input: tuple val(meta), path(gtf) val bsj_reads @@ -9,6 +14,7 @@ process CIRIQUANT_FILTER { output: tuple val(meta), path("${prefix}_ciriquant_circs.bed"), emit: results tuple val(meta), path("${prefix}_ciriquant.bed") , emit: matrix + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -27,5 +33,10 @@ process CIRIQUANT_FILTER { rm ${prefix}.gtf awk -v OFS="\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_ciriquant.bed > ${prefix}_ciriquant_circs.bed + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) + END_VERSIONS """ } diff --git a/modules/local/count_matrix/combined/main.nf b/modules/local/count_matrix/combined/main.nf index 65f430b5..e277ffff 100644 --- a/modules/local/count_matrix/combined/main.nf +++ b/modules/local/count_matrix/combined/main.nf @@ -1,7 +1,7 @@ process COUNTS_COMBINED { label 'process_low' - conda "r-base=3.6.3 python=2.7.15 r-argparser=0.6 r-dplyr=1.0.5" + conda "conda-forge::r-base=3.6.3 conda-forge::python=2.7.15 conda-forge::r-argparser=0.6 conda-forge::r-dplyr=1.0.5" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' : 'quay.io/biocontainers/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' }" @@ -12,6 +12,7 @@ process COUNTS_COMBINED { output: path("circRNA_matrix.txt"), emit: dea_matrix path("count_matrix.txt") , emit: clr_matrix + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -28,9 +29,11 @@ process COUNTS_COMBINED { cat <<-END_VERSIONS > versions.yml "${task.process}": + awk: \$(awk --version | head -n 1 | cut -d' ' -f3 | sed 's/,//g') r-base: \$(echo \$(R --version 2>&1) | sed 's/^.*R version //; s/ .*\$//') argparser: \$(Rscript -e "library(arparser); cat(as.character(packageVersion('argparser')))") dplyr: \$(Rscript -e "library(dplyr); cat(as.character(packageVersion('dplyr')))") + python: \$(python --version | sed -e 's/Python //g') END_VERSIONS """ } diff --git a/modules/local/count_matrix/merge_tools/main.nf b/modules/local/count_matrix/merge_tools/main.nf index fd3feb89..e2ee4b11 100644 --- a/modules/local/count_matrix/merge_tools/main.nf +++ b/modules/local/count_matrix/merge_tools/main.nf @@ -2,7 +2,7 @@ process MERGE_TOOLS { tag "$meta.id" label 'process_low' - conda "r-base=3.6.3 python=2.7.15 r-argparser=0.6 r-dplyr=1.0.5" + conda "conda-forge::r-base=3.6.3 conda-forge::python=2.7.15 conda-forge::r-argparser=0.6 conda-forge::r-dplyr=1.0.5" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' : 'quay.io/biocontainers/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' }" @@ -14,6 +14,7 @@ process MERGE_TOOLS { output: tuple val(meta), path("${prefix}.bed"), emit: merged + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -38,6 +39,7 @@ process MERGE_TOOLS { r-base: \$(echo \$(R --version 2>&1) | sed 's/^.*R version //; s/ .*\$//') argparser: \$(Rscript -e "library(arparser); cat(as.character(packageVersion('argparser')))") dplyr: \$(Rscript -e "library(dplyr); cat(as.character(packageVersion('dplyr')))") + python: \$(python --version | sed -e 's/Python //g') END_VERSIONS """ } diff --git a/modules/local/count_matrix/single/main.nf b/modules/local/count_matrix/single/main.nf index 8ce82da8..59f628c8 100644 --- a/modules/local/count_matrix/single/main.nf +++ b/modules/local/count_matrix/single/main.nf @@ -2,7 +2,7 @@ process COUNTS_SINGLE { tag "${meta.tool}" label 'process_low' - conda "r-base=3.6.3 python=2.7.15 r-argparser=0.6 r-dplyr=1.0.5" + conda "conda-forge::r-base=3.6.3 conda-forge::python=2.7.15 conda-forge::r-argparser=0.6 conda-forge::r-dplyr=1.0.5" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' : 'quay.io/biocontainers/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' }" @@ -13,6 +13,7 @@ process COUNTS_SINGLE { output: path("circRNA_matrix.txt"), emit: dea_matrix path("count_matrix.txt") , emit: clr_matrix + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -37,9 +38,11 @@ process COUNTS_SINGLE { cat <<-END_VERSIONS > versions.yml "${task.process}": + awk: \$(awk --version | head -n 1 | cut -d' ' -f3 | sed 's/,//g') r-base: \$(echo \$(R --version 2>&1) | sed 's/^.*R version //; s/ .*\$//') argparser: \$(Rscript -e "library(arparser); cat(as.character(packageVersion('argparser')))") dplyr: \$(Rscript -e "library(dplyr); cat(as.character(packageVersion('dplyr')))") + python: \$(python --version | sed -e 's/Python //g') END_VERSIONS """ } diff --git a/modules/local/dcc/filter/main.nf b/modules/local/dcc/filter/main.nf index b9bcca46..1fcd3ef7 100644 --- a/modules/local/dcc/filter/main.nf +++ b/modules/local/dcc/filter/main.nf @@ -2,6 +2,11 @@ process DCC_FILTER { tag "$meta.id" label 'process_single' + conda "bioconda::gawk=5.1.0" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/gawk%3A5.1.0' : + 'quay.io/biocontainers/gawk:5.1.0' }" + input: tuple val(meta), path(txt) val bsj_reads @@ -9,6 +14,7 @@ process DCC_FILTER { output: tuple val(meta), path("${prefix}_dcc_circs.bed"), emit: results tuple val(meta), path("${prefix}_dcc.bed") , emit: matrix + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -19,5 +25,10 @@ process DCC_FILTER { awk '{if(\$5 >= ${bsj_reads}) print \$0}' ${prefix}.txt > ${prefix}_dcc.filtered awk -v OFS="\t" '{\$2-=1;print}' ${prefix}_dcc.filtered > ${prefix}_dcc.bed awk -v OFS="\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_dcc.bed > ${prefix}_dcc_circs.bed + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) + END_VERSIONS """ } diff --git a/modules/local/fasta/main.nf b/modules/local/fasta/main.nf index c2cd5ada..f43543d8 100644 --- a/modules/local/fasta/main.nf +++ b/modules/local/fasta/main.nf @@ -38,6 +38,7 @@ process FASTA { cat <<-END_VERSIONS > versions.yml "${task.process}": bedtools: \$(bedtools --version | sed -e "s/bedtools v//g") + cut: \$(cut --version | head -n 1 | cut -d' ' -f4) END_VERSIONS """ } diff --git a/modules/local/mapsplice/align/main.nf b/modules/local/mapsplice/align/main.nf index 44c64d97..b62e4db2 100644 --- a/modules/local/mapsplice/align/main.nf +++ b/modules/local/mapsplice/align/main.nf @@ -26,8 +26,8 @@ process MAPSPLICE_ALIGN { def VERSION = 'v2.2.1' def gtf_prefix = gtf.toString() - ~/.gtf/ if(meta.single_end){ - def handleGzip_R1 = reads[0].toString().endsWith('.gz') ? "gzip -d -f ${reads[0]}" : '' - def read1 = reads[0].toString().endsWith('.gz') ? reads[0].toString() - ~/.gz/ : reads[0] + def handleGzip_R1 = reads[0].getExtension() == 'gz' ? "gzip -d -f ${reads[0]}" : '' + def read1 = reads[0].getExtension() == 'gz' ? reads[0].toString() - ~/.gz/ : reads[0] """ $handleGzip_R1 @@ -47,10 +47,10 @@ process MAPSPLICE_ALIGN { END_VERSIONS """ }else{ - def handleGzip_R1 = reads[0].toString().endsWith('.gz') ? "gzip -d -f ${reads[0]}" : '' - def handleGzip_R2 = reads[1].toString().endsWith('.gz') ? "gzip -d -f ${reads[1]}" : '' - def read1 = reads[0].toString().endsWith('.gz') ? reads[0].toString() - ~/.gz/ : reads[0] - def read2 = reads[1].toString().endsWith('.gz') ? reads[1].toString() - ~/.gz/ : reads[1] + def handleGzip_R1 = reads[0].getExtension() == 'gz' ? "gzip -d -f ${reads[0]}" : '' + def handleGzip_R2 = reads[1].getExtension() == 'gz' ? "gzip -d -f ${reads[1]}" : '' + def read1 = reads[0].getExtension() == 'gz' ? reads[0].toString() - ~/.gz/ : reads[0] + def read2 = reads[1].getExtension() == 'gz' ? reads[1].toString() - ~/.gz/ : reads[1] """ $handleGzip_R1 $handleGzip_R2 diff --git a/modules/local/mirna_targets/main.nf b/modules/local/mirna_targets/main.nf index c6beaeff..4f70ca03 100644 --- a/modules/local/mirna_targets/main.nf +++ b/modules/local/mirna_targets/main.nf @@ -37,6 +37,7 @@ process MIRNA_TARGETS { cat <<-END_VERSIONS > versions.yml "${task.process}": + awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) bedtools: \$(bedtools --version | sed -e "s/bedtools v//g") END_VERSIONS """ diff --git a/modules/local/segemehl/filter/main.nf b/modules/local/segemehl/filter/main.nf index 8ea15603..5ca86cca 100644 --- a/modules/local/segemehl/filter/main.nf +++ b/modules/local/segemehl/filter/main.nf @@ -1,7 +1,12 @@ -process SEGEMEHL_FILTER{ +process SEGEMEHL_FILTER { tag "$meta.id" label 'process_single' + conda "bioconda::gawk=5.1.0" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/gawk%3A5.1.0' : + 'quay.io/biocontainers/gawk:5.1.0' }" + input: tuple val(meta), path(results) val(bsj_reads) @@ -9,6 +14,7 @@ process SEGEMEHL_FILTER{ output: tuple val(meta), path("${prefix}_segemehl_circs.bed"), emit: results tuple val(meta), path("${prefix}_segemehl.bed") , emit: matrix + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -22,5 +28,11 @@ process SEGEMEHL_FILTER{ awk -v OFS="\t" -v BSJ=${bsj_reads} '{if(\$5>=BSJ) print \$0}' ${prefix}_collapsed.bed > ${prefix}_segemehl.bed awk -v OFS="\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_segemehl.bed > ${prefix}_segemehl_circs.bed + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) + sort: \$(sort --version | sed -e 's/sort (GNU coreutils) //g') + END_VERSIONS """ } diff --git a/modules/local/star/sjdb/main.nf b/modules/local/star/sjdb/main.nf index 602d0da9..60b81849 100644 --- a/modules/local/star/sjdb/main.nf +++ b/modules/local/star/sjdb/main.nf @@ -1,12 +1,18 @@ process SJDB { label 'process_single' + conda "bioconda::gawk=5.1.0" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/gawk%3A5.1.0' : + 'quay.io/biocontainers/gawk:5.1.0' }" + input: path(sjdb) val(bsj_reads) output: path("dataset.SJ.out.tab"), emit: sjtab + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -14,5 +20,10 @@ process SJDB { script: """ cat *.tab | awk -v BSJ=${bsj_reads} '(\$7 >= BSJ && \$6==0)' | cut -f1-6 | sort | uniq > dataset.SJ.out.tab + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) + END_VERSIONS """ } diff --git a/modules/local/stringtie/prepde/main.nf b/modules/local/stringtie/prepde/main.nf index da20b1a8..c5700673 100644 --- a/modules/local/stringtie/prepde/main.nf +++ b/modules/local/stringtie/prepde/main.nf @@ -12,6 +12,7 @@ process STRINGTIE_PREPDE { output: path "transcript_count_matrix.csv" , emit: transcript_matrix path "gene_count_matrix.csv" , emit: gene_matrix + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -21,5 +22,10 @@ process STRINGTIE_PREPDE { for file in \$(ls *.gtf); do sample_id=\${file%".transcripts.gtf"}; touch samples.txt; printf "\$sample_id\t\$file\n" >> samples.txt ; done prepDE.py -i samples.txt + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + python: \$(python --version | sed -e "s/Python //g") + END_VERSIONS """ } diff --git a/modules/local/targetscan/database/main.nf b/modules/local/targetscan/database/main.nf index 0581aa4c..75657365 100644 --- a/modules/local/targetscan/database/main.nf +++ b/modules/local/targetscan/database/main.nf @@ -13,6 +13,6 @@ process TARGETSCAN_DATABASE { script: """ - bash ${workflow.projectDir}/bin/targetscan_format.sh $mature + targetscan_format.sh $mature """ } diff --git a/modules/local/targetscan/predict/main.nf b/modules/local/targetscan/predict/main.nf index f6b37cb0..62599ab8 100644 --- a/modules/local/targetscan/predict/main.nf +++ b/modules/local/targetscan/predict/main.nf @@ -31,6 +31,7 @@ process TARGETSCAN { cat <<-END_VERSIONS > versions.yml "${task.process}": + awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) targetscan: $VERSION END_VERSIONS """ diff --git a/nextflow.config b/nextflow.config index e0d5c68a..14f1455c 100644 --- a/nextflow.config +++ b/nextflow.config @@ -22,7 +22,7 @@ params { tool_filter = 0 duplicates_fun = 'mean' exon_boundary = 200 - save_intermediates = true + save_intermediates = false // reference genome options genome = null diff --git a/nextflow_schema.json b/nextflow_schema.json index 659d8f0d..5eda7888 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -88,7 +88,7 @@ "save_intermediates": { "type": "boolean", "description": "Save intermediate alignment/circRNA files.", - "default": true, + "default": false, "fa_icon": "fas fa-save" }, "exon_boundary": { @@ -443,11 +443,10 @@ }, "email": { "type": "string", - "description": "Phenotype CSV file specifying the experimental design for DESeq2.", - "fa_icon": "fas fa-journal-whills", - "mimetype": "text/csv", - "help_text": "The response variable containing the phenotype of primary interest in the experiment must have the column name condition. An example phenotype file is given below:\n\n| Sample_ID | condition | replicates |\n|---------|-----------|------------|\n| control_rep1 | control | 1 |\n| control_rep2 | control | 2 |\n| control_rep3 | control | 3 |\n| lung_rep1 | lung | 1 |\n| lung_rep2 | lung | 2 |\n| lung_rep3 | lung | 3 |\n| melanoma_rep1 | melanoma | 1 |\n| melanoma_rep2 | melanoma | 2 |\n| melanoma_rep3 | melanoma | 3 |\n\nThis will produce the DESeq2 design formula '~ replicates + condition' i.e all columns not named condition will be controlled for in the linear mixed model.", - "pattern": "\\.csv$" + "description": "Email address for completion summary.", + "fa_icon": "fas fa-envelope", + "help_text": "Set this parameter to your e-mail address to get a summary e-mail with details of the run sent to you when the workflow exits. If set in your user config file (`~/.nextflow/config`) then you don't need to specify this on the command line for every run.", + "pattern": "^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$" }, "email_on_fail": { "type": "string", diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index e6f6571a..7a85eaa0 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -69,6 +69,7 @@ workflow CIRCRNA_DISCOVERY { SEGEMEHL_FILTER( segemehl_filter, bsj_reads ) ch_versions = ch_versions.mix(SEGEMEHL_ALIGN.out.versions) + ch_versions = ch_versions.mix(SEGEMEHL_FILTER.out.versions) // // STAR WORFKLOW: @@ -80,6 +81,7 @@ workflow CIRCRNA_DISCOVERY { STAR_2ND_PASS( reads, star_index, STAR_SJDB.out.sjtab, true, '', '' ) ch_versions = ch_versions.mix(STAR_1ST_PASS.out.versions) + ch_versions = ch_versions.mix(STAR_2ND_PASS.out.versions) // // CIRCEXPLORER2 WORKFLOW: @@ -94,6 +96,7 @@ workflow CIRCRNA_DISCOVERY { ch_versions = ch_versions.mix(CIRCEXPLORER2_REFERENCE.out.versions) ch_versions = ch_versions.mix(CIRCEXPLORER2_PARSE.out.versions) ch_versions = ch_versions.mix(CIRCEXPLORER2_ANNOTATE.out.versions) + ch_versions = ch_versions.mix(CIRCEXPLORER2_FILTER.out.versions) // // CIRCRNA_FINDER WORKFLOW: @@ -121,6 +124,7 @@ workflow CIRCRNA_DISCOVERY { ch_versions = ch_versions.mix(SAMTOOLS_INDEX.out.versions) ch_versions = ch_versions.mix(SAMTOOLS_VIEW.out.versions) ch_versions = ch_versions.mix(FIND_CIRC_ANCHORS.out.versions) + ch_versions = ch_versions.mix(FIND_CIRC.out.versions) ch_versions = ch_versions.mix(FIND_CIRC_FILTER.out.versions) // @@ -132,6 +136,7 @@ workflow CIRCRNA_DISCOVERY { CIRIQUANT_FILTER( CIRIQUANT.out.gtf.map{ meta, gtf -> meta.tool = "ciriquant"; return [ meta, gtf ] }, bsj_reads ) ch_versions = ch_versions.mix(CIRIQUANT.out.versions) + ch_versions = ch_versions.mix(CIRIQUANT_FILTER.out.versions) // // DCC WORKFLOW @@ -157,7 +162,13 @@ workflow CIRCRNA_DISCOVERY { DCC_FILTER( DCC.out.txt.map{ meta, txt -> meta.tool = "dcc"; return [ meta, txt ] }, bsj_reads ) ch_versions = ch_versions.mix(DCC_MATE1_1ST_PASS.out.versions) + ch_versions = ch_versions.mix(DCC_MATE1_SJDB.out.versions) + ch_versions = ch_versions.mix(DCC_MATE1_2ND_PASS.out.versions) + ch_versions = ch_versions.mix(DCC_MATE2_1ST_PASS.out.versions) + ch_versions = ch_versions.mix(DCC_MATE2_SJDB.out.versions) + ch_versions = ch_versions.mix(DCC_MATE2_2ND_PASS.out.versions) ch_versions = ch_versions.mix(DCC.out.versions) + ch_versions = ch_versions.mix(DCC_FILTER.out.versions) // // MAPSPLICE WORKFLOW: @@ -179,7 +190,12 @@ workflow CIRCRNA_DISCOVERY { // ANNOTATION WORKFLOW: // - circrna_filtered = CIRCEXPLORER2_FILTER.out.results.mix(SEGEMEHL_FILTER.out.results, CIRCRNA_FINDER_FILTER.out.results, FIND_CIRC_FILTER.out.results, CIRIQUANT_FILTER.out.results, DCC_FILTER.out.results, MAPSPLICE_FILTER.out.results ) + circrna_filtered = CIRCEXPLORER2_FILTER.out.results.mix(SEGEMEHL_FILTER.out.results, + CIRCRNA_FINDER_FILTER.out.results, + FIND_CIRC_FILTER.out.results, + CIRIQUANT_FILTER.out.results, + DCC_FILTER.out.results, + MAPSPLICE_FILTER.out.results) ANNOTATION( circrna_filtered, gtf, exon_boundary ) ch_versions = ch_versions.mix(ANNOTATION.out.versions) @@ -196,7 +212,13 @@ workflow CIRCRNA_DISCOVERY { // COUNT MATRIX WORKFLOW: // - ch_matrix = CIRCEXPLORER2_FILTER.out.matrix.mix(SEGEMEHL_FILTER.out.matrix, CIRCRNA_FINDER_FILTER.out.matrix, FIND_CIRC_FILTER.out.matrix, CIRIQUANT_FILTER.out.matrix, DCC_FILTER.out.matrix, MAPSPLICE_FILTER.out.matrix ) + ch_matrix = CIRCEXPLORER2_FILTER.out.matrix.mix(SEGEMEHL_FILTER.out.matrix, + CIRCRNA_FINDER_FILTER.out.matrix, + FIND_CIRC_FILTER.out.matrix, + CIRIQUANT_FILTER.out.matrix, + DCC_FILTER.out.matrix, + MAPSPLICE_FILTER.out.matrix) + tools_selected = params.tool.split(',').collect{it.trim().toLowerCase()} if( tools_selected.size() > 1){ @@ -207,14 +229,16 @@ workflow CIRCRNA_DISCOVERY { dea_matrix = COUNTS_COMBINED.out.dea_matrix clr_matrix = COUNTS_COMBINED.out.clr_matrix + ch_versions = ch_versions.mix(MERGE_TOOLS.out.versions) + ch_versions = ch_versions.mix(COUNTS_COMBINED.out.versions) }else{ - // TODO: concerned that this does not wait for all files? COUNTS_SINGLE( ch_matrix.map{ meta, bed -> var = [:]; var.tool = meta.tool; return [ var, bed ] }.groupTuple() ) dea_matrix = COUNTS_SINGLE.out.dea_matrix clr_matrix = COUNTS_SINGLE.out.clr_matrix + ch_versions = ch_versions.mix(COUNTS_SINGLE.out.versions) } diff --git a/subworkflows/local/differential_expression.nf b/subworkflows/local/differential_expression.nf index ef9c4c59..d6b22ab2 100644 --- a/subworkflows/local/differential_expression.nf +++ b/subworkflows/local/differential_expression.nf @@ -51,6 +51,7 @@ workflow DIFFERENTIAL_EXPRESSION { ch_versions = ch_versions.mix(HISAT2_ALIGN.out.versions) ch_versions = ch_versions.mix(SAMTOOLS_SORT.out.versions) ch_versions = ch_versions.mix(STRINGTIE_STRINGTIE.out.versions) + ch_versions = ch_versions.mix(STRINGTIE_PREPDE.out.versions) ch_versions = ch_versions.mix(DESEQ2_DIFFERENTIAL_EXPRESSION.out.versions) ch_versions = ch_versions.mix(PARENT_GENE.out.versions) ch_versions = ch_versions.mix(PREPARE_CLR_TEST.out.versions) diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 516b3fae..b49a4e83 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -31,43 +31,25 @@ workflow PREPARE_GENOME { stage_chromosomes = Channel.value("${workflow.launchDir}/${params.outdir}/genome/chromosomes") } - // some index procs use tuple, some dont -_- ch_fasta.map{ it -> meta = [:] meta.id = it.simpleName return [ meta, [it] ] }.set{ fasta_tuple } - BOWTIE_BUILD( - fasta - ) + BOWTIE_BUILD(fasta) - BOWTIE2_BUILD( - fasta_tuple - ) + BOWTIE2_BUILD(fasta_tuple) - BWA_INDEX ( - fasta_tuple - ) + BWA_INDEX (fasta_tuple) - HISAT2_EXTRACTSPLICESITES( - gtf - ) + HISAT2_EXTRACTSPLICESITES(gtf) - HISAT2_BUILD( - fasta, - gtf, - HISAT2_EXTRACTSPLICESITES.out.txt - ) + HISAT2_BUILD(fasta, gtf, HISAT2_EXTRACTSPLICESITES.out.txt) - STAR_GENOMEGENERATE( - fasta, - gtf - ) + STAR_GENOMEGENERATE(fasta, gtf) - SEGEMEHL_INDEX( - fasta - ) + SEGEMEHL_INDEX(fasta) // Collect versions ch_versions = ch_versions.mix(BOWTIE_BUILD.out.versions) diff --git a/workflows/circrna.nf b/workflows/circrna.nf index d43b430e..34ff6947 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -49,8 +49,6 @@ ch_multiqc_custom_methods_description = params.multiqc_methods_description ? fil ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -// MODULES: - // SUBWORKFLOWS: include { INPUT_CHECK } from '../subworkflows/local/input_check' include { PREPARE_GENOME } from '../subworkflows/local/prepare_genome' @@ -100,9 +98,7 @@ workflow CIRCRNA { meta, fastq -> meta.id = meta.id.split('_')[0..-2].join('_') [ meta, fastq ] } - .dump(tag: 'map') .groupTuple(by: [0]) - .dump(tag: 'group') .branch { meta, fastq -> single : fastq.size() == 1 From 575f732b5c6186dccd0213415ba24b17a3d40e61 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Tue, 31 Jan 2023 13:23:22 +0000 Subject: [PATCH 010/491] stage bin/biotypes file --- modules/local/annotation/full_annotation/main.nf | 4 +++- modules/local/annotation/parent_gene/main.nf | 3 ++- subworkflows/local/circrna_discovery.nf | 4 +++- subworkflows/local/differential_expression.nf | 4 +++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/full_annotation/main.nf index 4d751d66..a8954311 100644 --- a/modules/local/annotation/full_annotation/main.nf +++ b/modules/local/annotation/full_annotation/main.nf @@ -10,8 +10,10 @@ process ANNOTATION { input: tuple val(meta), path(bed) path gtf + path biotypes val exon_boundary + output: tuple val(meta), path("${prefix}.bed"), emit: bed path("*.log") , emit: log @@ -25,7 +27,7 @@ process ANNOTATION { prefix = task.ext.prefix ?: "${meta.id}" def VERSION = '377' """ - grep -vf unwanted_biotypes.txt $gtf > filt.gtf + grep -vf $biotypes $gtf > filt.gtf mv $bed circs.bed annotate_outputs.sh $exon_boundary &> ${prefix}.log diff --git a/modules/local/annotation/parent_gene/main.nf b/modules/local/annotation/parent_gene/main.nf index 023bed74..ed035527 100644 --- a/modules/local/annotation/parent_gene/main.nf +++ b/modules/local/annotation/parent_gene/main.nf @@ -9,6 +9,7 @@ process PARENT_GENE { input: path circrna_matrix path gtf + path biotypes val exon_boundary output: @@ -22,7 +23,7 @@ process PARENT_GENE { def VERSION = '377' """ # remove redundant biotypes from GTF. - grep -vf ${workflow.projectDir}/bin/unwanted_biotypes.txt $gtf > filt.gtf + grep -vf $biotypes $gtf > filt.gtf # generate circrna BED file. tail -n +2 $circrna_matrix | awk '{print \$1}' > IDs.txt diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 7a85eaa0..89d4df68 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -190,13 +190,15 @@ workflow CIRCRNA_DISCOVERY { // ANNOTATION WORKFLOW: // + ch_biotypes = Channel.fromPath("${projectDir}/bin/unwanted_biotypes.txt") + circrna_filtered = CIRCEXPLORER2_FILTER.out.results.mix(SEGEMEHL_FILTER.out.results, CIRCRNA_FINDER_FILTER.out.results, FIND_CIRC_FILTER.out.results, CIRIQUANT_FILTER.out.results, DCC_FILTER.out.results, MAPSPLICE_FILTER.out.results) - ANNOTATION( circrna_filtered, gtf, exon_boundary ) + ANNOTATION( circrna_filtered, gtf, ch_biotypes, exon_boundary ) ch_versions = ch_versions.mix(ANNOTATION.out.versions) diff --git a/subworkflows/local/differential_expression.nf b/subworkflows/local/differential_expression.nf index d6b22ab2..1d442a80 100644 --- a/subworkflows/local/differential_expression.nf +++ b/subworkflows/local/differential_expression.nf @@ -44,7 +44,9 @@ workflow DIFFERENTIAL_EXPRESSION { // CircRNA - Host Gene Ratio tests // - PARENT_GENE( clr_matrix, gtf, exon_boundary ) + ch_biotypes = Channel.fromPath("${projectDir}/bin/unwanted_biotypes.txt") + + PARENT_GENE( clr_matrix, gtf, ch_biotypes, exon_boundary ) PREPARE_CLR_TEST( STRINGTIE_PREPDE.out.gene_matrix, clr_matrix, PARENT_GENE.out.circ_host_map, gtf ) CIRCTEST( PREPARE_CLR_TEST.out.circular, PREPARE_CLR_TEST.out.linear, phenotype ) From d1230f28006c5e59ff87381f4fd96d0b32190691 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Tue, 31 Jan 2023 13:46:20 +0000 Subject: [PATCH 011/491] versions indentation --- modules/local/stringtie/prepde/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/stringtie/prepde/main.nf b/modules/local/stringtie/prepde/main.nf index c5700673..189cea1e 100644 --- a/modules/local/stringtie/prepde/main.nf +++ b/modules/local/stringtie/prepde/main.nf @@ -25,7 +25,7 @@ process STRINGTIE_PREPDE { cat <<-END_VERSIONS > versions.yml "${task.process}": - python: \$(python --version | sed -e "s/Python //g") + python: \$(python --version | sed -e 's/Python //g') END_VERSIONS """ } From 1c7bf5c5043dbb7e76987f34bd53d11a0307ae99 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Tue, 31 Jan 2023 14:02:02 +0000 Subject: [PATCH 012/491] use stringtie version for stringtie script --- modules/local/stringtie/prepde/main.nf | 2 +- subworkflows/local/circrna_discovery.nf | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/local/stringtie/prepde/main.nf b/modules/local/stringtie/prepde/main.nf index 189cea1e..07ff052e 100644 --- a/modules/local/stringtie/prepde/main.nf +++ b/modules/local/stringtie/prepde/main.nf @@ -25,7 +25,7 @@ process STRINGTIE_PREPDE { cat <<-END_VERSIONS > versions.yml "${task.process}": - python: \$(python --version | sed -e 's/Python //g') + stringtie: \$(stringtie --version 2>&1) END_VERSIONS """ } diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 89d4df68..651427e1 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -198,6 +198,7 @@ workflow CIRCRNA_DISCOVERY { CIRIQUANT_FILTER.out.results, DCC_FILTER.out.results, MAPSPLICE_FILTER.out.results) + ANNOTATION( circrna_filtered, gtf, ch_biotypes, exon_boundary ) ch_versions = ch_versions.mix(ANNOTATION.out.versions) From 2dabe07171e37a210be79f425be28d2ef3e46271 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Tue, 31 Jan 2023 14:17:23 +0000 Subject: [PATCH 013/491] collect biotypes chan --- subworkflows/local/circrna_discovery.nf | 4 ++-- subworkflows/local/differential_expression.nf | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 651427e1..a253959c 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -198,8 +198,8 @@ workflow CIRCRNA_DISCOVERY { CIRIQUANT_FILTER.out.results, DCC_FILTER.out.results, MAPSPLICE_FILTER.out.results) - - ANNOTATION( circrna_filtered, gtf, ch_biotypes, exon_boundary ) + + ANNOTATION( circrna_filtered, gtf, ch_biotypes.collect(), exon_boundary ) ch_versions = ch_versions.mix(ANNOTATION.out.versions) diff --git a/subworkflows/local/differential_expression.nf b/subworkflows/local/differential_expression.nf index 1d442a80..85e33af0 100644 --- a/subworkflows/local/differential_expression.nf +++ b/subworkflows/local/differential_expression.nf @@ -46,7 +46,7 @@ workflow DIFFERENTIAL_EXPRESSION { ch_biotypes = Channel.fromPath("${projectDir}/bin/unwanted_biotypes.txt") - PARENT_GENE( clr_matrix, gtf, ch_biotypes, exon_boundary ) + PARENT_GENE( clr_matrix, gtf, ch_biotypes.collect(), exon_boundary ) PREPARE_CLR_TEST( STRINGTIE_PREPDE.out.gene_matrix, clr_matrix, PARENT_GENE.out.circ_host_map, gtf ) CIRCTEST( PREPARE_CLR_TEST.out.circular, PREPARE_CLR_TEST.out.linear, phenotype ) From 7727fa7006773acff493c661f1c6bbb854313db9 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Tue, 31 Jan 2023 15:03:59 +0000 Subject: [PATCH 014/491] mawk not gawk, ubuntu20.04 container --- modules/local/circexplorer2/filter/main.nf | 9 +++++---- modules/local/ciriquant/filter/main.nf | 9 +++++---- modules/local/dcc/filter/main.nf | 9 +++++---- modules/local/segemehl/filter/main.nf | 11 ++++++----- modules/local/star/sjdb/main.nf | 9 +++++---- modules/local/targetscan/database/main.nf | 14 +++++++++++++- subworkflows/local/mirna_prediction.nf | 1 + 7 files changed, 40 insertions(+), 22 deletions(-) diff --git a/modules/local/circexplorer2/filter/main.nf b/modules/local/circexplorer2/filter/main.nf index fece7a46..4b246961 100644 --- a/modules/local/circexplorer2/filter/main.nf +++ b/modules/local/circexplorer2/filter/main.nf @@ -2,10 +2,10 @@ process CIRCEXPLORER2_FILTER { tag "$meta.id" label 'process_single' - conda "bioconda::gawk=5.1.0" + conda "conda-forge::sed=4.7" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/gawk%3A5.1.0' : - 'quay.io/biocontainers/gawk:5.1.0' }" + 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : + 'ubuntu:20.04' }" input: tuple val(meta), path(txt) @@ -22,6 +22,7 @@ process CIRCEXPLORER2_FILTER { script: def args = task.ext.args ?: '' prefix = task.ext.prefix ?: "${meta.id}" + def VERSION = '1.3.4' """ awk '{if(\$13 >= ${bsj_reads}) print \$0}' ${prefix}.txt | awk -v OFS="\t" '{print \$1,\$2,\$3,\$6,\$13}' > ${prefix}_${meta.tool}.bed @@ -29,7 +30,7 @@ process CIRCEXPLORER2_FILTER { cat <<-END_VERSIONS > versions.yml "${task.process}": - awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) + mawk: $VERSION END_VERSIONS """ } diff --git a/modules/local/ciriquant/filter/main.nf b/modules/local/ciriquant/filter/main.nf index 253d6d2b..38520091 100644 --- a/modules/local/ciriquant/filter/main.nf +++ b/modules/local/ciriquant/filter/main.nf @@ -2,10 +2,10 @@ process CIRIQUANT_FILTER { tag "$meta.id" label 'process_single' - conda "bioconda::gawk=5.1.0" + conda "conda-forge::sed=4.7" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/gawk%3A5.1.0' : - 'quay.io/biocontainers/gawk:5.1.0' }" + 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : + 'ubuntu:20.04' }" input: tuple val(meta), path(gtf) @@ -21,6 +21,7 @@ process CIRIQUANT_FILTER { script: prefix = task.ext.prefix ?: "${meta.id}" + def VERSION = '1.3.4' """ grep -v "#" ${prefix}.gtf | awk '{print \$14}' | cut -d '.' -f1 > counts grep -v "#" ${prefix}.gtf | awk -v OFS="\t" '{print \$1,\$4,\$5,\$7}' > ${prefix}.tmp @@ -36,7 +37,7 @@ process CIRIQUANT_FILTER { cat <<-END_VERSIONS > versions.yml "${task.process}": - awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) + mawk: $VERSION END_VERSIONS """ } diff --git a/modules/local/dcc/filter/main.nf b/modules/local/dcc/filter/main.nf index 1fcd3ef7..d7bc3c54 100644 --- a/modules/local/dcc/filter/main.nf +++ b/modules/local/dcc/filter/main.nf @@ -2,10 +2,10 @@ process DCC_FILTER { tag "$meta.id" label 'process_single' - conda "bioconda::gawk=5.1.0" + conda "conda-forge::sed=4.7" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/gawk%3A5.1.0' : - 'quay.io/biocontainers/gawk:5.1.0' }" + 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : + 'ubuntu:20.04' }" input: tuple val(meta), path(txt) @@ -21,6 +21,7 @@ process DCC_FILTER { script: prefix = task.ext.prefix ?: "${meta.id}" + def VERSION = '1.3.4' """ awk '{if(\$5 >= ${bsj_reads}) print \$0}' ${prefix}.txt > ${prefix}_dcc.filtered awk -v OFS="\t" '{\$2-=1;print}' ${prefix}_dcc.filtered > ${prefix}_dcc.bed @@ -28,7 +29,7 @@ process DCC_FILTER { cat <<-END_VERSIONS > versions.yml "${task.process}": - awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) + mawk: $VERSION END_VERSIONS """ } diff --git a/modules/local/segemehl/filter/main.nf b/modules/local/segemehl/filter/main.nf index 5ca86cca..40c895ff 100644 --- a/modules/local/segemehl/filter/main.nf +++ b/modules/local/segemehl/filter/main.nf @@ -2,10 +2,10 @@ process SEGEMEHL_FILTER { tag "$meta.id" label 'process_single' - conda "bioconda::gawk=5.1.0" + conda "conda-forge::sed=4.7" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/gawk%3A5.1.0' : - 'quay.io/biocontainers/gawk:5.1.0' }" + 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : + 'ubuntu:20.04' }" input: tuple val(meta), path(results) @@ -22,6 +22,7 @@ process SEGEMEHL_FILTER { script: def args = task.ext.args ?: '' prefix = task.ext.prefix ?: "${meta.id}" + def VERSION = '1.3.4' """ grep ';C;' ${prefix}.sngl.bed | awk -v OFS="\t" '{print \$1,\$2,\$3,\$6}' | sort | uniq -c | awk -v OFS="\t" '{print \$2,\$3,\$4,\$5,\$1}' > ${prefix}_collapsed.bed @@ -31,8 +32,8 @@ process SEGEMEHL_FILTER { cat <<-END_VERSIONS > versions.yml "${task.process}": - awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) - sort: \$(sort --version | sed -e 's/sort (GNU coreutils) //g') + mawk: $VERSION + sort: \$(sort --version | head -n 1 | sed -e 's/sort (GNU coreutils) //g') END_VERSIONS """ } diff --git a/modules/local/star/sjdb/main.nf b/modules/local/star/sjdb/main.nf index 60b81849..3a09d91a 100644 --- a/modules/local/star/sjdb/main.nf +++ b/modules/local/star/sjdb/main.nf @@ -1,10 +1,10 @@ process SJDB { label 'process_single' - conda "bioconda::gawk=5.1.0" + conda "conda-forge::sed=4.7" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/gawk%3A5.1.0' : - 'quay.io/biocontainers/gawk:5.1.0' }" + 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : + 'ubuntu:20.04' }" input: path(sjdb) @@ -18,12 +18,13 @@ process SJDB { task.ext.when == null || task.ext.when script: + def VERSION = '1.3.4' """ cat *.tab | awk -v BSJ=${bsj_reads} '(\$7 >= BSJ && \$6==0)' | cut -f1-6 | sort | uniq > dataset.SJ.out.tab cat <<-END_VERSIONS > versions.yml "${task.process}": - awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) + mawk: $VERSION END_VERSIONS """ } diff --git a/modules/local/targetscan/database/main.nf b/modules/local/targetscan/database/main.nf index 75657365..030ffe9b 100644 --- a/modules/local/targetscan/database/main.nf +++ b/modules/local/targetscan/database/main.nf @@ -2,17 +2,29 @@ process TARGETSCAN_DATABASE { tag "$mature" label 'process_low' + conda "conda-forge::sed=4.7" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : + 'ubuntu:20.04' }" + input: path(mature) output: - path("mature.txt"), emit: mature_txt + path("mature.txt") , emit: mature_txt + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when script: + def VERSION = '1.3.4' """ targetscan_format.sh $mature + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + mawk: $VERSION + END_VERSIONS """ } diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index 953c794e..b9a4cfc7 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -20,6 +20,7 @@ workflow MIRNA_PREDICTION{ TARGETSCAN_DATABASE( mature ) TARGETSCAN( circrna_fasta, TARGETSCAN_DATABASE.out.mature_txt ) + ch_versions = ch_versions.mix(TARGETSCAN_DATABASE.out.versions) ch_versions = ch_versions.mix(TARGETSCAN.out.versions) // From 77e7b4adf85091a7e54924349c2e35937effa35d Mon Sep 17 00:00:00 2001 From: Barry digby Date: Tue, 31 Jan 2023 15:45:21 +0000 Subject: [PATCH 015/491] update outputs.md --- docs/output.md | 30 +++++++++---------------- subworkflows/local/circrna_discovery.nf | 2 +- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/docs/output.md b/docs/output.md index 27dd215f..80185914 100644 --- a/docs/output.md +++ b/docs/output.md @@ -164,6 +164,17 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d ## circRNA Quantification +## Common Outputs + +The workflow is designed to output three files per quantification tool selected in the `circrna_discovery` directory. By design, the workflow standardises the outputs of each quantification tool. + +- `quantification_tool/`: + - `${sample_id}.bed`: A customised BED 12 file containing filtered, annotated circRNAs. Columns: chromosome, start, end, name, read counts, strand, start, end, RGB, number of exon blocks, size of exon blocks, start positions (within sequence) of exon blocks, parent gene ID(s), parent transcript ID(s), mature spliced length. + - `${sample_id}.log`: Script detailing the decisions made by `annotate_outputs.sh` when annotating each circRNA. + - `${sample_id}.fasta`: Mature spliced sequence of circRNA in FASTA format. Includes splice junction site (+-20bp). + +Intermediate files generated by each quantification tool are described in depth below. + ### CIRCexplorer2

@@ -172,9 +183,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d - `circrna_discovery/CIRCexplorer2/intermediates/${sample_id}/` - `*.STAR.junction.bed`: Intermediate file generated by `CIRCexplorer2 parse` module, identifying STAR fusion junctions for downstream annotation. - `*.txt`: Output files generated by `CIRCexplorer2 annotate` module, based on BED 12 format containing circRNA genomic location information, exon cassette composition and an additional 6 columns specifying circRNA annotations. Full descriptions of the 18 columns can be found in the `CIRCexplorer2` [documentation](https://circexplorer2.readthedocs.io/en/latest/modules/annotate/#output). -- `circrna_discovery/CIRCexplorer2/${sample_id}/` - - `${sample_id}.bed`: Filtered, annotated circRNAs in customised BED12 format. - - `fasta/`: Mature spliced length circRNA FASTA sequences.
@@ -197,9 +205,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d - `*.filteredJunctions.bed`: A bed file with **all** circular junctions found by the pipeline. The score column indicates the number reads spanning each junction. - `*.s_filteredJunctions.bed`: A bed file with those junctions in `*.filteredJunctions.bed` that are flanked by GT-AG splice sites. The score column indicates the number reads spanning each junction. - `*.s_filteredJunctions_fw.bed`: A bed file with the same circular junctions as in file (b), but here the score column gives the average number of forward spliced reads at both splice sites around each circular junction. -- `circrna_discovery/circRNA_Finder/${sample_id}/` - - `${sample_id}.bed`: Filtered, annotated circRNAs in customised BED12 format. - - `fasta/`: Mature spliced length circRNA FASTA sequences. @@ -221,9 +226,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d - `*_denovo.sorted.{bam, bam.bai}`: (Sorted and indexed) bam file from `BWA` alignment of candidate circular reads to the pseudo reference. - `*_index.*.ht2`: `BWA` index files of the pseudo reference. - `*_index.fa`: Reference FASTA file of candidate circular reads. -- `circrna_discovery/CIRIquant/${sample_id}/`` - - `${sample_id}.bed`: Filtered, annotated circRNAs in customised BED12 format. - - `fasta/`: Mature spliced length circRNA FASTA sequences. @@ -241,10 +243,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d - `mate1/`: Output directory of STAR 2nd pass alignment for R1. - `mate2/`: Output directory of STAR 2nd pass alignment for R2. -- `circrna_discovery/DCC/${sample_id}/` - - `${sample_id}.bed`: Filtered, annotated circRNAs in customised BED12 format. - - `fasta/`: Mature spliced length circRNA FASTA sequences. - [DCC](https://github.com/dieterich-lab/DCC) identifies back-splice junction sites from `*Chimeric.out.junction`, `*SJ.out.tab` & `*Aligned.sortedByCoord.out.bam` files generated by `STAR` 2 pass mode, mapping the paired end reads both jointly and separately (`STAR` does not output read pairs that contain more than one chimeric junction thus a more granular approach is taken by `DCC` to fully characterise back-splice junctions in reads). @@ -268,9 +266,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d - `*.sites.bed`: Output from `find_circ`, first six columns are in standard BED format. A description of the remaining columns is available in the `find_circ` [documentation](https://github.com/marvin-jens/find_circ#output-format). - `*.sites.log`: Summary statistics of candidate circular reads in the sample. - `*.sites.reads`: Tab delimited file containing circRNA ID & sequence. -- `circrna_discovery/find_circ/${sample_id}/` - - `${sample_id}.bed`: Filtered, annotated circRNAs in customised BED12 format. - - `fasta/`: Mature spliced length circRNA FASTA sequences. @@ -299,9 +294,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d - `insertions.txt`: Report of Insertions. - `junctions.txt`: Reported splice junctions. - `stats.txt`: Read alignment, Junction statistics. -- `circrna_discovery/MapSplice/${sample_id}/` - - `${sample_id}.bed`: Filtered, annotated circRNAs in customised BED12 format. - - `fasta/`: Mature spliced length circRNA FASTA sequences. diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index a253959c..213c6eeb 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -157,7 +157,7 @@ workflow CIRCRNA_DISCOVERY { DCC_MATE2_2ND_PASS( mate2, star_index, DCC_MATE2_SJDB.out.sjtab, true, '', '' ) dcc_stage = DCC_2ND_PASS.out.junction.join( DCC_MATE1_2ND_PASS.out.junction, remainder: true ).join( DCC_MATE2_2ND_PASS.out.junction, remainder: true ) - dcc = dcc_stage.map{ it -> def meta = it[0]; if( meta.single_end ){ return [ it[0], it[1], [], [] ] } else { return it } }.view() + dcc = dcc_stage.map{ it -> def meta = it[0]; if( meta.single_end ){ return [ it[0], it[1], [], [] ] } else { return it } } DCC( dcc, fasta, gtf ) DCC_FILTER( DCC.out.txt.map{ meta, txt -> meta.tool = "dcc"; return [ meta, txt ] }, bsj_reads ) From dab98acf20384648f50608bf4529936d25a76785 Mon Sep 17 00:00:00 2001 From: BarryDigby Date: Tue, 31 Jan 2023 15:57:55 +0000 Subject: [PATCH 016/491] Update CHANGELOG.md Co-authored-by: James A. Fellows Yates --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 465d994c..a1b80afd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## v1.0.0 - [13/12/2022] +## v1.0.0 - [27/01/2023] Initial release of nf-core/circrna, created with the [nf-core](https://nf-co.re/) template. From d1387ba29406c28f6119bdf884f889c798e7a6e8 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Tue, 31 Jan 2023 16:03:48 +0000 Subject: [PATCH 017/491] credits to contributors. --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index bd2c7b02..027e8d10 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,14 @@ The nf-core/circrna pipeline comes with documentation about the pipeline [usage] nf-core/circrna was originally written by Barry Digby. +We thank the following people for their extensive assistance in the development of this pipeline: + +- @apeltzer +- @ewels +- @maxulysse +- @KevinMenden +- @bj-w + ## Acknowledgements ![SFI](./docs/images/Genomics-Data-Science-original.png) From 5922ef22068b8daf2736c1751b9074394cc0368c Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 10:52:24 +0000 Subject: [PATCH 018/491] collect on ref genome paths ? ? : : [] --- README.md | 2 +- bin/check_empty.sh | 2 +- conf/modules.config | 4 --- .../local/count_matrix/merge_tools/main.nf | 2 +- modules/local/fasta/main.nf | 1 - modules/local/find_circ/anchors/main.nf | 2 +- modules/local/find_circ/filter/main.nf | 2 +- modules/local/find_circ/find_circ/main.nf | 2 +- modules/local/mirna_targets/main.nf | 2 +- nextflow.config | 3 +- nextflow_schema.json | 10 +++---- subworkflows/local/circrna_discovery.nf | 29 +++++++++++-------- subworkflows/local/differential_expression.nf | 2 +- subworkflows/local/input_check.nf | 1 - subworkflows/local/prepare_genome.nf | 6 ++-- workflows/circrna.nf | 11 ++++--- 16 files changed, 39 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 027e8d10..8f1d2970 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ On release, automated continuous integration tests run the pipeline on a full-si - Raw read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/)) - Adapter trimming ([`Trim Galore!`](https://www.bioinformatics.babraham.ac.uk/projects/trim_galore/)) +- MultiQC report [`MultiQC`](http://multiqc.info/) - circRNA quantification - [`CIRIquant`](https://github.com/Kevinzjy/CIRIquant) - [`STAR 2-Pass mode`](https://github.com/alexdobin/STAR) @@ -41,7 +42,6 @@ On release, automated continuous integration tests run the pipeline on a full-si - Filter results, miRNAs must be called by both tools - Differential expression analysis [`DESeq2`](https://bioconductor.org/packages/release/bioc/html/DESeq2.html) - Circular - Linear ratio tests ['CircTest'](https://github.com/dieterich-lab/CircTest) -- MultiQC report [`MultiQC`](http://multiqc.info/) ## Quick Start diff --git a/bin/check_empty.sh b/bin/check_empty.sh index 2f54d6da..8f28e88c 100755 --- a/bin/check_empty.sh +++ b/bin/check_empty.sh @@ -1,4 +1,4 @@ -#!/usr/bin/bash +#!/usr/bin/env bash ## When consolidating tool outputs for a sample, check if any are empty. ## This will prevent R from throwing errors diff --git a/conf/modules.config b/conf/modules.config index 21b50e7e..3c6f41b1 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -26,10 +26,6 @@ process { ] } - withName: FASTQC { - ext.args = '--quiet' - } - withName: CUSTOM_DUMPSOFTWAREVERSIONS { publishDir = [ path: { "${params.outdir}/pipeline_info" }, diff --git a/modules/local/count_matrix/merge_tools/main.nf b/modules/local/count_matrix/merge_tools/main.nf index e2ee4b11..cc6818dd 100644 --- a/modules/local/count_matrix/merge_tools/main.nf +++ b/modules/local/count_matrix/merge_tools/main.nf @@ -27,7 +27,7 @@ process MERGE_TOOLS { ls *.bed > samples.csv ## Add catch for empty bed file and delete - bash ${workflow.projectDir}/bin/check_empty.sh + check_empty.sh ## Use intersection of "n" (params.tool_filter) circRNAs called by tools ## remove duplicate IDs, keep highest count. diff --git a/modules/local/fasta/main.nf b/modules/local/fasta/main.nf index f43543d8..e33edeed 100644 --- a/modules/local/fasta/main.nf +++ b/modules/local/fasta/main.nf @@ -22,7 +22,6 @@ process FASTA { script: def args = task.ext.args ?: '' prefix = task.ext.prefix ?: "${meta.id}" - def VERSION = '377' """ ## FASTA sequences (bedtools does not like the extra annotation info - split will not work properly) cut -d\$'\t' -f1-12 ${prefix}.bed > bed12.tmp diff --git a/modules/local/find_circ/anchors/main.nf b/modules/local/find_circ/anchors/main.nf index 15b0650a..5359497d 100644 --- a/modules/local/find_circ/anchors/main.nf +++ b/modules/local/find_circ/anchors/main.nf @@ -2,7 +2,7 @@ process FIND_CIRC_ANCHORS { tag "$meta.id" label "process_high" - conda "find_circ=1.2" + conda "bioconda::find_circ=1.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/find_circ%3A1.2--hdfd78af_0' : 'quay.io/biocontainers/find_circ:1.2--hdfd78af_0' }" diff --git a/modules/local/find_circ/filter/main.nf b/modules/local/find_circ/filter/main.nf index 7be0de57..a12c15ba 100644 --- a/modules/local/find_circ/filter/main.nf +++ b/modules/local/find_circ/filter/main.nf @@ -2,7 +2,7 @@ process FIND_CIRC_FILTER { tag "$meta.id" label "process_low" - conda "find_circ=1.2" + conda "bioconda::find_circ=1.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/find_circ%3A1.2--hdfd78af_0' : 'quay.io/biocontainers/find_circ:1.2--hdfd78af_0' }" diff --git a/modules/local/find_circ/find_circ/main.nf b/modules/local/find_circ/find_circ/main.nf index 57bf656c..242e195f 100644 --- a/modules/local/find_circ/find_circ/main.nf +++ b/modules/local/find_circ/find_circ/main.nf @@ -2,7 +2,7 @@ process FIND_CIRC { tag "$meta.id" label "process_high" - conda "find_circ=1.2 bowtie2" + conda "bioconda::find_circ=1.2 bioconda::bowtie2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-c27e472038a09e49d9147bc52903e12836302c12:60ffb3b15a2c40c669f8d38382b1e6e4b065f5e4-0' : 'quay.io/biocontainers/mulled-v2-c27e472038a09e49d9147bc52903e12836302c12:60ffb3b15a2c40c669f8d38382b1e6e4b065f5e4-0' }" diff --git a/modules/local/mirna_targets/main.nf b/modules/local/mirna_targets/main.nf index 4f70ca03..0891e6e4 100644 --- a/modules/local/mirna_targets/main.nf +++ b/modules/local/mirna_targets/main.nf @@ -12,7 +12,7 @@ process MIRNA_TARGETS { output: tuple val(meta), path("${prefix}.mirna_targets.txt"), emit: results - path "versions.yml" , emit: versions + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/nextflow.config b/nextflow.config index 14f1455c..a2828498 100644 --- a/nextflow.config +++ b/nextflow.config @@ -7,7 +7,6 @@ */ // Global default params, used in configs -// TODO: tidy up after workflow is running smoothly params { // Input options @@ -246,7 +245,7 @@ manifest { description = """Quantification, miRNA target prediction and differential expression analysis of circular RNAs""" mainScript = 'main.nf' nextflowVersion = '!>=22.10.1' - version = '1.0.0' + version = '1.0.0' doi = '' } diff --git a/nextflow_schema.json b/nextflow_schema.json index 5eda7888..5b61d7d8 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -291,6 +291,11 @@ "help_text": "By default, trimmed FastQ files will not be saved to the results directory. Specify this flag (or set to true in your config file) to copy these files to the results directory when complete.", "fa_icon": "fas fa-save" }, + "skip_fastqc": { + "type": "boolean", + "description": "Skip FastQC quality control of the sequencing reads.", + "fa_icon": "fas fa-terminal" + }, "clip_r1": { "type": "integer", "description": "Instructs Trim Galore to remove bp from the 5' end of read 1 (or single-end reads).", @@ -415,11 +420,6 @@ "description": "Less common options for the pipeline, typically set in a config file.", "help_text": "These options are common to all nf-core pipelines and allow you to customise some of the core preferences for how the pipeline runs.\n\nTypically these options would be set in a Nextflow config file loaded for all pipeline runs, such as `~/.nextflow/config`.", "properties": { - "skip_fastqc": { - "type": "boolean", - "description": "Skip FastQC quality control of the sequencing reads.", - "fa_icon": "fas fa-terminal" - }, "help": { "type": "boolean", "description": "Display help text.", diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 213c6eeb..22b5c11c 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -30,15 +30,15 @@ include { STAR_ALIGN as DCC_MATE2_2ND_PASS } from '../../modules/nf-core/star/al include { SJDB as DCC_MATE2_SJDB } from '../../modules/local/star/sjdb/main' include { DCC } from '../../modules/local/dcc/dcc/main' include { DCC_FILTER } from '../../modules/local/dcc/filter/main' -include { CIRCEXPLORER2_REFERENCE as MAPSPLICE_REFERENCE } from '../../modules/local/circexplorer2/reference/main' include { MAPSPLICE_ALIGN } from '../../modules/local/mapsplice/align/main' -include { CIRCEXPLORER2_PARSE as MAPSPLICE_PARSE } from '../../modules/nf-core/circexplorer2/parse/main' -include { CIRCEXPLORER2_ANNOTATE as MAPSPLICE_ANNOTATE } from '../../modules/nf-core/circexplorer2/annotate/main' -include { CIRCEXPLORER2_FILTER as MAPSPLICE_FILTER } from '../../modules/local/circexplorer2/filter/main' include { FASTA } from '../../modules/local/fasta/main' include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools/main' include { COUNTS_COMBINED } from '../../modules/local/count_matrix/combined/main' include { COUNTS_SINGLE } from '../../modules/local/count_matrix/single/main' +include { CIRCEXPLORER2_REFERENCE as MAPSPLICE_REFERENCE } from '../../modules/local/circexplorer2/reference/main' +include { CIRCEXPLORER2_PARSE as MAPSPLICE_PARSE } from '../../modules/nf-core/circexplorer2/parse/main' +include { CIRCEXPLORER2_ANNOTATE as MAPSPLICE_ANNOTATE } from '../../modules/nf-core/circexplorer2/annotate/main' +include { CIRCEXPLORER2_FILTER as MAPSPLICE_FILTER } from '../../modules/local/circexplorer2/filter/main' workflow CIRCRNA_DISCOVERY { @@ -75,10 +75,15 @@ workflow CIRCRNA_DISCOVERY { // STAR WORFKLOW: // - STAR_1ST_PASS( reads, star_index, gtf, true, '', '' ) + // Define variables here, star_ignore_sjdbgtf not supposed to be toggled by user. + star_ignore_sjdbgtf = true + seq_center = params.seq_center ?: '' + seq_platform = '' + + STAR_1ST_PASS( reads, star_index, gtf, star_ignore_sjdbgtf, seq_platform, seq_center) sjdb = STAR_1ST_PASS.out.tab.map{ meta, tab -> return [ tab ] }.collect() STAR_SJDB( sjdb, bsj_reads ) - STAR_2ND_PASS( reads, star_index, STAR_SJDB.out.sjtab, true, '', '' ) + STAR_2ND_PASS( reads, star_index, STAR_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) ch_versions = ch_versions.mix(STAR_1ST_PASS.out.versions) ch_versions = ch_versions.mix(STAR_2ND_PASS.out.versions) @@ -142,19 +147,19 @@ workflow CIRCRNA_DISCOVERY { // DCC WORKFLOW // - DCC_1ST_PASS( reads, star_index, gtf, true, '', '' ) + DCC_1ST_PASS( reads, star_index, gtf, star_ignore_sjdbgtf, seq_platform, seq_center ) DCC_SJDB( DCC_1ST_PASS.out.tab.map{ meta, tab -> return [ tab ] }.collect(), bsj_reads ) - DCC_2ND_PASS( reads, star_index, DCC_SJDB.out.sjtab, true, '', '' ) + DCC_2ND_PASS( reads, star_index, DCC_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) mate1 = reads.map{ meta, reads -> return [meta, reads[0] ] } - DCC_MATE1_1ST_PASS( mate1, star_index, gtf, true, '', '' ) + DCC_MATE1_1ST_PASS( mate1, star_index, gtf, star_ignore_sjdbgtf, seq_platform, seq_center ) DCC_MATE1_SJDB( DCC_MATE1_1ST_PASS.out.tab.map{ meta, tab -> return [ tab ] }.collect(), bsj_reads ) - DCC_MATE1_2ND_PASS( mate1, star_index, DCC_MATE1_SJDB.out.sjtab, true, '', '' ) + DCC_MATE1_2ND_PASS( mate1, star_index, DCC_MATE1_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) mate2 = reads.map{ meta, reads -> return [ meta, reads[1] ] } - DCC_MATE2_1ST_PASS( mate2, star_index, gtf, true, '', '' ) + DCC_MATE2_1ST_PASS( mate2, star_index, gtf, star_ignore_sjdbgtf, seq_platform, seq_center ) DCC_MATE2_SJDB( DCC_MATE2_1ST_PASS.out.tab.map{ meta, tab -> return [ tab ] }.collect(), bsj_reads ) - DCC_MATE2_2ND_PASS( mate2, star_index, DCC_MATE2_SJDB.out.sjtab, true, '', '' ) + DCC_MATE2_2ND_PASS( mate2, star_index, DCC_MATE2_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) dcc_stage = DCC_2ND_PASS.out.junction.join( DCC_MATE1_2ND_PASS.out.junction, remainder: true ).join( DCC_MATE2_2ND_PASS.out.junction, remainder: true ) dcc = dcc_stage.map{ it -> def meta = it[0]; if( meta.single_end ){ return [ it[0], it[1], [], [] ] } else { return it } } diff --git a/subworkflows/local/differential_expression.nf b/subworkflows/local/differential_expression.nf index 85e33af0..8bf83bda 100644 --- a/subworkflows/local/differential_expression.nf +++ b/subworkflows/local/differential_expression.nf @@ -2,10 +2,10 @@ include { HISAT2_ALIGN } from '../../modules/nf-core/hisat2/align/m include { SAMTOOLS_SORT } from '../../modules/nf-core/samtools/sort/main' include { STRINGTIE_STRINGTIE } from '../../modules/nf-core/stringtie/stringtie/main' include { STRINGTIE_PREPDE } from '../../modules/local/stringtie/prepde/main' -include { DESEQ2_DIFFERENTIAL_EXPRESSION } from '../../modules/local/deseq2/differential_expression/main' include { PARENT_GENE } from '../../modules/local/annotation/parent_gene/main' include { PREPARE_CLR_TEST } from '../../modules/local/circtest/prepare/main' include { CIRCTEST } from '../../modules/local/circtest/test/main' +include { DESEQ2_DIFFERENTIAL_EXPRESSION } from '../../modules/local/deseq2/differential_expression/main' workflow DIFFERENTIAL_EXPRESSION { diff --git a/subworkflows/local/input_check.nf b/subworkflows/local/input_check.nf index 753a2838..faf7c5b2 100644 --- a/subworkflows/local/input_check.nf +++ b/subworkflows/local/input_check.nf @@ -24,7 +24,6 @@ workflow INPUT_CHECK { versions = SAMPLESHEET_CHECK.out.versions // channel: [ versions.yml ] } -// Function to get list of [ meta, [ fastq_1, fastq_2 ] ] // Function to get list of [ meta, [ fastq_1, fastq_2 ] ] def create_fastq_channel(LinkedHashMap row) { // create meta map diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index b49a4e83..e3b1b5e2 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -20,15 +20,15 @@ workflow PREPARE_GENOME { // MapSplice & find_circ requires reference genome to be split per chromosome: if( ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) && params.module.contains('circrna_discovery') ){ - file("${params.outdir}/genome/chromosomes").mkdirs() + file("${params.outdir}/reference/chromosomes").mkdirs() ch_fasta.splitFasta( record: [id:true] ) .map{ record -> record.id.toString() } .set{ ID } ch_fasta.splitFasta( file: true ) - .merge( ID ).map{ file, id -> file.copyTo("${params.outdir}/genome/chromosomes/${id}.fa") } + .merge( ID ).map{ file, id -> file.copyTo("${params.outdir}/reference/chromosomes/${id}.fa") } - stage_chromosomes = Channel.value("${workflow.launchDir}/${params.outdir}/genome/chromosomes") + stage_chromosomes = Channel.value("${workflow.launchDir}/${params.outdir}/reference/chromosomes") } ch_fasta.map{ it -> diff --git a/workflows/circrna.nf b/workflows/circrna.nf index 34ff6947..f165519a 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -63,7 +63,6 @@ include { DIFFERENTIAL_EXPRESSION } from '../subworkflows/local/differential_exp */ // MODULES: -include { FASTQC } from '../modules/nf-core/fastqc/main' include { MULTIQC } from '../modules/nf-core/multiqc/main' include { CUSTOM_DUMPSOFTWAREVERSIONS } from '../modules/nf-core/custom/dumpsoftwareversions/main' include { CAT_FASTQ } from '../modules/nf-core/cat/fastq/main' @@ -127,13 +126,13 @@ workflow CIRCRNA { ) // Stage the indices via newly created indices, iGenomes or empty list if tool not selected. - bowtie_index = params.fasta ? params.bowtie ? Channel.fromPath(params.bowtie) : PREPARE_GENOME.out.bowtie : [] - bowtie2_index = params.fasta ? params.bowtie2 ? Channel.fromPath(params.bowtie2) : PREPARE_GENOME.out.bowtie2 : [] - bwa_index = params.fasta ? params.bwa ? Channel.fromPath(params.bwa) : PREPARE_GENOME.out.bwa : [] + bowtie_index = params.fasta ? params.bowtie ? Channel.fromPath(params.bowtie).collect() : PREPARE_GENOME.out.bowtie : [] + bowtie2_index = params.fasta ? params.bowtie2 ? Channel.fromPath(params.bowtie2).collect() : PREPARE_GENOME.out.bowtie2 : [] + bwa_index = params.fasta ? params.bwa ? Channel.fromPath(params.bwa).collect() : PREPARE_GENOME.out.bwa : [] chromosomes = ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) ? PREPARE_GENOME.out.chromosomes : [] hisat2_index = ( params.tool.contains('ciriquant') || params.module.contains('differential_expression') ) ? PREPARE_GENOME.out.hisat2 : [] - star_index = params.fasta ? params.star ? Channel.fromPath(params.star) : PREPARE_GENOME.out.star : [] - segemehl_index = params.fasta ? params.segemehl ? Channel.fromPath(params.segemehl) : PREPARE_GENOME.out.segemehl : [] + star_index = params.fasta ? params.star ? Channel.fromPath(params.star).collect() : PREPARE_GENOME.out.star : [] + segemehl_index = params.fasta ? params.segemehl ? Channel.fromPath(params.segemehl).collect() : PREPARE_GENOME.out.segemehl : [] ch_versions = ch_versions.mix(PREPARE_GENOME.out.versions) // MODULE: Run FastQC, trimgalore! From 3e6fe7350feb4cde59a6243869f442a6f4a16328 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 11:04:46 +0000 Subject: [PATCH 019/491] bwa test --- subworkflows/local/prepare_genome.nf | 6 +++--- workflows/circrna.nf | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index e3b1b5e2..0cdf0c38 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -32,9 +32,9 @@ workflow PREPARE_GENOME { } ch_fasta.map{ it -> - meta = [:] - meta.id = it.simpleName - return [ meta, [it] ] + meta = [:] + meta.id = it.simpleName + return [ meta, [it] ] }.set{ fasta_tuple } BOWTIE_BUILD(fasta) diff --git a/workflows/circrna.nf b/workflows/circrna.nf index f165519a..d8c277f2 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -128,7 +128,7 @@ workflow CIRCRNA { // Stage the indices via newly created indices, iGenomes or empty list if tool not selected. bowtie_index = params.fasta ? params.bowtie ? Channel.fromPath(params.bowtie).collect() : PREPARE_GENOME.out.bowtie : [] bowtie2_index = params.fasta ? params.bowtie2 ? Channel.fromPath(params.bowtie2).collect() : PREPARE_GENOME.out.bowtie2 : [] - bwa_index = params.fasta ? params.bwa ? Channel.fromPath(params.bwa).collect() : PREPARE_GENOME.out.bwa : [] + bwa_index = params.fasta ? params.bwa ? Channel.fromPath(params.bwa).collect().map{ it -> [[id:it[0].baseName], it] }, sort : PREPARE_GENOME.out.bwa : [] chromosomes = ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) ? PREPARE_GENOME.out.chromosomes : [] hisat2_index = ( params.tool.contains('ciriquant') || params.module.contains('differential_expression') ) ? PREPARE_GENOME.out.hisat2 : [] star_index = params.fasta ? params.star ? Channel.fromPath(params.star).collect() : PREPARE_GENOME.out.star : [] From 9b979d0f99d78fad7fdf8b4200324dcf8a51c0cb Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 11:05:32 +0000 Subject: [PATCH 020/491] s --- workflows/circrna.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflows/circrna.nf b/workflows/circrna.nf index d8c277f2..dc9de65e 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -128,7 +128,7 @@ workflow CIRCRNA { // Stage the indices via newly created indices, iGenomes or empty list if tool not selected. bowtie_index = params.fasta ? params.bowtie ? Channel.fromPath(params.bowtie).collect() : PREPARE_GENOME.out.bowtie : [] bowtie2_index = params.fasta ? params.bowtie2 ? Channel.fromPath(params.bowtie2).collect() : PREPARE_GENOME.out.bowtie2 : [] - bwa_index = params.fasta ? params.bwa ? Channel.fromPath(params.bwa).collect().map{ it -> [[id:it[0].baseName], it] }, sort : PREPARE_GENOME.out.bwa : [] + bwa_index = params.fasta ? params.bwa ? Channel.fromPath(params.bwa).collect().map{ it -> [[id:it[0].baseName], it] }, sort } : PREPARE_GENOME.out.bwa : [] chromosomes = ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) ? PREPARE_GENOME.out.chromosomes : [] hisat2_index = ( params.tool.contains('ciriquant') || params.module.contains('differential_expression') ) ? PREPARE_GENOME.out.hisat2 : [] star_index = params.fasta ? params.star ? Channel.fromPath(params.star).collect() : PREPARE_GENOME.out.star : [] From ccd8d7251bd6e3edda1174624e52f8d2644ef598 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 11:38:16 +0000 Subject: [PATCH 021/491] bwa index fix --- workflows/circrna.nf | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/workflows/circrna.nf b/workflows/circrna.nf index dc9de65e..7f0a9da3 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -126,13 +126,13 @@ workflow CIRCRNA { ) // Stage the indices via newly created indices, iGenomes or empty list if tool not selected. - bowtie_index = params.fasta ? params.bowtie ? Channel.fromPath(params.bowtie).collect() : PREPARE_GENOME.out.bowtie : [] - bowtie2_index = params.fasta ? params.bowtie2 ? Channel.fromPath(params.bowtie2).collect() : PREPARE_GENOME.out.bowtie2 : [] - bwa_index = params.fasta ? params.bwa ? Channel.fromPath(params.bwa).collect().map{ it -> [[id:it[0].baseName], it] }, sort } : PREPARE_GENOME.out.bwa : [] + bowtie_index = params.fasta ? params.bowtie ? Channel.fromPath(params.bowtie) : PREPARE_GENOME.out.bowtie : [] + bowtie2_index = params.fasta ? params.bowtie2 ? Channel.fromPath(params.bowtie2) : PREPARE_GENOME.out.bowtie2 : [] + bwa_index = params.fasta ? params.bwa ? Channel.fromPath(params.bwa).map{ it -> [[id:it[0].baseName], it] }.view() : PREPARE_GENOME.out.bwa : [] chromosomes = ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) ? PREPARE_GENOME.out.chromosomes : [] hisat2_index = ( params.tool.contains('ciriquant') || params.module.contains('differential_expression') ) ? PREPARE_GENOME.out.hisat2 : [] - star_index = params.fasta ? params.star ? Channel.fromPath(params.star).collect() : PREPARE_GENOME.out.star : [] - segemehl_index = params.fasta ? params.segemehl ? Channel.fromPath(params.segemehl).collect() : PREPARE_GENOME.out.segemehl : [] + star_index = params.fasta ? params.star ? Channel.fromPath(params.star): PREPARE_GENOME.out.star : [] + segemehl_index = params.fasta ? params.segemehl ? Channel.fromPath(params.segemehl) : PREPARE_GENOME.out.segemehl : [] ch_versions = ch_versions.mix(PREPARE_GENOME.out.versions) // MODULE: Run FastQC, trimgalore! From 487102c11f211c7c5f4a105875121d0ed9488be5 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 11:47:43 +0000 Subject: [PATCH 022/491] testing collect --- workflows/circrna.nf | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/workflows/circrna.nf b/workflows/circrna.nf index 7f0a9da3..462de2f3 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -126,11 +126,11 @@ workflow CIRCRNA { ) // Stage the indices via newly created indices, iGenomes or empty list if tool not selected. - bowtie_index = params.fasta ? params.bowtie ? Channel.fromPath(params.bowtie) : PREPARE_GENOME.out.bowtie : [] - bowtie2_index = params.fasta ? params.bowtie2 ? Channel.fromPath(params.bowtie2) : PREPARE_GENOME.out.bowtie2 : [] - bwa_index = params.fasta ? params.bwa ? Channel.fromPath(params.bwa).map{ it -> [[id:it[0].baseName], it] }.view() : PREPARE_GENOME.out.bwa : [] - chromosomes = ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) ? PREPARE_GENOME.out.chromosomes : [] - hisat2_index = ( params.tool.contains('ciriquant') || params.module.contains('differential_expression') ) ? PREPARE_GENOME.out.hisat2 : [] + bowtie_index = params.fasta ? params.bowtie ? Channel.fromPath(params.bowtie).collect() : PREPARE_GENOME.out.bowtie : [] + bowtie2_index = params.fasta ? params.bowtie2 ? Channel.fromPath(params.bowtie2).collect() : PREPARE_GENOME.out.bowtie2 : [] + bwa_index = params.fasta ? params.bwa ? Channel.fromPath(params.bwa).collect().map{ it -> [[id:it[0].baseName], it] }.view() : PREPARE_GENOME.out.bwa : [] + chromosomes = params.fasta && ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) ? PREPARE_GENOME.out.chromosomes : [] + hisat2_index = params.fasta ? params.hisat2 && ( params.tool.contains('ciriquant') || params.module.contains('differential_expression') ) ? Channel.fromPath(params.hisat2).collect() : PREPARE_GENOME.out.hisat2 : [] star_index = params.fasta ? params.star ? Channel.fromPath(params.star): PREPARE_GENOME.out.star : [] segemehl_index = params.fasta ? params.segemehl ? Channel.fromPath(params.segemehl) : PREPARE_GENOME.out.segemehl : [] ch_versions = ch_versions.mix(PREPARE_GENOME.out.versions) From 513e594bb439bb8902dc98c7468fbdc05d868abc Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 11:51:52 +0000 Subject: [PATCH 023/491] yaml stuff --- subworkflows/local/circrna_discovery.nf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 22b5c11c..8f39b3a3 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -136,7 +136,9 @@ workflow CIRCRNA_DISCOVERY { // CIRIQUANT WORKFLOW: // - CIRIQUANT_YML( gtf, fasta, bwa_index.map{ meta, index -> return index }, hisat2_index ) + // only need path to bwa, only need path to hisat2. + // do not want to upset the collect declr for all indices just for this. + CIRIQUANT_YML( gtf, fasta, bwa_index.map{ meta, index -> return index[0].getPath() }, hisat2_index.map{ it -> return it[0].getPath() } ) CIRIQUANT( reads, CIRIQUANT_YML.out.yml.collect() ) CIRIQUANT_FILTER( CIRIQUANT.out.gtf.map{ meta, gtf -> meta.tool = "ciriquant"; return [ meta, gtf ] }, bsj_reads ) From f070228dbdc554bfea9ad41232550ae097b3f9bd Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 12:23:50 +0000 Subject: [PATCH 024/491] user paths fix --- subworkflows/local/circrna_discovery.nf | 2 +- subworkflows/local/prepare_genome.nf | 6 +++--- workflows/circrna.nf | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 8f39b3a3..054b34d6 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -138,7 +138,7 @@ workflow CIRCRNA_DISCOVERY { // only need path to bwa, only need path to hisat2. // do not want to upset the collect declr for all indices just for this. - CIRIQUANT_YML( gtf, fasta, bwa_index.map{ meta, index -> return index[0].getPath() }, hisat2_index.map{ it -> return it[0].getPath() } ) + CIRIQUANT_YML( gtf, fasta, bwa_index.map{ meta, index -> return index }, hisat2_index ) CIRIQUANT( reads, CIRIQUANT_YML.out.yml.collect() ) CIRIQUANT_FILTER( CIRIQUANT.out.gtf.map{ meta, gtf -> meta.tool = "ciriquant"; return [ meta, gtf ] }, bsj_reads ) diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 0cdf0c38..e4ec459e 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -20,15 +20,15 @@ workflow PREPARE_GENOME { // MapSplice & find_circ requires reference genome to be split per chromosome: if( ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) && params.module.contains('circrna_discovery') ){ - file("${params.outdir}/reference/chromosomes").mkdirs() + file("${params.outdir}/references/chromosomes").mkdirs() ch_fasta.splitFasta( record: [id:true] ) .map{ record -> record.id.toString() } .set{ ID } ch_fasta.splitFasta( file: true ) - .merge( ID ).map{ file, id -> file.copyTo("${params.outdir}/reference/chromosomes/${id}.fa") } + .merge( ID ).map{ file, id -> file.copyTo("${params.outdir}/references/chromosomes/${id}.fa") } - stage_chromosomes = Channel.value("${workflow.launchDir}/${params.outdir}/reference/chromosomes") + stage_chromosomes = Channel.value("${workflow.launchDir}/${params.outdir}/references/chromosomes") } ch_fasta.map{ it -> diff --git a/workflows/circrna.nf b/workflows/circrna.nf index 462de2f3..4f5e7056 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -126,9 +126,9 @@ workflow CIRCRNA { ) // Stage the indices via newly created indices, iGenomes or empty list if tool not selected. - bowtie_index = params.fasta ? params.bowtie ? Channel.fromPath(params.bowtie).collect() : PREPARE_GENOME.out.bowtie : [] - bowtie2_index = params.fasta ? params.bowtie2 ? Channel.fromPath(params.bowtie2).collect() : PREPARE_GENOME.out.bowtie2 : [] - bwa_index = params.fasta ? params.bwa ? Channel.fromPath(params.bwa).collect().map{ it -> [[id:it[0].baseName], it] }.view() : PREPARE_GENOME.out.bwa : [] + bowtie_index = params.fasta ? params.bowtie ? Channel.fromPath(params.bowtie) : PREPARE_GENOME.out.bowtie : [] + bowtie2_index = params.fasta ? params.bowtie2 ? Channel.fromPath(params.bowtie2).map{ it -> [[id:'bowtie2'], it] } : PREPARE_GENOME.out.bowtie2 : [] + bwa_index = params.fasta ? params.bwa ? Channel.fromPath(params.bwa).map{ it -> [[id:'bwa'], it] } : PREPARE_GENOME.out.bwa : [] chromosomes = params.fasta && ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) ? PREPARE_GENOME.out.chromosomes : [] hisat2_index = params.fasta ? params.hisat2 && ( params.tool.contains('ciriquant') || params.module.contains('differential_expression') ) ? Channel.fromPath(params.hisat2).collect() : PREPARE_GENOME.out.hisat2 : [] star_index = params.fasta ? params.star ? Channel.fromPath(params.star): PREPARE_GENOME.out.star : [] From a6e64237110d2bf1bdcd430a647d6bc249e8cefc Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 12:27:38 +0000 Subject: [PATCH 025/491] star ref output path --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 3c6f41b1..57de9f9b 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -124,7 +124,7 @@ if (!params.skip_trimming) { params.sjdboverhang ? "--sjdbOverhang ${params.sjdboverhang}" : '', ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/references/index/star" }, + path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_reference From 3f1709380cb27587ec72437d51a949bceb5b2244 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 12:57:40 +0000 Subject: [PATCH 026/491] star collect user path --- conf/modules.config | 4 ++-- subworkflows/local/circrna_discovery.nf | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 57de9f9b..75584759 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -71,7 +71,7 @@ if (!params.skip_trimming) { withName: BOWTIE_BUILD { ext.when = { params.fasta && !params.bowtie && params.tool.split(',').contains('mapsplice') && params.module.split(',').contains('circrna_discovery') } publishDir = [ - path: { "${params.outdir}/references/index/bowtie" }, + path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_reference @@ -111,7 +111,7 @@ if (!params.skip_trimming) { withName: HISAT2_BUILD { ext.when = { params.fasta && params.gtf && ( params.module.split(',').contains('differential_expression') || params.tool.split(',').contains('ciriquant') ) } publishDir = [ - path: { "${params.outdir}/references/index/hisat2" }, + path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_reference diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 054b34d6..c7612946 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -80,10 +80,10 @@ workflow CIRCRNA_DISCOVERY { seq_center = params.seq_center ?: '' seq_platform = '' - STAR_1ST_PASS( reads, star_index, gtf, star_ignore_sjdbgtf, seq_platform, seq_center) + STAR_1ST_PASS( reads, star_index.collect(), gtf, star_ignore_sjdbgtf, seq_platform, seq_center) sjdb = STAR_1ST_PASS.out.tab.map{ meta, tab -> return [ tab ] }.collect() STAR_SJDB( sjdb, bsj_reads ) - STAR_2ND_PASS( reads, star_index, STAR_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) + STAR_2ND_PASS( reads, star_index.collect(), STAR_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) ch_versions = ch_versions.mix(STAR_1ST_PASS.out.versions) ch_versions = ch_versions.mix(STAR_2ND_PASS.out.versions) @@ -149,19 +149,19 @@ workflow CIRCRNA_DISCOVERY { // DCC WORKFLOW // - DCC_1ST_PASS( reads, star_index, gtf, star_ignore_sjdbgtf, seq_platform, seq_center ) + DCC_1ST_PASS( reads, star_index.collect(), gtf, star_ignore_sjdbgtf, seq_platform, seq_center ) DCC_SJDB( DCC_1ST_PASS.out.tab.map{ meta, tab -> return [ tab ] }.collect(), bsj_reads ) - DCC_2ND_PASS( reads, star_index, DCC_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) + DCC_2ND_PASS( reads, star_index.collect(), DCC_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) mate1 = reads.map{ meta, reads -> return [meta, reads[0] ] } - DCC_MATE1_1ST_PASS( mate1, star_index, gtf, star_ignore_sjdbgtf, seq_platform, seq_center ) + DCC_MATE1_1ST_PASS( mate1, star_index.collect(), gtf, star_ignore_sjdbgtf, seq_platform, seq_center ) DCC_MATE1_SJDB( DCC_MATE1_1ST_PASS.out.tab.map{ meta, tab -> return [ tab ] }.collect(), bsj_reads ) - DCC_MATE1_2ND_PASS( mate1, star_index, DCC_MATE1_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) + DCC_MATE1_2ND_PASS( mate1, star_index.collect(), DCC_MATE1_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) mate2 = reads.map{ meta, reads -> return [ meta, reads[1] ] } - DCC_MATE2_1ST_PASS( mate2, star_index, gtf, star_ignore_sjdbgtf, seq_platform, seq_center ) + DCC_MATE2_1ST_PASS( mate2, star_index.collect(), gtf, star_ignore_sjdbgtf, seq_platform, seq_center ) DCC_MATE2_SJDB( DCC_MATE2_1ST_PASS.out.tab.map{ meta, tab -> return [ tab ] }.collect(), bsj_reads ) - DCC_MATE2_2ND_PASS( mate2, star_index, DCC_MATE2_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) + DCC_MATE2_2ND_PASS( mate2, star_index.collect(), DCC_MATE2_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) dcc_stage = DCC_2ND_PASS.out.junction.join( DCC_MATE1_2ND_PASS.out.junction, remainder: true ).join( DCC_MATE2_2ND_PASS.out.junction, remainder: true ) dcc = dcc_stage.map{ it -> def meta = it[0]; if( meta.single_end ){ return [ it[0], it[1], [], [] ] } else { return it } } From e6bd4d8e2f67b392f53ebef72a77ff6825ea012e Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 13:40:30 +0000 Subject: [PATCH 027/491] segemehl usr path collect --- subworkflows/local/circrna_discovery.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index c7612946..3dd50135 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -64,7 +64,7 @@ workflow CIRCRNA_DISCOVERY { // // SEGEMEHL WORKFLOW: // - SEGEMEHL_ALIGN( reads, fasta, segemehl_index ) + SEGEMEHL_ALIGN( reads, fasta, segemehl_index.collect() ) segemehl_filter = SEGEMEHL_ALIGN.out.results.map{ meta, results -> meta.tool = "segemehl"; return [ meta, results ] } SEGEMEHL_FILTER( segemehl_filter, bsj_reads ) From a46f123269b155ee53cd4c793aadc3b53969abf9 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 14:04:41 +0000 Subject: [PATCH 028/491] segemehl path file() --- workflows/circrna.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflows/circrna.nf b/workflows/circrna.nf index 4f5e7056..0adea651 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -132,7 +132,7 @@ workflow CIRCRNA { chromosomes = params.fasta && ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) ? PREPARE_GENOME.out.chromosomes : [] hisat2_index = params.fasta ? params.hisat2 && ( params.tool.contains('ciriquant') || params.module.contains('differential_expression') ) ? Channel.fromPath(params.hisat2).collect() : PREPARE_GENOME.out.hisat2 : [] star_index = params.fasta ? params.star ? Channel.fromPath(params.star): PREPARE_GENOME.out.star : [] - segemehl_index = params.fasta ? params.segemehl ? Channel.fromPath(params.segemehl) : PREPARE_GENOME.out.segemehl : [] + segemehl_index = params.fasta ? params.segemehl ? Channel.fromPath(file(params.segemehl)) : PREPARE_GENOME.out.segemehl : [] ch_versions = ch_versions.mix(PREPARE_GENOME.out.versions) // MODULE: Run FastQC, trimgalore! From 4d986aee7d53a4f7e8e0cb5b27b049884e0cf929 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 14:38:16 +0000 Subject: [PATCH 029/491] modules config fix for segemehl align --- conf/modules.config | 2 +- subworkflows/local/circrna_discovery.nf | 2 +- workflows/circrna.nf | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 75584759..b46f3b52 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -144,7 +144,7 @@ if (!params.skip_trimming) { // circRNA withName: SEGEMEHL_ALIGN { - ext.when = { params.fasta && !params.segemehl && params.tool.split(',').contains('segemehl') && params.module.split(',').contains('circrna_discovery') } + ext.when = { params.fasta && params.tool.split(',').contains('segemehl') && params.module.split(',').contains('circrna_discovery') } ext.args = [ "", "-b", "-S" diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 3dd50135..c7612946 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -64,7 +64,7 @@ workflow CIRCRNA_DISCOVERY { // // SEGEMEHL WORKFLOW: // - SEGEMEHL_ALIGN( reads, fasta, segemehl_index.collect() ) + SEGEMEHL_ALIGN( reads, fasta, segemehl_index ) segemehl_filter = SEGEMEHL_ALIGN.out.results.map{ meta, results -> meta.tool = "segemehl"; return [ meta, results ] } SEGEMEHL_FILTER( segemehl_filter, bsj_reads ) diff --git a/workflows/circrna.nf b/workflows/circrna.nf index 0adea651..4f5e7056 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -132,7 +132,7 @@ workflow CIRCRNA { chromosomes = params.fasta && ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) ? PREPARE_GENOME.out.chromosomes : [] hisat2_index = params.fasta ? params.hisat2 && ( params.tool.contains('ciriquant') || params.module.contains('differential_expression') ) ? Channel.fromPath(params.hisat2).collect() : PREPARE_GENOME.out.hisat2 : [] star_index = params.fasta ? params.star ? Channel.fromPath(params.star): PREPARE_GENOME.out.star : [] - segemehl_index = params.fasta ? params.segemehl ? Channel.fromPath(file(params.segemehl)) : PREPARE_GENOME.out.segemehl : [] + segemehl_index = params.fasta ? params.segemehl ? Channel.fromPath(params.segemehl) : PREPARE_GENOME.out.segemehl : [] ch_versions = ch_versions.mix(PREPARE_GENOME.out.versions) // MODULE: Run FastQC, trimgalore! From 5c494b69b03898b69bdd78d90dfb84dd2d60d2a8 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 15:53:47 +0000 Subject: [PATCH 030/491] DCC: ditch remainder, use groupTuple instead. --- conf/test.config | 2 +- nextflow_schema.json | 26 ++++++++++++------------- subworkflows/local/circrna_discovery.nf | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/conf/test.config b/conf/test.config index 10095fa6..aad536a2 100644 --- a/conf/test.config +++ b/conf/test.config @@ -28,7 +28,7 @@ params { phenotype = 'https://raw.githubusercontent.com/nf-core/test-datasets/circrna/phenotype.csv' skip_trimming = false module = 'circrna_discovery,mirna_prediction,differential_expression' - outdir = 'test_outdir/' + outdir = 'results/' bsj_reads = 2 species = 'cel' } diff --git a/nextflow_schema.json b/nextflow_schema.json index 5b61d7d8..f7b22160 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -188,7 +188,7 @@ "mimetype": "text/plain", "pattern": "^\\S+\\.fn?a(sta)?(\\.gz)?$", "description": "Path to FASTA genome file.", - "help_text": "Must be provided if --genome null", + "help_text": "If you use AWS iGenomes, this has already been set for you appropriately.\n\nThis parameter is *mandatory* if `--genome` is not specified.", "fa_icon": "fas fa-book" }, "gtf": { @@ -204,38 +204,38 @@ "mimetype": "text/plain", "help_text": "Typically this will be the `mature.fa` file from miRBase. Can be given either as a plain text `.fa` file or a compressed `.gz` file.", "fa_icon": "fas fa-wheelchair", - "default": "null" + "default": null }, "species": { "type": "string", "fa_icon": "fas fa-dog", "description": "String identifying species.", "help_text": "Check the igenomes.config file for species configured to work with nf-core/circrna", - "default": "null" + "default": null }, "bowtie": { "type": "string", "fa_icon": "fas fa-bold", - "description": "Path to Bowtie index files.", - "default": "null" + "description": "Path to Bowtie index files, surrounded by quotes. No glob pattern required.", + "default": null }, "bowtie2": { "type": "string", "fa_icon": "fas fa-bold", - "description": "Path to Bowtie2 index files.", - "default": "null" + "description": "Path to Bowtie2 index files, surrounded by quotes. No glob pattern required.", + "default": null }, "bwa": { "type": "string", "fa_icon": "fas fa-bold", - "description": "Path to BWA index directory.", - "default": "null" + "description": "Path to BWA index directory, surrounded by quotes. No glob pattern required.", + "default": null }, "hisat2": { "type": "string", - "description": "The title to use in the MultiQC report.", + "description": "Path to Hisat2 index directory, surrounded by quotes. No glob pattern required.", "default": null, - "fa_icon": "fab fa-redhat" + "fa_icon": "fab fa-bold" }, "hisat2_build_memory": { "type": "string", @@ -249,12 +249,12 @@ "type": "string", "default": "None", "fa_icon": "fab fa-stripe-s", - "description": "Path to Segemehl Index file" + "description": "Path to Segemehl Index **file**." }, "star": { "type": "string", "fa_icon": "far fa-star", - "description": "Path to STAR index directory." + "description": "Path to STAR index directory, surrounded by quotes. No glob pattern required." }, "igenomes_base": { "type": "string", diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index c7612946..6df5e63a 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -163,7 +163,7 @@ workflow CIRCRNA_DISCOVERY { DCC_MATE2_SJDB( DCC_MATE2_1ST_PASS.out.tab.map{ meta, tab -> return [ tab ] }.collect(), bsj_reads ) DCC_MATE2_2ND_PASS( mate2, star_index.collect(), DCC_MATE2_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) - dcc_stage = DCC_2ND_PASS.out.junction.join( DCC_MATE1_2ND_PASS.out.junction, remainder: true ).join( DCC_MATE2_2ND_PASS.out.junction, remainder: true ) + dcc_stage = DCC_2ND_PASS.out.junction.join( DCC_MATE1_2ND_PASS.out.junction).join( DCC_MATE2_2ND_PASS.out.junction ).groupTuple() dcc = dcc_stage.map{ it -> def meta = it[0]; if( meta.single_end ){ return [ it[0], it[1], [], [] ] } else { return it } } DCC( dcc, fasta, gtf ) DCC_FILTER( DCC.out.txt.map{ meta, txt -> meta.tool = "dcc"; return [ meta, txt ] }, bsj_reads ) From c9c5c00d6cf86aee9ba846392e6322bf4bec7e38 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 16:13:18 +0000 Subject: [PATCH 031/491] alias circexplorer2 modules avoid mapslice mixups --- subworkflows/local/circrna_discovery.nf | 30 ++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 6df5e63a..1cd897b1 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -9,10 +9,6 @@ include { FIND_CIRC_FILTER } from '../../modules/local/find_circ include { CIRIQUANT_YML } from '../../modules/local/ciriquant/yml/main' include { CIRIQUANT } from '../../modules/local/ciriquant/ciriquant/main' include { CIRIQUANT_FILTER } from '../../modules/local/ciriquant/filter/main' -include { CIRCEXPLORER2_REFERENCE } from '../../modules/local/circexplorer2/reference/main' -include { CIRCEXPLORER2_PARSE } from '../../modules/nf-core/circexplorer2/parse/main' -include { CIRCEXPLORER2_ANNOTATE } from '../../modules/nf-core/circexplorer2/annotate/main' -include { CIRCEXPLORER2_FILTER } from '../../modules/local/circexplorer2/filter/main' include { CIRCRNA_FINDER_FILTER } from '../../modules/local/circrna_finder/filter/main' include { SEGEMEHL_ALIGN } from '../../modules/nf-core/segemehl/align/main' include { SEGEMEHL_FILTER } from '../../modules/local/segemehl/filter/main' @@ -35,6 +31,10 @@ include { FASTA } from '../../modules/local/fasta/mai include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools/main' include { COUNTS_COMBINED } from '../../modules/local/count_matrix/combined/main' include { COUNTS_SINGLE } from '../../modules/local/count_matrix/single/main' +include { CIRCEXPLORER2_REFERENCE as CIRCEXPLORER2_REF } from '../../modules/local/circexplorer2/reference/main' +include { CIRCEXPLORER2_PARSE as CIRCEXPLORER2_PAR } from '../../modules/nf-core/circexplorer2/parse/main' +include { CIRCEXPLORER2_ANNOTATE as CIRCEXPLORER2_ANN } from '../../modules/nf-core/circexplorer2/annotate/main' +include { CIRCEXPLORER2_FILTER as CIRCEXPLORER2_FLT } from '../../modules/local/circexplorer2/filter/main' include { CIRCEXPLORER2_REFERENCE as MAPSPLICE_REFERENCE } from '../../modules/local/circexplorer2/reference/main' include { CIRCEXPLORER2_PARSE as MAPSPLICE_PARSE } from '../../modules/nf-core/circexplorer2/parse/main' include { CIRCEXPLORER2_ANNOTATE as MAPSPLICE_ANNOTATE } from '../../modules/nf-core/circexplorer2/annotate/main' @@ -92,16 +92,16 @@ workflow CIRCRNA_DISCOVERY { // CIRCEXPLORER2 WORKFLOW: // - CIRCEXPLORER2_REFERENCE( gtf ) - CIRCEXPLORER2_PARSE( STAR_2ND_PASS.out.junction ) - CIRCEXPLORER2_ANNOTATE( CIRCEXPLORER2_PARSE.out.junction, fasta, CIRCEXPLORER2_REFERENCE.out.txt ) - circexplorer2_filter = CIRCEXPLORER2_ANNOTATE.out.txt.map{ meta, txt -> meta.tool = "circexplorer2"; return [ meta, txt ] } - CIRCEXPLORER2_FILTER( circexplorer2_filter, bsj_reads ) + CIRCEXPLORER2_REF( gtf ) + CIRCEXPLORER2_PAR( STAR_2ND_PASS.out.junction ) + CIRCEXPLORER2_ANN( CIRCEXPLORER2_PAR.out.junction, fasta, CIRCEXPLORER2_REF.out.txt ) + circexplorer2_filter = CIRCEXPLORER2_ANN.out.txt.map{ meta, txt -> meta.tool = "circexplorer2"; return [ meta, txt ] } + CIRCEXPLORER2_FLT( circexplorer2_filter, bsj_reads ) - ch_versions = ch_versions.mix(CIRCEXPLORER2_REFERENCE.out.versions) - ch_versions = ch_versions.mix(CIRCEXPLORER2_PARSE.out.versions) - ch_versions = ch_versions.mix(CIRCEXPLORER2_ANNOTATE.out.versions) - ch_versions = ch_versions.mix(CIRCEXPLORER2_FILTER.out.versions) + ch_versions = ch_versions.mix(CIRCEXPLORER2_REF.out.versions) + ch_versions = ch_versions.mix(CIRCEXPLORER2_PAR.out.versions) + ch_versions = ch_versions.mix(CIRCEXPLORER2_ANN.out.versions) + ch_versions = ch_versions.mix(CIRCEXPLORER2_FLT.out.versions) // // CIRCRNA_FINDER WORKFLOW: @@ -199,7 +199,7 @@ workflow CIRCRNA_DISCOVERY { ch_biotypes = Channel.fromPath("${projectDir}/bin/unwanted_biotypes.txt") - circrna_filtered = CIRCEXPLORER2_FILTER.out.results.mix(SEGEMEHL_FILTER.out.results, + circrna_filtered = CIRCEXPLORER2_FLT.out.results.mix(SEGEMEHL_FILTER.out.results, CIRCRNA_FINDER_FILTER.out.results, FIND_CIRC_FILTER.out.results, CIRIQUANT_FILTER.out.results, @@ -222,7 +222,7 @@ workflow CIRCRNA_DISCOVERY { // COUNT MATRIX WORKFLOW: // - ch_matrix = CIRCEXPLORER2_FILTER.out.matrix.mix(SEGEMEHL_FILTER.out.matrix, + ch_matrix = CIRCEXPLORER2_FLT.out.matrix.mix(SEGEMEHL_FILTER.out.matrix, CIRCRNA_FINDER_FILTER.out.matrix, FIND_CIRC_FILTER.out.matrix, CIRIQUANT_FILTER.out.matrix, From ec3217c6c092927fb0e11bd3f7b802c0943c76b7 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 1 Feb 2023 16:29:16 +0000 Subject: [PATCH 032/491] apply to modules conf too! --- conf/modules.config | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index b46f3b52..f3b96c6d 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -219,7 +219,7 @@ if (!params.skip_trimming) { ] } - withName: CIRCEXPLORER2_REFERENCE { + withName: CIRCEXPLORER2_REF { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } ext.args = [ "", "-genePredExt", @@ -233,7 +233,7 @@ if (!params.skip_trimming) { ] } - withName: CIRCEXPLORER2_PARSE { + withName: CIRCEXPLORER2_PAR { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } publishDir = [ path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates" }, @@ -243,7 +243,7 @@ if (!params.skip_trimming) { ] } - withName: CIRCEXPLORER2_ANNOTATE { + withName: CIRCEXPLORER2_ANN { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } publishDir = [ path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates" }, @@ -253,7 +253,7 @@ if (!params.skip_trimming) { ] } - withName: CIRCEXPLORER2_FILTER { + withName: CIRCEXPLORER2_FLT { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } publishDir = [ path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates" }, From 2028b1596e09d84a3fdbc5e0fb480ac8f71a98df Mon Sep 17 00:00:00 2001 From: Barry digby Date: Tue, 7 Feb 2023 10:58:29 +0000 Subject: [PATCH 033/491] prettier --- CITATIONS.md | 2 +- docs/output.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CITATIONS.md b/CITATIONS.md index d0b737d9..7c7df82a 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -138,7 +138,7 @@ ## Test data References - > Cao D. An autoregulation loop in fust-1 for circular RNA regulation in Caenorhabditis elegans. Genetics. 2021 Nov 5;219(3):iyab145. doi: 10.1093/genetics/iyab145. PMID: 34740247; PMCID: PMC8570788. +> Cao D. An autoregulation loop in fust-1 for circular RNA regulation in Caenorhabditis elegans. Genetics. 2021 Nov 5;219(3):iyab145. doi: 10.1093/genetics/iyab145. PMID: 34740247; PMCID: PMC8570788. ## Software packaging/containerisation tools diff --git a/docs/output.md b/docs/output.md index 80185914..398f958e 100644 --- a/docs/output.md +++ b/docs/output.md @@ -313,6 +313,7 @@ Intermediate files generated by each quantification tool are described in depth - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). + - `circrna_discovery/STAR/2nd_Pass/${sample_id}/` - `*.Aligned.sortedByCoord.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). From 1edbfd6323d72dd6fcb654e550fb3bcfa8a79a50 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Tue, 7 Feb 2023 11:03:11 +0000 Subject: [PATCH 034/491] implement James ci.yml suggestion properly --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 181b2aea..9245777e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,4 +38,4 @@ jobs: - name: Run pipeline with test data run: | - nextflow run ${GITHUB_WORKSPACE} -profile ${{ matrix.profile }},docker --outdir ./results + nextflow run ${GITHUB_WORKSPACE} -profile test,docker --outdir ./results From 3ac54c5166644ae56a67cd781b92ea77954c71a1 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Tue, 7 Feb 2023 12:35:51 +0000 Subject: [PATCH 035/491] robust '--module' checks --- workflows/circrna.nf | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/workflows/circrna.nf b/workflows/circrna.nf index 4f5e7056..477badf3 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -9,6 +9,34 @@ def summary_params = NfcoreSchema.paramsSummaryMap(workflow, params) // Validate input parameters WorkflowCircrna.initialise(params, log) +// Check modules paramater +def checkParameterExistence(it, list) { + if (!list.contains(it)) { + log.warn "Unknown parameter: ${it}" + return false + } + return true +} + +def checkParameterList(list, realList) { + return list.every{ checkParameterExistence(it, realList) } +} + +def defineModuleList() { + return [ + 'circrna_discovery', + 'mirna_prediction', + 'differential_expression' + ] +} + +moduleList = defineModuleList() +module = params.module ? params.module.split(',').collect{it.trim().toLowerCase()} : [] +if(!checkParameterList(module, moduleList)) { + log.error "error: Unknown module selected, please choose one of the following:\n\n circrna_discovery\n\n mirna_prediction\n\n differential_expression\n\nPlease refer to the help documentation for a description of each module." + System.exit(1) +} + // Check input path parameters to see if they exist def checkPathParamList = [ params.input, params.multiqc_config ] for (param in checkPathParamList) { if (param) { file(param, checkIfExists: true) } } From e26c3c256baa0ea21764899e86207446fbaed67f Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 8 Feb 2023 09:21:27 +0000 Subject: [PATCH 036/491] BAM QC --- modules.json | 33 +++++++++- modules/nf-core/samtools/flagstat/main.nf | 35 ++++++++++ modules/nf-core/samtools/flagstat/meta.yml | 49 ++++++++++++++ modules/nf-core/samtools/idxstats/main.nf | 36 ++++++++++ modules/nf-core/samtools/idxstats/meta.yml | 50 ++++++++++++++ modules/nf-core/samtools/stats/main.nf | 49 ++++++++++++++ modules/nf-core/samtools/stats/meta.yml | 53 +++++++++++++++ subworkflows/local/differential_expression.nf | 15 ++++- .../nf-core/bam_sort_stats_samtools/main.nf | 50 ++++++++++++++ .../nf-core/bam_sort_stats_samtools/meta.yml | 65 +++++++++++++++++++ .../nf-core/bam_stats_samtools/main.nf | 32 +++++++++ .../nf-core/bam_stats_samtools/meta.yml | 54 +++++++++++++++ workflows/circrna.nf | 5 ++ 13 files changed, 521 insertions(+), 5 deletions(-) create mode 100644 modules/nf-core/samtools/flagstat/main.nf create mode 100644 modules/nf-core/samtools/flagstat/meta.yml create mode 100644 modules/nf-core/samtools/idxstats/main.nf create mode 100644 modules/nf-core/samtools/idxstats/meta.yml create mode 100644 modules/nf-core/samtools/stats/main.nf create mode 100644 modules/nf-core/samtools/stats/meta.yml create mode 100644 subworkflows/nf-core/bam_sort_stats_samtools/main.nf create mode 100644 subworkflows/nf-core/bam_sort_stats_samtools/meta.yml create mode 100644 subworkflows/nf-core/bam_stats_samtools/main.nf create mode 100644 subworkflows/nf-core/bam_stats_samtools/meta.yml diff --git a/modules.json b/modules.json index 5b501b5f..4471d3e7 100644 --- a/modules.json +++ b/modules.json @@ -80,15 +80,30 @@ "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, + "samtools/flagstat": { + "branch": "master", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", + "installed_by": ["bam_stats_samtools"] + }, + "samtools/idxstats": { + "branch": "master", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", + "installed_by": ["bam_stats_samtools"] + }, "samtools/index": { "branch": "master", "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", - "installed_by": ["modules"] + "installed_by": ["bam_sort_stats_samtools", "modules"] }, "samtools/sort": { "branch": "master", "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", - "installed_by": ["modules"] + "installed_by": ["bam_sort_stats_samtools", "modules"] + }, + "samtools/stats": { + "branch": "master", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", + "installed_by": ["bam_stats_samtools"] }, "samtools/view": { "branch": "master", @@ -126,6 +141,20 @@ "installed_by": ["modules"] } } + }, + "subworkflows": { + "nf-core": { + "bam_sort_stats_samtools": { + "branch": "master", + "git_sha": "3911652a6b24249358f79e8b8466338d63efb2a2", + "installed_by": ["subworkflows"] + }, + "bam_stats_samtools": { + "branch": "master", + "git_sha": "92eb5091ae5368a60cda58b3a0ced8b36d715b0f", + "installed_by": ["bam_sort_stats_samtools"] + } + } } } } diff --git a/modules/nf-core/samtools/flagstat/main.nf b/modules/nf-core/samtools/flagstat/main.nf new file mode 100644 index 00000000..2120cd7d --- /dev/null +++ b/modules/nf-core/samtools/flagstat/main.nf @@ -0,0 +1,35 @@ +process SAMTOOLS_FLAGSTAT { + tag "$meta.id" + label 'process_single' + + conda "bioconda::samtools=1.16.1" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/samtools:1.16.1--h6899075_1' : + 'quay.io/biocontainers/samtools:1.16.1--h6899075_1' }" + + input: + tuple val(meta), path(bam), path(bai) + + output: + tuple val(meta), path("*.flagstat"), emit: flagstat + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + samtools \\ + flagstat \\ + --threads ${task.cpus} \\ + $bam \\ + > ${prefix}.flagstat + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') + END_VERSIONS + """ +} diff --git a/modules/nf-core/samtools/flagstat/meta.yml b/modules/nf-core/samtools/flagstat/meta.yml new file mode 100644 index 00000000..95269063 --- /dev/null +++ b/modules/nf-core/samtools/flagstat/meta.yml @@ -0,0 +1,49 @@ +name: samtools_flagstat +description: Counts the number of alignments in a BAM/CRAM/SAM file for each FLAG type +keywords: + - stats + - mapping + - counts + - bam + - sam + - cram +tools: + - samtools: + description: | + SAMtools is a set of utilities for interacting with and post-processing + short DNA sequence read alignments in the SAM, BAM and CRAM formats, written by Heng Li. + These files are generated as output by short read aligners like BWA. + homepage: http://www.htslib.org/ + documentation: hhttp://www.htslib.org/doc/samtools.html + doi: 10.1093/bioinformatics/btp352 + licence: ["MIT"] +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - bam: + type: file + description: BAM/CRAM/SAM file + pattern: "*.{bam,cram,sam}" + - bai: + type: file + description: Index for BAM/CRAM/SAM file + pattern: "*.{bai,crai,sai}" +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - flagstat: + type: file + description: File containing samtools flagstat output + pattern: "*.{flagstat}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@drpatelh" diff --git a/modules/nf-core/samtools/idxstats/main.nf b/modules/nf-core/samtools/idxstats/main.nf new file mode 100644 index 00000000..a7b87d8b --- /dev/null +++ b/modules/nf-core/samtools/idxstats/main.nf @@ -0,0 +1,36 @@ +process SAMTOOLS_IDXSTATS { + tag "$meta.id" + label 'process_single' + + conda "bioconda::samtools=1.16.1" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/samtools:1.16.1--h6899075_1' : + 'quay.io/biocontainers/samtools:1.16.1--h6899075_1' }" + + input: + tuple val(meta), path(bam), path(bai) + + output: + tuple val(meta), path("*.idxstats"), emit: idxstats + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + samtools \\ + idxstats \\ + --threads ${task.cpus-1} \\ + $bam \\ + > ${prefix}.idxstats + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') + END_VERSIONS + """ +} diff --git a/modules/nf-core/samtools/idxstats/meta.yml b/modules/nf-core/samtools/idxstats/meta.yml new file mode 100644 index 00000000..3710ab88 --- /dev/null +++ b/modules/nf-core/samtools/idxstats/meta.yml @@ -0,0 +1,50 @@ +name: samtools_idxstats +description: Reports alignment summary statistics for a BAM/CRAM/SAM file +keywords: + - stats + - mapping + - counts + - chromosome + - bam + - sam + - cram +tools: + - samtools: + description: | + SAMtools is a set of utilities for interacting with and post-processing + short DNA sequence read alignments in the SAM, BAM and CRAM formats, written by Heng Li. + These files are generated as output by short read aligners like BWA. + homepage: http://www.htslib.org/ + documentation: hhttp://www.htslib.org/doc/samtools.html + doi: 10.1093/bioinformatics/btp352 + licence: ["MIT"] +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - bam: + type: file + description: BAM/CRAM/SAM file + pattern: "*.{bam,cram,sam}" + - bai: + type: file + description: Index for BAM/CRAM/SAM file + pattern: "*.{bai,crai,sai}" +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - idxstats: + type: file + description: File containing samtools idxstats output + pattern: "*.{idxstats}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@drpatelh" diff --git a/modules/nf-core/samtools/stats/main.nf b/modules/nf-core/samtools/stats/main.nf new file mode 100644 index 00000000..0a2a3640 --- /dev/null +++ b/modules/nf-core/samtools/stats/main.nf @@ -0,0 +1,49 @@ +process SAMTOOLS_STATS { + tag "$meta.id" + label 'process_single' + + conda "bioconda::samtools=1.16.1" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/samtools:1.16.1--h6899075_1' : + 'quay.io/biocontainers/samtools:1.16.1--h6899075_1' }" + + input: + tuple val(meta), path(input), path(input_index) + path fasta + + output: + tuple val(meta), path("*.stats"), emit: stats + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def reference = fasta ? "--reference ${fasta}" : "" + """ + samtools \\ + stats \\ + --threads ${task.cpus} \\ + ${reference} \\ + ${input} \\ + > ${prefix}.stats + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') + END_VERSIONS + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.stats + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') + END_VERSIONS + """ +} diff --git a/modules/nf-core/samtools/stats/meta.yml b/modules/nf-core/samtools/stats/meta.yml new file mode 100644 index 00000000..cac50b1c --- /dev/null +++ b/modules/nf-core/samtools/stats/meta.yml @@ -0,0 +1,53 @@ +name: samtools_stats +description: Produces comprehensive statistics from SAM/BAM/CRAM file +keywords: + - statistics + - counts + - bam + - sam + - cram +tools: + - samtools: + description: | + SAMtools is a set of utilities for interacting with and post-processing + short DNA sequence read alignments in the SAM, BAM and CRAM formats, written by Heng Li. + These files are generated as output by short read aligners like BWA. + homepage: http://www.htslib.org/ + documentation: hhttp://www.htslib.org/doc/samtools.html + doi: 10.1093/bioinformatics/btp352 + licence: ["MIT"] +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}" + - input_index: + type: file + description: BAI/CRAI file from alignment + pattern: "*.{bai,crai}" + - fasta: + type: optional file + description: Reference file the CRAM was created with + pattern: "*.{fasta,fa}" +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - stats: + type: file + description: File containing samtools stats output + pattern: "*.{stats}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@drpatelh" + - "@FriederikeHanssen" diff --git a/subworkflows/local/differential_expression.nf b/subworkflows/local/differential_expression.nf index 8bf83bda..82107038 100644 --- a/subworkflows/local/differential_expression.nf +++ b/subworkflows/local/differential_expression.nf @@ -6,6 +6,7 @@ include { PARENT_GENE } from '../../modules/local/annotation/paren include { PREPARE_CLR_TEST } from '../../modules/local/circtest/prepare/main' include { CIRCTEST } from '../../modules/local/circtest/test/main' include { DESEQ2_DIFFERENTIAL_EXPRESSION } from '../../modules/local/deseq2/differential_expression/main' +include { BAM_SORT_STATS_SAMTOOLS } from '../nf-core/bam_sort_stats_samtools/main' workflow DIFFERENTIAL_EXPRESSION { @@ -24,16 +25,23 @@ workflow DIFFERENTIAL_EXPRESSION { main: ch_versions = Channel.empty() + qc_reports = Channel.empty() // // LINEAR RNA ALIGNEMT WORKFLOW: // HISAT2_ALIGN( reads, hisat2_index, splice_sites ) - SAMTOOLS_SORT( HISAT2_ALIGN.out.bam ) - STRINGTIE_STRINGTIE( SAMTOOLS_SORT.out.bam, gtf ) + BAM_SORT_STATS_SAMTOOLS( HISAT2_ALIGN.out.bam, fasta ) + STRINGTIE_STRINGTIE( BAM_SORT_STATS_SAMTOOLS.out.bam, gtf ) STRINGTIE_PREPDE( STRINGTIE_STRINGTIE.out.transcript_gtf.map{ meta, gtf -> return [ gtf ] }.collect() ) + qc_reports = qc_reports.mix(HISAT2_ALIGN.out.summary.map{ meta, log -> log}) + qc_reports = qc_reports.mix(BAM_SORT_STATS_SAMTOOLS.out.stats.map{ meta, stats -> stats}) + qc_reports = qc_reports.mix(BAM_SORT_STATS_SAMTOOLS.out.flagstat.map{ meta, flagstat -> flagstat}) + qc_reports = qc_reports.mix(BAM_SORT_STATS_SAMTOOLS.out.idxstats.map{ meta, idxstats -> idxstats}) + + // // Circular, Linear Differential Expression // @@ -51,7 +59,7 @@ workflow DIFFERENTIAL_EXPRESSION { CIRCTEST( PREPARE_CLR_TEST.out.circular, PREPARE_CLR_TEST.out.linear, phenotype ) ch_versions = ch_versions.mix(HISAT2_ALIGN.out.versions) - ch_versions = ch_versions.mix(SAMTOOLS_SORT.out.versions) + ch_versions = ch_versions.mix(BAM_SORT_STATS_SAMTOOLS.out.versions) ch_versions = ch_versions.mix(STRINGTIE_STRINGTIE.out.versions) ch_versions = ch_versions.mix(STRINGTIE_PREPDE.out.versions) ch_versions = ch_versions.mix(DESEQ2_DIFFERENTIAL_EXPRESSION.out.versions) @@ -61,4 +69,5 @@ workflow DIFFERENTIAL_EXPRESSION { emit: versions = ch_versions + reports = qc_reports } diff --git a/subworkflows/nf-core/bam_sort_stats_samtools/main.nf b/subworkflows/nf-core/bam_sort_stats_samtools/main.nf new file mode 100644 index 00000000..617871fe --- /dev/null +++ b/subworkflows/nf-core/bam_sort_stats_samtools/main.nf @@ -0,0 +1,50 @@ +// +// Sort, index BAM file and run samtools stats, flagstat and idxstats +// + +include { SAMTOOLS_SORT } from '../../../modules/nf-core/samtools/sort/main' +include { SAMTOOLS_INDEX } from '../../../modules/nf-core/samtools/index/main' +include { BAM_STATS_SAMTOOLS } from '../bam_stats_samtools/main' + +workflow BAM_SORT_STATS_SAMTOOLS { + take: + ch_bam // channel: [ val(meta), [ bam ] ] + ch_fasta // channel: [ fasta ] + + main: + + ch_versions = Channel.empty() + + SAMTOOLS_SORT ( ch_bam ) + ch_versions = ch_versions.mix(SAMTOOLS_SORT.out.versions.first()) + + SAMTOOLS_INDEX ( SAMTOOLS_SORT.out.bam ) + ch_versions = ch_versions.mix(SAMTOOLS_INDEX.out.versions.first()) + + SAMTOOLS_SORT.out.bam + .join(SAMTOOLS_INDEX.out.bai, by: [0], remainder: true) + .join(SAMTOOLS_INDEX.out.csi, by: [0], remainder: true) + .map { + meta, bam, bai, csi -> + if (bai) { + [ meta, bam, bai ] + } else { + [ meta, bam, csi ] + } + } + .set { ch_bam_bai } + + BAM_STATS_SAMTOOLS ( ch_bam_bai, ch_fasta ) + ch_versions = ch_versions.mix(BAM_STATS_SAMTOOLS.out.versions) + + emit: + bam = SAMTOOLS_SORT.out.bam // channel: [ val(meta), [ bam ] ] + bai = SAMTOOLS_INDEX.out.bai // channel: [ val(meta), [ bai ] ] + csi = SAMTOOLS_INDEX.out.csi // channel: [ val(meta), [ csi ] ] + + stats = BAM_STATS_SAMTOOLS.out.stats // channel: [ val(meta), [ stats ] ] + flagstat = BAM_STATS_SAMTOOLS.out.flagstat // channel: [ val(meta), [ flagstat ] ] + idxstats = BAM_STATS_SAMTOOLS.out.idxstats // channel: [ val(meta), [ idxstats ] ] + + versions = ch_versions // channel: [ versions.yml ] +} diff --git a/subworkflows/nf-core/bam_sort_stats_samtools/meta.yml b/subworkflows/nf-core/bam_sort_stats_samtools/meta.yml new file mode 100644 index 00000000..131065be --- /dev/null +++ b/subworkflows/nf-core/bam_sort_stats_samtools/meta.yml @@ -0,0 +1,65 @@ +name: bam_sort_stats_samtools +description: Sort SAM/BAM/CRAM file +keywords: + - sort + - bam + - sam + - cram +modules: + - samtools/sort + - samtools/index + - samtools/stats + - samtools/idxstats + - samtools/flagstat +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - bam: + type: file + description: BAM/CRAM/SAM file + pattern: "*.{bam,cram,sam}" + - fasta: + type: file + description: Reference genome fasta file + pattern: "*.{fasta,fa}" +# TODO Update when we decide on a standard for subworkflow docs +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - bam: + type: file + description: Sorted BAM/CRAM/SAM file + pattern: "*.{bam,cram,sam}" + - bai: + type: file + description: BAM/CRAM/SAM index file + pattern: "*.{bai,crai,sai}" + - crai: + type: file + description: BAM/CRAM/SAM index file + pattern: "*.{bai,crai,sai}" + - stats: + type: file + description: File containing samtools stats output + pattern: "*.{stats}" + - flagstat: + type: file + description: File containing samtools flagstat output + pattern: "*.{flagstat}" + - idxstats: + type: file + description: File containing samtools idxstats output + pattern: "*.{idxstats}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@drpatelh" + - "@ewels" diff --git a/subworkflows/nf-core/bam_stats_samtools/main.nf b/subworkflows/nf-core/bam_stats_samtools/main.nf new file mode 100644 index 00000000..cfcc48dd --- /dev/null +++ b/subworkflows/nf-core/bam_stats_samtools/main.nf @@ -0,0 +1,32 @@ +// +// Run SAMtools stats, flagstat and idxstats +// + +include { SAMTOOLS_STATS } from '../../../modules/nf-core/samtools/stats/main' +include { SAMTOOLS_IDXSTATS } from '../../../modules/nf-core/samtools/idxstats/main' +include { SAMTOOLS_FLAGSTAT } from '../../../modules/nf-core/samtools/flagstat/main' + +workflow BAM_STATS_SAMTOOLS { + take: + bam_bai // channel: [ val(meta), [ bam/cram ], [bai/csi] ] + fasta // channel: [ fasta ] + + main: + ch_versions = Channel.empty() + + SAMTOOLS_STATS ( bam_bai, fasta ) + ch_versions = ch_versions.mix(SAMTOOLS_STATS.out.versions) + + SAMTOOLS_FLAGSTAT ( bam_bai ) + ch_versions = ch_versions.mix(SAMTOOLS_FLAGSTAT.out.versions) + + SAMTOOLS_IDXSTATS ( bam_bai ) + ch_versions = ch_versions.mix(SAMTOOLS_IDXSTATS.out.versions) + + emit: + stats = SAMTOOLS_STATS.out.stats // channel: [ val(meta), [ stats ] ] + flagstat = SAMTOOLS_FLAGSTAT.out.flagstat // channel: [ val(meta), [ flagstat ] ] + idxstats = SAMTOOLS_IDXSTATS.out.idxstats // channel: [ val(meta), [ idxstats ] ] + + versions = ch_versions // channel: [ versions.yml ] +} diff --git a/subworkflows/nf-core/bam_stats_samtools/meta.yml b/subworkflows/nf-core/bam_stats_samtools/meta.yml new file mode 100644 index 00000000..5252b0e4 --- /dev/null +++ b/subworkflows/nf-core/bam_stats_samtools/meta.yml @@ -0,0 +1,54 @@ +name: bam_stats_samtools +description: Produces comprehensive statistics from SAM/BAM/CRAM file +keywords: + - statistics + - counts + - bam + - sam + - cram +modules: + - samtools/stats + - samtools/idxstats + - samtools/flagstat +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - bam: + type: file + description: BAM/CRAM/SAM file + pattern: "*.{bam,cram,sam}" + - bai: + type: file + description: Index for BAM/CRAM/SAM file + pattern: "*.{bai,crai,sai}" + - fasta: + type: file + description: Reference genome fasta file + pattern: "*.{fasta,fa}" +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - stats: + type: file + description: File containing samtools stats output + pattern: "*.{stats}" + - flagstat: + type: file + description: File containing samtools flagstat output + pattern: "*.{flagstat}" + - idxstats: + type: file + description: File containing samtools idxstats output + pattern: "*.{idxstats}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@drpatelh" diff --git a/workflows/circrna.nf b/workflows/circrna.nf index 477badf3..0101bc67 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -108,6 +108,7 @@ def multiqc_report = [] workflow CIRCRNA { + ch_reports = Channel.empty() ch_versions = Channel.empty() // @@ -170,6 +171,8 @@ workflow CIRCRNA { params.skip_trimming ) ch_versions = ch_versions.mix(FASTQC_TRIMGALORE.out.versions) + ch_reports = ch_reports.mix(FASTQC_TRIMGALORE.out.trim_zip.collect{it[1]}.ifEmpty([])) + ch_reports = ch_reports.mix(FASTQC_TRIMGALORE.out.trim_log.collect{it[1]}.ifEmpty([])) reads_for_circrna = FASTQC_TRIMGALORE.out.reads reads_for_diff_exp = FASTQC_TRIMGALORE.out.reads @@ -229,6 +232,7 @@ workflow CIRCRNA { ) ch_versions = ch_versions.mix(DIFFERENTIAL_EXPRESSION.out.versions) + ch_reports = ch_reports.mix(DIFFERENTIAL_EXPRESSION.out.reports) CUSTOM_DUMPSOFTWAREVERSIONS ( ch_versions.unique().collectFile(name: 'collated_versions.yml') @@ -246,6 +250,7 @@ workflow CIRCRNA { ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml')) ch_multiqc_files = ch_multiqc_files.mix(CUSTOM_DUMPSOFTWAREVERSIONS.out.mqc_yml.collect()) ch_multiqc_files = ch_multiqc_files.mix(FASTQC_TRIMGALORE.out.fastqc_zip.collect{it[1]}.ifEmpty([])) + ch_multiqc_files = ch_multiqc_files.mix(ch_reports.collect().ifEmpty([])) MULTIQC ( ch_multiqc_files.collect(), From 1caf535541067c4bc6f2845d22530f594fd66dc9 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Wed, 8 Feb 2023 09:39:17 +0000 Subject: [PATCH 037/491] black, 23.1.0 --- bin/check_samplesheet.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/check_samplesheet.py b/bin/check_samplesheet.py index 339900f2..0a5041b0 100755 --- a/bin/check_samplesheet.py +++ b/bin/check_samplesheet.py @@ -55,7 +55,6 @@ def check_samplesheet(file_in, file_out): sample_mapping_dict = {} with open(file_in, "r", encoding="utf-8-sig") as fin: - ## Check header MIN_COLS = 2 ## edit by BDigby as not using strandedness yet. HEADER = ["sample", "fastq_1", "fastq_2"] @@ -130,7 +129,6 @@ def check_samplesheet(file_in, file_out): with open(file_out, "w") as fout: fout.write(",".join(["sample", "single_end", "fastq_1", "fastq_2"]) + "\n") for sample in sorted(sample_mapping_dict.keys()): - ## Check that multiple runs of the same sample are of the same datatype i.e. single-end / paired-end if not all(x[0] == sample_mapping_dict[sample][0][0] for x in sample_mapping_dict[sample]): print_error( From 0bc397f07231c4233cb732a394e228bbe52636a6 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Thu, 9 Feb 2023 15:19:15 +0000 Subject: [PATCH 038/491] tidy circrna outdirs + corresponding output.md doc --- conf/modules.config | 46 +++--- docs/output.md | 154 +++++++++++--------- modules/local/circrna_finder/filter/main.nf | 1 + 3 files changed, 109 insertions(+), 92 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index f3b96c6d..e90eb069 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -47,18 +47,18 @@ if (!params.skip_trimming) { } publishDir = [ [ - path: { "${params.outdir}/trimgalore/fastqc" }, + path: { "${params.outdir}/quality_control/trimgalore/fastqc" }, mode: params.publish_dir_mode, pattern: "*.{html,zip}" ], [ - path: { "${params.outdir}/trimgalore" }, + path: { "${params.outdir}/quality_control/trimgalore" }, mode: params.publish_dir_mode, pattern: "*.fq.gz", enabled: params.save_trimmed ], [ - path: { "${params.outdir}/trimgalore" }, + path: { "${params.outdir}/quality_control/trimgalore" }, mode: params.publish_dir_mode, pattern: "*.txt" ] @@ -150,7 +150,7 @@ if (!params.skip_trimming) { "-S" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/segemehl/intermediates" }, + path: { "${params.outdir}/circrna_discovery/segemehl/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates @@ -160,7 +160,7 @@ if (!params.skip_trimming) { withName: SEGEMEHL_FILTER { ext.when = { params.tool.split(',').contains('segemehl') && params.module.split(',').contains('circrna_discovery') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/segemehl/intermediates" }, + path: { "${params.outdir}/circrna_discovery/segemehl/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates, @@ -236,7 +236,7 @@ if (!params.skip_trimming) { withName: CIRCEXPLORER2_PAR { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates" }, + path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates @@ -246,7 +246,7 @@ if (!params.skip_trimming) { withName: CIRCEXPLORER2_ANN { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates" }, + path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates @@ -256,7 +256,7 @@ if (!params.skip_trimming) { withName: CIRCEXPLORER2_FLT { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates" }, + path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates, @@ -267,7 +267,7 @@ if (!params.skip_trimming) { withName: CIRCRNA_FINDER_FILTER { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circrna_finder') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/circrna_finder/intermediates" }, + path: { "${params.outdir}/circrna_discovery/circrna_finder/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates, @@ -285,7 +285,7 @@ if (!params.skip_trimming) { "-q" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/find_circ/intermediates" }, + path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates @@ -297,7 +297,7 @@ if (!params.skip_trimming) { ext.prefix = { "${meta.id}_unmapped" } ext.args = "-hf 4" publishDir = [ - path: { "${params.outdir}/circrna_discovery/find_circ/intermediates" }, + path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates @@ -307,7 +307,7 @@ if (!params.skip_trimming) { withName: FIND_CIRC_ANCHORS { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('find_circ') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/find_circ/intermediates" }, + path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates @@ -317,7 +317,7 @@ if (!params.skip_trimming) { withName: FIND_CIRC { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('find_circ') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/find_circ/intermediates" }, + path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates @@ -327,7 +327,7 @@ if (!params.skip_trimming) { withName: FIND_CIRC_FILTER { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('find_circ') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/find_circ/intermediates" }, + path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates, @@ -348,7 +348,7 @@ if (!params.skip_trimming) { withName: CIRIQUANT { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('ciriquant') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/ciriquant/intermediates" }, + path: { "${params.outdir}/circrna_discovery/ciriquant/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates @@ -358,7 +358,7 @@ if (!params.skip_trimming) { withName: CIRIQUANT_FILTER { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('ciriquant') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/ciriquant/intermediates" }, + path: { "${params.outdir}/circrna_discovery/ciriquant/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates, @@ -526,7 +526,7 @@ if (!params.skip_trimming) { withName: DCC { ext.when = { params.tool.split(',').contains('dcc') && params.module.split(',').contains('circrna_discovery') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/dcc/intermediates/" }, + path: { "${params.outdir}/circrna_discovery/dcc/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates @@ -558,7 +558,7 @@ if (!params.skip_trimming) { "--fusion-non-canonical" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates" }, + path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates @@ -568,7 +568,7 @@ if (!params.skip_trimming) { withName: MAPSPLICE_PARSE { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates" }, + path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates @@ -578,7 +578,7 @@ if (!params.skip_trimming) { withName: MAPSPLICE_ANNOTATE { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates" }, + path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates @@ -588,7 +588,7 @@ if (!params.skip_trimming) { withName: MAPSPLICE_FILTER { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates" }, + path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates, @@ -598,7 +598,7 @@ if (!params.skip_trimming) { withName: ANNOTATION { publishDir = [ - path: { "${params.outdir}/circrna_discovery/${meta.tool}" }, + path: { "${params.outdir}/circrna_discovery/${meta.tool}/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -607,7 +607,7 @@ if (!params.skip_trimming) { withName: FASTA { ext.when = { params.module.split(',').contains('circrna_discovery') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/${meta.tool}" }, + path: { "${params.outdir}/circrna_discovery/${meta.tool}/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.fasta" diff --git a/docs/output.md b/docs/output.md index 398f958e..0264fb06 100644 --- a/docs/output.md +++ b/docs/output.md @@ -11,9 +11,10 @@ A full run of the workflow will produce the following directory output structure |-- circrna_discovery |-- differential_expression |-- mirna_prediction + |-- multiqc |-- pipeline_info |-- quality_control - |-- reference_genome + |-- references ``` ## Pipeline Overview @@ -166,12 +167,45 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d ## Common Outputs -The workflow is designed to output three files per quantification tool selected in the `circrna_discovery` directory. By design, the workflow standardises the outputs of each quantification tool. +The workflow is designed to output three files _per sample_, _per quantification tool_ in the `circrna_discovery` directory. Using the test dataset as an example, the directory structure for the `fust_1` sample is: -- `quantification_tool/`: - - `${sample_id}.bed`: A customised BED 12 file containing filtered, annotated circRNAs. Columns: chromosome, start, end, name, read counts, strand, start, end, RGB, number of exon blocks, size of exon blocks, start positions (within sequence) of exon blocks, parent gene ID(s), parent transcript ID(s), mature spliced length. - - `${sample_id}.log`: Script detailing the decisions made by `annotate_outputs.sh` when annotating each circRNA. - - `${sample_id}.fasta`: Mature spliced sequence of circRNA in FASTA format. Includes splice junction site (+-20bp). +```console +|-- results/ + |-- circrna_discovery/ + |-- circexplorer2/ + | -- fust_1/ + | -- fust_1.bed + | -- fust_1.fasta + | -- fust_1.log + + +- `${sample_id}.bed`: A customised BED 12 file containing filtered, annotated circRNAs. Columns: chromosome, start, end, name, read counts, strand, start, end, RGB, number of exon blocks, size of exon blocks, start positions (within sequence) of exon blocks, parent gene ID(s), parent transcript ID(s), mature spliced length. +- `${sample_id}.log`: Script detailing the decisions made by `annotate_outputs.sh` when annotating each circRNA. +- `${sample_id}.fasta`: Mature spliced sequence of circRNA in FASTA format. Includes splice junction site (+-20bp). + +Sample outputs for the corresponding `.log`, `.bed` and `.fasta` entry are given below for a circRNA called by `CIRCexplorer2`: + +```console +[nf-core/circrna]: Starting analysis for: chrI:1140805-1147588:- +[nf-core/circrna]: chrI:1140805-1147588:- overlaps features in GTF file +[nf-core/circrna]: Inspecting Genes... +[nf-core/circrna]: Overlapping Gene IDs: Y48G8AL.10 +[nf-core/circrna]: Converting to BED12 +[nf-core/circrna]: Attempting to fit circRNA to gene exon boundaries +[nf-core/circrna]: chrI:1140805-1147588:- fits gene exons, is a circRNA +[nf-core/circrna]: cleaning up intermediate files +``` + +```console +chrI 1140805 1147588 chrI:1140805-1147588:- 2 - 1140805 1147588 0 5 229,214,191,141,499 0,1282,2546,4912,6284 circRNA Y48G8AL.10 NM_001306296,NM_001306297,NM_001306298,NM_001306299 1274 +``` + +```console +>chrI:1087252-1088602:- +CATGAAGTCTCGAGATCTCGTTTATAAGCACCAATATCCACGTTCAGCATTATTGATTGataaaattaatttataaattcgaaaataaaatttaaatttttCTTTAGAAATTATCGATTTATCGACTTCCACGTAATTCCACACCACGCTAAAATTCCATATCAATCTCGCGTTGTTTGGCTTCTCGTTGGGTGTCCGCCGCGTGGGAGTAGTATCTGCAAAAAAAAATTTGAGAATAAAAAATGTAAAATTGtttttcctattttctattgccgaaatttgagatttccggcaaatcggcaaattgccggaattgaaatttgcggcaaatcggcaaactgccgcaattgaaatttcgggtaaatcggcaaatttccggcaaatcggcatattgccggaatttaaatttccggcaaggcggccaatcggaaaattggcaaattgccgcaattgaaatttgcggcaaatcggcaattgtcgactattttcgacaacttctcgctttgcacttttttgtacatttcagattttttttcaatttcaatcggcaaaaacatttccggcaaatcggtaaattgccagaattgaaatttccggcaaatcggcaaattgccggaattgaaatttcccgcaaatcggcaaatttctttaattgaaatttccggcaaatcggtaaattgccggaatttaaatttccggcaactcggcaaactgccccaattgaaatttccggtaaatcggtaaaatgccgaaatttaaatttccggcaaggtggcaaatcggaaaattggcaaattgccggaattcaaatatccggcaaatcggcaagttgctggaattgaaatttccggcaaggcggcaaatttccggcaaatcggcaattGTCTTATattttcgacaacttctcgttttgcacttttttttgtacatttcaggttttttttcaatttcaatcggcaaaaacatttccggcaaatctgatatccggcaaacggcaaatcggcaatttgccgaaaataaaaaattcaagcaactcggcaaaccggcaaattTTATAGAGCACATTTGACCCACCTATTGAGAATAAACAATTGCGAGATAAAAATCTTGATGTAAATTCCGGCGAATGCGATCAAAATTGCTTTTCGATCTGAAAAAAATCCAATTTTGCTCAGCCAATAAATGGACGGAGCTAAAAACAAGGCGCTACTCACGAGAAATCCACTCATACGGGTCTTCTGTCACATTTTCCTGCTCGGATTTCGATTTTGGCGTATCTTCGGTCGGATTTCCGTGGTAATCGGACAACCAGGCAATCACTACAATTATTGCGCAAATGAATCGGGCAAC +``` + +The workflow's manual annotation process is designed to mimick annotation performed by `CIRCexplorer2` to standardise the annotation process for all circRNA quantification tools. Intermediate files generated by each quantification tool are described in depth below. @@ -180,10 +214,29 @@ Intermediate files generated by each quantification tool are described in depth
Output files -- `circrna_discovery/CIRCexplorer2/intermediates/${sample_id}/` - - `*.STAR.junction.bed`: Intermediate file generated by `CIRCexplorer2 parse` module, identifying STAR fusion junctions for downstream annotation. +- `circrna_discovery/circexplorer2/intermediates/${sample_id}/` + - `*.bed`: Intermediate file generated by `CIRCexplorer2 parse` module, identifying STAR fusion junctions for downstream annotation. + - `*_circexplorer2_circs.bed`: Filtered BED6 file containing circRNA counts used for count matrix generation. - `*.txt`: Output files generated by `CIRCexplorer2 annotate` module, based on BED 12 format containing circRNA genomic location information, exon cassette composition and an additional 6 columns specifying circRNA annotations. Full descriptions of the 18 columns can be found in the `CIRCexplorer2` [documentation](https://circexplorer2.readthedocs.io/en/latest/modules/annotate/#output). +- `circrna_discovery/star` + - `1st_pass` + - `*.Aligned.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. + - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). + - `*.Log.final.out`: Summary mapping statistics after mapping job is complete, useful for quality control. The statistics are calculated for each read (single- or paired-end) and then summed or averaged over all reads. + - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. + - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. + - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). + - `2nd_pass` + - `*.Aligned.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. + - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). + - `*.Log.final.out`: Summary mapping statistics after mapping job is complete, useful for quality control. The statistics are calculated for each read (single- or paired-end) and then summed or averaged over all reads. + - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. + - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. + - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). + - `sjdb` + - `dataset.SJ.out.tab`: Chromosome, start, end & strand coordinates of novel splice junctions for **all samples** aligned using STAR 1st pass. +
[CIRCexplorer2](https://circexplorer2.readthedocs.io/en/latest/) uses `*.Chimeric.out.junction` files generated from `STAR` 2 pass mode to extract back-splice junction sites using the `CIRCexplorer2 parse` module. Following this, `CIRCexplorer2 annotate` performs re-alignment of reads to the back-splice junction sites to determine the precise positions of downstream donor and upstream acceptor splice sites. Back-splice junction sites are subsequently updated and annotated using the customised annotation text file. @@ -193,29 +246,40 @@ Intermediate files generated by each quantification tool are described in depth
Output files -- `circrna_discovery/circRNA_Finder/intermediates/${sample_id}/` - - `*.Aligned.sortedByCoord.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. - - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). - - `*.Chimeric.out.sam`: Chimeric alignments in SAM format. - - `*.Log.final.out`: Summary mapping statistics after mapping job is complete, useful for quality control. The statistics are calculated for each read (single- or paired-end) and then summed or averaged over all reads. - - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. - - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. - - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). - - `*.Chimeric.out.sorted.{bam,bam.bai}`: (Sorted and indexed) bam file with all chimeric reads identified by STAR. The circRNA junction spanning reads are a subset of these. +- `circrna_discovery/circrna_finder/intermediates/${sample_id}/` - `*.filteredJunctions.bed`: A bed file with **all** circular junctions found by the pipeline. The score column indicates the number reads spanning each junction. - `*.s_filteredJunctions.bed`: A bed file with those junctions in `*.filteredJunctions.bed` that are flanked by GT-AG splice sites. The score column indicates the number reads spanning each junction. - `*.s_filteredJunctions_fw.bed`: A bed file with the same circular junctions as in file (b), but here the score column gives the average number of forward spliced reads at both splice sites around each circular junction. +- `circrna_discovery/star` + - `1st_pass` + - `*.Aligned.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. + - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). + - `*.Log.final.out`: Summary mapping statistics after mapping job is complete, useful for quality control. The statistics are calculated for each read (single- or paired-end) and then summed or averaged over all reads. + - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. + - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. + - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). + - `2nd_pass` + - `*.Aligned.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. + - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). + - `*.Chimeric.out.sam`: Chimeric alignments in SAM format. + - `*.Log.final.out`: Summary mapping statistics after mapping job is complete, useful for quality control. The statistics are calculated for each read (single- or paired-end) and then summed or averaged over all reads. + - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. + - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. + - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). + - `sjdb` + - `dataset.SJ.out.tab`: Chromosome, start, end & strand coordinates of novel splice junctions for **all samples** aligned using STAR 1st pass. +
-[circRNA finder](https://github.com/orzechoj/circRNA_finder) uses `*.Chimeric.out.sam`, `*.Chimeric.out.junction` & `*.SJ.out.tab` files to identify circular RNAs in RNA-Seq data. +[circRNA finder](https://github.com/orzechoj/circRNA_finder) uses `*.Chimeric.out.sam`, `*.Chimeric.out.junction` & `*.SJ.out.tab` from STAR 2nd pass files to identify circular RNAs in RNA-Seq data. ### CIRIquant
Output files -- `circrna_discovery/CIRIquant/intermediates/${sample_id}/` +- `circrna_discovery/ciriquant/intermediates/${sample_id}/` - `*.log`: A `CIRIerror.log` file which should be empty, and a `${sample_id}.log` file which contains the output log of `CIRIquant`. - `*.bed`: `CIRI2` output file in BED 6 format. - `*.gtf`: Output file from `CIRIquant` in GTF format. Full description of the columns available in the `CIRIquant` [documentation](https://ciriquant-cookbook.readthedocs.io/en/latest/quantification.html#output-format). @@ -282,7 +346,7 @@ Intermediate files generated by each quantification tool are described in depth
Output files -- `circrna_discovery/MapSplice/intermediates/${sample_id}/` +- `circrna_discovery/mapsplice/intermediates/${sample_id}/` - `alignments.bam`: Bam file containing aligned reads and fusion alignments. - `deletions.txt`: Report of deletions. - `Fusion output files`: @@ -299,46 +363,13 @@ Intermediate files generated by each quantification tool are described in depth [MapSplice](http://www.netlab.uky.edu/p/bioinfo/MapSplice2) first splits reads into segments, and maps them to reference genome by using `Bowtie`. `MapSplice` attempts to fix unmapped segments as gapped alignments, with each gap corresponding to a splice junction. Finally a remapping step is used to identify back-spliced alignments that are in the presence of small exons. -### STAR - -
-Output files - -- `circrna_discovery/STAR/1st_Pass/${sample_id}/` - - - `*.Aligned.sortedByCoord.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. - - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). - - `*.Chimeric.out.sam`: Chimeric alignments in SAM format. - - `*.Log.final.out`: Summary mapping statistics after mapping job is complete, useful for quality control. The statistics are calculated for each read (single- or paired-end) and then summed or averaged over all reads. - - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. - - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. - - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). - -- `circrna_discovery/STAR/2nd_Pass/${sample_id}/` - - `*.Aligned.sortedByCoord.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. - - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). - - `*.Chimeric.out.sam`: Chimeric alignments in SAM format. - - `*.Log.final.out`: Summary mapping statistics after mapping job is complete, useful for quality control. The statistics are calculated for each read (single- or paired-end) and then summed or averaged over all reads. - - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. - - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. - - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). -- `circrna_discovery/STAR/SJFile/` - - `*.SJFile.tab`: Chromosome, start, end & strand coordinates of novel splice junctions. - -
- -[STAR](https://github.com/alexdobin/STAR) can characterise novel splice junctions in RNA-Seq data by specifying `--ChimOutType Junctions`, with reported novel junctions written to a `*SJ.out.tab` file (per sample). Following the initial `STAR` alignment, a 2nd pass strategy is employed whereby **all** `*SJ.out.tab` files from RNA-Seq samples are converted to `*SJFile.tab` files of novel junction coordinates and provided during the 2nd alignment step via `--sjdbFileChrStartEnd`. - -This achieves the highest sensitivity for novel junction alignment. For instance, if there is a novel junction that's highly expressed (many reads, confident detection) in the wild-type, but only weakly expressed (few reads) in the experimental group, by using junctions detected in all samples for the 2nd pass, `STAR` will detect lowly expressed spliced reads in the experimental group. - ### Segemehl
Output files -- `circrna_discovery/Segemehl/intermediates/${sample_id}/` +- `circrna_discovery/segemehl/intermediates/${sample_id}/` - `*.bam`: Aligned reads in BAM format - - `*_collapsed.bed`: Segemehl circRNA counts in minimal BED 6 format - `*.mult.bed`: Thus, this bed file contains all splice events of a read. The start and end positions indicate the nucleotide after the first split (i.e. the beginning of the first intron) and the nucleotide before the last split (i.e. the end of the last intron), respectively. The name and score are equivalent to the one in the \*.sngl file described above. The following fields 7 & 8 (thickStart and thickEnd) should be the identical to fields 2 & 3. Field 9 holds the color information for the item in RGB encoding (itemRGB). Field 10 (blockCount) indicates the number of splits represented by the BED item. Field 11 is a comma separated list of the intron sizes (blockSizes). Field 12 is the comma separated list of intron starts (blockStarts). - `*.sngl.bed`: The bed file contains all single splice events predicted in the split read alignments. - `*.trns.bed`: The custom text file contains all single split alignments predicted to be in trans, i.e. split alignments that are located on different chromosomes and/or different strands. @@ -403,21 +434,6 @@ This achieves the highest sensitivity for novel junction alignment. For instance 1. miRNA must be called by both `miRanda` and `TargetScan`. 2. If a site within the circRNA mature sequence shares duplicate miRNA ID's overlapping the same coordinates, the miRNA with the highest score is kept. -### Circos Plot - -
-Output files - -- `mirna_prediction/${sample_id}/` - - `*_miRNA_Plot.pdf`: Circos plot of mature spliced circRNA sequence with exon boundaries where applicable, displaying miRNA binding sites. -

- circRNA - miRNA circos plot -

- -
- -`nf-core/circrna` plots the filtered miRNA targets given using a circos plot, displaying the miRNA response elements along the mature circRNA sequence. Please note this plot becomes overcrowded when plotting `EIciRNAs` due to their highly variable sequence length (in contrast to `circRNAs` and `ciRNAs` which typically fall within the range of 100 - 1000nt). Therefore `EIciRNAs` with large mature spliced lengths should be considered as potentially spurious calls. - ## Differential Expression Analysis `nf-core/circrna` will perform differential expression analysis by contrasting every variable within the `condition` column i.e the response variable. diff --git a/modules/local/circrna_finder/filter/main.nf b/modules/local/circrna_finder/filter/main.nf index e5198cfb..0cda828e 100644 --- a/modules/local/circrna_finder/filter/main.nf +++ b/modules/local/circrna_finder/filter/main.nf @@ -15,6 +15,7 @@ process CIRCRNA_FINDER_FILTER { output: tuple val(meta), path("${prefix}_circrna_finder_circs.bed"), emit: results tuple val(meta), path("${prefix}_circrna_finder.bed") , emit: matrix + tuple val(meta), path("*filteredJunctions*") , emit: intermediates path "versions.yml" , emit: versions when: From ffdf7966ace420050257d0f67a1a98ea860aecb0 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Thu, 9 Feb 2023 15:28:42 +0000 Subject: [PATCH 039/491] pre-commit --- .pre-commit-config.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..aa6b011a --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,10 @@ +repos: + - repo: https://github.com/pre-commit/mirrors-prettier + rev: "v2.6.2" + hooks: + - id: prettier + - repo: https://github.com/psf/black + rev: 23.1.0 + hooks: + - id: black + From adece2df10d8395f41575cf37f4421d445497ed1 Mon Sep 17 00:00:00 2001 From: Barry digby Date: Thu, 9 Feb 2023 15:34:23 +0000 Subject: [PATCH 040/491] pre-commit run? --- .pre-commit-config.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index aa6b011a..1ec7576e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,4 +7,3 @@ repos: rev: 23.1.0 hooks: - id: black - From 60cbad737a7db28ddd0399bf48d399d076ec5e3d Mon Sep 17 00:00:00 2001 From: Barry digby Date: Thu, 9 Feb 2023 15:34:39 +0000 Subject: [PATCH 041/491] pre-commit :) --- docs/output.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/output.md b/docs/output.md index 0264fb06..e661bf63 100644 --- a/docs/output.md +++ b/docs/output.md @@ -169,7 +169,7 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d The workflow is designed to output three files _per sample_, _per quantification tool_ in the `circrna_discovery` directory. Using the test dataset as an example, the directory structure for the `fust_1` sample is: -```console +````console |-- results/ |-- circrna_discovery/ |-- circexplorer2/ @@ -194,7 +194,7 @@ Sample outputs for the corresponding `.log`, `.bed` and `.fasta` entry are given [nf-core/circrna]: Attempting to fit circRNA to gene exon boundaries [nf-core/circrna]: chrI:1140805-1147588:- fits gene exons, is a circRNA [nf-core/circrna]: cleaning up intermediate files -``` +```` ```console chrI 1140805 1147588 chrI:1140805-1147588:- 2 - 1140805 1147588 0 5 229,214,191,141,499 0,1282,2546,4912,6284 circRNA Y48G8AL.10 NM_001306296,NM_001306297,NM_001306298,NM_001306299 1274 @@ -215,6 +215,7 @@ Intermediate files generated by each quantification tool are described in depth Output files - `circrna_discovery/circexplorer2/intermediates/${sample_id}/` + - `*.bed`: Intermediate file generated by `CIRCexplorer2 parse` module, identifying STAR fusion junctions for downstream annotation. - `*_circexplorer2_circs.bed`: Filtered BED6 file containing circRNA counts used for count matrix generation. - `*.txt`: Output files generated by `CIRCexplorer2 annotate` module, based on BED 12 format containing circRNA genomic location information, exon cassette composition and an additional 6 columns specifying circRNA annotations. Full descriptions of the 18 columns can be found in the `CIRCexplorer2` [documentation](https://circexplorer2.readthedocs.io/en/latest/modules/annotate/#output). @@ -247,6 +248,7 @@ Intermediate files generated by each quantification tool are described in depth Output files - `circrna_discovery/circrna_finder/intermediates/${sample_id}/` + - `*.filteredJunctions.bed`: A bed file with **all** circular junctions found by the pipeline. The score column indicates the number reads spanning each junction. - `*.s_filteredJunctions.bed`: A bed file with those junctions in `*.filteredJunctions.bed` that are flanked by GT-AG splice sites. The score column indicates the number reads spanning each junction. - `*.s_filteredJunctions_fw.bed`: A bed file with the same circular junctions as in file (b), but here the score column gives the average number of forward spliced reads at both splice sites around each circular junction. From b969146ba24502018d13b0f0a1c4cfa40e24a2e4 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Fri, 28 Apr 2023 14:19:44 +0000 Subject: [PATCH 042/491] Template update for nf-core/tools version 2.8 --- .editorconfig | 2 +- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/PULL_REQUEST_TEMPLATE.md | 3 +- .github/workflows/awsfulltest.yml | 2 +- .github/workflows/awstest.yml | 2 +- .github/workflows/branch.yml | 2 +- .github/workflows/clean-up.yml | 24 ++++ .github/workflows/linting.yml | 2 +- .pre-commit-config.yaml | 5 + README.md | 74 ++++++---- bin/check_samplesheet.py | 3 - conf/base.config | 2 +- conf/igenomes.config | 8 ++ conf/test_full.config | 2 + docs/usage.md | 130 +++++------------- lib/NfcoreSchema.groovy | 4 +- lib/WorkflowCircrna.groovy | 12 +- lib/WorkflowMain.groovy | 13 +- main.nf | 1 - modules.json | 4 +- modules/local/samplesheet_check.nf | 2 +- .../custom/dumpsoftwareversions/main.nf | 6 +- .../custom/dumpsoftwareversions/meta.yml | 2 + modules/nf-core/multiqc/main.nf | 6 +- modules/nf-core/multiqc/meta.yml | 3 +- nextflow.config | 29 +++- tower.yml | 5 + 27 files changed, 193 insertions(+), 157 deletions(-) create mode 100644 .github/workflows/clean-up.yml create mode 100644 .pre-commit-config.yaml create mode 100644 tower.yml diff --git a/.editorconfig b/.editorconfig index b78de6e6..b6b31907 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,7 +8,7 @@ trim_trailing_whitespace = true indent_size = 4 indent_style = space -[*.{md,yml,yaml,html,css,scss,js,cff}] +[*.{md,yml,yaml,html,css,scss,js}] indent_size = 2 # These files are edited and tested upstream in nf-core/modules diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index d0232664..485ce3a4 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -45,6 +45,6 @@ body: * Nextflow version _(eg. 22.10.1)_ * Hardware _(eg. HPC, Desktop, Cloud)_ * Executor _(eg. slurm, local, awsbatch)_ - * Container engine: _(e.g. Docker, Singularity, Conda, Podman, Shifter or Charliecloud)_ + * Container engine: _(e.g. Docker, Singularity, Conda, Podman, Shifter, Charliecloud, or Apptainer)_ * OS _(eg. CentOS Linux, macOS, Linux Mint)_ * Version of nf-core/circrna _(eg. 1.1, 1.5, 1.8.2)_ diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8e964d35..fcb76164 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -15,7 +15,8 @@ Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/circ - [ ] This comment contains a description of changes (with reason). - [ ] If you've fixed a bug or added code that should be tested, add tests! -- [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/nf-core/circrna/tree/master/.github/CONTRIBUTING.md)- [ ] If necessary, also make a PR on the nf-core/circrna _branch_ on the [nf-core/test-datasets](https://github.com/nf-core/test-datasets) repository. +- [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/nf-core/circrna/tree/master/.github/CONTRIBUTING.md) +- [ ] If necessary, also make a PR on the nf-core/circrna _branch_ on the [nf-core/test-datasets](https://github.com/nf-core/test-datasets) repository. - [ ] Make sure your code lints (`nf-core lint`). - [ ] Ensure the test suite passes (`nextflow run . -profile test,docker --outdir `). - [ ] Usage Documentation in `docs/usage.md` is updated. diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 96940e16..ec111638 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Launch workflow via tower - uses: nf-core/tower-action@v3 + uses: seqeralabs/action-tower-launch@v1 # TODO nf-core: You can customise AWS full pipeline tests as required # Add full size test data (but still relatively small datasets for few samples) # on the `test_full.config` test runs with only one set of parameters diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index 6677bb32..31933f32 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -12,7 +12,7 @@ jobs: steps: # Launch workflow using Tower CLI tool action - name: Launch workflow via tower - uses: nf-core/tower-action@v3 + uses: seqeralabs/action-tower-launch@v1 with: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 10173ce4..343d881e 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -13,7 +13,7 @@ jobs: - name: Check PRs if: github.repository == 'nf-core/circrna' run: | - { [[ ${{github.event.pull_request.head.repo.full_name }} == nf-core/circrna ]] && [[ $GITHUB_HEAD_REF = "dev" ]]; } || [[ $GITHUB_HEAD_REF == "patch" ]] + { [[ ${{github.event.pull_request.head.repo.full_name }} == nf-core/circrna ]] && [[ $GITHUB_HEAD_REF == "dev" ]]; } || [[ $GITHUB_HEAD_REF == "patch" ]] # If the above check failed, post a comment on the PR explaining the failure # NOTE - this doesn't currently work if the PR is coming from a fork, due to limitations in GitHub actions secrets diff --git a/.github/workflows/clean-up.yml b/.github/workflows/clean-up.yml new file mode 100644 index 00000000..694e90ec --- /dev/null +++ b/.github/workflows/clean-up.yml @@ -0,0 +1,24 @@ +name: "Close user-tagged issues and PRs" +on: + schedule: + - cron: "0 0 * * 0" # Once a week + +jobs: + clean-up: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v7 + with: + stale-issue-message: "This issue has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor. Remove stale label or add a comment otherwise this issue will be closed in 20 days." + stale-pr-message: "This PR has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor. Remove stale label or add a comment if it is still useful." + close-issue-message: "This issue was closed because it has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor and then staled for 20 days with no activity." + days-before-stale: 30 + days-before-close: 20 + days-before-pr-close: -1 + any-of-labels: "awaiting-changes,awaiting-feedback" + exempt-issue-labels: "WIP" + exempt-pr-labels: "WIP" + repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 858d622e..888cb4bc 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -78,7 +78,7 @@ jobs: - uses: actions/setup-python@v4 with: - python-version: "3.7" + python-version: "3.8" architecture: "x64" - name: Install dependencies diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..0c31cdb9 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,5 @@ +repos: + - repo: https://github.com/pre-commit/mirrors-prettier + rev: "v2.7.1" + hooks: + - id: prettier diff --git a/README.md b/README.md index 75428759..c4c1179b 100644 --- a/README.md +++ b/README.md @@ -8,57 +8,71 @@ [![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) [![Launch on Nextflow Tower](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Nextflow%20Tower-%234256e7)](https://tower.nf/launch?pipeline=https://github.com/nf-core/circrna) -[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23circrna-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/circrna)[![Follow on Twitter](http://img.shields.io/badge/twitter-%40nf__core-1DA1F2?labelColor=000000&logo=twitter)](https://twitter.com/nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core) +[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23circrna-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/circrna)[![Follow on Twitter](http://img.shields.io/badge/twitter-%40nf__core-1DA1F2?labelColor=000000&logo=twitter)](https://twitter.com/nf_core)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core) ## Introduction - +**nf-core/circrna** is a bioinformatics pipeline that ... -**nf-core/circrna** is a bioinformatics best-practice analysis pipeline for Quantification, miRNA target prediction and differential expression analysis of circular RNAs. - -The pipeline is built using [Nextflow](https://www.nextflow.io), a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It uses Docker/Singularity containers making installation trivial and results highly reproducible. The [Nextflow DSL2](https://www.nextflow.io/docs/latest/dsl2.html) implementation of this pipeline uses one container per process which makes it much easier to maintain and update software dependencies. Where possible, these processes have been submitted to and installed from [nf-core/modules](https://github.com/nf-core/modules) in order to make them available to all nf-core pipelines, and to everyone within the Nextflow community! - - - -On release, automated continuous integration tests run the pipeline on a full-sized dataset on the AWS cloud infrastructure. This ensures that the pipeline runs on AWS, has sensible resource allocation defaults set to run on real-world datasets, and permits the persistent storage of results to benchmark between pipeline releases and other analysis sources.The results obtained from the full-sized test can be viewed on the [nf-core website](https://nf-co.re/circrna/results). - -## Pipeline summary + + 1. Read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/)) 2. Present QC for raw reads ([`MultiQC`](http://multiqc.info/)) -## Quick Start +## Usage + +> **Note** +> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how +> to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) +> with `-profile test` before running the workflow on actual data. + + - Note that some form of configuration will be needed so that Nextflow knows how to fetch the required software. This is usually done in the form of a config profile (`YOURPROFILE` in the example command above). You can chain multiple config profiles in a comma-separated string. +Now, you can run the pipeline using: - > - The pipeline comes with config profiles called `docker`, `singularity`, `podman`, `shifter`, `charliecloud` and `conda` which instruct the pipeline to use the named tool for software management. For example, `-profile test,docker`. - > - Please check [nf-core/configs](https://github.com/nf-core/configs#documentation) to see if a custom config file to run nf-core pipelines already exists for your Institute. If so, you can simply use `-profile ` in your command. This will enable either `docker` or `singularity` and set the appropriate execution settings for your local compute environment. - > - If you are using `singularity`, please use the [`nf-core download`](https://nf-co.re/tools/#downloading-pipelines-for-offline-use) command to download images first, before running the pipeline. Setting the [`NXF_SINGULARITY_CACHEDIR` or `singularity.cacheDir`](https://www.nextflow.io/docs/latest/singularity.html?#singularity-docker-hub) Nextflow options enables you to store and re-use the images from a central location for future pipeline runs. - > - If you are using `conda`, it is highly recommended to use the [`NXF_CONDA_CACHEDIR` or `conda.cacheDir`](https://www.nextflow.io/docs/latest/conda.html) settings to store the environments in a central location for future pipeline runs. + -4. Start running your own analysis! +```bash +nextflow run nf-core/circrna \ + -profile \ + --input samplesheet.csv \ + --outdir +``` - +> **Warning:** +> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those +> provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; +> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files). - ```bash - nextflow run nf-core/circrna --input samplesheet.csv --outdir --genome GRCh37 -profile - ``` +For more details, please refer to the [usage documentation](https://nf-co.re/circrna/usage) and the [parameter documentation](https://nf-co.re/circrna/parameters). -## Documentation +## Pipeline output -The nf-core/circrna pipeline comes with documentation about the pipeline [usage](https://nf-co.re/circrna/usage), [parameters](https://nf-co.re/circrna/parameters) and [output](https://nf-co.re/circrna/output). +To see the the results of a test run with a full size dataset refer to the [results](https://nf-co.re/circrna/results) tab on the nf-core website pipeline page. +For more details about the output files and reports, please refer to the +[output documentation](https://nf-co.re/circrna/output). ## Credits diff --git a/bin/check_samplesheet.py b/bin/check_samplesheet.py index 11b15572..4a758fe0 100755 --- a/bin/check_samplesheet.py +++ b/bin/check_samplesheet.py @@ -158,9 +158,6 @@ def sniff_format(handle): peek = read_head(handle) handle.seek(0) sniffer = csv.Sniffer() - if not sniffer.has_header(peek): - logger.critical("The given sample sheet does not appear to contain a header.") - sys.exit(1) dialect = sniffer.sniff(peek) return dialect diff --git a/conf/base.config b/conf/base.config index 5e4a442d..307e9381 100644 --- a/conf/base.config +++ b/conf/base.config @@ -15,7 +15,7 @@ process { memory = { check_max( 6.GB * task.attempt, 'memory' ) } time = { check_max( 4.h * task.attempt, 'time' ) } - errorStrategy = { task.exitStatus in [143,137,104,134,139] ? 'retry' : 'finish' } + errorStrategy = { task.exitStatus in ((130..145) + 104) ? 'retry' : 'finish' } maxRetries = 1 maxErrors = '-1' diff --git a/conf/igenomes.config b/conf/igenomes.config index 7a1b3ac6..3f114377 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -36,6 +36,14 @@ params { macs_gsize = "2.7e9" blacklist = "${projectDir}/assets/blacklists/hg38-blacklist.bed" } + 'CHM13' { + fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/BWAIndex/" + bwamem2 = "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/BWAmem2Index/" + gtf = "${params.igenomes_base}/Homo_sapiens/NCBI/CHM13/Annotation/Genes/genes.gtf" + gff = "ftp://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/009/914/755/GCF_009914755.1_T2T-CHM13v2.0/GCF_009914755.1_T2T-CHM13v2.0_genomic.gff.gz" + mito_name = "chrM" + } 'GRCm38' { fasta = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa" bwa = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BWAIndex/version0.6.0/" diff --git a/conf/test_full.config b/conf/test_full.config index a3b229ad..7a280c2a 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -10,6 +10,8 @@ ---------------------------------------------------------------------------------------- */ +cleanup = true + params { config_profile_name = 'Full test profile' config_profile_description = 'Full test dataset to check pipeline function' diff --git a/docs/usage.md b/docs/usage.md index ab73d14e..6b8b01f5 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -71,6 +71,29 @@ work # Directory containing the nextflow working files # Other nextflow hidden files, eg. history of pipeline runs and old logs. ``` +If you wish to repeatedly use the same parameters for multiple runs, rather than specifying each flag in the command, you can specify these in a params file. + +Pipeline settings can be provided in a `yaml` or `json` file via `-params-file `. + +> ⚠️ Do not use `-c ` to specify parameters as this will result in errors. Custom config files specified with `-c` must only be used for [tuning process resource specifications](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources), other infrastructural tweaks (such as output directories), or module arguments (args). +> The above pipeline run specified with a params file in yaml format: + +```bash +nextflow run nf-core/circrna -profile docker -params-file params.yaml +``` + +with `params.yaml` containing: + +```yaml +input: './samplesheet.csv' +outdir: './results/' +genome: 'GRCh37' +input: 'data' +<...> +``` + +You can also generate such `YAML`/`JSON` files via [nf-core/launch](https://nf-co.re/launch). + ### Updating the pipeline When you run the above command, Nextflow automatically pulls the pipeline code from GitHub and stores it as a cached version. When running the pipeline after this, it will always use the cached version if available - even if the pipeline has been updated since. To make sure that you're running the latest version of the pipeline, make sure that you regularly update the cached version of the pipeline: @@ -87,6 +110,10 @@ First, go to the [nf-core/circrna releases page](https://github.com/nf-core/circ This version number will be logged in reports when you run the pipeline, so that you'll know what you used when you look back in the future. For example, at the bottom of the MultiQC reports. +To further assist in reproducbility, you can use share and re-use [parameter files](#running-the-pipeline) to repeat pipeline runs with the same settings without having to write out a command with every single parameter. + +> 💡 If you wish to share such profile (such as upload as supplementary material for academic publications), make sure to NOT include cluster specific paths to files, nor institutional specific profiles. + ## Core Nextflow arguments > **NB:** These options are part of Nextflow and use a _single_ hyphen (pipeline parameters use a double-hyphen). @@ -95,7 +122,7 @@ This version number will be logged in reports when you run the pipeline, so that Use this parameter to choose a configuration profile. Profiles can give configuration presets for different compute environments. -Several generic profiles are bundled with the pipeline which instruct the pipeline to use software packaged using different methods (Docker, Singularity, Podman, Shifter, Charliecloud, Conda) - see below. +Several generic profiles are bundled with the pipeline which instruct the pipeline to use software packaged using different methods (Docker, Singularity, Podman, Shifter, Charliecloud, Apptainer, Conda) - see below. > We highly recommend the use of Docker or Singularity containers for full pipeline reproducibility, however when this is not possible, Conda is also supported. @@ -119,8 +146,10 @@ If `-profile` is not specified, the pipeline will run locally and expect all sof - A generic configuration profile to be used with [Shifter](https://nersc.gitlab.io/development/shifter/how-to-use/) - `charliecloud` - A generic configuration profile to be used with [Charliecloud](https://hpc.github.io/charliecloud/) +- `apptainer` + - A generic configuration profile to be used with [Apptainer](https://apptainer.org/) - `conda` - - A generic configuration profile to be used with [Conda](https://conda.io/docs/). Please only use Conda as a last resort i.e. when it's not possible to run the pipeline with Docker, Singularity, Podman, Shifter or Charliecloud. + - A generic configuration profile to be used with [Conda](https://conda.io/docs/). Please only use Conda as a last resort i.e. when it's not possible to run the pipeline with Docker, Singularity, Podman, Shifter, Charliecloud, or Apptainer. ### `-resume` @@ -138,102 +167,19 @@ Specify the path to a specific config file (this is a core Nextflow command). Se Whilst the default requirements set within the pipeline will hopefully work for most people and with most input data, you may find that you want to customise the compute resources that the pipeline requests. Each step in the pipeline has a default set of requirements for number of CPUs, memory and time. For most of the steps in the pipeline, if the job exits with any of the error codes specified [here](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/conf/base.config#L18) it will automatically be resubmitted with higher requests (2 x original, then 3 x original). If it still fails after the third attempt then the pipeline execution is stopped. -For example, if the nf-core/rnaseq pipeline is failing after multiple re-submissions of the `STAR_ALIGN` process due to an exit code of `137` this would indicate that there is an out of memory issue: - -```console -[62/149eb0] NOTE: Process `NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN (WT_REP1)` terminated with an error exit status (137) -- Execution is retried (1) -Error executing process > 'NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN (WT_REP1)' - -Caused by: - Process `NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN (WT_REP1)` terminated with an error exit status (137) - -Command executed: - STAR \ - --genomeDir star \ - --readFilesIn WT_REP1_trimmed.fq.gz \ - --runThreadN 2 \ - --outFileNamePrefix WT_REP1. \ - - -Command exit status: - 137 - -Command output: - (empty) - -Command error: - .command.sh: line 9: 30 Killed STAR --genomeDir star --readFilesIn WT_REP1_trimmed.fq.gz --runThreadN 2 --outFileNamePrefix WT_REP1. -Work dir: - /home/pipelinetest/work/9d/172ca5881234073e8d76f2a19c88fb - -Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run` -``` - -#### For beginners - -A first step to bypass this error, you could try to increase the amount of CPUs, memory, and time for the whole pipeline. Therefor you can try to increase the resource for the parameters `--max_cpus`, `--max_memory`, and `--max_time`. Based on the error above, you have to increase the amount of memory. Therefore you can go to the [parameter documentation of rnaseq](https://nf-co.re/rnaseq/3.9/parameters) and scroll down to the `show hidden parameter` button to get the default value for `--max_memory`. In this case 128GB, you than can try to run your pipeline again with `--max_memory 200GB -resume` to skip all process, that were already calculated. If you can not increase the resource of the complete pipeline, you can try to adapt the resource for a single process as mentioned below. - -#### Advanced option on process level - -To bypass this error you would need to find exactly which resources are set by the `STAR_ALIGN` process. The quickest way is to search for `process STAR_ALIGN` in the [nf-core/rnaseq Github repo](https://github.com/nf-core/rnaseq/search?q=process+STAR_ALIGN). -We have standardised the structure of Nextflow DSL2 pipelines such that all module files will be present in the `modules/` directory and so, based on the search results, the file we want is `modules/nf-core/star/align/main.nf`. -If you click on the link to that file you will notice that there is a `label` directive at the top of the module that is set to [`label process_high`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/modules/nf-core/software/star/align/main.nf#L9). -The [Nextflow `label`](https://www.nextflow.io/docs/latest/process.html#label) directive allows us to organise workflow processes in separate groups which can be referenced in a configuration file to select and configure subset of processes having similar computing requirements. -The default values for the `process_high` label are set in the pipeline's [`base.config`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/conf/base.config#L33-L37) which in this case is defined as 72GB. -Providing you haven't set any other standard nf-core parameters to **cap** the [maximum resources](https://nf-co.re/usage/configuration#max-resources) used by the pipeline then we can try and bypass the `STAR_ALIGN` process failure by creating a custom config file that sets at least 72GB of memory, in this case increased to 100GB. -The custom config below can then be provided to the pipeline via the [`-c`](#-c) parameter as highlighted in previous sections. - -```nextflow -process { - withName: 'NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN' { - memory = 100.GB - } -} -``` - -> **NB:** We specify the full process name i.e. `NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN` in the config file because this takes priority over the short name (`STAR_ALIGN`) and allows existing configuration using the full process name to be correctly overridden. -> -> If you get a warning suggesting that the process selector isn't recognised check that the process name has been specified correctly. - -### Updating containers (advanced users) - -The [Nextflow DSL2](https://www.nextflow.io/docs/latest/dsl2.html) implementation of this pipeline uses one container per process which makes it much easier to maintain and update software dependencies. If for some reason you need to use a different version of a particular tool with the pipeline then you just need to identify the `process` name and override the Nextflow `container` definition for that process using the `withName` declaration. For example, in the [nf-core/viralrecon](https://nf-co.re/viralrecon) pipeline a tool called [Pangolin](https://github.com/cov-lineages/pangolin) has been used during the COVID-19 pandemic to assign lineages to SARS-CoV-2 genome sequenced samples. Given that the lineage assignments change quite frequently it doesn't make sense to re-release the nf-core/viralrecon everytime a new version of Pangolin has been released. However, you can override the default container used by the pipeline by creating a custom config file and passing it as a command-line argument via `-c custom.config`. - -1. Check the default version used by the pipeline in the module file for [Pangolin](https://github.com/nf-core/viralrecon/blob/a85d5969f9025409e3618d6c280ef15ce417df65/modules/nf-core/software/pangolin/main.nf#L14-L19) -2. Find the latest version of the Biocontainer available on [Quay.io](https://quay.io/repository/biocontainers/pangolin?tag=latest&tab=tags) -3. Create the custom config accordingly: - - - For Docker: +To change the resource requests, please see the [max resources](https://nf-co.re/docs/usage/configuration#max-resources) and [tuning workflow resources](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources) section of the nf-core website. - ```nextflow - process { - withName: PANGOLIN { - container = 'quay.io/biocontainers/pangolin:3.0.5--pyhdfd78af_0' - } - } - ``` +### Custom Containers - - For Singularity: +In some cases you may wish to change which container or conda environment a step of the pipeline uses for a particular tool. By default nf-core pipelines use containers and software from the [biocontainers](https://biocontainers.pro/) or [bioconda](https://bioconda.github.io/) projects. However in some cases the pipeline specified version maybe out of date. - ```nextflow - process { - withName: PANGOLIN { - container = 'https://depot.galaxyproject.org/singularity/pangolin:3.0.5--pyhdfd78af_0' - } - } - ``` +To use a different container from the default container or conda environment specified in a pipeline, please see the [updating tool versions](https://nf-co.re/docs/usage/configuration#updating-tool-versions) section of the nf-core website. - - For Conda: +### Custom Tool Arguments - ```nextflow - process { - withName: PANGOLIN { - conda = 'bioconda::pangolin=3.0.5' - } - } - ``` +A pipeline might not always support every possible argument or option of a particular tool used in pipeline. Fortunately, nf-core pipelines provide some freedom to users to insert additional parameters that the pipeline does not include by default. -> **NB:** If you wish to periodically update individual tool-specific results (e.g. Pangolin) generated by the pipeline then you must ensure to keep the `work/` directory otherwise the `-resume` ability of the pipeline will be compromised and it will restart from scratch. +To learn how to provide additional arguments to a particular tool of the pipeline, please see the [customising tool arguments](https://nf-co.re/docs/usage/configuration#customising-tool-arguments) section of the nf-core website. ### nf-core/configs diff --git a/lib/NfcoreSchema.groovy b/lib/NfcoreSchema.groovy index 33cd4f6e..9b34804d 100755 --- a/lib/NfcoreSchema.groovy +++ b/lib/NfcoreSchema.groovy @@ -2,6 +2,7 @@ // This file holds several functions used to perform JSON parameter validation, help and summary rendering for the nf-core pipeline template. // +import nextflow.Nextflow import org.everit.json.schema.Schema import org.everit.json.schema.loader.SchemaLoader import org.everit.json.schema.ValidationException @@ -83,6 +84,7 @@ class NfcoreSchema { 'stub-run', 'test', 'w', + 'with-apptainer', 'with-charliecloud', 'with-conda', 'with-dag', @@ -177,7 +179,7 @@ class NfcoreSchema { } if (has_error) { - System.exit(1) + Nextflow.error('Exiting!') } } diff --git a/lib/WorkflowCircrna.groovy b/lib/WorkflowCircrna.groovy index 7833ed4a..f990810a 100755 --- a/lib/WorkflowCircrna.groovy +++ b/lib/WorkflowCircrna.groovy @@ -2,6 +2,7 @@ // This file holds several functions specific to the workflow/circrna.nf in the nf-core/circrna pipeline // +import nextflow.Nextflow import groovy.text.SimpleTemplateEngine class WorkflowCircrna { @@ -14,8 +15,7 @@ class WorkflowCircrna { if (!params.fasta) { - log.error "Genome fasta file not specified with e.g. '--fasta genome.fa' or via a detectable config file." - System.exit(1) + Nextflow.error "Genome fasta file not specified with e.g. '--fasta genome.fa' or via a detectable config file." } } @@ -61,17 +61,19 @@ class WorkflowCircrna { def description_html = engine.createTemplate(methods_text).make(meta) return description_html - }// + } + + // // Exit pipeline if incorrect --genome key provided // private static void genomeExistsError(params, log) { if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { - log.error "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + + def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + " Currently, the available genome keys are:\n" + " ${params.genomes.keySet().join(", ")}\n" + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - System.exit(1) + Nextflow.error(error_string) } } } diff --git a/lib/WorkflowMain.groovy b/lib/WorkflowMain.groovy index 0d7be86b..328c2764 100755 --- a/lib/WorkflowMain.groovy +++ b/lib/WorkflowMain.groovy @@ -2,6 +2,8 @@ // This file holds several functions specific to the main.nf workflow in the nf-core/circrna pipeline // +import nextflow.Nextflow + class WorkflowMain { // @@ -21,7 +23,7 @@ class WorkflowMain { // // Generate help string // - public static String help(workflow, params, log) { + public static String help(workflow, params) { def command = "nextflow run ${workflow.manifest.name} --input samplesheet.csv --genome GRCh37 -profile docker" def help_string = '' help_string += NfcoreTemplate.logo(workflow, params.monochrome_logs) @@ -34,7 +36,7 @@ class WorkflowMain { // // Generate parameter summary log string // - public static String paramsSummaryLog(workflow, params, log) { + public static String paramsSummaryLog(workflow, params) { def summary_log = '' summary_log += NfcoreTemplate.logo(workflow, params.monochrome_logs) summary_log += NfcoreSchema.paramsSummaryLog(workflow, params) @@ -49,7 +51,7 @@ class WorkflowMain { public static void initialise(workflow, params, log) { // Print help to screen if required if (params.help) { - log.info help(workflow, params, log) + log.info help(workflow, params) System.exit(0) } @@ -61,7 +63,7 @@ class WorkflowMain { } // Print parameter summary log to screen - log.info paramsSummaryLog(workflow, params, log) + log.info paramsSummaryLog(workflow, params) // Validate workflow parameters via the JSON schema if (params.validate_params) { @@ -81,8 +83,7 @@ class WorkflowMain { // Check input has been provided if (!params.input) { - log.error "Please provide an input samplesheet to the pipeline e.g. '--input samplesheet.csv'" - System.exit(1) + Nextflow.error("Please provide an input samplesheet to the pipeline e.g. '--input samplesheet.csv'") } } // diff --git a/main.nf b/main.nf index 526c619d..1c002ad4 100644 --- a/main.nf +++ b/main.nf @@ -4,7 +4,6 @@ nf-core/circrna ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Github : https://github.com/nf-core/circrna - Website: https://nf-co.re/circrna Slack : https://nfcore.slack.com/channels/circrna ---------------------------------------------------------------------------------------- diff --git a/modules.json b/modules.json index 5b7c59e8..11cb5db3 100644 --- a/modules.json +++ b/modules.json @@ -7,7 +7,7 @@ "nf-core": { "custom/dumpsoftwareversions": { "branch": "master", - "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", + "git_sha": "76cc4938c1f6ea5c7d83fed1eeffc146787f9543", "installed_by": ["modules"] }, "fastqc": { @@ -17,7 +17,7 @@ }, "multiqc": { "branch": "master", - "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", + "git_sha": "f2d63bd5b68925f98f572eed70993d205cc694b7", "installed_by": ["modules"] } } diff --git a/modules/local/samplesheet_check.nf b/modules/local/samplesheet_check.nf index 4e85a56e..e102f46d 100644 --- a/modules/local/samplesheet_check.nf +++ b/modules/local/samplesheet_check.nf @@ -5,7 +5,7 @@ process SAMPLESHEET_CHECK { conda "conda-forge::python=3.8.3" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/python:3.8.3' : - 'quay.io/biocontainers/python:3.8.3' }" + 'biocontainers/python:3.8.3' }" input: path samplesheet diff --git a/modules/nf-core/custom/dumpsoftwareversions/main.nf b/modules/nf-core/custom/dumpsoftwareversions/main.nf index 3df21765..800a6099 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/main.nf +++ b/modules/nf-core/custom/dumpsoftwareversions/main.nf @@ -2,10 +2,10 @@ process CUSTOM_DUMPSOFTWAREVERSIONS { label 'process_single' // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container - conda "bioconda::multiqc=1.13" + conda "bioconda::multiqc=1.14" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.13--pyhdfd78af_0' : - 'quay.io/biocontainers/multiqc:1.13--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.14--pyhdfd78af_0' : + 'quay.io/biocontainers/multiqc:1.14--pyhdfd78af_0' }" input: path versions diff --git a/modules/nf-core/custom/dumpsoftwareversions/meta.yml b/modules/nf-core/custom/dumpsoftwareversions/meta.yml index 60b546a0..c32657de 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/meta.yml +++ b/modules/nf-core/custom/dumpsoftwareversions/meta.yml @@ -1,7 +1,9 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/yaml-schema.json name: custom_dumpsoftwareversions description: Custom module used to dump software versions within the nf-core pipeline template keywords: - custom + - dump - version tools: - custom: diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 68f66bea..4b604749 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,10 +1,10 @@ process MULTIQC { label 'process_single' - conda "bioconda::multiqc=1.13" + conda "bioconda::multiqc=1.14" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.13--pyhdfd78af_0' : - 'quay.io/biocontainers/multiqc:1.13--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.14--pyhdfd78af_0' : + 'quay.io/biocontainers/multiqc:1.14--pyhdfd78af_0' }" input: path multiqc_files, stageAs: "?/*" diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index ebc29b27..f93b5ee5 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -1,3 +1,4 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/yaml-schema.json name: MultiQC description: Aggregate results from bioinformatics analyses across many samples into a single report keywords: @@ -37,7 +38,7 @@ output: description: MultiQC report file pattern: "multiqc_report.html" - data: - type: dir + type: directory description: MultiQC data dir pattern: "multiqc_data" - plots: diff --git a/nextflow.config b/nextflow.config index eabafb20..8ab54444 100644 --- a/nextflow.config +++ b/nextflow.config @@ -78,7 +78,11 @@ try { profiles { - debug { process.beforeScript = 'echo $HOSTNAME' } + debug { + dumpHashes = true + process.beforeScript = 'echo $HOSTNAME' + cleanup = false + } conda { conda.enabled = true docker.enabled = false @@ -86,6 +90,7 @@ profiles { podman.enabled = false shifter.enabled = false charliecloud.enabled = false + apptainer.enabled = false } mamba { conda.enabled = true @@ -95,14 +100,18 @@ profiles { podman.enabled = false shifter.enabled = false charliecloud.enabled = false + apptainer.enabled = false } docker { docker.enabled = true + docker.registry = 'quay.io' docker.userEmulation = true + conda.enabled = false singularity.enabled = false podman.enabled = false shifter.enabled = false charliecloud.enabled = false + apptainer.enabled = false } arm { docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' @@ -110,31 +119,49 @@ profiles { singularity { singularity.enabled = true singularity.autoMounts = true + conda.enabled = false docker.enabled = false podman.enabled = false shifter.enabled = false charliecloud.enabled = false + apptainer.enabled = false } podman { podman.enabled = true + podman.registry = 'quay.io' + conda.enabled = false docker.enabled = false singularity.enabled = false shifter.enabled = false charliecloud.enabled = false + apptainer.enabled = false } shifter { shifter.enabled = true + conda.enabled = false docker.enabled = false singularity.enabled = false podman.enabled = false charliecloud.enabled = false + apptainer.enabled = false } charliecloud { charliecloud.enabled = true + conda.enabled = false docker.enabled = false singularity.enabled = false podman.enabled = false shifter.enabled = false + apptainer.enabled = false + } + apptainer { + apptainer.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false } gitpod { executor.name = 'local' diff --git a/tower.yml b/tower.yml new file mode 100644 index 00000000..787aedfe --- /dev/null +++ b/tower.yml @@ -0,0 +1,5 @@ +reports: + multiqc_report.html: + display: "MultiQC HTML report" + samplesheet.csv: + display: "Auto-created samplesheet with collated metadata and FASTQ paths" From ab234c96d00ca5e54133420e08ae737657385694 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Fri, 30 Jun 2023 16:12:56 +0000 Subject: [PATCH 043/491] Template update for nf-core/tools version 2.9 --- .github/CONTRIBUTING.md | 1 - .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/workflows/awsfulltest.yml | 11 +- .github/workflows/awstest.yml | 10 +- .github/workflows/ci.yml | 2 +- .gitpod.yml | 5 + CITATIONS.md | 6 + README.md | 6 +- assets/methods_description_template.yml | 12 +- assets/multiqc_config.yml | 4 +- assets/nf-core-circrna_logo_light.png | Bin 9946 -> 64214 bytes assets/slackreport.json | 2 +- conf/test_full.config | 2 - docs/usage.md | 6 +- lib/NfcoreSchema.groovy | 530 ------------------------ lib/NfcoreTemplate.groovy | 2 +- lib/WorkflowCircrna.groovy | 45 +- lib/WorkflowMain.groovy | 37 -- main.nf | 16 + nextflow.config | 52 ++- nextflow_schema.json | 36 +- workflows/circrna.nf | 25 +- 22 files changed, 175 insertions(+), 637 deletions(-) delete mode 100755 lib/NfcoreSchema.groovy diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6566cc5d..c173003a 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -116,4 +116,3 @@ To get started: Devcontainer specs: - [DevContainer config](.devcontainer/devcontainer.json) -- [Dockerfile](.devcontainer/Dockerfile) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 485ce3a4..42e95fff 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -42,7 +42,7 @@ body: attributes: label: System information description: | - * Nextflow version _(eg. 22.10.1)_ + * Nextflow version _(eg. 23.04.0)_ * Hardware _(eg. HPC, Desktop, Cloud)_ * Executor _(eg. slurm, local, awsbatch)_ * Container engine: _(e.g. Docker, Singularity, Conda, Podman, Shifter, Charliecloud, or Apptainer)_ diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index ec111638..552540b6 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Launch workflow via tower - uses: seqeralabs/action-tower-launch@v1 + uses: seqeralabs/action-tower-launch@v2 # TODO nf-core: You can customise AWS full pipeline tests as required # Add full size test data (but still relatively small datasets for few samples) # on the `test_full.config` test runs with only one set of parameters @@ -22,13 +22,18 @@ jobs: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} compute_env: ${{ secrets.TOWER_COMPUTE_ENV }} + revision: ${{ github.sha }} workdir: s3://${{ secrets.AWS_S3_BUCKET }}/work/circrna/work-${{ github.sha }} parameters: | { + "hook_url": "${{ secrets.MEGATESTS_ALERTS_SLACK_HOOK_URL }}", "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/circrna/results-${{ github.sha }}" } - profiles: test_full,aws_tower + profiles: test_full + - uses: actions/upload-artifact@v3 with: name: Tower debug log file - path: tower_action_*.log + path: | + tower_action_*.log + tower_action_*.json diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index 31933f32..75cde376 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -12,18 +12,22 @@ jobs: steps: # Launch workflow using Tower CLI tool action - name: Launch workflow via tower - uses: seqeralabs/action-tower-launch@v1 + uses: seqeralabs/action-tower-launch@v2 with: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} compute_env: ${{ secrets.TOWER_COMPUTE_ENV }} + revision: ${{ github.sha }} workdir: s3://${{ secrets.AWS_S3_BUCKET }}/work/circrna/work-${{ github.sha }} parameters: | { "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/circrna/results-test-${{ github.sha }}" } - profiles: test,aws_tower + profiles: test + - uses: actions/upload-artifact@v3 with: name: Tower debug log file - path: tower_action_*.log + path: | + tower_action_*.log + tower_action_*.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c650441..735ec12e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: strategy: matrix: NXF_VER: - - "22.10.1" + - "23.04.0" - "latest-everything" steps: - name: Check out pipeline code diff --git a/.gitpod.yml b/.gitpod.yml index 85d95ecc..25488dcc 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,4 +1,9 @@ image: nfcore/gitpod:latest +tasks: + - name: Update Nextflow and setup pre-commit + command: | + pre-commit install --install-hooks + nextflow self-update vscode: extensions: # based on nf-core.nf-core-extensionpack diff --git a/CITATIONS.md b/CITATIONS.md index a90e70da..c3be1aad 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -12,7 +12,10 @@ - [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) + > Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. Available online https://www.bioinformatics.babraham.ac.uk/projects/fastqc/. + - [MultiQC](https://pubmed.ncbi.nlm.nih.gov/27312411/) + > Ewels P, Magnusson M, Lundin S, Käller M. MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics. 2016 Oct 1;32(19):3047-8. doi: 10.1093/bioinformatics/btw354. Epub 2016 Jun 16. PubMed PMID: 27312411; PubMed Central PMCID: PMC5039924. ## Software packaging/containerisation tools @@ -31,5 +34,8 @@ - [Docker](https://dl.acm.org/doi/10.5555/2600239.2600241) + > Merkel, D. (2014). Docker: lightweight linux containers for consistent development and deployment. Linux Journal, 2014(239), 2. doi: 10.5555/2600239.2600241. + - [Singularity](https://pubmed.ncbi.nlm.nih.gov/28494014/) + > Kurtzer GM, Sochat V, Bauer MW. Singularity: Scientific containers for mobility of compute. PLoS One. 2017 May 11;12(5):e0177459. doi: 10.1371/journal.pone.0177459. eCollection 2017. PubMed PMID: 28494014; PubMed Central PMCID: PMC5426675. diff --git a/README.md b/README.md index c4c1179b..12e662ff 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/circrna/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) -[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A522.10.1-23aa62.svg)](https://www.nextflow.io/) +[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A523.04.0-23aa62.svg)](https://www.nextflow.io/) [![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) [![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) [![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) @@ -66,11 +66,11 @@ nextflow run nf-core/circrna \ > provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; > see [docs](https://nf-co.re/usage/configuration#custom-configuration-files). -For more details, please refer to the [usage documentation](https://nf-co.re/circrna/usage) and the [parameter documentation](https://nf-co.re/circrna/parameters). +For more details and further functionality, please refer to the [usage documentation](https://nf-co.re/circrna/usage) and the [parameter documentation](https://nf-co.re/circrna/parameters). ## Pipeline output -To see the the results of a test run with a full size dataset refer to the [results](https://nf-co.re/circrna/results) tab on the nf-core website pipeline page. +To see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/circrna/results) tab on the nf-core website pipeline page. For more details about the output files and reports, please refer to the [output documentation](https://nf-co.re/circrna/output). diff --git a/assets/methods_description_template.yml b/assets/methods_description_template.yml index 32e39806..3affe6b5 100644 --- a/assets/methods_description_template.yml +++ b/assets/methods_description_template.yml @@ -3,17 +3,21 @@ description: "Suggested text and references to use when describing pipeline usag section_name: "nf-core/circrna Methods Description" section_href: "https://github.com/nf-core/circrna" plot_type: "html" -## TODO nf-core: Update the HTML below to your prefered methods description, e.g. add publication citation for this pipeline +## TODO nf-core: Update the HTML below to your preferred methods description, e.g. add publication citation for this pipeline ## You inject any metadata in the Nextflow '${workflow}' object data: |

Methods

-

Data was processed using nf-core/circrna v${workflow.manifest.version} ${doi_text} of the nf-core collection of workflows (Ewels et al., 2020).

+

Data was processed using nf-core/circrna v${workflow.manifest.version} ${doi_text} of the nf-core collection of workflows (Ewels et al., 2020), utilising reproducible software environments from the Bioconda (Grüning et al., 2018) and Biocontainers (da Veiga Leprevost et al., 2017) projects.

The pipeline was executed with Nextflow v${workflow.nextflow.version} (Di Tommaso et al., 2017) with the following command:

${workflow.commandLine}
+

${tool_citations}

References

    -
  • Di Tommaso, P., Chatzou, M., Floden, E. W., Barja, P. P., Palumbo, E., & Notredame, C. (2017). Nextflow enables reproducible computational workflows. Nature Biotechnology, 35(4), 316-319. https://doi.org/10.1038/nbt.3820
  • -
  • Ewels, P. A., Peltzer, A., Fillinger, S., Patel, H., Alneberg, J., Wilm, A., Garcia, M. U., Di Tommaso, P., & Nahnsen, S. (2020). The nf-core framework for community-curated bioinformatics pipelines. Nature Biotechnology, 38(3), 276-278. https://doi.org/10.1038/s41587-020-0439-x
  • +
  • Di Tommaso, P., Chatzou, M., Floden, E. W., Barja, P. P., Palumbo, E., & Notredame, C. (2017). Nextflow enables reproducible computational workflows. Nature Biotechnology, 35(4), 316-319. doi: 10.1038/nbt.3820
  • +
  • Ewels, P. A., Peltzer, A., Fillinger, S., Patel, H., Alneberg, J., Wilm, A., Garcia, M. U., Di Tommaso, P., & Nahnsen, S. (2020). The nf-core framework for community-curated bioinformatics pipelines. Nature Biotechnology, 38(3), 276-278. doi: 10.1038/s41587-020-0439-x
  • +
  • Grüning, B., Dale, R., Sjödin, A., Chapman, B. A., Rowe, J., Tomkins-Tinch, C. H., Valieris, R., Köster, J., & Bioconda Team. (2018). Bioconda: sustainable and comprehensive software distribution for the life sciences. Nature Methods, 15(7), 475–476. doi: 10.1038/s41592-018-0046-7
  • +
  • da Veiga Leprevost, F., Grüning, B. A., Alves Aflitos, S., Röst, H. L., Uszkoreit, J., Barsnes, H., Vaudel, M., Moreno, P., Gatto, L., Weber, J., Bai, M., Jimenez, R. C., Sachsenberg, T., Pfeuffer, J., Vera Alvarez, R., Griss, J., Nesvizhskii, A. I., & Perez-Riverol, Y. (2017). BioContainers: an open-source and community-driven framework for software standardization. Bioinformatics (Oxford, England), 33(16), 2580–2582. doi: 10.1093/bioinformatics/btx192
  • + ${tool_bibliography}
Notes:
diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index ecd398c2..82a8c2de 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,7 +1,7 @@ report_comment: > - This report has been generated by the nf-core/circrna + This report has been generated by the nf-core/circrna analysis pipeline. For information about how to interpret these results, please see the - documentation. + documentation. report_section_order: "nf-core-circrna-methods-description": order: -1000 diff --git a/assets/nf-core-circrna_logo_light.png b/assets/nf-core-circrna_logo_light.png index b1316cff22fe2008894af4a6d7f86a09dec8ebcf..d3cd49c1fffb4c615ab9d6e96f131be71830d2b2 100644 GIT binary patch literal 64214 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�ev`Q}H7y#R1zKkC5n?0_OP7^FqWWeXhX0t0pNK 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

)bNtXB<>| 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

V0GI8SHG1^dh_*}1*QM#w2kyE^nW%>`QZD7q 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 Q)8RG*JHk(BI-FkqACU4o?*IS* literal 9946 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 N+UojhwU2G0{|8JJXnOzv diff --git a/assets/slackreport.json b/assets/slackreport.json index 043d02f2..b6be7a75 100644 --- a/assets/slackreport.json +++ b/assets/slackreport.json @@ -3,7 +3,7 @@ { "fallback": "Plain-text summary of the attachment.", "color": "<% if (success) { %>good<% } else { %>danger<%} %>", - "author_name": "sanger-tol/readmapping v${version} - ${runName}", + "author_name": "nf-core/circrna v${version} - ${runName}", "author_icon": "https://www.nextflow.io/docs/latest/_static/favicon.ico", "text": "<% if (success) { %>Pipeline completed successfully!<% } else { %>Pipeline completed with errors<% } %>", "fields": [ diff --git a/conf/test_full.config b/conf/test_full.config index 7a280c2a..a3b229ad 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -10,8 +10,6 @@ ---------------------------------------------------------------------------------------- */ -cleanup = true - params { config_profile_name = 'Full test profile' config_profile_description = 'Full test dataset to check pipeline function' diff --git a/docs/usage.md b/docs/usage.md index 6b8b01f5..850476f1 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -57,7 +57,7 @@ An [example samplesheet](../assets/samplesheet.csv) has been provided with the p The typical command for running the pipeline is as follows: ```bash -nextflow run nf-core/circrna --input samplesheet.csv --outdir --genome GRCh37 -profile docker +nextflow run nf-core/circrna --input ./samplesheet.csv --outdir ./results --genome GRCh37 -profile docker ``` This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. @@ -76,7 +76,8 @@ If you wish to repeatedly use the same parameters for multiple runs, rather than Pipeline settings can be provided in a `yaml` or `json` file via `-params-file `. > ⚠️ Do not use `-c ` to specify parameters as this will result in errors. Custom config files specified with `-c` must only be used for [tuning process resource specifications](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources), other infrastructural tweaks (such as output directories), or module arguments (args). -> The above pipeline run specified with a params file in yaml format: + +The above pipeline run specified with a params file in yaml format: ```bash nextflow run nf-core/circrna -profile docker -params-file params.yaml @@ -88,7 +89,6 @@ with `params.yaml` containing: input: './samplesheet.csv' outdir: './results/' genome: 'GRCh37' -input: 'data' <...> ``` diff --git a/lib/NfcoreSchema.groovy b/lib/NfcoreSchema.groovy deleted file mode 100755 index 9b34804d..00000000 --- a/lib/NfcoreSchema.groovy +++ /dev/null @@ -1,530 +0,0 @@ -// -// This file holds several functions used to perform JSON parameter validation, help and summary rendering for the nf-core pipeline template. -// - -import nextflow.Nextflow -import org.everit.json.schema.Schema -import org.everit.json.schema.loader.SchemaLoader -import org.everit.json.schema.ValidationException -import org.json.JSONObject -import org.json.JSONTokener -import org.json.JSONArray -import groovy.json.JsonSlurper -import groovy.json.JsonBuilder - -class NfcoreSchema { - - // - // Resolve Schema path relative to main workflow directory - // - public static String getSchemaPath(workflow, schema_filename='nextflow_schema.json') { - return "${workflow.projectDir}/${schema_filename}" - } - - // - // Function to loop over all parameters defined in schema and check - // whether the given parameters adhere to the specifications - // - /* groovylint-disable-next-line UnusedPrivateMethodParameter */ - public static void validateParameters(workflow, params, log, schema_filename='nextflow_schema.json') { - def has_error = false - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Check for nextflow core params and unexpected params - def json = new File(getSchemaPath(workflow, schema_filename=schema_filename)).text - def Map schemaParams = (Map) new JsonSlurper().parseText(json).get('definitions') - def nf_params = [ - // Options for base `nextflow` command - 'bg', - 'c', - 'C', - 'config', - 'd', - 'D', - 'dockerize', - 'h', - 'log', - 'q', - 'quiet', - 'syslog', - 'v', - - // Options for `nextflow run` command - 'ansi', - 'ansi-log', - 'bg', - 'bucket-dir', - 'c', - 'cache', - 'config', - 'dsl2', - 'dump-channels', - 'dump-hashes', - 'E', - 'entry', - 'latest', - 'lib', - 'main-script', - 'N', - 'name', - 'offline', - 'params-file', - 'pi', - 'plugins', - 'poll-interval', - 'pool-size', - 'profile', - 'ps', - 'qs', - 'queue-size', - 'r', - 'resume', - 'revision', - 'stdin', - 'stub', - 'stub-run', - 'test', - 'w', - 'with-apptainer', - 'with-charliecloud', - 'with-conda', - 'with-dag', - 'with-docker', - 'with-mpi', - 'with-notification', - 'with-podman', - 'with-report', - 'with-singularity', - 'with-timeline', - 'with-tower', - 'with-trace', - 'with-weblog', - 'without-docker', - 'without-podman', - 'work-dir' - ] - def unexpectedParams = [] - - // Collect expected parameters from the schema - def expectedParams = [] - def enums = [:] - for (group in schemaParams) { - for (p in group.value['properties']) { - expectedParams.push(p.key) - if (group.value['properties'][p.key].containsKey('enum')) { - enums[p.key] = group.value['properties'][p.key]['enum'] - } - } - } - - for (specifiedParam in params.keySet()) { - // nextflow params - if (nf_params.contains(specifiedParam)) { - log.error "ERROR: You used a core Nextflow option with two hyphens: '--${specifiedParam}'. Please resubmit with '-${specifiedParam}'" - has_error = true - } - // unexpected params - def params_ignore = params.schema_ignore_params.split(',') + 'schema_ignore_params' - def expectedParamsLowerCase = expectedParams.collect{ it.replace("-", "").toLowerCase() } - def specifiedParamLowerCase = specifiedParam.replace("-", "").toLowerCase() - def isCamelCaseBug = (specifiedParam.contains("-") && !expectedParams.contains(specifiedParam) && expectedParamsLowerCase.contains(specifiedParamLowerCase)) - if (!expectedParams.contains(specifiedParam) && !params_ignore.contains(specifiedParam) && !isCamelCaseBug) { - // Temporarily remove camelCase/camel-case params #1035 - def unexpectedParamsLowerCase = unexpectedParams.collect{ it.replace("-", "").toLowerCase()} - if (!unexpectedParamsLowerCase.contains(specifiedParamLowerCase)){ - unexpectedParams.push(specifiedParam) - } - } - } - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Validate parameters against the schema - InputStream input_stream = new File(getSchemaPath(workflow, schema_filename=schema_filename)).newInputStream() - JSONObject raw_schema = new JSONObject(new JSONTokener(input_stream)) - - // Remove anything that's in params.schema_ignore_params - raw_schema = removeIgnoredParams(raw_schema, params) - - Schema schema = SchemaLoader.load(raw_schema) - - // Clean the parameters - def cleanedParams = cleanParameters(params) - - // Convert to JSONObject - def jsonParams = new JsonBuilder(cleanedParams) - JSONObject params_json = new JSONObject(jsonParams.toString()) - - // Validate - try { - schema.validate(params_json) - } catch (ValidationException e) { - println '' - log.error 'ERROR: Validation of pipeline parameters failed!' - JSONObject exceptionJSON = e.toJSON() - printExceptions(exceptionJSON, params_json, log, enums) - println '' - has_error = true - } - - // Check for unexpected parameters - if (unexpectedParams.size() > 0) { - Map colors = NfcoreTemplate.logColours(params.monochrome_logs) - println '' - def warn_msg = 'Found unexpected parameters:' - for (unexpectedParam in unexpectedParams) { - warn_msg = warn_msg + "\n* --${unexpectedParam}: ${params[unexpectedParam].toString()}" - } - log.warn warn_msg - log.info "- ${colors.dim}Ignore this warning: params.schema_ignore_params = \"${unexpectedParams.join(',')}\" ${colors.reset}" - println '' - } - - if (has_error) { - Nextflow.error('Exiting!') - } - } - - // - // Beautify parameters for --help - // - public static String paramsHelp(workflow, params, command, schema_filename='nextflow_schema.json') { - Map colors = NfcoreTemplate.logColours(params.monochrome_logs) - Integer num_hidden = 0 - String output = '' - output += 'Typical pipeline command:\n\n' - output += " ${colors.cyan}${command}${colors.reset}\n\n" - Map params_map = paramsLoad(getSchemaPath(workflow, schema_filename=schema_filename)) - Integer max_chars = paramsMaxChars(params_map) + 1 - Integer desc_indent = max_chars + 14 - Integer dec_linewidth = 160 - desc_indent - for (group in params_map.keySet()) { - Integer num_params = 0 - String group_output = colors.underlined + colors.bold + group + colors.reset + '\n' - def group_params = params_map.get(group) // This gets the parameters of that particular group - for (param in group_params.keySet()) { - if (group_params.get(param).hidden && !params.show_hidden_params) { - num_hidden += 1 - continue; - } - def type = '[' + group_params.get(param).type + ']' - def description = group_params.get(param).description - def defaultValue = group_params.get(param).default != null ? " [default: " + group_params.get(param).default.toString() + "]" : '' - def description_default = description + colors.dim + defaultValue + colors.reset - // Wrap long description texts - // Loosely based on https://dzone.com/articles/groovy-plain-text-word-wrap - if (description_default.length() > dec_linewidth){ - List olines = [] - String oline = "" // " " * indent - description_default.split(" ").each() { wrd -> - if ((oline.size() + wrd.size()) <= dec_linewidth) { - oline += wrd + " " - } else { - olines += oline - oline = wrd + " " - } - } - olines += oline - description_default = olines.join("\n" + " " * desc_indent) - } - group_output += " --" + param.padRight(max_chars) + colors.dim + type.padRight(10) + colors.reset + description_default + '\n' - num_params += 1 - } - group_output += '\n' - if (num_params > 0){ - output += group_output - } - } - if (num_hidden > 0){ - output += colors.dim + "!! Hiding $num_hidden params, use --show_hidden_params to show them !!\n" + colors.reset - } - output += NfcoreTemplate.dashedLine(params.monochrome_logs) - return output - } - - // - // Groovy Map summarising parameters/workflow options used by the pipeline - // - public static LinkedHashMap paramsSummaryMap(workflow, params, schema_filename='nextflow_schema.json') { - // Get a selection of core Nextflow workflow options - def Map workflow_summary = [:] - if (workflow.revision) { - workflow_summary['revision'] = workflow.revision - } - workflow_summary['runName'] = workflow.runName - if (workflow.containerEngine) { - workflow_summary['containerEngine'] = workflow.containerEngine - } - if (workflow.container) { - workflow_summary['container'] = workflow.container - } - workflow_summary['launchDir'] = workflow.launchDir - workflow_summary['workDir'] = workflow.workDir - workflow_summary['projectDir'] = workflow.projectDir - workflow_summary['userName'] = workflow.userName - workflow_summary['profile'] = workflow.profile - workflow_summary['configFiles'] = workflow.configFiles.join(', ') - - // Get pipeline parameters defined in JSON Schema - def Map params_summary = [:] - def params_map = paramsLoad(getSchemaPath(workflow, schema_filename=schema_filename)) - for (group in params_map.keySet()) { - def sub_params = new LinkedHashMap() - def group_params = params_map.get(group) // This gets the parameters of that particular group - for (param in group_params.keySet()) { - if (params.containsKey(param)) { - def params_value = params.get(param) - def schema_value = group_params.get(param).default - def param_type = group_params.get(param).type - if (schema_value != null) { - if (param_type == 'string') { - if (schema_value.contains('$projectDir') || schema_value.contains('${projectDir}')) { - def sub_string = schema_value.replace('\$projectDir', '') - sub_string = sub_string.replace('\${projectDir}', '') - if (params_value.contains(sub_string)) { - schema_value = params_value - } - } - if (schema_value.contains('$params.outdir') || schema_value.contains('${params.outdir}')) { - def sub_string = schema_value.replace('\$params.outdir', '') - sub_string = sub_string.replace('\${params.outdir}', '') - if ("${params.outdir}${sub_string}" == params_value) { - schema_value = params_value - } - } - } - } - - // We have a default in the schema, and this isn't it - if (schema_value != null && params_value != schema_value) { - sub_params.put(param, params_value) - } - // No default in the schema, and this isn't empty - else if (schema_value == null && params_value != "" && params_value != null && params_value != false) { - sub_params.put(param, params_value) - } - } - } - params_summary.put(group, sub_params) - } - return [ 'Core Nextflow options' : workflow_summary ] << params_summary - } - - // - // Beautify parameters for summary and return as string - // - public static String paramsSummaryLog(workflow, params) { - Map colors = NfcoreTemplate.logColours(params.monochrome_logs) - String output = '' - def params_map = paramsSummaryMap(workflow, params) - def max_chars = paramsMaxChars(params_map) - for (group in params_map.keySet()) { - def group_params = params_map.get(group) // This gets the parameters of that particular group - if (group_params) { - output += colors.bold + group + colors.reset + '\n' - for (param in group_params.keySet()) { - output += " " + colors.blue + param.padRight(max_chars) + ": " + colors.green + group_params.get(param) + colors.reset + '\n' - } - output += '\n' - } - } - output += "!! Only displaying parameters that differ from the pipeline defaults !!\n" - output += NfcoreTemplate.dashedLine(params.monochrome_logs) - return output - } - - // - // Loop over nested exceptions and print the causingException - // - private static void printExceptions(ex_json, params_json, log, enums, limit=5) { - def causingExceptions = ex_json['causingExceptions'] - if (causingExceptions.length() == 0) { - def m = ex_json['message'] =~ /required key \[([^\]]+)\] not found/ - // Missing required param - if (m.matches()) { - log.error "* Missing required parameter: --${m[0][1]}" - } - // Other base-level error - else if (ex_json['pointerToViolation'] == '#') { - log.error "* ${ex_json['message']}" - } - // Error with specific param - else { - def param = ex_json['pointerToViolation'] - ~/^#\// - def param_val = params_json[param].toString() - if (enums.containsKey(param)) { - def error_msg = "* --${param}: '${param_val}' is not a valid choice (Available choices" - if (enums[param].size() > limit) { - log.error "${error_msg} (${limit} of ${enums[param].size()}): ${enums[param][0..limit-1].join(', ')}, ... )" - } else { - log.error "${error_msg}: ${enums[param].join(', ')})" - } - } else { - log.error "* --${param}: ${ex_json['message']} (${param_val})" - } - } - } - for (ex in causingExceptions) { - printExceptions(ex, params_json, log, enums) - } - } - - // - // Remove an element from a JSONArray - // - private static JSONArray removeElement(json_array, element) { - def list = [] - int len = json_array.length() - for (int i=0;i - if(raw_schema.keySet().contains('definitions')){ - raw_schema.definitions.each { definition -> - for (key in definition.keySet()){ - if (definition[key].get("properties").keySet().contains(ignore_param)){ - // Remove the param to ignore - definition[key].get("properties").remove(ignore_param) - // If the param was required, change this - if (definition[key].has("required")) { - def cleaned_required = removeElement(definition[key].required, ignore_param) - definition[key].put("required", cleaned_required) - } - } - } - } - } - if(raw_schema.keySet().contains('properties') && raw_schema.get('properties').keySet().contains(ignore_param)) { - raw_schema.get("properties").remove(ignore_param) - } - if(raw_schema.keySet().contains('required') && raw_schema.required.contains(ignore_param)) { - def cleaned_required = removeElement(raw_schema.required, ignore_param) - raw_schema.put("required", cleaned_required) - } - } - return raw_schema - } - - // - // Clean and check parameters relative to Nextflow native classes - // - private static Map cleanParameters(params) { - def new_params = params.getClass().newInstance(params) - for (p in params) { - // remove anything evaluating to false - if (!p['value']) { - new_params.remove(p.key) - } - // Cast MemoryUnit to String - if (p['value'].getClass() == nextflow.util.MemoryUnit) { - new_params.replace(p.key, p['value'].toString()) - } - // Cast Duration to String - if (p['value'].getClass() == nextflow.util.Duration) { - new_params.replace(p.key, p['value'].toString().replaceFirst(/d(?!\S)/, "day")) - } - // Cast LinkedHashMap to String - if (p['value'].getClass() == LinkedHashMap) { - new_params.replace(p.key, p['value'].toString()) - } - } - return new_params - } - - // - // This function tries to read a JSON params file - // - private static LinkedHashMap paramsLoad(String json_schema) { - def params_map = new LinkedHashMap() - try { - params_map = paramsRead(json_schema) - } catch (Exception e) { - println "Could not read parameters settings from JSON. $e" - params_map = new LinkedHashMap() - } - return params_map - } - - // - // Method to actually read in JSON file using Groovy. - // Group (as Key), values are all parameters - // - Parameter1 as Key, Description as Value - // - Parameter2 as Key, Description as Value - // .... - // Group - // - - private static LinkedHashMap paramsRead(String json_schema) throws Exception { - def json = new File(json_schema).text - def Map schema_definitions = (Map) new JsonSlurper().parseText(json).get('definitions') - def Map schema_properties = (Map) new JsonSlurper().parseText(json).get('properties') - /* Tree looks like this in nf-core schema - * definitions <- this is what the first get('definitions') gets us - group 1 - title - description - properties - parameter 1 - type - description - parameter 2 - type - description - group 2 - title - description - properties - parameter 1 - type - description - * properties <- parameters can also be ungrouped, outside of definitions - parameter 1 - type - description - */ - - // Grouped params - def params_map = new LinkedHashMap() - schema_definitions.each { key, val -> - def Map group = schema_definitions."$key".properties // Gets the property object of the group - def title = schema_definitions."$key".title - def sub_params = new LinkedHashMap() - group.each { innerkey, value -> - sub_params.put(innerkey, value) - } - params_map.put(title, sub_params) - } - - // Ungrouped params - def ungrouped_params = new LinkedHashMap() - schema_properties.each { innerkey, value -> - ungrouped_params.put(innerkey, value) - } - params_map.put("Other parameters", ungrouped_params) - - return params_map - } - - // - // Get maximum number of characters across all parameter names - // - private static Integer paramsMaxChars(params_map) { - Integer max_chars = 0 - for (group in params_map.keySet()) { - def group_params = params_map.get(group) // This gets the parameters of that particular group - for (param in group_params.keySet()) { - if (param.size() > max_chars) { - max_chars = param.size() - } - } - } - return max_chars - } -} diff --git a/lib/NfcoreTemplate.groovy b/lib/NfcoreTemplate.groovy index 25a0a74a..408951ae 100755 --- a/lib/NfcoreTemplate.groovy +++ b/lib/NfcoreTemplate.groovy @@ -128,7 +128,7 @@ class NfcoreTemplate { def email_html = html_template.toString() // Render the sendmail template - def max_multiqc_email_size = params.max_multiqc_email_size as nextflow.util.MemoryUnit + def max_multiqc_email_size = (params.containsKey('max_multiqc_email_size') ? params.max_multiqc_email_size : 0) as nextflow.util.MemoryUnit def smail_fields = [ email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "$projectDir", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes() ] def sf = new File("$projectDir/assets/sendmail_template.txt") def sendmail_template = engine.createTemplate(sf).make(smail_fields) diff --git a/lib/WorkflowCircrna.groovy b/lib/WorkflowCircrna.groovy index f990810a..e03279a4 100755 --- a/lib/WorkflowCircrna.groovy +++ b/lib/WorkflowCircrna.groovy @@ -11,6 +11,7 @@ class WorkflowCircrna { // Check and validate parameters // public static void initialise(params, log) { + genomeExistsError(params, log) @@ -46,15 +47,57 @@ class WorkflowCircrna { return yaml_file_text } - public static String methodsDescriptionText(run_workflow, mqc_methods_yaml) { + // + // Generate methods description for MultiQC + // + + public static String toolCitationText(params) { + + // TODO Optionally add in-text citation tools to this list. + // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "", + // Uncomment function in methodsDescriptionText to render in MultiQC report + def citation_text = [ + "Tools used in the workflow included:", + "FastQC (Andrews 2010),", + "MultiQC (Ewels et al. 2016)", + "." + ].join(' ').trim() + + return citation_text + } + + public static String toolBibliographyText(params) { + + // TODO Optionally add bibliographic entries to this list. + // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "

  • Author (2023) Pub name, Journal, DOI
  • " : "", + // Uncomment function in methodsDescriptionText to render in MultiQC report + def reference_text = [ + "
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", + "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " + ].join(' ').trim() + + return reference_text + } + + public static String methodsDescriptionText(run_workflow, mqc_methods_yaml, params) { // Convert to a named map so can be used as with familar NXF ${workflow} variable syntax in the MultiQC YML file def meta = [:] meta.workflow = run_workflow.toMap() meta["manifest_map"] = run_workflow.manifest.toMap() + // Pipeline DOI meta["doi_text"] = meta.manifest_map.doi ? "(doi: ${meta.manifest_map.doi})" : "" meta["nodoi_text"] = meta.manifest_map.doi ? "": "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " + // Tool references + meta["tool_citations"] = "" + meta["tool_bibliography"] = "" + + // TODO Only uncomment below if logic in toolCitationText/toolBibliographyText has been filled! + //meta["tool_citations"] = toolCitationText(params).replaceAll(", \\.", ".").replaceAll("\\. \\.", ".").replaceAll(", \\.", ".") + //meta["tool_bibliography"] = toolBibliographyText(params) + + def methods_text = mqc_methods_yaml.text def engine = new SimpleTemplateEngine() diff --git a/lib/WorkflowMain.groovy b/lib/WorkflowMain.groovy index 328c2764..69de09aa 100755 --- a/lib/WorkflowMain.groovy +++ b/lib/WorkflowMain.groovy @@ -20,40 +20,11 @@ class WorkflowMain { " https://github.com/${workflow.manifest.name}/blob/master/CITATIONS.md" } - // - // Generate help string - // - public static String help(workflow, params) { - def command = "nextflow run ${workflow.manifest.name} --input samplesheet.csv --genome GRCh37 -profile docker" - def help_string = '' - help_string += NfcoreTemplate.logo(workflow, params.monochrome_logs) - help_string += NfcoreSchema.paramsHelp(workflow, params, command) - help_string += '\n' + citation(workflow) + '\n' - help_string += NfcoreTemplate.dashedLine(params.monochrome_logs) - return help_string - } - - // - // Generate parameter summary log string - // - public static String paramsSummaryLog(workflow, params) { - def summary_log = '' - summary_log += NfcoreTemplate.logo(workflow, params.monochrome_logs) - summary_log += NfcoreSchema.paramsSummaryLog(workflow, params) - summary_log += '\n' + citation(workflow) + '\n' - summary_log += NfcoreTemplate.dashedLine(params.monochrome_logs) - return summary_log - } // // Validate parameters and print summary to screen // public static void initialise(workflow, params, log) { - // Print help to screen if required - if (params.help) { - log.info help(workflow, params) - System.exit(0) - } // Print workflow version and exit on --version if (params.version) { @@ -62,14 +33,6 @@ class WorkflowMain { System.exit(0) } - // Print parameter summary log to screen - log.info paramsSummaryLog(workflow, params) - - // Validate workflow parameters via the JSON schema - if (params.validate_params) { - NfcoreSchema.validateParameters(workflow, params, log) - } - // Check that a -profile or Nextflow config has been provided to run the pipeline NfcoreTemplate.checkConfigProvided(workflow, log) diff --git a/main.nf b/main.nf index 1c002ad4..2be2de64 100644 --- a/main.nf +++ b/main.nf @@ -25,6 +25,22 @@ params.fasta = WorkflowMain.getGenomeAttribute(params, 'fasta') ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +include { validateParameters; paramsHelp } from 'plugin/nf-validation' + +// Print help message if needed +if (params.help) { + def logo = NfcoreTemplate.logo(workflow, params.monochrome_logs) + def citation = '\n' + WorkflowMain.citation(workflow) + '\n' + def String command = "nextflow run ${workflow.manifest.name} --input samplesheet.csv --genome GRCh37 -profile docker" + log.info logo + paramsHelp(command) + citation + NfcoreTemplate.dashedLine(params.monochrome_logs) + System.exit(0) +} + +// Validate input parameters +if (params.validate_params) { + validateParameters() +} + WorkflowMain.initialise(workflow, params, log) /* diff --git a/nextflow.config b/nextflow.config index 8ab54444..b39e2c9f 100644 --- a/nextflow.config +++ b/nextflow.config @@ -12,12 +12,12 @@ params { // TODO nf-core: Specify your pipeline's command line flags // Input options input = null - - // References genome = null igenomes_base = 's3://ngi-igenomes/igenomes' igenomes_ignore = false + + // MultiQC options multiqc_config = null multiqc_title = null @@ -27,7 +27,6 @@ params { // Boilerplate options outdir = null - tracedir = "${params.outdir}/pipeline_info" publish_dir_mode = 'copy' email = null email_on_fail = null @@ -36,19 +35,15 @@ params { hook_url = null help = false version = false - validate_params = true - show_hidden_params = false - schema_ignore_params = 'genomes' - // Config options + config_profile_name = null + config_profile_description = null custom_config_version = 'master' custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" - config_profile_description = null config_profile_contact = null config_profile_url = null - config_profile_name = null - + // Max resource options // Defaults only, expecting to be overwritten @@ -56,6 +51,13 @@ params { max_cpus = 16 max_time = '240.h' + // Schema validation default options + validationFailUnrecognisedParams = false + validationLenientMode = false + validationSchemaIgnoreParams = 'genomes' + validationShowHiddenParams = false + validate_params = true + } // Load base.config by default for all pipelines @@ -75,13 +77,11 @@ try { // } catch (Exception e) { // System.err.println("WARNING: Could not load nf-core/config/circrna profiles: ${params.custom_config_base}/pipeline/circrna.config") // } - - profiles { debug { dumpHashes = true process.beforeScript = 'echo $HOSTNAME' - cleanup = false + cleanup = false } conda { conda.enabled = true @@ -104,7 +104,6 @@ profiles { } docker { docker.enabled = true - docker.registry = 'quay.io' docker.userEmulation = true conda.enabled = false singularity.enabled = false @@ -128,7 +127,6 @@ profiles { } podman { podman.enabled = true - podman.registry = 'quay.io' conda.enabled = false docker.enabled = false singularity.enabled = false @@ -172,6 +170,18 @@ profiles { test_full { includeConfig 'conf/test_full.config' } } +// Set default registry for Apptainer, Docker, Podman and Singularity independent of -profile +// Will not be used unless Apptainer / Docker / Podman / Singularity are enabled +// Set to your registry if you have a mirror of containers +apptainer.registry = 'quay.io' +docker.registry = 'quay.io' +podman.registry = 'quay.io' +singularity.registry = 'quay.io' + +// Nextflow plugins +plugins { + id 'nf-validation' // Validation of pipeline parameters and creation of an input channel from a sample sheet +} // Load igenomes.config if required if (!params.igenomes_ignore) { @@ -179,8 +189,6 @@ if (!params.igenomes_ignore) { } else { params.genomes = [:] } - - // Export these variables to prevent local Python/R libraries from conflicting with those in the container // The JULIA depot path has been adjusted to a fixed path `/usr/local/share/julia` that needs to be used for packages in the container. // See https://apeltzer.github.io/post/03-julia-lang-nextflow/ for details on that. Once we have a common agreement on where to keep Julia packages, this is adjustable. @@ -198,19 +206,19 @@ process.shell = ['/bin/bash', '-euo', 'pipefail'] def trace_timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') timeline { enabled = true - file = "${params.tracedir}/execution_timeline_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/execution_timeline_${trace_timestamp}.html" } report { enabled = true - file = "${params.tracedir}/execution_report_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/execution_report_${trace_timestamp}.html" } trace { enabled = true - file = "${params.tracedir}/execution_trace_${trace_timestamp}.txt" + file = "${params.outdir}/pipeline_info/execution_trace_${trace_timestamp}.txt" } dag { enabled = true - file = "${params.tracedir}/pipeline_dag_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/pipeline_dag_${trace_timestamp}.html" } manifest { @@ -219,7 +227,7 @@ manifest { homePage = 'https://github.com/nf-core/circrna' description = """Quantification, miRNA target prediction and differential expression analysis of circular RNAs""" mainScript = 'main.nf' - nextflowVersion = '!>=22.10.1' + nextflowVersion = '!>=23.04.0' version = '1.0.0' doi = '' } diff --git a/nextflow_schema.json b/nextflow_schema.json index b225d480..972619c1 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -15,9 +15,9 @@ "input": { "type": "string", "format": "file-path", + "exists": true, "mimetype": "text/csv", "pattern": "^\\S+\\.csv$", - "schema": "assets/schema_input.json", "description": "Path to comma-separated file containing information about the samples in the experiment.", "help_text": "You will need to create a design file with information about the samples in your experiment before running the pipeline. Use this parameter to specify its location. It has to be a comma-separated file with 3 columns, and a header row. See [usage docs](https://nf-co.re/circrna/usage#samplesheet-input).", "fa_icon": "fas fa-file-csv" @@ -57,6 +57,7 @@ "fasta": { "type": "string", "format": "file-path", + "exists": true, "mimetype": "text/plain", "pattern": "^\\S+\\.fn?a(sta)?(\\.gz)?$", "description": "Path to FASTA genome file.", @@ -157,7 +158,7 @@ "description": "Maximum amount of time that can be requested for any single job.", "default": "240.h", "fa_icon": "far fa-clock", - "pattern": "^(\\d+\\.?\\s*(s|m|h|day)\\s*)+$", + "pattern": "^(\\d+\\.?\\s*(s|m|h|d|day)\\s*)+$", "hidden": true, "help_text": "Use to set an upper-limit for the time requirement for each process. Should be a string in the format integer-unit e.g. `--max_time '2.h'`" } @@ -174,12 +175,14 @@ "type": "boolean", "description": "Display help text.", "fa_icon": "fas fa-question-circle", + "default": false, "hidden": true }, "version": { "type": "boolean", "description": "Display version and exit.", "fa_icon": "fas fa-question-circle", + "default": false, "hidden": true }, "publish_dir_mode": { @@ -203,6 +206,7 @@ "type": "boolean", "description": "Send plain-text email instead of HTML.", "fa_icon": "fas fa-remove-format", + "default": false, "hidden": true }, "max_multiqc_email_size": { @@ -217,6 +221,7 @@ "type": "boolean", "description": "Do not use coloured log outputs.", "fa_icon": "fas fa-palette", + "default": false, "hidden": true }, "hook_url": { @@ -228,6 +233,7 @@ }, "multiqc_config": { "type": "string", + "format": "file-path", "description": "Custom config file to supply to MultiQC.", "fa_icon": "fas fa-cog", "hidden": true @@ -243,13 +249,6 @@ "description": "Custom MultiQC yaml file containing HTML including a methods description.", "fa_icon": "fas fa-cog" }, - "tracedir": { - "type": "string", - "description": "Directory to keep pipeline Nextflow logs and reports.", - "default": "${params.outdir}/pipeline_info", - "fa_icon": "fas fa-cogs", - "hidden": true - }, "validate_params": { "type": "boolean", "description": "Boolean whether to validate parameters against the schema at runtime", @@ -257,12 +256,29 @@ "fa_icon": "fas fa-check-square", "hidden": true }, - "show_hidden_params": { + "validationShowHiddenParams": { "type": "boolean", "fa_icon": "far fa-eye-slash", "description": "Show all params when using `--help`", + "default": false, "hidden": true, "help_text": "By default, parameters set as _hidden_ in the schema are not shown on the command line when a user runs with `--help`. Specifying this option will tell the pipeline to show all parameters." + }, + "validationFailUnrecognisedParams": { + "type": "boolean", + "fa_icon": "far fa-check-circle", + "description": "Validation of parameters fails when an unrecognised parameter is found.", + "default": false, + "hidden": true, + "help_text": "By default, when an unrecognised parameter is found, it returns a warinig." + }, + "validationLenientMode": { + "type": "boolean", + "fa_icon": "far fa-check-circle", + "description": "Validation of parameters in lenient more.", + "default": false, + "hidden": true, + "help_text": "Allows string values that are parseable as numbers or booleans. For further information see [JSONSchema docs](https://github.com/everit-org/json-schema#lenient-mode)." } } } diff --git a/workflows/circrna.nf b/workflows/circrna.nf index 448b8fb1..1eaf2c91 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -1,21 +1,19 @@ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - VALIDATE INPUTS + PRINT PARAMS SUMMARY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -def summary_params = NfcoreSchema.paramsSummaryMap(workflow, params) +include { paramsSummaryLog; paramsSummaryMap } from 'plugin/nf-validation' -// Validate input parameters -WorkflowCircrna.initialise(params, log) +def logo = NfcoreTemplate.logo(workflow, params.monochrome_logs) +def citation = '\n' + WorkflowMain.citation(workflow) + '\n' +def summary_params = paramsSummaryMap(workflow) -// TODO nf-core: Add all file path parameters for the pipeline to the list below -// Check input path parameters to see if they exist -def checkPathParamList = [ params.input, params.multiqc_config, params.fasta ] -for (param in checkPathParamList) { if (param) { file(param, checkIfExists: true) } } +// Print parameter summary log to screen +log.info logo + paramsSummaryLog(workflow) + citation -// Check mandatory parameters -if (params.input) { ch_input = file(params.input) } else { exit 1, 'Input samplesheet not specified!' } +WorkflowCircrna.initialise(params, log) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -69,9 +67,12 @@ workflow CIRCRNA { // SUBWORKFLOW: Read in samplesheet, validate and stage input files // INPUT_CHECK ( - ch_input + file(params.input) ) ch_versions = ch_versions.mix(INPUT_CHECK.out.versions) + // TODO: OPTIONAL, you can use nf-validation plugin to create an input channel from the samplesheet with Channel.fromSamplesheet("input") + // See the documentation https://nextflow-io.github.io/nf-validation/samplesheets/fromSamplesheet/ + // ! There is currently no tooling to help you write a sample sheet schema // // MODULE: Run FastQC @@ -91,7 +92,7 @@ workflow CIRCRNA { workflow_summary = WorkflowCircrna.paramsSummaryMultiqc(workflow, summary_params) ch_workflow_summary = Channel.value(workflow_summary) - methods_description = WorkflowCircrna.methodsDescriptionText(workflow, ch_multiqc_custom_methods_description) + methods_description = WorkflowCircrna.methodsDescriptionText(workflow, ch_multiqc_custom_methods_description, params) ch_methods_description = Channel.value(methods_description) ch_multiqc_files = Channel.empty() From 3605257f0b62da4052805955bb1c7cd8e609c94f Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Mon, 25 Sep 2023 15:16:33 +0000 Subject: [PATCH 044/491] Template update for nf-core/tools version 2.10 --- .devcontainer/devcontainer.json | 1 + .github/CONTRIBUTING.md | 4 +- .github/workflows/linting.yml | 2 +- .github/workflows/release-announcments.yml | 68 +++++++++ CITATIONS.md | 2 +- CODE_OF_CONDUCT.md | 133 ++++++++++++++---- README.md | 21 +-- assets/multiqc_config.yml | 6 +- conf/modules.config | 9 ++ docs/output.md | 5 +- docs/usage.md | 16 ++- lib/NfcoreTemplate.groovy | 16 +++ lib/WorkflowCircrna.groovy | 2 +- main.nf | 3 + modules.json | 6 +- .../custom/dumpsoftwareversions/main.nf | 2 +- modules/nf-core/fastqc/main.nf | 8 +- modules/nf-core/multiqc/main.nf | 2 +- nextflow.config | 7 +- nextflow_schema.json | 15 -- workflows/circrna.nf | 1 + 21 files changed, 253 insertions(+), 76 deletions(-) create mode 100644 .github/workflows/release-announcments.yml diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ea27a584..4ecfbfe3 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,6 +2,7 @@ "name": "nfcore", "image": "nfcore/gitpod:latest", "remoteUser": "gitpod", + "runArgs": ["--privileged"], // Configure tool-specific properties. "customizations": { diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index c173003a..4da158df 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -9,7 +9,9 @@ Please use the pre-filled template to save time. However, don't be put off by this template - other more general issues and suggestions are welcome! Contributions to the code are even more welcome ;) -> If you need help using or modifying nf-core/circrna then the best place to ask is on the nf-core Slack [#circrna](https://nfcore.slack.com/channels/circrna) channel ([join our Slack here](https://nf-co.re/join/slack)). +:::info +If you need help using or modifying nf-core/circrna then the best place to ask is on the nf-core Slack [#circrna](https://nfcore.slack.com/channels/circrna) channel ([join our Slack here](https://nf-co.re/join/slack)). +::: ## Contribution workflow diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 888cb4bc..b8bdd214 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -78,7 +78,7 @@ jobs: - uses: actions/setup-python@v4 with: - python-version: "3.8" + python-version: "3.11" architecture: "x64" - name: Install dependencies diff --git a/.github/workflows/release-announcments.yml b/.github/workflows/release-announcments.yml new file mode 100644 index 00000000..6ad33927 --- /dev/null +++ b/.github/workflows/release-announcments.yml @@ -0,0 +1,68 @@ +name: release-announcements +# Automatic release toot and tweet anouncements +on: + release: + types: [published] + workflow_dispatch: + +jobs: + toot: + runs-on: ubuntu-latest + steps: + - uses: rzr/fediverse-action@master + with: + access-token: ${{ secrets.MASTODON_ACCESS_TOKEN }} + host: "mstdn.science" # custom host if not "mastodon.social" (default) + # GitHub event payload + # https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#release + message: | + Pipeline release! ${{ github.repository }} v${{ github.event.release.tag_name }} - ${{ github.event.release.name }}! + + Please see the changelog: ${{ github.event.release.html_url }} + + send-tweet: + runs-on: ubuntu-latest + + steps: + - uses: actions/setup-python@v4 + with: + python-version: "3.10" + - name: Install dependencies + run: pip install tweepy==4.14.0 + - name: Send tweet + shell: python + run: | + import os + import tweepy + + client = tweepy.Client( + access_token=os.getenv("TWITTER_ACCESS_TOKEN"), + access_token_secret=os.getenv("TWITTER_ACCESS_TOKEN_SECRET"), + consumer_key=os.getenv("TWITTER_CONSUMER_KEY"), + consumer_secret=os.getenv("TWITTER_CONSUMER_SECRET"), + ) + tweet = os.getenv("TWEET") + client.create_tweet(text=tweet) + env: + TWEET: | + Pipeline release! ${{ github.repository }} v${{ github.event.release.tag_name }} - ${{ github.event.release.name }}! + + Please see the changelog: ${{ github.event.release.html_url }} + TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }} + TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_SECRET }} + TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }} + TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} + + bsky-post: + runs-on: ubuntu-latest + steps: + - uses: zentered/bluesky-post-action@v0.0.2 + with: + post: | + Pipeline release! ${{ github.repository }} v${{ github.event.release.tag_name }} - ${{ github.event.release.name }}! + + Please see the changelog: ${{ github.event.release.html_url }} + env: + BSKY_IDENTIFIER: ${{ secrets.BSKY_IDENTIFIER }} + BSKY_PASSWORD: ${{ secrets.BSKY_PASSWORD }} + # diff --git a/CITATIONS.md b/CITATIONS.md index c3be1aad..fb3c1f6e 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -12,7 +12,7 @@ - [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) - > Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. Available online https://www.bioinformatics.babraham.ac.uk/projects/fastqc/. + > Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. - [MultiQC](https://pubmed.ncbi.nlm.nih.gov/27312411/) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index f4fd052f..c089ec78 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,18 +1,20 @@ -# Code of Conduct at nf-core (v1.0) +# Code of Conduct at nf-core (v1.4) ## Our Pledge -In the interest of fostering an open, collaborative, and welcoming environment, we as contributors and maintainers of nf-core, pledge to making participation in our projects and community a harassment-free experience for everyone, regardless of: +In the interest of fostering an open, collaborative, and welcoming environment, we as contributors and maintainers of nf-core pledge to making participation in our projects and community a harassment-free experience for everyone, regardless of: - Age +- Ability - Body size +- Caste - Familial status - Gender identity and expression - Geographical location - Level of experience - Nationality and national origins - Native language -- Physical and neurological ability +- Neurodiversity - Race or ethnicity - Religion - Sexual identity and orientation @@ -22,80 +24,133 @@ Please note that the list above is alphabetised and is therefore not ranked in a ## Preamble -> Note: This Code of Conduct (CoC) has been drafted by the nf-core Safety Officer and been edited after input from members of the nf-core team and others. "We", in this document, refers to the Safety Officer and members of the nf-core core team, both of whom are deemed to be members of the nf-core community and are therefore required to abide by this Code of Conduct. This document will amended periodically to keep it up-to-date, and in case of any dispute, the most current version will apply. +:::note +This Code of Conduct (CoC) has been drafted by Renuka Kudva, Cris Tuñí, and Michael Heuer, with input from the nf-core Core Team and Susanna Marquez from the nf-core community. "We", in this document, refers to the Safety Officers and members of the nf-core Core Team, both of whom are deemed to be members of the nf-core community and are therefore required to abide by this Code of Conduct. This document will be amended periodically to keep it up-to-date. In case of any dispute, the most current version will apply. +::: -An up-to-date list of members of the nf-core core team can be found [here](https://nf-co.re/about). Our current safety officer is Renuka Kudva. +An up-to-date list of members of the nf-core core team can be found [here](https://nf-co.re/about). + +Our Safety Officers are Saba Nafees, Cris Tuñí, and Michael Heuer. nf-core is a young and growing community that welcomes contributions from anyone with a shared vision for [Open Science Policies](https://www.fosteropenscience.eu/taxonomy/term/8). Open science policies encompass inclusive behaviours and we strive to build and maintain a safe and inclusive environment for all individuals. -We have therefore adopted this code of conduct (CoC), which we require all members of our community and attendees in nf-core events to adhere to in all our workspaces at all times. Workspaces include but are not limited to Slack, meetings on Zoom, Jitsi, YouTube live etc. +We have therefore adopted this CoC, which we require all members of our community and attendees of nf-core events to adhere to in all our workspaces at all times. Workspaces include, but are not limited to, Slack, meetings on Zoom, gather.town, YouTube live etc. -Our CoC will be strictly enforced and the nf-core team reserve the right to exclude participants who do not comply with our guidelines from our workspaces and future nf-core activities. +Our CoC will be strictly enforced and the nf-core team reserves the right to exclude participants who do not comply with our guidelines from our workspaces and future nf-core activities. -We ask all members of our community to help maintain a supportive and productive workspace and to avoid behaviours that can make individuals feel unsafe or unwelcome. Please help us maintain and uphold this CoC. +We ask all members of our community to help maintain supportive and productive workspaces and to avoid behaviours that can make individuals feel unsafe or unwelcome. Please help us maintain and uphold this CoC. -Questions, concerns or ideas on what we can include? Contact safety [at] nf-co [dot] re +Questions, concerns, or ideas on what we can include? Contact members of the Safety Team on Slack or email safety [at] nf-co [dot] re. ## Our Responsibilities -The safety officer is responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behaviour. +Members of the Safety Team (the Safety Officers) are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behaviour. -The safety officer in consultation with the nf-core core team have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. +The Safety Team, in consultation with the nf-core core team, have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this CoC, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. -Members of the core team or the safety officer who violate the CoC will be required to recuse themselves pending investigation. They will not have access to any reports of the violations and be subject to the same actions as others in violation of the CoC. +Members of the core team or the Safety Team who violate the CoC will be required to recuse themselves pending investigation. They will not have access to any reports of the violations and will be subject to the same actions as others in violation of the CoC. -## When are where does this Code of Conduct apply? +## When and where does this Code of Conduct apply? -Participation in the nf-core community is contingent on following these guidelines in all our workspaces and events. This includes but is not limited to the following listed alphabetically and therefore in no order of preference: +Participation in the nf-core community is contingent on following these guidelines in all our workspaces and events, such as hackathons, workshops, bytesize, and collaborative workspaces on gather.town. These guidelines include, but are not limited to, the following (listed alphabetically and therefore in no order of preference): - Communicating with an official project email address. - Communicating with community members within the nf-core Slack channel. - Participating in hackathons organised by nf-core (both online and in-person events). -- Participating in collaborative work on GitHub, Google Suite, community calls, mentorship meetings, email correspondence. -- Participating in workshops, training, and seminar series organised by nf-core (both online and in-person events). This applies to events hosted on web-based platforms such as Zoom, Jitsi, YouTube live etc. +- Participating in collaborative work on GitHub, Google Suite, community calls, mentorship meetings, email correspondence, and on the nf-core gather.town workspace. +- Participating in workshops, training, and seminar series organised by nf-core (both online and in-person events). This applies to events hosted on web-based platforms such as Zoom, gather.town, Jitsi, YouTube live etc. - Representing nf-core on social media. This includes both official and personal accounts. ## nf-core cares 😊 -nf-core's CoC and expectations of respectful behaviours for all participants (including organisers and the nf-core team) include but are not limited to the following (listed in alphabetical order): +nf-core's CoC and expectations of respectful behaviours for all participants (including organisers and the nf-core team) include, but are not limited to, the following (listed in alphabetical order): - Ask for consent before sharing another community member’s personal information (including photographs) on social media. - Be respectful of differing viewpoints and experiences. We are all here to learn from one another and a difference in opinion can present a good learning opportunity. -- Celebrate your accomplishments at events! (Get creative with your use of emojis 🎉 🥳 💯 🙌 !) +- Celebrate your accomplishments! (Get creative with your use of emojis 🎉 🥳 💯 🙌 !) - Demonstrate empathy towards other community members. (We don’t all have the same amount of time to dedicate to nf-core. If tasks are pending, don’t hesitate to gently remind members of your team. If you are leading a task, ask for help if you feel overwhelmed.) - Engage with and enquire after others. (This is especially important given the geographically remote nature of the nf-core community, so let’s do this the best we can) - Focus on what is best for the team and the community. (When in doubt, ask) -- Graciously accept constructive criticism, yet be unafraid to question, deliberate, and learn. +- Accept feedback, yet be unafraid to question, deliberate, and learn. - Introduce yourself to members of the community. (We’ve all been outsiders and we know that talking to strangers can be hard for some, but remember we’re interested in getting to know you and your visions for open science!) -- Show appreciation and **provide clear feedback**. (This is especially important because we don’t see each other in person and it can be harder to interpret subtleties. Also remember that not everyone understands a certain language to the same extent as you do, so **be clear in your communications to be kind.**) +- Show appreciation and **provide clear feedback**. (This is especially important because we don’t see each other in person and it can be harder to interpret subtleties. Also remember that not everyone understands a certain language to the same extent as you do, so **be clear in your communication to be kind.**) - Take breaks when you feel like you need them. -- Using welcoming and inclusive language. (Participants are encouraged to display their chosen pronouns on Zoom or in communication on Slack.) +- Use welcoming and inclusive language. (Participants are encouraged to display their chosen pronouns on Zoom or in communication on Slack) ## nf-core frowns on 😕 -The following behaviours from any participants within the nf-core community (including the organisers) will be considered unacceptable under this code of conduct. Engaging or advocating for any of the following could result in expulsion from nf-core workspaces. +The following behaviours from any participants within the nf-core community (including the organisers) will be considered unacceptable under this CoC. Engaging or advocating for any of the following could result in expulsion from nf-core workspaces: - Deliberate intimidation, stalking or following and sustained disruption of communication among participants of the community. This includes hijacking shared screens through actions such as using the annotate tool in conferencing software such as Zoom. - “Doxing” i.e. posting (or threatening to post) another person’s personal identifying information online. - Spamming or trolling of individuals on social media. -- Use of sexual or discriminatory imagery, comments, or jokes and unwelcome sexual attention. -- Verbal and text comments that reinforce social structures of domination related to gender, gender identity and expression, sexual orientation, ability, physical appearance, body size, race, age, religion or work experience. +- Use of sexual or discriminatory imagery, comments, jokes, or unwelcome sexual attention. +- Verbal and text comments that reinforce social structures of domination related to gender, gender identity and expression, sexual orientation, ability, physical appearance, body size, race, age, religion, or work experience. ### Online Trolling -The majority of nf-core interactions and events are held online. Unfortunately, holding events online comes with the added issue of online trolling. This is unacceptable, reports of such behaviour will be taken very seriously, and perpetrators will be excluded from activities immediately. +The majority of nf-core interactions and events are held online. Unfortunately, holding events online comes with the risk of online trolling. This is unacceptable — reports of such behaviour will be taken very seriously and perpetrators will be excluded from activities immediately. -All community members are required to ask members of the group they are working within for explicit consent prior to taking screenshots of individuals during video calls. +All community members are **required** to ask members of the group they are working with for explicit consent prior to taking screenshots of individuals during video calls. -## Procedures for Reporting CoC violations +## Procedures for reporting CoC violations If someone makes you feel uncomfortable through their behaviours or actions, report it as soon as possible. -You can reach out to members of the [nf-core core team](https://nf-co.re/about) and they will forward your concerns to the safety officer(s). +You can reach out to members of the Safety Team (Saba Nafees, Cris Tuñí, and Michael Heuer) on Slack. Alternatively, contact a member of the nf-core core team [nf-core core team](https://nf-co.re/about), and they will forward your concerns to the Safety Team. + +Issues directly concerning members of the Core Team or the Safety Team will be dealt with by other members of the core team and the safety manager — possible conflicts of interest will be taken into account. nf-core is also in discussions about having an ombudsperson and details will be shared in due course. + +All reports will be handled with the utmost discretion and confidentiality. + +You can also report any CoC violations to safety [at] nf-co [dot] re. In your email report, please do your best to include: + +- Your contact information. +- Identifying information (e.g. names, nicknames, pseudonyms) of the participant who has violated the Code of Conduct. +- The behaviour that was in violation and the circumstances surrounding the incident. +- The approximate time of the behaviour (if different than the time the report was made). +- Other people involved in the incident, if applicable. +- If you believe the incident is ongoing. +- If there is a publicly available record (e.g. mailing list record, a screenshot). +- Any additional information. + +After you file a report, one or more members of our Safety Team will contact you to follow up on your report. + +## Who will read and handle reports + +All reports will be read and handled by the members of the Safety Team at nf-core. + +If members of the Safety Team are deemed to have a conflict of interest with a report, they will be required to recuse themselves as per our Code of Conduct and will not have access to any follow-ups. + +To keep this first report confidential from any of the Safety Team members, please submit your first report by direct messaging on Slack/direct email to any of the nf-core members you are comfortable disclosing the information to, and be explicit about which member(s) you do not consent to sharing the information with. + +## Reviewing reports + +After receiving the report, members of the Safety Team will review the incident report to determine whether immediate action is required, for example, whether there is immediate threat to participants’ safety. + +The Safety Team, in consultation with members of the nf-core core team, will assess the information to determine whether the report constitutes a Code of Conduct violation, for them to decide on a course of action. + +In the case of insufficient information, one or more members of the Safety Team may contact the reporter, the reportee, or any other attendees to obtain more information. -Issues directly concerning members of the core team will be dealt with by other members of the core team and the safety manager, and possible conflicts of interest will be taken into account. nf-core is also in discussions about having an ombudsperson, and details will be shared in due course. +Once additional information is gathered, the Safety Team will collectively review and decide on the best course of action to take, if any. The Safety Team reserves the right to not act on a report. -All reports will be handled with utmost discretion and confidentially. +## Confidentiality + +All reports, and any additional information included, are only shared with the team of safety officers (and possibly members of the core team, in case the safety officer is in violation of the CoC). We will respect confidentiality requests for the purpose of protecting victims of abuse. + +We will not name harassment victims, beyond discussions between the safety officer and members of the nf-core team, without the explicit consent of the individuals involved. + +## Enforcement + +Actions taken by the nf-core’s Safety Team may include, but are not limited to: + +- Asking anyone to stop a behaviour. +- Asking anyone to leave the event and online spaces either temporarily, for the remainder of the event, or permanently. +- Removing access to the gather.town and Slack, either temporarily or permanently. +- Communicating to all participants to reinforce our expectations for conduct and remind what is unacceptable behaviour; this may be public for practical reasons. +- Communicating to all participants that an incident has taken place and how we will act or have acted — this may be for the purpose of letting event participants know we are aware of and dealing with the incident. +- Banning anyone from participating in nf-core-managed spaces, future events, and activities, either temporarily or permanently. +- No action. ## Attribution and Acknowledgements @@ -106,6 +161,22 @@ All reports will be handled with utmost discretion and confidentially. ## Changelog -### v1.0 - March 12th, 2021 +### v1.4 - February 8th, 2022 + +- Included a new member of the Safety Team. Corrected a typographical error in the text. + +### v1.3 - December 10th, 2021 + +- Added a statement that the CoC applies to nf-core gather.town workspaces. Corrected typographical errors in the text. + +### v1.2 - November 12th, 2021 + +- Removed information specific to reporting CoC violations at the Hackathon in October 2021. + +### v1.1 - October 14th, 2021 + +- Updated with names of new Safety Officers and specific information for the hackathon in October 2021. + +### v1.0 - March 15th, 2021 - Complete rewrite from original [Contributor Covenant](http://contributor-covenant.org/) CoC. diff --git a/README.md b/README.md index 12e662ff..57b75df6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # ![nf-core/circrna](docs/images/nf-core-circrna_logo_light.png#gh-light-mode-only) ![nf-core/circrna](docs/images/nf-core-circrna_logo_dark.png#gh-dark-mode-only) -[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/circrna/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) +[![GitHub Actions CI Status](https://github.com/nf-core/circrna/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/circrna/actions?query=workflow%3A%22nf-core+CI%22) +[![GitHub Actions Linting Status](https://github.com/nf-core/circrna/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/circrna/actions?query=workflow%3A%22nf-core+linting%22)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/circrna/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) [![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A523.04.0-23aa62.svg)](https://www.nextflow.io/) [![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) @@ -29,10 +30,11 @@ ## Usage -> **Note** -> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how -> to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) -> with `-profile test` before running the workflow on actual data. +:::note +If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how +to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) +with `-profile test` before running the workflow on actual data. +::: - + diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index 177ece08..9a1b5bda 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,9 +1,7 @@ report_comment: > - - This report has been generated by the nf-core/circrna + This report has been generated by the nf-core/circrna analysis pipeline. For information about how to interpret these results, please see the - documentation. - + documentation. report_section_order: "nf-core-circrna-methods-description": order: -1000 diff --git a/assets/slackreport.json b/assets/slackreport.json index b6be7a75..aa925620 100644 --- a/assets/slackreport.json +++ b/assets/slackreport.json @@ -3,7 +3,7 @@ { "fallback": "Plain-text summary of the attachment.", "color": "<% if (success) { %>good<% } else { %>danger<%} %>", - "author_name": "nf-core/circrna v${version} - ${runName}", + "author_name": "nf-core/circrna ${version} - ${runName}", "author_icon": "https://www.nextflow.io/docs/latest/_static/favicon.ico", "text": "<% if (success) { %>Pipeline completed successfully!<% } else { %>Pipeline completed with errors<% } %>", "fields": [ diff --git a/conf/modules.config b/conf/modules.config index 39e81386..d91c6aba 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -39,7 +39,7 @@ process { } withName: 'MULTIQC' { - ext.args = params.multiqc_title ? "--title \"$params.multiqc_title\"" : '' + ext.args = { params.multiqc_title ? "--title \"$params.multiqc_title\"" : '' } publishDir = [ path: { "${params.outdir}/multiqc" }, mode: params.publish_dir_mode, diff --git a/docs/usage.md b/docs/usage.md index 9be6ccc4..8960ea47 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -20,7 +20,7 @@ You will need to create a samplesheet with information about the samples you wou The `sample` identifiers have to be the same when you have re-sequenced the same sample more than once e.g. to increase sequencing depth. The pipeline will concatenate the raw reads before performing any downstream analysis. Below is an example for the same sample sequenced across 3 lanes: -```console +```csv title="samplesheet.csv" sample,fastq_1,fastq_2 CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz CONTROL_REP1,AEG588A1_S1_L003_R1_001.fastq.gz,AEG588A1_S1_L003_R2_001.fastq.gz @@ -33,7 +33,7 @@ The pipeline will auto-detect whether a sample is single- or paired-end using th A final samplesheet file consisting of both single- and paired-end data may look something like the one below. This is for 6 samples, where `TREATMENT_REP3` has been sequenced twice. -```console +```csv title="samplesheet.csv" sample,fastq_1,fastq_2 CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz CONTROL_REP2,AEG588A2_S2_L002_R1_001.fastq.gz,AEG588A2_S2_L002_R2_001.fastq.gz diff --git a/lib/NfcoreTemplate.groovy b/lib/NfcoreTemplate.groovy index 01b8653d..e248e4c3 100755 --- a/lib/NfcoreTemplate.groovy +++ b/lib/NfcoreTemplate.groovy @@ -4,6 +4,7 @@ import org.yaml.snakeyaml.Yaml import groovy.json.JsonOutput +import nextflow.extension.FilesEx class NfcoreTemplate { @@ -141,12 +142,14 @@ class NfcoreTemplate { try { if (params.plaintext_email) { throw GroovyException('Send plaintext e-mail, not HTML') } // Try to send HTML e-mail using sendmail + def sendmail_tf = new File(workflow.launchDir.toString(), ".sendmail_tmp.html") + sendmail_tf.withWriter { w -> w << sendmail_html } [ 'sendmail', '-t' ].execute() << sendmail_html log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Sent summary e-mail to $email_address (sendmail)-" } catch (all) { // Catch failures and try with plaintext def mail_cmd = [ 'mail', '-s', subject, '--content-type=text/html', email_address ] - if ( mqc_report.size() <= max_multiqc_email_size.toBytes() ) { + if ( mqc_report != null && mqc_report.size() <= max_multiqc_email_size.toBytes() ) { mail_cmd += [ '-A', mqc_report ] } mail_cmd.execute() << email_html @@ -155,14 +158,16 @@ class NfcoreTemplate { } // Write summary e-mail HTML to a file - def output_d = new File("${params.outdir}/pipeline_info/") - if (!output_d.exists()) { - output_d.mkdirs() - } - def output_hf = new File(output_d, "pipeline_report.html") + def output_hf = new File(workflow.launchDir.toString(), ".pipeline_report.html") output_hf.withWriter { w -> w << email_html } - def output_tf = new File(output_d, "pipeline_report.txt") + FilesEx.copyTo(output_hf.toPath(), "${params.outdir}/pipeline_info/pipeline_report.html"); + output_hf.delete() + + // Write summary e-mail TXT to a file + def output_tf = new File(workflow.launchDir.toString(), ".pipeline_report.txt") output_tf.withWriter { w -> w << email_txt } + FilesEx.copyTo(output_tf.toPath(), "${params.outdir}/pipeline_info/pipeline_report.txt"); + output_tf.delete() } // @@ -227,15 +232,14 @@ class NfcoreTemplate { // Dump pipeline parameters in a json file // public static void dump_parameters(workflow, params) { - def output_d = new File("${params.outdir}/pipeline_info/") - if (!output_d.exists()) { - output_d.mkdirs() - } - def timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') - def output_pf = new File(output_d, "params_${timestamp}.json") + def filename = "params_${timestamp}.json" + def temp_pf = new File(workflow.launchDir.toString(), ".${filename}") def jsonStr = JsonOutput.toJson(params) - output_pf.text = JsonOutput.prettyPrint(jsonStr) + temp_pf.text = JsonOutput.prettyPrint(jsonStr) + + FilesEx.copyTo(temp_pf.toPath(), "${params.outdir}/pipeline_info/params_${timestamp}.json") + temp_pf.delete() } // diff --git a/modules.json b/modules.json index 21badbb0..0452434d 100644 --- a/modules.json +++ b/modules.json @@ -7,17 +7,17 @@ "nf-core": { "custom/dumpsoftwareversions": { "branch": "master", - "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", + "git_sha": "bba7e362e4afead70653f84d8700588ea28d0f9e", "installed_by": ["modules"] }, "fastqc": { "branch": "master", - "git_sha": "bd8092b67b5103bdd52e300f75889442275c3117", + "git_sha": "65ad3e0b9a4099592e1102e92e10455dc661cf53", "installed_by": ["modules"] }, "multiqc": { "branch": "master", - "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", + "git_sha": "4ab13872435962dadc239979554d13709e20bf29", "installed_by": ["modules"] } } diff --git a/modules/nf-core/custom/dumpsoftwareversions/environment.yml b/modules/nf-core/custom/dumpsoftwareversions/environment.yml new file mode 100644 index 00000000..f0c63f69 --- /dev/null +++ b/modules/nf-core/custom/dumpsoftwareversions/environment.yml @@ -0,0 +1,7 @@ +name: custom_dumpsoftwareversions +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::multiqc=1.17 diff --git a/modules/nf-core/custom/dumpsoftwareversions/main.nf b/modules/nf-core/custom/dumpsoftwareversions/main.nf index ebc87273..7685b33c 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/main.nf +++ b/modules/nf-core/custom/dumpsoftwareversions/main.nf @@ -2,10 +2,10 @@ process CUSTOM_DUMPSOFTWAREVERSIONS { label 'process_single' // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container - conda "bioconda::multiqc=1.14" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.14--pyhdfd78af_0' : - 'biocontainers/multiqc:1.14--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.17--pyhdfd78af_0' : + 'biocontainers/multiqc:1.17--pyhdfd78af_0' }" input: path versions diff --git a/modules/nf-core/custom/dumpsoftwareversions/meta.yml b/modules/nf-core/custom/dumpsoftwareversions/meta.yml index c32657de..5f15a5fd 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/meta.yml +++ b/modules/nf-core/custom/dumpsoftwareversions/meta.yml @@ -1,4 +1,4 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/yaml-schema.json +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json name: custom_dumpsoftwareversions description: Custom module used to dump software versions within the nf-core pipeline template keywords: @@ -16,7 +16,6 @@ input: type: file description: YML file containing software versions pattern: "*.yml" - output: - yml: type: file @@ -30,7 +29,9 @@ output: type: file description: File containing software versions pattern: "versions.yml" - authors: - "@drpatelh" - "@grst" +maintainers: + - "@drpatelh" + - "@grst" diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test new file mode 100644 index 00000000..eec1db10 --- /dev/null +++ b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test @@ -0,0 +1,38 @@ +nextflow_process { + + name "Test Process CUSTOM_DUMPSOFTWAREVERSIONS" + script "../main.nf" + process "CUSTOM_DUMPSOFTWAREVERSIONS" + tag "modules" + tag "modules_nfcore" + tag "custom" + tag "dumpsoftwareversions" + tag "custom/dumpsoftwareversions" + + test("Should run without failures") { + when { + process { + """ + def tool1_version = ''' + TOOL1: + tool1: 0.11.9 + '''.stripIndent() + + def tool2_version = ''' + TOOL2: + tool2: 1.9 + '''.stripIndent() + + input[0] = Channel.of(tool1_version, tool2_version).collectFile() + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } +} diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap new file mode 100644 index 00000000..4274ed57 --- /dev/null +++ b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap @@ -0,0 +1,27 @@ +{ + "Should run without failures": { + "content": [ + { + "0": [ + "software_versions.yml:md5,1c851188476409cda5752ce971b20b58" + ], + "1": [ + "software_versions_mqc.yml:md5,2570f4ba271ad08357b0d3d32a9cf84d" + ], + "2": [ + "versions.yml:md5,3843ac526e762117eedf8825b40683df" + ], + "mqc_yml": [ + "software_versions_mqc.yml:md5,2570f4ba271ad08357b0d3d32a9cf84d" + ], + "versions": [ + "versions.yml:md5,3843ac526e762117eedf8825b40683df" + ], + "yml": [ + "software_versions.yml:md5,1c851188476409cda5752ce971b20b58" + ] + } + ], + "timestamp": "2023-11-03T14:43:22.157011" + } +} diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml b/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml new file mode 100644 index 00000000..405aa24a --- /dev/null +++ b/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml @@ -0,0 +1,2 @@ +custom/dumpsoftwareversions: + - modules/nf-core/custom/dumpsoftwareversions/** diff --git a/modules/nf-core/fastqc/environment.yml b/modules/nf-core/fastqc/environment.yml new file mode 100644 index 00000000..1787b38a --- /dev/null +++ b/modules/nf-core/fastqc/environment.yml @@ -0,0 +1,7 @@ +name: fastqc +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::fastqc=0.12.1 diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf index 249f9064..9e19a74c 100644 --- a/modules/nf-core/fastqc/main.nf +++ b/modules/nf-core/fastqc/main.nf @@ -2,10 +2,10 @@ process FASTQC { tag "$meta.id" label 'process_medium' - conda "bioconda::fastqc=0.11.9" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/fastqc:0.11.9--0' : - 'biocontainers/fastqc:0.11.9--0' }" + 'https://depot.galaxyproject.org/singularity/fastqc:0.12.1--hdfd78af_0' : + 'biocontainers/fastqc:0.12.1--hdfd78af_0' }" input: tuple val(meta), path(reads) @@ -37,7 +37,7 @@ process FASTQC { cat <<-END_VERSIONS > versions.yml "${task.process}": - fastqc: \$( fastqc --version | sed -e "s/FastQC v//g" ) + fastqc: \$( fastqc --version | sed '/FastQC v/!d; s/.*v//' ) END_VERSIONS """ @@ -49,7 +49,7 @@ process FASTQC { cat <<-END_VERSIONS > versions.yml "${task.process}": - fastqc: \$( fastqc --version | sed -e "s/FastQC v//g" ) + fastqc: \$( fastqc --version | sed '/FastQC v/!d; s/.*v//' ) END_VERSIONS """ } diff --git a/modules/nf-core/fastqc/meta.yml b/modules/nf-core/fastqc/meta.yml index 4da5bb5a..ee5507e0 100644 --- a/modules/nf-core/fastqc/meta.yml +++ b/modules/nf-core/fastqc/meta.yml @@ -50,3 +50,8 @@ authors: - "@grst" - "@ewels" - "@FelixKrueger" +maintainers: + - "@drpatelh" + - "@grst" + - "@ewels" + - "@FelixKrueger" diff --git a/modules/nf-core/fastqc/tests/main.nf.test b/modules/nf-core/fastqc/tests/main.nf.test new file mode 100644 index 00000000..b9e8f926 --- /dev/null +++ b/modules/nf-core/fastqc/tests/main.nf.test @@ -0,0 +1,109 @@ +nextflow_process { + + name "Test Process FASTQC" + script "../main.nf" + process "FASTQC" + tag "modules" + tag "modules_nfcore" + tag "fastqc" + + test("Single-Read") { + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = [ + [ id: 'test', single_end:true ], + [ + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + ] + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + // NOTE The report contains the date inside it, which means that the md5sum is stable per day, but not longer than that. So you can't md5sum it. + // looks like this:
    Mon 2 Oct 2023
    test.gz
    + // https://github.com/nf-core/modules/pull/3903#issuecomment-1743620039 + { assert process.out.html.get(0).get(1) ==~ ".*/test_fastqc.html" }, + { assert path(process.out.html.get(0).get(1)).getText().contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match("versions") }, + { assert process.out.zip.get(0).get(1) ==~ ".*/test_fastqc.zip" } + ) + } + } +// TODO +// // +// // Test with paired-end data +// // +// workflow test_fastqc_paired_end { +// input = [ +// [id: 'test', single_end: false], // meta map +// [ +// file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), +// file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) +// ] +// ] + +// FASTQC ( input ) +// } + +// // +// // Test with interleaved data +// // +// workflow test_fastqc_interleaved { +// input = [ +// [id: 'test', single_end: false], // meta map +// file(params.test_data['sarscov2']['illumina']['test_interleaved_fastq_gz'], checkIfExists: true) +// ] + +// FASTQC ( input ) +// } + +// // +// // Test with bam data +// // +// workflow test_fastqc_bam { +// input = [ +// [id: 'test', single_end: false], // meta map +// file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) +// ] + +// FASTQC ( input ) +// } + +// // +// // Test with multiple samples +// // +// workflow test_fastqc_multiple { +// input = [ +// [id: 'test', single_end: false], // meta map +// [ +// file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), +// file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true), +// file(params.test_data['sarscov2']['illumina']['test2_1_fastq_gz'], checkIfExists: true), +// file(params.test_data['sarscov2']['illumina']['test2_2_fastq_gz'], checkIfExists: true) +// ] +// ] + +// FASTQC ( input ) +// } + +// // +// // Test with custom prefix +// // +// workflow test_fastqc_custom_prefix { +// input = [ +// [ id:'mysample', single_end:true ], // meta map +// file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) +// ] + +// FASTQC ( input ) +// } +} diff --git a/modules/nf-core/fastqc/tests/main.nf.test.snap b/modules/nf-core/fastqc/tests/main.nf.test.snap new file mode 100644 index 00000000..636a32ce --- /dev/null +++ b/modules/nf-core/fastqc/tests/main.nf.test.snap @@ -0,0 +1,10 @@ +{ + "versions": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "timestamp": "2023-10-09T23:40:54+0000" + } +} \ No newline at end of file diff --git a/modules/nf-core/fastqc/tests/tags.yml b/modules/nf-core/fastqc/tests/tags.yml new file mode 100644 index 00000000..7834294b --- /dev/null +++ b/modules/nf-core/fastqc/tests/tags.yml @@ -0,0 +1,2 @@ +fastqc: + - modules/nf-core/fastqc/** diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml new file mode 100644 index 00000000..bc0bdb5b --- /dev/null +++ b/modules/nf-core/multiqc/environment.yml @@ -0,0 +1,7 @@ +name: multiqc +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::multiqc=1.18 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 1fc387be..00cc48d2 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,10 +1,10 @@ process MULTIQC { label 'process_single' - conda "bioconda::multiqc=1.14" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.14--pyhdfd78af_0' : - 'biocontainers/multiqc:1.14--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.18--pyhdfd78af_0' : + 'biocontainers/multiqc:1.18--pyhdfd78af_0' }" input: path multiqc_files, stageAs: "?/*" @@ -25,12 +25,14 @@ process MULTIQC { def args = task.ext.args ?: '' def config = multiqc_config ? "--config $multiqc_config" : '' def extra_config = extra_multiqc_config ? "--config $extra_multiqc_config" : '' + def logo = multiqc_logo ? /--cl-config 'custom_logo: "${multiqc_logo}"'/ : '' """ multiqc \\ --force \\ $args \\ $config \\ $extra_config \\ + $logo \\ . cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index f93b5ee5..f1aa660e 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -1,5 +1,5 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/yaml-schema.json -name: MultiQC +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json +name: multiqc description: Aggregate results from bioinformatics analyses across many samples into a single report keywords: - QC @@ -13,7 +13,6 @@ tools: homepage: https://multiqc.info/ documentation: https://multiqc.info/docs/ licence: ["GPL-3.0-or-later"] - input: - multiqc_files: type: file @@ -31,7 +30,6 @@ input: type: file description: Optional logo file for MultiQC pattern: "*.{png}" - output: - report: type: file @@ -54,3 +52,8 @@ authors: - "@bunop" - "@drpatelh" - "@jfy133" +maintainers: + - "@abhi18av" + - "@bunop" + - "@drpatelh" + - "@jfy133" diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test new file mode 100644 index 00000000..c2dad217 --- /dev/null +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -0,0 +1,63 @@ +nextflow_process { + + name "Test Process MULTIQC" + script "../main.nf" + process "MULTIQC" + tag "modules" + tag "modules_nfcore" + tag "multiqc" + + test("MULTIQC: FASTQC") { + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)]) + input[1] = [] + input[2] = [] + input[3] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert path(process.out.report.get(0)).exists() }, + { assert path(process.out.data.get(0)).exists() }, + { assert path(process.out.versions.get(0)).getText().contains("multiqc") } + ) + } + + } + + test("MULTIQC: FASTQC and a config file") { + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)]) + input[1] = Channel.of(file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true)) + input[2] = [] + input[3] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert path(process.out.report.get(0)).exists() }, + { assert path(process.out.data.get(0)).exists() }, + { assert path(process.out.versions.get(0)).getText().contains("multiqc") } + ) + } + + } +} diff --git a/modules/nf-core/multiqc/tests/tags.yml b/modules/nf-core/multiqc/tests/tags.yml new file mode 100644 index 00000000..bea6c0d3 --- /dev/null +++ b/modules/nf-core/multiqc/tests/tags.yml @@ -0,0 +1,2 @@ +multiqc: + - modules/nf-core/multiqc/** diff --git a/nextflow.config b/nextflow.config index 2dac3ee7..3893e1a3 100644 --- a/nextflow.config +++ b/nextflow.config @@ -14,7 +14,7 @@ params { input = null // References genome = null - igenomes_base = 's3://ngi-igenomes/igenomes' + igenomes_base = 's3://ngi-igenomes/igenomes/' igenomes_ignore = false @@ -82,6 +82,7 @@ profiles { dumpHashes = true process.beforeScript = 'echo $HOSTNAME' cleanup = false + nextflow.enable.configProcessNamesValidation = true } conda { conda.enabled = true @@ -104,13 +105,13 @@ profiles { } docker { docker.enabled = true - docker.userEmulation = true conda.enabled = false singularity.enabled = false podman.enabled = false shifter.enabled = false charliecloud.enabled = false apptainer.enabled = false + runOptions = '-u $(id -u):$(id -g)' } arm { docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' @@ -181,7 +182,7 @@ singularity.registry = 'quay.io' // Nextflow plugins plugins { - id 'nf-validation' // Validation of pipeline parameters and creation of an input channel from a sample sheet + id 'nf-validation@1.1.3' // Validation of pipeline parameters and creation of an input channel from a sample sheet } // Load igenomes.config if required @@ -204,6 +205,9 @@ env { // Capture exit codes from upstream processes when piping process.shell = ['/bin/bash', '-euo', 'pipefail'] +// Disable process selector warnings by default. Use debug profile to enable warnings. +nextflow.enable.configProcessNamesValidation = false + def trace_timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') timeline { enabled = true @@ -229,7 +233,7 @@ manifest { description = """Quantification, miRNA target prediction and differential expression analysis of circular RNAs""" mainScript = 'main.nf' nextflowVersion = '!>=23.04.0' - version = '1.0.0' + version = 'dev' doi = '' } From 600c9afacf72c075480b786e261436d7178e3392 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Wed, 20 Dec 2023 15:56:43 +0000 Subject: [PATCH 080/491] Template update for nf-core/tools version 2.11.1 --- .../{release-announcments.yml => release-announcements.yml} | 0 nextflow.config | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename .github/workflows/{release-announcments.yml => release-announcements.yml} (100%) diff --git a/.github/workflows/release-announcments.yml b/.github/workflows/release-announcements.yml similarity index 100% rename from .github/workflows/release-announcments.yml rename to .github/workflows/release-announcements.yml diff --git a/nextflow.config b/nextflow.config index 3893e1a3..4b3b98de 100644 --- a/nextflow.config +++ b/nextflow.config @@ -111,10 +111,10 @@ profiles { shifter.enabled = false charliecloud.enabled = false apptainer.enabled = false - runOptions = '-u $(id -u):$(id -g)' + docker.runOptions = '-u $(id -u):$(id -g)' } arm { - docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' + docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' } singularity { singularity.enabled = true From 6894bb1e2506bcc651be8f1e0876a25b4e47919e Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Mon, 19 Dec 2022 12:04:47 +0000 Subject: [PATCH 081/491] Template update for nf-core/tools version 2.7.2 --- modules.json | 4 ++-- .../nf-core/custom/dumpsoftwareversions/main.nf | 2 +- modules/nf-core/fastqc/main.nf | 8 ++------ modules/nf-core/multiqc/main.nf | 2 +- nextflow.config | 4 ++++ nextflow_schema.json | 14 -------------- 6 files changed, 10 insertions(+), 24 deletions(-) diff --git a/modules.json b/modules.json index b6944888..ec1c9d84 100644 --- a/modules.json +++ b/modules.json @@ -47,7 +47,7 @@ }, "custom/dumpsoftwareversions": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "fastqc": { @@ -77,7 +77,7 @@ }, "multiqc": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", "installed_by": ["modules"] }, "samtools/flagstat": { diff --git a/modules/nf-core/custom/dumpsoftwareversions/main.nf b/modules/nf-core/custom/dumpsoftwareversions/main.nf index c9d014b1..d3a1cc25 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/main.nf +++ b/modules/nf-core/custom/dumpsoftwareversions/main.nf @@ -2,7 +2,7 @@ process CUSTOM_DUMPSOFTWAREVERSIONS { label 'process_single' // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container - conda "bioconda::multiqc=1.15" + conda "bioconda::multiqc=1.13" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/multiqc:1.15--pyhdfd78af_0' : 'biocontainers/multiqc:1.15--pyhdfd78af_0' }" diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf index 67209f79..7df41546 100644 --- a/modules/nf-core/fastqc/main.nf +++ b/modules/nf-core/fastqc/main.nf @@ -2,7 +2,7 @@ process FASTQC { tag "$meta.id" label 'process_medium' - conda "bioconda::fastqc=0.12.1" + conda "bioconda::fastqc=0.11.9" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/fastqc:0.12.1--hdfd78af_0' : 'biocontainers/fastqc:0.12.1--hdfd78af_0' }" @@ -29,11 +29,7 @@ process FASTQC { printf "%s %s\\n" $rename_to | while read old_name new_name; do [ -f "\${new_name}" ] || ln -s \$old_name \$new_name done - - fastqc \\ - $args \\ - --threads $task.cpus \\ - $renamed_files + fastqc $args --threads $task.cpus $renamed_files cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 40a691eb..4c84d257 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,7 +1,7 @@ process MULTIQC { label 'process_single' - conda "bioconda::multiqc=1.17" + conda "bioconda::multiqc=1.13" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/multiqc:1.17--pyhdfd78af_0' : 'biocontainers/multiqc:1.17--pyhdfd78af_0' }" diff --git a/nextflow.config b/nextflow.config index 4d0b2496..651c52df 100644 --- a/nextflow.config +++ b/nextflow.config @@ -80,6 +80,10 @@ params { hook_url = null help = false version = false + validate_params = true + show_hidden_params = false + schema_ignore_params = 'genomes' + // Config options config_profile_name = null diff --git a/nextflow_schema.json b/nextflow_schema.json index 8f5e22b5..562d309d 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -512,20 +512,6 @@ "description": "Show all params when using `--help`", "hidden": true, "help_text": "By default, parameters set as _hidden_ in the schema are not shown on the command line when a user runs with `--help`. Specifying this option will tell the pipeline to show all parameters." - }, - "validationFailUnrecognisedParams": { - "type": "boolean", - "fa_icon": "far fa-check-circle", - "description": "Validation of parameters fails when an unrecognised parameter is found.", - "hidden": true, - "help_text": "By default, when an unrecognised parameter is found, it returns a warinig." - }, - "validationLenientMode": { - "type": "boolean", - "fa_icon": "far fa-check-circle", - "description": "Validation of parameters in lenient more.", - "hidden": true, - "help_text": "Allows string values that are parseable as numbers or booleans. For further information see [JSONSchema docs](https://github.com/everit-org/json-schema#lenient-mode)." } } } From e61dc7fcd9d57192e57bfc2de5f6e0ec61f212ec Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Fri, 28 Apr 2023 14:19:44 +0000 Subject: [PATCH 082/491] Template update for nf-core/tools version 2.8 --- .github/workflows/linting.yml | 2 +- README.md | 48 +++++++++++++------ bin/check_samplesheet.py | 26 +++++++--- conf/igenomes.config | 8 ++++ docs/usage.md | 23 +++------ modules.json | 4 +- .../custom/dumpsoftwareversions/main.nf | 6 +-- modules/nf-core/multiqc/main.nf | 6 +-- nextflow.config | 2 + 9 files changed, 78 insertions(+), 47 deletions(-) diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index b8bdd214..888cb4bc 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -78,7 +78,7 @@ jobs: - uses: actions/setup-python@v4 with: - python-version: "3.11" + python-version: "3.8" architecture: "x64" - name: Install dependencies diff --git a/README.md b/README.md index 8d0053fb..ebb5401e 100644 --- a/README.md +++ b/README.md @@ -44,34 +44,52 @@ On release, automated continuous integration tests run the pipeline on a full-si - Differential expression analysis [`DESeq2`](https://bioconductor.org/packages/release/bioc/html/DESeq2.html) - Circular - Linear ratio tests ['CircTest'](https://github.com/dieterich-lab/CircTest) -## Quick Start +## Usage -1. Install [`Nextflow`](https://www.nextflow.io/docs/latest/getstarted.html#installation) (`>=22.10.1`) +> **Note** +> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how +> to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) +> with `-profile test` before running the workflow on actual data. -2. Install any of [`Docker`](https://docs.docker.com/engine/installation/), [`Singularity`](https://www.sylabs.io/guides/3.0/user-guide/) (you can follow [this tutorial](https://singularity-tutorial.github.io/01-installation/)), [`Podman`](https://podman.io/), [`Shifter`](https://nersc.gitlab.io/development/shifter/how-to-use/) or [`Charliecloud`](https://hpc.github.io/charliecloud/) for full pipeline reproducibility _(you can use [`Conda`](https://conda.io/miniconda.html) both to install Nextflow itself and also to manage software within pipelines. Please only use it within pipelines as a last resort; see [docs](https://nf-co.re/usage/configuration#basic-configuration-profiles))_. + ```bash nextflow run nf-core/circrna --input samplesheet.csv --outdir --genome GRCh37 -profile --tool 'ciriquant' --module 'circrna_discovery,mirna_prediction,differential_expression' --bsj_reads 2 ``` -## Documentation +```bash +nextflow run nf-core/circrna \ + -profile \ + --input samplesheet.csv \ + --outdir +``` + +> **Warning:** +> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those +> provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; +> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files). -The nf-core/circrna pipeline comes with documentation about the pipeline [usage](https://nf-co.re/circrna/usage), [parameters](https://nf-co.re/circrna/parameters) and [output](https://nf-co.re/circrna/output). +For more details, please refer to the [usage documentation](https://nf-co.re/circrna/usage) and the [parameter documentation](https://nf-co.re/circrna/parameters). + +## Pipeline output + +To see the the results of a test run with a full size dataset refer to the [results](https://nf-co.re/circrna/results) tab on the nf-core website pipeline page. +For more details about the output files and reports, please refer to the +[output documentation](https://nf-co.re/circrna/output). ```bash nextflow run nf-core/circrna \ diff --git a/bin/check_samplesheet.py b/bin/check_samplesheet.py index 0a5041b0..2baec583 100755 --- a/bin/check_samplesheet.py +++ b/bin/check_samplesheet.py @@ -34,12 +34,26 @@ def make_dir(path): raise exception -def print_error(error, context="Line", context_str=""): - error_str = f"ERROR: Please check samplesheet -> {error}" - if context != "" and context_str != "": - error_str = f"ERROR: Please check samplesheet -> {error}\n{context.strip()}: '{context_str.strip()}'" - print(error_str) - sys.exit(1) +def sniff_format(handle): + """ + Detect the tabular format. + + Args: + handle (text file): A handle to a `text file`_ object. The read position is + expected to be at the beginning (index 0). + + Returns: + csv.Dialect: The detected tabular format. + + .. _text file: + https://docs.python.org/3/glossary.html#term-text-file + + """ + peek = read_head(handle) + handle.seek(0) + sniffer = csv.Sniffer() + dialect = sniffer.sniff(peek) + return dialect def check_samplesheet(file_in, file_out): diff --git a/conf/igenomes.config b/conf/igenomes.config index f597c35a..ec1a5c26 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -37,6 +37,14 @@ params { mito_name = "chrM" species_id = "hsa" } + 'CHM13' { + fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/BWAIndex/" + bwamem2 = "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/BWAmem2Index/" + gtf = "${params.igenomes_base}/Homo_sapiens/NCBI/CHM13/Annotation/Genes/genes.gtf" + gff = "ftp://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/009/914/755/GCF_009914755.1_T2T-CHM13v2.0/GCF_009914755.1_T2T-CHM13v2.0_genomic.gff.gz" + mito_name = "chrM" + } 'GRCm38' { fasta = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa" fasta_fai = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa.fai" diff --git a/docs/usage.md b/docs/usage.md index 9a9286db..27523ba3 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -310,28 +310,17 @@ Specify the path to a specific config file (this is a core Nextflow command). Se Whilst the default requirements set within the pipeline will hopefully work for most people and with most input data, you may find that you want to customise the compute resources that the pipeline requests. Each step in the pipeline has a default set of requirements for number of CPUs, memory and time. For most of the steps in the pipeline, if the job exits with any of the error codes specified [here](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/conf/base.config#L18) it will automatically be resubmitted with higher requests (2 x original, then 3 x original). If it still fails after the third attempt then the pipeline execution is stopped. -For example, if the nf-core/rnaseq pipeline is failing after multiple re-submissions of the `STAR_ALIGN` process due to an exit code of `137` this would indicate that there is an out of memory issue: +To change the resource requests, please see the [max resources](https://nf-co.re/docs/usage/configuration#max-resources) and [tuning workflow resources](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources) section of the nf-core website. -```console -[62/149eb0] NOTE: Process `NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN (WT_REP1)` terminated with an error exit status (137) -- Execution is retried (1) -Error executing process > 'NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN (WT_REP1)' +### Custom Containers -Caused by: - Process `NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN (WT_REP1)` terminated with an error exit status (137) +In some cases you may wish to change which container or conda environment a step of the pipeline uses for a particular tool. By default nf-core pipelines use containers and software from the [biocontainers](https://biocontainers.pro/) or [bioconda](https://bioconda.github.io/) projects. However in some cases the pipeline specified version maybe out of date. -Command executed: - STAR \ - --genomeDir star \ - --readFilesIn WT_REP1_trimmed.fq.gz \ - --runThreadN 2 \ - --outFileNamePrefix WT_REP1. \ - +To use a different container from the default container or conda environment specified in a pipeline, please see the [updating tool versions](https://nf-co.re/docs/usage/configuration#updating-tool-versions) section of the nf-core website. -Command exit status: - 137 +### Custom Tool Arguments -Command output: - (empty) +A pipeline might not always support every possible argument or option of a particular tool used in pipeline. Fortunately, nf-core pipelines provide some freedom to users to insert additional parameters that the pipeline does not include by default. Command error: .command.sh: line 9: 30 Killed STAR --genomeDir star --readFilesIn WT_REP1_trimmed.fq.gz --runThreadN 2 --outFileNamePrefix WT_REP1. diff --git a/modules.json b/modules.json index ec1c9d84..2c7eaa94 100644 --- a/modules.json +++ b/modules.json @@ -47,7 +47,7 @@ }, "custom/dumpsoftwareversions": { "branch": "master", - "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", + "git_sha": "76cc4938c1f6ea5c7d83fed1eeffc146787f9543", "installed_by": ["modules"] }, "fastqc": { @@ -77,7 +77,7 @@ }, "multiqc": { "branch": "master", - "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", + "git_sha": "f2d63bd5b68925f98f572eed70993d205cc694b7", "installed_by": ["modules"] }, "samtools/flagstat": { diff --git a/modules/nf-core/custom/dumpsoftwareversions/main.nf b/modules/nf-core/custom/dumpsoftwareversions/main.nf index d3a1cc25..800a6099 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/main.nf +++ b/modules/nf-core/custom/dumpsoftwareversions/main.nf @@ -2,10 +2,10 @@ process CUSTOM_DUMPSOFTWAREVERSIONS { label 'process_single' // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container - conda "bioconda::multiqc=1.13" + conda "bioconda::multiqc=1.14" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.15--pyhdfd78af_0' : - 'biocontainers/multiqc:1.15--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.14--pyhdfd78af_0' : + 'quay.io/biocontainers/multiqc:1.14--pyhdfd78af_0' }" input: path versions diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 4c84d257..4b604749 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,10 +1,10 @@ process MULTIQC { label 'process_single' - conda "bioconda::multiqc=1.13" + conda "bioconda::multiqc=1.14" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.17--pyhdfd78af_0' : - 'biocontainers/multiqc:1.17--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.14--pyhdfd78af_0' : + 'quay.io/biocontainers/multiqc:1.14--pyhdfd78af_0' }" input: path multiqc_files, stageAs: "?/*" diff --git a/nextflow.config b/nextflow.config index 651c52df..03dbdb8e 100644 --- a/nextflow.config +++ b/nextflow.config @@ -152,6 +152,7 @@ profiles { } docker { docker.enabled = true + docker.registry = 'quay.io' docker.userEmulation = true conda.enabled = false singularity.enabled = false @@ -175,6 +176,7 @@ profiles { } podman { podman.enabled = true + podman.registry = 'quay.io' conda.enabled = false docker.enabled = false singularity.enabled = false From 611e48f6fa79e0aaa31dc47109e2101c29846ecc Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Fri, 30 Jun 2023 16:12:56 +0000 Subject: [PATCH 083/491] Template update for nf-core/tools version 2.9 --- .github/workflows/ci.yml | 2 +- README.md | 6 +++--- assets/multiqc_config.yml | 8 +++----- docs/usage.md | 4 +--- lib/WorkflowCircrna.groovy | 2 +- nextflow.config | 13 ++++--------- nextflow_schema.json | 30 +++++++++++++++++++++++++++--- workflows/circrna.nf | 3 +++ 8 files changed, 43 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2eb40246..e86fca57 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: strategy: matrix: NXF_VER: - - "22.10.1" + - "23.04.0" - "latest-everything" steps: diff --git a/README.md b/README.md index ebb5401e..cccd27a6 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![GitHub Actions CI Status](https://github.com/nf-core/circrna/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/circrna/actions?query=workflow%3A%22nf-core+CI%22) [![GitHub Actions Linting Status](https://github.com/nf-core/circrna/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/circrna/actions?query=workflow%3A%22nf-core+linting%22)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/circrna/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) -[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A522.10.1-22aa62.svg)](https://www.nextflow.io/) +[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A523.04.0-23aa62.svg)](https://www.nextflow.io/) [![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) [![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) [![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) @@ -83,11 +83,11 @@ nextflow run nf-core/circrna \ > provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; > see [docs](https://nf-co.re/usage/configuration#custom-configuration-files). -For more details, please refer to the [usage documentation](https://nf-co.re/circrna/usage) and the [parameter documentation](https://nf-co.re/circrna/parameters). +For more details and further functionality, please refer to the [usage documentation](https://nf-co.re/circrna/usage) and the [parameter documentation](https://nf-co.re/circrna/parameters). ## Pipeline output -To see the the results of a test run with a full size dataset refer to the [results](https://nf-co.re/circrna/results) tab on the nf-core website pipeline page. +To see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/circrna/results) tab on the nf-core website pipeline page. For more details about the output files and reports, please refer to the [output documentation](https://nf-co.re/circrna/output). diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index e6c9ce18..82a8c2de 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,9 +1,7 @@ report_comment: > - This report has been generated by the nf-core/circrna analysis pipeline. For information about how to - interpret these results, please see the documentation. - + This report has been generated by the nf-core/circrna + analysis pipeline. For information about how to interpret these results, please see the + documentation. report_section_order: "nf-core-circrna-methods-description": order: -1000 diff --git a/docs/usage.md b/docs/usage.md index 27523ba3..311b83fb 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -29,9 +29,7 @@ If you wish to repeatedly use the same parameters for multiple runs, rather than Pipeline settings can be provided in a `yaml` or `json` file via `-params-file `. -:::warning -Do not use `-c ` to specify parameters as this will result in errors. Custom config files specified with `-c` must only be used for [tuning process resource specifications](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources), other infrastructural tweaks (such as output directories), or module arguments (args). -::: +> ⚠️ Do not use `-c ` to specify parameters as this will result in errors. Custom config files specified with `-c` must only be used for [tuning process resource specifications](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources), other infrastructural tweaks (such as output directories), or module arguments (args). The above pipeline run specified with a params file in yaml format: diff --git a/lib/WorkflowCircrna.groovy b/lib/WorkflowCircrna.groovy index eae29c19..e03279a4 100755 --- a/lib/WorkflowCircrna.groovy +++ b/lib/WorkflowCircrna.groovy @@ -53,7 +53,7 @@ class WorkflowCircrna { public static String toolCitationText(params) { - // TODO nf-core: Optionally add in-text citation tools to this list. + // TODO Optionally add in-text citation tools to this list. // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "", // Uncomment function in methodsDescriptionText to render in MultiQC report def citation_text = [ diff --git a/nextflow.config b/nextflow.config index 03dbdb8e..04d94707 100644 --- a/nextflow.config +++ b/nextflow.config @@ -71,7 +71,7 @@ params { multiqc_methods_description = null // Boilerplate options - outdir = './results' + outdir = null publish_dir_mode = 'copy' email = null email_on_fail = null @@ -80,10 +80,6 @@ params { hook_url = null help = false version = false - validate_params = true - show_hidden_params = false - schema_ignore_params = 'genomes' - // Config options config_profile_name = null @@ -93,7 +89,6 @@ params { config_profile_contact = null config_profile_url = null - // Max resource options max_memory = '300.GB' max_cpus = 50 @@ -105,7 +100,9 @@ params { validationSchemaIgnoreParams = 'genomes,igenomes_base' validationShowHiddenParams = false validate_params = true - + withName: INTEGRATE_SCVI { + cpus: 60 + } } // Load base.config by default for all pipelines @@ -152,7 +149,6 @@ profiles { } docker { docker.enabled = true - docker.registry = 'quay.io' docker.userEmulation = true conda.enabled = false singularity.enabled = false @@ -176,7 +172,6 @@ profiles { } podman { podman.enabled = true - podman.registry = 'quay.io' conda.enabled = false docker.enabled = false singularity.enabled = false diff --git a/nextflow_schema.json b/nextflow_schema.json index 562d309d..5d16b61a 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -14,10 +14,13 @@ "properties": { "input": { "type": "string", - "fa_icon": "fas fa-file-csv", + "format": "file-path", + "exists": true, "mimetype": "text/csv", - "description": "A 'samplehseet' CSV file containing the absolute paths to FASTQ files.", - "help_text": "An example of a valid CSV sample sheet is provided below, depicting paired-end control samples and single-end treatment samples. The headers `sample`, `fastq_1` and `fastq_2` must be included in the input CSV file.\n\n| sample \t| fastq_1 \t| fastq_2 \t|\n|-----------\t|--------------------------\t|--------------------------\t|\n| control_1 \t| /data/ctrl_1_R1.fastq.gz \t| /data/ctrl_1_R2.fastq.gz \t|\n| control_2 \t| /data/ctrl_2_R1.fastq.gz \t| /data/ctrl_2_R2.fastq.gz \t|\n| control_3 \t| /data/ctrl_3_R1.fastq.gz \t| /data/ctrl_3_R2.fastq.gz \t|\n| treated_1 \t| /data/trt_1_R1.fastq.gz \t| \t|\n| treated_2 \t| /data/trt_2_R1.fastq.gz \t| \t|\n| treated_3 \t| /data/trt_3_R1.fastq.gz \t| \t|" + "pattern": "^\\S+\\.csv$", + "description": "Path to comma-separated file containing information about the samples in the experiment.", + "help_text": "You will need to create a design file with information about the samples in your experiment before running the pipeline. Use this parameter to specify its location. It has to be a comma-separated file with 3 columns, and a header row. See [usage docs](https://nf-co.re/circrna/usage#samplesheet-input).", + "fa_icon": "fas fa-file-csv" }, "outdir": { "type": "string", @@ -417,12 +420,14 @@ "type": "boolean", "description": "Display help text.", "fa_icon": "fas fa-question-circle", + "default": false, "hidden": true }, "version": { "type": "boolean", "description": "Display version and exit.", "fa_icon": "fas fa-question-circle", + "default": false, "hidden": true }, "publish_dir_mode": { @@ -453,6 +458,7 @@ "type": "boolean", "description": "Send plain-text email instead of HTML.", "fa_icon": "fas fa-remove-format", + "default": false, "hidden": true }, "multiqc_title": { @@ -472,6 +478,7 @@ "type": "boolean", "description": "Do not use coloured log outputs.", "fa_icon": "fas fa-palette", + "default": false, "hidden": true }, "hook_url": { @@ -510,8 +517,25 @@ "type": "boolean", "fa_icon": "far fa-eye-slash", "description": "Show all params when using `--help`", + "default": false, "hidden": true, "help_text": "By default, parameters set as _hidden_ in the schema are not shown on the command line when a user runs with `--help`. Specifying this option will tell the pipeline to show all parameters." + }, + "validationFailUnrecognisedParams": { + "type": "boolean", + "fa_icon": "far fa-check-circle", + "description": "Validation of parameters fails when an unrecognised parameter is found.", + "default": false, + "hidden": true, + "help_text": "By default, when an unrecognised parameter is found, it returns a warinig." + }, + "validationLenientMode": { + "type": "boolean", + "fa_icon": "far fa-check-circle", + "description": "Validation of parameters in lenient more.", + "default": false, + "hidden": true, + "help_text": "Allows string values that are parseable as numbers or booleans. For further information see [JSONSchema docs](https://github.com/everit-org/json-schema#lenient-mode)." } } } diff --git a/workflows/circrna.nf b/workflows/circrna.nf index e84a6561..74a3e420 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -131,6 +131,9 @@ workflow CIRCRNA { } .set { ch_fastq } ch_versions = ch_versions.mix(INPUT_CHECK.out.versions) + // TODO: OPTIONAL, you can use nf-validation plugin to create an input channel from the samplesheet with Channel.fromSamplesheet("input") + // See the documentation https://nextflow-io.github.io/nf-validation/samplesheets/fromSamplesheet/ + // ! There is currently no tooling to help you write a sample sheet schema // MODULE: // Concatenate FastQ files from same sample if required From 4a567c341bf167ae76c8ec8059f6a6ea9b11e2be Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Mon, 25 Sep 2023 15:16:33 +0000 Subject: [PATCH 084/491] Template update for nf-core/tools version 2.10 --- .github/workflows/linting.yml | 2 +- CITATIONS.md | 2 +- README.md | 18 ++++++++++-------- assets/multiqc_config.yml | 6 ++++-- docs/usage.md | 4 +++- lib/WorkflowCircrna.groovy | 2 +- modules.json | 4 ++-- .../custom/dumpsoftwareversions/main.nf | 2 +- modules/nf-core/fastqc/main.nf | 10 +++++++--- modules/nf-core/multiqc/main.nf | 2 +- nextflow_schema.json | 7 ------- 11 files changed, 31 insertions(+), 28 deletions(-) diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 888cb4bc..b8bdd214 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -78,7 +78,7 @@ jobs: - uses: actions/setup-python@v4 with: - python-version: "3.8" + python-version: "3.11" architecture: "x64" - name: Install dependencies diff --git a/CITATIONS.md b/CITATIONS.md index 2ee62d2b..7b0c25be 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -44,7 +44,7 @@ - [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) - > Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. Available online https://www.bioinformatics.babraham.ac.uk/projects/fastqc/. + > Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. - [find circ](https://doi.org/10.1038/nature11928) diff --git a/README.md b/README.md index cccd27a6..ac935b13 100644 --- a/README.md +++ b/README.md @@ -46,10 +46,11 @@ On release, automated continuous integration tests run the pipeline on a full-si ## Usage -> **Note** -> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how -> to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) -> with `-profile test` before running the workflow on actual data. +:::note +If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how +to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) +with `-profile test` before running the workflow on actual data. +::: - ```bash - nextflow run nf-core/circrna --input samplesheet.csv --outdir --genome GRCh37 -profile --tool 'ciriquant' --module 'circrna_discovery,mirna_prediction,differential_expression' --bsj_reads 2 - ``` +```bash +nextflow run nf-core/circrna --input samplesheet.csv --outdir --genome GRCh37 -profile --tool 'ciriquant' --module 'circrna_discovery,mirna_prediction,differential_expression' --bsj_reads 2 +``` ```bash nextflow run nf-core/circrna \ diff --git a/docs/usage.md b/docs/usage.md index 27523ba3..2f9684a0 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -323,12 +323,13 @@ To use a different container from the default container or conda environment spe A pipeline might not always support every possible argument or option of a particular tool used in pipeline. Fortunately, nf-core pipelines provide some freedom to users to insert additional parameters that the pipeline does not include by default. Command error: - .command.sh: line 9: 30 Killed STAR --genomeDir star --readFilesIn WT_REP1_trimmed.fq.gz --runThreadN 2 --outFileNamePrefix WT_REP1. +.command.sh: line 9: 30 Killed STAR --genomeDir star --readFilesIn WT_REP1_trimmed.fq.gz --runThreadN 2 --outFileNamePrefix WT_REP1. Work dir: - /home/pipelinetest/work/9d/172ca5881234073e8d76f2a19c88fb +/home/pipelinetest/work/9d/172ca5881234073e8d76f2a19c88fb Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run` -``` + +```` To change the resource requests, please see the [max resources](https://nf-co.re/docs/usage/configuration#max-resources) and [tuning workflow resources](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources) section of the nf-core website. @@ -352,7 +353,7 @@ process { memory = 100.GB } } -``` +```` > **NB:** We specify the full process name i.e. `NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN` in the config file because this takes priority over the short name (`STAR_ALIGN`) and allows existing configuration using the full process name to be correctly overridden. > From 57bb1395d0ca1bdb70ac5001e515c48e0d08cf1f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 13 Jan 2024 11:38:03 +0100 Subject: [PATCH 088/491] Increase minimum nextflow version --- nextflow.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index 7fb0bd97..b3699c50 100644 --- a/nextflow.config +++ b/nextflow.config @@ -280,7 +280,7 @@ manifest { homePage = 'https://github.com/nf-core/circrna' description = """Quantification, miRNA target prediction and differential expression analysis of circular RNAs""" mainScript = 'main.nf' - nextflowVersion = '!>=22.10.1' + nextflowVersion = '!>=23.04.0' version = 'dev' doi = '' } From ca64cd71c5b8b6a219e6a8a6fc3bfb1c04d12465 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 13 Jan 2024 11:42:56 +0100 Subject: [PATCH 089/491] Update nf-core modules --- modules.json | 83 +- .../bedtools/intersect/environment.yml | 3 +- modules/nf-core/bedtools/intersect/main.nf | 4 +- modules/nf-core/bedtools/sort/environment.yml | 3 +- modules/nf-core/bedtools/sort/main.nf | 4 +- modules/nf-core/bowtie/align/environment.yml | 7 + modules/nf-core/bowtie/align/main.nf | 4 +- modules/nf-core/bowtie/build/environment.yml | 7 + modules/nf-core/bowtie/build/main.nf | 2 +- modules/nf-core/bowtie2/align/environment.yml | 9 + modules/nf-core/bowtie2/align/main.nf | 17 +- .../bowtie2/align/tests/large_index.config | 5 + .../nf-core/bowtie2/align/tests/main.nf.test | 561 +++++++++++++ .../bowtie2/align/tests/main.nf.test.snap | 263 ++++++ .../nf-core/bowtie2/align/tests/sam.config | 5 + .../nf-core/bowtie2/align/tests/sam2.config | 5 + modules/nf-core/bowtie2/align/tests/tags.yml | 2 + modules/nf-core/bowtie2/build/environment.yml | 7 + modules/nf-core/bowtie2/build/main.nf | 6 +- .../nf-core/bowtie2/build/tests/main.nf.test | 31 + .../bowtie2/build/tests/main.nf.test.snap | 45 + modules/nf-core/bowtie2/build/tests/tags.yml | 2 + modules/nf-core/bwa/index/environment.yml | 7 + modules/nf-core/bwa/index/main.nf | 2 +- modules/nf-core/cat/cat/environment.yml | 1 + modules/nf-core/cat/cat/main.nf | 12 +- modules/nf-core/cat/cat/tests/main.nf.test | 26 + modules/nf-core/cat/fastq/environment.yml | 7 + modules/nf-core/cat/fastq/main.nf | 2 +- .../nf-core/cat/fastq/tests/main.nf.test.snap | 24 +- .../circexplorer2/annotate/environment.yml | 7 + .../nf-core/circexplorer2/annotate/main.nf | 2 +- .../circexplorer2/parse/environment.yml | 7 + modules/nf-core/circexplorer2/parse/main.nf | 2 +- .../dumpsoftwareversions/environment.yml | 2 +- .../custom/dumpsoftwareversions/main.nf | 4 +- .../dumpsoftwareversions/tests/main.nf.test | 7 +- .../tests/main.nf.test.snap | 50 +- modules/nf-core/fastqc/tests/main.nf.test | 271 ++++-- .../nf-core/fastqc/tests/main.nf.test.snap | 12 +- modules/nf-core/hisat2/align/environment.yml | 8 + modules/nf-core/hisat2/align/main.nf | 2 +- modules/nf-core/hisat2/build/environment.yml | 7 + modules/nf-core/hisat2/build/main.nf | 2 +- .../hisat2/extractsplicesites/environment.yml | 7 + .../nf-core/hisat2/extractsplicesites/main.nf | 2 +- modules/nf-core/miranda/environment.yml | 7 + modules/nf-core/miranda/main.nf | 2 +- modules/nf-core/multiqc/environment.yml | 2 +- modules/nf-core/multiqc/main.nf | 6 +- modules/nf-core/multiqc/meta.yml | 1 - modules/nf-core/multiqc/tests/main.nf.test | 48 +- .../nf-core/multiqc/tests/main.nf.test.snap | 21 + .../nf-core/samtools/flagstat/environment.yml | 7 + modules/nf-core/samtools/flagstat/main.nf | 6 +- .../samtools/flagstat/tests/main.nf.test | 36 + .../samtools/flagstat/tests/main.nf.test.snap | 16 + .../nf-core/samtools/flagstat/tests/tags.yml | 2 + .../nf-core/samtools/idxstats/environment.yml | 7 + modules/nf-core/samtools/idxstats/main.nf | 6 +- .../samtools/idxstats/tests/main.nf.test | 36 + .../samtools/idxstats/tests/main.nf.test.snap | 16 + .../nf-core/samtools/idxstats/tests/tags.yml | 2 + .../nf-core/samtools/index/environment.yml | 7 + modules/nf-core/samtools/index/main.nf | 6 +- .../samtools/index/tests/csi.nextflow.config | 7 + .../nf-core/samtools/index/tests/main.nf.test | 87 ++ .../samtools/index/tests/main.nf.test.snap | 28 + modules/nf-core/samtools/index/tests/tags.yml | 2 + modules/nf-core/samtools/sort/environment.yml | 7 + modules/nf-core/samtools/sort/main.nf | 6 +- .../nf-core/samtools/sort/tests/main.nf.test | 5 +- .../samtools/sort/tests/main.nf.test.snap | 19 +- .../nf-core/samtools/stats/environment.yml | 7 + modules/nf-core/samtools/stats/main.nf | 6 +- .../nf-core/samtools/stats/tests/main.nf.test | 2 +- .../samtools/stats/tests/main.nf.test.snap | 20 +- modules/nf-core/samtools/view/environment.yml | 7 + modules/nf-core/samtools/view/main.nf | 19 +- .../nf-core/samtools/view/tests/bam.config | 3 + .../samtools/view/tests/bam_index.config | 3 + .../nf-core/samtools/view/tests/main.nf.test | 231 ++++++ .../samtools/view/tests/main.nf.test.snap | 140 ++++ modules/nf-core/samtools/view/tests/tags.yml | 2 + .../nf-core/segemehl/align/environment.yml | 7 + modules/nf-core/segemehl/align/main.nf | 2 +- .../nf-core/segemehl/index/environment.yml | 7 + modules/nf-core/segemehl/index/main.nf | 2 +- modules/nf-core/star/align/environment.yml | 9 + modules/nf-core/star/align/main.nf | 6 +- modules/nf-core/star/align/tests/main.nf.test | 339 ++++++++ .../star/align/tests/main.nf.test.snap | 769 ++++++++++++++++++ .../star/align/tests/nextflow.arriba.config | 14 + .../nf-core/star/align/tests/nextflow.config | 14 + .../align/tests/nextflow.starfusion.config | 14 + modules/nf-core/star/align/tests/tags.yml | 2 + .../star/genomegenerate/environment.yml | 11 + modules/nf-core/star/genomegenerate/main.nf | 89 +- .../star/genomegenerate/tests/main.nf.test | 117 +++ .../genomegenerate/tests/main.nf.test.snap | 22 + .../star/genomegenerate/tests/tags.yml | 2 + .../stringtie/stringtie/environment.yml | 7 + modules/nf-core/stringtie/stringtie/main.nf | 2 +- .../stringtie/stringtie/tests/main.nf.test | 108 +++ .../stringtie/tests/main.nf.test.snap | 186 +++++ .../stringtie/stringtie/tests/tags.yml | 2 + modules/nf-core/trimgalore/environment.yml | 7 + modules/nf-core/trimgalore/main.nf | 2 +- .../tests/main.nf.test | 14 +- .../tests/main.nf.test.snap | 302 ++----- .../bam_sort_stats_samtools/tests/tags.yml | 2 +- 111 files changed, 3940 insertions(+), 501 deletions(-) create mode 100644 modules/nf-core/bowtie/align/environment.yml create mode 100644 modules/nf-core/bowtie/build/environment.yml create mode 100644 modules/nf-core/bowtie2/align/environment.yml create mode 100644 modules/nf-core/bowtie2/align/tests/large_index.config create mode 100644 modules/nf-core/bowtie2/align/tests/main.nf.test create mode 100644 modules/nf-core/bowtie2/align/tests/main.nf.test.snap create mode 100644 modules/nf-core/bowtie2/align/tests/sam.config create mode 100644 modules/nf-core/bowtie2/align/tests/sam2.config create mode 100644 modules/nf-core/bowtie2/align/tests/tags.yml create mode 100644 modules/nf-core/bowtie2/build/environment.yml create mode 100644 modules/nf-core/bowtie2/build/tests/main.nf.test create mode 100644 modules/nf-core/bowtie2/build/tests/main.nf.test.snap create mode 100644 modules/nf-core/bowtie2/build/tests/tags.yml create mode 100644 modules/nf-core/bwa/index/environment.yml create mode 100644 modules/nf-core/cat/fastq/environment.yml create mode 100644 modules/nf-core/circexplorer2/annotate/environment.yml create mode 100644 modules/nf-core/circexplorer2/parse/environment.yml create mode 100644 modules/nf-core/hisat2/align/environment.yml create mode 100644 modules/nf-core/hisat2/build/environment.yml create mode 100644 modules/nf-core/hisat2/extractsplicesites/environment.yml create mode 100644 modules/nf-core/miranda/environment.yml create mode 100644 modules/nf-core/multiqc/tests/main.nf.test.snap create mode 100644 modules/nf-core/samtools/flagstat/environment.yml create mode 100644 modules/nf-core/samtools/flagstat/tests/main.nf.test create mode 100644 modules/nf-core/samtools/flagstat/tests/main.nf.test.snap create mode 100644 modules/nf-core/samtools/flagstat/tests/tags.yml create mode 100644 modules/nf-core/samtools/idxstats/environment.yml create mode 100644 modules/nf-core/samtools/idxstats/tests/main.nf.test create mode 100644 modules/nf-core/samtools/idxstats/tests/main.nf.test.snap create mode 100644 modules/nf-core/samtools/idxstats/tests/tags.yml create mode 100644 modules/nf-core/samtools/index/environment.yml create mode 100644 modules/nf-core/samtools/index/tests/csi.nextflow.config create mode 100644 modules/nf-core/samtools/index/tests/main.nf.test create mode 100644 modules/nf-core/samtools/index/tests/main.nf.test.snap create mode 100644 modules/nf-core/samtools/index/tests/tags.yml create mode 100644 modules/nf-core/samtools/sort/environment.yml create mode 100644 modules/nf-core/samtools/stats/environment.yml create mode 100644 modules/nf-core/samtools/view/environment.yml create mode 100644 modules/nf-core/samtools/view/tests/bam.config create mode 100644 modules/nf-core/samtools/view/tests/bam_index.config create mode 100644 modules/nf-core/samtools/view/tests/main.nf.test create mode 100644 modules/nf-core/samtools/view/tests/main.nf.test.snap create mode 100644 modules/nf-core/samtools/view/tests/tags.yml create mode 100644 modules/nf-core/segemehl/align/environment.yml create mode 100644 modules/nf-core/segemehl/index/environment.yml create mode 100644 modules/nf-core/star/align/environment.yml create mode 100644 modules/nf-core/star/align/tests/main.nf.test create mode 100644 modules/nf-core/star/align/tests/main.nf.test.snap create mode 100644 modules/nf-core/star/align/tests/nextflow.arriba.config create mode 100644 modules/nf-core/star/align/tests/nextflow.config create mode 100644 modules/nf-core/star/align/tests/nextflow.starfusion.config create mode 100644 modules/nf-core/star/align/tests/tags.yml create mode 100644 modules/nf-core/star/genomegenerate/environment.yml create mode 100644 modules/nf-core/star/genomegenerate/tests/main.nf.test create mode 100644 modules/nf-core/star/genomegenerate/tests/main.nf.test.snap create mode 100644 modules/nf-core/star/genomegenerate/tests/tags.yml create mode 100644 modules/nf-core/stringtie/stringtie/environment.yml create mode 100644 modules/nf-core/stringtie/stringtie/tests/main.nf.test create mode 100644 modules/nf-core/stringtie/stringtie/tests/main.nf.test.snap create mode 100644 modules/nf-core/stringtie/stringtie/tests/tags.yml create mode 100644 modules/nf-core/trimgalore/environment.yml diff --git a/modules.json b/modules.json index 2a84205f..57acc918 100644 --- a/modules.json +++ b/modules.json @@ -5,139 +5,164 @@ "https://github.com/nf-core/modules.git": { "modules": { "nf-core": { + "bedtools/intersect": { + "branch": "master", + "git_sha": "3b248b84694d1939ac4bb33df84bf6233a34d668", + "installed_by": ["modules"] + }, + "bedtools/sort": { + "branch": "master", + "git_sha": "3b248b84694d1939ac4bb33df84bf6233a34d668", + "installed_by": ["modules"] + }, "bowtie/align": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "3c77ca9aac783e76c3614a06db3bfe4fef619bde", "installed_by": ["modules"] }, "bowtie/build": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": ["modules"] }, "bowtie2/align": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "3c77ca9aac783e76c3614a06db3bfe4fef619bde", "installed_by": ["modules"] }, "bowtie2/build": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "1fea64f5132a813ec97c1c6d3a74e0aee7142b6d", "installed_by": ["modules"] }, "bwa/index": { "branch": "master", - "git_sha": "28a23ea6529caff44855c774f439a4074883027c", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "installed_by": ["modules"] + }, + "cat/cat": { + "branch": "master", + "git_sha": "d593e8f6b7d1bbbb2acf43a4b9efeeac8d6720f2", "installed_by": ["modules"] }, "cat/fastq": { "branch": "master", - "git_sha": "363a40e3af1f2dec0545379f4ede49c1fac089f1", + "git_sha": "e8940f18cfbbdcdcde38f4b3633df5ed4e48da10", "installed_by": ["modules"] }, "circexplorer2/annotate": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": ["modules"] }, "circexplorer2/parse": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "installed_by": ["modules"] + }, + "csvtk/split": { + "branch": "master", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": ["modules"] }, "custom/dumpsoftwareversions": { "branch": "master", - "git_sha": "bba7e362e4afead70653f84d8700588ea28d0f9e", + "git_sha": "8ec825f465b9c17f9d83000022995b4f7de6fe93", "installed_by": ["modules"] }, "fastqc": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "617777a807a1770f73deb38c80004bac06807eef", + "installed_by": ["modules"] + }, + "gawk": { + "branch": "master", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": ["modules"] }, "hisat2/align": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": ["modules"] }, "hisat2/build": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": ["modules"] }, "hisat2/extractsplicesites": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": ["modules"] }, "miranda": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": ["modules"] }, "multiqc": { "branch": "master", - "git_sha": "4ab13872435962dadc239979554d13709e20bf29", + "git_sha": "8ec825f465b9c17f9d83000022995b4f7de6fe93", "installed_by": ["modules"] }, "samtools/flagstat": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", "installed_by": ["bam_stats_samtools"] }, "samtools/idxstats": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", "installed_by": ["bam_stats_samtools"] }, "samtools/index": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", "installed_by": ["bam_sort_stats_samtools", "modules"] }, "samtools/sort": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", "installed_by": ["bam_sort_stats_samtools", "modules"] }, "samtools/stats": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", "installed_by": ["bam_stats_samtools"] }, "samtools/view": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", "installed_by": ["modules"] }, "segemehl/align": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": ["modules"] }, "segemehl/index": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": ["modules"] }, "star/align": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", "installed_by": ["modules"] }, "star/genomegenerate": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "d87a6e2156c2099c09280fa70776eaf0a824817a", "installed_by": ["modules"] }, "stringtie/stringtie": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "b0dcb44b018d9b2bcb35b1abb7bcd34061bc5a6d", "installed_by": ["modules"] }, "trimgalore": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": ["modules"] } } @@ -146,12 +171,12 @@ "nf-core": { "bam_sort_stats_samtools": { "branch": "master", - "git_sha": "7c8eeb2b37a6c6d3ffba0aef55ff60c8718c0ba6", + "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", "installed_by": ["subworkflows"] }, "bam_stats_samtools": { "branch": "master", - "git_sha": "cfd937a668919d948f6fcbf4218e79de50c2f36f", + "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", "installed_by": ["bam_sort_stats_samtools"] } } diff --git a/modules/nf-core/bedtools/intersect/environment.yml b/modules/nf-core/bedtools/intersect/environment.yml index 55ce727a..2a343050 100644 --- a/modules/nf-core/bedtools/intersect/environment.yml +++ b/modules/nf-core/bedtools/intersect/environment.yml @@ -1,6 +1,7 @@ +name: bedtools_intersect channels: - conda-forge - bioconda - defaults dependencies: - - bioconda::bedtools=2.30.0 + - bioconda::bedtools=2.31.1 diff --git a/modules/nf-core/bedtools/intersect/main.nf b/modules/nf-core/bedtools/intersect/main.nf index 177fb5d5..d9e79e7f 100644 --- a/modules/nf-core/bedtools/intersect/main.nf +++ b/modules/nf-core/bedtools/intersect/main.nf @@ -4,8 +4,8 @@ process BEDTOOLS_INTERSECT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/bedtools:2.30.0--hc088bd4_0' : - 'biocontainers/bedtools:2.30.0--hc088bd4_0' }" + 'https://depot.galaxyproject.org/singularity/bedtools:2.31.1--hf5e1c6e_0' : + 'biocontainers/bedtools:2.31.1--hf5e1c6e_0' }" input: tuple val(meta), path(intervals1), path(intervals2) diff --git a/modules/nf-core/bedtools/sort/environment.yml b/modules/nf-core/bedtools/sort/environment.yml index ee820940..87b2e425 100644 --- a/modules/nf-core/bedtools/sort/environment.yml +++ b/modules/nf-core/bedtools/sort/environment.yml @@ -1,6 +1,7 @@ +name: bedtools_sort channels: - conda-forge - bioconda - defaults dependencies: - - bioconda::bedtools=2.31.0 + - bioconda::bedtools=2.31.1 diff --git a/modules/nf-core/bedtools/sort/main.nf b/modules/nf-core/bedtools/sort/main.nf index 5b748903..b833150a 100644 --- a/modules/nf-core/bedtools/sort/main.nf +++ b/modules/nf-core/bedtools/sort/main.nf @@ -4,8 +4,8 @@ process BEDTOOLS_SORT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/bedtools:2.31.0--hf5e1c6e_2' : - 'biocontainers/bedtools:2.31.0--hf5e1c6e_2' }" + 'https://depot.galaxyproject.org/singularity/bedtools:2.31.1--hf5e1c6e_0' : + 'biocontainers/bedtools:2.31.1--hf5e1c6e_0' }" input: tuple val(meta), path(intervals) diff --git a/modules/nf-core/bowtie/align/environment.yml b/modules/nf-core/bowtie/align/environment.yml new file mode 100644 index 00000000..2617e6f0 --- /dev/null +++ b/modules/nf-core/bowtie/align/environment.yml @@ -0,0 +1,7 @@ +name: bowtie_align +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::bowtie=1.3.0 diff --git a/modules/nf-core/bowtie/align/main.nf b/modules/nf-core/bowtie/align/main.nf index 082c0762..29e9cd53 100644 --- a/modules/nf-core/bowtie/align/main.nf +++ b/modules/nf-core/bowtie/align/main.nf @@ -2,7 +2,7 @@ process BOWTIE_ALIGN { tag "$meta.id" label 'process_high' - conda "bioconda::bowtie=1.3.0 bioconda::samtools=1.16.1" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-ffbf83a6b0ab6ec567a336cf349b80637135bca3:c84c7c55c45af231883d9ff4fe706ac44c479c36-0' : 'biocontainers/mulled-v2-ffbf83a6b0ab6ec567a336cf349b80637135bca3:c84c7c55c45af231883d9ff4fe706ac44c479c36-0' }" @@ -36,7 +36,7 @@ process BOWTIE_ALIGN { $unaligned \\ $args \\ $endedness \\ - 2> ${prefix}.out \\ + 2> >(tee ${prefix}.out >&2) \\ | samtools view $args2 -@ $task.cpus -bS -o ${prefix}.bam - if [ -f ${prefix}.unmapped.fastq ]; then diff --git a/modules/nf-core/bowtie/build/environment.yml b/modules/nf-core/bowtie/build/environment.yml new file mode 100644 index 00000000..0907b0f8 --- /dev/null +++ b/modules/nf-core/bowtie/build/environment.yml @@ -0,0 +1,7 @@ +name: bowtie_build +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::bowtie=1.3.0 diff --git a/modules/nf-core/bowtie/build/main.nf b/modules/nf-core/bowtie/build/main.nf index 6de02e6e..05e22fe8 100644 --- a/modules/nf-core/bowtie/build/main.nf +++ b/modules/nf-core/bowtie/build/main.nf @@ -2,7 +2,7 @@ process BOWTIE_BUILD { tag "$fasta" label 'process_high' - conda "bioconda::bowtie=1.3.0" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/bowtie:1.3.0--py38hed8969a_1' : 'biocontainers/bowtie:1.3.0--py38hed8969a_1' }" diff --git a/modules/nf-core/bowtie2/align/environment.yml b/modules/nf-core/bowtie2/align/environment.yml new file mode 100644 index 00000000..d2796359 --- /dev/null +++ b/modules/nf-core/bowtie2/align/environment.yml @@ -0,0 +1,9 @@ +name: bowtie2_align +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::bowtie2=2.5.2 + - bioconda::samtools=1.18 + - conda-forge::pigz=2.6 diff --git a/modules/nf-core/bowtie2/align/main.nf b/modules/nf-core/bowtie2/align/main.nf index a77114d2..8c405ee3 100644 --- a/modules/nf-core/bowtie2/align/main.nf +++ b/modules/nf-core/bowtie2/align/main.nf @@ -2,10 +2,10 @@ process BOWTIE2_ALIGN { tag "$meta.id" label "process_high" - conda "bioconda::bowtie2=2.4.4 bioconda::samtools=1.16.1 conda-forge::pigz=2.6" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-ac74a7f02cebcfcc07d8e8d1d750af9c83b4d45a:a0ffedb52808e102887f6ce600d092675bf3528a-0' : - 'biocontainers/mulled-v2-ac74a7f02cebcfcc07d8e8d1d750af9c83b4d45a:a0ffedb52808e102887f6ce600d092675bf3528a-0' }" + 'https://depot.galaxyproject.org/singularity/mulled-v2-ac74a7f02cebcfcc07d8e8d1d750af9c83b4d45a:f70b31a2db15c023d641c32f433fb02cd04df5a6-0' : + 'biocontainers/mulled-v2-ac74a7f02cebcfcc07d8e8d1d750af9c83b4d45a:f70b31a2db15c023d641c32f433fb02cd04df5a6-0' }" input: tuple val(meta) , path(reads) @@ -52,7 +52,7 @@ process BOWTIE2_ALIGN { --threads $task.cpus \\ $unaligned \\ $args \\ - 2> ${prefix}.bowtie2.log \\ + 2> >(tee ${prefix}.bowtie2.log >&2) \\ | samtools $samtools_command $args2 --threads $task.cpus -o ${prefix}.${extension} - if [ -f ${prefix}.unmapped.fastq.1.gz ]; then @@ -76,12 +76,17 @@ process BOWTIE2_ALIGN { def prefix = task.ext.prefix ?: "${meta.id}" def extension_pattern = /(--output-fmt|-O)+\s+(\S+)/ def extension = (args2 ==~ extension_pattern) ? (args2 =~ extension_pattern)[0][2].toLowerCase() : "bam" + def create_unmapped = "" + if (meta.single_end) { + create_unmapped = save_unaligned ? "touch ${prefix}.unmapped.fastq.gz" : "" + } else { + create_unmapped = save_unaligned ? "touch ${prefix}.unmapped_1.fastq.gz && touch ${prefix}.unmapped_2.fastq.gz" : "" + } """ touch ${prefix}.${extension} touch ${prefix}.bowtie2.log - touch ${prefix}.unmapped_1.fastq.gz - touch ${prefix}.unmapped_2.fastq.gz + ${create_unmapped} cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/bowtie2/align/tests/large_index.config b/modules/nf-core/bowtie2/align/tests/large_index.config new file mode 100644 index 00000000..fdc1c59d --- /dev/null +++ b/modules/nf-core/bowtie2/align/tests/large_index.config @@ -0,0 +1,5 @@ +process { + withName: BOWTIE2_BUILD { + ext.args = '--large-index' + } +} \ No newline at end of file diff --git a/modules/nf-core/bowtie2/align/tests/main.nf.test b/modules/nf-core/bowtie2/align/tests/main.nf.test new file mode 100644 index 00000000..a478d17b --- /dev/null +++ b/modules/nf-core/bowtie2/align/tests/main.nf.test @@ -0,0 +1,561 @@ +nextflow_process { + + name "Test Process BOWTIE2_ALIGN" + script "../main.nf" + process "BOWTIE2_ALIGN" + tag "modules" + tag "modules_nfcore" + tag "bowtie2" + tag "bowtie2/align" + + test("sarscov2 - fastq, index, false, false - bam") { + + setup { + run("BOWTIE2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = [ + [ id:'test'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:true ], // meta map + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + ] + input[1] = BOWTIE2_BUILD.out.index + input[2] = false //save_unaligned + input[3] = false //sort + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.aligned[0][1]).name, + process.out.log, + process.out.fastq, + process.out.versions + ).match() } + ) + } + + } + + test("sarscov2 - fastq, index, false, false - sam") { + + config "./sam.config" + setup { + run("BOWTIE2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = [ + [ id:'test'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:true ], // meta map + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + ] + input[1] = BOWTIE2_BUILD.out.index + input[2] = false //save_unaligned + input[3] = false //sort + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.aligned[0][1]).readLines()[0..4], + process.out.log, + process.out.fastq, + process.out.versions + ).match() } + ) + } + + } + + test("sarscov2 - fastq, index, false, false - sam2") { + + config "./sam2.config" + setup { + run("BOWTIE2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = [ + [ id:'test'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:true ], // meta map + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + ] + input[1] = BOWTIE2_BUILD.out.index + input[2] = false //save_unaligned + input[3] = false //sort + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.aligned[0][1]).readLines()[0..4], + process.out.log, + process.out.fastq, + process.out.versions + ).match() } + ) + } + + } + + test("sarscov2 - fastq, index, false, true - bam") { + + setup { + run("BOWTIE2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = [ + [ id:'test'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:true ], // meta map + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + ] + input[1] = BOWTIE2_BUILD.out.index + input[2] = false //save_unaligned + input[3] = true //sort + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.aligned[0][1]).name, + process.out.log, + process.out.fastq, + process.out.versions + ).match() } + ) + } + + } + + test("sarscov2 - [fastq1, fastq2], index, false, false - bam") { + + setup { + run("BOWTIE2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = [ + [ id:'test'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + [ + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) + ] + ] + input[1] = BOWTIE2_BUILD.out.index + input[2] = false //save_unaligned + input[3] = false //sort + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.aligned[0][1]).name, + process.out.log, + process.out.fastq, + process.out.versions + ).match() } + ) + } + + } + + test("sarscov2 - [fastq1, fastq2], index, false, true - bam") { + + setup { + run("BOWTIE2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = [ + [ id:'test'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + [ + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) + ] + ] + input[1] = BOWTIE2_BUILD.out.index + input[2] = false //save_unaligned + input[3] = true //sort + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.aligned[0][1]).name, + process.out.log, + process.out.fastq, + process.out.versions + ).match() } + ) + } + + } + + test("sarscov2 - fastq, large_index, false, false - bam") { + + config "./large_index.config" + setup { + run("BOWTIE2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = [ + [ id:'test'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:true ], // meta map + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + ] + input[1] = BOWTIE2_BUILD.out.index + input[2] = false //save_unaligned + input[3] = false //sort + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.aligned[0][1]).name, + process.out.log, + process.out.fastq, + process.out.versions + ).match() } + ) + } + + } + + test("sarscov2 - [fastq1, fastq2], large_index, false, false - bam") { + + config "./large_index.config" + setup { + run("BOWTIE2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = [ + [ id:'test'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + [ + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) + ] + ] + input[1] = BOWTIE2_BUILD.out.index + input[2] = false //save_unaligned + input[3] = false //sort + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.aligned[0][1]).name, + process.out.log, + process.out.fastq, + process.out.versions + ).match() } + ) + } + + } + + test("sarscov2 - [fastq1, fastq2], index, true, false - bam") { + + setup { + run("BOWTIE2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = [ + [ id:'test'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + [ + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) + ] + ] + input[1] = BOWTIE2_BUILD.out.index + input[2] = true //save_unaligned + input[3] = false //sort + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.aligned[0][1]).name, + process.out.log, + process.out.fastq, + process.out.versions + ).match() } + ) + } + + } + + test("sarscov2 - fastq, index, true, false - bam") { + + setup { + run("BOWTIE2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = [ + [ id:'test'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:true ], // meta map + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + ] + input[1] = BOWTIE2_BUILD.out.index + input[2] = true //save_unaligned + input[3] = false //sort + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.aligned[0][1]).name, + process.out.log, + process.out.fastq, + process.out.versions + ).match() } + + ) + } + + } + + test("sarscov2 - [fastq1, fastq2], index, false, false - stub") { + + options "-stub" + setup { + run("BOWTIE2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = [ + [ id:'test'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + [ + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) + ] + ] + input[1] = BOWTIE2_BUILD.out.index + input[2] = false //save_unaligned + input[3] = false //sort + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.aligned[0][1]).name, + file(process.out.log[0][1]).name, + process.out.fastq, + process.out.versions + ).match() } + ) + } + + } + + test("sarscov2 - fastq, index, true, false - stub") { + + options "-stub" + setup { + run("BOWTIE2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = [ + [ id:'test'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:true ], // meta map + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + ] + input[1] = BOWTIE2_BUILD.out.index + input[2] = true //save_unaligned + input[3] = false //sort + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.aligned[0][1]).name, + file(process.out.log[0][1]).name, + file(process.out.fastq[0][1]).name, + process.out.versions + ).match() } + ) + } + + } + +} diff --git a/modules/nf-core/bowtie2/align/tests/main.nf.test.snap b/modules/nf-core/bowtie2/align/tests/main.nf.test.snap new file mode 100644 index 00000000..883dc7ec --- /dev/null +++ b/modules/nf-core/bowtie2/align/tests/main.nf.test.snap @@ -0,0 +1,263 @@ +{ + "sarscov2 - fastq, index, false, false - sam2": { + "content": [ + [ + "ERR5069949.2151832\t16\tMT192765.1\t17453\t42\t150M\t*\t0\t0\tACGCACATTGCTAACTAAGGGCACACTAGAACCAGAATATTTCAATTCAGTGTGTAGACTTATGAAAACTATAGGTCCAGACATGTTCCTCGGAACTTGTCGGCGTTGTCCTGCTGAAATTGTTGACACTGTGAGTGCTTTGGTTTATGA\tAAAA\\n#nf-core-versions tbody:nth-child(even) {\\n background-color: #f2f2f2;\\n\\", + " }\\n\\n\\n \\n \\n \\n \\n \\n \\n \\n\\", + " \\n\\n\\n \\n \\n\\", + " \\ \\n\\n\\n\\n \\n \\", + " \\ \\n \\n\\n\\n\\n\\", + " \\n\\n \\n \\n\\", + " \\ \\n\\n\\n\\n\\n\\n \\n\\", + " \\ \\n \\n\\n\\n\\n\\", + " \\n\\n \\n \\n\\" + ], + [ + "CUSTOM_DUMPSOFTWAREVERSIONS:", + " python: 3.11.7", + " yaml: 5.4.1", + "TOOL1:", + " tool1: 0.11.9", + "TOOL2:", + " tool2: '1.9'", + "Workflow:" + ] ], - "timestamp": "2023-10-11T17:10:02.930699" + "timestamp": "2024-01-09T23:01:18.710682" } -} +} \ No newline at end of file diff --git a/modules/nf-core/fastqc/tests/main.nf.test b/modules/nf-core/fastqc/tests/main.nf.test index b9e8f926..ad9bc54f 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test +++ b/modules/nf-core/fastqc/tests/main.nf.test @@ -3,23 +3,21 @@ nextflow_process { name "Test Process FASTQC" script "../main.nf" process "FASTQC" + tag "modules" tag "modules_nfcore" tag "fastqc" - test("Single-Read") { + test("sarscov2 single-end [fastq]") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = [ - [ id: 'test', single_end:true ], - [ - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) - ] + [ id: 'test', single_end:true ], + [ + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + ] ] """ } @@ -28,82 +26,195 @@ nextflow_process { then { assertAll ( { assert process.success }, + // NOTE The report contains the date inside it, which means that the md5sum is stable per day, but not longer than that. So you can't md5sum it. // looks like this:
    Mon 2 Oct 2023
    test.gz
    // https://github.com/nf-core/modules/pull/3903#issuecomment-1743620039 - { assert process.out.html.get(0).get(1) ==~ ".*/test_fastqc.html" }, - { assert path(process.out.html.get(0).get(1)).getText().contains("") }, - { assert snapshot(process.out.versions).match("versions") }, - { assert process.out.zip.get(0).get(1) ==~ ".*/test_fastqc.zip" } + + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("") }, + + { assert snapshot(process.out.versions).match("versions") } + ) + } + } + + test("sarscov2 paired-end [fastq]") { + + when { + process { + """ + input[0] = [ + [id: 'test', single_end: false], // meta map + [ + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) + ] + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + + { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, + { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, + { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, + { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, + { assert path(process.out.html[0][1][0]).text.contains("") }, + { assert path(process.out.html[0][1][1]).text.contains("") }, + + { assert snapshot(process.out.versions).match("versions") } + ) + } + } + + test("sarscov2 interleaved [fastq]") { + + when { + process { + """ + input[0] = [ + [id: 'test', single_end: false], // meta map + file(params.test_data['sarscov2']['illumina']['test_interleaved_fastq_gz'], checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("") }, + + { assert snapshot(process.out.versions).match("versions") } + ) + } + } + + test("sarscov2 paired-end [bam]") { + + when { + process { + """ + input[0] = [ + [id: 'test', single_end: false], // meta map + file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("") }, + + { assert snapshot(process.out.versions).match("versions") } ) } } -// TODO -// // -// // Test with paired-end data -// // -// workflow test_fastqc_paired_end { -// input = [ -// [id: 'test', single_end: false], // meta map -// [ -// file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), -// file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) -// ] -// ] - -// FASTQC ( input ) -// } - -// // -// // Test with interleaved data -// // -// workflow test_fastqc_interleaved { -// input = [ -// [id: 'test', single_end: false], // meta map -// file(params.test_data['sarscov2']['illumina']['test_interleaved_fastq_gz'], checkIfExists: true) -// ] - -// FASTQC ( input ) -// } - -// // -// // Test with bam data -// // -// workflow test_fastqc_bam { -// input = [ -// [id: 'test', single_end: false], // meta map -// file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) -// ] - -// FASTQC ( input ) -// } - -// // -// // Test with multiple samples -// // -// workflow test_fastqc_multiple { -// input = [ -// [id: 'test', single_end: false], // meta map -// [ -// file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), -// file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true), -// file(params.test_data['sarscov2']['illumina']['test2_1_fastq_gz'], checkIfExists: true), -// file(params.test_data['sarscov2']['illumina']['test2_2_fastq_gz'], checkIfExists: true) -// ] -// ] - -// FASTQC ( input ) -// } - -// // -// // Test with custom prefix -// // -// workflow test_fastqc_custom_prefix { -// input = [ -// [ id:'mysample', single_end:true ], // meta map -// file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) -// ] - -// FASTQC ( input ) -// } + + test("sarscov2 multiple [fastq]") { + + when { + process { + """ + input[0] = [ + [id: 'test', single_end: false], // meta map + [ + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test2_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test2_2_fastq_gz'], checkIfExists: true) + ] + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + + { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, + { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, + { assert process.out.html[0][1][2] ==~ ".*/test_3_fastqc.html" }, + { assert process.out.html[0][1][3] ==~ ".*/test_4_fastqc.html" }, + { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, + { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, + { assert process.out.zip[0][1][2] ==~ ".*/test_3_fastqc.zip" }, + { assert process.out.zip[0][1][3] ==~ ".*/test_4_fastqc.zip" }, + { assert path(process.out.html[0][1][0]).text.contains("") }, + { assert path(process.out.html[0][1][1]).text.contains("") }, + { assert path(process.out.html[0][1][2]).text.contains("") }, + { assert path(process.out.html[0][1][3]).text.contains("") }, + + { assert snapshot(process.out.versions).match("versions") } + ) + } + } + + test("sarscov2 custom_prefix") { + + when { + process { + """ + input[0] = [ + [ id:'mysample', single_end:true ], // meta map + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + + { assert process.out.html[0][1] ==~ ".*/mysample_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/mysample_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("") }, + + { assert snapshot(process.out.versions).match("versions") } + ) + } + } + + test("sarscov2 single-end [fastq] - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id: 'test', single_end:true ], + [ + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + ] + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out.html.collect { file(it[1]).getName() } + + process.out.zip.collect { file(it[1]).getName() } + + process.out.versions ).match() } + ) + } + } + } diff --git a/modules/nf-core/fastqc/tests/main.nf.test.snap b/modules/nf-core/fastqc/tests/main.nf.test.snap index 636a32ce..5ef5afbd 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test.snap +++ b/modules/nf-core/fastqc/tests/main.nf.test.snap @@ -1,10 +1,20 @@ { + "sarscov2 single-end [fastq] - stub": { + "content": [ + [ + "test.html", + "test.zip", + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "timestamp": "2023-12-29T02:48:05.126117287" + }, "versions": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], - "timestamp": "2023-10-09T23:40:54+0000" + "timestamp": "2023-12-29T02:46:49.507942667" } } \ No newline at end of file diff --git a/modules/nf-core/hisat2/align/environment.yml b/modules/nf-core/hisat2/align/environment.yml new file mode 100644 index 00000000..0c1415f9 --- /dev/null +++ b/modules/nf-core/hisat2/align/environment.yml @@ -0,0 +1,8 @@ +name: hisat2_align +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::hisat2=2.2.1 + - bioconda::samtools=1.16.1 diff --git a/modules/nf-core/hisat2/align/main.nf b/modules/nf-core/hisat2/align/main.nf index db8e8bb6..2289a9fc 100644 --- a/modules/nf-core/hisat2/align/main.nf +++ b/modules/nf-core/hisat2/align/main.nf @@ -3,7 +3,7 @@ process HISAT2_ALIGN { label 'process_high' // WARN: Version information not provided by tool on CLI. Please update version string below when bumping container versions. - conda "bioconda::hisat2=2.2.1 bioconda::samtools=1.16.1" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-a97e90b3b802d1da3d6958e0867610c718cb5eb1:2cdf6bf1e92acbeb9b2834b1c58754167173a410-0' : 'biocontainers/mulled-v2-a97e90b3b802d1da3d6958e0867610c718cb5eb1:2cdf6bf1e92acbeb9b2834b1c58754167173a410-0' }" diff --git a/modules/nf-core/hisat2/build/environment.yml b/modules/nf-core/hisat2/build/environment.yml new file mode 100644 index 00000000..2e67cd3e --- /dev/null +++ b/modules/nf-core/hisat2/build/environment.yml @@ -0,0 +1,7 @@ +name: hisat2_build +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::hisat2=2.2.1 diff --git a/modules/nf-core/hisat2/build/main.nf b/modules/nf-core/hisat2/build/main.nf index 90f8efcc..766e8731 100644 --- a/modules/nf-core/hisat2/build/main.nf +++ b/modules/nf-core/hisat2/build/main.nf @@ -4,7 +4,7 @@ process HISAT2_BUILD { label 'process_high_memory' // WARN: Version information not provided by tool on CLI. Please update version string below when bumping container versions. - conda "bioconda::hisat2=2.2.1" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/hisat2:2.2.1--h1b792b2_3' : 'biocontainers/hisat2:2.2.1--h1b792b2_3' }" diff --git a/modules/nf-core/hisat2/extractsplicesites/environment.yml b/modules/nf-core/hisat2/extractsplicesites/environment.yml new file mode 100644 index 00000000..4b03e5e4 --- /dev/null +++ b/modules/nf-core/hisat2/extractsplicesites/environment.yml @@ -0,0 +1,7 @@ +name: hisat2_extractsplicesites +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::hisat2=2.2.1 diff --git a/modules/nf-core/hisat2/extractsplicesites/main.nf b/modules/nf-core/hisat2/extractsplicesites/main.nf index a6e59e20..b0c8513a 100644 --- a/modules/nf-core/hisat2/extractsplicesites/main.nf +++ b/modules/nf-core/hisat2/extractsplicesites/main.nf @@ -3,7 +3,7 @@ process HISAT2_EXTRACTSPLICESITES { label 'process_medium' // WARN: Version information not provided by tool on CLI. Please update version string below when bumping container versions. - conda "bioconda::hisat2=2.2.1" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/hisat2:2.2.1--h1b792b2_3' : 'biocontainers/hisat2:2.2.1--h1b792b2_3' }" diff --git a/modules/nf-core/miranda/environment.yml b/modules/nf-core/miranda/environment.yml new file mode 100644 index 00000000..a04ca7f8 --- /dev/null +++ b/modules/nf-core/miranda/environment.yml @@ -0,0 +1,7 @@ +name: miranda +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::miranda=3.3a diff --git a/modules/nf-core/miranda/main.nf b/modules/nf-core/miranda/main.nf index eb7f6e76..47a98253 100644 --- a/modules/nf-core/miranda/main.nf +++ b/modules/nf-core/miranda/main.nf @@ -2,7 +2,7 @@ process MIRANDA { tag "$meta.id" label 'process_medium' - conda "bioconda::miranda=3.3a" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/miranda:3.3a--h779adbc_3': 'biocontainers/miranda:3.3a--h779adbc_3' }" diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index bc0bdb5b..7625b752 100644 --- a/modules/nf-core/multiqc/environment.yml +++ b/modules/nf-core/multiqc/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - bioconda::multiqc=1.18 + - bioconda::multiqc=1.19 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 00cc48d2..1b9f7c43 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -3,8 +3,8 @@ process MULTIQC { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.18--pyhdfd78af_0' : - 'biocontainers/multiqc:1.18--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.19--pyhdfd78af_0' : + 'biocontainers/multiqc:1.19--pyhdfd78af_0' }" input: path multiqc_files, stageAs: "?/*" @@ -43,7 +43,7 @@ process MULTIQC { stub: """ - touch multiqc_data + mkdir multiqc_data touch multiqc_plots touch multiqc_report.html diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index f1aa660e..45a9bc35 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -1,4 +1,3 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json name: multiqc description: Aggregate results from bioinformatics analyses across many samples into a single report keywords: diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test index c2dad217..d0438eda 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -7,12 +7,9 @@ nextflow_process { tag "modules_nfcore" tag "multiqc" - test("MULTIQC: FASTQC") { + test("sarscov2 single-end [fastqc]") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)]) @@ -26,20 +23,17 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert path(process.out.report.get(0)).exists() }, - { assert path(process.out.data.get(0)).exists() }, - { assert path(process.out.versions.get(0)).getText().contains("multiqc") } + { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, + { assert process.out.data[0] ==~ ".*/multiqc_data" }, + { assert snapshot(process.out.versions).match("versions") } ) } } - test("MULTIQC: FASTQC and a config file") { + test("sarscov2 single-end [fastqc] [config]") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)]) @@ -53,9 +47,35 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert path(process.out.report.get(0)).exists() }, - { assert path(process.out.data.get(0)).exists() }, - { assert path(process.out.versions.get(0)).getText().contains("multiqc") } + { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, + { assert process.out.data[0] ==~ ".*/multiqc_data" }, + { assert snapshot(process.out.versions).match("versions") } + ) + } + } + + test("sarscov2 single-end [fastqc] - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)]) + input[1] = [] + input[2] = [] + input[3] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.report.collect { file(it).getName() } + + process.out.data.collect { file(it).getName() } + + process.out.plots.collect { file(it).getName() } + + process.out.versions ).match() } ) } diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap new file mode 100644 index 00000000..d37e7304 --- /dev/null +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -0,0 +1,21 @@ +{ + "versions": { + "content": [ + [ + "versions.yml:md5,14e9a2661241abd828f4f06a7b5c222d" + ] + ], + "timestamp": "2024-01-09T23:02:49.911994" + }, + "sarscov2 single-end [fastqc] - stub": { + "content": [ + [ + "multiqc_report.html", + "multiqc_data", + "multiqc_plots", + "versions.yml:md5,14e9a2661241abd828f4f06a7b5c222d" + ] + ], + "timestamp": "2024-01-09T23:03:14.524346" + } +} \ No newline at end of file diff --git a/modules/nf-core/samtools/flagstat/environment.yml b/modules/nf-core/samtools/flagstat/environment.yml new file mode 100644 index 00000000..5efae053 --- /dev/null +++ b/modules/nf-core/samtools/flagstat/environment.yml @@ -0,0 +1,7 @@ +name: samtools_flagstat +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::samtools=1.18 diff --git a/modules/nf-core/samtools/flagstat/main.nf b/modules/nf-core/samtools/flagstat/main.nf index b75707ec..f1893d7c 100644 --- a/modules/nf-core/samtools/flagstat/main.nf +++ b/modules/nf-core/samtools/flagstat/main.nf @@ -2,10 +2,10 @@ process SAMTOOLS_FLAGSTAT { tag "$meta.id" label 'process_single' - conda "bioconda::samtools=1.17" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.17--h00cdaf9_0' : - 'biocontainers/samtools:1.17--h00cdaf9_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.18--h50ea8bc_1' : + 'biocontainers/samtools:1.18--h50ea8bc_1' }" input: tuple val(meta), path(bam), path(bai) diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test b/modules/nf-core/samtools/flagstat/tests/main.nf.test new file mode 100644 index 00000000..c8dd8dc9 --- /dev/null +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test @@ -0,0 +1,36 @@ +nextflow_process { + + name "Test Process SAMTOOLS_FLAGSTAT" + script "../main.nf" + process "SAMTOOLS_FLAGSTAT" + tag "modules" + tag "modules_nfcore" + tag "samtools" + tag "samtools/flagstat" + + test("BAM") { + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam_bai'], checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out.flagstat).match() }, + { assert path(process.out.versions.get(0)).getText().contains("samtools") } + ) + } + } +} diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap new file mode 100644 index 00000000..880019f2 --- /dev/null +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap @@ -0,0 +1,16 @@ +{ + "BAM": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" + ] + ] + ], + "timestamp": "2023-11-14T15:49:22.577133" + } +} \ No newline at end of file diff --git a/modules/nf-core/samtools/flagstat/tests/tags.yml b/modules/nf-core/samtools/flagstat/tests/tags.yml new file mode 100644 index 00000000..2d2b7255 --- /dev/null +++ b/modules/nf-core/samtools/flagstat/tests/tags.yml @@ -0,0 +1,2 @@ +samtools/flagstat: + - modules/nf-core/samtools/flagstat/** diff --git a/modules/nf-core/samtools/idxstats/environment.yml b/modules/nf-core/samtools/idxstats/environment.yml new file mode 100644 index 00000000..2401db0f --- /dev/null +++ b/modules/nf-core/samtools/idxstats/environment.yml @@ -0,0 +1,7 @@ +name: samtools_idxstats +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::samtools=1.18 diff --git a/modules/nf-core/samtools/idxstats/main.nf b/modules/nf-core/samtools/idxstats/main.nf index 83c7c34b..00d916bb 100644 --- a/modules/nf-core/samtools/idxstats/main.nf +++ b/modules/nf-core/samtools/idxstats/main.nf @@ -2,10 +2,10 @@ process SAMTOOLS_IDXSTATS { tag "$meta.id" label 'process_single' - conda "bioconda::samtools=1.17" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.17--h00cdaf9_0' : - 'biocontainers/samtools:1.17--h00cdaf9_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.18--h50ea8bc_1' : + 'biocontainers/samtools:1.18--h50ea8bc_1' }" input: tuple val(meta), path(bam), path(bai) diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test b/modules/nf-core/samtools/idxstats/tests/main.nf.test new file mode 100644 index 00000000..f6c92150 --- /dev/null +++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test @@ -0,0 +1,36 @@ +nextflow_process { + + name "Test Process SAMTOOLS_IDXSTATS" + script "../main.nf" + process "SAMTOOLS_IDXSTATS" + tag "modules" + tag "modules_nfcore" + tag "samtools" + tag "samtools/idxstats" + + test("BAM") { + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam_bai'], checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out.idxstats).match() }, + { assert path(process.out.versions.get(0)).getText().contains("samtools") } + ) + } + } +} diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap new file mode 100644 index 00000000..4c6c12bd --- /dev/null +++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap @@ -0,0 +1,16 @@ +{ + "BAM": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" + ] + ] + ], + "timestamp": "2023-11-14T15:52:19.875194" + } +} \ No newline at end of file diff --git a/modules/nf-core/samtools/idxstats/tests/tags.yml b/modules/nf-core/samtools/idxstats/tests/tags.yml new file mode 100644 index 00000000..d3057c61 --- /dev/null +++ b/modules/nf-core/samtools/idxstats/tests/tags.yml @@ -0,0 +1,2 @@ +samtools/idxstats: + - modules/nf-core/samtools/idxstats/** diff --git a/modules/nf-core/samtools/index/environment.yml b/modules/nf-core/samtools/index/environment.yml new file mode 100644 index 00000000..296ed99e --- /dev/null +++ b/modules/nf-core/samtools/index/environment.yml @@ -0,0 +1,7 @@ +name: samtools_index +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::samtools=1.18 diff --git a/modules/nf-core/samtools/index/main.nf b/modules/nf-core/samtools/index/main.nf index 0b20aa4b..8ad18fdc 100644 --- a/modules/nf-core/samtools/index/main.nf +++ b/modules/nf-core/samtools/index/main.nf @@ -2,10 +2,10 @@ process SAMTOOLS_INDEX { tag "$meta.id" label 'process_low' - conda "bioconda::samtools=1.17" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.17--h00cdaf9_0' : - 'biocontainers/samtools:1.17--h00cdaf9_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.18--h50ea8bc_1' : + 'biocontainers/samtools:1.18--h50ea8bc_1' }" input: tuple val(meta), path(input) diff --git a/modules/nf-core/samtools/index/tests/csi.nextflow.config b/modules/nf-core/samtools/index/tests/csi.nextflow.config new file mode 100644 index 00000000..0ed260ef --- /dev/null +++ b/modules/nf-core/samtools/index/tests/csi.nextflow.config @@ -0,0 +1,7 @@ +process { + + withName: SAMTOOLS_INDEX { + ext.args = '-c' + } + +} diff --git a/modules/nf-core/samtools/index/tests/main.nf.test b/modules/nf-core/samtools/index/tests/main.nf.test new file mode 100644 index 00000000..c76a9169 --- /dev/null +++ b/modules/nf-core/samtools/index/tests/main.nf.test @@ -0,0 +1,87 @@ +nextflow_process { + + name "Test Process SAMTOOLS_INDEX" + script "../main.nf" + process "SAMTOOLS_INDEX" + tag "modules" + tag "modules_nfcore" + tag "samtools" + tag "samtools/index" + + test("sarscov2 [BAI]") { + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out.bai).match("bai") }, + { assert path(process.out.versions.get(0)).getText().contains("samtools") } + ) + } + } + + test("homo_sapiens [CRAI]") { + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.test_data['homo_sapiens']['illumina']['test_paired_end_recalibrated_sorted_cram'], checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out.crai).match("crai") }, + { assert path(process.out.versions.get(0)).getText().contains("samtools") } + ) + } + } + + test("homo_sapiens [CSI]") { + + config "./csi.nextflow.config" + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert path(process.out.csi.get(0).get(1)).exists() }, + { assert path(process.out.versions.get(0)).getText().contains("samtools") } + ) + } + } +} diff --git a/modules/nf-core/samtools/index/tests/main.nf.test.snap b/modules/nf-core/samtools/index/tests/main.nf.test.snap new file mode 100644 index 00000000..b3baee7f --- /dev/null +++ b/modules/nf-core/samtools/index/tests/main.nf.test.snap @@ -0,0 +1,28 @@ +{ + "crai": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" + ] + ] + ], + "timestamp": "2023-11-15T15:17:37.30801" + }, + "bai": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" + ] + ] + ], + "timestamp": "2023-11-15T15:17:30.869234" + } +} \ No newline at end of file diff --git a/modules/nf-core/samtools/index/tests/tags.yml b/modules/nf-core/samtools/index/tests/tags.yml new file mode 100644 index 00000000..e0f58a7a --- /dev/null +++ b/modules/nf-core/samtools/index/tests/tags.yml @@ -0,0 +1,2 @@ +samtools/index: + - modules/nf-core/samtools/index/** diff --git a/modules/nf-core/samtools/sort/environment.yml b/modules/nf-core/samtools/sort/environment.yml new file mode 100644 index 00000000..cd50868c --- /dev/null +++ b/modules/nf-core/samtools/sort/environment.yml @@ -0,0 +1,7 @@ +name: samtools_sort +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::samtools=1.18 diff --git a/modules/nf-core/samtools/sort/main.nf b/modules/nf-core/samtools/sort/main.nf index 2b7753fd..4a666d42 100644 --- a/modules/nf-core/samtools/sort/main.nf +++ b/modules/nf-core/samtools/sort/main.nf @@ -2,10 +2,10 @@ process SAMTOOLS_SORT { tag "$meta.id" label 'process_medium' - conda "bioconda::samtools=1.17" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.17--h00cdaf9_0' : - 'biocontainers/samtools:1.17--h00cdaf9_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.18--h50ea8bc_1' : + 'biocontainers/samtools:1.18--h50ea8bc_1' }" input: tuple val(meta), path(bam) diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test b/modules/nf-core/samtools/sort/tests/main.nf.test index 1f72f3b9..abb80978 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test +++ b/modules/nf-core/samtools/sort/tests/main.nf.test @@ -61,7 +61,10 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot( + file(process.out.bam[0][1]).name, + process.out.versions + ).match() } ) } diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test.snap b/modules/nf-core/samtools/sort/tests/main.nf.test.snap index a43566da..ff722259 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/sort/tests/main.nf.test.snap @@ -8,14 +8,14 @@ "id": "test", "single_end": false }, - "test.sorted.bam:md5,a29570e7607d217c2fa4d75829e09cd7" + "test.sorted.bam:md5,ea6a0fef94eb534e901f107a05a33a06" ] ], "1": [ ], "2": [ - "versions.yml:md5,46f7a36082fa1f68285fe30d689244e8" + "versions.yml:md5,33b6a403dc19a0d28e4219ccab0a1d80" ], "bam": [ [ @@ -23,17 +23,26 @@ "id": "test", "single_end": false }, - "test.sorted.bam:md5,a29570e7607d217c2fa4d75829e09cd7" + "test.sorted.bam:md5,ea6a0fef94eb534e901f107a05a33a06" ] ], "csi": [ ], "versions": [ - "versions.yml:md5,46f7a36082fa1f68285fe30d689244e8" + "versions.yml:md5,33b6a403dc19a0d28e4219ccab0a1d80" ] } ], - "timestamp": "2023-10-17T17:21:46.5427968" + "timestamp": "2023-12-04T11:11:22.005628301" + }, + "test_samtools_sort_stub": { + "content": [ + "test.sorted.bam", + [ + "versions.yml:md5,33b6a403dc19a0d28e4219ccab0a1d80" + ] + ], + "timestamp": "2023-12-04T17:47:22.314445935" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/stats/environment.yml b/modules/nf-core/samtools/stats/environment.yml new file mode 100644 index 00000000..b89ce647 --- /dev/null +++ b/modules/nf-core/samtools/stats/environment.yml @@ -0,0 +1,7 @@ +name: samtools_stats +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::samtools=1.18 diff --git a/modules/nf-core/samtools/stats/main.nf b/modules/nf-core/samtools/stats/main.nf index 4a2607de..7539140a 100644 --- a/modules/nf-core/samtools/stats/main.nf +++ b/modules/nf-core/samtools/stats/main.nf @@ -2,10 +2,10 @@ process SAMTOOLS_STATS { tag "$meta.id" label 'process_single' - conda "bioconda::samtools=1.17" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.17--h00cdaf9_0' : - 'biocontainers/samtools:1.17--h00cdaf9_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.18--h50ea8bc_1' : + 'biocontainers/samtools:1.18--h50ea8bc_1' }" input: tuple val(meta), path(input), path(input_index) diff --git a/modules/nf-core/samtools/stats/tests/main.nf.test b/modules/nf-core/samtools/stats/tests/main.nf.test index e037132c..20c3efe1 100644 --- a/modules/nf-core/samtools/stats/tests/main.nf.test +++ b/modules/nf-core/samtools/stats/tests/main.nf.test @@ -4,7 +4,7 @@ nextflow_process { script "../main.nf" process "SAMTOOLS_STATS" tag "modules" - tag "modules/nf-core" + tag "modules_nfcore" tag "samtools" tag "samtools/stats" diff --git a/modules/nf-core/samtools/stats/tests/main.nf.test.snap b/modules/nf-core/samtools/stats/tests/main.nf.test.snap index 516b2b01..025c83a5 100644 --- a/modules/nf-core/samtools/stats/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/stats/tests/main.nf.test.snap @@ -8,11 +8,11 @@ "id": "test", "single_end": false }, - "test.stats:md5,6e768486d5df0257351c5419a79f9c9b" + "test.stats:md5,045a48208b1c6f5b8af4347fe31f4def" ] ], "1": [ - "versions.yml:md5,08035f3409d934d47a416150884bb0df" + "versions.yml:md5,650a365c6635001436008350ae83337c" ], "stats": [ [ @@ -20,15 +20,15 @@ "id": "test", "single_end": false }, - "test.stats:md5,6e768486d5df0257351c5419a79f9c9b" + "test.stats:md5,045a48208b1c6f5b8af4347fe31f4def" ] ], "versions": [ - "versions.yml:md5,08035f3409d934d47a416150884bb0df" + "versions.yml:md5,650a365c6635001436008350ae83337c" ] } ], - "timestamp": "2023-10-18T12:12:42.998746" + "timestamp": "2023-12-04T11:07:28.26821485" }, "SAMTOOLS CRAM Should run without failures": { "content": [ @@ -39,11 +39,11 @@ "id": "test", "single_end": false }, - "test.stats:md5,7c9ee5747793cceb9d6f4d733345641a" + "test.stats:md5,dfbfa130d4a6925ddd1931dcd8354a43" ] ], "1": [ - "versions.yml:md5,08035f3409d934d47a416150884bb0df" + "versions.yml:md5,650a365c6635001436008350ae83337c" ], "stats": [ [ @@ -51,14 +51,14 @@ "id": "test", "single_end": false }, - "test.stats:md5,7c9ee5747793cceb9d6f4d733345641a" + "test.stats:md5,dfbfa130d4a6925ddd1931dcd8354a43" ] ], "versions": [ - "versions.yml:md5,08035f3409d934d47a416150884bb0df" + "versions.yml:md5,650a365c6635001436008350ae83337c" ] } ], - "timestamp": "2023-10-18T12:13:30.747222" + "timestamp": "2023-12-04T11:07:50.356233402" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/view/environment.yml b/modules/nf-core/samtools/view/environment.yml new file mode 100644 index 00000000..99aa69d0 --- /dev/null +++ b/modules/nf-core/samtools/view/environment.yml @@ -0,0 +1,7 @@ +name: samtools_view +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::samtools=1.18 diff --git a/modules/nf-core/samtools/view/main.nf b/modules/nf-core/samtools/view/main.nf index cb91facf..0b5a2912 100644 --- a/modules/nf-core/samtools/view/main.nf +++ b/modules/nf-core/samtools/view/main.nf @@ -2,10 +2,10 @@ process SAMTOOLS_VIEW { tag "$meta.id" label 'process_low' - conda "bioconda::samtools=1.17" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.17--h00cdaf9_0' : - 'biocontainers/samtools:1.17--h00cdaf9_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.18--h50ea8bc_1' : + 'biocontainers/samtools:1.18--h50ea8bc_1' }" input: tuple val(meta), path(input), path(index) @@ -53,10 +53,19 @@ process SAMTOOLS_VIEW { """ stub: + def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" + def file_type = args.contains("--output-fmt sam") ? "sam" : + args.contains("--output-fmt bam") ? "bam" : + args.contains("--output-fmt cram") ? "cram" : + input.getExtension() + if ("$input" == "${prefix}.${file_type}") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" + + def index = args.contains("--write-index") ? "touch ${prefix}.csi" : "" + """ - touch ${prefix}.bam - touch ${prefix}.cram + touch ${prefix}.${file_type} + ${index} cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/samtools/view/tests/bam.config b/modules/nf-core/samtools/view/tests/bam.config new file mode 100644 index 00000000..c10d1081 --- /dev/null +++ b/modules/nf-core/samtools/view/tests/bam.config @@ -0,0 +1,3 @@ +process { + ext.args = "--output-fmt bam" +} \ No newline at end of file diff --git a/modules/nf-core/samtools/view/tests/bam_index.config b/modules/nf-core/samtools/view/tests/bam_index.config new file mode 100644 index 00000000..771ae033 --- /dev/null +++ b/modules/nf-core/samtools/view/tests/bam_index.config @@ -0,0 +1,3 @@ +process { + ext.args = "--output-fmt bam --write-index" +} \ No newline at end of file diff --git a/modules/nf-core/samtools/view/tests/main.nf.test b/modules/nf-core/samtools/view/tests/main.nf.test new file mode 100644 index 00000000..89ed3555 --- /dev/null +++ b/modules/nf-core/samtools/view/tests/main.nf.test @@ -0,0 +1,231 @@ +nextflow_process { + + name "Test Process SAMTOOLS_VIEW" + script "../main.nf" + process "SAMTOOLS_VIEW" + + tag "modules" + tag "modules_nfcore" + tag "samtools" + tag "samtools/view" + + test("sarscov2 - [bam, []], [], []") { + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['illumina']['test_paired_end_bam'], checkIfExists: true), + [] + ] + input[1] = [[],[]] + input[2] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + file(process.out.bam[0][1]).name, + process.out.cram, + process.out.sam, + process.out.bai, + process.out.crai, + process.out.csi, + process.out.versions + ).match() } + ) + } + + } + + test("homo_sapiens - [cram, crai], fasta, []") { + + when { + process { + """ + input[0] = [ + [ id: 'test' ], // meta map + file(params.test_data['homo_sapiens']['illumina']['test_paired_end_sorted_cram'], checkIfExists: true), + file(params.test_data['homo_sapiens']['illumina']['test_paired_end_sorted_cram_crai'], checkIfExists: true) + ] + input[1] = [ + [ id:'genome' ], + file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true) + ] + input[2] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + file(process.out.cram[0][1]).name, + process.out.bam, + process.out.sam, + process.out.bai, + process.out.crai, + process.out.csi, + process.out.versions + ).match() } + ) + } + + } + + test("homo_sapiens - [cram, []], fasta, [] - bam output") { + + config "./bam.config" + + when { + process { + """ + input[0] = [ + [ id: 'test' ], // meta map + file(params.test_data['homo_sapiens']['illumina']['test_paired_end_sorted_cram'], checkIfExists: true), + [] + ] + input[1] = [ + [ id:'genome' ], + file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true) + ] + input[2] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + file(process.out.bam[0][1]).name, + process.out.cram, + process.out.sam, + process.out.bai, + process.out.crai, + process.out.csi, + process.out.versions + ).match() } + ) + } + + } + + test("homo_sapiens - [cram, []], fasta, [] - bam & index output") { + + config "./bam_index.config" + + when { + process { + """ + input[0] = [ + [ id: 'test' ], // meta map + file(params.test_data['homo_sapiens']['illumina']['test_paired_end_sorted_cram'], checkIfExists: true), + [] + ] + input[1] = [ + [ id:'genome' ], + file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true) + ] + input[2] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + file(process.out.bam[0][1]).name, + process.out.cram, + process.out.sam, + file(process.out.csi[0][1]).name, + process.out.crai, + process.out.bai, + process.out.versions + ).match() } + ) + } + + } + + test("homo_sapiens - [cram, []], fasta, qname - bam & index output") { + + config "./bam_index.config" + + when { + process { + """ + input[0] = [ + [ id: 'test' ], // meta map + file(params.test_data['homo_sapiens']['illumina']['test_paired_end_sorted_cram'], checkIfExists: true), + [] + ] + input[1] = [ + [ id:'genome' ], + file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true) + ] + input[2] = Channel.of("testN:2817", "testN:2814").collectFile(name: "readnames.list", newLine: true) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + file(process.out.bam[0][1]).name, + process.out.cram, + process.out.sam, + file(process.out.csi[0][1]).name, + process.out.crai, + process.out.bai, + process.out.versions + ).match() } + ) + } + + } + + test("sarscov2 - [bam, []], [], [] - stub") { + + options "-stub" + config "./bam_index.config" + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['illumina']['test_paired_end_bam'], checkIfExists: true), + [] + ] + input[1] = [[],[]] + input[2] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + file(process.out.bam[0][1]).name, + process.out.cram, + process.out.sam, + file(process.out.csi[0][1]).name, + process.out.crai, + process.out.bai, + process.out.versions + ).match() } + ) + } + + } + +} diff --git a/modules/nf-core/samtools/view/tests/main.nf.test.snap b/modules/nf-core/samtools/view/tests/main.nf.test.snap new file mode 100644 index 00000000..83427491 --- /dev/null +++ b/modules/nf-core/samtools/view/tests/main.nf.test.snap @@ -0,0 +1,140 @@ +{ + "homo_sapiens - [cram, []], fasta, [] - bam output": { + "content": [ + "test.bam", + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + "versions.yml:md5,06b9049228b111e7bed5c52fe8a98d9b" + ] + ], + "timestamp": "2023-12-04T17:41:17.563069206" + }, + "sarscov2 - [bam, []], [], []": { + "content": [ + "test.bam", + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + "versions.yml:md5,06b9049228b111e7bed5c52fe8a98d9b" + ] + ], + "timestamp": "2023-12-04T17:41:03.206994564" + }, + "homo_sapiens - [cram, []], fasta, qname - bam & index output": { + "content": [ + "test.bam", + [ + + ], + [ + + ], + "test.bam.csi", + [ + + ], + [ + + ], + [ + "versions.yml:md5,06b9049228b111e7bed5c52fe8a98d9b" + ] + ], + "timestamp": "2023-12-04T17:44:39.165289759" + }, + "homo_sapiens - [cram, []], fasta, [] - bam & index output": { + "content": [ + "test.bam", + [ + + ], + [ + + ], + "test.bam.csi", + [ + + ], + [ + + ], + [ + "versions.yml:md5,06b9049228b111e7bed5c52fe8a98d9b" + ] + ], + "timestamp": "2023-12-04T17:44:32.25731224" + }, + "sarscov2 - [bam, []], [], [] - stub": { + "content": [ + "test.bam", + [ + + ], + [ + + ], + "test.csi", + [ + + ], + [ + + ], + [ + "versions.yml:md5,06b9049228b111e7bed5c52fe8a98d9b" + ] + ], + "timestamp": "2023-12-04T17:44:45.81037195" + }, + "homo_sapiens - [cram, crai], fasta, []": { + "content": [ + "test.cram", + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + "versions.yml:md5,06b9049228b111e7bed5c52fe8a98d9b" + ] + ], + "timestamp": "2023-12-04T17:41:10.730011823" + } +} \ No newline at end of file diff --git a/modules/nf-core/samtools/view/tests/tags.yml b/modules/nf-core/samtools/view/tests/tags.yml new file mode 100644 index 00000000..4fdf1dd1 --- /dev/null +++ b/modules/nf-core/samtools/view/tests/tags.yml @@ -0,0 +1,2 @@ +samtools/view: + - "modules/nf-core/samtools/view/**" diff --git a/modules/nf-core/segemehl/align/environment.yml b/modules/nf-core/segemehl/align/environment.yml new file mode 100644 index 00000000..e7dbc662 --- /dev/null +++ b/modules/nf-core/segemehl/align/environment.yml @@ -0,0 +1,7 @@ +name: segemehl_align +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::segemehl=0.3.4 diff --git a/modules/nf-core/segemehl/align/main.nf b/modules/nf-core/segemehl/align/main.nf index 768cd384..77f88820 100644 --- a/modules/nf-core/segemehl/align/main.nf +++ b/modules/nf-core/segemehl/align/main.nf @@ -2,7 +2,7 @@ process SEGEMEHL_ALIGN { tag "$meta.id" label 'process_high' - conda "bioconda::segemehl=0.3.4" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/segemehl:0.3.4--hc2ea5fd_5': 'biocontainers/segemehl:0.3.4--hc2ea5fd_5' }" diff --git a/modules/nf-core/segemehl/index/environment.yml b/modules/nf-core/segemehl/index/environment.yml new file mode 100644 index 00000000..c0641330 --- /dev/null +++ b/modules/nf-core/segemehl/index/environment.yml @@ -0,0 +1,7 @@ +name: segemehl_index +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::segemehl=0.3.4 diff --git a/modules/nf-core/segemehl/index/main.nf b/modules/nf-core/segemehl/index/main.nf index 4a9146fe..ea912c6e 100644 --- a/modules/nf-core/segemehl/index/main.nf +++ b/modules/nf-core/segemehl/index/main.nf @@ -2,7 +2,7 @@ process SEGEMEHL_INDEX { tag "$fasta" label 'process_high' - conda "bioconda::segemehl=0.3.4" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/segemehl:0.3.4--hc2ea5fd_5': 'biocontainers/segemehl:0.3.4--hc2ea5fd_5' }" diff --git a/modules/nf-core/star/align/environment.yml b/modules/nf-core/star/align/environment.yml new file mode 100644 index 00000000..36fcd022 --- /dev/null +++ b/modules/nf-core/star/align/environment.yml @@ -0,0 +1,9 @@ +name: star_align +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::star=2.7.10a + - bioconda::samtools=1.18 + - conda-forge::gawk=5.1.0 diff --git a/modules/nf-core/star/align/main.nf b/modules/nf-core/star/align/main.nf index d0e20384..8e9c48b1 100644 --- a/modules/nf-core/star/align/main.nf +++ b/modules/nf-core/star/align/main.nf @@ -2,10 +2,10 @@ process STAR_ALIGN { tag "$meta.id" label 'process_high' - conda "bioconda::star=2.7.10a bioconda::samtools=1.16.1 conda-forge::gawk=5.1.0" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-1fa26d1ce03c295fe2fdcf85831a92fbcbd7e8c2:1df389393721fc66f3fd8778ad938ac711951107-0' : - 'biocontainers/mulled-v2-1fa26d1ce03c295fe2fdcf85831a92fbcbd7e8c2:1df389393721fc66f3fd8778ad938ac711951107-0' }" + 'https://depot.galaxyproject.org/singularity/mulled-v2-1fa26d1ce03c295fe2fdcf85831a92fbcbd7e8c2:ded3841da0194af2701c780e9b3d653a85d27489-0' : + 'biocontainers/mulled-v2-1fa26d1ce03c295fe2fdcf85831a92fbcbd7e8c2:ded3841da0194af2701c780e9b3d653a85d27489-0' }" input: tuple val(meta), path(reads, stageAs: "input*/*") diff --git a/modules/nf-core/star/align/tests/main.nf.test b/modules/nf-core/star/align/tests/main.nf.test new file mode 100644 index 00000000..4c878474 --- /dev/null +++ b/modules/nf-core/star/align/tests/main.nf.test @@ -0,0 +1,339 @@ +nextflow_process { + + name "Test Process STAR_ALIGN" + script "../main.nf" + process "STAR_ALIGN" + tag "modules" + tag "modules_nfcore" + tag "star" + tag "star/align" + + test("homo_sapiens - single_end") { + config "./nextflow.config" + + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + ]) + """ + } + } + } + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_1_fastq_gz'], checkIfExists: true) ] + ]) + input[1] = STAR_GENOMEGENERATE.out.index + input[2] = Channel.of([ + [ id:'test_gtf' ], + [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + ]) + input[3] = false + input[4] = 'illumina' + input[5] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - single_end - log_final") }, + { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - single_end - log_out") }, + { assert snapshot(process.out.bam).match("homo_sapiens - single_end - bam") }, + { assert snapshot(process.out.bam_sorted).match("homo_sapiens - single_end - bam_sorted") }, + { assert snapshot(process.out.bam_transcript).match("homo_sapiens - single_end - bam_transcript") }, + { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - single_end - bam_unsorted") }, + { assert snapshot(process.out.bedgraph).match("homo_sapiens - single_end - bedgraph") }, + { assert snapshot(process.out.fastq).match("homo_sapiens - single_end - fastq") }, + { assert snapshot(process.out.junction).match("homo_sapiens - single_end - junction") }, + { assert snapshot(process.out.log_progress).match("homo_sapiens - single_end - log_progress") }, + { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - single_end - read_per_gene_tab") }, + { assert snapshot(process.out.sam).match("homo_sapiens - single_end - sam") }, + { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - single_end - spl_junc_tab") }, + { assert snapshot(process.out.tab).match("homo_sapiens - single_end - tab") }, + { assert snapshot(process.out.wig).match("homo_sapiens - single_end - wig") }, + { assert snapshot(process.out.versions).match("homo_sapiens - single_end - versions") } + ) + } + } + + test("homo_sapiens - paired_end") { + config "./nextflow.config" + + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + ]) + """ + } + } + } + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ + file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_1_fastq_gz'], checkIfExists: true), + file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_2_fastq_gz'], checkIfExists: true) + ] + ]) + input[1] = STAR_GENOMEGENERATE.out.index + input[2] = Channel.of([ + [ id:'test_gtf' ], + [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + ]) + input[3] = false + input[4] = 'illumina' + input[5] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - paired_end - log_final") }, + { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - paired_end - log_out") }, + { assert snapshot(process.out.bam).match("homo_sapiens - paired_end - bam") }, + { assert snapshot(process.out.bam_sorted).match("homo_sapiens - paired_end - bam_sorted") }, + { assert snapshot(process.out.bam_transcript).match("homo_sapiens - paired_end - bam_transcript") }, + { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - paired_end - bam_unsorted") }, + { assert snapshot(process.out.bedgraph).match("homo_sapiens - paired_end - bedgraph") }, + { assert snapshot(process.out.fastq).match("homo_sapiens - paired_end - fastq") }, + { assert snapshot(process.out.junction).match("homo_sapiens - paired_end - junction") }, + { assert snapshot(process.out.log_progress).match("homo_sapiens - paired_end - log_progress") }, + { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - paired_end - read_per_gene_tab") }, + { assert snapshot(process.out.sam).match("homo_sapiens - paired_end - sam") }, + { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - paired_end - spl_junc_tab") }, + { assert snapshot(process.out.tab).match("homo_sapiens - paired_end - tab") }, + { assert snapshot(process.out.wig).match("homo_sapiens - paired_end - wig") }, + { assert snapshot(process.out.versions).match("homo_sapiens - paired_end - versions") } + ) + } + } + + test("homo_sapiens - paired_end - arriba") { + config "./nextflow.arriba.config" + + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + ]) + """ + } + } + } + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ + file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_1_fastq_gz'], checkIfExists: true), + file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_2_fastq_gz'], checkIfExists: true) + ] + ]) + input[1] = STAR_GENOMEGENERATE.out.index + input[2] = Channel.of([ + [ id:'test_gtf' ], + [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + ]) + input[3] = false + input[4] = 'illumina' + input[5] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - paired_end - arriba - log_final") }, + { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - paired_end - arriba - log_out") }, + { assert snapshot(file(process.out.log_progress[0][1]).name).match("homo_sapiens - paired_end - arriba - log_progress") }, + { assert snapshot(process.out.bam).match("homo_sapiens - paired_end - arriba - bam") }, + { assert snapshot(process.out.bam_sorted).match("homo_sapiens - paired_end - arriba - bam_sorted") }, + { assert snapshot(process.out.bam_transcript).match("homo_sapiens - paired_end - arriba - bam_transcript") }, + { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - paired_end - arriba - bam_unsorted") }, + { assert snapshot(process.out.bedgraph).match("homo_sapiens - paired_end - arriba - bedgraph") }, + { assert snapshot(process.out.fastq).match("homo_sapiens - paired_end - arriba - fastq") }, + { assert snapshot(process.out.junction).match("homo_sapiens - paired_end - arriba - junction") }, + { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - paired_end - arriba - read_per_gene_tab") }, + { assert snapshot(process.out.sam).match("homo_sapiens - paired_end - arriba - sam") }, + { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - paired_end - arriba - spl_junc_tab") }, + { assert snapshot(process.out.tab).match("homo_sapiens - paired_end - arriba - tab") }, + { assert snapshot(process.out.wig).match("homo_sapiens - paired_end - arriba - wig") }, + { assert snapshot(process.out.versions).match("homo_sapiens - paired_end - arriba - versions") } + ) + } + } + + test("homo_sapiens - paired_end - starfusion") { + config "./nextflow.starfusion.config" + + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + ]) + """ + } + } + } + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ + file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_1_fastq_gz'], checkIfExists: true), + file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_2_fastq_gz'], checkIfExists: true) + ] + ]) + input[1] = STAR_GENOMEGENERATE.out.index + input[2] = Channel.of([ + [ id:'test_gtf' ], + [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + ]) + input[3] = false + input[4] = 'illumina' + input[5] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - paired_end - starfusion - log_final") }, + { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - paired_end - starfusion - log_out") }, + { assert snapshot(file(process.out.log_progress[0][1]).name).match("homo_sapiens - paired_end - starfusion - log_progress") }, + { assert snapshot(process.out.bam).match("homo_sapiens - paired_end - starfusion - bam") }, + { assert snapshot(process.out.bam_sorted).match("homo_sapiens - paired_end - starfusion - bam_sorted") }, + { assert snapshot(process.out.bam_transcript).match("homo_sapiens - paired_end - starfusion - bam_transcript") }, + { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - paired_end - starfusion - bam_unsorted") }, + { assert snapshot(process.out.bedgraph).match("homo_sapiens - paired_end - starfusion - bedgraph") }, + { assert snapshot(process.out.fastq).match("homo_sapiens - paired_end - starfusion - fastq") }, + { assert snapshot(process.out.junction).match("homo_sapiens - paired_end - starfusion - junction") }, + { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - paired_end - starfusion - read_per_gene_tab") }, + { assert snapshot(process.out.sam).match("homo_sapiens - paired_end - starfusion - sam") }, + { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - paired_end - starfusion - spl_junc_tab") }, + { assert snapshot(process.out.tab).match("homo_sapiens - paired_end - starfusion - tab") }, + { assert snapshot(process.out.wig).match("homo_sapiens - paired_end - starfusion - wig") }, + { assert snapshot(process.out.versions).match("homo_sapiens - paired_end - starfusion - versions") } + ) + } + } + + test("homo_sapiens - paired_end - multiple") { + config "./nextflow.config" + + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + ]) + """ + } + } + } + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ + file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_1_fastq_gz'], checkIfExists: true), + file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_2_fastq_gz'], checkIfExists: true), + file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_1_fastq_gz'], checkIfExists: true), + file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_2_fastq_gz'], checkIfExists: true) + ] + ]) + input[1] = STAR_GENOMEGENERATE.out.index + input[2] = Channel.of([ + [ id:'test_gtf' ], + [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + ]) + input[3] = false + input[4] = 'illumina' + input[5] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - paired_end - multiple - log_final") }, + { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - paired_end - multiple - log_out") }, + { assert snapshot(file(process.out.log_progress[0][1]).name).match("homo_sapiens - paired_end - multiple - log_progress") }, + { assert snapshot(process.out.bam).match("homo_sapiens - paired_end - multiple - bam") }, + { assert snapshot(process.out.bam_sorted).match("homo_sapiens - paired_end - multiple - bam_sorted") }, + { assert snapshot(process.out.bam_transcript).match("homo_sapiens - paired_end - multiple - bam_transcript") }, + { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - paired_end - multiple - bam_unsorted") }, + { assert snapshot(process.out.bedgraph).match("homo_sapiens - paired_end - multiple - bedgraph") }, + { assert snapshot(process.out.fastq).match("homo_sapiens - paired_end - multiple - fastq") }, + { assert snapshot(process.out.junction).match("homo_sapiens - paired_end - multiple - junction") }, + { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - paired_end - multiple - read_per_gene_tab") }, + { assert snapshot(process.out.sam).match("homo_sapiens - paired_end - multiple - sam") }, + { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - paired_end - multiple - spl_junc_tab") }, + { assert snapshot(process.out.tab).match("homo_sapiens - paired_end - multiple - tab") }, + { assert snapshot(process.out.wig).match("homo_sapiens - paired_end - multiple - wig") }, + { assert snapshot(process.out.versions).match("homo_sapiens - paired_end - multiple - versions") } + ) + } + } +} \ No newline at end of file diff --git a/modules/nf-core/star/align/tests/main.nf.test.snap b/modules/nf-core/star/align/tests/main.nf.test.snap new file mode 100644 index 00000000..08edb914 --- /dev/null +++ b/modules/nf-core/star/align/tests/main.nf.test.snap @@ -0,0 +1,769 @@ +{ + "homo_sapiens - paired_end - multiple - bam_sorted": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.sortedByCoord.out.bam:md5,ab07c21d63ab0a6c07d171d213c81d5a" + ] + ] + ], + "timestamp": "2023-12-04T18:01:19.968225733" + }, + "homo_sapiens - paired_end - multiple - wig": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:29:01.857804" + }, + "homo_sapiens - paired_end - arriba - tab": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,5155c9fd1f787ad6d7d80987fb06219c" + ] + ] + ], + "timestamp": "2023-12-04T17:56:12.347549723" + }, + "homo_sapiens - single_end - wig": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:22:55.24701" + }, + "homo_sapiens - paired_end - sam": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:23:33.383818" + }, + "homo_sapiens - paired_end - arriba - versions": { + "content": [ + [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ] + ], + "timestamp": "2023-12-04T17:56:12.431212643" + }, + "homo_sapiens - paired_end - multiple - bedgraph": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Signal.Unique.str1.out.bg:md5,d7bf8b70b436ca048a62513e1d0ece3a", + "test.Signal.UniqueMultiple.str1.out.bg:md5,686d58493b9eb445b56ace4d67f76ef6" + ] + ] + ] + ], + "timestamp": "2023-12-04T18:01:20.07119229" + }, + "homo_sapiens - paired_end - read_per_gene_tab": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:23:33.368841" + }, + "homo_sapiens - paired_end - arriba - bedgraph": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:25:07.102537" + }, + "homo_sapiens - single_end - junction": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:22:55.185369" + }, + "homo_sapiens - paired_end - arriba - spl_junc_tab": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,5155c9fd1f787ad6d7d80987fb06219c" + ] + ] + ], + "timestamp": "2023-12-04T17:56:12.268388251" + }, + "homo_sapiens - single_end - sam": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:22:55.216183" + }, + "homo_sapiens - paired_end - fastq": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:23:33.327236" + }, + "homo_sapiens - single_end - versions": { + "content": [ + [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ] + ], + "timestamp": "2023-12-04T17:53:26.664210196" + }, + "homo_sapiens - paired_end - multiple - log_out": { + "content": [ + "test.Log.out" + ], + "timestamp": "2023-11-23T13:29:01.022176" + }, + "homo_sapiens - paired_end - arriba - fastq": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:25:07.15277" + }, + "homo_sapiens - paired_end - multiple - junction": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:29:01.52923" + }, + "homo_sapiens - paired_end - multiple - spl_junc_tab": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,069877e053714e23010fe4e1c003b4a2" + ] + ] + ], + "timestamp": "2023-12-04T18:01:20.189486201" + }, + "homo_sapiens - paired_end - starfusion - log_final": { + "content": [ + "test.Log.final.out" + ], + "timestamp": "2023-11-23T13:27:55.905883" + }, + "homo_sapiens - paired_end - starfusion - fastq": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:27:56.192302" + }, + "homo_sapiens - paired_end - multiple - sam": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:29:01.661837" + }, + "homo_sapiens - paired_end - multiple - log_final": { + "content": [ + "test.Log.final.out" + ], + "timestamp": "2023-11-23T13:29:00.966417" + }, + "homo_sapiens - paired_end - starfusion - bam": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.out.bam:md5,bcad07b838f6762fc01eea52b5cd3f84" + ] + ] + ], + "timestamp": "2023-12-04T17:59:58.53235164" + }, + "homo_sapiens - paired_end - arriba - junction": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:25:07.202776" + }, + "homo_sapiens - single_end - bedgraph": { + "content": [ + [ + [ + { + "id": "test", + "single_end": true + }, + [ + "test.Signal.Unique.str1.out.bg:md5,c56fc1472776fb927eaf62d973da5f9a", + "test.Signal.UniqueMultiple.str1.out.bg:md5,e93373cf6f2a2a9506e2efdb260cdd4f" + ] + ] + ] + ], + "timestamp": "2023-12-04T17:53:26.394863748" + }, + "homo_sapiens - paired_end - arriba - read_per_gene_tab": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:25:07.251962" + }, + "homo_sapiens - paired_end - starfusion - bam_sorted": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:27:56.040843" + }, + "homo_sapiens - single_end - bam_unsorted": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:22:55.154172" + }, + "homo_sapiens - paired_end - bam": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.sortedByCoord.out.bam:md5,b9ee1c607e07323bc1652ef3babb543f" + ] + ] + ], + "timestamp": "2023-12-04T17:54:11.934832258" + }, + "homo_sapiens - paired_end - arriba - bam_transcript": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:25:06.998817" + }, + "homo_sapiens - paired_end - log_out": { + "content": [ + "test.Log.out" + ], + "timestamp": "2023-11-23T13:23:33.259699" + }, + "homo_sapiens - paired_end - arriba - log_out": { + "content": [ + "test.Log.out" + ], + "timestamp": "2023-11-23T13:25:06.849451" + }, + "homo_sapiens - paired_end - multiple - versions": { + "content": [ + [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ] + ], + "timestamp": "2023-12-04T18:01:20.393705142" + }, + "homo_sapiens - paired_end - starfusion - bam_transcript": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:27:56.082408" + }, + "homo_sapiens - paired_end - starfusion - tab": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,19c3faa1bfa9a0cc5e4c45f17065b53a" + ] + ] + ], + "timestamp": "2023-12-04T17:59:58.818041322" + }, + "homo_sapiens - single_end - fastq": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:22:55.175307" + }, + "homo_sapiens - paired_end - tab": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,844af19ab0fc8cd9a3f75228445aca0d" + ] + ] + ], + "timestamp": "2023-12-04T17:54:12.255481058" + }, + "homo_sapiens - paired_end - starfusion - bedgraph": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:27:56.155413" + }, + "homo_sapiens - single_end - bam_transcript": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:22:55.144852" + }, + "homo_sapiens - paired_end - versions": { + "content": [ + [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ] + ], + "timestamp": "2023-12-04T17:54:12.343840482" + }, + "homo_sapiens - paired_end - multiple - tab": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,069877e053714e23010fe4e1c003b4a2" + ] + ] + ], + "timestamp": "2023-12-04T18:01:20.291692062" + }, + "homo_sapiens - single_end - bam": { + "content": [ + [ + [ + { + "id": "test", + "single_end": true + }, + "test.Aligned.sortedByCoord.out.bam:md5,c6cfaccaf91bc7fdabed3cfe236d4535" + ] + ] + ], + "timestamp": "2023-12-04T17:53:26.265642675" + }, + "homo_sapiens - paired_end - arriba - wig": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:25:07.444214" + }, + "homo_sapiens - paired_end - log_progress": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.progress.out:md5,b2bd061d6cbaaf3d6d3b1fed547f69b8" + ] + ] + ], + "timestamp": "2023-12-04T17:54:12.126063825" + }, + "homo_sapiens - paired_end - arriba - log_final": { + "content": [ + "test.Log.final.out" + ], + "timestamp": "2023-11-23T13:25:06.829799" + }, + "homo_sapiens - paired_end - bam_unsorted": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:23:33.300509" + }, + "homo_sapiens - paired_end - arriba - sam": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:25:07.300383" + }, + "homo_sapiens - paired_end - multiple - bam": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.sortedByCoord.out.bam:md5,ab07c21d63ab0a6c07d171d213c81d5a" + ] + ] + ], + "timestamp": "2023-12-04T18:01:19.851247126" + }, + "homo_sapiens - paired_end - multiple - fastq": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:29:01.462257" + }, + "homo_sapiens - single_end - bam_sorted": { + "content": [ + [ + [ + { + "id": "test", + "single_end": true + }, + "test.Aligned.sortedByCoord.out.bam:md5,c6cfaccaf91bc7fdabed3cfe236d4535" + ] + ] + ], + "timestamp": "2023-12-04T17:53:26.335457371" + }, + "homo_sapiens - paired_end - arriba - bam_sorted": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:25:06.94699" + }, + "homo_sapiens - paired_end - starfusion - junction": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.Chimeric.out.junction:md5,c10ef219f4a30e83711b995bc5e40dba" + ] + ] + ], + "timestamp": "2023-12-04T17:59:58.641115828" + }, + "homo_sapiens - single_end - tab": { + "content": [ + [ + [ + { + "id": "test", + "single_end": true + }, + "test.SJ.out.tab:md5,75a516ab950fb958f40b29996474949c" + ] + ] + ], + "timestamp": "2023-12-04T17:53:26.580593434" + }, + "homo_sapiens - paired_end - starfusion - versions": { + "content": [ + [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ] + ], + "timestamp": "2023-12-04T17:59:58.907317103" + }, + "homo_sapiens - paired_end - multiple - bam_unsorted": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:29:01.330463" + }, + "homo_sapiens - paired_end - arriba - log_progress": { + "content": [ + "test.Log.progress.out" + ], + "timestamp": "2023-11-23T13:25:06.86866" + }, + "homo_sapiens - paired_end - bedgraph": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Signal.Unique.str1.out.bg:md5,d7bf8b70b436ca048a62513e1d0ece3a", + "test.Signal.UniqueMultiple.str1.out.bg:md5,686d58493b9eb445b56ace4d67f76ef6" + ] + ] + ] + ], + "timestamp": "2023-12-04T17:54:12.064121304" + }, + "homo_sapiens - paired_end - starfusion - bam_unsorted": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:27:56.118974" + }, + "homo_sapiens - paired_end - starfusion - read_per_gene_tab": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:27:56.264699" + }, + "homo_sapiens - paired_end - multiple - log_progress": { + "content": [ + "test.Log.progress.out" + ], + "timestamp": "2023-11-23T13:29:01.076947" + }, + "homo_sapiens - paired_end - arriba - bam_unsorted": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:25:07.050409" + }, + "homo_sapiens - paired_end - bam_sorted": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.sortedByCoord.out.bam:md5,b9ee1c607e07323bc1652ef3babb543f" + ] + ] + ], + "timestamp": "2023-12-04T17:54:12.002180537" + }, + "homo_sapiens - single_end - spl_junc_tab": { + "content": [ + [ + [ + { + "id": "test", + "single_end": true + }, + "test.SJ.out.tab:md5,75a516ab950fb958f40b29996474949c" + ] + ] + ], + "timestamp": "2023-12-04T17:53:26.50932751" + }, + "homo_sapiens - paired_end - starfusion - spl_junc_tab": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,19c3faa1bfa9a0cc5e4c45f17065b53a" + ] + ] + ], + "timestamp": "2023-12-04T17:59:58.731699486" + }, + "homo_sapiens - single_end - log_out": { + "content": [ + "test.Log.out" + ], + "timestamp": "2023-11-23T13:22:55.126286" + }, + "homo_sapiens - paired_end - log_final": { + "content": [ + "test.Log.final.out" + ], + "timestamp": "2023-11-23T13:23:33.253884" + }, + "homo_sapiens - single_end - log_final": { + "content": [ + "test.Log.final.out" + ], + "timestamp": "2023-11-23T13:22:55.11799" + }, + "homo_sapiens - paired_end - bam_transcript": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:23:33.287684" + }, + "homo_sapiens - paired_end - starfusion - log_progress": { + "content": [ + "test.Log.progress.out" + ], + "timestamp": "2023-11-23T13:27:55.971484" + }, + "homo_sapiens - paired_end - multiple - bam_transcript": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:29:01.264176" + }, + "homo_sapiens - paired_end - multiple - read_per_gene_tab": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:29:01.596406" + }, + "homo_sapiens - single_end - read_per_gene_tab": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:22:55.205936" + }, + "homo_sapiens - paired_end - junction": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:23:33.340653" + }, + "homo_sapiens - paired_end - spl_junc_tab": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,844af19ab0fc8cd9a3f75228445aca0d" + ] + ] + ], + "timestamp": "2023-12-04T17:54:12.185730856" + }, + "homo_sapiens - paired_end - starfusion - sam": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:27:56.300637" + }, + "homo_sapiens - paired_end - arriba - bam": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.out.bam:md5,c1b1747f5873f2d17762725636e891d5" + ] + ] + ], + "timestamp": "2023-12-04T17:56:12.190560178" + }, + "homo_sapiens - single_end - log_progress": { + "content": [ + [ + [ + { + "id": "test", + "single_end": true + }, + "test.Log.progress.out:md5,b2bd061d6cbaaf3d6d3b1fed547f69b8" + ] + ] + ], + "timestamp": "2023-12-04T17:53:26.450352138" + }, + "homo_sapiens - paired_end - starfusion - wig": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:27:56.422018" + }, + "homo_sapiens - paired_end - wig": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:23:33.429457" + }, + "homo_sapiens - paired_end - starfusion - log_out": { + "content": [ + "test.Log.out" + ], + "timestamp": "2023-11-23T13:27:55.93945" + } +} \ No newline at end of file diff --git a/modules/nf-core/star/align/tests/nextflow.arriba.config b/modules/nf-core/star/align/tests/nextflow.arriba.config new file mode 100644 index 00000000..2324b9e5 --- /dev/null +++ b/modules/nf-core/star/align/tests/nextflow.arriba.config @@ -0,0 +1,14 @@ +process { + + withName: STAR_GENOMEGENERATE { + ext.args = '--genomeSAindexNbases 9' + } + + withName: STAR_ALIGN { + ext.args = '--readFilesCommand zcat --outSAMtype BAM Unsorted --outSAMunmapped Within --outBAMcompression 0 --outFilterMultimapNmax 50 --peOverlapNbasesMin 10 --alignSplicedMateMapLminOverLmate 0.5 --alignSJstitchMismatchNmax 5 -1 5 5 --chimSegmentMin 10 --chimOutType WithinBAM HardClip --chimJunctionOverhangMin 10 --chimScoreDropMax 30 --chimScoreJunctionNonGTAG 0 --chimScoreSeparation 1 --chimSegmentReadGapMax 3 --chimMultimapNmax 50' + } + +} + +// Fix chown issue for the output star folder +docker.runOptions = '--platform=linux/amd64 -u $(id -u):$(id -g)' diff --git a/modules/nf-core/star/align/tests/nextflow.config b/modules/nf-core/star/align/tests/nextflow.config new file mode 100644 index 00000000..c4ac5808 --- /dev/null +++ b/modules/nf-core/star/align/tests/nextflow.config @@ -0,0 +1,14 @@ +process { + + withName: STAR_GENOMEGENERATE { + ext.args = '--genomeSAindexNbases 9' + } + + withName: STAR_ALIGN { + ext.args = '--readFilesCommand zcat --outSAMtype BAM SortedByCoordinate --outWigType bedGraph --outWigStrand Unstranded' + } + +} + +// Fix chown issue for the output star folder +docker.runOptions = '--platform=linux/amd64 -u $(id -u):$(id -g)' diff --git a/modules/nf-core/star/align/tests/nextflow.starfusion.config b/modules/nf-core/star/align/tests/nextflow.starfusion.config new file mode 100644 index 00000000..467b6497 --- /dev/null +++ b/modules/nf-core/star/align/tests/nextflow.starfusion.config @@ -0,0 +1,14 @@ +process { + + withName: STAR_GENOMEGENERATE { + ext.args = '--genomeSAindexNbases 9' + } + + withName: STAR_ALIGN { + ext.args = '--readFilesCommand zcat --outSAMtype BAM Unsorted --outReadsUnmapped None --twopassMode Basic --outSAMstrandField intronMotif --outSAMunmapped Within --chimSegmentMin 12 --chimJunctionOverhangMin 8 --chimOutJunctionFormat 1 --alignSJDBoverhangMin 10 --alignMatesGapMax 100000 --alignIntronMax 100000 --alignSJstitchMismatchNmax 5 -1 5 5 --chimMultimapScoreRange 3 --chimScoreJunctionNonGTAG -4 --chimMultimapNmax 20 --chimNonchimScoreDropMin 10 --peOverlapNbasesMin 12 --peOverlapMMp 0.1 --alignInsertionFlush Right --alignSplicedMateMapLminOverLmate 0 --alignSplicedMateMapLmin 30' + } + +} + +// Fix chown issue for the output star folder +docker.runOptions = '--platform=linux/amd64 -u $(id -u):$(id -g)' diff --git a/modules/nf-core/star/align/tests/tags.yml b/modules/nf-core/star/align/tests/tags.yml new file mode 100644 index 00000000..8beace16 --- /dev/null +++ b/modules/nf-core/star/align/tests/tags.yml @@ -0,0 +1,2 @@ +star/align: + - modules/nf-core/star/align/** diff --git a/modules/nf-core/star/genomegenerate/environment.yml b/modules/nf-core/star/genomegenerate/environment.yml new file mode 100644 index 00000000..93e4476a --- /dev/null +++ b/modules/nf-core/star/genomegenerate/environment.yml @@ -0,0 +1,11 @@ +name: star_genomegenerate + +channels: + - conda-forge + - bioconda + - defaults + +dependencies: + - bioconda::samtools=1.18 + - bioconda::star=2.7.10a + - conda-forge::gawk=5.1.0 diff --git a/modules/nf-core/star/genomegenerate/main.nf b/modules/nf-core/star/genomegenerate/main.nf index 43424042..b8855715 100644 --- a/modules/nf-core/star/genomegenerate/main.nf +++ b/modules/nf-core/star/genomegenerate/main.nf @@ -2,10 +2,10 @@ process STAR_GENOMEGENERATE { tag "$fasta" label 'process_high' - conda "bioconda::star=2.7.10a bioconda::samtools=1.16.1 conda-forge::gawk=5.1.0" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-1fa26d1ce03c295fe2fdcf85831a92fbcbd7e8c2:1df389393721fc66f3fd8778ad938ac711951107-0' : - 'biocontainers/mulled-v2-1fa26d1ce03c295fe2fdcf85831a92fbcbd7e8c2:1df389393721fc66f3fd8778ad938ac711951107-0' }" + 'https://depot.galaxyproject.org/singularity/mulled-v2-1fa26d1ce03c295fe2fdcf85831a92fbcbd7e8c2:ded3841da0194af2701c780e9b3d653a85d27489-0' : + 'biocontainers/mulled-v2-1fa26d1ce03c295fe2fdcf85831a92fbcbd7e8c2:ded3841da0194af2701c780e9b3d653a85d27489-0' }" input: tuple val(meta), path(fasta) @@ -19,9 +19,10 @@ process STAR_GENOMEGENERATE { task.ext.when == null || task.ext.when script: - def args = task.ext.args ?: '' - def args_list = args.tokenize() - def memory = task.memory ? "--limitGenomeGenerateRAM ${task.memory.toBytes() - 100000000}" : '' + def args = task.ext.args ?: '' + def args_list = args.tokenize() + def memory = task.memory ? "--limitGenomeGenerateRAM ${task.memory.toBytes() - 100000000}" : '' + def include_gtf = gtf ? "--sjdbGTFfile $gtf" : '' if (args_list.contains('--genomeSAindexNbases')) { """ mkdir star @@ -29,7 +30,7 @@ process STAR_GENOMEGENERATE { --runMode genomeGenerate \\ --genomeDir star/ \\ --genomeFastaFiles $fasta \\ - --sjdbGTFfile $gtf \\ + $include_gtf \\ --runThreadN $task.cpus \\ $memory \\ $args @@ -51,7 +52,7 @@ process STAR_GENOMEGENERATE { --runMode genomeGenerate \\ --genomeDir star/ \\ --genomeFastaFiles $fasta \\ - --sjdbGTFfile $gtf \\ + $include_gtf \\ --runThreadN $task.cpus \\ --genomeSAindexNbases \$NUM_BASES \\ $memory \\ @@ -67,30 +68,52 @@ process STAR_GENOMEGENERATE { } stub: - """ - mkdir star - touch star/Genome - touch star/Log.out - touch star/SA - touch star/SAindex - touch star/chrLength.txt - touch star/chrName.txt - touch star/chrNameLength.txt - touch star/chrStart.txt - touch star/exonGeTrInfo.tab - touch star/exonInfo.tab - touch star/geneInfo.tab - touch star/genomeParameters.txt - touch star/sjdbInfo.txt - touch star/sjdbList.fromGTF.out.tab - touch star/sjdbList.out.tab - touch star/transcriptInfo.tab + if (gtf) { + """ + mkdir star + touch star/Genome + touch star/Log.out + touch star/SA + touch star/SAindex + touch star/chrLength.txt + touch star/chrName.txt + touch star/chrNameLength.txt + touch star/chrStart.txt + touch star/exonGeTrInfo.tab + touch star/exonInfo.tab + touch star/geneInfo.tab + touch star/genomeParameters.txt + touch star/sjdbInfo.txt + touch star/sjdbList.fromGTF.out.tab + touch star/sjdbList.out.tab + touch star/transcriptInfo.tab - cat <<-END_VERSIONS > versions.yml - "${task.process}": - star: \$(STAR --version | sed -e "s/STAR_//g") - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - gawk: \$(echo \$(gawk --version 2>&1) | sed 's/^.*GNU Awk //; s/, .*\$//') - END_VERSIONS - """ + cat <<-END_VERSIONS > versions.yml + "${task.process}": + star: \$(STAR --version | sed -e "s/STAR_//g") + samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') + gawk: \$(echo \$(gawk --version 2>&1) | sed 's/^.*GNU Awk //; s/, .*\$//') + END_VERSIONS + """ + } else { + """ + mkdir star + touch star/Genome + touch star/Log.out + touch star/SA + touch star/SAindex + touch star/chrLength.txt + touch star/chrName.txt + touch star/chrNameLength.txt + touch star/chrStart.txt + touch star/genomeParameters.txt + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + star: \$(STAR --version | sed -e "s/STAR_//g") + samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') + gawk: \$(echo \$(gawk --version 2>&1) | sed 's/^.*GNU Awk //; s/, .*\$//') + END_VERSIONS + """ + } } diff --git a/modules/nf-core/star/genomegenerate/tests/main.nf.test b/modules/nf-core/star/genomegenerate/tests/main.nf.test new file mode 100644 index 00000000..af0c9421 --- /dev/null +++ b/modules/nf-core/star/genomegenerate/tests/main.nf.test @@ -0,0 +1,117 @@ +nextflow_process { + + name "Test Process STAR_GENOMEGENERATE" + script "../main.nf" + process "STAR_GENOMEGENERATE" + tag "modules" + tag "modules_nfcore" + tag "star" + tag "star/genomegenerate" + + test("homo_sapiens") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("index_with_gtf") }, + { assert snapshot(process.out.versions).match("versions") } + ) + } + + } + + test("homo_sapiens-stub") { + + options '-stub' + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("index_with_gtf") }, + { assert snapshot(process.out.versions).match("versions") } + ) + } + + } + + test("homo_sapiens-without_gtf") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] + ]) + input[1] = Channel.of([ [], [] ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("index_without_gtf") }, + { assert snapshot(process.out.versions).match("versions") } + ) + } + + } + + test("homo_sapiens-without_gtf-stub") { + + options '-stub' + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] + ]) + input[1] = Channel.of([ [], [] ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("index_without_gtf") }, + { assert snapshot(process.out.versions).match("versions") } + ) + } + + } + +} \ No newline at end of file diff --git a/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap b/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap new file mode 100644 index 00000000..9de08c74 --- /dev/null +++ b/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap @@ -0,0 +1,22 @@ +{ + "versions": { + "content": [ + [ + "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" + ] + ], + "timestamp": "2023-12-19T11:05:51.741109" + }, + "index_with_gtf": { + "content": [ + "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, exonGeTrInfo.tab, exonInfo.tab, geneInfo.tab, genomeParameters.txt, sjdbInfo.txt, sjdbList.fromGTF.out.tab, sjdbList.out.tab, transcriptInfo.tab]" + ], + "timestamp": "2023-12-19T11:38:14.551548" + }, + "index_without_gtf": { + "content": [ + "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, genomeParameters.txt]" + ], + "timestamp": "2023-12-19T11:38:22.382905" + } +} \ No newline at end of file diff --git a/modules/nf-core/star/genomegenerate/tests/tags.yml b/modules/nf-core/star/genomegenerate/tests/tags.yml new file mode 100644 index 00000000..79f619bf --- /dev/null +++ b/modules/nf-core/star/genomegenerate/tests/tags.yml @@ -0,0 +1,2 @@ +star/genomegenerate: + - modules/nf-core/star/genomegenerate/** diff --git a/modules/nf-core/stringtie/stringtie/environment.yml b/modules/nf-core/stringtie/stringtie/environment.yml new file mode 100644 index 00000000..7a0eccdb --- /dev/null +++ b/modules/nf-core/stringtie/stringtie/environment.yml @@ -0,0 +1,7 @@ +name: stringtie_stringtie +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::stringtie=2.2.1 diff --git a/modules/nf-core/stringtie/stringtie/main.nf b/modules/nf-core/stringtie/stringtie/main.nf index d0f8b563..6e25ba27 100644 --- a/modules/nf-core/stringtie/stringtie/main.nf +++ b/modules/nf-core/stringtie/stringtie/main.nf @@ -2,7 +2,7 @@ process STRINGTIE_STRINGTIE { tag "$meta.id" label 'process_medium' - conda "bioconda::stringtie=2.2.1" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/stringtie:2.2.1--hecb563c_2' : 'biocontainers/stringtie:2.2.1--hecb563c_2' }" diff --git a/modules/nf-core/stringtie/stringtie/tests/main.nf.test b/modules/nf-core/stringtie/stringtie/tests/main.nf.test new file mode 100644 index 00000000..68786b74 --- /dev/null +++ b/modules/nf-core/stringtie/stringtie/tests/main.nf.test @@ -0,0 +1,108 @@ +nextflow_process { + + name "Test Process STRINGTIE_STRINGTIE" + script "../main.nf" + process "STRINGTIE_STRINGTIE" + tag "modules" + tag "modules_nfcore" + tag "stringtie" + tag "stringtie/stringtie" + + test("sarscov2 [bam] - forward strandedness") { + + when { + process { + """ + input[0] = [ + [ id:'test', strandedness:'forward' ], // meta map + [ file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) ] + ] + input[1] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.transcript_gtf).match("fs_transcript_gtf") }, + { assert snapshot(process.out.abundance).match("fs_abundance") }, + { assert snapshot(process.out.versions).match("fs_versions") } + ) + } + } + + test("sarscov2 [bam] - forward strandedness + reference annotation") { + + when { + process { + """ + input[0] = [ + [ id:'test', strandedness:'forward' ], // meta map + [ file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) ] + ] + input[1] = file(params.test_data['sarscov2']['genome']['genome_gtf'], checkIfExists: true) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.transcript_gtf).match("fs_gtf_transcript_gtf") }, + { assert snapshot(process.out.abundance).match("fs_gtf_abundance") }, + { assert snapshot(process.out.ballgown).match("fs_gtf_ballgown") }, + { assert snapshot(process.out.versions).match("fs_gtf_versions") } + ) + } + } + + test("sarscov2 [bam] - reverse strandedness") { + + when { + process { + """ + input[0] = [ + [ id:'test', strandedness:'reverse' ], // meta map + [ file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) ] + ] + input[1] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.transcript_gtf).match("rs_transcript_gtf") }, + { assert snapshot(process.out.abundance).match("rs_abundance") }, + { assert snapshot(process.out.versions).match("rs_versions") } + ) + } + } + + test("sarscov2 [bam] - reverse strandedness + reference annotation") { + + when { + process { + """ + input[0] = [ + [ id:'test', strandedness:'reverse' ], // meta map + [ file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) ] + ] + input[1] = file(params.test_data['sarscov2']['genome']['genome_gtf'], checkIfExists: true) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.transcript_gtf).match("rs_gtf_transcript_gtf") }, + { assert snapshot(process.out.abundance).match("rs_gtf_abundance") }, + { assert snapshot(process.out.ballgown).match("rs_gtf_ballgown") }, + { assert snapshot(process.out.versions).match("rs_gtf_versions") } + ) + } + } +} diff --git a/modules/nf-core/stringtie/stringtie/tests/main.nf.test.snap b/modules/nf-core/stringtie/stringtie/tests/main.nf.test.snap new file mode 100644 index 00000000..bf751636 --- /dev/null +++ b/modules/nf-core/stringtie/stringtie/tests/main.nf.test.snap @@ -0,0 +1,186 @@ +{ + "fs_abundance": { + "content": [ + [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.gene.abundance.txt:md5,d6f5c8cadb8458f1df0427cf790246e3" + ] + ] + ], + "timestamp": "2023-11-23T13:55:41.032044613" + }, + "fs_transcript_gtf": { + "content": [ + [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.transcripts.gtf:md5,569137af5be452413086b50653a97203" + ] + ] + ], + "timestamp": "2023-11-23T13:55:41.017978904" + }, + "rs_abundance": { + "content": [ + [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.gene.abundance.txt:md5,d6f5c8cadb8458f1df0427cf790246e3" + ] + ] + ], + "timestamp": "2023-11-23T13:56:13.601112933" + }, + "fs_gtf_versions": { + "content": [ + [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" + ] + ], + "timestamp": "2023-11-23T13:56:00.523797974" + }, + "fs_gtf_transcript_gtf": { + "content": [ + [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.transcripts.gtf:md5,f56cf8aba2c4a5673bc7963ba5f12d04" + ] + ] + ], + "timestamp": "2023-11-23T13:56:00.475164879" + }, + "rs_versions": { + "content": [ + [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" + ] + ], + "timestamp": "2023-11-23T13:56:13.623892691" + }, + "rs_gtf_transcript_gtf": { + "content": [ + [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.transcripts.gtf:md5,bb346053a8c156b803b055133376c7fa" + ] + ] + ], + "timestamp": "2023-11-23T13:56:22.693599559" + }, + "fs_gtf_abundance": { + "content": [ + [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.gene.abundance.txt:md5,7d8bce7f2a922e367cedccae7267c22e" + ] + ] + ], + "timestamp": "2023-11-23T13:56:00.482135418" + }, + "rs_gtf_ballgown": { + "content": [ + [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + [ + "e2t.ctab:md5,e981c0038295ae54b63cedb1083f1540", + "e_data.ctab:md5,879b6696029d19c4737b562e9d149218", + "i2t.ctab:md5,8a117c8aa4334b4c2d4711932b006fb4", + "i_data.ctab:md5,be3abe09740603213f83d50dcf81427f", + "t_data.ctab:md5,3b66c065da73ae0dd41cc332eff6a818" + ] + ] + ] + ], + "timestamp": "2023-11-23T13:56:22.715698347" + }, + "rs_transcript_gtf": { + "content": [ + [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.transcripts.gtf:md5,31c34aec2bf36bb0ea3c16c2afeeeb1f" + ] + ] + ], + "timestamp": "2023-11-23T13:56:13.590054035" + }, + "rs_gtf_versions": { + "content": [ + [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" + ] + ], + "timestamp": "2023-11-23T13:56:22.725513476" + }, + "fs_gtf_ballgown": { + "content": [ + [ + [ + { + "id": "test", + "strandedness": "forward" + }, + [ + "e2t.ctab:md5,e981c0038295ae54b63cedb1083f1540", + "e_data.ctab:md5,6b4cf69bc03f3f69890f972a0e8b7471", + "i2t.ctab:md5,8a117c8aa4334b4c2d4711932b006fb4", + "i_data.ctab:md5,be3abe09740603213f83d50dcf81427f", + "t_data.ctab:md5,3b66c065da73ae0dd41cc332eff6a818" + ] + ] + ] + ], + "timestamp": "2023-11-23T13:56:00.494299817" + }, + "fs_versions": { + "content": [ + [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" + ] + ], + "timestamp": "2023-11-23T13:55:41.049417582" + }, + "rs_gtf_abundance": { + "content": [ + [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.gene.abundance.txt:md5,7385b870b955dae2c2ab78a70cf05cce" + ] + ] + ], + "timestamp": "2023-11-23T13:56:22.701059059" + } +} diff --git a/modules/nf-core/stringtie/stringtie/tests/tags.yml b/modules/nf-core/stringtie/stringtie/tests/tags.yml new file mode 100644 index 00000000..da9b051c --- /dev/null +++ b/modules/nf-core/stringtie/stringtie/tests/tags.yml @@ -0,0 +1,2 @@ +stringtie/stringtie: + - modules/nf-core/stringtie/stringtie/** diff --git a/modules/nf-core/trimgalore/environment.yml b/modules/nf-core/trimgalore/environment.yml new file mode 100644 index 00000000..6cd0f51b --- /dev/null +++ b/modules/nf-core/trimgalore/environment.yml @@ -0,0 +1,7 @@ +name: trimgalore +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::trim-galore=0.6.7 diff --git a/modules/nf-core/trimgalore/main.nf b/modules/nf-core/trimgalore/main.nf index dcb77ae7..24ead871 100644 --- a/modules/nf-core/trimgalore/main.nf +++ b/modules/nf-core/trimgalore/main.nf @@ -2,7 +2,7 @@ process TRIMGALORE { tag "$meta.id" label 'process_high' - conda "bioconda::trim-galore=0.6.7" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/trim-galore:0.6.7--hdfd78af_0' : 'biocontainers/trim-galore:0.6.7--hdfd78af_0' }" diff --git a/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test b/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test index a8a13f2a..59b749d8 100644 --- a/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test +++ b/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test @@ -5,7 +5,9 @@ nextflow_workflow { workflow "BAM_SORT_STATS_SAMTOOLS" tag "subworkflows" tag "subworkflows_nfcore" + tag "subworkflows/bam_sort_stats_samtools" tag "bam_sort_stats_samtools" + tag "subworkflows/bam_stats_samtools" tag "bam_stats_samtools" tag "samtools" tag "samtools/index" @@ -35,7 +37,11 @@ nextflow_workflow { then { assertAll( { assert workflow.success}, - { assert snapshot(workflow.out).match()} + { assert workflow.out.bam.get(0).get(1) ==~ ".*.bam"}, + { assert workflow.out.bai.get(0).get(1) ==~ ".*.bai"}, + { assert snapshot(workflow.out.stats).match("test_bam_sort_stats_samtools_single_end_stats") }, + { assert snapshot(workflow.out.flagstat).match("test_bam_sort_stats_samtools_single_end_flagstats") }, + { assert snapshot(workflow.out.idxstats).match("test_bam_sort_stats_samtools_single_end_idxstats") } ) } } @@ -61,7 +67,11 @@ nextflow_workflow { then { assertAll( { assert workflow.success}, - { assert snapshot(workflow.out).match()} + { assert workflow.out.bam.get(0).get(1) ==~ ".*.bam"}, + { assert workflow.out.bai.get(0).get(1) ==~ ".*.bai"}, + { assert snapshot(workflow.out.stats).match("test_bam_sort_stats_samtools_paired_end_stats") }, + { assert snapshot(workflow.out.flagstat).match("test_bam_sort_stats_samtools_paired_end_flagstats") }, + { assert snapshot(workflow.out.idxstats).match("test_bam_sort_stats_samtools_paired_end_idxstats") } ) } } diff --git a/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap b/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap index 50ffde60..77afbf17 100644 --- a/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap +++ b/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap @@ -1,236 +1,86 @@ { - "test_bam_sort_stats_samtools_single_end": { + "test_bam_sort_stats_samtools_paired_end_flagstats": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam:md5,2cf8fe8dbba3da7eb4fb251c79f428dc" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam.bai:md5,002488588110dcee464e65f68c4726e8" - ] - ], - "2": [ - - ], - "3": [ - [ - { - "id": "test", - "single_end": false - }, - "test.stats:md5,796f45f791f06291b76329528fae0a54" - ] - ], - "4": [ - [ - { - "id": "test", - "single_end": false - }, - "test.flagstat:md5,2191911d72575a2358b08b1df64ccb53" - ] - ], - "5": [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,613e048487662c694aa4a2f73ca96a20" - ] - ], - "6": [ - "versions.yml:md5,176f12ceae81f76341e481988c799c15", - "versions.yml:md5,7beadfaf6b22ea0ae6e655b41447803f", - "versions.yml:md5,bfcdd8e2d5151a14dac15a9332d73d52", - "versions.yml:md5,dd8f44a9bfef10555ef1c8cc0267ff9c", - "versions.yml:md5,f2eb7aba102adae159006c9a443c301b" - ], - "bai": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam.bai:md5,002488588110dcee464e65f68c4726e8" - ] - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam:md5,2cf8fe8dbba3da7eb4fb251c79f428dc" - ] - ], - "csi": [ - - ], - "flagstat": [ - [ - { - "id": "test", - "single_end": false - }, - "test.flagstat:md5,2191911d72575a2358b08b1df64ccb53" - ] - ], - "idxstats": [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,613e048487662c694aa4a2f73ca96a20" - ] - ], - "stats": [ - [ - { - "id": "test", - "single_end": false - }, - "test.stats:md5,796f45f791f06291b76329528fae0a54" - ] - ], - "versions": [ - "versions.yml:md5,176f12ceae81f76341e481988c799c15", - "versions.yml:md5,7beadfaf6b22ea0ae6e655b41447803f", - "versions.yml:md5,bfcdd8e2d5151a14dac15a9332d73d52", - "versions.yml:md5,dd8f44a9bfef10555ef1c8cc0267ff9c", - "versions.yml:md5,f2eb7aba102adae159006c9a443c301b" + [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" ] - } + ] ], - "timestamp": "2023-10-18T09:34:31.989804787" + "timestamp": "2023-10-22T20:25:03.687121177" }, - "test_bam_sort_stats_samtools_paired_end": { + "test_bam_sort_stats_samtools_paired_end_idxstats": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam:md5,81adec7882577c0ad17962599acf7745" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam.bai:md5,9e6427a796975290b1110c9d542ac79d" - ] - ], - "2": [ - - ], - "3": [ - [ - { - "id": "test", - "single_end": false - }, - "test.stats:md5,f3f0e5aad236aae678ac5361b529a664" - ] - ], - "4": [ - [ - { - "id": "test", - "single_end": false - }, - "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" - ] - ], - "5": [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" - ] - ], - "6": [ - "versions.yml:md5,176f12ceae81f76341e481988c799c15", - "versions.yml:md5,7beadfaf6b22ea0ae6e655b41447803f", - "versions.yml:md5,bfcdd8e2d5151a14dac15a9332d73d52", - "versions.yml:md5,dd8f44a9bfef10555ef1c8cc0267ff9c", - "versions.yml:md5,f2eb7aba102adae159006c9a443c301b" - ], - "bai": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam.bai:md5,9e6427a796975290b1110c9d542ac79d" - ] - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam:md5,81adec7882577c0ad17962599acf7745" - ] - ], - "csi": [ - - ], - "flagstat": [ - [ - { - "id": "test", - "single_end": false - }, - "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" - ] - ], - "idxstats": [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" - ] - ], - "stats": [ - [ - { - "id": "test", - "single_end": false - }, - "test.stats:md5,f3f0e5aad236aae678ac5361b529a664" - ] - ], - "versions": [ - "versions.yml:md5,176f12ceae81f76341e481988c799c15", - "versions.yml:md5,7beadfaf6b22ea0ae6e655b41447803f", - "versions.yml:md5,bfcdd8e2d5151a14dac15a9332d73d52", - "versions.yml:md5,dd8f44a9bfef10555ef1c8cc0267ff9c", - "versions.yml:md5,f2eb7aba102adae159006c9a443c301b" + [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" ] - } + ] ], - "timestamp": "2023-10-18T09:34:57.682759147" + "timestamp": "2023-10-22T20:25:03.709648916" + }, + "test_bam_sort_stats_samtools_single_end_stats": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,f281507081517414eb1a04b2d9c855b2" + ] + ] + ], + "timestamp": "2023-12-04T11:06:50.951881479" + }, + "test_bam_sort_stats_samtools_paired_end_stats": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,e32e7e49dce1fbe327a89e0fb7bc01b1" + ] + ] + ], + "timestamp": "2023-12-04T11:06:59.253905951" + }, + "test_bam_sort_stats_samtools_single_end_idxstats": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,613e048487662c694aa4a2f73ca96a20" + ] + ] + ], + "timestamp": "2023-10-22T20:25:58.451364604" + }, + "test_bam_sort_stats_samtools_single_end_flagstats": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,2191911d72575a2358b08b1df64ccb53" + ] + ] + ], + "timestamp": "2023-10-22T20:25:58.416859285" } } \ No newline at end of file diff --git a/subworkflows/nf-core/bam_sort_stats_samtools/tests/tags.yml b/subworkflows/nf-core/bam_sort_stats_samtools/tests/tags.yml index a8274109..30b69d6a 100644 --- a/subworkflows/nf-core/bam_sort_stats_samtools/tests/tags.yml +++ b/subworkflows/nf-core/bam_sort_stats_samtools/tests/tags.yml @@ -1,2 +1,2 @@ -bam_sort_stats_samtools: +subworkflows/bam_sort_stats_samtools: - subworkflows/nf-core/bam_sort_stats_samtools/** From 38ef8e13bbf751d419a467c73a3ea27c5f32887f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 13 Jan 2024 11:45:45 +0100 Subject: [PATCH 090/491] Remove config artifact --- nextflow.config | 3 --- 1 file changed, 3 deletions(-) diff --git a/nextflow.config b/nextflow.config index b3699c50..0b995eda 100644 --- a/nextflow.config +++ b/nextflow.config @@ -100,9 +100,6 @@ params { validationSchemaIgnoreParams = 'genomes,igenomes_base' validationShowHiddenParams = false validate_params = true - withName: INTEGRATE_SCVI { - cpus: 60 - } } // Load base.config by default for all pipelines From 1b96c1ba1427e2a4480e6a083c44fd300fab5eb3 Mon Sep 17 00:00:00 2001 From: nictru Date: Sun, 22 Oct 2023 14:37:05 +0200 Subject: [PATCH 091/491] Prevent meta alteration --- subworkflows/local/circrna_discovery.nf | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 09428987..d75f6ed0 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -80,7 +80,7 @@ workflow CIRCRNA_DISCOVERY { // SEGEMEHL WORKFLOW: // SEGEMEHL_ALIGN( reads, fasta, segemehl_index ) - segemehl_filter = SEGEMEHL_ALIGN.out.results.map{ meta, results -> meta.tool = "segemehl"; return [ meta, results ] } + segemehl_filter = SEGEMEHL_ALIGN.out.results.map{ meta, results -> [ meta + [tool: "segemehl"], results ] } SEGEMEHL_FILTER( segemehl_filter, bsj_reads ) ch_versions = ch_versions.mix(SEGEMEHL_ALIGN.out.versions) @@ -110,7 +110,7 @@ workflow CIRCRNA_DISCOVERY { CIRCEXPLORER2_REF( gtf ) CIRCEXPLORER2_PAR( STAR_2ND_PASS.out.junction ) CIRCEXPLORER2_ANN( CIRCEXPLORER2_PAR.out.junction, fasta, CIRCEXPLORER2_REF.out.txt ) - circexplorer2_filter = CIRCEXPLORER2_ANN.out.txt.map{ meta, txt -> meta.tool = "circexplorer2"; return [ meta, txt ] } + circexplorer2_filter = CIRCEXPLORER2_ANN.out.txt.map{ meta, txt -> [ meta + [tool: "circexplorer2"], txt ] } CIRCEXPLORER2_FLT( circexplorer2_filter, bsj_reads ) ch_versions = ch_versions.mix(CIRCEXPLORER2_REF.out.versions) @@ -123,7 +123,7 @@ workflow CIRCRNA_DISCOVERY { // circrna_finder_stage = STAR_2ND_PASS.out.sam.join( STAR_2ND_PASS.out.junction).join(STAR_2ND_PASS.out.tab) - circrna_finder_filter = circrna_finder_stage.map{ meta, sam, junction, tab -> meta.tool = "circrna_finder"; return [ meta, sam, junction, tab ] } + circrna_finder_filter = circrna_finder_stage.map{ meta, sam, junction, tab -> [ meta + [tool: "circrna_finder"], sam, junction, tab ] } CIRCRNA_FINDER_FILTER( circrna_finder_filter, fasta, bsj_reads ) ch_versions = ch_versions.mix(CIRCRNA_FINDER_FILTER.out.versions) @@ -137,7 +137,7 @@ workflow CIRCRNA_DISCOVERY { SAMTOOLS_VIEW( FIND_CIRC_ALIGN.out.aligned.join( SAMTOOLS_INDEX.out.bai ), fasta_tuple, [] ) FIND_CIRC_ANCHORS( SAMTOOLS_VIEW.out.bam ) FIND_CIRC( FIND_CIRC_ANCHORS.out.anchors, bowtie2_index.collect(), fasta ) - find_circ_filter = FIND_CIRC.out.bed.map{ meta, bed -> meta.tool = "find_circ"; return [ meta, bed ] } + find_circ_filter = FIND_CIRC.out.bed.map{ meta, bed -> [ meta + [tool: "find_circ"], bed ] } FIND_CIRC_FILTER( find_circ_filter, bsj_reads ) ch_versions = ch_versions.mix(FIND_CIRC_ALIGN.out.versions) @@ -155,7 +155,7 @@ workflow CIRCRNA_DISCOVERY { // do not want to upset the collect declr for all indices just for this. CIRIQUANT_YML( gtf, fasta, bwa_index.map{ meta, index -> return index }, hisat2_index.map{ meta, index -> return index } ) CIRIQUANT( reads, CIRIQUANT_YML.out.yml.collect() ) - CIRIQUANT_FILTER( CIRIQUANT.out.gtf.map{ meta, gtf -> meta.tool = "ciriquant"; return [ meta, gtf ] }, bsj_reads ) + CIRIQUANT_FILTER( CIRIQUANT.out.gtf.map{ meta, gtf -> [ meta + [tool: "ciriquant"], gtf ] }, bsj_reads ) ch_versions = ch_versions.mix(CIRIQUANT.out.versions) ch_versions = ch_versions.mix(CIRIQUANT_FILTER.out.versions) @@ -191,7 +191,7 @@ workflow CIRCRNA_DISCOVERY { dcc = dcc_stage.map{ it -> [ it[0], it[1], it[2] ?: [], it[3] ?: [] ] } DCC( dcc, fasta, gtf ) - DCC_FILTER( DCC.out.txt.map{ meta, txt -> meta.tool = "dcc"; return [ meta, txt ] }, bsj_reads ) + DCC_FILTER( DCC.out.txt.map{ meta, txt -> [ meta + [tool: "dcc"], txt ] }, bsj_reads ) ch_versions = ch_versions.mix(DCC_MATE1_1ST_PASS.out.versions) ch_versions = ch_versions.mix(DCC_MATE1_SJDB.out.versions) @@ -210,7 +210,7 @@ workflow CIRCRNA_DISCOVERY { MAPSPLICE_ALIGN( reads, bowtie_index.collect(), chromosomes, gtf ) MAPSPLICE_PARSE( MAPSPLICE_ALIGN.out.raw_fusions ) MAPSPLICE_ANNOTATE( MAPSPLICE_PARSE.out.junction, fasta, MAPSPLICE_REFERENCE.out.txt ) - mapsplice_filter = MAPSPLICE_ANNOTATE.out.txt.map{ meta, txt -> meta.tool = "mapsplice"; return [ meta, txt ] } + mapsplice_filter = MAPSPLICE_ANNOTATE.out.txt.map{ meta, txt -> [ meta + [tool: "mapsplice"], txt ] } MAPSPLICE_FILTER( mapsplice_filter, bsj_reads ) ch_versions = ch_versions.mix(MAPSPLICE_REFERENCE.out.versions) @@ -258,7 +258,7 @@ workflow CIRCRNA_DISCOVERY { if( tools_selected.size() > 1){ - MERGE_TOOLS( ch_matrix.map{ meta, bed -> var = [:]; var.id = meta.id; return [ var, bed ] }.groupTuple(), tool_filter, duplicates_fun ) + MERGE_TOOLS( ch_matrix.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), tool_filter, duplicates_fun ) COUNTS_COMBINED( MERGE_TOOLS.out.merged.map{ meta, bed -> return [ bed ] }.collect() ) @@ -269,7 +269,7 @@ workflow CIRCRNA_DISCOVERY { }else{ - COUNTS_SINGLE( ch_matrix.map{ meta, bed -> var = [:]; var.tool = meta.tool; return [ var, bed ] }.groupTuple() ) + COUNTS_SINGLE( ch_matrix.map{ meta, bed -> [ [tool: meta.tool], bed ] }.groupTuple() ) dea_matrix = COUNTS_SINGLE.out.dea_matrix clr_matrix = COUNTS_SINGLE.out.clr_matrix From 690ab3c88f74608e062337a98b3c2f86580c522f Mon Sep 17 00:00:00 2001 From: nictru Date: Tue, 24 Oct 2023 15:32:37 +0200 Subject: [PATCH 092/491] Fix problems which prevent proper caching --- bin/circRNA_counts_matrix.py | 2 ++ modules/local/count_matrix/combined/main.nf | 4 +-- .../local/count_matrix/merge_tools/main.nf | 2 +- modules/local/fasta/main.nf | 9 +++--- subworkflows/local/circrna_discovery.nf | 20 ++++--------- subworkflows/local/differential_expression.nf | 10 ++----- subworkflows/local/prepare_genome.nf | 30 ++++++++----------- 7 files changed, 28 insertions(+), 49 deletions(-) diff --git a/bin/circRNA_counts_matrix.py b/bin/circRNA_counts_matrix.py index 07999b23..3f6e24f6 100755 --- a/bin/circRNA_counts_matrix.py +++ b/bin/circRNA_counts_matrix.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + import sys, glob from collections import defaultdict diff --git a/modules/local/count_matrix/combined/main.nf b/modules/local/count_matrix/combined/main.nf index e277ffff..353da918 100644 --- a/modules/local/count_matrix/combined/main.nf +++ b/modules/local/count_matrix/combined/main.nf @@ -20,12 +20,12 @@ process COUNTS_COMBINED { script: def args = task.ext.args ?: '' """ - python ${workflow.projectDir}/bin/circRNA_counts_matrix.py > matrix.txt + circRNA_counts_matrix.py > matrix.txt ## handle non-canon chromosomes here (https://stackoverflow.com/questions/71479919/joining-columns-based-on-number-of-fields) n_samps=\$(ls *.bed | wc -l) canon=\$(awk -v a="\$n_samps" 'BEGIN {print a + 4}') awk -v n="\$canon" '{ for (i = 2; i <= NF - n + 1; ++i) { \$1 = \$1"-"\$i; \$i=""; } } 1' matrix.txt | awk -v OFS="\t" '\$1=\$1' > circRNA_matrix.txt - Rscript ${workflow.projectDir}/bin/reformat_count_matrix.R + reformat_count_matrix.R cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/count_matrix/merge_tools/main.nf b/modules/local/count_matrix/merge_tools/main.nf index cc6818dd..106df47b 100644 --- a/modules/local/count_matrix/merge_tools/main.nf +++ b/modules/local/count_matrix/merge_tools/main.nf @@ -31,7 +31,7 @@ process MERGE_TOOLS { ## Use intersection of "n" (params.tool_filter) circRNAs called by tools ## remove duplicate IDs, keep highest count. - Rscript ${workflow.projectDir}/bin/consolidate_algorithms_intersection.R samples.csv $tool_filter $duplicates_fun + consolidate_algorithms_intersection.R samples.csv $tool_filter $duplicates_fun mv combined_counts.bed ${prefix}.bed cat <<-END_VERSIONS > versions.yml diff --git a/modules/local/fasta/main.nf b/modules/local/fasta/main.nf index e33edeed..904cecc3 100644 --- a/modules/local/fasta/main.nf +++ b/modules/local/fasta/main.nf @@ -8,8 +8,8 @@ process FASTA { 'quay.io/biocontainers/bedtools:2.30.0--h7d7f7ad_2' }" input: - tuple val(meta), path(bed) - path fasta + tuple val(meta), path(bed, name: "bed.input") + path fasta, name: "fasta.input" output: tuple val(meta), path("${prefix}.fa"), emit: analysis_fasta @@ -24,15 +24,14 @@ process FASTA { prefix = task.ext.prefix ?: "${meta.id}" """ ## FASTA sequences (bedtools does not like the extra annotation info - split will not work properly) - cut -d\$'\t' -f1-12 ${prefix}.bed > bed12.tmp + cut -d\$'\t' -f1-12 bed.input > bed12.tmp bedtools getfasta -fi $fasta -bed bed12.tmp -s -split -name > circ_seq.tmp ## clean fasta header grep -A 1 '>' circ_seq.tmp | cut -d: -f1,2,3 > ${prefix}.fa && rm circ_seq.tmp ## add backsplice sequence for miRanda Targetscan, publish canonical FASTA to results. - rm $fasta - bash ${workflow.projectDir}/bin/backsplice_gen.sh ${prefix}.fa + backsplice_gen.sh ${prefix}.fa cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index d75f6ed0..2949f9c0 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -60,20 +60,10 @@ workflow CIRCRNA_DISCOVERY { main: ch_versions = Channel.empty() - ch_fasta = Channel.fromPath(fasta) - ch_gtf = Channel.fromPath(gtf) - - ch_fasta.map{ it -> - meta = [:] - meta.id = it.simpleName - return [ meta, [it] ] - }.set{ fasta_tuple } - - gtf_tuple = ch_gtf.map{ it -> - meta = [:] - meta.id = it.simpleName - return [ meta, [it] ] - }.collect() + ch_fasta = Channel.value(fasta) + ch_gtf = Channel.value(gtf) + fasta_tuple = Channel.value([[id: "fasta"], fasta]) + gtf_tuple = Channel.value([[id: "gtf"], gtf]) // @@ -207,7 +197,7 @@ workflow CIRCRNA_DISCOVERY { // MAPSPLICE_REFERENCE( gtf ) - MAPSPLICE_ALIGN( reads, bowtie_index.collect(), chromosomes, gtf ) + MAPSPLICE_ALIGN( reads, bowtie_index.collect(), chromosomes, ch_gtf ) MAPSPLICE_PARSE( MAPSPLICE_ALIGN.out.raw_fusions ) MAPSPLICE_ANNOTATE( MAPSPLICE_PARSE.out.junction, fasta, MAPSPLICE_REFERENCE.out.txt ) mapsplice_filter = MAPSPLICE_ANNOTATE.out.txt.map{ meta, txt -> [ meta + [tool: "mapsplice"], txt ] } diff --git a/subworkflows/local/differential_expression.nf b/subworkflows/local/differential_expression.nf index aa92527a..2964c3fb 100644 --- a/subworkflows/local/differential_expression.nf +++ b/subworkflows/local/differential_expression.nf @@ -29,16 +29,10 @@ workflow DIFFERENTIAL_EXPRESSION { ch_fasta = Channel.fromPath(fasta) ch_gtf = Channel.fromPath(gtf) - ch_fasta.map{ it -> - meta = [:] - meta.id = it.simpleName - return [ meta, [it] ] + ch_fasta.map{ it -> [ [id: it.simpleName], [it] ] }.set{ fasta_tuple } - ch_gtf.map{ it -> - meta = [:] - meta.id = it.simpleName - return [ meta, [it] ] + ch_gtf.map{ it -> [ [id: it.simpleName], [it] ] }.set{ gtf_tuple } // diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 496002ff..84d932db 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -18,33 +18,27 @@ workflow PREPARE_GENOME { ch_fasta = Channel.fromPath(fasta) ch_gtf = Channel.fromPath(gtf) + fasta_tuple = Channel.value([[id: "fasta"], fasta]) + gtf_tuple = Channel.value([[id: "gtf"], gtf]) // MapSplice & find_circ requires reference genome to be split per chromosome: if( ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) && params.module.contains('circrna_discovery') ){ - file("${params.outdir}/references/chromosomes").mkdirs() - ch_fasta.splitFasta( record: [id:true] ) + directory = file("${params.outdir}/references/chromosomes") + + if ( !directory.exists() ) { + directory.mkdirs() + ch_fasta.splitFasta( record: [id:true] ) .map{ record -> record.id.toString() } .set{ ID } - ch_fasta.splitFasta( file: true ) - .merge( ID ).map{ file, id -> file.copyTo("${params.outdir}/references/chromosomes/${id}.fa") } + ch_fasta.splitFasta( file: true ) + .merge( ID ).map{ file, id -> file.copyTo(directory + "/${id}.fa") } + } - stage_chromosomes = Channel.value("${workflow.launchDir}/${params.outdir}/references/chromosomes") + stage_chromosomes = Channel.value(directory) } - ch_fasta.map{ it -> - meta = [:] - meta.id = it.simpleName - return [ meta, [it] ] - }.set{ fasta_tuple } - - ch_gtf.map{ it -> - meta = [:] - meta.id = it.simpleName - return [ meta, [it] ] - }.set{ gtf_tuple } - - BOWTIE_BUILD(fasta) + BOWTIE_BUILD(ch_fasta) BOWTIE2_BUILD(fasta_tuple) From 7036c933dfb5d79becd564d907c1e1e9f0368e55 Mon Sep 17 00:00:00 2001 From: nictru Date: Sun, 19 Nov 2023 08:19:38 +0100 Subject: [PATCH 093/491] Escape tab characters --- modules/local/annotation/full_annotation/main.nf | 2 +- modules/local/annotation/parent_gene/main.nf | 4 ++-- modules/local/circexplorer2/filter/main.nf | 4 ++-- modules/local/circexplorer2/reference/main.nf | 2 +- modules/local/circrna_finder/filter/main.nf | 4 ++-- modules/local/ciriquant/filter/main.nf | 6 +++--- modules/local/count_matrix/combined/main.nf | 2 +- modules/local/count_matrix/single/main.nf | 2 +- modules/local/dcc/dcc/main.nf | 4 ++-- modules/local/dcc/filter/main.nf | 4 ++-- modules/local/fasta/main.nf | 2 +- modules/local/find_circ/filter/main.nf | 4 ++-- modules/local/mirna_targets/main.nf | 8 ++++---- modules/local/segemehl/filter/main.nf | 6 +++--- modules/local/stringtie/prepde/main.nf | 2 +- modules/local/targetscan/predict/main.nf | 2 +- 16 files changed, 29 insertions(+), 29 deletions(-) diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/full_annotation/main.nf index a8954311..789c884f 100644 --- a/modules/local/annotation/full_annotation/main.nf +++ b/modules/local/annotation/full_annotation/main.nf @@ -33,7 +33,7 @@ process ANNOTATION { annotate_outputs.sh $exon_boundary &> ${prefix}.log mv master_bed12.bed ${prefix}.bed.tmp - awk -v FS="\t" '{print \$11}' ${prefix}.bed.tmp > mature_len.tmp + awk -v FS="\\t" '{print \$11}' ${prefix}.bed.tmp > mature_len.tmp awk -v FS="," '{for(i=t=0;i mature_length paste ${prefix}.bed.tmp mature_length > ${prefix}.bed diff --git a/modules/local/annotation/parent_gene/main.nf b/modules/local/annotation/parent_gene/main.nf index ed035527..9566f015 100644 --- a/modules/local/annotation/parent_gene/main.nf +++ b/modules/local/annotation/parent_gene/main.nf @@ -35,14 +35,14 @@ process PARENT_GENE { start=\$(echo \$line | cut -d- -f1 | cut -d: -f2) stop=\$(echo \$line | cut -d- -f2 | cut -d: -f1) sign=\$(echo \$line | cut -d: -f3) - echo -e "\$chr\t\$start\t\$stop\t\$name\t0\t\$sign" >> \${name}.bed + echo -e "\$chr\\t\$start\\t\$stop\\t\$name\\t0\\t\$sign" >> \${name}.bed done < IDs.txt cat *.bed > merged.txt && rm IDs.txt && rm *.bed && mv merged.txt circs.bed # Re-use annotation script to identify the host gene. annotate_outputs.sh $exon_boundary &> annotation.log - awk -v OFS="\t" '{print \$4, \$14}' master_bed12.bed > circrna_host-gene.txt + awk -v OFS="\\t" '{print \$4, \$14}' master_bed12.bed > circrna_host-gene.txt cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/circexplorer2/filter/main.nf b/modules/local/circexplorer2/filter/main.nf index e0973753..3b6cc9bf 100644 --- a/modules/local/circexplorer2/filter/main.nf +++ b/modules/local/circexplorer2/filter/main.nf @@ -24,9 +24,9 @@ process CIRCEXPLORER2_FILTER { prefix = task.ext.prefix ?: "${meta.id}" def VERSION = '1.3.4' """ - awk '{if(\$13 >= ${bsj_reads}) print \$0}' ${prefix}.txt | awk -v OFS="\t" '{print \$1,\$2,\$3,\$6,\$13}' > ${prefix}_${meta.tool}.bed + awk '{if(\$13 >= ${bsj_reads}) print \$0}' ${prefix}.txt | awk -v OFS="\\t" '{print \$1,\$2,\$3,\$6,\$13}' > ${prefix}_${meta.tool}.bed - awk -v OFS="\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_${meta.tool}.bed > ${prefix}_${meta.tool}_circs.bed + awk -v OFS="\\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_${meta.tool}.bed > ${prefix}_${meta.tool}_circs.bed cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/circexplorer2/reference/main.nf b/modules/local/circexplorer2/reference/main.nf index 6bb46f78..07571e4a 100644 --- a/modules/local/circexplorer2/reference/main.nf +++ b/modules/local/circexplorer2/reference/main.nf @@ -27,7 +27,7 @@ process CIRCEXPLORER2_REFERENCE { $gtf \ ${prefix}.genepred - awk -v OFS="\t" '{print \$12, \$1, \$2, \$3, \$4, \$5, \$6, \$7, \$8, \$9, \$10}' ${prefix}.genepred > ${prefix}.txt + awk -v OFS="\\t" '{print \$12, \$1, \$2, \$3, \$4, \$5, \$6, \$7, \$8, \$9, \$10}' ${prefix}.genepred > ${prefix}.txt cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/circrna_finder/filter/main.nf b/modules/local/circrna_finder/filter/main.nf index 0cda828e..1182442f 100644 --- a/modules/local/circrna_finder/filter/main.nf +++ b/modules/local/circrna_finder/filter/main.nf @@ -29,9 +29,9 @@ process CIRCRNA_FINDER_FILTER { mkdir -p star_dir && mv *.tab *.junction *.sam star_dir postProcessStarAlignment.pl --starDir star_dir/ --outDir ./ - awk '{if(\$5 >= ${bsj_reads}) print \$0}' ${prefix}.filteredJunctions.bed | awk -v OFS="\t" -F"\t" '{print \$1,\$2,\$3,\$6,\$5}' > ${prefix}_circrna_finder.bed + awk '{if(\$5 >= ${bsj_reads}) print \$0}' ${prefix}.filteredJunctions.bed | awk -v OFS="\\t" -F"\\t" '{print \$1,\$2,\$3,\$6,\$5}' > ${prefix}_circrna_finder.bed - awk -v OFS="\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_circrna_finder.bed > ${prefix}_circrna_finder_circs.bed + awk -v OFS="\\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_circrna_finder.bed > ${prefix}_circrna_finder_circs.bed cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/ciriquant/filter/main.nf b/modules/local/ciriquant/filter/main.nf index 518555a3..c36e4638 100644 --- a/modules/local/ciriquant/filter/main.nf +++ b/modules/local/ciriquant/filter/main.nf @@ -24,16 +24,16 @@ process CIRIQUANT_FILTER { def VERSION = '1.3.4' """ grep -v "#" ${prefix}.gtf | awk '{print \$14}' | cut -d '.' -f1 > counts - grep -v "#" ${prefix}.gtf | awk -v OFS="\t" '{print \$1,\$4,\$5,\$7}' > ${prefix}.tmp + grep -v "#" ${prefix}.gtf | awk -v OFS="\\t" '{print \$1,\$4,\$5,\$7}' > ${prefix}.tmp paste ${prefix}.tmp counts > ${prefix}_unfilt.bed awk '{if(\$5 >= ${bsj_reads}) print \$0}' ${prefix}_unfilt.bed > ${prefix}_filt.bed grep -v '^\$' ${prefix}_filt.bed > ${prefix}_ciriquant - awk -v OFS="\t" '{\$2-=1;print}' ${prefix}_ciriquant > ${prefix}_ciriquant.bed + awk -v OFS="\\t" '{\$2-=1;print}' ${prefix}_ciriquant > ${prefix}_ciriquant.bed rm ${prefix}.gtf - awk -v OFS="\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_ciriquant.bed > ${prefix}_ciriquant_circs.bed + awk -v OFS="\\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_ciriquant.bed > ${prefix}_ciriquant_circs.bed cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/count_matrix/combined/main.nf b/modules/local/count_matrix/combined/main.nf index 353da918..4c299853 100644 --- a/modules/local/count_matrix/combined/main.nf +++ b/modules/local/count_matrix/combined/main.nf @@ -24,7 +24,7 @@ process COUNTS_COMBINED { ## handle non-canon chromosomes here (https://stackoverflow.com/questions/71479919/joining-columns-based-on-number-of-fields) n_samps=\$(ls *.bed | wc -l) canon=\$(awk -v a="\$n_samps" 'BEGIN {print a + 4}') - awk -v n="\$canon" '{ for (i = 2; i <= NF - n + 1; ++i) { \$1 = \$1"-"\$i; \$i=""; } } 1' matrix.txt | awk -v OFS="\t" '\$1=\$1' > circRNA_matrix.txt + awk -v n="\$canon" '{ for (i = 2; i <= NF - n + 1; ++i) { \$1 = \$1"-"\$i; \$i=""; } } 1' matrix.txt | awk -v OFS="\\t" '\$1=\$1' > circRNA_matrix.txt reformat_count_matrix.R cat <<-END_VERSIONS > versions.yml diff --git a/modules/local/count_matrix/single/main.nf b/modules/local/count_matrix/single/main.nf index 59f628c8..856ffa7e 100644 --- a/modules/local/count_matrix/single/main.nf +++ b/modules/local/count_matrix/single/main.nf @@ -33,7 +33,7 @@ process COUNTS_SINGLE { ## handle non-canon chromosomes here (https://stackoverflow.com/questions/71479919/joining-columns-based-on-number-of-fields) n_samps=\$(ls *.bed | wc -l) canon=\$(awk -v a="\$n_samps" 'BEGIN {print a + 4}') - awk -v n="\$canon" '{ for (i = 2; i <= NF - n + 1; ++i) { \$1 = \$1"-"\$i; \$i=""; } } 1' matrix.txt | awk -v OFS="\t" '\$1=\$1' > circRNA_matrix.txt + awk -v n="\$canon" '{ for (i = 2; i <= NF - n + 1; ++i) { \$1 = \$1"-"\$i; \$i=""; } } 1' matrix.txt | awk -v OFS="\\t" '\$1=\$1' > circRNA_matrix.txt Rscript ${workflow.projectDir}/bin/reformat_count_matrix.R cat <<-END_VERSIONS > versions.yml diff --git a/modules/local/dcc/dcc/main.nf b/modules/local/dcc/dcc/main.nf index b8db483f..77dc2c55 100644 --- a/modules/local/dcc/dcc/main.nf +++ b/modules/local/dcc/dcc/main.nf @@ -31,7 +31,7 @@ process DCC { DCC @samplesheet -D -an $gtf -Pi -ss -F -M -Nr 1 1 -fg -A $fasta -N -T ${task.cpus} awk '{print \$6}' CircCoordinates >> strand - paste CircRNACount strand | tail -n +2 | awk -v OFS="\t" '{print \$1,\$2,\$3,\$5,\$4}' >> ${prefix}.txt + paste CircRNACount strand | tail -n +2 | awk -v OFS="\\t" '{print \$1,\$2,\$3,\$5,\$4}' >> ${prefix}.txt cat <<-END_VERSIONS > versions.yml "${task.process}": @@ -49,7 +49,7 @@ process DCC { DCC @samplesheet -mt1 @mate1file -mt2 @mate2file -D -an $gtf -Pi -ss -F -M -Nr 1 1 -fg -A $fasta -N -T ${task.cpus} awk '{print \$6}' CircCoordinates >> strand - paste CircRNACount strand | tail -n +2 | awk -v OFS="\t" '{print \$1,\$2,\$3,\$5,\$4}' >> ${prefix}.txt + paste CircRNACount strand | tail -n +2 | awk -v OFS="\\t" '{print \$1,\$2,\$3,\$5,\$4}' >> ${prefix}.txt cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/dcc/filter/main.nf b/modules/local/dcc/filter/main.nf index 4c7d235e..78d3e571 100644 --- a/modules/local/dcc/filter/main.nf +++ b/modules/local/dcc/filter/main.nf @@ -24,8 +24,8 @@ process DCC_FILTER { def VERSION = '1.3.4' """ awk '{if(\$5 >= ${bsj_reads}) print \$0}' ${prefix}.txt > ${prefix}_dcc.filtered - awk -v OFS="\t" '{\$2-=1;print}' ${prefix}_dcc.filtered > ${prefix}_dcc.bed - awk -v OFS="\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_dcc.bed > ${prefix}_dcc_circs.bed + awk -v OFS="\\t" '{\$2-=1;print}' ${prefix}_dcc.filtered > ${prefix}_dcc.bed + awk -v OFS="\\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_dcc.bed > ${prefix}_dcc_circs.bed cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/fasta/main.nf b/modules/local/fasta/main.nf index 904cecc3..aff89fde 100644 --- a/modules/local/fasta/main.nf +++ b/modules/local/fasta/main.nf @@ -24,7 +24,7 @@ process FASTA { prefix = task.ext.prefix ?: "${meta.id}" """ ## FASTA sequences (bedtools does not like the extra annotation info - split will not work properly) - cut -d\$'\t' -f1-12 bed.input > bed12.tmp + cut -d\$'\\t' -f1-12 bed.input > bed12.tmp bedtools getfasta -fi $fasta -bed bed12.tmp -s -split -name > circ_seq.tmp ## clean fasta header diff --git a/modules/local/find_circ/filter/main.nf b/modules/local/find_circ/filter/main.nf index a12c15ba..c8e4f3a7 100644 --- a/modules/local/find_circ/filter/main.nf +++ b/modules/local/find_circ/filter/main.nf @@ -30,9 +30,9 @@ process FIND_CIRC_FILTER { maxlength.py 100000 \ > ${prefix}.txt - tail -n +2 ${prefix}.txt | awk -v OFS="\t" '{print \$1,\$2,\$3,\$6,\$5}' > ${prefix}_find_circ.bed + tail -n +2 ${prefix}.txt | awk -v OFS="\\t" '{print \$1,\$2,\$3,\$6,\$5}' > ${prefix}_find_circ.bed - awk -v OFS="\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_find_circ.bed > ${prefix}_find_circ_circs.bed + awk -v OFS="\\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_find_circ.bed > ${prefix}_find_circ_circs.bed cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/mirna_targets/main.nf b/modules/local/mirna_targets/main.nf index 0891e6e4..fdfee556 100644 --- a/modules/local/mirna_targets/main.nf +++ b/modules/local/mirna_targets/main.nf @@ -22,8 +22,8 @@ process MIRNA_TARGETS { prefix = task.ext.prefix ?: "${meta.id}" """ ## reformat and sort miRanda, TargetScan outputs, convert to BED for overlaps. - tail -n +2 $targetscan | sort -k1,1 -k4n | awk -v OFS="\t" '{print \$1, \$2, \$4, \$5, \$9}' | awk -v OFS="\t" '{print \$2, \$3, \$4, \$1, "0", \$5}' > targetscan.bed - tail -n +2 $miranda | sort -k2,2 -k7n | awk -v OFS="\t" '{print \$2, \$1, \$3, \$4, \$7, \$8}' | awk -v OFS="\t" '{print \$2, \$5, \$6, \$1, \$3, \$4}' | sed 's/^[^-]*-//g' > miranda.bed + tail -n +2 $targetscan | sort -k1,1 -k4n | awk -v OFS="\\t" '{print \$1, \$2, \$4, \$5, \$9}' | awk -v OFS="\t" '{print \$2, \$3, \$4, \$1, "0", \$5}' > targetscan.bed + tail -n +2 $miranda | sort -k2,2 -k7n | awk -v OFS="\\t" '{print \$2, \$1, \$3, \$4, \$7, \$8}' | awk -v OFS="\t" '{print \$2, \$5, \$6, \$1, \$3, \$4}' | sed 's/^[^-]*-//g' > miranda.bed ## intersect, consolidate miRanda, TargetScan information about miRs. ## -wa to output miRanda hits - targetscan makes it difficult to resolve duplicate miRNAs at MRE sites. @@ -32,8 +32,8 @@ process MIRNA_TARGETS { ## remove duplicate miRNA entries at MRE sites. ## strategy: sory by circs, sort by start position, sort by site type - the goal is to take the best site type (i.e rank site type found at MRE site). - paste ${prefix}.mirnas.tmp mirna_type | sort -k3,3 -k2n -k7r | awk -v OFS="\t" '{print \$4,\$1,\$2,\$3,\$5,\$6,\$7}' | awk -F "\t" '{if (!seen[\$1,\$2,\$3,\$4,\$5,\$6]++)print}' | sort -k1,1 -k3n > ${prefix}.mirna_targets.tmp - echo -e "circRNA\tmiRNA\tStart\tEnd\tScore\tEnergy_KcalMol\tSite_type" | cat - ${prefix}.mirna_targets.tmp > ${prefix}.mirna_targets.txt + paste ${prefix}.mirnas.tmp mirna_type | sort -k3,3 -k2n -k7r | awk -v OFS="\\t" '{print \$4,\$1,\$2,\$3,\$5,\$6,\$7}' | awk -F "\\t" '{if (!seen[\$1,\$2,\$3,\$4,\$5,\$6]++)print}' | sort -k1,1 -k3n > ${prefix}.mirna_targets.tmp + echo -e "circRNA\\tmiRNA\\tStart\\tEnd\\tScore\\tEnergy_KcalMol\\tSite_type" | cat - ${prefix}.mirna_targets.tmp > ${prefix}.mirna_targets.txt cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/segemehl/filter/main.nf b/modules/local/segemehl/filter/main.nf index a3c1c7a8..a1cf9929 100644 --- a/modules/local/segemehl/filter/main.nf +++ b/modules/local/segemehl/filter/main.nf @@ -24,11 +24,11 @@ process SEGEMEHL_FILTER { prefix = task.ext.prefix ?: "${meta.id}" def VERSION = '1.3.4' """ - grep ';C;' ${prefix}.sngl.bed | awk -v OFS="\t" '{print \$1,\$2,\$3,\$6}' | sort | uniq -c | awk -v OFS="\t" '{print \$2,\$3,\$4,\$5,\$1}' > ${prefix}_collapsed.bed + grep ';C;' ${prefix}.sngl.bed | awk -v OFS="\\t" '{print \$1,\$2,\$3,\$6}' | sort | uniq -c | awk -v OFS="\\t" '{print \$2,\$3,\$4,\$5,\$1}' > ${prefix}_collapsed.bed - awk -v OFS="\t" -v BSJ=${bsj_reads} '{if(\$5>=BSJ) print \$0}' ${prefix}_collapsed.bed > ${prefix}_segemehl.bed + awk -v OFS="\\t" -v BSJ=${bsj_reads} '{if(\$5>=BSJ) print \$0}' ${prefix}_collapsed.bed > ${prefix}_segemehl.bed - awk -v OFS="\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_segemehl.bed > ${prefix}_segemehl_circs.bed + awk -v OFS="\\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_segemehl.bed > ${prefix}_segemehl_circs.bed cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/stringtie/prepde/main.nf b/modules/local/stringtie/prepde/main.nf index 92f4680c..eb72483b 100644 --- a/modules/local/stringtie/prepde/main.nf +++ b/modules/local/stringtie/prepde/main.nf @@ -19,7 +19,7 @@ process STRINGTIE_PREPDE { script: """ - for file in \$(ls *.gtf); do sample_id=\${file%".transcripts.gtf"}; touch samples.txt; printf "\$sample_id\t\$file\\n" >> samples.txt ; done + for file in \$(ls *.gtf); do sample_id=\${file%".transcripts.gtf"}; touch samples.txt; printf "\$sample_id\\t\$file\\n" >> samples.txt ; done prepDE.py -i samples.txt diff --git a/modules/local/targetscan/predict/main.nf b/modules/local/targetscan/predict/main.nf index 62599ab8..e8e5567f 100644 --- a/modules/local/targetscan/predict/main.nf +++ b/modules/local/targetscan/predict/main.nf @@ -25,7 +25,7 @@ process TARGETSCAN { ##format for targetscan cat $fasta | grep ">" | sed 's/>//g' > id cat $fasta | grep -v ">" > seq - paste id seq | awk -v OFS="\t" '{print \$1, "0000", \$2}' > ${prefix}_ts.txt + paste id seq | awk -v OFS="\\t" '{print \$1, "0000", \$2}' > ${prefix}_ts.txt # run targetscan targetscan_70.pl mature.txt ${prefix}_ts.txt ${prefix}.txt From 099b99784a11eb6809232abf9793d5a78b5344fd Mon Sep 17 00:00:00 2001 From: nictru Date: Fri, 10 Nov 2023 08:26:15 +0100 Subject: [PATCH 094/491] Fix problems with illegal R column names --- bin/reformat_count_matrix.R | 2 +- modules/local/count_matrix/combined/main.nf | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/bin/reformat_count_matrix.R b/bin/reformat_count_matrix.R index 8afabe6f..3c635b29 100755 --- a/bin/reformat_count_matrix.R +++ b/bin/reformat_count_matrix.R @@ -4,7 +4,7 @@ ## License: MIT library(dplyr) -mat <- read.table("circRNA_matrix.txt", sep="\t", header=T, stringsAsFactors=F) +mat <- read.table("circRNA_matrix.txt", sep="\t", header=T, stringsAsFactors=F, check.names=F) mat$ID <- with(mat, paste0(Chr, sep=":", Start, sep="-", Stop, sep=":", Strand)) mat <- mat[,-c(1:4)] mat1 <- mat %>% select(ID, everything()) diff --git a/modules/local/count_matrix/combined/main.nf b/modules/local/count_matrix/combined/main.nf index 4c299853..0c4719ab 100644 --- a/modules/local/count_matrix/combined/main.nf +++ b/modules/local/count_matrix/combined/main.nf @@ -31,9 +31,7 @@ process COUNTS_COMBINED { "${task.process}": awk: \$(awk --version | head -n 1 | cut -d' ' -f3 | sed 's/,//g') r-base: \$(echo \$(R --version 2>&1) | sed 's/^.*R version //; s/ .*\$//') - argparser: \$(Rscript -e "library(arparser); cat(as.character(packageVersion('argparser')))") dplyr: \$(Rscript -e "library(dplyr); cat(as.character(packageVersion('dplyr')))") - python: \$(python --version | sed -e 's/Python //g') END_VERSIONS """ } From bcfb46ebc1ba876f61302b4dada3bef3d3cf5a47 Mon Sep 17 00:00:00 2001 From: nictru Date: Tue, 31 Oct 2023 14:49:53 +0100 Subject: [PATCH 095/491] Recycle general STAR run for DCC --- subworkflows/local/circrna_discovery.nf | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 2949f9c0..8501cffb 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -154,10 +154,6 @@ workflow CIRCRNA_DISCOVERY { // DCC WORKFLOW // - DCC_1ST_PASS( reads, star_index, gtf_tuple, star_ignore_sjdbgtf, seq_platform, seq_center ) - DCC_SJDB( DCC_1ST_PASS.out.tab.map{ meta, tab -> return tab }.collect().map{[[id: "dcc_sjdb"], it]}, bsj_reads ) - DCC_2ND_PASS( reads, star_index, DCC_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) - mate1 = reads.filter{ meta, reads -> !meta.single_end }.map{ meta, reads -> return [ [id: meta.id, single_end: true], reads[0] ] } DCC_MATE1_1ST_PASS( mate1, star_index, gtf_tuple, star_ignore_sjdbgtf, seq_platform, seq_center ) DCC_MATE1_SJDB( DCC_MATE1_1ST_PASS.out.tab.map{ meta, tab -> return tab }.collect().map{[[id: "mate1_sjdb"], it]}, bsj_reads ) @@ -168,7 +164,7 @@ workflow CIRCRNA_DISCOVERY { DCC_MATE2_SJDB( DCC_MATE2_1ST_PASS.out.tab.map{ meta, tab -> return tab }.collect().map{[[id: "mate2_sjdb"], it]}, bsj_reads ) DCC_MATE2_2ND_PASS( mate2, star_index, DCC_MATE2_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) - dcc_stage = DCC_2ND_PASS.out.junction.map{ meta, junction -> return [ meta.id, meta, junction]} + dcc_stage = STAR_2ND_PASS.out.junction.map{ meta, junction -> return [ meta.id, meta, junction]} .join( DCC_MATE1_2ND_PASS.out.junction.map{ meta, junction -> return [ meta.id, junction] }, remainder: true From eecedfd202450fcfc31b02983c15bfa51326890e Mon Sep 17 00:00:00 2001 From: nictru Date: Tue, 5 Dec 2023 09:57:46 +0100 Subject: [PATCH 096/491] Remove unnecessary input naming --- modules/local/fasta/main.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/local/fasta/main.nf b/modules/local/fasta/main.nf index aff89fde..086fd61a 100644 --- a/modules/local/fasta/main.nf +++ b/modules/local/fasta/main.nf @@ -8,8 +8,8 @@ process FASTA { 'quay.io/biocontainers/bedtools:2.30.0--h7d7f7ad_2' }" input: - tuple val(meta), path(bed, name: "bed.input") - path fasta, name: "fasta.input" + tuple val(meta), path(bed) + path fasta output: tuple val(meta), path("${prefix}.fa"), emit: analysis_fasta @@ -24,7 +24,7 @@ process FASTA { prefix = task.ext.prefix ?: "${meta.id}" """ ## FASTA sequences (bedtools does not like the extra annotation info - split will not work properly) - cut -d\$'\\t' -f1-12 bed.input > bed12.tmp + cut -d\$'\\t' -f1-12 $bed > bed12.tmp bedtools getfasta -fi $fasta -bed bed12.tmp -s -split -name > circ_seq.tmp ## clean fasta header From f38dd944bb577a4cbb2702941f424182e5bb6c66 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 13 Jan 2024 17:45:22 +0100 Subject: [PATCH 097/491] Unify test config --- .github/workflows/ci.yml | 2 +- conf/test.config | 20 ++++++++++---------- conf/test_cache.config | 34 ---------------------------------- nextflow.config | 5 +++-- 4 files changed, 14 insertions(+), 47 deletions(-) delete mode 100644 conf/test_cache.config diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82c8f42a..79f1ee44 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,4 +67,4 @@ jobs: - name: Run pipeline with test data run: | - nextflow run ${GITHUB_WORKSPACE} -profile test_cache,docker --outdir ./results --test_data_base ${{ github.workspace }}/test-datasets + nextflow run ${GITHUB_WORKSPACE} -profile test,docker --outdir ./results --test_data_base ${{ github.workspace }}/test-datasets diff --git a/conf/test.config b/conf/test.config index f8694df1..c0444832 100644 --- a/conf/test.config +++ b/conf/test.config @@ -19,16 +19,16 @@ params { max_memory = 6.GB max_time = 6.h - // Input data for test data - input = 'https://raw.githubusercontent.com/nf-core/test-datasets/circrna/samples.csv' - fasta = 'https://raw.githubusercontent.com/nf-core/test-datasets/circrna/reference/chrI.fa' - gtf = 'https://raw.githubusercontent.com/nf-core/test-datasets/circrna/reference/chrI.gtf' - mature = 'https://raw.githubusercontent.com/nf-core/test-datasets/circrna/reference/mature.fa' - species = 'cel' - tool = 'circexplorer2' - phenotype = 'https://raw.githubusercontent.com/nf-core/test-datasets/circrna/phenotype.csv' + // Test input data + input = "${params.test_data_base}/samples.csv" + fasta = "${params.test_data_base}/reference/chrI.fa" + gtf = "${params.test_data_base}/reference/chrI.gtf" + mature = "${params.test_data_base}/reference/mature.fa" + tool = "circexplorer2" + phenotype = "${params.test_data_base}/phenotype.csv" skip_trimming = false - module = 'circrna_discovery,mirna_prediction,differential_expression' - outdir = 'results/' + module = "circrna_discovery,mirna_prediction,differential_expression" + outdir = "results/" bsj_reads = 2 + species = "cel" } diff --git a/conf/test_cache.config b/conf/test_cache.config deleted file mode 100644 index c0444832..00000000 --- a/conf/test_cache.config +++ /dev/null @@ -1,34 +0,0 @@ -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Nextflow config file for running minimal tests -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Defines input files and everything required to run a fast and simple pipeline test. - - Use as follows: - nextflow run nf-core/circrna -profile test, --outdir - ----------------------------------------------------------------------------------------- -*/ - -params { - config_profile_name = 'Test profile' - config_profile_description = 'Minimal test dataset to check pipeline function' - - // Limit resources so that this can run on GitHub Actions - max_cpus = 2 - max_memory = 6.GB - max_time = 6.h - - // Test input data - input = "${params.test_data_base}/samples.csv" - fasta = "${params.test_data_base}/reference/chrI.fa" - gtf = "${params.test_data_base}/reference/chrI.gtf" - mature = "${params.test_data_base}/reference/mature.fa" - tool = "circexplorer2" - phenotype = "${params.test_data_base}/phenotype.csv" - skip_trimming = false - module = "circrna_discovery,mirna_prediction,differential_expression" - outdir = "results/" - bsj_reads = 2 - species = "cel" -} diff --git a/nextflow.config b/nextflow.config index 0b995eda..26d79e5c 100644 --- a/nextflow.config +++ b/nextflow.config @@ -94,10 +94,12 @@ params { max_cpus = 50 max_time = '240.h' + test_data_base = 'https://raw.githubusercontent.com/nf-core/test-datasets/circrna' + // Schema validation default options validationFailUnrecognisedParams = false validationLenientMode = false - validationSchemaIgnoreParams = 'genomes,igenomes_base' + validationSchemaIgnoreParams = 'genomes,igenomes_base,test_data_base' validationShowHiddenParams = false validate_params = true } @@ -211,7 +213,6 @@ profiles { executor.memory = 8.GB } test { includeConfig 'conf/test.config' } - test_cache { includeConfig 'conf/test_cache.config' } test_igenomes { includeConfig 'conf/test_igenomes.config' } full { includeConfig 'conf/full.config' } test_full { includeConfig 'conf/test_full.config' } From 2f08d15ed151c18c6e4ae14b11201e84849d608f Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:13:53 +0100 Subject: [PATCH 098/491] add missing defaults to documentation --- README.md | 8 +++----- docs/usage.md | 20 ++++++++------------ nextflow_schema.json | 27 ++++++++++++++++++--------- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index f59c42c0..fefe74a4 100644 --- a/README.md +++ b/README.md @@ -76,11 +76,9 @@ nextflow run nf-core/circrna \ --outdir ``` -:::warning -Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those -provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; -see [docs](https://nf-co.re/usage/configuration#custom-configuration-files). -::: +> [!WARNING] +> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; +> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files). For more details and further functionality, please refer to the [usage documentation](https://nf-co.re/circrna/usage) and the [parameter documentation](https://nf-co.re/circrna/parameters). diff --git a/docs/usage.md b/docs/usage.md index 2f9684a0..b7b18c5c 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -29,9 +29,8 @@ If you wish to repeatedly use the same parameters for multiple runs, rather than Pipeline settings can be provided in a `yaml` or `json` file via `-params-file `. -:::warning -Do not use `-c ` to specify parameters as this will result in errors. Custom config files specified with `-c` must only be used for [tuning process resource specifications](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources), other infrastructural tweaks (such as output directories), or module arguments (args). -::: +> [!WARNING] +> Do not use `-c ` to specify parameters as this will result in errors. Custom config files specified with `-c` must only be used for [tuning process resource specifications](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources), other infrastructural tweaks (such as output directories), or module arguments (args). The above pipeline run specified with a params file in yaml format: @@ -70,9 +69,8 @@ This version number will be logged in reports when you run the pipeline, so that To further assist in reproducbility, you can use share and re-use [parameter files](#running-the-pipeline) to repeat pipeline runs with the same settings without having to write out a command with every single parameter. -:::tip -If you wish to share such profile (such as upload as supplementary material for academic publications), make sure to NOT include cluster specific paths to files, nor institutional specific profiles. -::: +> [!TIP] +> If you wish to share such profile (such as upload as supplementary material for academic publications), make sure to NOT include cluster specific paths to files, nor institutional specific profiles. # Input specifications @@ -250,9 +248,8 @@ To view the outputs of the module, please see the output [documentation](https:/ ## Core Nextflow arguments -:::note -These options are part of Nextflow and use a _single_ hyphen (pipeline parameters use a double-hyphen). -::: +> [!NOTE] +> These options are part of Nextflow and use a _single_ hyphen (pipeline parameters use a double-hyphen). ### `-profile` @@ -260,9 +257,8 @@ Use this parameter to choose a configuration profile. Profiles can give configur Several generic profiles are bundled with the pipeline which instruct the pipeline to use software packaged using different methods (Docker, Singularity, Podman, Shifter, Charliecloud, Apptainer, Conda) - see below. -:::info -We highly recommend the use of Docker or Singularity containers for full pipeline reproducibility, however when this is not possible, Conda is also supported. -::: +> [!INFO] +> We highly recommend the use of Docker or Singularity containers for full pipeline reproducibility, however when this is not possible, Conda is also supported. The pipeline also dynamically loads configurations from [https://github.com/nf-core/configs](https://github.com/nf-core/configs) when it runs, making multiple config profiles for various institutional clusters available at run time. For more information and to see if your system is available in these configs please see the [nf-core/configs documentation](https://github.com/nf-core/configs#documentation). diff --git a/nextflow_schema.json b/nextflow_schema.json index 70ac90d7..8dc62486 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -163,7 +163,8 @@ "type": "boolean", "fa_icon": "fas fa-save", "description": "Where possible, save unaligned reads from either STAR, HISAT2 or Salmon to the results directory.", - "help_text": "This may either be in the form of FastQ or BAM files depending on the options available for that particular tool." + "help_text": "This may either be in the form of FastQ or BAM files depending on the options available for that particular tool.", + "default": false } } }, @@ -279,44 +280,52 @@ "type": "boolean", "description": "Skip the adapter trimming step.", "help_text": "Use this if your input FastQ files have already been trimmed outside of the workflow or if you're very confident that there is no adapter contamination in your data.", - "fa_icon": "fas fa-fast-forward" + "fa_icon": "fas fa-fast-forward", + "default": false }, "save_trimmed": { "type": "boolean", "description": "Save the trimmed FastQ files in the results directory.", "help_text": "By default, trimmed FastQ files will not be saved to the results directory. Specify this flag (or set to true in your config file) to copy these files to the results directory when complete.", - "fa_icon": "fas fa-save" + "fa_icon": "fas fa-save", + "default": false }, "skip_fastqc": { "type": "boolean", "description": "Skip FastQC quality control of the sequencing reads.", - "fa_icon": "fas fa-terminal" + "fa_icon": "fas fa-terminal", + "default": false }, "clip_r1": { "type": "integer", "description": "Instructs Trim Galore to remove bp from the 5' end of read 1 (or single-end reads).", - "fa_icon": "fas fa-cut" + "fa_icon": "fas fa-cut", + "default": null }, "clip_r2": { "type": "integer", "description": "Instructs Trim Galore to remove bp from the 5' end of read 2 (paired-end reads only).", - "fa_icon": "fas fa-cut" + "fa_icon": "fas fa-cut", + "default": null }, "three_prime_clip_r1": { "type": "integer", "description": "Instructs Trim Galore to remove bp from the 3' end of read 1 AFTER adapter/quality trimming has been performed.", - "fa_icon": "fas fa-cut" + "fa_icon": "fas fa-cut", + "default": null }, "three_prime_clip_r2": { "type": "integer", "description": "Instructs Trim Galore to remove bp from the 3' end of read 2 AFTER adapter/quality trimming has been performed.", - "fa_icon": "fas fa-cut" + "fa_icon": "fas fa-cut", + "default": null }, "trim_nextseq": { "type": "integer", "description": "Instructs Trim Galore to apply the --nextseq=X option, to trim based on quality after removing poly-G tails.", "help_text": "This enables the option Cutadapt `--nextseq-trim=3'CUTOFF` option via Trim Galore, which will set a quality cutoff (that is normally given with -q instead), but qualities of G bases are ignored. This trimming is in common for the NextSeq- and NovaSeq-platforms, where basecalls without any signal are called as high-quality G bases.", - "fa_icon": "fas fa-cut" + "fa_icon": "fas fa-cut", + "default": null }, "min_trimmed_reads": { "type": "integer", From 87b10267276bcc754121257b6d1a093c73b392a7 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:04:35 +0100 Subject: [PATCH 099/491] fix wrong default params (null for int) and prettier --- .devcontainer/devcontainer.json | 8 ++++---- nextflow_schema.json | 15 +++++---------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 4ecfbfe3..4a9bc5c7 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -18,11 +18,11 @@ "python.linting.flake8Path": "/opt/conda/bin/flake8", "python.linting.pycodestylePath": "/opt/conda/bin/pycodestyle", "python.linting.pydocstylePath": "/opt/conda/bin/pydocstyle", - "python.linting.pylintPath": "/opt/conda/bin/pylint" + "python.linting.pylintPath": "/opt/conda/bin/pylint", }, // Add the IDs of extensions you want installed when the container is created. - "extensions": ["ms-python.python", "ms-python.vscode-pylance", "nf-core.nf-core-extensionpack"] - } - } + "extensions": ["ms-python.python", "ms-python.vscode-pylance", "nf-core.nf-core-extensionpack"], + }, + }, } diff --git a/nextflow_schema.json b/nextflow_schema.json index 8dc62486..71fb9ef2 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -299,33 +299,28 @@ "clip_r1": { "type": "integer", "description": "Instructs Trim Galore to remove bp from the 5' end of read 1 (or single-end reads).", - "fa_icon": "fas fa-cut", - "default": null + "fa_icon": "fas fa-cut" }, "clip_r2": { "type": "integer", "description": "Instructs Trim Galore to remove bp from the 5' end of read 2 (paired-end reads only).", - "fa_icon": "fas fa-cut", - "default": null + "fa_icon": "fas fa-cut" }, "three_prime_clip_r1": { "type": "integer", "description": "Instructs Trim Galore to remove bp from the 3' end of read 1 AFTER adapter/quality trimming has been performed.", - "fa_icon": "fas fa-cut", - "default": null + "fa_icon": "fas fa-cut" }, "three_prime_clip_r2": { "type": "integer", "description": "Instructs Trim Galore to remove bp from the 3' end of read 2 AFTER adapter/quality trimming has been performed.", - "fa_icon": "fas fa-cut", - "default": null + "fa_icon": "fas fa-cut" }, "trim_nextseq": { "type": "integer", "description": "Instructs Trim Galore to apply the --nextseq=X option, to trim based on quality after removing poly-G tails.", "help_text": "This enables the option Cutadapt `--nextseq-trim=3'CUTOFF` option via Trim Galore, which will set a quality cutoff (that is normally given with -q instead), but qualities of G bases are ignored. This trimming is in common for the NextSeq- and NovaSeq-platforms, where basecalls without any signal are called as high-quality G bases.", - "fa_icon": "fas fa-cut", - "default": null + "fa_icon": "fas fa-cut" }, "min_trimmed_reads": { "type": "integer", From cf629aea1e6c02092bd6460e6a92a98d7fffc204 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sun, 28 Jan 2024 21:45:27 +0100 Subject: [PATCH 100/491] Fix problems with backsplice_gen.sh script in fasta extraction --- modules/local/fasta/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/fasta/main.nf b/modules/local/fasta/main.nf index 086fd61a..63381c1b 100644 --- a/modules/local/fasta/main.nf +++ b/modules/local/fasta/main.nf @@ -9,7 +9,7 @@ process FASTA { input: tuple val(meta), path(bed) - path fasta + path(fasta, stageAs: 'fasta.input') // TODO: Remove input renaming, currently necessary to prevent problems with the backsplice_gen.sh script output: tuple val(meta), path("${prefix}.fa"), emit: analysis_fasta From b0214b71f454682dd6eaed739bbfd93162aec279 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Mon, 29 Jan 2024 14:49:58 +0000 Subject: [PATCH 101/491] Template update for nf-core/tools version 2.12 --- .editorconfig | 8 + .github/workflows/awsfulltest.yml | 2 +- .github/workflows/awstest.yml | 2 +- .github/workflows/branch.yml | 2 +- .github/workflows/clean-up.yml | 2 +- .github/workflows/download_pipeline.yml | 67 +++++ .github/workflows/fix-linting.yml | 72 +++-- .github/workflows/linting.yml | 61 +--- .github/workflows/linting_comment.yml | 2 +- .github/workflows/release-announcements.yml | 4 +- .gitpod.yml | 1 + .pre-commit-config.yaml | 7 +- README.md | 8 +- assets/email_template.html | 2 +- assets/email_template.txt | 2 +- assets/nf-core-circrna_logo_light.png | Bin 64214 -> 67279 bytes docs/images/nf-core-circrna_logo_dark.png | Bin 64294 -> 25192 bytes docs/images/nf-core-circrna_logo_light.png | Bin 64214 -> 21840 bytes lib/WorkflowMain.groovy | 16 +- lib/nfcore_external_java_deps.jar | Bin 2291171 -> 0 bytes main.nf | 2 +- modules.json | 6 +- .../dumpsoftwareversions/environment.yml | 2 +- .../custom/dumpsoftwareversions/main.nf | 4 +- .../dumpsoftwareversions/tests/main.nf.test | 7 +- .../tests/main.nf.test.snap | 50 ++-- modules/nf-core/fastqc/tests/main.nf.test | 265 ++++++++++++------ .../nf-core/fastqc/tests/main.nf.test.snap | 12 +- modules/nf-core/multiqc/environment.yml | 2 +- modules/nf-core/multiqc/main.nf | 6 +- modules/nf-core/multiqc/meta.yml | 1 - modules/nf-core/multiqc/tests/main.nf.test | 48 +++- .../nf-core/multiqc/tests/main.nf.test.snap | 21 ++ nextflow.config | 3 +- pyproject.toml | 17 +- workflows/circrna.nf | 7 + 36 files changed, 490 insertions(+), 221 deletions(-) create mode 100644 .github/workflows/download_pipeline.yml delete mode 100644 lib/nfcore_external_java_deps.jar create mode 100644 modules/nf-core/multiqc/tests/main.nf.test.snap diff --git a/.editorconfig b/.editorconfig index b6b31907..9b990088 100644 --- a/.editorconfig +++ b/.editorconfig @@ -22,3 +22,11 @@ indent_size = unset [/assets/email*] indent_size = unset + +# ignore Readme +[README.md] +indent_style = unset + +# ignore python +[*.{py}] +indent_style = unset diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 552540b6..7b6bd16d 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -31,7 +31,7 @@ jobs: } profiles: test_full - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: Tower debug log file path: | diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index 75cde376..9590dcae 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -25,7 +25,7 @@ jobs: } profiles: test - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: Tower debug log file path: | diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 343d881e..a9339b73 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -19,7 +19,7 @@ jobs: # NOTE - this doesn't currently work if the PR is coming from a fork, due to limitations in GitHub actions secrets - name: Post PR comment if: failure() - uses: mshick/add-pr-comment@v1 + uses: mshick/add-pr-comment@v2 with: message: | ## This PR is against the `master` branch :x: diff --git a/.github/workflows/clean-up.yml b/.github/workflows/clean-up.yml index 694e90ec..e37cfda5 100644 --- a/.github/workflows/clean-up.yml +++ b/.github/workflows/clean-up.yml @@ -10,7 +10,7 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/stale@v7 + - uses: actions/stale@v9 with: stale-issue-message: "This issue has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor. Remove stale label or add a comment otherwise this issue will be closed in 20 days." stale-pr-message: "This PR has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor. Remove stale label or add a comment if it is still useful." diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml new file mode 100644 index 00000000..8611458a --- /dev/null +++ b/.github/workflows/download_pipeline.yml @@ -0,0 +1,67 @@ +name: Test successful pipeline download with 'nf-core download' + +# Run the workflow when: +# - dispatched manually +# - when a PR is opened or reopened to master branch +# - the head branch of the pull request is updated, i.e. if fixes for a release are pushed last minute to dev. +on: + workflow_dispatch: + pull_request: + types: + - opened + branches: + - master + pull_request_target: + branches: + - master + +env: + NXF_ANSI_LOG: false + +jobs: + download: + runs-on: ubuntu-latest + steps: + - name: Install Nextflow + uses: nf-core/setup-nextflow@v1 + + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + architecture: "x64" + - uses: eWaterCycle/setup-singularity@v7 + with: + singularity-version: 3.8.3 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install git+https://github.com/nf-core/tools.git@dev + + - name: Get the repository name and current branch set as environment variable + run: | + echo "REPO_LOWERCASE=${GITHUB_REPOSITORY,,}" >> ${GITHUB_ENV} + echo "REPOTITLE_LOWERCASE=$(basename ${GITHUB_REPOSITORY,,})" >> ${GITHUB_ENV} + echo "REPO_BRANCH=${GITHUB_REF#refs/heads/}" >> ${GITHUB_ENV} + + - name: Download the pipeline + env: + NXF_SINGULARITY_CACHEDIR: ./ + run: | + nf-core download ${{ env.REPO_LOWERCASE }} \ + --revision ${{ env.REPO_BRANCH }} \ + --outdir ./${{ env.REPOTITLE_LOWERCASE }} \ + --compress "none" \ + --container-system 'singularity' \ + --container-library "quay.io" -l "docker.io" -l "ghcr.io" \ + --container-cache-utilisation 'amend' \ + --download-configuration + + - name: Inspect download + run: tree ./${{ env.REPOTITLE_LOWERCASE }} + + - name: Run the downloaded pipeline + env: + NXF_SINGULARITY_CACHEDIR: ./ + NXF_SINGULARITY_HOME_MOUNT: true + run: nextflow run ./${{ env.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ env.REPO_BRANCH }}) -stub -profile test,singularity --outdir ./results diff --git a/.github/workflows/fix-linting.yml b/.github/workflows/fix-linting.yml index 7e6550db..505d843c 100644 --- a/.github/workflows/fix-linting.yml +++ b/.github/workflows/fix-linting.yml @@ -4,7 +4,7 @@ on: types: [created] jobs: - deploy: + fix-linting: # Only run if comment is on a PR with the main repo, and if it contains the magic keywords if: > contains(github.event.comment.html_url, '/pull/') && @@ -13,10 +13,17 @@ jobs: runs-on: ubuntu-latest steps: # Use the @nf-core-bot token to check out so we can push later - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 with: token: ${{ secrets.nf_core_bot_auth_token }} + # indication that the linting is being fixed + - name: React on comment + uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 + with: + comment-id: ${{ github.event.comment.id }} + reactions: eyes + # Action runs on the issue comment, so we don't get the PR by default # Use the gh cli to check out the PR - name: Checkout Pull Request @@ -24,32 +31,59 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.nf_core_bot_auth_token }} - - uses: actions/setup-node@v4 + # Install and run pre-commit + - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 + with: + python-version: 3.11 - - name: Install Prettier - run: npm install -g prettier @prettier/plugin-php + - name: Install pre-commit + run: pip install pre-commit - # Check that we actually need to fix something - - name: Run 'prettier --check' - id: prettier_status - run: | - if prettier --check ${GITHUB_WORKSPACE}; then - echo "result=pass" >> $GITHUB_OUTPUT - else - echo "result=fail" >> $GITHUB_OUTPUT - fi + - name: Run pre-commit + id: pre-commit + run: pre-commit run --all-files + continue-on-error: true - - name: Run 'prettier --write' - if: steps.prettier_status.outputs.result == 'fail' - run: prettier --write ${GITHUB_WORKSPACE} + # indication that the linting has finished + - name: react if linting finished succesfully + if: steps.pre-commit.outcome == 'success' + uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 + with: + comment-id: ${{ github.event.comment.id }} + reactions: "+1" - name: Commit & push changes - if: steps.prettier_status.outputs.result == 'fail' + id: commit-and-push + if: steps.pre-commit.outcome == 'failure' run: | git config user.email "core@nf-co.re" git config user.name "nf-core-bot" git config push.default upstream git add . git status - git commit -m "[automated] Fix linting with Prettier" + git commit -m "[automated] Fix code linting" git push + + - name: react if linting errors were fixed + id: react-if-fixed + if: steps.commit-and-push.outcome == 'success' + uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 + with: + comment-id: ${{ github.event.comment.id }} + reactions: hooray + + - name: react if linting errors were not fixed + if: steps.commit-and-push.outcome == 'failure' + uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 + with: + comment-id: ${{ github.event.comment.id }} + reactions: confused + + - name: react if linting errors were not fixed + if: steps.commit-and-push.outcome == 'failure' + uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 + with: + issue-number: ${{ github.event.issue.number }} + body: | + @${{ github.actor }} I tried to fix the linting errors, but it didn't work. Please fix them manually. + See [CI log](https://github.com/nf-core/circrna/actions/runs/${{ github.run_id }}) for more details. diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 905c58e4..81cd098e 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -11,61 +11,22 @@ on: types: [published] jobs: - EditorConfig: + pre-commit: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - - - name: Install editorconfig-checker - run: npm install -g editorconfig-checker - - - name: Run ECLint check - run: editorconfig-checker -exclude README.md $(find .* -type f | grep -v '.git\|.py\|.md\|json\|yml\|yaml\|html\|css\|work\|.nextflow\|build\|nf_core.egg-info\|log.txt\|Makefile') - - Prettier: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - - - name: Install Prettier - run: npm install -g prettier - - - name: Run Prettier --check - run: prettier --check ${GITHUB_WORKSPACE} - - PythonBlack: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Check code lints with Black - uses: psf/black@stable - - # If the above check failed, post a comment on the PR explaining the failure - - name: Post PR comment - if: failure() - uses: mshick/add-pr-comment@v1 + - name: Set up Python 3.11 + uses: actions/setup-python@v5 with: - message: | - ## Python linting (`black`) is failing - - To keep the code consistent with lots of contributors, we run automated code consistency checks. - To fix this CI test, please run: - - * Install [`black`](https://black.readthedocs.io/en/stable/): `pip install black` - * Fix formatting errors in your pipeline: `black .` - - Once you push these changes the test should pass, and you can hide this comment :+1: + python-version: 3.11 + cache: "pip" - We highly recommend setting up Black in your code editor so that this formatting is done automatically on save. Ask about it on Slack for help! + - name: Install pre-commit + run: pip install pre-commit - Thanks again for your contribution! - repo-token: ${{ secrets.GITHUB_TOKEN }} - allow-repeats: false + - name: Run pre-commit + run: pre-commit run --all-files nf-core: runs-on: ubuntu-latest @@ -76,7 +37,7 @@ jobs: - name: Install Nextflow uses: nf-core/setup-nextflow@v1 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: "3.11" architecture: "x64" @@ -99,7 +60,7 @@ jobs: - name: Upload linting log file artifact if: ${{ always() }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: linting-logs path: | diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index 0bbcd30f..147bcd10 100644 --- a/.github/workflows/linting_comment.yml +++ b/.github/workflows/linting_comment.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download lint results - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: workflow: linting.yml workflow_conclusion: completed diff --git a/.github/workflows/release-announcements.yml b/.github/workflows/release-announcements.yml index 6ad33927..21ac3f06 100644 --- a/.github/workflows/release-announcements.yml +++ b/.github/workflows/release-announcements.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: "3.10" - name: Install dependencies @@ -56,7 +56,7 @@ jobs: bsky-post: runs-on: ubuntu-latest steps: - - uses: zentered/bluesky-post-action@v0.0.2 + - uses: zentered/bluesky-post-action@v0.1.0 with: post: | Pipeline release! ${{ github.repository }} v${{ github.event.release.tag_name }} - ${{ github.event.release.name }}! diff --git a/.gitpod.yml b/.gitpod.yml index acf72695..363d5b1d 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -7,6 +7,7 @@ tasks: - name: unset JAVA_TOOL_OPTIONS command: | unset JAVA_TOOL_OPTIONS + vscode: extensions: # based on nf-core.nf-core-extensionpack - codezombiech.gitignore # Language support for .gitignore files diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0c31cdb9..af57081f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,10 @@ repos: - repo: https://github.com/pre-commit/mirrors-prettier - rev: "v2.7.1" + rev: "v3.1.0" hooks: - id: prettier + - repo: https://github.com/editorconfig-checker/editorconfig-checker.python + rev: "2.7.3" + hooks: + - id: editorconfig-checker + alias: ec diff --git a/README.md b/README.md index ba556c75..496a65ac 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ -# ![nf-core/circrna](docs/images/nf-core-circrna_logo_light.png#gh-light-mode-only) ![nf-core/circrna](docs/images/nf-core-circrna_logo_dark.png#gh-dark-mode-only) - +

    + + + nf-core/circrna + +

    [![GitHub Actions CI Status](https://github.com/nf-core/circrna/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/circrna/actions?query=workflow%3A%22nf-core+CI%22) [![GitHub Actions Linting Status](https://github.com/nf-core/circrna/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/circrna/actions?query=workflow%3A%22nf-core+linting%22)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/circrna/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) diff --git a/assets/email_template.html b/assets/email_template.html index 03b6ba6e..ddd62126 100644 --- a/assets/email_template.html +++ b/assets/email_template.html @@ -12,7 +12,7 @@ -

    nf-core/circrna v${version}

    +

    nf-core/circrna ${version}

    Run Name: $runName

    <% if (!success){ diff --git a/assets/email_template.txt b/assets/email_template.txt index 65572a8f..927b5b6a 100644 --- a/assets/email_template.txt +++ b/assets/email_template.txt @@ -4,7 +4,7 @@ |\\ | |__ __ / ` / \\ |__) |__ } { | \\| | \\__, \\__/ | \\ |___ \\`-._,-`-, `._,._,' - nf-core/circrna v${version} + nf-core/circrna ${version} ---------------------------------------------------- Run Name: $runName diff --git a/assets/nf-core-circrna_logo_light.png b/assets/nf-core-circrna_logo_light.png index d3cd49c1fffb4c615ab9d6e96f131be71830d2b2..85a200b325d8ef5ec381b5863b8300262d646720 100644 GIT binary patch literal 67279 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 literal 64214 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�ev`Q}H7y#R1zKkC5n?0_OP7^FqWWeXhX0t0pNK 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

    )bNtXB<>| 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

    V0GI8SHG1^dh_*}1*QM#w2kyE^nW%>`QZD7q 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 Q)8RG*JHk(BI-FkqACU4o?*IS* diff --git a/docs/images/nf-core-circrna_logo_dark.png b/docs/images/nf-core-circrna_logo_dark.png index 6af6190079f10f0f53b89ae796a04d50a72bd664..b48e7b08c6faa330c043d93a106076880d4157c8 100644 GIT binary patch literal 25192 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

    (}N~EkT z_hBB}&{~IJR z_L2isfFUbIJzd__32lm^QeHvZARp3(p)Ns{fo3&mMOU`itCjnmxqW!Uu^sel|JOaG dZds4a70Jj536`h=|3L!6pSg%DH*vZBe*hyUOU(cP literal 64294 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%0D6Aha9ZZvy3Owj0R@{kHIA1_W(q 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 diff --git a/docs/images/nf-core-circrna_logo_light.png b/docs/images/nf-core-circrna_logo_light.png index d3cd49c1fffb4c615ab9d6e96f131be71830d2b2..611d5449ba941306c58ea81f5a3ac26ab47a5c81 100644 GIT binary patch literal 21840 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

    hsG=h|z|>dQ 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�ev`Q}H7y#R1zKkC5n?0_OP7^FqWWeXhX0t0pNK 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

    )bNtXB<>| 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

    A$B3k~{RycObG@6y| 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 $@vz03z8Z`qI{ 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

    =%>>2|D73@_9Fx}<*!s;{SFX;r+XReUC zs(|mEkHHq9IX6^vM^EgXIeYohiI?hV>^hwxYR>KuRb@}z5I-ASzTYk3_~FS}RNjRL zBd*dzvW_1pe2RefXtrAi)Sg*@9Jknu z$o8-Te9~-C48q7aAXk0lTYyLPSq7kgBw^!nZU+R0_nf_OedZnHyrlT|3Uy@d6(W|C znHTk!>h~;8ca-b(8S8i^YnxhdJ9ZBN?AFMLYi2sdMg10nS)a)E>s*<)nG(xjqj-|) zADeL|%!nJN7z;c%R6Jyv;ke4y^e=Ege88b$E>s+UBVuvoH&<#VpjT@xLyu^Kuy z#4zgUiihw^Yf@aV+#?zu85^R}j%9h(v(QGX(`p%;CD`^ED=1X4BSy)iHwp}VI;x#koUS#@Yl;}RE}cMZ{Qar!6y>5A4=2Qqrpd0kgTDpz zs-l^R9_DF00+*ht{4w=X^yW!0O_16+Rk)g|yOQvWsgXP!u4u~6Kd!H?uWmC^k|Qle0OU{F|S@kW-Rp5($CYRsw!GkE>w zmdC5ybrX@hWKa&*n&(H+hnJ{Dr?v;L9?0Sz*Jk!&irG!A&KuZY?B4|~MZ(0&>f3gN zVj611$*;HaKQ`D{0vE$Ka>X+U#w#8c2_BwPySAW#nI5b}oP6rd!oVSWQ14I27@=gX zjIZFP6zBMpdHL&@SqY|qIRIp!Pzp^(A4}!{jq)e2ZC%224dY7MQ1$Yr-kNw~*Dhe6 z`@q|8ll6EmPIpu}oIIwO9E^Eo+b5|JWJCL`t-3MB?@ppyrX7T9f%L?Ubce)?eEUd3 zN7@I4%kx1mozwr7SZz1xBjrJ*b0dhxflwGYE&9Z2QUG2Au^qa_cu>nBBTD^nC^0s8 zE^Vx7e~8s63|)bLJt!0!(q45t6cd=kZUK{KtIpS0KYMT~J6>*?Saq!z*L$gb*Ue`3 z1DN-`j`&7v#>}vFdCI|l4H<=x>__reJtQU#l58T}OX3xC)57p`^xN5PiHcS&fTq1| zpmiAfny@uxcWaYHG>ZOD-z)z*jFc}&_jS_{d5iLOlap`rbwSm8TZhNuvI2T#hiGPw zPT}}LVM`2=N?Yiead(NRA@USLn&2&UNFJ4FE4H!hpIymK5)^h@A%Xy&@61=iYv6Ki zj|jI;b6|I<@*4=&A1>XX)u9POP19j_UqIhVLMo#JlQ)`>47 zn*#L%6@Whz#5H?ZxB=@5>hzvUJT+V#%z^c`U^m0MVf;M4o_?>>txZS2pQe%TVJ&%< zFHz-;NeRS7%NmZpgY`1G6@V(^dE=vrHHXXpVwETu@Ptf(X{mb8q3VZ9p$E_!ilj53 z*PRxpZfFWdR@N^`8E!fG`e#h^cdkYL?mGjL9Q8jHPPqRzCQ>)n|08W{<7oC@)1f2{ zNHwh`R9;gwJZ?Nfeh7W?z@HeQse@J|B9MMYL>a#ghJ_M<@Qn6<1vHQtG+As}G%ag1 zRaXs{TWkBTGYaL~OKWIavR$25TVI_oOIMw7xNKY5Zo{O?UU%GVJA67^uU)&{ziyVq z@WTC&luOc601FI2;!cNDWK7*d=;2F-jJdzBg^}$|;P#LRF4@DxWbJR@#@TBsK>8p+ z_NEY|bKn8z8xO>vxaC&lhUbgZ2gga=1AU>KfxEwD!todnAL`Pl+`C@=KBl!{knIrA;tZM;d2zG;9tGhv7*TBpX&Y z(w;Ovb}`C~a(H2p?LRQG)8mB)MVd~kmFstdNZaDQDLsddB&2YT5q)fG&GPO!7froV z^`a~Bs5rmx=**^lf`w?sBrF-a0Dxy^_o|d|m1^`o>_?}}P-_RrZkgCx@6R5Na1EY`Ep2WN14UAvs#LX3SdgJWO?zI840Kk<)v|Z7~tYhMwsd{-$d$UzlR!Zj$ zW9r1Tli?oz;W3@C$yqsY@(3B3zf%{@;^h<9(c0)9Xr^@Q_|JQ zx(gPQh*+p{2g~B!V^=7aM@EBb-HeKxYW&rJ5lkvdaDG7ON=)l9tdTN;swNsIr`dv< zN7N-5mQRy)VYZ{tk%oWNl(DdYI+)Q^;S$SiJ7&ULxrPtW3n7 z`2?}l^wfx>VLuvna>t~(C1oK2;8oRgk!r(Z*>!Xy@=F=YSdWvDKow_QwQ<1v75i-p!qrQ*pnUc@aVuE_=?#uY*nyanD%B=exn zRx(il2sADuri2(z?3V!|!#u)3$^@YIECDbbQAd{(fL%fiZDb=D;p*BHODedUtPX>w>Uk91% zI=0Sh7q%|3;i5~ke`m59dvz?016|!o#gpk5`QO)tw*wbr7qTQuEy4X%JA4YJ?@Y~u2$~4Tglsjs8HImG)t@&?}}^=u4_+wI0voI zNh4*K_ol4Atmt+4+^D)!M`s_b6aB?OjGt_E~LZT?`RS`}s5><^}ulDA&{t%=$S zeQi>aS>2metJ`OND!1$03aejj531kHgg{jysaCvEy$c6L#Em=?Z&%{qFsSSl};g!qV((og*BbOHt`pQ^6iZNe(4*kc`9qUs#?~apBt0CR5@*j)5 zG>n(zS6$j+w4`nuxOK*CF8zl-nhK+AA5Zw@D8RVr;4kCsxAzR8j2qU0lxHI>Q7J~By@!KaBqy6h zOKI_fRV6IhWsPeWv0yaUHb@WRJ)Pfv^?^wk-ZPqWo;YRZZ)h43k#AYb#?E>E2-=D& zv(Ic+-6)Gjm~8=I&cU=)5b1pK(|dBDEKQR!es_LrK5!tbNL~DD2sb$)@JlJS9FOXW zi=Q36PtS|54j?46Kq=Jtr1CzAT}N~T*DAPXxQbZJ_B=WbLO4=u_0f&R(FDUXjx>Yq zp1k8M`wJQ9#jq7(JKrL+zF#UC*9K&3RKzihO)%pKYi)<6T!xv4WZ*#65;EbYFtuch z{RxNou7{+b&4T83k`qOdL$R4GjcyZ6`{<9E==KM)$|d4^G`_x$xtVNUZJuT+(>f8O zPul#+G|U)US$G&s>RSsUWk;3?iberO{;)9q<3|Zm*x(qr6Q(_Elm;)6h5|>u*YZob;y-_uy3u2q>%l z)e_ylM3{uEuub#j&PW2AsQy`bD~?Ap25$C=u$Kj%vvA95=DH-`d64gl9Lp#A=O*9O zk8pn>@C9ZnW|qne#3J3l^tfG0}v4;HOxn zTUsq=X_nFyrwq=OnwbMbvO&Q~F~^A*!}Cn%V7(w*)2BQ8qbAXDs&(YPZ2b!xm*|i_ z28+mwJh?OG;^H#m>P#|%S1%}w9L2pNq~*LZXlN-?y#VA{41Z)e(V@e-B!C9R(1jka4t&I| z$a))CcYYX6jL_9UZJ|+FwZX18R!vZiNCJ^(Bu;*oZ;@;-*Sh1`e9ycT-FR0rK^Wi~*T(oE| zSPatA%C5WgWEzUJiaT9hTqx>=gtakp?HyclU#m2lx2`cYb$y~t?>Sinf|ihRJ0)3l z>I1lEkinkv=+KHDTsKhA3mN7mZGJ0|&7zR?f)Gn>Da(a~EkklWYgS^6*tZ3=RF)!+ zwu+?5y%hq@^rqG_>9t^1Q}3-E6niY zQo?eERKX&OkeOywK{6T_Ov*?jQ-!)}Gf;Qcl$jbzCo32JeT|93ntRP=u&kECPDmOQ zYHX)t8)ltbv7JkyoBRiCkxC4hrGHqXb|MW_EeFHpjFHx1cH3%q^hf8?{SP>?ZUX<# zA*B$qLlx^0>uP44&gk^d;rmayFK?K4LU*I4BvD+0W%?>UHacSiwTpQBqZ$DbL@tjIwpfRP2aH zC|fp21w7K}cZsUqES$USb)R~fqkg8dfbu9EwZ#YKs@i@SGH=7f3(*5^r3s<&92mRO zzTo}96=yYJPVddQe;m9e+aSH2I%+;F8qX!uc~;>1h7iur2SI!2{FQG{CfB=Q9~wCe z!|2C4#;Q%VB%H89{)jP)SDj_rL>j(dU}>0wFyzp$B#2bL<_gfbt72fiTE{BDMMzcUmrmg&?cCIBHH;$ne(#Ne(Hy(reAX4HcIV&MBCdZ*z*NGA1 z&Uh8BBNWLK`x+x>$t-@Z^}TpPzfmscK~9vS%@WVn7G9r~mkNPSTG{qXUtP@CkO4%15m znRE-aEOH~xRvvEwc=Kr?Ck6~-jauyV)R;tVm_5Z^nE}SETz8$&fp9;M6~rLU!5BA5RzAlfU~3r^Xga!zp=N3E zPSLUgp3m?An00A6)3>2aL+W()&6=49gs>I{5v$|2o;Gz;f|^1pk}o{W0#UvUV8lzr6K1+m8r{N-tdENLvm|l zPAB&ZbSbUA{OIn3!utkjIn;InjkaS5K!^xYAI%QEU+~4eb!qu?hOnYL_9D9aD%$3n z>h;bWfnVzyIfRHNy0wqNb_qZN1iHpsW*Y#Q1G4o2f^@tS`y6O94KIih_zf?R5jpiQ zm<^r1q3B!tCpgQxtwWM@fclVX#2%w4Rke@sp&Iqh@qPA)om$tZp$l#*p9zpVSd;ZD z#2#eZKY(XC0NM({u5HI4{?E1*(S9#?l4i-+Wh|((xa3@Vtfd0~VBtrxUi8gE(R@F< z)5hf^|3NH%L5==Avq|)D>pReQrxQ_XPXDjY_i=rHoD5ZF+d!F$al$|Y&G+`{CCznJ zn>}#u94%qLL#Szg^@D0q{l+8)(6+`5Ld=;!8_p~Ap< z+5W5HQGW@&>nIUmb1|p#L{&L*&XrPJM4`~HZ2*U*E2_SlH0EB3Rlo2 zgAIykh9AWEd&b-K%ZAVw1-*5RjDN$w?ak6G==snfSV?u#h$)XNY01no7cbmK_@f9z zgXI0TVh|C(YLw=duzQJv>e5ojQmL@E==b%zoDwy}k^V(>0SCv|x8CBFB zRWtl%kUF_oQ-AG^7#zs+dQ6(CrzTRYDkcdz=J*ug!Gg~W=;4K>r5->7qr+pXB9ATuf#bTfP|PWu#69UyL$@ z5hhFg^e-+X4`F6=KoNBgB1Rmvbz@$}1O(*+U30H((k$`c!ERxOTF;zX7=;LgjZG00 zupql8!%BQFQV4NSLj!Tch>=VWfr^R%HSd#TKrM`aYR62;v+q?pu@|Z6ONi>$;&0U#<~jt0qM_av>h;tUXE<32x-O#O zDOGNx!3{NwN?)F}f2wnLyt=j7s^+^pwdPPt7J3sb;x8ZfR62?2t@$<%o+jyJ6LVXVYzQDM?Jl zV-PQe5l12Yb;Uv)NhDg;g`E`KBC@&O(YF3eKM)S(E=t~Xu%>In)%49|S)2-e2BRS8 zBM~!zP%8;7aIfqSBhOVB|wOjIepV)i6pC%xhgtYj5$}4?mKw zC!u8O_)sxo_-HAHp@|8GHWd3}8z@ji=gm|QBs>~`<>oWCU0rCba2V^^LdHPEjj#QR zm@+-NNN)fX@Kc?hC+Umsv;kEoA?_-fJ4MfFCncR3wA)-xxqr1sAw8{VCQdufV15f) zwX1$J4Pj3FQ6Aer_3XUZ5&GMx%<-1p3gj0y@S~P?rBoZFYasdI%>ZzU+;G%oJO;cx z?){{nrC}~ZIm}qO19SjW=}ys*+6A#R8(6SMJl$H3`GuVb{v;D`s}tw0;tB48quGwZ zcdRZc`nojyJ(TfrZ{}Ys@Bkp(kczU~n($Mez3-c#1kMi@06IW5s#}(Cb`ZmzAKAwc z;DYw02arYk%177Q-${Rg$8`z&ve@_87i|8^%;!}&XFE8O{vzaAPFV;cEsvsHV7q{u zzMs3o>>djT#W`l-GsQjAjzV6VNF;4fX_KM=BQaD!Ng7^EDVV502e*`{AH0O`uw@se zQ?g@W;HOX=CQOrDuU3|*Z<~y^7pu$H)5W*E-9@t*vqVliSkM5zTmSicw#LET684*i z1@^%LB*M02HV$D-5+R?iMyfJ^ZL?ev8l({IEhl2=Y=?eGquPdBl36$xArT}}Lt&^T zL5g0kHLjMzC{w_8>cS4AcJsvIp0F*DnPeedCO-^KHB(a&Ms?j_fp(xSrNpqIE+D)AP@lwGD#vWx>Ig+TZNPvo!j0y*!OWn}cSry&Vl_-nC^J2f| zj-5F|BKzvHYi52~c5+;lA3Y`|P2os826bjlK(JCd+|)%%X8_hwrMaU)xv$vi-!*@~hT zmbGu2!X064kX7$Z;Iz#ofz^X48z3(jcwWS@>W;1?_>^j#_17TYPGq``wfLhQZ)B;( zniM#U^duGMvXHyOo39uTC`iYlJ7eT39?#60IY)JRpPpXcW`)#^xNtXF9@gfljrvYjmCwZRVww8z1shs0IvF-ER#O`F zwW2aLW_Cnc7IQEBvcy4sOm~r+&KiD97@)V!&fJJn-dM^|tJj_zbk|nav)087?3G_Q*IDT(3eI zvBPZbY@U5s)SkUR&OHPlA7K)k>s2_b)1IWo9Bfm9Yr_Pi-Hc!Tpo$J!Ar1LOP{@k$*$22y|<&l$(}r|D;t zSF_-=vX~)NUXFg^6%>R^Xm6Wj_&rS=`3NT`52YpX(eNsKm>U7`3?m8CjBlM6+gu}A z@jv9`-uV#^#QD<)*_$bB!y_~tK8}3jM)M5u{#D+S>8{q?8z*-2IG@utQ=;DfSpfaS zOYs@_P7I$FtJ)%CA{a*Q46z2QBoDd^ZdCZvx#+<8kMdOsk!aG+g;14Y#YzO@LQ?fH5eq;ceMqNq8Tz`DJuPaK(+)Pzn7& zg*`@?&`o~@Uth(u8M92`(gS+BkWZ2MgNqq%kzuimV%|_4HNUPBettR-)>jruTnH|@ z&0VMgr2FR2CE!8nd5oVaxShw;_cvxAj4*ANiqE`Y^ITE#}*U*`+_}q|2fg7Te%#+Ya>0 zAMWe_3Vq1V;;FE&0n1?pfypbT9gDD@F@qno zgIa#PMk%bdk|CvebTSJoEQ?Eg0#Q^f98@^B^<#Tgb{H}&t{1K4FNmCL;?goT&xCg> z>`P~;GT^*2p5etK=3wb@j68muuAKh$(aK_HB-5>I+4Z zdr0ulO&oMnN@Z1ea7}I(3D=9{UG^B;?7LAQ|GW*1XK3zD>A2oIVUa$~Vc1hkBkbfR z3|Tvtw`#lJXP!xekYR$GwYJn-TvCisl$7J;tAj9eaW(H0=*zcRT!~-VDX)UplO|E3qFs zOKcn3hGNS5qcY6!)u}nGUWw^@F@3!&@8Z+i_ z3pLG80l*omUqMA&GmkHe?glLj{$N$OHYjB76Q(E#9E~Gj&=kFn|LXjU*`{7pGwx)6SAD|5-?$l9R3Nq}CVVf>OI;$3=?>Nmx5K?t7P3_!S7n>3vZtZdc0 z*VhQuYAdy}&rDVtHaE{q2RB=bn}ncj3XM!5qkcS8E>*_J-@spf#xmFtQ6sFU!A%PyKmiYt2< zY&KUsFSJ8f@bstb4&(NX!@_3$R=*l0TgoggHnz__l)W~wXVi>`) z(*CiI;%udiWrEm3o8K9%@uF9``WEEMr6mhLADNi7x1=1F8qCVvS*w(1@)j1W4pqGt zE1cz(9v67D)@y$i&?dnJc2@9|8PS=G<# z>M)NJN^alf!@wIQ%iRQkKMw?e-0lLo-delf60lT&=RL|srVpM?Q8GQ7O>b@o=r|Wo zt8qP9P$un zZiM=;HO8(TyW$WcVl#qp#~wVd27cqsTP!OzZ=CBm-oz2m zIPLh<|KW+;#|G)CXxE()&Xxnk_*y>Iw0%@1n4+7=l8Rd*W*n#bx^H!qL=s4(r07=W z##&x3<&If0Q{AAVQcja8W1=-xudt7hYv6*fC!z!friDET2BXA@8>i)@! z4`@TS?+JKS=ci^J&j$MC+BWdUH?RcUO3fo^B>M`=qdBJciD8wu=nwf=#}Xf{TFzp^ABQ}9!ZDH zRrBz>Lx6j^+ZpE~K`Y%!qv<3<<()wz>Zv>QY{`!-BhYq2zS2=xxggY25$IVv-(fYs zV-4ToA4=w+>()T&U~);QX4#--WWNooezU3jCId51Lpe5pmZIkVKfb;JN|J5cwrtzB zZQHhO+crDPwrzFUw#}}pE*ss|_3PYo-~0c)`|r&WBQi&3M2?X=GWObQuDRy4p`G`G zRiYGP*C^n}D4++5ZwC>l69NvR&dmPU(ej4sVOtXGI^iaJJi{@LLxf8Yc(DH#FO+8&y=@w* z2X_o7Yc>oqfg78dHeLaLZ%1UQO=8M1PV}vr9`L~-l{Z(eMUrjz%@D*TAw#w@KYiMk zh%WmF-i#JIJes4#kBy?bxzIyw{yhwLQ-WoFA@+?Thw)G!qzdr1icW8($RHi7*v(u> zceo1iwhC`=r5t9Ats;lX(06VnSvzIUQ(=5an@W0{0D@&*A@;4J=VM`K4IPWvm}B7& z$O;TyH8#wXQD_OecJYz>f>*=Y`Udf*Q{i|Zn^O8JYQ!p-3Uw3r=bM|zv#EYRa$R4W z!xztmNyi{P(N4`z2cbTnhHE5$`ee~v{7%bnL;T4xJI&;O)Ryk?{2o^Hy&-x96xxrE zv_KL{_q8ZiixPCJ;BCt|#c)d*dg2LFE)o`Zx%~NUH_D$%qTGi+8HIRvBz}L-A^H=1 zfU9;F_!ol?gM5Um783|4Mf5*m|Nq)(`QHpWvaf24levqV_umD8_|y%Rujb;2PYWnw zV=Xbdu%MtKGhm2ed@y1vIIt2h#%f1D0^kl1$6wbiUHMZAp5r@#uv!&<=`PWxq<&3#U6wqtsM5lMk^E+#-?$ zhS;_PB1WAQatSicsS?VRORYw>7aZg7)z*ByU6qsC+E=;%!DI4X)P*_(C1;* zRPXo)l2v#{?9(yE=Uv3o)I~&6!+tpqBk_=McguyxP)Crq^aCkUSk`p3zULGY*PJG+ ztDb{q*ZVMjFTdj*+_{1eL!J6fy{59Qw^*jX#gy*j$!c2%SVUPR`Ldh#Lv_Ow9oHnx zXgD#Jy;f(947H6a;!11fF8f%D4)INcmjI7WE zS|Z>F6rX*m^1NDjxIub&)9913Mvqhn=M~u8(F&jm*mZ@e50WocIrF^vR)u&a>ax zn@x-&ZP-uV`Y%?NE{2)jH?tLy@Zx@wn=Um#0m2g5YYQTKaWqUhK_NbBM`Ta7XSQl# zs*hs31p%!skgdY+;qyZ1@yi#5IN_UoVDtscWnKiB zE`5r`nf3r;@pgy|t_Be>+#2C(g(W38970)!K(NwyGlwBQ2*2 z?$4JBb~KP^#X!|=C@vApNn03EAp3!GhU_PIpy<5<)%hXi3wKY9hG+kJ*m3>AlrMNg z2=uNM-w@;wWe|lfGDll(jzN3c%I>+A4u*rm18VC>ERQ@@qgLBmj`{23^+^tDwq;?2 z+t}ZcE&WBsY_Y^dkIQ~>=_6wvZ#|R5O>(m$n(cqG{;d3@hZ`FOwY6GmGK-?zAn_X$we6={ebVCjp|GA*eR3bK$Nat{NSHj^!Xd%! zs?a#9Iy?fUYk!HD8yH(Q|v#MJO6cL z|6d{6uhF%3H2ZtX^H17R7!*Q^u%uT)(7F4P^ob&S8XdKDfCh*aBZJ<#SaWuCw3W4x zb!TDzrG}Mb4;hDJzZl^9YRSWU^_Nd8ke<*~7%FNOMGnh&m(1svtmASL94B;G zx%Hkr1Z*sm`KJ01r%O4IL|%X&h5{vmHyLOjZTS85DPvJ?1#CqxdLbMiM0`HGXNa#~ zi5QKQtv~c$lEJ3!AN7R?QsmhV85_83@AC>ouJ;t-QH81ptnw&=Bc9u0NqbW-O_DsiW!7 z)cR&2d<)hy66p_e#$rH~TP6cz!zRK$MhQlWUyHCVXgnwI_35xek(WEHt`~UQuhtl$ zVb!=Zdb3C++{b(c4-h)s-El2vWksxU^~rC2-Z;(ac|i*l6nq8kr^*}W3ikpco@VN% zHN|jc`O!#pM6rw7NM#}&5oL~z;&5jdp6>W?>7VD{?-Y3;8j)z`^1wVq375~}_l1BD z(G1~;h6tlJGKgT#r!Cs)vum*Nmg@efeJuepmgom$n3v(LxM`@7*0T3{1u*q^U5%B4 zknvyBL!ITdUdErLr79IC^wx@7*0Qf;sNvgZ_Kt$FoiBA+kRhPD;(2C9Yr3g=Qh>!p z(stFHSr~~6iB8K{f#_Jet7a=Y*4sQcb=iC?^Nf|)h+J#9cL!nymCWz2=v6TJ1}c`f z1TU%xU4e*r`;<)HX02Ohu7&#xL;?R^S&JOfUW~DmrcZw=pR#}gWlCdOCh2q6sT-$< zlTS4sg)Fh%p8Y(J_Ebl1L3vx7&et)*#zE}7%k9hGrMU!u=eFD0bcF-^=}tv{sjZqf z+x2H&Z|<%KDvxDRH*JQF9j!e@8T?dJPtca0sN53#<}fR`{u2C(7UQA&aXk5UvG>Dr zf`t!<_k_%r?c;q;>Oc~gj zNVq)~J`=AvNRW40vDLt(wxq19d3mYuN)%4{nFMSbn$m>@hBO|n(}H46P1S_jI__At zD7~c(hU2`7{Yrk#jJt3@aMhm}D5E=OyDnvK)-hCS9%|3}jE=A%3Fwr0l1{$j6@&V! z@2b}K@vvvr+mIPzm78yit0LYK1PI|o`zqdRbU)!&bQERlT#tVtt~3OVewoevQlizA zp5UpSzKv1QyC5s3!9+rsTUI-~%=9&o7GFdiZhlT`N`W<(#uvD}GSJKHoSe}#uXBl| zNz$>AW>@(cdG>-?A&J@LjHAZ-s2*uBXxr#RA|Mh8 z+b^PPe4cgrQ-%ThWU=PnI@H+E^RM>d`A14In6YeWR{-%`AQ9*WWxu3V z8bR^}B^RmxX_q5O`4E?6jdFJ$zddI>NPIlr(NcFT1&7RDa`A&3LE@&YOPS1W+e}|d zV;~U+doG_Yl?CLa|EJh12E%)pvZlgE<}C_?Wu-D(*P3rgC7wG+juM0ngyiH1WStis zql3#$v)*>HaBSi$;~;J8<@Qg~Kaoz|7|z*=uZEg@0QCH+2>&KIKCYAjWx}Vxy7#M^ zuE>_|RxE5Z7O1pjL!{p1z-Y~;db}tx7OS~};y3~*6oaR7!iPfF1O2Hb$!$Eygmiqe z(4)viWGsrfl>+{Q;uFmL8e!i>NnUX-_0YB@$?rm3`k`%8lD?4)4_#X&4o1lmnKi`k zmPVkte-pD%${{GOzFLko;QrGjO8PI8sJfcyf3bf4ubXJRioN2J5*EMb&Z-K;q1Z5R z2#JnR#Xc;Jm}rD7#1zv8QLtnB6^l$4##X|9V3L>#NHiHmfNI}sWZYe+?!bbPh+xic zj&I&+-s#C{KBFP<^nPjtG(Hc7I^QB-I0XTGiAD}Tk(o4e10jTxCXdDH&7`thYr5AQ zi>||9X4}1b8?L5{Dcy@`(rw)hpLuTn2zKu9x$D+%%6;`-7S1lSkoJNnpg-3rcMBfy z`b44mE8z8rQ`BX^rDmT!)FiH+b-39YD}jpRr|ux_1AR7D4@C$`eJuK2@IhH4 zpTYXcukDsjRaV(xOKx_b?ohGnt*u@tDpc!xxV31Sg(3B8^|`vm)25u$Ral4cEx4+a z(;84^d!7xmGml|mrRR<#U10S^8L8Bg7rsWvPWZkL1;p)U0;Wgo!cGaJ4GUezq(lGE zt=`AI9|7*Rnrb25Z)I&mAGsQk<6i_B3>uGh!k%M}?wE1yCfpv|6Fc9da&sOS5}t6j zJm$wwSEZ((zR#U(;innNMVN4+n3CAiRfpy1p!my zXY35QI{AP;zBM0B#ws!@HP=v+dTXQ{c@HvF=dGis&bi z6AlBgNa&{+C@K1gvE9FmNPS0_ksPdI%Y4PMQTsr^Au!0O`pu&V*yaj;#>STf0Bukd zccL8qtsPX@^6?h&wJx~-XE!|z5YShP7@F#Lsjq+Xe?PuD#{QR}y@jKTy|LTZ5)l*( z4G0Pf>R(Rb`gf=N*WDoTk8dDTb@R3}|NHfqUBN$zahkT8sFp|pX`BrcO&~7GR8~sE z--3Xv>65$;XaGn`6)`;w#?Y}-4%>EWK7DJucE4H!`&~B!D(u1OPFtR3`O5{X${!p| zK$zFHW+%G8H{b9*Oi%MRPwjpFe&!7l@S{Co8s$F|N{M~YlanGdLGdtc!pV(tWhOVq z!R)v;VNWoU7^E{mbJiYY&^wTDML{^Mic0Uen?hkYK(F&wAGGz#g$iMjx(LK%`Vkw)K7q^IRfQ5s!+R2pPM z!Jblq=Vi<3!_!=pO_rgd>t`({haZ{MGF#;{t^fHm!@8ELtyTwNJ*tqr!ckV*hbs2!Y1d>5c6kG6*Ud#Z zUHzy^iA4jH{@?mx3}qc2t7zZG&2=>6%&eGFRpP-BkOT~e1H2|!;8i)3s}HOeipP-k z+2Pr{$s3tj3z1ODspEHLDyVf?<6EF)``_@pF^CP-&?N`B097xA42`Y_|k+EOKVlx-f+FGr-K*-G@}DaVK5B-~F=NUzMMD+mo6hNyOimv~Nj%IgIAJPMZe)i#Vg|?f&E|4GLcgrrM zrITTcVx`>??55uV3!vQr;u7zo;}knP;^)9F-Brx0+b`$i+L9L45t6`>oEpCMRn%2W zixajaWun{M{RW^llygmpV#^!uKRu1e?|}?BC-kbdsR$hYT*`fido}Y*VC;BR8P)6< z8v3m>%Gn``oW^MihUfd-0#iY)v5X#)k!7fXismONZDa!-BeKw(988DE@1MPd>sE*7 zHv=bL-d0kVmA_A?#29b?i4fU0PKke5*Mys-lbK_N8`8D2_hgpMcTMIX#+LA#65i7C z)p@Z^$Q&TCEKXj$#an9OYYo#XO))kua|;Cj(LrD3USd#ZMv!*>iRGW==wA~@t! zsbGG2cDV1CHJcUm2L)}CY(>kep|)0i3RV0?nbe+^jR+jIbWmQ>`Bve|koYgz<6^JAEso|Y`bd{w1r9VLK?vbv9IoOKiM{0r z#UZ@|3H{>vQfx%TL_&s+=x4(Ggd1-9bLDN#&)n6K0b{p#S6_a7$eR~Mt;`Jw#0@tB zG$6Gv10eP<2VIgrz?4!P#VAJhPK_V84WJdq0&EQ)KJR=6IJDQZ-LXe8qVk! zMAG%pE+d?IAzQ=?7`HJO6?&p8L0cCH@7;A}GLEU5en1QHAvZWoAy5Tb;0u#o%tAbv z{II+Q0K7BkMPx}fa37ZphI-odod+O?HB=*FsT$1q8b{pqN*57sg(L&}&iFA`16_~- zb}zg!l~w00P_^$$4QWx7T7n+Tc@RFnKadE=Y_vOKk-?4ft92`K2GQf3O5o;~vID#>ULM1#y_Pmn#0Vuf=k zu)b%|!7szLD!b_7dw{>py!?Yozi0eO(e0YO&fA{g|5R&hRSfi8f6&k47w9G^HifeZ zTLPNG)Bvs4faOP*z`!9s%(xHsJt}}BR@noa*#lhKBUNDuO2Ty*k^3>|r#v2+WMqKw zRZkHN$5I+IWrFLO$9qx8AJxtH`35~Al0eWdwx{YK-P~Gaywm9{b_5k zOruz$g+3|{?soyk1uJCCoW^^%+OT;z4!<$H10AxdoK zlB4`CA<$~pV$wU+8W6SgQgw=}Y<=RF6({mX8_$8q_-XL*;p4g2aqXLrcTy5Ze2Tlv zkAL7;oYTbZeP6#iC3=nVA#kU^a_MTQQiRq0UV*zaqI+|(wqRA zKO(fPfTr;>T$)xDVwd8gy6<)Gx|_ zDJ(P28a-*tLP2)(9YOJjyscz&ax0Iev8!!e5vJ=lj$K%G(*A$ngfOO#D-a$lbX`UYN86KHb%*MbQ)cL$a!WTOwHg!o z5z4QGS$~9oTk{SGx1?_r1U>(d72UDOa0ID{#v}?hS&2EMBxdd|Jmx}*hU9>l4Llo# zV$Nl#q$f$cjJ58(rHaAjn0S;Jx*dz*lm#ko$-f z(3Y^@W(fP$gExckb&Br?Px;>ongmB9Bde9je@Cp+Z0fz@V?HnZVRffCpxHov1%7iJ zzZbLue2QoPh7o>ar@(Sbl%`4!l)Ipm8|92sM(=TG#g?>^z9B4bN{S9%tYpf-bU$S@Z^3^u{R( z72<&|fnB4bSlVU!IP+D$pq6FU?k5;>?_@^xj;RR6uB`Vxyc0VH3YKC(77)7Sr7~Vy z^93Xa`&yedI8@X?UeSdyU5rp&3~_xI!(O`x`)>3INk@q4L5RHV1eLpwT-}_U1bVOf zIGQ^XbZNJ&^GaZIjICwHNOTiz@MUo{B%AxFN(s6=K@_o$KHXg1F%t33g4ryC3*?<@ zjR%KFF&$hG&_Y-cd3>)r#GkNu(D$Xiy*o;7sm1wm;RK1Cn7#|(eT|~>onV~U{ro~7 zA)#oiu7^FovW?-dJmcS|4|M--j+0hZ{GS=b-}6~dhPR)pI>y+X^%8~rQYr)$8kAB= zNlF?8nw@YOhE*f%x(R(p>4YtGiL|^*LljrX%~Zz%4MPx7h@A~}!P)+J1!)57&p6VG zBbMTdqq?uX>#VQz!|s*p0c${nU_j65?hXITw(plnMY?6*o+l6x#i0!=UHGoqI_$5w zhCQ&vEMfuz){Ic9XfE0ljN^2%3hd{b%AHdF+vSijpqB z$#3+YdkT}zu*q-ao{`|rmcf7Mo_@-c?$hE8aq5Lm@EcJBku07pUu-aWFgajk+{8rM zgt?ilSxZYrOGSH8Yf+m;i$xov!K_hB8=?u$1baGZh9%6LN)};?DeXW4&sZ!QS(1b- z74mms!xSL`u~yaZ0BWsk*KiS(%xKk~0LNFfu-9(qa#E~GPy%S;+Rck}8{W;VQlrr7 z4M}!s`rv)M`r`+sd~NR)S^X*faD3zX`UbxJ2kGku&V5GR7Ark>qII1PwtZ*xh#q?t zVs{(Ya9CPBbI+>5l2>McIlG}+>Ol1{A%3Q z%@q5HjKUe|o;m!M?q2=`F1N+a24VBhv0S{f*h^m2lWIRh2xMsQvlp?#%|6${p{yWd7 zatGZl98?%=ELuV5ne=AVPm_rZ0PDL8U1F8RxbN{sqqf7kzGj!dOz}3fz{C1I8b>A_ zLR}t$6INe^AFxn_4%%5%m%ApplBEind#sEk{2_wHxFgMu;$?=o3B9%%Yh zc2)s(zF<X2roe4bp&VTzxWrB7V1dtR7=&R1NI zXF4O33t~1JhXq(Xl@G4L;T=6N%Sj>mD{X0IHzMxQ*QFIGT7FzK zBYP+aIGS73taEag&`>L+TPSkLDyfvuWT%66bHcdK$EoiNC6!6UeoErqe^H8vR$s7! zh=q3zVR(zgku5NKHqGu2LjD{E)MiQBvlAuvD054CBWd*_x{eBCc;^8bX@WQvSK-iDls5)mqzCMe zBQIFGNOTN3B2=DEwqRM>PPK6<Xbge?7;P&s&;(+(NS0f?6Q07{Nr-|%|L z8{KoeghUB=9sGLQcRzzfdFX^sF$)75(?nG*g*GGVG;Jpu1yL+q*S2}WpH_~DU_(je zb^1lD=^FKp*z{g7l8q1yZToIH#sisj%?;Zi)dwW78V%gp<_J@I3Ez`SW6TLQk$*gk zOZxJbmROm5Qd#S6*Cl*2J5q10bqco=o>)3a<7;~^IDU?x`lf`Uqk1Ihc_ z!R5jju~YCSSo2aXPnKO4UY1@K-*MJ24VZD^xv%uhtjTASrHnuj`9y~PHo@|O68Cx7Zw1jSGY0eo#F@tUl)8^4i zYpyZk&M!?iC!YeRtJY!&lSNiol>ZeVsL11PQmMAqoznXZB|f&ssp(ERyZD`Lo*DDL zF6B7e86E!)P#yl0Q)x8+{gSXV(MeaPCOlvTiZtK{j)>tfhrqWBovhV5Lif}Ua!6#^`8z&yJ zg-Q;}%E&7;o@8NVM?E;H_%|PvK9Mo;TmZ>wr|-XAR0*jZVP>j@997@dN47D}YUdPh z%bbKNi|{5c5bs$jsO~oB9^V2;(5V)WorKW+Bbp-Ef6g$>R`cAs%V^@MS9maqS5`fv zj5CHFcHg7EWS8AnhozS;v%yRhL!{P7A139GP(> znMzl;QP|X&#GlM-Da5l&o2FXTOyJnYj4lqV)I^tRp~^N=q?yRmjbv%Xus5RFnozI) z^MhDX)c>@pqQ?Gzw`7xGz|=EDY2sAd5J`jiE60 z8<;Q@K%PqgGTIDOp^*?I)}L{h*iCdYAj)x)?J_uQ>_yZB)thA%;}RTIB$~LF%vg|& z{R-IC+C-R<>;_yG&rR6J!(?DS$3Ti&dL3?O`5O&eiSrPSjT9yhONTKuyV=jqs^SP> zAAXq%Vp~S7PGVNxMoft3{sIY5PWaNY0YDj>!(;**wQB>;YUn}(wiS)UMlt(<&1E?8 zMl?TD3vR^2@rx*eytCGiTLLWO8(>|;xZ{gnb@XmPx?Iu5O)RV5SJ?61XLaxR;nXd?9oc$&3kA>;> z%_UeLBfa89GpfQ=z3QKwB!OCt>&0?#Cv{gWJ!4-Jcg!2| z=dCosfg29h-oo48wKo9w7GM41w4ZuuKny6bj|#P%2VyiO!4oI# zj;HVP7kDUm~J2*3m-3Cu4@oOo|Z@?*ekI?`pb*qaOZhbqGei2g>pc)BFWhul|aF`HL^ z9Tu3 zXp)ssAK6bqgFdoB7@e_=mIPNT{L@7qjjv6Zcs5kpi)MNlCnK~~NwU5={ISGk!L%xT zS7qu99lb=sO`EgDyx0*ph96_I;{B0lV{u*$RCiRvkTQdGKjd`pb)6PA^R)j$V3-4>dNb1nk_RG_NiX( ziRZJ*gh{s?ZERv^lH%qpfoo5fHhNakr51Ba@T4h?(R~O=T$`#qF^j*;l?hnee0jZp z&q4aoSFn!r2RMc@t94@}-SJ>Wtqn?K~k91-dh?`jt zz3PC}+&9n*|8>ink)Z3nUmguREs>1uW!o}BSoE<=UbII5~^6aQE1j~~0 zyB^ab1QlW`>~5@msodYGk}xij%7U{n1dmTWjk5soq>j;jj@1Cul=m|HE?H8uWcM`u z_h+G z6z@<1Ze6lH;(G~xmjtN*>0^1HW4++GQ@FQQ0&VIf4HCyy(rPgmHbDCs;6ZFr`ncBT zxRQiBdwlD0+y?N~V7B!%jsvixaH%EGrcDwi`TjW01L%$#ci?yFmD&|L#`ie}0d&WX z^FEC)iMj9sE*{5y0DMBn`aWi%QUnzDU&j?n5s=>#@ZY-u_#}>de9Vfa0z{8}`0wF@ z*~pMPg%j;iq-T%geU3>0)8zL8{4R}BJW*dw;s|IH)?yB;q;qH!onpK7l6mAwuuebEVwdj(=O`1lQQL)*9I?k& zV%N*0J0zXKWNgo~uQV)sM<#0x+z$r~Ra@eCjX>#x$Q z^gk&`rJ5Ii*@}JYH%+*tw-RBwA;+Ls0jKQ8(g@RpMGiz+-P)(JYa20N9$J{LY^Jx~ zc-q?Ldb}52!5QW#RI|poZ*DRMob4_26+ds2Ly0w1Fu8KRY`e~W zGZpzo4nF2AG7bT&Oe*JQ?4lx}LRXGf6I5sfH8dDd0!1M);v^%CW6DB@-4^E@F{ou| zQqaS=IZ^*6nH%@OE6m4TI`+lIX!ycyI z&gl+cPHJ1G8llR2L^DX#K6XTDk_#P?^jZ-hfoQ4Eil2~;osQu>h}Y)Ed4UDj>OEDf z`q1J4ABkFLsxt)OU{UsHC*(oC`FVl8KGAQ|B77D6{Q8GslgQ=KItXI+?7Rlb)3@Tf z5>Hy0SNslbOn&NYDj}CG2l&G*i>#@AD33UzcYbJKg&+M@V~J&lBjVnhZ|o-m)2oOH z91gaN0>dxs5q6cY#es)pw>n_bnHawTJE?i6B{30KLuMH1d4jM=0 zuOgKU;l!)f2<5BVh~=x^C?-wsusOP6v{avlGx#18A8UKmuuW_wnCJ|N40HTk%TOaf zq5?vwU}jmI@=)YYi>LX#ZhG45pm9Glc21?ua+8B2MXX48&ehCB z=F_<02Yg=>_ML2|FIq|5&mWd?=Q4a9@=s-6ODR})p=a^fz_r;J z{QOQQCXhvPW*6e}@997sbikJ8jAbIa#9dLCJw~0%S@d$}%w4--M2;uqmI+ATSqV6q zOsY&|bbn#*$i+U6@|b19p#*&2(MLRH()oL1DX%yWCJzAY5D-yX0N^^+v>Jy+G(2TKr%Ej=(!5PK{$l zcX)q2BDLayU$BL4BYnFpIsXX5qWk#TJ>9SlED85Z_L;WS+zGtSK0!=NzdV{kzu}~# zD0Tlp<`tR>m|?t&L8!(-*6|j**K3e?zK&^I90_yRb8;CxXDJTYn~4JcoFpY z&wFZCAj*`O*IqFd72p|cG9>t>dt(0?8Z2b7HTqYe#%z$?C<@3%FbKg2%5J#IE`0n8 z(XgipXkuaJOHurdNXl4a?8`zslz;ebPs*}Fy*t?alp4u`_1Lu#j~>qBj>sE4U3x%y z<_%98r9;rpK+I6`yhGt3gjxuHbZT!DraHN3_W?&0R-H&O;T#L{^mUAT%Dl9iB*pco zD962=ZB3yma2<+H0*paiYd6@%8%vn?H>9*9BE#TfJyJ1M_}y@an~l)Z9)}XTMNH+Z z1oY2;*e|JLm5Iqg00H^@k7CyUrchA*ySVjt(MHL|+Ts85AHL1WfHEVE_AR$oKN+gu z0`slJ3O}}Sjtm}(#M1jHG&kF(xv4JN-EHu_0tuvKTxpaNML`U5qV~ScnCQC5ix-%nM| zq8t^a;)%shD5;cL(=1tfTc-oSY4#Ny=4&6+Fc9KKd^b3nFPeTEe>?r%HObPnkZyfp%RO9OXVRjY} z=*C1X_5Oq(sDO*u>(hpfrBk7Z#AHWw3p_-zDGT4&x@doMvCL4<`{(+-BfRGyvP;GQ zByPkn4lDG3tc?9z)c9W(2Y;i+wOX)#YL=;=fe$m&xt*@4L}nrsU|2*#8PZURSwbSR z-f8nlRP{K^Kfl2lZ%)YZum)?y*464)+uLi#$^@q^s#LYn+7kmSU$C}~^j-~Fu2j`t zba}XI>hE~G2-zUzR*5x;jc$2|j-KqK zFoNN?BJXKvdhbq=$ovM8?8x$lk?hF&mJoAeqBZhz%QYoXcqpBtdFvnGH5p%i2e-#x zeaM|-dCw=<+kXrRW1x12VqkF()AvT4OvwDkoSaYfS_vztdN5W^@EfmB=~lM4x2y=E z&*a|L;#Yjk+FgW9Rltg^4~Zv$~s1M|F3rvpTS?&wdmdr6H~${!z$=%4X| zw6C!-7{6CSKL_?+uWzQG`utunvVU`!eiGin-hSsit45Nud!!;efc+lxG&nF^2_xQt zcJKpI9i5<%x=3!M^iilp4;fX>?OwFJp>tSFTn@!aoP(02QH_h3shu?M%)X0d7u7~a z{C!aV`%!eSQdMPc->8Uka=pAzv>gI@5*>>r9CEIF`dO4`WRY=jOaiT_uc$m|rBus= zmt_7FNw&w0LWC+$U}Dhv1WEM^*7&-Q&$5QQo5&I7|RXF;Q+ zAEu?b^;(K0Ik71~;3Rlc)*BF@{-pxa5{`5mH%^Zy&LsF<-z+3^_u7D!@;qQSqiSiQ z&Y}b(fh0|n^k=V>jbfKv+S-@m3f#xVqvQ}I2Oqq;GzMBlXLJoi`z45JXGU!iU($3c zgJnP91XIg&rn_bvE3$~?o*cK0V{S4BUKrQd(!pK6LlF6zLXTyk-JEC?g_mRkN_}fm zi!KkQl;loJrGSQ(T+)mSu+FHkd9|gX>QRypwyOOxHF4|gRq<^C;`otokM5TicJ_e!ujvg{bh_NU(mojjcwKsU-P`H_lqnNh;za*d>fiuH8M2+$imq)2JYnz zk)t?=whGZX#$fVQnHk*}zWPnB9!@krLp1v0u5ZiWBdca9@=1DBiedExQDlRer1Lv- zzv$6%)n}SS(wxki{iis~a&6~|kL=>aiUDN5vgSAfK`YlfA4Nks!GcFc;xK4gF73I2 zy0hazgEpWGNY+3=%@(|Bn1UzW3XtO>P?(yAY2&@%&l>TCwN*f3#G~w`>#H{O%8&GEoXr%9O4nlx`r-D{9ZLr?2lmA^~BYzOqwdx!qV&2ak>^{#pD(m(6`v^ z#t`7sk9Kgn8dQgTZw=sYhR|_#6A`VTjMGV~v=_^xaC#M18ZdvMDOX2ZoAAt_l;%>` zcqWoqSPjnY6As14WK>3Lo3uq_-$KK;9|1jGoXZ#ct6FTSi{(=Mi0aJBp!}J6gOwaA zmtfU_$sDY$ZK=wJa}6)9N#O(eKG>)R5zeu1?>qP>pxEidA9Nxm-v{Kgu0fCkDc(iw z2Q7(E1ql^X>G*1SG{p93cYKx>Q5G9tjB1Ql#X4gYDLJ+kYbnt|=x)>b`_X&H(c&fQWxIaR5g=Z;=^gTMF7WU}b6NjF5U)Kg11Q?_ zwXUMw98&kclQC1*yO%|HIa2W;?TSUKkHmWyeicNFkFU%KHdp~T_O7N~0Ofw0X{ha3s+Xc!Lk6dm`{lBoU&&(&9StQ_fb&Kxoam^9$MCFF#svS+CEi>Ez& zy~++_qt))5tv+>3*X4}1cR<}is_A)W$ z%7lB0c+>0^QPn84C#$a|bPr}F1+_3iX#;X94B>U_s@|v2?^DUIGptl!t6#3Y(6m{9 zqJ6r2Pu=wBVt}xhIU~j?D}Vd;NJs?>HYdcE6KoH4Z|pJXq8LK=-|>**G;?5um(yrmoq(pegtT zbpD6V*gwH7Fwc!J4AIjB0>Kyofi#L#E9|=zNeHd{j_VoCqgHN+DOSt}*ya5IT#f3d zSIC)qR2E5q>hK7OrIN?u;LM!=amoPy%&`Ykd+HP2f|syv&WPO`#zKIeem}-3c8V@~ zPI(_#61bhSj&?qA)?miL{#;3g7{gj>o*|(j~G>2u+zwFmNbJeN~ZcZMG@O~%aI+6 zQGNQ$rsZPhn7*B3N5r@9*}IEq`u&D0He!Mc*;Z>zTB2phwA#|QT-|=9Ez5+E2Q#u$ zk1{2!tXjiOip3Is5Uqznb=S#dU700uE1jUKa|Jd?sx_PcRFL2W=oa?6#Y|5|19gV<$F6dN;-9U?l#2&$m>NKZXc;vX*^L3+a~xGd7|M%bY8j9ZS|LS)(#D8&GqaA(=kK>IjB z@^78@C}Q#(#V~}2ssX3E)vVNzu(YlqL(M*NM=0@z6yq8_3>sI5jB$V`+pl1B&t?6g zEA>R^vI#B-L|RhlU$9|3{8pQAnFZNyk6^rdL6z?dNhJ$anyJJb9};`wDEDL@F4 zn=Rm*0LVGzH>_a2+E6@(49ulkg-gl-MBN-NlbAYA)6;SS6A8Pv|VRm_xKjXf3{Hx*TJ${Lq*LY%vXa_#*t#@7Q{DY(CHb#QWK$HKsj{j5W9& z9~@Dj4Q2MwojfcUtw4?ibPRdlU#mJ4i16*szZ}mFdZBIN2cEP0`;*_PgrJpIo3y1gI zA?gema6ahyOIj@unyW?hL6Mi5YTWFd7>H zVGLV|%@|9gf<)POS`v5rAL)oll9Eb_X`^*9;G$MObX-k)IOp#;=HvBLq5<;Q_dNcc zh-2_r&dl5b!LJ6yW0-B5q30#K!_t_1u_GY#2we=wR_cC}*m_J+p6c8X3)`1fF0W`Y zh=Sl$49iC4!9{J_Qo7!~E#oDm%d`W55Pjs7Puj5=% zKKYhNQ;`R2^`RXNozuD=5SXoLzt9Zdh%{PgD4D_q4fx`q9}{jK*Mtd2yh`JpmyJ`- z<)^e`2)nh%CJ?-UwIRysB55cKR5S`S6eMzMhEdK(Y_!8=&DlLBaE4FR^eAnen{y&S zU3d_tu(=pMxTq};t6eyHNiUoXW(Q(j2nzS=IoBlMJ05YYj;$QvZkeT!&yRyTaF-64 z5N=Cz^m96^2`BaGHb5fvVq7}mT+L|xy@3qJd1s^@W{6gGX4N-@A7futke}T(o@t{5 zq9Wyj{x@_&8U6AK}6xQmy z^BC%5*Oqq9T$j4s^McX^7i`kle{%l5$6NgxUEIj|fW?aj{k_Y5H#i?_sf~W>%sV4= ziX_Mnv}&*s8tFzEV*s8|^L8w{3*qXNZG*N!Z0>z1)C8h&VmE?xC*iLXNvGs)g8U>x z(vrZD^cj%~mL5X9yI!?5RO_`P?6vr~yk7{UPL;^P2^#5ug%g1f3nW}!eSx(z=kpQ( za?+-hHxz+4R`W43-8WC=n7#Oud#cq*-v)VtA@qBLuoM5N$)k13n=#1~&<^zgV9#;J zLx-&OgbBtY;EB^cX+FErip98v%Db@&LHy$0K&3dIcr1IFF)7(GD_3h|oH8hW1!SKP zl1DP}Gd}UNUucEpR3eJ1VR?m6{IbYC2_%nS?}Eq7$D$RcQ;9GhMg1mDn9Sb~cw?n$ zlw?`5ey+R3+el@kZK0i7n+W6FPwN{od*em%MJxZ7HybyZi(dlY9@-8tF0Q<0%7w@2 ztveeBsXZuD`I9O12_pXoJ^6S~iT*Po^Pc{YOCFB{?vLPKH3Gz7fNJfRv-{y!x9Yzq zk5T?-tmSWl>^~6zO>ZwXP4v&52^P*|$gp6b!b>7KiYc@bbLoPxZ$KU>OsG-8D(@_= z$#B!%nX|s2(Z4j(yVh(*{3|tRH43u6k+eG0dNiurw${2+Giar2^eOf!UXH#}!<>QX4JADgQ>YH!9MV!GlegszP6^U;5n2Tkx+7Z2f z$$K#njdLBl@8;MMxxZQWh6i|Z?2vP{i=TYsuswSIHVn>T8~1hjHgo5heprm1mlE{H z{xkb989VRjEd|9h^ROAa?cp=^@NvNoD`48m+kf8`KquKN0ibi(=)E-oC@I>f@52md z;ppu?m!U+B?1*-by%N9Ai8!3*?d+a8_>7!_SRukxI$Q1 zFk^lfFxFm{(Hg>x*~%cNEd`aG3!0T|bX7ZvwOrbpNr_sFe#UhW5kcb&C{DCg$d!$arML_Pu&kb z+`zG)a$XZ=daJt?w(dKcU;x!I%&{5iV{n#xm?e2oW<^F_uh*2W8jF15opxSIo4fcZ zV+{DMi-Y{OD4qE`3m{=0L9u}6%*B$_&=`WX{7^o4v+!H?d<__;gCl*!E}zb@Z++i! z-c$~zKp~xyJ;I?XAv4gqhPxBM!(MqX892mg2CkOQrWrnG$x2LgHcoz7; z%tYO7d`1yrCAW=;*eHygO$lbFbv$)*H9}i{m--w#do-JIL8$9+`s%;s>$yQu#J|ED zSEN}Smdi@tX{LmRGF&upRj89VLcx$oMslDiA`7?4lZjTeKjyr&vbjB1tP~4_tz(#B z+5k=J6;;}j>wMdPwM*iySH4mh%aHUh#e~Tn-lUVe#_92a>4Q z40kWm$XX@F>#N*+D9UwGTBqE8P%ik1;?b^s);tua9YB4Pu8|NGy%2;o>Bemfqe&42 zhmn*DQbsX`W~0eUVa~Bf5q+d_S(a0Xt^5d37HuFAR!mKz{lg^xs8JeDKtz`r8yaD! z(AvUVPC8PwMl+7nV&KuZ)^E8Kc&+Vl#YJAWmG< zxovJJ_pB*Pi2!|HxtZ>shnk9_#5NFf3;~&$Zu)KPUK5_?Tun;!IPw!c=}U;@2k}uw zrMjrKS48UTxFD)9dlP^ALXnm+iD#sF@5hB8t1xHkhM%lg`3tcuA10FY%RW*g=(I6VoKD0>t_Jo>6=4}H+Ku)x4NvD0pH9u~n+`L5RHw_9^rCfK+ zMeA~VL>lEPksIo))8p74z1TrL2jmZc)-8P0-Y@o;<5RL{y%v7A7rTle2h}mtI!4xC zN%fBt!)vQBOJ6V98V%c6971 zO1-B(e9@z?Vrza7iyK@c-z=>1eq&^59u^y?+u*{n&4A<~%WA9UeKF6_v@1=+ zF(c%%=d_WToy1IcBm`lnv$<~#n(D^4S zguM0FHFxWOk^vQvp|*$z(&_3ADC{T)3#sZ*D5hSAVq|WPKP>K z=yD~EGOM^v73HQ>04)KbR>OEFaaF=pLdoG~IIL$h1_UWRdOk8;jcT7nk#XJn=sdD~r&0>0fKYE86ZEKPb0FD=lEg`4GS2vZ}b!j(C#)ORX!u-9Z?Tk@)! z3@9j}w!}Zx3_FIuWxu(-HF1xC!TlIlP-|%IDi2v!Pf?2-t56A@5MgOA+Oap=X*{Te zX2a*o!aSnwyq9w*We0n)_eUT-h`O;51VCO>`t7rW$W9kCT_7f>ZxE5Uz6%9828Tj? zPEh)`@J4+r^FN{7YY1b|G#n?67x)PT4sn~EnfoL6&{yE(yYf~aSI*@oxx$u!-F=x6 zC4ctO0OO-Fug^Cu4If2+(*1dslZLbXVh!Gl&rC3P9|+#IA6+5Dn>|d_$mdG$xV_Ty zBSf@xW9>w>k&Lpz5!${H?yWJih9vQMgUSVh9+K$&a}B_cUed=048OJnF2Kz#C^j}s zQ&56^O0E;fUXFXLh%cqsn&)%dZXX79& z82Mf*@HEj(O3TH(y7KJ&rVFi1z1z9Y;eYNP9TT6Q&)au>AUYK0T~`nsNKhhi zN{qqO04|J_vM~n4A)a7gImrwPfCbL^@aA;@D@1;Y5s*t_wYKMCVJFqXVKbhW&~lY%ZP$yEtT4eb ze!$OAgrq{O7Gx^^1~sl+gj8^lmYnY5Jc(2q2h-28c1j|3FN`UMp^MDamT% z$C<40s`aFVNX1f+q5r}p))-Hu;b%J{ONA0-Lm#!+&R`aeEp&f6o9p!=V2fc`HG*6! zGCA*dz;i8aZG85?&Q#Y+@9A%tAETQ}3R1Gbpvh%ic^Vxt-V}fEpa9KZI!7yk_B~$m z4uhKG71dv84x?&*Eeb!a8h=0yahHShlE3(RS%guT5rO;JYFix1J9>%M`OVdb7!q{% z038G%Z}ca53H#)>(hdv*DjV=w+C(#NhzJo&{br#U4RJa$%3pYexcdJNp7EI?@gIIuDM}1~7&r;5f8q z&;wn8)x%$c5bqF2^`r-+Tdd^4{2;Ay?$gUYod*1O?7yPQf70aS`io_t@E@b!*BwGH} zu^lr8h9$Y&rqg*SIJ=fueqGo6a@H9~`z<0QrOAE!-c|Cw)r#-m)X(3i3*HI8I3Cvj zk>kPk@ABFI_2dm4olG1h{-V>^8d%H!?ce{I&6I5H=HyX)X;Gkbp7ugAIMe7i$W3Z# zZ?T7j8L;9-Wm2Wy)px3>0#)0!ko_V)d*M@`<1Gvy62ke$+-X^bSQ(;!cuw&g^B!~9 zb@KW8z5?l^yP%#^R+W)kiW><9hFE!UCLPHS6){uYIqM9f1){z1;KAv7bdA@Tfah90 z24)*U+Kp5O;^T1kwOvDWiTy?<<32J7BtXTXUlApAzPv6;rgJ~x3RIFU#C%}y&%1ni zS75%lv7bJL8A<58e93O<*C&>4nWn#XynTonDjSMooN83v8FrT2sx3Bi+C~k9vB+OC z9N|lmrTl8EQcKdk6rRE&LpI%XIhT5Fb;>G~-pQz!g>w;kj3BJUD$l zrP+vK`)vclW#{RYkp?CVKhz{RY4tTCY;c`sRFqw`2g=}pS#YiBF_TFr`K}&3)S`x4 z`O1sxla7UF(01LUK{fY-E}BzZU7z^W5Rqq)wH3KaR4LNS2SvcSIHdjm(q#qoVA!5L#%64|#`P5SzGOY!FE7$K+-(C@0Jym%!Lf z?byX@_ZMQ=$qNQQ#1AaH@#3p-3+Qs7yF?zC%u#5+fc_QhsY*O-uwP%>UwYJkUqSi* z-52+F>em0#+e?_)+Bq5+TK|jQUS--2TjUF9*Kaj0XRtb)6-cEkt_j+ZRZ8U0vh$f^ zL9h_ZhUXJ1(q_0D+8tC3dPYN`({}dq#X1TIJDeiWU_jqsz^QmVgE3RL%_3 zM<63&4^Cv3v%~=4*CpM5{TdINpDSR=j5}w-f*Yfowj43XFgd9)>x{Q2OHR2Q&l{WZ zvG5%9oR>_ZDNY^ps=7oG!&p#QukCaI!;{lCmM5hG?XB@!a}};?Y9rt9u&R|tbV<7_ zBMCA0E|;FHA202=5k082-=gJAR&%1LzYnm#lr$JaI}F&)>>c3**prQ`Hd2zMSy3=> z>NrG}CQ0^6di*XEr%~Hb8JA)?f5w(;Ikt3d#oySkJQN%HgV;uHRZ3jOm4oTIzuK8v z9}Wt}qgUE0WjL0+^19~6NfLuae;ekni^EJG;s89oOU<&L_SvCAg9rwT3^rw;*nbbE z+mq;z?w~7_Z1C{;lj#OYmz6#m6PUxo)Z}eSRUV9X2Nl?9gvl7MNU!NcS=*yuX6Sb# zm}_IYjy9qco`V|7R#Tbbt+1C)Qn1p4WLH&K5a3grU1+3;fV%pt;0_?SAH>=Wl?prC zB??e!EM~S`yab;Tq7HB4JU5S2Nt6!s2-yp$4`Q>FYd=yTB&e#0yLmsgP^F)MoyU~A+?4A_NLlLS6cSAB6r`HSj^aieFN-$vySpOM`1 zy`v7}vE>;fO0A0mxhsbj)a`M_WJrqO%$Swd`EO=8VYV@u8aGgrbgZ~rKpz{iXBfx$ zaS7&3W?+^OP1OTQc(Qh(g&E6Aw}zrhmki|LP}ikH-8pffhXv2sZ7geV>_ypJR`-Mk zr2ia%aW2j5bG=pN^(#wv0{(pO@FbDexz@Jo_*IaqC`Q(Qd{Rb)l_R?Oi=ZaZD*{jQ zrhVpldFF+U{+Y)!;@T+8FOun<%h=p6*)N9r^Sj8$H{|t|JccaN=jZX=>n-Fds%NCGN-1!U5*0dulHH}Z>gK@URe33fKXSZc z?S_{Sl&jt*Z12w3#o>gAh`SNvw;iHB{fR%3o!;pt=6wa?=6SBBpF!~QStNCXK7Im9 z2;wIYL=$KJwvB+>gh8AA0^mvi5h@7$yY%sog7v==h?4Uc8`SJyfOwMfxa~YY3Qt0t z!+u*~A$$%3c>{ku?*T zj$fOz2SA=Ea0!t}d5G$;p&bg3xlp>@E~)^n7H1@bRRw8BRq>2 zDENpy0U7rudYUwj%9CXvEoyeg(bMhc;8fap6o3{|Z$-gOu90MDh%V|przw4jp=zi< z2kJd1?G9m}M^1(6+NkFtG+bKC_{_5763sNSz}BGwxnPL@W+=6dH58X&sx@{@JTXvA z`=c%-1}U6tWc?sL$~{+?0S(JJw%f{C*NRKr!h~%;WB;Y4+!Hr1{e%f;68?IZ4Tk9l zRSZnNt9n#Pc^?Z|nYzg|yl{3Xv0;;ub@?Pn)x0v9#SHR^02K2;-5T?!#Ovt^krbcL z;R&xmd$Jd3a)zh>02Alz!rWR6E&t0mk(aQ!Vz2vPlbh1fIg>!$+=m&rJPf~qd`8?XzEVH|k?PPL4dxUWV$ zk=c5GmDe(5IojH<^6L9#_49w1*Zv<>8w)|U@-0x20V{64S2nRl3f!#j(%7JGL+FeX{_IuO5JEo zYullre4<2wu1Br&mwEvmVvt*{%d6Oj!W94b4jC+P4z7x^pdsw>`@1^>0llQwDvKaz z$-{3;!{>n=MSiNdY=5UHFbG-K$S~IAiyWJq+skBpDU0DbnHhpltqo$Zxh~_=9g8Q2 z1+Tby8eC&B;zaFx=)azech3gFUp7D4{}Jf^x5GUp3mf}?!5m3S({{*WUzo#ptC1~Z zdo>mTI2TgiE1{(T0VtP0jNdWon<8P(!`vVqSLB6`RVOXSgEG5v*@6`k*0e_z}XMGQ+q4? znb^ydk72gROEeV3B!)8qb^Jq{@m#q*Bd^HERK*+49ikpgFxu6%ggH7cJZv4L`lwsm zv|H#oEZwA_V9PpkTc=HUvCtF%N z4vO*Qs>t>;U9~(}{96lLU%Od%#&IscRsB|CK|Fys4!o}24O+A@@u<5giI@MByp8Lz zKmX>!wvjAgeWp$TSv8~SvJR=*ALy%tT*J4+zySM50Q9a>y0w!w#qd*L3g)&V2<7uz z{sX%3=m&D?HqnE9kRy1iFgg8sIm012gE7-Z{Y^0# zTuScX_ZOT#p7l^4e~r>vB%7M}_Aaw(tmR&W#WyyHr+oLC<$k03;SUR!vClYc##0*? zD;1?<-af*!JaBbxCWb@fcq?$cqTr8<${@{JWDX~iJ}jcy!$`BIrP=4!5OwWw4X$Zm zibrNxTtABqOxnqRb>DE;{-Px}TJ5AFdq)|pq`u=2WCrGyE|#n{Gc=s&^S7(qf9{fM zMZXIDkN;TcN&j7;|9gS|+iC8<~{d7SkBPbaznPLg8HCZm5qIuck zKa20?8KhaZr_85r+g>Y6hNOO1o!1*qF;g#7Zd0AFyJFkk$UTDEHIC|bBDk#THMIyC zGgj;qS>D#kKeS+4oQ?sgTD6rwIe#_oIk~G_+BNSXKBN^;DnI^2{R1&ZK>UQtaS_}9 z69?=Nf%SB4sXa2bi@u|ruIwUsC0s{Un4UP)oY&A1uSvfd^}dGphXV)ML2P2bIPdQR zqiW?fGhJRaCZpbbv?eU`^>rN9IbTOM#=W7Up?pivuq zbIU)|Wt&2WhFiJuz$wUj4UV3Srh%1-rcrbp37}iC#}KnF5eozrvvG$RE+|xm28_qh z&F$^IzJ`Pxy|#rEC5uE)PDW~;X;Qmygdn>M!jajS_nTRpi-qEF+MM)BVze#fd?XODKNS%cMhB&C*k37MGvVI`|DC-l3xs~ z$1RIhEb-(gR;e7Cw18m&U#?x!TbmQOG2BpI@3+aR=|lM{WN6;FJlW2|x(cqVMxC?q zTdLH_bqj)PSXT-SX>C*@IW$rdnfLTb4SUuXJAQ2?)Qm$OQ4)RHsE$x5b@xb@M^g-P zV5mQ`%NTcx^i`cj*=$OaIX_%WC}9&>6xPIzCd=YTm?eq!Af5_`^fKvkR_*lck%zdg zT{)%c@_W*>lLZUMZT~Rh_>jfeZ+c?h>kLt6J-y3%>1<=l z#P?AY^EhKtX%|_G6xUA2@tM0_+19MRNP zTbt}{+<19I0?uoOWHH~?w6ClE`~0Cxqd--M{fpv8W4m zHiBFbG}Szw^ng_yb!1m3fAeJcIq8jL-3xIH?2a*9o3&X0ueW<;1+nK6bOVO6(Ff-Z z9{9|#jmtMo`<{INgCU5ID5UVAN8As_(lGgS)h1V(SIyct#tWtiMOrFKsqhKkB$R?D zNDxP%vcd9n(67br$a~5uZ&cls`-;O0a{k>!v{^Eh$kuBV73Gb`D7A&5>O0eMJ~+DL-+a$@w?4F&FJH zX3NUwANJvN4?rT{wAVfmvU513M|O|i9`daS&>ND!52}RrkgvAEe0LNX#D_+~oc`fu z{(Yz1@f+@4XNUkG&mC!1hjO)e-egQ=twXLTrZ0DPgUEu{;|Vxv|6Ou7XY6_~e%k^I z^Pq@3dgW~Ox197@)DN=!LMKdTJd+?c^;4soebU+v5o){q_l>OWyWOW}#E)42H^;0nzq#;dbyh?v#jsLgYQ@&xpNcD0bv3e5@>rlcl%Usp`ZJ2g zDdY$EdTr^pJPEGXvyI(xuGh$A@DPjJ3c-H*-#_lXfohT zaneU|Vvv~-3Qvtm>kE}si00ViRgMHTM`STaepDyHs!^aORF+vGNv{>7p89D%$S%C* zVw&VZnb9&?M{q_gTn?dtPH?7b<9vqTa=NIq%Q1VT%AtDVR{j(H@Pg~GZZIO6K1`-2 zLYI92t!1!@8U96iu~Kgtd1e} zdR>_?@F}r?XFM&pNUW?uGJBS3x||13bSQbkb3gSA9K)MeUM*5aLmHo+*`mY;+UaXH*_NL|8p+&$Qu z_a4sQBF+?^yN?pV^(IyA zz0(7gN7h>8XfyN0nV7CFy$RtRk`8ZFq|vMM6RSn5-GQA3*=8t*W+-e8+gm2Zm!kO? zsTMEj=M)zZmaF?Y<1Fem?ePHcj#K?YpMRU~(@`QF+M?mJn3o&5a6roR}yZWe} zv* zc}7`OQ_|=ScSA-YGOZ|XiuhzJUJ-Q*vxr`7DC8zSDtM!0Bc{xfpf>Yk@#?6Pvts~S zdgkSn7=vau}CuvvoW5`zs@^&W?$?3(>h z_1f@6!)YcH5=RJbE-ZoxdEhy_W-f~*@rKh_oDnJG`Ez|eV}Ft*5(B*{x}!u{HMMSy zwrw*SV4^!s0<*OfiC>6o$_m0TGz6`|(!5_56`gqiQBhzyLEKWjcg7yk0#=D$McS$* z2u8@ArHUc+EFPdiVdUDf1Ea@niC&@HmC23DghjoARo7BM5E>ievrC${|q9uPdQ-T8;_V`BMA+z?EN)heojR36BsPU^knn)Pm(xsuSwM$ zWHr?gwZ%^uIgaKQx-4VrPnZ{tUs7ZZzGh93Z6>);qLIX&X8*!r6we7is4W^!T#8GOk|a;f-6NkwCtam!k*s*m5Z`;e zG6j8U@@T9 ztbhhx#<$}=s(|@p@l={nDR$D9rcUt{=_(|bfEhtIV+N+uN>s_)sW^P}A>=I5RTQZ- zF^_xsF7bm}6 zq-yAw_p680u};lY71xb3>$ZP0lRNm>@@Xb-IkPP&_;XCo&5!K6XsP{?_i1N@{6EIdej*Rck!PAL-d@Hl-a+Kolzm*>FZ!*OJzk+OTB?Pmy^5@ z6hzdXxs?L5(a|~;uA-srlowTW(uQBe<<<7b<$1zhogcyS+Nzu0(14g-I-_Ed4)1nM zN}yf@(%V|#J~PMARCUwt>o`nI3=Z)mF506#)8TwU4Rf9Sw9=gzTzr9jbq<^9i_057 z*3Bb8NG@7GOrAT`13vM96t;n;K=XYe@sHlA^WH3+dCE6a;+sFVem0P@yt(+<<5jlF zO`P$Xu=@V8?;!8I3t>K(_mN##7FoSH=^`=j9Tcy@pavz(f}0VRMc+hGOcD!_^!CA& z4a-Du*#&Z7lo`Fy6nu2c9kqaDVQg)Ti9>I@9xo|sD5z8T1Y%tz9bIL=+(RKfO!EEk zm}!)@(S9o4Q_y`#lG5|=j)Quq)a^f4-ZFgI7X6X*nF4XcR+H8p4)#ISaHE%>^@-O0 za*c4*Ef)0o9sF6#J>nBF|6PuK@-vFq4_oP-uI72$KJ611?i0M~&TmiTgRW!XGkW^& zbI0i&*W154k`6M&V|P$3xQD7Q^csS%iwwwJMR}h^A#zy+b_*rr2D=v1E}ZjSWue|O zx1O^$$p$&PLWa54b#{y}FZwYet3uDYX5SDU8?k-Wqc&6~f_^-b)>X#2{&-OLH)icG zA6@RLF7j;s=7EF@tGpB+EgVBWgiwmJDn=$OsfioqIRTtph5*~WoJ1}u=bQPB#nrW( zjX_e4(2SKW6}9%LNxV!NIy8inIiGjDGgXQ;aZ&==9=dFS=rDr}4B>VR!D9B{PUq@a zZTRoAdPF46Q}PM;nnuMH+D}MlTFEscidUpOe1maRlrM(Wdm7H0DVM^2-)s_Nhveyo zYIQPu;T+H^_cYiFh9wEIXbpn6h}>!$&AmH+CN=_j!j-YZ%V>Y&(QXKr2of$M%mFU^ zNjn4hAnV0@qMrIGd;GihdD36R%u*^+K#jYR}PTQ*Gxs3WlkR? zX$Zq~hJbDtPM+YS9S5F>`Zr;E`yaoQq8yNcr*_uhA@y2Ju&o)8>~1RrEL=(nSI{ zgFTl~frKn5LF%{}Kt?AZ7x2KR6K^1g5ZNmfx#|0{!)6Z-iLhIdrHDd_g6BFlHNmm% zcI0h#G|tDj`JFyG0i+KRGCUs)21djWZkHD)vZx>IYFL~Zck%WopaPJ|Uv^u7-O!ms zL;qX45tSNMP1B_rgH^S2uf9@$5jOJP_XM5q1{QIvUpj&G|>B0RhVSgjY zl-ae+Z}MT?1CNx8xW+XnU3MiMhw7HWqH{XbW<>jYAOGw>&_^BDUcK7$HqAWAHP=_8+3MQ2mbpDA--S<<6J17dTSBz| zGOMW1SdGCT5-qr_atyQkQ**{@n7bHEqU^vGt-sF~Q#?I`4;BZ7ri-? z6e-ELqk`)&u|&LB`nE0?CaDFWW-WtR7-5moJX@_e^(M})rKzz!P-cThnrTDKl1O91 zalM;Zr)&v)oWxQKtFyximYAyp(64|HZP#v_1g&XGRFQRIKP0s_>5Pu5GdxF($b&uU zkOAfLKrSt=#x!(#vJ7nw9d=_Vd0>leI;5$IjM7%Nlv1$%b5**mAuNw0F{dw&^rwJG z2q|!Y4kzus;!!`-lR?Di{i4tz9nK&G#nj>({JeoSJ~p&7NXiL$)f~NU0b+-AzI)Qp z4OaBN%h;aG*e-7R0C?0RK~|5Ma^JBtlHQEabA+se70!{gVGY9+t0j5(K8Da4-Cv>2 zb%eTZ^)<3|_?O+w|AgEBeQ5u~O-;_!)XBv8AAsA({%<0x&1SFZF77_k8z2Jf@f4EP zNj1KeWa2`8{1yZ#5`X?zgX9Y$jg^a#P1wRl&LmT3&0$w+02U<@K2t9ejWjlXLt&*$ ziDBgur_uT>XI`UbgYVbio^hwut{zfCy!a!|Ym4V8bNf2eYr56V>1ytj>06bUq!>W} z-o(J9Ws3-GBuSZb3*(t3%fd+us+6NWc5<0P8gef@-a;)-qwLNfv@99b1N}lqjc`uf z@*4|Wf{LYDut!UmO2#goVa|$_7NI-^!~6kK|I=AhsxW`Ow&?a~DfIOh4aiau4Z5RE74`EGVkrENXRpF_m4;q~NLBhc<#|m!X<=lB z;Z1L4Li@?8^io8A%w&5@_60hp<`sFovsk9Ys6}0lZsm(<0Mb2*a8m!pgc^X*mVU4e zkDU!C7C;7w*N0fe1&AoklXH<7Mb0U?JYtx@PKtQdh}e0ZskNirB{ZqavEFLEe-zBh zECtoBu}sMF_(8mZCcR3=dGICEXE0&SGzuF@XH>PEwoG;)g`~W`bv}X)D^h*bG1x%= zJ1cf7>@R<-1$&w!hzaaq_(4NeE%qkr)uly)!FeKVOMTiS%+weUBrO=`eBnJ=V7Fac zmJOm?Okf)Qcf-cIMSdzmq-1{^^8|A?ghAJETrk5EdV647W&|<8y!jqkVo*z7*Zra6 zI(#jNv}}YC+-iEk+m@t?=wKy^$nh<%^xd|~^-9$yb$b<2UU4c+_+iG!3IEAYccwRC z(4y7nSz!_L&5`6)of-=mx1#bEXrul`razXCqvr-*gz_Axvnkr04WLkwR%ALEPK(Bj z?d@^rS#Fk^A)Y?$NVSBNldMU4v&316t$0vXctppuWAi2*tC|ia1*-Vh5rX4_<2t+Q z=)bW0YZU%~K*O~kAiJSH5&iIMf`E#s1}X-ked{iZ_SaN`wdlfCl$mw*Dxt|1*KFKH zAyen|u#)YNmU?!bYOIbN@4ahXN^U^#okilPnLGu!Lq7MY+!e(JY3ND<9bh-C&)!kGhj8)}#yGO6J*036 zIA46SQ9Lr8YbuXF9Qg+2k-+S^zQ|mkI7)+(<^?D8hP&eq2I?>pVk9N?w@K3tQ4g^+ z8Gu0tPO5U|4^+c`k(D0U3w04#B2K^+Kl1r6{a`lwAe`*qM07he;oG8p!?SBMbDd@ zZZEHcIP;ECl7lyTpSpg!mfH!i0U|TS<0s>fnF!HuB%ucfjFUq>6H0=qxW=*YdiK67qj_s#}WDl$e|4&D^b$*UZW zeDj6DB5Jp1^%f_@LVMJp1nGy|or*{uzLcWxx0lsx#SHsnh+HqAT~VcFIFnr|AM51X ziYRxYh_IA5c@AHRY3kNjeSnrB51TqXcaii{zsZ<2g>j_pMj$CICoZRq0N!CV zl4sZjyV%nSFrjE_3h=Qsof5Ijn9j*A1mjkDLYaRsrdI2g@`6tpwh zhmhMYVIvf}$bfR4Fs}_VQ>o5G5w0QcV9+m4VGfc3ngxn7i(+*_oxEh%aLzWlirhC5 zWFJ-L`Qw4j2aj1nJp_d{BE^T;6_L%o@2`38v3O{Dd13?k4<@(lJ|Y*zVj^@rq;T`P z4nbX{fH}4ShS#EJg2%8Q^T>NFugUINaAD1*YVX-_5l<(v&(M$I-Adj4GGaJjKEn(t z+0N7j`G7&^iQ43C($LpQj*TaauA9Y3HRPHM57!_oOHp|zS_NEfoYYGz%*)-eKyv-s z7P+M0Ua>KidB2y+*#skD_+J|cj;G8W57g400J$rV#Cc3@Il4X4C6(DHj)07nHGdIv z{nGj;=?^jo;1j>U5R1Q?AFANjfG`2>|K9bdLeSvvPbs>gF%?iEK79WrdZbyslxE7Q@&anPm*Ev96$MGxmD=)kl=xj? z$f?+czahuMF=gJX>zeC0+v)f%rh5C^#b7CWyf_R0FdU0>NiGwB)_J%VnaANmusWoR zeQtz!CgwW}jO9wD0enBHhbAXewzIc^+(^fR6wHKi2_H4?=?{|=sbg(AJ8c)6@tZ>z z18McH)cnCj6i_eQTJpN1jKk+w56;hye%#lbQ@mfh_WSJd) z!MU_q1f-QE6;8DMf}C!PZ3dX2TqH+^5`% z7kmwUZLEQ2y$egBha0_8Z3N7E#-0-r$X;NeJ`5qs5_LMVR}(_S3E0CBIYuUK9)`?Zpsz9lN*HsBFt~90lL8DYN+ZF;lxzdt?q~<|T2^_=-iJ-6UKpPP#Bt|0 zgPJ%aO>!4nNC6?&7UIDg6`A{_XDL_MsgT`dJ3E<}9LY}GF9f4=zDMs|;S@xWjP6@w zf}vAsEh1yOL`am^#PU&8gpYJq_|R|`J=IOx7T30{?Kst@q|bJMB_7$>HgDoLYR!_ zr-UaKW>d*ko=T!`^onruWCL~{Zn1~ZC%@Mjvbvws12Ew=PzY>6zqM zVkMLL8`>Tl0WL$88Px#L?idiipJ*Q#m+u6wH)1D;ay2|*5wjj5tD1!m60H%|#_|rn z0^9+`D=hMxB!m#*%`qZ=h;#(Cib6=ZCvYq!sLxDe{Z7s|Y9~i@GyQsou}ffn(FPx; z!O0M7=D4{SFzIablEu|i2nNI!TiDTmK>i9&6&N%wy03Pk@jo&k`2OojfvAQ1|A`auh^WFS)+B`WS+OkS7B>z%2-SZ$Ure2W|nuEsSAayYd_LtS~o5#olv`#gXk0X zp5tXtTMCy3`Sq?)mq0lPiOAgJsAn0bD%FHx3MbYXCA08 zelWB=fkf4=C!)G)-{Ip#hUZ}`V{}aFbeIh|A|qUm7rr4NRJY74gCim zKvNUlbYhQ=o3MG=_S6`dV`g(hL=tX&TCJyuTp4~ri2s}&Lv|f!jC`^hAly z@C*iK^WBbex6yNcnl(*^| z$aAKZY)t6GqW&$ZB}ZM+Ui&n>d~fAyj7(D4A>k0OLaUe`Nf~39f?jl1#-xizM*844 z8LkA;&zFthx&6M_bTH8X0rG#4_Kwk&aND+MRlH)`wr$(CZQHhO+jhmaSz*O?C8^}* z+xxtG_ulP&=e^TzYb)!=`j^q>9J7zn$LJl-mV0L<3~p^(coI=?mwm(TuM}y1w0hL= z^H3FD-CLRvCdw2PMlVJU&?pDq>ILjU<-C{$|4!TLY!udK(b?IxV59d zoq_rUJ-_DRs@DVqHp;yBeem&{y?^hW`Tcl(z4{G%!1C1jo6H%Y-T9g zNOQ)q8>Zt77m@xxiyV`=Qqx+XJipSRL@ieu(VWRxEZ0g^Zmu2y`bXuqYT8M$Vp;90 zV}e&~Ql&`A*jdobxw)QSG+9WutOM>SU^n46`DubV1U&?lG2LuY0BD$H}TTeDGz11fxsZR&u`2hk!&kbSdxt5ehB3lh7Wx^fz} z71EW|nvmTay^jR)E6B@<7Jo(AtTfXs#dLJ8*)4X?MZxka{3-aBGofBFs1p-He&#N!WN|3=88K^^9KfyNI_e?2ME9xH+COiA#zh#1MJ zk)UF@3wYrb&=i~z*_9a8l^|GGWWY+)_tbt2SLlNac4=3jOXGvVdt(_9F{0H^OyWDF zlc%!bwYGS#lKSS;WQn%r(JVJp@VQtx{$(9|K+pIT5K@eb9 zL|<1(8R{rjS4-`u5aR)RIin?LbsOROS*&S)cXufum{1 zlUXr>FETGH*vO2K(E)oO>1lH2NKhWJ`;~+lPJ14A0*eKJK#&X^vDhyxTtox^J%<14 zsB;b3*cBkaDsxj;m~%w#wOtbKG487!S%xQCfHVxPa2Qd@kL*#HE|NVX(wUYYhPiP+ zN}A_UbE^;PuIVdq1DjbdGSpq4|o}^ZyYR>y4 zW$;c;-nKAkwjj$qf@I)MCzza@%H0%$(nhUeGAzoNP`8!|as`Wor>L(};VyT+@KCGP zrxRgF*O~~eRuP~r#MC9L^2Cbr#-)65o%oK0ZiuHJO=B481CiqsOm$(TUDkEoAlJRm zCk)rK$c+{@Ci1g8VQAL;(Tp&ng``;?x{KSBFXX0f6Gr6)<8kwN$xaVn*a_=xA&6H{ zuB}V*0DAg+Bjg^kY|x*7O!7|G4BBviwZtpFjPCzFN%Q|*lK%H8l>acV7cww1H<2>& z_^%mX1)0B!OrAQoiDZL0O z<_|E|E9b!xVP*#dXQID$PIr(C4W+fGx}JNPj=%K8-#!i&&AuHcH0c|9!#iXziERji zl}Q`BWHU0*(4T=_YA&ihwp?$uQ_^_IarV@oa-^Kt2Fy>& z{J@}vEWZEc`1_g<@*HSHQQqw177}agqQ$DRiPTDyVLpCa6tCD@z^kH*=hOvsdl*WxxgBEee^cwhG&S@`x*6G9B=2fwd(^tj~aUVUG$V--EUB;nVjX4TJn(zYn3pdCX!K9LWVOptw!?gd28~)b! z=5KI=qKTP^`#+Rkh#CHQAafMIET0+RePmfR)LBX9nn7C&qR{w0nebXxUB;QX7 zz`3(up^iA&UX=#K!!0cIm!^zeQ? z8Q&h>B-%R8qf+A0ZUXB|+mwb_i5xsH=%Iyy=cgD>$k=&g$@niwy z)jNScVw5g{Gsw`#lqj(aM9vr;(HAyb_-aH@bzwI<6I{W5x8a}sC&+r5b$^6?gD${k z=zl@Nl2S|*L|0779gui{qi`ONl~SmEYpkGBC#Eri`|D(^@#U!1ej#g;|Mq13?VixT zC#!#v0s2o&scL17{3QZZ%GK56#`SC7RSQ*}M&7(@+oWW;P^X-qqFr4x9~1;R;|g{& z;BtzQE2`T&=|)N>Isyogj;X{#JOn`jT9ZyrJfapJmyWJS!0@q~_JKN^BfELo3PJj@ z=5_qjYvxa{SFh96_UuP5GqgUy(ZTf)eyx_l?k);&J+f(RYHC8 z&1Lvz&wv-_c-j*Xhit^TL1KMlK)O>5oU>(0WXF2jGL6{z`{!o+XAxp6l>UaO(jv|B z6lD4Ox@~&Ji7ruvFinkI%oW2F?{MVE@6Os{oXPZWb*%~vO|6TCTpa76he~_+B%3Nc zCXcNq2SP?;^b$rPO5B{*o#E6va3_E-)?wybUbRsnYhQurpfMr4CLXJwOt|>&m{m?Ktx2(>~M^rE;n;lbk zsV_LKo>^cOA4nqC~|d=_9

    QZHj*2PbD8Of4*hG?|8I*H4b+U*8pBDQ_eP*Dcm2ZKmTkwsSVx2%yb z>On2Y#}8}veP)sjZIjH20^6WX1r%w*UZ+O7XX{?7+BSzL7Yq)jg4$*GNN_P1b*o83 z2a0BAMHVzCJ&gN?qzO~(siR2*ldU*XK-{=Hc9$`CfGCC&z1m1md13>W3sB|t5pH}z zzL+S@nK6h%T(n0yV*M_yEii^ctRj=|7>y@u+BiBXijJ8m3rg;z(J37P0TDn&6ymX4 zgZhA%I-y>yuhCCteqc_yZ6l-fwkqV8&!mHn+Vo0u;&i132HdUy2E_#;eUW_Fe7vP7 z^G}YEIa#Y*G^CaiZaMVM5_3+Sc{>$}Er zIN`>x0pdEN+yi|zc7ncaHfR`wk%vYp_SF`_DC47DGL)b1xjJ z!w#O}y3rNZ zXhOb$Wn)lFn!Ubn@&y6b{ZUuYONp=O&CMX~;iSgxUcXk?sOAw5M>p z^`{(PG#6~5o!~`ejq{Jf*aLOoIF0KFt=ZSV% zs_1hL%hOs%X(rg;zqoB6$K;54$lM`QU~hNfDTSNYrtCmQ5svPGjINO$?}h&WDf|%c z#~vVb1xQucnc~H(0Au1jguu=t;&xWW4}A}>6&z4Iu{uqrC24c|9b8;MHjHorr2T~P zyvl_l5_0HvPpNqJ$F?gnljr;FXgPO4qdfa=N1)_BQ@94OGaN|y43Nm0XzBiy;6b>N zHlran1`F>IEoQrmr}iS)nDDui`#KuAiJl?t8|3nZ7374=!mZZp;5!a$!*xMDUVWN1 z8cz2Nh*` z-lQ$N7TY47sUOX#>RTuBiRa}2s{22kj-;JTYDvBtz~IpT9e5W0{|BD`^*u5-a5OOb z`r+SK-jyVjkOa_ua5ABZiSps)@oUQsV%miX#3PF23luHC8>WzDNk9b+N@q)J*M7j$ zTx;8pDoRyxmzVsy8vZo={rK%Wf;Q};-gDMkSb^nsQ3`l!SJ4Cj+3?8$4hT|kjbcJ$uSiJHrb<6*`A zRPe*dP_T@+G^)3i=*wNS8AtDwNeR=b978gRCKI%#Zh;YPP{x>S6cwQblo=yO{HzpN z8OXw*#%h+dY!^oYF-`_^Dfg;_joY0kXVcj#Ad*ou>%Nv~5z10zr!h%m6}h;0Av(L; zbfVj?Lsmd2(ZD^Yyee6&7~+O$;GV{yj!0LHQpG*wmn7BwS-OLFr6YNR8(j4X$q@!ssK>^uy#ME45J+veRMUZdK zCu{iyTBE+$bN2G11WRY)dw8Yi&bB(6TXIT%}26WnZaR#e-+ks$=OJJ|5SyS1xG2HFWmaZWEI%XWY7va;KfMFg{yy&>{!POy<`F zB9`gDkWyM{PEiaIfk%A=Ai?$TZlqrF3%o<<^+C~zhhGN3?dGXpu@lVAHS0??Y0vUJ zZ*iH8=>72f0NO=QRgTtoM8|v@BP}zed#V^Sk{o7!q9Pv(z}rz|_Yb1L7F1v*0W|>? zLk~To8HJ>y$EIG<`BB2>DkB6}qf$VJUSK|_KaSYC?tT>^X;b1HMxfv#(@(G3hV4+( z^UD7Ma}Xet+6*z4&~5vYiUiq2o2~j1PM}M@jE*d)iA5{ar0!?U&EmXiulZ^+ixf-o zopRC#q%zL?>mIi~b}M4_*$le~mjtcA(rDFn$ppm{%eXkyP;}2Z=J59`g#P-j@D^_e zNz}MQ|31ffA+X!F)w)x>FxKtVBiX@Qf(Q92x!EYQhnLWcDauef&x^Ba4@8ENyd+a6EzJ#F60S<~OvTl^ zs+;%Pd9e&a2Io};&3AT_<+x#=QcBKo7S2D$$pq+fNaD54Rl|??9ZS2(p1)tv#9*{4 zRS|;Syver&t>S2McZ~GvH(a6Za;9VmN8FOIHFv-ze+g1Xmo@W z*AmGjZLL-jUkG15o3{Qwfw|$s#1Ni|w^@Zh6-$c!d`8aojd$2@&VQ(z?K0Dzu-o$I z%Z&nXJb*DF!8Y_;Z>rWJaZc1GC2)W(+mf%6V;8?>q|sUG2!Wqd4pbz_e+w*U-cz-r zaNaLuJ_dPkHH&u3gXLbvg2%pMB8$H?0lD2zXP~jNbyw{H3Y$DoL6 z<{-PP&Qu#i_|DZq-Pxc;bKGPuCWh)&&lZIZ3wiPCLqlX_B~+@+qw%mG&M(%@6oVLJ zf_kTHidmh7#QQ?Fe2lgS*B*!Hgg9bb>7l9 zYMM*j<`7YbOD5GOvJ#nUAnV+A4syHZ0$XXQn0Yg4?yo{}1^-{j0|7H=-ts zM|M&<07_1HvxYa^pG!8q}*}>cTFiJ)*(U0YOh6pAUDX+s9{TxASG?lYjHM26m zq_VM!E^tc@x?du~UD|V%0z6ITTN6;^Oe3%0496ed;q){8#r(c`7DcJ}bItn$^@!ZF zC~hd;Vl|66qx=x;DoX$J?!)g&(cydj=6>IY#M*y!k;1`;Qb-(Cxv)>}0>FOzhx*%@ zxRNUE*QEsddQ$)XO%(bc!`Xk18vRrB;S1FM*Nn7^mK>HDJWpQFfld~vv;hH$b$hTp z7IdigmZQud$q)eKs|JeK^k_gctI$yLiYZ?zqf{)B{PX>0j#PnIH@;GpBt)`isjX7+ zQ)uUvPV%^kq8K2v2tIo;<90N)p0WN|=l5}g)tw3TdpKe=Vb>^{7U0eny&8W0VRqyx9MYnq6ac=4QK*Uw_B}$4)w*>Mk#N{MQN3 zcN4-q1JD+xSgReHn!2?R5i63>1hB5Lh-{S#4x=uO>i~Z~#9x*DFc{LEy1M$W!-`eE zfsS*OsgKb{q)y>%?A%SKH=6f3CZ|WpaMeRV--;41OEsd6VQ3DeLYSqJAE%LqO*rKg z**l_jPLhy0GjC#JIlBvraA7#1nJdwk7=lqz202CPD~+I6UAm*NI7b)?3>8O_Z6Sr_ zM5x_CN2f`*qkCA??v7MP?@8E{vNt3*v2v5#RHV<_Ly99efr{$9r_fAXRXaTpk8pn= z&nMMdp^-YOHkjXY50-Tvsjgf!lg)XU%Gh@6*w<`vN6{hac(YV<2i#q_@5h+M`KOV& zaUWzV4OOe)zIGl!$`fngD&bFCu&HMwN{EtyR7RGhD5auCytXkwnd|m0IQ^_2yKk3F zMsO)(`29_zLi^2Y2PArIQbJMXp(QPTwawf{^(RPxRNZaqSnK0Q-6@sLyFqyXTnoft z99T!i`*(}@NzJG3x{E*WRs$Rm-Q#LR(Q1bl&(HANJa0EHZ5M+(HdjKwLl1zat+52Y zsR$Kdf>fZgAdB)W-=2CjV>4x3fO?&Mz<%^3E%`$$0&5|mQOfHvrBxgDRR)j13V5e; z@Z%S}ARWqqyaSfyVSWKz4ND73VGCa4=b&A{L4}~6eM8{8a>d5%dmCe(O>PjBP0$ka z9bLWA=#@!GDvlUckkx3rm7`nvr&`q@e0BFbBw~4eQ z6=ZhGyh1Tyc}LBbJ-%>!tJlv)*M1C&r6=C8qQn6i#YnsIGoX6JGR*q-r) zYs^t_w(cjSUFU|GIKntBMS*j~kXrIHq?;E(9~7xdD`2FSVwqj`na&1|k^9k>g6Jqh zN0-9tC}Qm_zP&kPfIFk`EwH>x2fc)d-eAS-!*#|IWy14jB6G?_Xm*llp2nW!7oQYw z5(+XErkM_-bW$Bz=u*#n8D^vkhhE)swl)glZP=&ygrlh4`|YBLy!}HG%2}(;1?y{o z0{&|o>;L4U|2fdNH24>wA2L4;IY18$e$%yEC9cDF1j|LfIpgK8Gl8n^pktzu(9=_s zA07%x688Q9Xtpt6ur=Q@eDv(gx+>VZ-k3GLu3k2F!W|&^)j=MybC-$l0Nj(DljcGT zA&^;}waNf*w!h$!(u9Q4r@Rkq52H)(3$22hZ7&T9)&r{AnEJ!NIeKQai;{%V(ZpFA zv^wJtE z6#2i2g}w8?#KPw*7D0c-;!Xd07kKOjwEOA;*d4$+#kd(g!sz{0;>sCevMX>u$@iyz zP=9=jf<4{tJ@ETxZ>Mgjkq7>9evOoh-JyjQwdjgNm6{)>aEeWb4OiJsAbc@wE@YpE zdIAw&oM3I7OpyE`vddWcZOjX@VKT5#zq?otbA32Qm6GByG$(_iv>6t~i8SKJg2mg) zD985lYhfJ;)phk^H1N2cWSG0KoijJn=X>`n^SV#Cw+5{oCv)Rjat7XCAkxFi$LufJ zu;~BGxR^NoTU`2K1L>i`cDo|J;sPH8*SE|B*Jom&g1T<0iaNNt8L)eSiUd1n=hqgC z+AZKCVz=yET6R`&DmyBamFm^3%A!(n#>^+ff<`3OH7w_cS`WGDxarV%13lrS<5Ey- zhel0KB0WIUX`$aHkE}^Ch}IVr;a{c-T7+YwSd}3&df=a`AS$VB3J&eC^t}gKv;fW| z2pz4|-DNVWJ72}ZEQ9nU;Zqa)7&klhHs$pE_tk;<6Y0CjL`{}b`w0XG zzCx4nZ=v~54vqVN{FICS)t9ocv;D6(T=h{pwQB6wDtgWF)(L>kBt95PD6NF{u~dellewE#j{PQ{`_>7Sy- zC%R1wvklk-yg%8#(b6)rK3Ir|N%>q(R~*+roo0BRy|=sad>;2$zPasX24Y$}=~FN> zSfdFE?-85@$KpV0&QqL&zn~j?YJ*gyuoD z*;uWWN>@OWYX)%}Dbl1jX+G^Q(Ui0^G>k71gjm8lQY;!4Cm|6xuoB$#auU=vP8YRo z2<8HATSkFJt4q_biWT!X@8%p_QgdmxSw)iBctW3be6U*QGgXwm!o!j}{N32j><<3fi)X7)gqg zu&%`!stPXX+9w7s`TcJhe37~#NXR6HuIrcs3y07aC#lB}0Vxx9R|iBc86 zx)7C0WhtTn0SiE;!X0)Dpett&K?9VjbO$p9Uss$AOd^uPWz@G0BBR2EM&04dP}FW4f*T#SxfXbuY(+H!eZrLoODo7K zjWii6oK8E!yz4#RWO))3>8+M@*oQm^mJBmGCB?}x^QI$Pg1M;wh;pOr@|DY)omy%FY}X$75)ggN0**dhImRYY6#L2?FcS~^5`oE_^&QEF4- zn&xAARKEjKihj0NicpUl-6q<0)*vVvN=#@go zl{ofHp6<$q3QH9in6z6P@8-v+wAXgb5glZSb8*WqyVU7u2R0;$FLUhpDgo3~1CGW7 zx>{IY(e()j_TY=e0jc`O z$TDn9_iRX@!_Pj_Pc+!yQitPg@pPYXNWbdj@t>JiF{^Rpb;i^Y<$4m~^t;&01yPfd zhmD9b-QD^*v+$f;M`9BfPJOj7IfS?vZ ziC`etB_(}Yr-tZVXrG|RLbN9ajU9Ii7f7#Gq9rTBevsZwz_9X2eF+Ppm5tFR{oz<# zv=1%^x9lidqI&LMKPMWkpp`yLe(SlL9HVlX{Q<-Rh2{DBxuLaB5`!7A|dHA ziwtR|`roI8Nu~u+K4pl-HL`ylq zrWwd`#;aX0^cGBc0jTVmDaYt7D0<7Xyae9vm~(u{Qr(g)ZzJ|n-^Py{=PpfaoauWX zcQbceys%@jgHB%PzG=}jT zF}`Q-twR4Wc}YSvw99+YFYFuTxqCll0}q+N&Mz@&L#agy}>9#Dedt6j)sxTtO&oPCTq3H#R?mvtV9x zepZnC)y|-W|G$II#{XJI_$0`{2I0epJj-~3!|7wP=`>z$0Jjq`DiqSk09$nXC@hgn zXVv@v{@MMzAXK8rbIxHqq&uWN8`Wtl+g-U{}=vC`)?5<|KB0RznQWUwJ@Q%+ zK%oDiG=4YsPh}vmKtLV8djz9#s4;#9AOiqoi2yla<5edzf9Gp~Q`umdlD1ov;iP4sdzzz`RGgx-z#n-;(g|Zg|2ln>tZi)F=fg*WAKuv8|yCd4fL9 z0cz^dIVDu;@L)lpaWko6{Sq=wIzmO%h}ILzidfZPLT9f{OANx?SisoA2_;O~$@>E> zYG!@1Dd>n^{Oi-(H1Nb3jf$l;GpbB1+Dk-Td%L^9t%!!NgQ?Ee)%RaOu@SfQJ`J)Y z^XkT$KGTWf+ZS_*mYE&n&!5MrSf#0m6A_dFR6b~+^yg=a2z7BJ(;-6_?H-Gup>1yV zs>H~qJ2X8;ky5E4s-ci)N%LociS8ohoQ$U5L?mG!DbK2e#>F|KB?%iQh}StTs2*~( za#SZZO-Dg%pEMAc3)D>nG!jdxpiW0zK<=v^6DN@tHwte9J6z_Syc6q6hJBVRBgJhP zG2=*>vr+Ar9XZKkNydLx9N(qQp5?csh#d1--G`?n-jX|mlMTm z!qA<%W7L_yq{QkSsNk60V&NEcml{#%uHJ;kvI$u344iZNM(v!sV_l!T@cc9h;5&IC zN_xH_gZZpD@bS*y`{C>z9_RdyfoJg&6&rUO5eqUFEce_0b41T&3BR-mm&)ZG#&7io zF86m?=;!=RM(pfuNUZ29yr8_?TKZZBd%8GjWWslTm1VBsi(H->;MtUfOebB+s$^|L2a*Xp zUnDoCvN}EU7BMGdIf%!u%Z~^Rd#gzuJqk51vL-z6tA_m-;MGvQWWsk-d8wc_grpEt zFO*G>w68p@!ZK_fXL`hK)yksM5Gre8h6bDrTMpHTr6brC$ANTeeq-2}^&IofaLb7p zIrk@8tKANLKTaaykm54o+DVHraVs}DqF7(O&kq{cnL2ev#llfZ=lr^Nh!aP)P-}Or zduA9Sh^7^U^0O*sFGlQ$CYz0x<@DOXGkT6MxWW>3mF1AjGUA$~vc;L% z<$8(Yo2i3t#YGx2>l@kU{t{La_l!OoImqqJmv_alo$zA5RgR=;VuJ5SKdOVcaDvyX zBxB2ZFO~Sk6k27Lhm6K6LHx?ZjX6dI*qbxMRFt_QtUwfe68+@OBg93xQDtv(&0SoQ zO_1hUjB}G8jn9DUKG#GHe5e7T_;uY zkY6#bsTgKP?>RNwL0*%OuCOnJLi2vz-UzYk9WN{4Q1MNgm5!_U$jZ+BMyjWOM{Nn^ z00V-mKqu;{GZgj;C-mZl8$6xo1@HRf86Vqs&;fqIZY)UtuenNJPk3Y#EJi{{EOY8IG%C1kQYnzMX zj?BuN+nz&%f2B_pF2x$uZYUIPWew@TI4CjYf|zS$KYMKZVPKs6dcV2GhRnInmUp4` zO@~&vwHvI%5#e>hDuJ$U(7prR$OHoE7vfaB!BhgmMhAL9bIvG$i0oEnG=G*adTN0= z4;B6L!r#2CiI;C2n zsBYZ(FUyS%5EKi!NC*e;TiuQ>{7V?;V4ck%*^fQ~=NZv7noWEhn5WRAdq@1!ZY)4Y zR{o*pLp&Rjgh`lx4X(^EImSSgaVm_7)JOY&$3oYB3uma8CJ zaZ;(0J%%FFDx0`LWcyPgmCe++Xd4RcLJ{lOthh;A=0LZMfQiBKvc8L~5RQl&7HZan zj?7|hs)bOiyCMXfha;4S1J(AdOz=;)-IN^>KM$;t@#%KOpRtY|p!dI?9dfopAv=I4 z4`r(px*BA!`b}Ru19J;fQdbG{x?S(LZ;q2ziLg0fC+$WDzrN)cb#jiomYK7DMrioU zTo{1wEi;uf2n&?$Id8$_sK(;6g+QO72gkQb%obydVJ6E6q_K2_!P{Sk@{RU~V|vTi z(R68q9bvdb^c;h62f-59+4k8}NF_~j?kqd|PWE)7ZbRgF6^tVjIDO0cW%a&fF-B@Ei@;b0$T)_`$U|bJgJ(2@$Up;Rq(Nk;L1gG5F#afgcR;;Aw1OC4 zr2yLLgSnFtJfg8qv^!w^4eL7Qh5%}WUmv~UsI0{{;Tu|5j-=l;7(LN5hfTqLA#h5P z{(2qswc>Pox3RKV-PS))T$jPzE#}aHbI`-J>j-iRY>MH?#hhq;!@4H@GS(BoeR{w< z`F63JyxcrE7=4HA%_Du{;L6mW{+ zHD>|Uc_GlolWxEcW5cIA@r*e$92Sqa1as_4&E`DY$77EKbumo1AzPMmZ`?H6Jl~Ms zX3NsX>3;v7e}&Nv*A~B9?v=0DK0k)f&dM$lsTiy?r=q?!5v_b6I=HpF2jkY1b%hLR zK|jXHwFL1 zes0DF8)WDx54j1mDhoN{U-rlh!_w8^4LsY~Z6KDe8pt_`!C8|&+CI=PP2_|Iu~Usq zij@(G{cx=0-9#_*co2|a5gRQ%s%wm?k!z1a*HLj?nw!wCr@13ROocJEpA=L5@ZCGa zQBy?de%eyDXh2R5e(ZT(!Z+OZj)<}VPs!plIC8EG8O*PQ{slbp@Hm|kOQG;0y%t-& zoLQNI%rY4ZkP@L%$z-dj#+NBI#q1Xx_IW8Eziqc1-2V~ zcThbsN@kf4Z&}|i4TJPYMIK}cf0GfxQqlYSA*nT}dU}OPTg|mA7)_NXcOnU*(IYKC>2~G@w$D(CW~%&?;8lq+G_-YI!ZK(XDB!QP^p;QO2^) zTCPdHvOMuHK^bR4zKMK+(T(%M;{T#}tiq*FdTBRNi*n(m0SJ+?Ew`0b}hV59o zzd96wTu624yh%o3W%u37xrT__fvMY*uYwLUTHYtk7|!iCNVIy-$zX&QV+6He-&huG z!I0bzpgog4Ebp?9*ofq{#Cn}CnNj0nkiHy1ajp}q>}i+097T44t5xOW&*)6!J^a3a zC|2_;`x5pX6hBwWjJAxt1WF8G9L{gSi(=~M>x4T`zRuTI^j7`Z8{M3)fiR+2bROcd zl&UDDs3mvlwdAT~1c&MFw+j)9J4}zoidt$<6%)!9r@D9&c{J~c37RDqWzJma!JH#X zlqH5_&Rpri94%UuCH5zC^@NL=M*britD;>PriDQ{ebg@Hc>S|kk4(C`|C+2i|43@q z;oQoQf7x$}Ra?UA1&|;5dOb{k#Xgl5HR{54N1jbm&%N>ndf?}_nkq`bvzFZ+nrpyDGv{|*qjE!$^*%v1G4B3s%Srg#hic zycvKv#u;YAY_boLJ1WNDv2XDBuwXSZbJ5OYp9uWDS0odB(OWn(PWoQKg12+oor`gi zX>-A(c{oX63}23sUU72ByaoxfWhTASWte)p52yw!)qJ}_`aFVjI*LWpZbKn1#R6_e zoT!cV(m-HCX!@POFvJ>x}g zs6j3(HdG6K2OAKA4RU46e7KcSgCbVg@&=oIldAYe?Pz6lmF~XjkmE&jewn*sSET(e zo#`Ov6zR{P-Zx`wevCi#*;3xP%WQ17TD$LP|5&W~L;Woe?%THs+<$G8{3l)X|GBdM z&%*zo+)$4?ly~xS%ID78G}WLOM8NkuV(wsig5WS=XaM4U{5*HOFugexUJ~7SA3c&8 zDXMv!d6ia`O^scYIavSUa%ELbl&ea4tIC#B@3j$QlC*D@ zv)_;D>*pM=nT{{XnJbRxTrW~FSsZWZJ|Kpj7}fXSept4vK3TSz{v6r&B^a(NLsz;W z9b4_-ZCmO-T+(aP3o~2lQ6A{m^k*kB-#t-ODH8*_rfZYxyoNXQ_r(4`&`%8R{{2DF zxP~|ML1O4b7#C*t{{406*v9tZ{YB6p5&cHcxMnvXL1Y;3OhIMZFD!AN1G^TkkMu^f z?6+8?vGljqNV6Qb-B?i#n;|=QFF-+P+w4gss0VJe?^a-!=Ok>Z`#ah0>k(@1zih!i zXQtFJ-ov2kZlCnr_Fz!?&PFJi#O)ZLP=k!Hr*@o-cU<>y$bS9`>B@PL%k`d(c+PnV zLh?gSUqal(Tsj|2nAW5&6|-daOY;rrRpEaO5flb*F;|X*G%lS0tew$Wn#05M1~jnj z$upOR7*@6D$JNRw3f#j?%N#S%f?&tEwDd+{W+VbVrJ_t%X=ccaS66gY#5!Q@wJg`T zFgL$qTG%s~6s}WMX=$CSveZ;n)M_ZS)eg6%riCLJZ~R!eAv0#DmEWpY=+dS-j{prc z`LG|`L5esjP}h(F(kT$>!fd%J0m7gOn2AR{kC1))t&{$<92LqA_GPj%#vtWq0n%!n zni%1Rs-nYbIhsoBh!ESfCIU)1HE!oN2hp;qM>U{rk#&>>M9@=d_6WwaSY;EQI5r9u zBOrg=c2V6Yu!%TkzLZPM8CxiXf@qP>o_Mql!VPNNfRYn|)2T2?a(c5@(@)%! zb!*EO2q#h}{So8#z&-gg3iEtYHJ<5~U{23K0jY2WsT1Z^;!%t3ZO`)U31KVs{8sni zO^!A)czs zJcu`1Ry?OOGnxU|e!^sFNLMRlIc?)Y$JIg!d{fbMOSN_g=~@@}F@)QxIRr}10!5zk z&!f~;t^1iA%0IPJKJrmm+@#vc_E*n=xp@dw`niABMV=$5+!_hzyzmeE?X^e3-6H5b zA-J{UHyge^e6!^V74FzXk{=X4;xaW z19kSOes|I)3~7DG!kam%233@#A!8M31J&3u6_MOAv@uL?S@WVoe=;c0QaI_?K!F}5 zC{;1e)BF%a7p-?sH){AJCnohE7jTffY7r6D42rujHn%XL=I%mq6eZ9A3qwvLCJ;#P zg2@*Bd>#Vq%auO?vHp5SOq8qy<&hct&;c4mT$Vs3MV(ER=^-|i=`sMsVMEzOF$G@q zijO%kdnVh0EYs}F!u67prYNBKLjMk75%g_J+rmL1UN02|!Xrn0DU7Kiuk^}|of46+ zl&q*Ayot4LL{9J5Y=?kFhm_6`SYM1CeFTGbstKta{ecSO%&ZZlhtN5j<5{hGJ?9x% z>}`0PT>uBO43elJQ5NYueVoZIU2xmLFAk+yC?)eNVuQ8HJvc6%s633*NJliJbpK#? zN_n&${rAz*+`Vxxv>?SapXiXeZaLZw8lhMvj<+ z1?p-};Bx5%Q#b>53>)8#9N*(5Dt`_8i4`|Wi?m>ZZq21atU}VP&Cgh8GR4R?ARN=Tv z+_4<+`aMKsrdM`%6cJS>jiSMArja_WeDI`^Q!N+P3 zuXqb9PH9qC8a3G8*=?HZW8suCZ1XVai9Lprqf7|!NmqvuE%A~E0Y21i#hSx)r_<<0 z;-c(?SeoG z`UF}So5p-%1Q@v0KUX=^_Rh>bbF41M3E3*~EtxqK6qU+YGZxD&v)J^9BVtvxBC6{}*NN z7+guew{6da6Hjd0wr$(CZA@(2wrv|LwrywPWS;Eny1A?Ne&2h2=r7$}y}GOZ_~ATG zvHEQ+igTyJxDTi?AIhjLruu%F`ag6^OWDKVankkMGW!ACQC9e4HnIh*S(Pb9HE0x; zlE(w;M4rYNxK`#ymST^b<`2aQ)+DRfut~~uFLvZ(I!VLe#8FnLV>($Pwj8TyTF;_h z)A3m{^;DNP$yk2pzXB^W+V&tQpaxvzj6<0;enP*D0T*Y&l#JFW%U-zwj%Nb*CDs9?VPT z?w(7%{y8uBCYTpN%v*o*J8+wkjuuYC(DU{8-J<@3LS$n7?&Ww! z!j0vrCu`VNTHtlVur6G|aZ7+(TCw%OCz36e;qt?nM@@)7t|-YaGEPVr>ULvN2N%ow z>-%P^M!6Qpbn}+f%J;}Oh^%Udls+rlN4D#tPO4p^*=3Vm&B%Qq3LYU(IQ$B0-r2#i3GZm43yV;)uGBJj+#}23MQuPB4KOnJ`ZT~9 z5+1VXYVi7`&{i1wxM(X*{n6+v(EU1fd)x^(gkVq5{n=vAbP=WC=9$v_I)>e;wK~8V zf-6-J;H@5QFw)CV#s2QF_RexajAt1VG+0)+s)OY408H z+0?0SkX|9b4So>F+^Fv1-xj*5aS`Ic)58A_XCsOZA0Zx0aL9L)kU?7GpQiD=6VL2%89^j_9MHM~9In+_F+DUp1e?8%I z3;t63%*R8)lPDX;J619@a_4><<|UsQOB<1Jr+k~{CFw=8jpCc+i{zUyGL&+sXfN@Z zMsbp&Ko%Rmm&h_ijXmymszfplUBuU(L{LW2aHuv!IYNGKoLnztLaFSKU#}&j07ytk zx;Kt?$eUEwFz&8bK_SCDP%4s?QDhlIA2)U=uGh}a)1o#dXB{&*bU9VNigirlu2(uu zxlasm$h(W=Qgl~Iro4{89uKMaKf88*{-y3K%(@9lYP{c?R6C4dyv0Dfte(;0H&L-^ zI9S@KruqEZEj$p}>;K&!!`ISQW!Ta~o zM&+s$*;JGhgBSAt@f*Z!h(Ip1z*iY|AzyiP9lFN5$irO`mlVwx9IRq z_eI{xpP#(-`8^94>wyV`I%!XeUWbPf%1O4}W^CfRQOZTpn%iSch76zb2-imGFMSVs zpLW~!g|Bp(AG;4l4Ypp*pImP^E7l(pz6A91W#GRyU^_a2(C;K76Sn(M?@%)1TOfqD zXfEz#AP;_r>9~Uj#l5X9Zk6mF>0R}z(Fm?4X*uBtA>Sr*|8m4AWz})|F>zX|$_gm5 zSrrD~+WLvXE&g(zJN@AWQ{1ezmQvN;cuI{r^-Aqrc%e~b$g+hP8`b-=9J981F<^+ z+caXmvak>Ss+exF9n;Qf>8AL@Ul}^k0)^h@4sQ3!LvX*}+8a8okAyx+ViG>bhT($8 zsIJ!=qQ0>>wtQmJ#ouy9Ry^85Cx}Dn>l35!!t!ztyIK7-nv#LgttG`Pv65oosZ3)% zV_b0-knv=xS`OQ{m7I~%gBv9sVke_%e(J*nvvoTXdxyw&Skicph(;@G;QtOCbmv&_ zz-Uuf>6K$;7qFIW=>n#_Q8}k-;SBcsAxl~p*xPh=S!~-t2HiUX>*LXfrxfscP{^#< z?@$I%6PI+BjAKjC7;qT+MH~)=9FCb39&Wr~&}L_uZ>wXJ38i<3UrAJi$^)`?U*24q z`C;b%gA&Yn&S__JMSR72M>nlS@#488YtZ5~t1}pB-P|hR-1n=&_RFW&vQwhQre%o=t}wRhITr zTg#&&?`XA(dWX|}haln6+ane;*ctm$Cvi1YH6}0p6im-%bUfnRZu>Iv)7|a{ZViS& z?_zj0(vp`C2@O{aU7DA$rbKY;tJBFsLh_SVCpd>_y=B@sbsOD%j0a#tVbgSPx zk-b4}9@+M5xW2cnspk;_k2R^B&G*uBR1Ivm*v zY+?5T|hvkpne*lGr4+joVEJD0tOY0?Y`9aPPYG{Q)*K2 zw9_(1{Mp7_Ruq(vG4vzyUt~wAZ0clyZB`yf_4>q}sDrPk4 zst+W5-*ul)r)yRyx#{s!*f`kGC$6$e3FP#y2&>c~ zA9z&A>;ah`9@cmikM&fvhgDznOJV|dR1}?h5PLB5SG6!G(_&b+O$&1~Au`^VaEq}8 zy@^GSg8Be*FfH7%rm-aM2QE`%(syYVB3ig7OO_OB7$OXXOC1ZlpodV^2C3n~l7>o* zOAOSmFkDH%#MQ<2i`aLd@`x}~q2Nky9uK^Ym)r0rH8^rwk|1Ub#C#!so7Ia^r92zrkMZk}maHt4oDP(5acYsk1B>@JMpCyr2?{40Rw_2U9h|U$WTbVE) z*lGD~6z&GDXmk|LWyy%z;?y#z!8A|zl3b}(&3c`|u@TQ++Jxgz#b==a=~*W2!Qnw}MB9ENVz z;aWmy)_S;+%-h+Bx=^3wgMiH$6)$l&q)FfLnn^*8^oPo#e%D%fa)Eooj)sPPf`Jtk zA$WU*y+&_uwhaZHaHwHrZgQ%E(RB}_I}RP*uV6xeU>W9F#qeN9}! zsa<+I47U$8emRq*O0R~{^c{1`1*@hp!wToCd7e+G$}EM-$YzL>{G_@UXzJANJ2ZW) z8cNuH&KT4ao{?meDrT^jp}X9iwYo?pQwg@EQYd~E9{dja8G<>|Lz3}QQ{wL{kp5g! zEOLPP2W2rdvB48S({apH`^Hyy46@rTT3Eq-tW|fsez7&Ai&+iC8{l^k2*g_B)#nQf z>#GM_&&vi*{7k|1Ylkb7apk86vc*Zi`NH#I3f~*{uU+<1cPtP1>W}F@Z`f?uMLFR6 z84(y}GLEfTwDy@Rjzf(Z?Hu8zykIBQjMxLz&pQH&C(JYU%5yvPYE-#H*47+RX2a?I z`V{$r6Cc5B!K!V!Be~<{EXSD-j;Xv)^~c2dFip2JURNgmYXQgX!=Afi2+ zb*J8{PIJt^L4Hq%Mi|4Q{cWtsT=9E;96pMEMRLW-I6?w!r6GxKpg_aTOiFE7_7L&| z*2oj(ip;d5*KutE9F+*IUM7H0RChoB6#=Ix1^w5#ZQL!U@GuN;YfTDB+xxEo}UQym3IGSf$?3um6xgWH(WVZ*tzw(frfVU?3gepD|a`Evtk6rB$ zAshLs5PABd*GCc8cO)lZQ$AyAi8tqAsoUaw5}@MPP*_>3$t)@&pr)}@o4g{LyegW! zI-0yfnY@BAeh@Q$ATxe2Gk(B`oVubFY!4Lj+O@yKyUyg;;eMd2G6qkoX}{kxYEa>A z+6fqrQR=*{ErI&$2=c^4LAH0w^4$VB*0PW<4;GUe*ajiX$xyT~u`X>kt2(kp2IZVx zHA6;j>=x;`ypT=hP!qd?NA#zU>de6~VWutdL~+WyNN!HVQZ}w82b{;L4^fYxjwn^q zmfHds>wlNXl{t1-v@6&xMm;S4TLzfH+DMxA+5^}_^rxzVq2Qm<5>Io3+$DY zWu~V#?la2d6%PDLI?(+4y7CT&azDPZh=Ovgd=^_Z0=Vt>mNE>P@+3F4s{R5CW*kM! zI92D#a+ucK>XBt-TFvv}rXeqgJ7ovEnlKHjFb%EUKX>`6=Ydk2K*F1lEo(|u`EVaY zSvpt5SC@2D*7o7T<8^1?w|NZZa}>&tc>N8K7ecg8HaeS;AU(KezJGPL%8_-vSAT5@ z(!L5>|1Fn8RO}G@YG(bf-@hzo{nvI~-@)-e#md$((y-t8e+KEkVe(=^u-57q7+QzK zij&~)0$C^ON7`t_45+jD35Hpq5XfgpbgAlgE$q8@0Hfu?=c44&%oIng<0cgZ)uXNn z6(Y7ElDT;1@m(Ga$#D|Wor?^UFfd~hr{T3RC$qEbyA0iDv=ngh#A1q+wNs>#XN}&< ztP*EA&e6jN`ZjelwMCh?PmARaEst3wc|Ui9gL3#5_^5)WZzsNR6s;(K`vv5MEb$H^ z@$HFWMUV7`qn!310nN+o1#;)ttAl>Q^Zxsj{PRwU;_C`q2UA)LTO)m1Cv$6KS`%9b zYkeo$e`@yqj|e7N(+<%XY2=S?yi3C6qX1+OP*Ahn8i_eDC^A_~Gm^NudETJ{pHqg- zJheFj3nq;Ye2p7w4pt5pvaXvSy7?j?bRQUS(h=Q#c2W_YBKq5_BLga)NXO^?ZK%n^nIi!IJ(UIBm3@ePV>678a^_WH{Te1R$APU!1)?CR8}bTQPK_ zNPBo>I)JLM5HU$>C`9Um0J3}(`FGRK(1_ALB-V^00{LJfh4<6SQ05ts!k6-h(VfiD z`_`Qy;qNgFZj1QR(kJ1=wcWgBL;Z?l_Ux4v^Ac_ZWzrKKZep_w2dzbmV|b;4^~pzI z=SR$RiO?UPMoQ6?(4U{=FPT_?6ALb@t69t0!6+@MxM2y*S)p6kLiKh*>C#u4;O^uh zq4v-njjzXe#P1)p)$2-=fiunV5#*!;vcfuweuFHM6`!!q`~BW%^z(k)7`!j%N#kz6q#jbAj94{&Hw5eNGUb;X>kvdubTkEx znz5$!(T_qoR~7^X_EGhOAlGS&BN||#Ty4z^4GM8yi*`08Aqkg#t0joJH=$=A z-nFi`S~Pl2E#`0v4TxIt#4j&&Vono-a*NCx3=Pa1&;jYNmQUq6Jt;)sR$Spb$eY|? znnc4u*}Ef=y6qQ6;8--QNZ^^S?k#3Z6tfJ(!c48)=d;(3keT0`ZKRU|X8_f?JIso) zOA$Avaj*Co+BFi1pm<)Ybz;1a)g zptl~?$0X(&4TFCWUx}m!%8suEPib{a&l_%ACDIyZ+;~@qnBH{{KI+_x6XHmaAZFG^ z$CV;apY$YM77}8L&Jp_^R;ZJscvy>yhH;-M##KFd;Ff|iAw>z%^{sAWvcQKUVF_kD zRUv0|a32BoR_SU47)U44?wcwRw1HT^q+6Q)A{S|2R}aCCGDOX;^LJY@H$+wRo? z?Q-0I9O&2-El$YO!zS7dg4wrfhzwqd297|l8iAv$OG=3Q%XGNSk5uV$uCpm7GOw`J zS*V_g?Vq)1ZM@h-rSeQn`@%gZ9U)z%CAZ(VS13AoEz(<+B{0$sO1J14?{#qVa!Whj z<)!lyP8J&rS#k^K9U?tyR`V3#L(=nq`D9fUY=`1Jzf|Ut^5U`%OCXM@nV-yPz=*h( zL>X~@EJLAgG%kUe^a1s0+JOqR?7-G)-q^`IBrUdO7E*T>~}=m_P$r z!9tNu*ykxHzg9cC)TX;DFgC27|WE2TW$6$No5edD$`uR zOJk&ED78d>9+H@XRhY`9)C7&{*26L!vc`2EC94lRY!6Kx)tW4ry1cG^#}Oer0R+`m zTwy0J!?%8FKMSy)X{ET{Y6Ups7W^vtGI|s1f@sdra+WV^pB?q6{dFnKc|Ii4jH{`J z3+gyp_kLydf{8so9bEQKILIZ@5n{d^wEK5L?Vx{IlOy8__!9>H{6AHTbpH>Md0poXh^y&?Y?MoxC?^_js%o5f7OKA;Z7?9uPv zozmSZhgDA)FTocsbzs4c&1vA6w&ryl2pUCZL%a+gXkJD?v#RttH4!+dMDA_^`hn zXJ6<}#y+}rro=H3uI6f~vVz?q^Ye@ac5gc?{_Zcv0V3VKde_&Q8~$%4IR8?l{ZFg1 zfU~)kk+B2Oe}j(yUZ=BE))g_8(f&}gj|JBvd5Ev`%}9_R0l^em3+1Zi&J=_CgG3aq zxvWy*qq)pa1uI;uyrX88(E@Jvpe)R(XDsUW**KaRIrb0xz-_&6`~L8M0OI9n$~4k; zGw-wRwSBf-eU8^RUha<&{Jh;JKxs9!%!csc7l%rPGD1t9y;g!;oDy>pMYU=RB5K;T z*}?_iAJA|KXs|{gP(5ZQlwY+%^S6b;W$(MbqZ*(&?V@KM?EU0*TMAO-nyZDvX$*DK z8C3ti?%Dnt4U5C+SxC9$-pshRzRfekgND5WzJFJUHJ(1ERH~RGHW6%fCKBPdr^b*s zX0jv)3Ia*dL~~tiL=7LFCZZtO*l0gsM8(OGo~ghH)SSIlI>7vDJg)>3#Y7=fb7x%& z;Y^XpNi;N$tV+L0xA+XtT;Qa2A>S0pPSQJ@z7TJc@vWzZFBM4hGXY4g1g9i&+#^1H zEhP(0K8oL+NSHH&(LzFb^3V^Sx>_c#o^~%rE((dg$Vjoi>@fkiKTZ^{xQ(k6>gJUt z@ElLJd=_C>zU44F!NY7+Ed9k=bvZG=c&f14SZEaJLTMFRf31xjUgwY<;)wEm^ijGo()%)&LkM02$UL!5i73KLPKjkA7CNsIZ>K@`DaR!A#} z4oJA)uoR_s|9cCOKC6Y$AaN-ga$GE3aABZ*Cmwzf#KZ&+kJ2tYd|@>q^fZtlD=(!8Bwqkv7o&^c_ z@ArCD8O6vm-(`Yoc-FS*C_Jb=6y!5f6vA_;*sVWsQ+Y&L%!CD(gy`W?m1I9}cm>FM za0@o+4kFM$0j1kNN;T)zmfW0W>-bz^eoG7=TlnK{OD%m;N((!!mX$I*HcKPnVY zuo9wDJ$NcC!ZmWCyCy`aL2*oMw{!uH!ybPI7HAdQnuQ6jErKvnPRC9g%ZJ=w;X31@ zyrV-qn}^_yX>UMfyXOr`nA2Ne+`e$vC}&7Cr`6gtz%= zy}i&W+_v*f|B#6bH}(X%GHTfFT2G`usX5SpEbrORJ)@@;a3+YGp1 zQ~lIx2Yqv9v$9t1D?)Fi5r9@<-tues(V}l_g7Zks)z}caXVUC-qR+ZhuTORZkEM)* zlFH<6q=F}no#At_AqxFdojMfHehv3V06O|y5p{ByT#);Oj(Nt}9B0X8Om4y~&f zjbfo!GK?6>G;EqFC3-_)W3`E*#7^-c0@w%Hu~1)hN`v>Mgsbd#zz0Kf_$O6 z{;E|`Q*F{bMfl@|`*rnEnsTZn z!w}3U+F)!XWh+JT0D;?J2$&Y)ygURv1S`=-qFn_4QbBRjtW}04beH|SL|KK2f}%C| zz+%!nrE|7sd)h`+1f5d!X|T<<-jC-Pa0o8F8>v)rfE?yB3{S=cm7}G+rc6Q!zWxz3 zXZgJoLx&kavt6GN`f}PU$5I^rx-fchuVM{RdTP}}BPs)edW!HDnjlmZLR+KBy%$b) zq$8m*uK^lW!u5{RT>5Ce8N=lB7czNAKdk|Qs~qZf0ada}*GOq5(jGL*OkpMn3Q}XXcn5k7*=eVeE(?JK zNyn}6rF!-3qR_7LDe9U#kg)CwFHbZ;N)^1|essHmV+V%5-CK}FdyJz&mJYkMzS$kP zL`G9X00HhM^t-)`_yh1`RVVj{HSatlA$N1nm?)G*W`#NVsOVN z6jcEcHfvxrUBpZxs*cDX8M6Y}icFAmo~Yc1J1A;&4=~lVOonXI&0sbd7&ml?I?W&B{t_>(pA(DwD6=?K4$Z(B?oaw0OcCD3KCGpOU#GgAJ zKGjL2CX_sCMdeWrRvncZP~Ejir{Ma;i&|3xJ%x>dh7@YXL`iFF@7(g}wDWY$U_g8N zo5ISa-FW*@Ut!%5yJ1F7*H=_)m(BESXNI@pQ=*OWb-y7$0G|a^WmA*o*@;$|VlE;R zgSv@M%*FB0M5O~orGGGOAx6Oo?Gx^P95}-VoxfDgt48s(7?!^NwaXLu%$wx+s!~<` z+bY$+%)R_qI_huK<=-RHId)0{nEvO;AM@qvC0V)cUO`WKx2=Td@0utYjczx|SJCT< zsZ{0^uNF97-*6=|H~n#;U;@#7#C;OdrfZ(yzM-;3)}b2e?j$Dj^H%U7)>!8f5NZau z@ww7Tf$o(TE0V^-)dzXV&yi`4Pm~jAmZs$yC9>;|2T>*(!Hre4xh|orb`zVQpQKkv zvAa7Z$2VCcH^!w+AZG-_0exgFXO`z?X%DmgM6)hkW7v+fcoureOpAX%45p?-P*zyK&u6%&~WBLm|fMWswN^8~q+te1zzncEU6=nakT>p3XI+38Q zjiZykjg#ZwpSmdx!VO9Ib+{+nX__cuOk7Mrj18D*S4^xws#FWeKQ|1|ty0_sC_p?| z8Vp`_R+(#QQQO(oS#?v}wsWX4_^}%u`5G9m6B&-H*HD?uuBWAAZhlj-a^(KcJy)l$ z@^8(a*Yb9gc8>d%Y|bnE{JQRN=yoY{KPCa#AgW-hUsz!3km_LUSPmcuVx#i0+kDZ% zO#JEi)Uk9#K;}VIA(ehY_>}k~d~0}@v9My$^^kX(Vx)yo2qBfhSWxP~?6CDH4qOMW zv50u20!#cd{+ZA(+y_XbW&G`0>bP<;PzqV~I1V1M8Pj~HQlq$X+)zcl0svTwV=`Yz zGGCGVw%B{T$6$ z`<+oGTnAj?%AW+T1lK=e!ReL)$hbk=(I#5Zk3b}1av#VfVu~m=<=nCEKs2(2PRSFq zMNZKZvxQID6SGB6K@*$v9|$C9`E`crYWSM@b%Hv<+_CS#4x~plV_WdA`L=?rLOQ|S zaqqq#2#&&zipIv^=kW0aT?AhEdx5=R-GLrV_}%6B-9-s>H^B!{9F1_KsMbUVWt8vF zK8iV8RyK5z>u@)a} z@i${N@o4$7L%6`*QSP7*%tsYtN%3X*a6+tpae=ub-O(N3k5j0VJl<2?yp z1#CdIf!}c)FppNmqT;XPeGOFso#0N8)o*P;cVJy*GbcH&Y^mKGYbeo9!HJvWE%?UY zx-b>G6}#ccdC5El9&pNeU&#&>Pd5FgQSXXoJ0M{`a?H--a1`!l+u#cQhDsRZP9rSv z3x6nB!5+^GNbu6khLk4ry$VWHRdBU$qyBiA!$+rjfTsz><9B)kxg$q_4)#hb{c9Td zm8bvP_yy>@uFGi3{shd+o!1M#E^ZKKSsTbOMD7KFVx7cLh%n=U$AS*<^QQ4~ z1iSscU|taJa7W={x#a6bPqwy zPWv0iP{l=KA_7fCH1aQ3G-0+llh^K5skG?aL5^Vjzu=@Q=ZC!S}s* zeJJTAia{o-ld?WAOoQ&I)H(GR%Nw)MZ*tbYfaK5wcGeviwGz7u`~jY%eOd&QVRw}h zP{3hL)iZM1fktjxbWl2e+954CDpAQ{rew4s*R9Esnflqor1%zXoheG|RXSQ;pYwHT zFipWkm>Fc!4oH6y0@v?Jx28}`p-z!OOW{tL!E@nG{y|LPPVvDE;SI7qY66#t(g?ST z(3Y?j!aWjr7cl`xy8(wEiyJh$@5dxjbU%ptsHsvxishnjtrzGXm z))#s9U{Tk35Zp|+e6toaL^h>od1Ks6#)PgbW(D`+hr7eEx)sF=RmsB^h;FHuk93Ap z{GoU4=2HItB<2)^!$k0_iNm4fk*N~uYfM+4*_+-3vWlXT9-mzHYfZGK==^(uLJAtsvlIG55M9HiU< zGK)1YVoeEI#)*35QKDfKL)HXT*8p>sF#ISgDxfUCQT!xKtiL21KQS|+(xxZEKOn&Vy) zd5CoQr|5@tL0>K%2Oha78v7S_@WN+nn#ihFDj<^@&Jc8GVztk4K7ir8a$pp1N;NQL zg?x_Ua1iiBzPTz2`;(MFTW_u}%y!{ULSDyaxQPW=k&gL|ptK7cnE4clZQ;5Sq> z?P$@jtYYrxoHM~8@6-LRS*qiiF8Vr%WA0mL3hp|81Cq2d8Q_`X*0@z)W&~;>I zm1@`yn@-niG+~F!im1DT6ag(i@!7nN5ZVkvWNTj?Gz0?yXC_ zsCw_V+O8SM{r6qgo`L&}IVKy6=HRnqYzut2rcjcX+nM(zoU@i}wvz3u+ zF=*+M(irS%SZnFhUI`6X8E%wCt`iO*7w#pmw*t{#K@Vq*wK}3b6#%C!MVu!LhD|l~ z+g_LR=xn%0a^~2hD*W_ql$fH~PSajsT=k;8G8oqGZ=FCZ8MSjSYdtW!?`*9=b7kJI zHqD&2_h=xQC~4U^IE6{jPU{%-;=nPy9Aa6_cB@A9W-MS;DDp)tm^Vs0Vq>&^lHwYP z=t!`4wJ&~Rlu6pHSF|4sGxfBGW3*x1Z>Ez;*sWLSnR;rnSJ&B?kMs<-*F--~!B!Ro z6j&gbX3v2#9Rzjv&sZ}p{6P@}uE%1`Vke1tK%tqBSO>H|v5mx_rO-^&O{Ntb!|?M> zbk1Z!Zw|5h49!5RN23FiWELRE?1tk6;-S zvuNn_X4VsY7N#kvtl=4NbdHF;HilAL+nMb(xg1oEl)QVi_Ru_chSGZ0lRg%uTLDaT z4>CbGQ?qWEEP`gWKQ?!wzMP$XR_ZqH^|U&W5ON z!Hn)<)DzGe+^ zY)x>as2|gx1DPOCsFAvw9r>-pb-hNPSlK_NaE*ceSpFR=Ee+?*SqEy%b?S=Tqg`PkOU zJl1=pHiebApf*StS1Kx~muOTfc2>TnI`cNLFjh>OT#`O6?5O@g2sSZ2Gh1lc8Mb_636I7_K=B8Wri;%N`t~t zWh^_T5kMl%F>q3y*bz2`U35Hizz87!*Yz4lSQL)YaqJQN?zBg$yz+i0e@5x|_mw0p9xW-^V`@ru;(Xgu?6B9oor*eQ)s^C%PF(PS)> z(HIar$u4;`naFNBk;$KS|1FJC@FH7f6^z}b&r&c0iX<~ z>67lUlcx#nsN3W}{F^9@vL^2|id>#k^hsV7_c2_ul!;c1E8AhT(*k1BU6Oh69FGP+Zp%p#a}{ybX1XW2Yiz-Q6CSionMViA9YQ#svf)>(1Z%^Oqe~8c6|U8p5}4(qH+l|L*Jh=T?#sRUC?Bo&XkV4PAtzak|G7vmRYpqV5 zs>7s%_#N5z7wxki!Q!)?7vrrc`ZN`?gyfIBv1~@qqYPU>=JmzH^foT<_sIP+e-$BM zIrsz;nyFBx0!Re31QV@v2y+r-DSeG-oHzP{pB76o?7Z1@Oz7vqWJl;=^~u^|7n<(e zyJ+A9b>*A}Az)Wd3P7&E4bI%!_0L60~4kligxl%dZfJxa*aCJBY z5@sciG>p4MmlL0Fd9H@bw-torJd~S_SR-SfD8UPf38S`uh?S>`N(iHwBSWbv)dd>! zswh<&NDpx&qZix6=Y;b^(>E?J`{BE(!=qhk%|bv^6Wy-G5l(iFb|{z@E~GcxSK;87 z8fY3b_UJTHWoRg^$JWX5vuQReR3=+*(o;3GtE)vUJQ-8_LE^T#h@)v#e6$k7f)1f8 zz-asa`WP2qHM&fE3?jRlotlAsMcXZs40Z~Bk6WlFZPJ$YPq5ApS^G8P&4fWTJ^Gfv z-P=9m7l>Ek2keEW^BKGKN-q~wLUx6Z8$K-4Tkt`8BeV+9Irj`maqSbGAiTLHL&6cn zj3FEq)hh2`R@!o;h$#%0ERT~c9S*g~EF}rGh%YTRBas^6DH?|tQJ50y>3_q_I&e#k zEb%WMlKt`N`!u&-(c8mz17D6=nd?sf{$ka@qmIo3%$p<3>I)P#O$bm-J%S3%4X(C% zZcq0l5+R}``ho_qac}1phHbFgd0|-P=|O?UoCEG70SS4IT%vH(`7yT5wD2D{Uy#Bj z++SuFs0)xbS+utC7PoX^ctN{vAXC5Lx$KM!G^0Nmt_oiM@*-$cd{Za*%JSR)TSF_p z|F4nwcMkf0SV1a%wP9-5+8E2|TO0p99+OlyWwDfz{%jh%TwgGFB?_#Q6DZYg7WFna zX>1BxbWl6lLnRf-Sth}Dv`q9eG-PEl6W{iwK8rp~fg|Ev083wh^PuHe%(3z!}gNsFEvUn$Y%9& zHN8Z$i#?;r7s?j)@WED(76&Fdnxa|s!xie0u&#X_j&=1?F7CM7ZL4JhLyFh*Oi zx^uStl(j+a^7j}Apal}G1_HK5L;Wokdf3DsJ#USx7wtdctPH8qf?G!OAU&keva^f( zn4{iNlrokfNkdGkZ2J6>5|SmEF(Fm)bsMnn)b_93IZ7nc*ms91ONmXONvW$-0+Zlx z3oiu8tWz>0(U^?)*Hu2ix!F_&QeP_VUWo#OWuz?JAlrjUXRGtzv24v!`;}qu(nNv@EBJRXL}dn`rC=IT4b3WPh(vV;xTs)Q2rwX90kyv8M|Nx& z;khKk&D0{!4B8dn2#2|dtCYjUClF)^Y>^`JTcZz79x6xW8mpxXQwIia)G zGu*NBt4?<_T$tF~S@O1U;sR<{rDmI1xPI-5xm7HQu;7ZWxv=jh-*X8C{Bawoij(yi zc2U97WW630_RsUUB;IG-OP3$-NOCTs?dXq#Io8?a04-u6MVafbVj)@dFq{@)E=vry zR78HNWR$Hw87na_NDiknL=qi@S*~D=sy1*JaBOAxaA<+ZcNHBFJ{(7yr?I}-DIB2j_LY5~;hs3zN+7tC~Z3tps$* z)yDWZx9>mB4;=|oipwgET04!+jqy2zkmBN{MMHTUKP-pQ%yCQGe(5K4qF^?kdfPRx zdzUvI!I@jS&hPQ6q>&)cOyw4);gx#$x?T?<5Af@M5DHX)a0p=>efR#6bBDvG8`x9# zvVWnvY9dB{7{mu!&9m=^BJH^TJIwaq~v^5-J!vndcK_@*DFZwlcOm z#mVWcN@zM3AUloNl|wLtq!v%agU7x{PyOcv2gfeAMO*dCpEfDy3}LkubWu`zWO2W&yuWO9jGvn?HU5h^tzTt{Jz8HaVxaKv&#v_l!&n zgYarDzjDfm9~+`{#kHxrB^p6!$?}q-wtR3@f`+YOhIdubalYP>PmQPVJQy|t%O7wv zrS~0;&*tv9TF3N%_IltBLzV{G^WReHCPZzdUF$lg7~4H6rk((V$=;>J$vp(QpTQ`< zT`v^>@b$csf-UygiGN@!^5bC|*#+=)A}f)d?(0Bh52Y@Pt*t+7Z&J$r`Ah8gFk5qf z|78e75BWd0I{)_;Lc{-Q_L7ybEipic6mkvj83F<3WHk`R+VAhGbL}JZW2!HiWlT(g zY5L23SaxUep-bw%#L@hgKyFPJFt%J{Jx4t%F(ZnPK1=D02f9Qw)sNdsaCLOWcZ zxdu!-O15Wn{Mz74vSKqAq2-nNooW|!O9c{E2!WbNM11>O-1v0=^tohXhx*p_u_|0f z#P8o%F77QcMe@~UiOnkH76*V~9gLYVEs|CmN22f0D32f2(YT;zh?#rSrvBYP3+xip zpancW@;js8HU?;;Wc2JbA)rZ5ZeyW&NY+aX?lf!?{FE|sKS+Wf3RF86W1F;oMV>Fh zaArY~1UrEX;$M7D%?LA`AT3mVjL1n9%La^CQN>qr54@>fO3eCVr2RkE-Z4nBXxkd? zvRz%aZQIPUZQHKuve9MRwr$%sy4+>Iy64>c?z#8H`66Dt7a92{e`Ms|YpO+*AoTAl+rLpM{^!U4VHYlFYHH#B&)Qa`AR|2> zfas&OP`vzVbFLPPrwJN(g4P!iERbg?ijci*jM7q=QNI?}GZo0+i%%*mR6gs8gr3~O zZFk(2wiP?m;`Zaje2t^lVRZK1{jdm$eP2x4B#0lCie&~?b>p%X_K^l=X9%|H(Y{}= z6~*Bvmyz&ZZ4S8qtWJy5Os(21lPg{$%boq@>k2ie;CY7zCjH?#A(8Maf1ky_z zjqsL=)M-T+x#Y1!2f-ZnFqbn~-3%^qNk5b!@6j;j_kD(2lQTJl@u{cS=^E84jXqHJ zG9)1Wv-kY8-Y~g5%qV=#AH#Am0~4K1*3S&vaYyeUzVp><{|b=<-77EDY#nI;h9;mc zRwR(|OjU=rMf4(~EfTERHCzD2cF=u;NLgor(HOO#bRHFFtkJAI{s~@7} z_sZt~AN8la|88af>-6yd>{(3Qo&V(kk)-C~th|KzwWV>D;cuBcgMPE$KVz5UmqswRkpkN~Jd9#Oz@yImDb z^GC_aeP;H8lc(nE7JI^&F_VTA{7%PH$IeIc&ePWQHs{-p(F{;(OwYK;a)&~!9h74r z;BW(PGc1F|+;w-}Z?I6bHjqg(Z({XV9Dxm9P@O_t#t;jUL4#xa+n$+?^B$c3*-~ z1h8vyx=rE(-A!^1?jX0Pj+WK;Hqu4QNyX7&*Mgu=`T4w^RS zJzUgQ>!@&+NL_qt1Xu`5wo%QNO{T3nHCZKTp3HD)K@SpEcgv}|J$y}s`Ivd@N3_@v zxf=W#pBRVsVqtsZ1`iB3_PMlJ?3k-u>66gd22N}PD%}Px)fMVfyXIldntP#eJ{t91 zqOt5&v`G8z51^L?GSvG91B+T2&cw#ejH^CBqhS>R_8A4Rf_kbXPKJzI=0BnTpr5ST znMaC8o0DLzYwmD_S)J#L@e?e}LbD&eXa#sq!ivL{*OOzQAsDiX-%05-JSSQ(SBiow zTr~z5q#j`RpYdolXhWtJ5{ay(=0v_hYLAwfS%dp36k^_QF*4e)0EB!Es>|T!I4(zf zEiR*GWWeo~r(S8W;cPT{a(ChvqjPn4DC*DBe?}Fahs;y&!iyx_5-dfO2F(M`)L&)t zm~kwY4%A?>pwV_c!JOuD_3@6WpUG6ER%>!W!6mC%A zC7!DScJ?g5vfMTM1;Ik?)%%z^h*p96;NwF5_&tRB3~7GP7Ug1#|C}6N`FX#KAuQNq zG%CN%jvyAT&xE%E*U(JJtX)XDE+OCNz%#)>HdBUrn?->5D%{0l5mER^M7+ldM(!X5 z$zQX}qMLXVACOWf(uXPN8>@zzIaEOu=Y*`QWRHhV(pkL=m#K6EA;{$r(^rg*ysdmA z-dVJ3(^;^q(K``kFhmUqBtk)sofU}TpNq(P1Bu2 z@oo54xvS(|yz6A}2gcwJQFr1EdWcm>WyK~_>U^agV^y=zLmI0p7MyS_yGWymkQ@VG ztU~!2oxM?_d}0uj41v~kiN$0*f&r(>Mmw95f{W$F6PQ(WDxCpv2j}`7AJc*YzO=${ zx;|*YMT1)zw;eg`(pJJ+(V`5yR53OiM3{^TJvN#d*L+s_wXl>UHcjeue+t5@(4e?t;a z>(e0x>Qh@Di#Whex71zJ2{t)s4 zB7A7p+{WpLH#W|@YwHUx#i83gbeH8kbn$$O26VQ+54yH!C&+Yu9Rw3}tNQUqIGX{b z21-UUirO<{U3opgrBsm}hu40+wiqPXS52jE5d?h-UNb$CVOWtUF*-0IaVwI@mw))? zZTE=V9?b8@g!z;p(*!Lu^}K0%nD}3cvhvF6vyhIN5aJOrAdNFSBXa0xV&fA+)Vokd zfBtln0kZ9wvuAYV*abJHA-jsRfD5IWx~(=i^_m7{=Y$1uq8}Gf(PL zAQnaJin2IF+$us=2+-E|+;!Sf6`t~=0;b7Dm7}aGOF9@!7CsSNk>XF7nDp=aUX(FD zhhHeEgHHtk{NWbwl=0@%#OGIqUAk&4ATa}lB8GRw{xG!Da z5r@kY`D)-w7^dmV<}pi09M;xtwXaetMU!e(FVzdA%Is<8Zhce!a1E%!%;neH0&cit z3yiDY5T!aCf_JLggYD7DUQJZ4gfz0my{o@r_lT7RP32|;#j?w4kaC*ZEaj1|>~>%~ zf3>wp2$eOh+2AoNWiv~caYF5+$J`WR2@l`LMIh@P0ol)w?$5Ut^x7C{F^Aw?Fh;QxndKt&KPbv{a4M7Kd_Z9?k@_Hkcd%emF3i=3;q)- zDLx^i!AdTi<_rxmdSwSoyw6m;*`4pj1*H{EURy5pYIIwnm`g>vZ4fJ~W#!cmUKFTu z2-PTHYSt<_e~_-e*_$z9<&P%t0|NI$lKe!rJ)l3Z^#y;rQL9bJ8N&Oddc1Su7}pyB^Tk7d0eg?^ znHIZcSLfuPD1XVQ^zRu`y=hs4d&h15-7~><_q1B|4$>UxH|ly9yNdV8c)pucJMgaL zn(j9|eLJ)E_73CvThI7wSFhd=`FiKw&fWm7T5jdbn9FlNhg_#Il<`r2nsQZ$$g0Y> z9loc2x+dE5YUWm2u@R2c9q7;3cY6#0S;Iar`R6-vXy6-`{qJ`9|NS||+3{aODTC+w z{v)gteD|MWo${`a?F|UKq>T<}Hr#-$`%84(n7lLaE|#5~ILqjQ+t*`pm^~o`d3Dyc z7iGVcq!zSt?Q*WElJOjh$I829fk*1T&W0)ntp#AaN;kL zG$gNTw^?w+Fyvyw`c04Me3h%P#N}zZ2^c5>NFgSTgW_6mM!2rCr;W}eML;RfSEWfU zGm>Z#sunZsF|)tjv0jvG+dq7TsdIOR8^8O<$p2%9$^P#;%>P^a`VV~izxvI8qSgNi zPAloyAq%4Ng22E`%&QiuXuSc^)?egXq2L1;SZRF=p;S;TQQn$+6Y2V^=_13wW8QaB z5K_%$SQ#%9!uiMDA)wG`!F_h&pQbrawmG@)F5gP%e=Iu)561(Cm|#*f#Y2-6q7K$# z75P~)mP$n0>nt)cv0!R|7hNj1t+*R;vxYd&Jy@D??EHP9I}(;D+g0TpaGrC0K5%WA?9!>&%$0hszFhqT4`eeK z;0*z_LkiHmw^|}{v-~6!mY=X?7SW3!s?!b;H)0VV*|1d8wddEX)T*IvFyLfuus8Q0 z{Vbo#f}XL1S(^G%rh38i_);PUM5q=FF;rv;@=&gL49%E5omnMqHmmI+*cbpD?{^EL zZK3%FUO}0o$4h4o7%F82aLB(}+LX10gn}|7IEs}g4P}Q+v=ta*!9vn@W_WEA=g44h zv7U0W+9oh<<}<`w3=ydB#S9?{B8SnR4|YLMj=$_6dNTvVinan0WOFOa=kH# zrwUjX1VR?IC4Qn|4}8L&)qWzS;^ukaG=g}8CW-(GKt1vuB!Xe9|;k|-1jZXr_f9%72EUHUW+WMDSL zeqJW)1o$q|N7T_uh@e(6FCd!Fe{5lw*dtwq?-(9N zRiaY}q~W{Bv~xZ7-nrm3n|XhJx#a$ZR5|>+R|iBA7E^+FV1cHYx(i@4tVX38AZo+3+h(GVn+D`_O#=CTVjp^G1mOsR zBy_1^Uvj$~_^jxMrCQP1j+tM%SElQOwCxh{&OpIqijjngyWk78i@I3J=`d-a?4;?^ zo}OcJxv{h0Q!g@P2~~o|-9o1IE{%(bhS=4F{cM`TQ8u062h5jftujXFL?Y-y+9AIa zk(|dVUX5WbFiV!WPwgx_?JOtFnDq$w2sa%^DU?TwWWaxODT56DY3-C;)-Q_i=*1=`W%eH>8jFrb@ zReh_?uIeG+Cw@MOx0I9XbDRd3&A>&gf2?Ado2T6r+Az$V?37Ps9*G-5K8wrYw>ovd zwbL3|Ab%`I0lU9UtA2ecziQ-US@OL81MhKY_=|7yjrXAckJbC%NFMXQtH%FTfB!e$ z^Uq4$qygovb@V&uclP_C*;-82D5o_9IaxUEgaf?&=n;;r5G)_?v_DD=MZGokX#8*E zctl%ZUXY^3;J9Lc`=I365P^%?Mw||qi)JmUmJ!>DD_5@{MH^_%CN)>{_x#tqS-xb7 zzAPi&*FHOwe#aTtUOVi}ugf{zpFBuYCrVgDXFf@vO2pV*dJ>GU^l*ng!SAtBU(}cQ zDzE%WpL)d6eDY^E=s;Gk0B}DABT! z35&4gc9}e=R@{l?9P2m6e#&N7{zZ+p^e9g#fdUkbt6)v-SsG+r9p152?_mm=mTOli z5GN$egrWfg%q&vptdma68{^KEt5;5iJa@+M8aD|BsS6d3+OTMUPLoA{^C3wmR*eDZ z=ACi$h@$A@N)2(MLUhRW>fp(v3yOpjK{V*|M8?5!NkXbn8nlHfqgY5<)NDRFRrJ=4ZhtQxaAU@X|}lsyu}e77ra(Yl4a7m1B4 z#y427cBzB4Ne?Z#=h6@&p0T!d2l*V<;U6a!0MTBY1ch=(zDW?NQe55+Ujhu9J$>lW zVEKURW_u1q8@Lz4I)SLNT2>|w)Nrr^prk9Xwm65OSxB4WosnPyhw=R7G66hO0HBc@PhP{CKC}=d%H*rrdaqu?tDt30yFJ-!t zt)UT$TuM6=$`;*q(Zk_i_Z{}Au42R)gI(1zAA(cK8sVQsTnN%HsNk#Nz`#NFp277P zB0SnQ++M4nSm8zj^NLmGO6}yl7|`^fg*yU24D`G?BA}MEZfTggguCtilvZN0fc(5I zU=ADg(|M1KJW`>P!3O%=VG_EkeVG&HvCe{H<{t^(OXSQ8?8G5?MQScmp@i}`$NEu!i15JSm5hMwJxL2&Y5ma}AL4}(%s43GcJa8@KvL*_B{(06)r zVEmC`Mq}QHpd=NGZ%!of0o!8-;HgvRG}o2rLJ; zJI{#&D5RbsIhwa)gwt&h_M0%S$js#Y=`%meGwvZ2+eIeWsxIT&nK z9Mpzx54;PTysUyBQ7$r&d}&F`P z9t1%qx26wl($IRUcAp%{Cz<0o7r4KWM(MO6lqb+b-$=F2PXpzYUUW4rA){xQ&81EO zNfYC+IW*wi6^U0uu6<9zTl|-f(V!(VW|o-h`gaO;t>X`j`7KQ8h=U)1$6^;*TbQ>x z4Pk$G0>;yXAydudl@(84Q~z(R@(Rn~D#*8;paPq)wC~MY5x9bV0>?hZrrqNbEd0p+ zEAR#6Vo<0sVUnHeEvd|G@q-P}H7`~YF#lU)0 zXf~D$oyT$f(e!_iX@g(d|&{Kz`*!E|r&-%z7qMU^UZ<^~OSyc|O8_G7ms}!$2 z-=rR@jB6_@e6<$~^qgHYW#8o?a*x5G0-pZG)D$96!8J9$1<{jZpzxgJ6LPL%OH1v7 zJ_#i)wROy$m*2^hY-XZd;lF--z&I%+sH7Uyi@rLxFrGl4zT=Q3Xy_PP@@F7%s#wN9 zED{C96${?+6?$gyiVn&Vl@?6C#l6}js~oiPPq1pN4?lUwG%eOGYkBc4aIg8Vx@XT+ zU2zPfJh&VzGSad&;HqIKD6UY^qtrjKDhW~`UZp&*>XHjO`Qy*^mA6VXF0~K^P3FBe zs^p#=_LoAuL?@HBIaF&+HcLTM9w2ZZ{2tV1YQR8Aw^&}2StyB{(0;(obVFnF#;&`s z2VAD|@}Xfe1)lv(?{6dm7}%A|D>9|3m{DN?=+Tk}>&Hc^`=Six!}%+El`>U&D4(=Y zU0^|?9AlOs%yi|aP1>n;l<8%UO$juil3I?K9P}~@vXH6n!6AKY zeXuDU3}Dyyx%^NJus8E19s~6?^b{5S>XR2C*D%=~ohj_KP0J+4Y@W`l15pGS)jGuK z3o&w(5NxJ(Fd;v>?-c$TvPYRM5aXi_RjSxt!&@_Po`;Q4$PBZ7j^s&8<*V-T0si_8 zvfl>cBT+4QJ-oqFe-LgSV3xS*ly1#iV9YN$zHn;P4$%mTBa)IJw59xQYxaiOzLK~d zsS9=qEy2CsHn6}T1qLy?c0*K#yGdCid(c$7@J3Y@T_b;MG4I(KU7+mz&eG;N9w}aS z7+lDNV3GTAmR(*|!zfccGw)MOXv3g5nVE-en66Nn zvBxV~6jBa_Sx%K3bP7M~qYQ9U?;~g8#2$JU@sI^q3u5gG~JsUm*Lm(g39uNb+RBSXg&xDjaWdDjF2l(;GSt(_w zHa|glF&R7Wa?Ob8r-{2-KA%8W6wt!2ufLyS1ZAV5^ z&Zx;2X`(jn!q4^SuUAB~SwvlpWJC&i&%k2cfyh{RBwtr#UR&SO ziiwe$-yC!V1AT%zi;v!oy_K>K3gjGR&~L~Pir zPw>trH|9%LmR55K#gr$P2NtU0=M!OK6nW4qQ^v}3qE261ls3oC11o(Ac~oH)!7u?* zWrE##fKamip~x+W4%`hn39<*k`DE}u!D)|A`aV=%(=BA_CzDAvk}YJH2-E58O3s8< z=d`=cgXqe!@`i{TMZT!y7Ur`h!#wn4RzUibA;)dW*@6iLGf_fEV=Ir zPl>q-sdfj~`FWEKFt5qjj^)@6#A_z$7nby=POe_dp`O(k{q3{`FOkH}2H?{r35?j; zf$a-u){gAOO6HU3rluxyw-GU};nPDJ%q9sQ##f^go#sVNMRRXLS+DW1XAt>|bT);qf+(^dM@O+c^t@VfT!3*?kK`8_Ks0_+PS zw?^}?o5tRT%4|>5_YZ0Ezc9)5GaKvaL+(Mo*Gk5IWm=m}F}s@q`e-KgZ6W>ip6zKF z+%XUD!MW#_e7~C{5P4AEXWB}f+N@&kF=blGC~?G$NuT0v4^UWVdW>j+5a{8KiJ`7f zd-^kZaMo(ggNrQIY0G(ym-d9gKNkAMEB#rO{El4w5lH&QCf&ma_v-WNKc;6yMk;%w z$0?*{;*>Idj~kgp&otf`@@56y!|WN@2jxcwV^TWJL~C8LZ4eznrLZ!5E##z63lO5 z%)tfv)0E;~Ab=!M{6risAU>{ZYP97I2SK5WXCLJHIu645(alpYkIC-9sF1B&D!t`{ zf)h)$^qvLo9&&*KY=akWlnYC-JfjSwyg(keM93tSjB-V(sXo$_+H166QvfEZ%lWq> zGp&Mc3EB~SyGUDPJ1QkYm!w^qX|)*jUHbA3av8*rFJw5J-24!93;iHhJf)a5B~mb6 z4&}#$@=Y1iabD%TO=+dXH-fKbQe6YK?Iu!F* z)40^AZdGLBu2)qR_}A@>cOg|UmFCT_Zgn=kwiIiw`XjYV!#{wS1s9DX1WcEmE$yi` z>Pkt!Zzd`6HI0e-64}u_MKNtz7NtqHe7?Q(+ZgWdwo~F9e8i7Lg&%5(A@vh%|MJ7F*Gb#D7gw*0No zCrwm!}edZM41O9_}b3?iA1qx%|T{463l^(## znw_fDf^BI5QK)AnBeDK?O#$KsKc8BH2yovck6MMBdRfGuC?F50UMim+U1~aAoaC~z zG5>UdL~n+80$Dl(BZTDn5kORl;(>lG1j?kvyp5#OM?WaZu!FjnR7_=}kHlzSao#ET zv+XTWkEZDF4W|0fdb*+aw7*26DlY?do&*P{N9b@<%>qd;Cnnh!JR8?>1J#+%1aw>` z$JqbDLkh!ecQk)PdEx&@>W%#0fqnnf=lv_yrV`By-7kO|bTX7vnuOOUi;aGMFGQlx z5d0wh7Z#gMLqiS0Y!8Sh(Y#i^1S7;Cz}7Q9nroy4t81HsK`S zb)!+6N(=eqmxlN`*5e;HiBw;Uj?UzM1gM}NS*3EPc{`-A+j#oV|3ErhRRds4zb|d) z`~BY}?EgkOss7!?f1ASmt8DQ6@)pJ1Ir%5m=>1oU2kv(zS^RCFJzH05 z6h8IVNpt=j<`A5sf{V}0x4W*11Jw;@8Ru}ycFge7M2L`ZpdiT*BzD{(vvWTdc)i(a&W3VH3t0w zCVMD!IEffF1!nuSV2c%4>pYR+D1R1m3OeQ~FLd~yTPx)u2b+~gkS(TFDJ>?!LgJzY zf*=!Af226Dn9i)}%MhQ(tES*x-R1zN(6JZGG?IG@&s9Lz-EP~fyn5y;6@NS~j(ONu zEr*w$=-gJckm*M`v2hdO_9A=l)G8*VxLlc);GXOA6R7WT(j87XkD7rcKM%L}B2Lz2 zeEH9#1w5+l9mgF|nIUv5lkvO*Lr{2;HoBm5=DU&v4ym+x`*%0!;4MM!4Gpuq#g}rrniD@$KHVWQ<2S&l>EKPx|=$q=l9gk z`0+K%dl$^Yts&(n(9Y~lELQi);FC^jxL-VxZt@hh?0W+W|Ll!0`mw|(ptE#OoNjUg z@QM!i^`~FxJtM@=Ef2iL^0^Ks@)qCmhTr5)Pq8Iuv?gaf*q1EhYx%~BT-V7UEm1LC zPvZFe?|F*jehtgJ98}7i9=ht@*WqeSR_iztkPM{E>L_xAQmL%L3F=;4G#PdYnUr~> zy+ytcKd^NqbMZ0C=KYJDZd8Hrw>jnm}ju=a- zw5M+A#gV@J(=-Axl@Slw9O`jYVME>jGrA*iqrIK0!)smhsFsL<)vlGawty5h5u|+4 z#yPjZ#!IW^a0BcjuQ}P)2pJUTG7FbCBjE7L+-jp=*QN+GK7*^prD0|L19!u7{ZOse zM%YZe0?1h+mml#4J5g*WHLydxP1Z8|$kp}XnVVY^*kgbcR?}-@>Rv`GSEYAtX?|g0 zd8;oN4fHYODHwazi9QF`BTNZaSWWWf42r&Ou-F)FK8>Tvm998I|Qpgtw?fIi8zA ze7OgrvnS%{yxu6$(yewaEeZGFOFVxVk>yMTb}E+60UZuRLBmGp|Ng$ zti)!rQbIiE%UhSrFjcx!D50f{pKtS>pd7G2@wXC6B)*K*h?i31h3@ns2@5MZS&VDH zEUIXem@Y8>k)+VUs0DFFqosmkYGl7H-N=RnO_CLcqA9Y4d53NA4YQBZUjlF~f$;Dr z9ItJtRD~+L#mUMFUCvx14WrC`I#tvTp7{jnkYu#cV^2#z$|7j>E#EWs4tHD zG(H1K^qSWZRAg04qpR86d}srA7kB1t0R+gNu~e=@fJLgAoquNZW@VXovmZe!9$pOj zDXeWEP6uf_zjs`@+_VGNy$=)bR$8v{xx_3H*$Q5fO;g7(Or8EuYBzI3twXp8-MaH6 z)6AdyVlv0tD|oR*k0efk+|D0tiq)`7mhM|P>!@37e!O|^Zl~mXseh+SSJqYA z>*Ztv=+wKNEshzoW|t=0n&~a^{#FyT$meu362;zAo&TcwEwr^73u5byf$wmDQt!ck zu>@MLGl-I zd&H5i++CUoiI3tVH#{xs??%rg2LXH*FG}*b=aGNh`HcZ10FLks+XiRDqgS zX5?ppsP09ZLfQ=gR}W6`0^L^el8I$IXrDum9#J1CF+=bV2sD((_Yq2#==YY9!Si~o z#nI#?Y899oq^r+tbI(svn(lhTqR(7$*C_%|ahJQhzSmRw;k&_BIyQRQerx#DVB&0o z@sS*EZ{`5+Ck~fXP9<5UBU9zq>6rZ5ZV^qGf3nLU)7aAF_7J2l6)``^qeOX?-QpGQ z6Po?psW1JdPw%^9f$dmuAPw3i?#iKU`2Ja5E*vyDHyj!XtKEnvV`J;E(=-1c) zr+01b2SwS?Mew`H20L)ZHA^DOF#Sc(h%3{f+%{t=%eZ7gkatUJZ3oA({>~mZRFa?T zCug=ln*OzQ4gXGMr84#6pP7R8ZXum*_wnI#I2>OV)SyZ0yLt0O6n{7QB! zxwEz2xXi5)3ZldoXMcH8`GNGT$lv~8MSRA%Vt3InO=nQ~;{fXFkm=egXEc8ctb~_0 zE3ObQGWx-RSNn_m?`{Ijo*wDDWWQY8TX-hO^+{?Fg!dmx!0nn`-lW&P$x?;@?;OcWF-a zJ%cA;joZ6mczV~cmmTxbZtlje0EgZHzS}6wXB5>7Wk@PzGH#IF{p;(t90s-2_@EZsDQ5vbP}>r5xM8WlK$u!Xx>2D1T8qe?dEc$^D9a zu%14i?nxA}`)VRzj&EG{thWl2Yyq%#JS{4?F6jx9Rqvw1uQ5;n;faFxFtj`$JVU|{ z1kTvK29F;GKcXrrL1~C`Lo#PHekfD-Is&W4IV}S3)&f@&=cZ-OX#HTJ{+07<>d?Cn zc()Pwf?(Iw5pPD+gO!-H>(C%k+9Xk&;R(29mVTgq} z&$wP&%?(rYLtOzznCS~mW0VWBq!rg>A6|GFT}DF-py86p+V#ma{%5*Ee6O5a&+oIr z2y_J_z={?WUo`j`xO@nu@zMc@84N;3%W8Pl6M3O^Sc3+BOiuF>=J}6t8ijF&s(_Yl=l<&PecUA4pa-`}79u!di?!Q#}L0zymuQBpH0MZUqpVZAWsF%NCf zHjG2md5F^@l&DVlC#;nGBfA5S;26_T335t%f6VeAc>u{Fz*C#F27K_=YM?i;L6!eUNlte1MMW2HcV>^=7lKFhHS5KeG}w zvzcYw`VCIQt_L*=<(-1cIyP_pk#pUZOAXprNb3mcxoEO&hhoOR==g|Ic;jtGzYOlu zDAh7#%>g#u936MjTyww#P-gc`r2UX0|5D3CnG!sn600BVp{N@2hdw_Zud`c{R=sy1 z78~_~LY*k~^1igBZoUBg&e4jLY_5|0?CBuYiraswxukB`75Utnc-7Jit;71HcEc4< zxEY4Sx+6^7I>mnSk!Oy$O@78maN^KFCre(#%N8f;I!@B&jc&uN@`PITPS3>a819hz z;ADbG#wU9;qsI7nMe9$2d(_L!@s!%s3taMD&B-fqXCCIAXyVhLVoVnw9r@8iShby_ zJ5Iwx$);VkqM^jVfaeR(8MTr&^wB?J*mx1z+s(9McNk+#!ntb<@E567(ff ziO;4DqT=@8vTm5<)4}9!7?6%23%v??9#n}+Rvjj@k1a3Uh6riTb zAgvJ#HV#gspgC8*8T9R`Dq94yB}M+4NJo-b#Zl;dAV?Y}N4ar>Ng7l`!R?^g26mF@ zc5puKbyGhdsg}goSqwXSH*?Ep%S_ZXOcS4!=EP>C99hRZtXk@bDSyOfE`_R;gkehI zpj!##0i!KuaN^Xm<$Gt?t_of~-58hiaBLQK4WG;qz2d3DNn&?*$nocnBc{KiHeR4C z{xF?#k;;OF@=e|O`XG3lLC8FlxTc9%MV!Iq5osafA>^l6V|vA+X7n3cLY#sc z?;qw>docF#?gwZrpGQmLN0o*bu>&i>!>Y$i%GBY4xs~FKp-~v%_(5jGhv}XQJ)5kp zzW{45nYckFTbvbHP(l|ki=Elbnz?v(^@-`#Emyk@2Jgsrkuuc2;4j~1;dl6Bk{3fM zj+o*LB0Sa8zUvMvF6{~J_IRn1bZ&Ht27w8QL^)&`N1HOcBHWw##JJY@pZy74&LKkja znLYnNgZ*!*J_f$iX5PMY-u@c_{NGAdihqX?*qAsu8JL;;>#VrXob-3x3?lfhPr`N| zNb2@4n-#oXIDbhJXcqY5+eh3(q{s!b5W(&j1?OK&?jQFRNqheEWdc!KA8eW5BN(a? z*;+2?baM;6Au({VF;{jl9!8`Zy5Zs11Zwf>7=3`%)CW3%vG@@zO!F9fF8~dOIJHd1 zqAg+8U1tQ;#_+Eej~Y#se(^+G)P~TzqD4QIs_g>g_<|i)2aCZ^YQ3B;nqpgr_P4Fj zo#@5`i2p!IK&>jUtG}=Cf9A{lZyh`Rzq<$jrT6?-cc6b_Bt;rf?#fF)KWAt>#txC{ z2jYTYfdEVih>&rEB8UgRO?K|Y4d)TVDk7f>+pyONAvQojO$agcW{pk~5uHTq6D zVSGb!BG>kear*AYY7fx&?@EKvgW~iw?P2LP;{sD?IAT)3+(ijGEd{}K8+Khf2~F)Z zZ>ZljC-D+)uwkHYlYiJryN?9y?7JbWLY41m-9Wr6{NjhYIUyl?js)`?>M(q=3)tEj zy5Q|Q!$6|NNWrt^mTZsSt@vX)$n-CvIPE4YAKlm# zhU&TVa~iFaOZ#LnZ5=5M_pQszO?l#3w6;xKbS0(0XUqF$?kzy}cI$N8wgwt(>!!&b zt5~v*%Q%+VEUvjqCSP%BtcK;CXDSW5tSat#eH6K23g-7jbV}>87b_j6fuwCoNkio} ziagg(e4}(7gOGTu+jLf6(%urMA;hujQe5??@t+QkEABoz(*ilqq_R1Bw^K09dZnOb zqLeDph8Rnpfq2P@cpb}~%V$cf%Zp+Xu0xs}ykfUQ6)TjNK*uTeArlAClVku|ON`Ac zkZ7$7W3YomA;AeWORpa`9-yDGiFD`*grRPnDEkh2{Q-I2%#n=$YFR%1D&PrrG-+4_Yy=VOy#mvl2OPpH@6_} zL!{A%vAM@1IfeMe48?Ick{E3CedAPEVak)Frpg^H72Fu7FuJaWfj43q81<3s;COP@ zhmRW=h}~p8DL~z4i{R$5sEPt?g1$Mhu zTkk{H|Jjp4dQ93Iw8TWu6&-$2Cq3Y498>pqGNCv{?xjW=gNzd#=2WNptuRcwN^qbR zB}@itLNkmUKFLJ7Ylu0ePG;1mze2@P1&VJnT&6BB#*N_~1RM_tPb3+D=n+9nij=^^@$Fr;UgKP_k&|E2qsPPqKpaUWk}tTAOkSP{oq|P@CzhL4l6&W_&Bvqo6`R#zqHl{45jTP}~Rg5XXY7n`AtNaQO zz(DbHnS^QI#LXv^D07LRn=f`XYz9s%R%rXN0G3L)05GV5PNOQ58a7cL0-pn2)5i1b zJ%d{13W%WHZGs}TPI2U|^;iJd*s&XLu)EgsUhUDjf-TeO zsbVXT7h~@kAL&YYp(7Q;9hiS`s|ECRgv@euPJ6`Rkym4q0dT;v*!e6+Z>V~hXSjyq zcWQJLD%1kBZk@rGk&!{R?MsJSR5Y)JYtJIIbK%qZ7dCvLD;Rc8?q1OxWL#Y9r(hz% z9V=Fn;)(((U-KG)&{5CN|AHYN+qP|+{W5d!t@rLsy{S6qFF3pQ zK5Omu{j9g&r2Y2XKl0LYdl!LH2Nzs6XQnN0Yhx3A(<&BaafxT!Z?%&X%byu6H*tLjRTd2dr=I|OPHiP)uCekEi zQv&!v%@fyCjKS&TKVqJJLDb!Sa4EZ^#aD$pC*j0CbrKn2`Bg4%zXu3FySWU;=_uhtx-%7vUam0L)dDk+>S4kIJNR zIUW>8Z|2;YBTi*=WtVu@EQ;DfEZqSoO%q~^I3G4gj*RWPf-U!k%6?M^gEqw4%`h~j zQ_664BS6L60~^o@!6f)$jZe;l-Pz&&j3I5osNjOxM#W`ek=>@|GuNj-ak{_eZVPZY zGyP~9MzOGwqi63}Nzb@d&Bnb)-` zm@h_^Pz?`1xP=;H{>nfCW_}bF>=y1B`>9KiQH!IP%}(9JtASS`@5zy}Yp=|pOOuU9 zeOkfFLm%lupkYYDQm6@#G8e{&F)`kGvFu!Wz7cy~`egw;ycmy2q8>Sb{M21(4NE8L z&ayn7HJCw&@zT5tLy8ek^qxbcqiezUb9W81P8Uu zL04y^XK45=zw`9{CGVU)6LcLSy?(hRZ?Er$l zGqCA$zo6iNl{1@c%tGosrmZoSK@oYhqh!w)SBGv(mj`U4HUNwj4@2fBdC}y zB-oucu6RCjl4*jdQu$nA87pzCU}~ut7fP9OUi@}$ob22_KW}nl;KgvE+d8LsK^sqp zf{d-e#FB84&XDo2D0r|&TXeun{kf-rmi#0EcWk1S?nG#GfVOfv?y#bfEyIf6{IX~@ z<6NQZVKVzq4!~UO8pycudccAvJ>#;i7^amuQIt-%PZxZt4(+5NVY(l)T#SiskkwKc zjjo?o)88Eck3Or&D$k;6&Z(*hqvQ+0ZY8N!H{PFSq%kI)Y|j6;UzN`*E)+^PTvAEM zKQq>xjkz>H&91KsJ4JJ9hBMksz7d}WFD&y(pD9F5-$@l#9r^Tz7+O*2&dITIQ0 z(1!Z{%D`BNvxfZcoUOl3roRrYxK_?dcXQe`KbH_p9#a&LoYtNDu|_(5?nqtZfLPdxS1Ff^6aIP+FW zfiSmRXG#MYnfC|Sp7))>`6|#DX}J>WTUHijb+RPvbbRC>SR1| zgwxGXKIDV@q;@6D_mIK&QW$Lyp{|Dqom^!Yta2hqsZ|sC^}wgl+VPg9GiUHY>EdTo zS_kqhNG1pZaT@;q-}R`mMhF)VP^B}4$-)t)lxIVvlBG6O|BUB7!}FhJcGBPT0-KT{ zwMip*kFeJzW_2Oi14#HWb1)pTA$QPteK?OieE9{hiP3vB9&w^`Qi&2HR5`lEf*wJp z^A(MWx&`PSS^kgYIudpcajhV(mVM1(Ai4la7$-%#7oldHHb;ilu(e^0HqMtkW>=SO z7miE!;%G-tU3W+`8!>#ja+zly=Q@o)6=m)PcZ1U?cDAgw57D9(aakgMe1CwwL+2iu z>d#R4K1(PIX5=MujDGvB+PPBgp;(}yhC4b_8<2ON!YG#Que>4&k_8P{rogMyRF!Z!1)v8I!>hf1~TY&cf( z{&eBIoaSOb$+sNn;wcM#!qLgQ+S{R2!Gbq2bF6zjHgzHJ&x}&z%!UpdDOSNUGL%Aubpz~3Z2qHt*>sxeVxRH7ohA8I3p$gymj|3G|7$N47J=p#lBfJH zXbf8K0kjuRw*Eb7LJ8_BkQ~h|EYC#MNh;6GAsARU$j;I73+gN1=iec{!)qyNUDNw; zV6iXJ$XV7B_l*MYJ7YPsvC|EwGjWrXXMg%<`_fj zXS{pQ{xY}pw#mH}m=8$L(eh2|XLg5gD)3DoL0acbC%;2PuWxXV{Ywq>C*1dRm9PCp zj`a6X!N24^e&|ZSf8)162>gAALd1~JjrWhF!j3>T%D;ts8|1uCUI6ocpE2I!d>#f{AYX0@(;mx7d^&e&R&DBefdWiFf?K^zLbU<63vS)f=m25Ft&c5V;kPvO1z%u&*wXfptsJv5xMags$@j zl>wzpcstKl7mlm@@5_B4Q{uLzxnq-LOrvbLJYzy+e9ITGrq~?}Bpj zCSF8qS=j1o_P4zyuefS^@tuV|90QE?0UtO6OEbbk=aFC+t2o`AYeI+cHBjy>`5q1x zUW7xXD{T}=ut!x;Pn|E9z&2+M;(8WbVx7QJR+9A>;r={(Mjj60;i7h#&$9B3L>x6s zH|)nC@C@FL7t62qU3RToCo9M0wk=y*WhWALm+ZBVM*Bx7whBkX`$<0R)tWH895^b!ex(RZ;vDADC9S237jGY>d^GFddF0>${70x7Q+dO|{SxVlaNeNc20Bf~fjYmQ9NT)x~b@HJvidUW2O&@6?)6?t|M0P?Be zT*LrOZ~~jF(f85#k&;cmM}m{mqrF+{4u&xtt zEI}yLvC2`Mo_d&RNw#JD2;s)qX}s~q*U>@{m1KC*VYLTSeq9R1z$6JV#N;$KrVW-} zm@Fgu>`TReW`I#DSMe3%4=;fVF!4yd7vMt3aph_bE6UwPP?pyCxQA?@zM{oL zZ)^f&t>198&_dLj*hrruSh{9Yb9u_%;rvVW_}6nJezSxo6lWPcrTf~*^y&))tg^~Q z6u1$O3*>tV9v|Joh;$SKvjBIA1F4@MuxR3kM6J&J1a= zP-qwt9cD&5(dQ)cD;L13ct`-jDmSi_-=l9;ACe?j5f&#UKF~(1aKLv3kTa2g7*{Gd z@GaMaz!+6#Z#u?LN&wm(K)-H(o@=44La$HttUZ%C6pUK(?|s)@F7tBkc$W{)(o&upz$2eLBW zsyhVdmJXfcFE`PuAi{2|xQB8pfyS-`!<_~&;GBBER7?(7lu4LUlu&8Sh}s!A{Iyw{ z578nosd1yY?A#8`&SXpTeCy?*(u!p}H5$8EU(~O*_Z!VNgj;1Zc%#iZB-~8DDw13I zabK3JXeB$92QS^mM$-D?c+lQ@j#Y0xMI(peH{lE>DPVm?_L6K61;Pfq7 zYipuwV_tS3C3bG9@o0Ht)HN*XqClj5(B0yu1TK#dRBw|bnRT;?H(ukm7dB?RoCDh8 z7i9Q*3fp2&-k-F{Nov-~>y;P>jgWFED(ft>C^-1=VuKE8L>3MdY}xw#oo;x?Fs8|i zEV^{hlo$abZ`v*|b5@BbX=jGR5rI05AD@Mt#48|u?^7vxQOQG)%A#+$`tl8bv2i4# z-oYEI)#VXjA*dE`A6-oCCY{%<17k_K^y2Ta*e7hYwiH(xfN)HNQ=IvtCyG&b|^b{#E~B#0(8D`6SP_&Q{qOq~rtJ@5cX! zLdYpD#S)JkY@Nhg;5I)FyMVt;rweClMrT)zevwvJqz@%t3u3(+l(qYp(;ht&4zlAF zf`KFC9bl91g7qpObq`U>pE|!I^z}#5mw`4!kORYi5Q}))Vz&^zmw1Imo)zent}e>& zYYr;5limUqmmUJ?3|9@vd$`wK{*xMmSQGYhVnf&QPTLY8Zk`bqN0L3hqq32{Oj(v1 zFUbGQ@fP<}&CKKiFgB;RNCE%W! z-WduCviI@oHW?$vCE8o&sv#P|T`wVhqCR(F2ew@fX`FyF(==Dg+Z*UK7}zwAc!QE~ zZMdidc|$5u17)P3RdHr*_&u$>iq3rGkzLS+QC7;{GeP4XqWVN(+{dglM|_3OXU7<| z@>@5&q-bM zRHMSkDR(<$ntMDgi~5w_B5-=+L2IEm-p>w}R>JQQB>IwnOSrki3aQSqqt@gm5ES~+ zuE676M)C@ZoX{#q1&pq!hG2{hK8A4AT|)prGGpD^`{3$SrIzKt%`qo^950 zgSaXPFced)W;nMrCpF!oTx6FmuK-R<$M6GT00(36L+(U1-93^IQtKr)&fz0(rp(}+ z7!4w$XWp}{vR4qtwl%=1Y!TV_DX6HIF2@WiMwh@mX4T-au!Vm^aQlmX2c8>qfx=ox(#V5=;=dgloOA&t zwh+>QlMU`ZFWTZAq)g3*8%!pCQ=1&Dc*aQEBoHy6BAVp525naM@JqQ}GV4;jtU=;e z@7u2kp%>7l3$$Znx0qA2J*P2bOLohBj>^J7-Zjt`31NOaC_NLf9GOR$ zoaKMy@MO|m!8zW4L7yuKCXsGHerNb zII1P!p}2s8S=-@l(pq-xRaHr`t-KieLJ>Vy1^q2wW7&(7Mo?`jtQQFmeJ>pUe9-{v@;3Ojw#U{jNJ`b zdjgrXb77@O3~Gp{b;gvO=7Y1s zTh9&~SCG0kfN3=JQxLmGfG=u$n-RY}92uGw|DaT;uM8;^Ev%T>71qx$l8u`gX}+Oi zh<%u*OHoYLx+1-7XSSPm6!Ns63OD4)w7-IOGn7;_r;x-{GoE3S>zp9H_`HIXR>#DL zh7gyB@HRNEwyon%`lry|dXW>1`@5>|){wvd;xXT?h36OW9)XB~UL-vAsRb`XJu=vJdABJCek&cUl zw1QlM2>M@W>iG}9L6skg#zy=TD+sIuX&`|6_rc$s3q1(-j-2I(&liY&$)u+6u$8n4| zP!HXV1f#F=qTzWYBX~mWEo})b))xYXaeic2ng`8EPR4r*$}OSlH=t9{ouWa`l#WN~*nMYj(CNM1#bb^TN zg8gL7X;c~6R1GvIdzDETC#_U4gX_Q5mX)T$1vt@JN6}JHSk$gdfhGxZjki&i{#7Ap{BWo_r@F=x{W13`0YA@2K*zU1+qadAj2LWgYI><%qYEz z7WENO0uq=5hmI}PDsBvuA;lu13Z$osgnaX7#VBe*aa%LnB1?iaB}JyoeM1;Um94|j zjFLuu+XGH)0Ft~ikK=;$1{zQ-39%zLM_myYc{=jFGO@&JiVwXDLC)9UDDnYT;C-Jb z(xflU+i#}ZQ7aXbka5;lY)Ck_C({bN7bp6&O17VT)4))A~~uLbfrRg0lG#wQzc4#RtoGc9xHa3W&!G$2W^}~ z7z~m2M6~dI0;~Kd9|a7cnuog=|F~Mvxu?Wx7%IOgo`^Qv?R&wIc(edbzq1#%s%*<%mV|*NUvh>DIA$I=2QYS z45Nbib9>JHw7;Fv7^-6zjBoH>qb_#ypMF$vFXe8+4;arF=6~AkaR2*e_kVd&N$OBu z8B1~hVyfl7?>S{NQxSJ0G6$1wHbEi#;DJsoL7PpiDRK)DQ7;+_2&Jl{|4?q}&VFp# zx^Dc@^4MVwB<6O8DcT4^*KD`>fkn;ObnxcA$h2HdE|d(+Q>-0g%)CUW{hQ2Sx7+67 zeQt^2ht$UzV)fF7Fc27^=zJ}Nr@&AA7Si>S>_%8&d~0m{))_IoCE$YJM73`4)c2 z5bYq}UtxPe>?DQVoW1IK>78676g~-Ieehd+iI2vxeF_iAIRlLPB67xFP6V@2?-St( z@Dss41xFa}Xy7PB-dBiUaV)-6M{fc@bw>zp#Vo!gMstcjQqbJ6ebMg!F+a0gFg@%* zZIaE83CLQs6&@u+#fYZY@(~B(0b)C`mrgN>bqdh9LPf69aq^F~Y2u>$bwc0XpzZ1M9qjm0#e#KY}^W&nF@uYZ_%4T0{| z*{M)P(9Go-%qX-<+_;!&9B#DsyXyA;2qWTm#{5Pj*q`CRP1L6*Fp)CrUg-jdr>l`a z_uOcm4fRf0589rG2gvhmDUn&k=2=Fj28B=E62)8+v6C8(#d%EOl?6HrmF;iBgn53z z&n0qdC{8oM$P&vN3!DIE0QDjU+)(kyuu_<~b$j~idmTV}7+x$Msrd&c6;UEcwav8M zpX|SC%;OT?(suKQn9s-$ncP~L&XuA(RhfTC@;Nx)lonUA^vhI>z8+Ad6lbnyTaP_1 zDS*_)3985BFRh&Ld>KAST(*S^oTU>2WwXSdz^Pe&g+0^3Rg)}db+WYdh8^yW&EYej zDP4BQmvMJ4el6R>Z`HA*m(?)&+({Bm9VkUJtu~?)$0)SN#DW!*z2B=nF;Z#`b(v~> z_*?01ZRX5)UApXx_|a9hpeYIng1w;8wkMn$H z(>4B0^;l_=|I?it7tqP+mcBAo zU&~BkLYYhV>v~Ma71Obig(X^OO06C=#YQxOD`qR!W;?oL|`Xm z&8}s!elR~aTZzzI-ypzaII<{Q+9Hj^pjl3nT`P?`>Nj>{7}x7CdN*T89Ndg)Ky$6? zdiaXfqJ=!h+h8DfP^WT%ZGcCqnyPD@s5dxoMDy4rjfrtbY($WD{#+6GRqjNfL5XMz z&Y~O$_*Fg)?79rM$l((BbrB6*W)Tf1enc_`Ohya%d|B^ewi_3^EP9ol&ROz}gjl{o z!a>_K0XJH>X#W*b+_fG1DK$1~{YbAjhZ&)Nf;JCMBSsCIIl&eC=`Y@m+<-&&*5XUX zTkv+#0-}Im3*k!7q)9MX>>{M7YPMUhwJ`SiRDlE3S@Zr}A;415t>g0H(yhwE4`=I~`A(wRH%q ztGmL;P>D$Eq=afsJrh9xF0SN-_3rk=7I`?B4BlgUm z!|8>0$c-;awW@1)#T0R>z(-3VD?FrIQaCaJY_XIxrs$kJ=(4YI?;&#Yq;=^>=%_#2 zmn*)|IVx+N%#lHFO%=@+8Q7wAs?mBt!!>72}Rv(}|d#9GD?sYw3tuhlK+acVV0 zs!TA+BzcaV7Kqk>H^fGehU3RY(>7F*Xw)1%1sfW?TB);UpvQcBsYj{hIw%S(+1NVi zpE3j#r)^dg-04cSgz%=L!%a@|qjZXFQ+pTPJY0Tfi%U#tky|L`X)vG^WzTjGS{ddV z4r<-}GE?g3cQ(xS4Pv$MYMJ1Uf+#3mzEDpOV(Tz(Rz<>@OTTaYXAWtXb7Ppvl9uWl+x z1_c|(VQK)OQMBo~Q7DF&!HtH~k}wVow*3 zK7k6f(fM8LA)Drqu8yKmb2@`Q9sONO6qy*etBH-y`S>{Vc(yT$?4P6*ML%5KeX~DO zj%~qciirG#4+X2>{Y)J8D1!C{NCv4q%wV^xtS@b34lAHN|Y|9|?(fr(`1g`aCx!b;&!Q0SE*0wXZfcKxWgr;~N6+3nU zH!7bWUTNZ6w9Z>tvUhc7uO{?|YD=%idUt!)IV)**Psdqa7>Bvlzu#UdqJdo1BA8jd?yN?o@OAMVYNR9(ohmL~@|X51KhVdy$5+>~$EAKa|&-LNW6T4AxR zXYtM2W}H5t@Q+eTf|~t${Etn42+(?ChTT)dI|`Q!b*t21>hW;r=_@dyP?bjSzU1SLv zmGuVQ&U%pDGE3>hG(=c#t;jr>rwciiNn==!mKf{WjsY|TeH9_UML=O8>kQgY!GfbHbwdD253R8BXVP% zB=yk?tHYd)DbSh5Vw;tqx;8YmdCG)Cz!tV$;5Abrj=vv&XCIhP>nnldVOjG9uu;F( zlV}~+K2_F`zMi@?KfjrmVBAvjJJWTF(!AncBQWqqKTfQxz=j44_d@;3GPy+YH;<19?z#p$D!(dp*n3FcE^}8NM z_rRIyMEYk~W<4cx#c6G~t{YEx8X&zB=sQIae#vZ^#vTyCA0+kaTQ&+J{f{nZ!GAft z{S~tb*12ILn6%5++PUw@L8e*z6703!aNN*uw+Y>I}xb zh@v*BdsN$QSc{g8-JZ4Wtz&A0nto&J(rQfqgg0Nv{zGTJXLF@~dnr@Ew?~RfcZSL% zH@7>Np@!-YMkZpBdqjSe1y2c7~D z0uwwC;1LoG2hZTN8P%exIn7AGK)~+84_uXNG}tzhFBfn^-}s8nV<;X_qQ(TvHOmvjYrQavNAIz-L!cV`L|;EKVg?j#>V`*Wt%h@s zdu8rm-K#nx`pEfv4_ORC)XlnoZVcIOV1tf(!_5_Mt>9=}-%f&&<2`MA;6<1og1f4a zE5;kQ@`8zE&6r8tL}X zW0#vA-;jHv@BlD8c!t}@=cj9v@ITyYDzvVYvyTU;f~EE$UOoy4M~Qj+NtUm_a5WRb zF9yW~lMIIJA=S7es!+vy*2EW&oSv&4U+2RwPqff5NsG98{u_5DmCjy4V*JWz6%!|# zz!x8pPawnZL@_>?1Y>$CwnybjFqr$GG$C&A14VrAYzv-ubDv*nGV|^64(qr4Q;*hQ zK5CpjO2;692HBz05YU5qS7YYaO*|7^eg!}j5;hT|XFwiv^ zu~y>IU32i6vK~J)lMJj)H-1Y=n(SZ8`u%WG^@&B8?6Eb(Sv$eCfGy6aGmGXuniU8sj5k@>>zlgFjJ#i_HGO?Rb00u0f zgkK$KQ(_4bw*>faZj}r;WxffD3a?v`Ps)kxG}+ugvEHi-CzEH{QZv^#{QSN^y*#K& zh<;7FZYwYsu=`T;DSI^FNE9Dw0*$%aefs)B@B7{rbu|7q-4}WDS}1$$M@FoB#_Y=S z6IWCzCxUB;ZD{!6Hn5Lw_*EgymA>orjF{Xebc-NIG;&Mp=F;W`bnT~^Y7d*#Lap`D zo=P6s*89kr#C&VW0f}Luq?wBBJiFNdrl`Kju{M6_>vJ97T>;9rlpU(`g0Nj4491jt zZV^`YCinM$$Mf!FB7{j93~TXb7$g~4sU6o~oyV~IvSI$QMhYE`|9 z4U4OW&Zu*Vi{hHa`(@+bOhgJNx=Tkkk55|eThOq7R-CO=S`VUPy)nH%Vda zNd(K>AbMaUOGEGu+BdQV&Mi}a?qmClyWe!&OHq<5!1h9_a;rY_E`C3$I?vL{tSL~N zH>iR{cW@~XX)wjHj+h<%)+iv}EfozU50keE@_V#`6|If){QP^ubG_oII&@vsd}~g< zD*c6l$?<-F+{g~65Xywfd+}h*=%!rX*+D^V0D$(mg(%Dc)8``CaWFmzg=PBv0kY}} zdkekGZ98~GS&bI|E0pS#B{kS501J~4mlT(o12zRVy4NH?ZI}8^q2CI;W&p0ADd2$7 zz#iEaJCnFm?Mq!Fq33*?p0|2ArK}o#{84%j$$we z*;lkx{M~7vA@n4S0jZnROXQ#?tcR#u`jZY-T21wK3#7vLKZiz`2x#7Fe|R|x|6_^k zPuKDn)=s2K?oI#`8yO30YYV3zOV`E1*u?RFC2+ju zW&X3?Zlf?t#)#kWtI}T{VLf23!>tT5TyOT=djsA?D81KI>sHMDw$SYs;0_8*OmeVxm3F>)poc5 z|E&5_WD+&RxLO6Z3_#t5YR^5U{&J>mV)IWL`@9@!3kR(zBrj7O0gMCwH;;Axp}y2E z<=g*zUv*KM)OzV#Z-3!OV)abV{Vw6&w}ST ze#`kf4=zXU`zd>uzx*_PE7^W7fZw3<>-3>q3>J4 z{`K?zzmq)wH2_8a-#&`8osog{e|(w$>Z_|xsNtBP{)0m#$12`iyRU34T8jN8poIpi zweia)R*Ww3y;+Dkuy0H{Q`*g(KvPevrF!d}(<3_S1hD5&0n_pg<`J#+qIr`wmO(V- z|DkjJ^09T}v$MGqwDaxx$nw|ht}IYM8&3b%%IY8)?Y;_>lzMWlzY5ZdNGG|#ARLrW zWnIhk2K(BE{tbG@%33FpLNNPU=g_gu@0;7<4(n|rr;Mn6Qzc=+!Q{Wum6jIa-FccC zQ>?bbC!mlKz|lj}Bvv%RU3sUROE0f?J>D(q8X)^$&W@Qj;M11Drh2H1cwEdnTc`y%z?z1pifFUlg;?j3 z^j&3|7vsgUam~C^4NFT?cx(b-2qDQXi8^HEX$tI(=?yHLo>R@rWLKo|$1fDzf0C`_Kf>Q7Q2vNUaWBh%qAoEnHL;!`@QF^(W~PQzqNr%tJ$kXbYm zw4x6yQOn_|Lu(mVmNJ$nc+8hkd4!$1lC_PA@$Tg5qO54z;8OSTyj+vx$U}eI^kgmb z5R}lebXkbjJbDU%%v=k#J#UddT5|(x_Kpf1J9$+aCyhW(>;{c`xr2WV$pJ1aR*8e? zFywUjY8+Gei^wVSJfmhqJJNS&f#dXp?n&YtQAl!+?BM zYPE3#b|dD!3xRIIoezN)#ZA1QD1r8eMCtuT2y>qxL8srw9kamL?&e4~po6&n`}7K;NaPbx z^t0>2R&u1DB7il*@viMuT`G!bB@7f(}e1d*b+2 zJ%0)vwP$*8@tqzZ?qhkNKVfb5PZHl@GLd=!^DT<=Ou|rX5;X_g$vYysOCxMPdXjVF z0(Uf$kGQ;{FuWpw;P)+~jqVBoUm0_30kTH>88rweFeuCZHp#Gd2XJ4ZmaC7zRzz4|Sb zc7>-z?m2v3v3+aOOIO*#Wbg2fi?SXJj!*|+FV}X&k zNTTHW^DmBK?jQeughY9PguQ2fO!5RwSn%~$Ki3D?u4T6nLxK8Rhr zr+o;!LlFeS2?rUCLU~}0ZZA^_JA7*|5}~9*WBfTYJ^!*lHVnkO07VsgOoLU92}FCP(fXsy zI#kiY0m-*GokwwofFPe5Qs)fSw(8I7Ej2t_D_6oxkZO^D^xHQWLH@RO*L8c$Wi$Db z6PhxfC0-InJb#jflVzQ3*A8>%d~Y=uEY(wQ@9($`{1hF}LgYA31)&}~_$~X`p^E9H z*kXsB(dH81{2iz*B|MM~a@s_h$v#$jrn-m{@Mme|x^emTuhJnde*OxD{2^~}##A<{ zpc^+HNa5aEXKyp^^Z}nK5GJg#zq}yZuRoK#^Yo3u)hnFJ-+!&>yn@GnjGFwA6x|eB zvc!x+m(BACms1%69xnEQ`zCdgxM$;%!a07&K?qdG@8^Spzo1|31|05%`m^c99hlc5 z)L^pXJkB_cioxQl-G1ItziH)Vf(#vFEYaJT(g_Nfo=w7O6m$mXS=G{xY0D?n+xmxW z4_(T(N6u4eBERO7UyuM$>FM)|eTp@8)2`>3RF2X+`%!&nhH@|Ksh~Uob#9i077iAVG%% zx~<~@#cLT(V1`cTGe7*Nw2xg}o?5A`^X_j7Th{_eSI9L!jZ3HeoiOgK)tla#t<=bj zOb)^x*D?DRSP)wd`xu;;eGJ=Aa{4#$?7krZjOg;;_lHIJX!BkZ^P|-F0uWJj&%(-Xv+#gE3k3-`+aROBznL%-CgP zgYA*&eO+Xro|QIcEvKnXWHHtzq(+T*KkE)D1{z6;+pw6LT&In zhrj}mFq_2+-(JUtr{!$?&zi}ZEi%H<+NRscy zZ6?3S2m||=?#@Q;l$BZNU|fyOu5#3oxs56Yu^RiL(`c>V@i7y(E`qV6+(H_jMv(&c zND^iv^p$pyTr`7d+RRME%Tmpjj85u-^s>a4GkJ~A&3_?MnlzcQh;i!9DCm+BV>n)f z)L_hQ-(8sq9x48EEOa1-(hR^vk7Tr^eYbZLY`z$ZUSCUrHpWODHPJsNG-M+w(%vC* zEUdBBijg)FE6{%mY^_rlC~ogU5Pa~%hM8XDlxFW^*}@$I zSQC(RWz@TM8*d-q>Gzt_aDp>&FcOoE{4y{jUrU!5Le2`Lnsl`_7AqvjmjEmqtC2l9 zqFxwUM3=Xzkc2_s)6xG))j1m*+-JLp$BS!KNL|`Wzm#yUH3Iu~z9@YNie{xK1pI$%`O9@@=%O+^7pu%V8BDo7zHj_(<8?9{5 z9XL%kH!HK*fcy75Zf~X*(N|55>p+f_<-01Fe-0(4fi^u?iAe^v41-ZSUHmYnP%$ox zq_l0(M8I_M3q|z$K{q%`T&x||cT*f-+WbLc;Y7t!8qUbJGezTJcvq@X50kzaCk>gK z<}vWCPHd^YyHXZNJ|i7e-5!X6XFwM!IBC z$g*@+4e8021=X;4*6KGA;aiqdYcFk-&%1S}4xyLTLlJj8Bf+QU-6fmkS`C(+? zySO?mBcn`jTG7`%69)OwcD7{kdup#(%|F1diW}z&Oz_MQ>e#nm4WJ!90r0}xL7bT} zK_YJ{A$%6!)G1u3Q$EUd=K`ZFJ;-Pk|f}9HC!V^tN_{(7l6ySRi3nTW6!F=3o3Zc5+#kHMi{0YOZEMK8sZRop9-%ju>%aE5;d0D zo7wJpF@W`L7c#k5Ln$i~_)Z{INH$j2iXO>Z=T&217U%}miDmQ_)HhJt@Q=9st$S2C z^GTyFF+~jld{BFX1@=3P&txPFrl-xF$@5j5!c3kz)fMo3VlW5Pu0nWY^s>?gbZIC5 zp0sAzxLTE+gw*4E#^HZY--L}eVH_I3DX9-wbeh7trch4%v~8%dWiETTXnh2$1g0I_ z=2ekoOJlwbZ7RAa!cSiG;hCbT_f-AyLNgBv_AGQZ<1%6tZtC0t|?ZJe<&;I@ZT zfkyXPNM+ySUTc+{j-Ajeh{=n$X3F|9$WnLB!M&!sWZbPkF6v29Hw_$zySe*x7 zDyD>2CnHMFitkZ@W8a(6-<7shiTkLyvAijOi52png-vS4PXXnriCXLIu5rfA;&_C~t+Xap#RDtpQRe_v1S?={$yP+Jm3 zAZv{6HZa$ov0s0Do%-@^`=v7IdmgyItKbjJk>C>O$(G}}4@>^W@g~4ZewN9a%pQsL zdYycqCUu-{6V_`9b=?RmYpR3#9~X!KLB`%R`$5iLZ;Ny^9{LCvt;)g9k)f#ba(MC| zHXLN0P$&rbMcwijqkdkXs3}XefGWdumy`~jrz*3Dau7f6-E*P4+~PL-J2y6|EjYXt zePo|s2tJ|E+98Cl@6N426b@=+s$TAeTSU#ChTU5&^;<1zxERKqiy;OhpxxywVl5rQ zm+(iX36pDo?031W@|4m2K{^z0A;r73Bz` z?`reQyi>_1J6P90-iV;BEVHJJjOa}aW{oP~HoBhq+}4;rS$HpRSF2UX-SNCBH=-Uo zC-q#|q6w&1MjX==B9@=?GJB-VZV8!<4bQM8_2T4i2qbQngbyaUN=DuS3RaFCu8SM$ ziA{B65*!bc3{ntPgST{71Zbbz5%yz*L}u_~3?>1K&u%)LcIfU~ZE{;$hf8mfdb?ie zC)azK2TZ;Us#B8zq!>eP zMiBnP3H~+1YzWkIsQrd!w(Om$@#194+ne@8NPUM`eg}!ZudsOFz`75W8A&l0Su*P{ z!~rrh`p=Ki2e*Ia7T0CZ-3y}UXk`T^GlId8LARgI4eQGd%x>Q~J$xsDz-}J5Qv~M@ z-e$N1b;vVukiZ;byCmWkNXH+c41-{S?=x+?m*SD=TQq0?CLAt@I^s6X5t&adzL1(~ zK5=5K_>x3tE#@T2(>(tkGl??9JpLX#Dc!wmLC~K-OT1R+{@tEBL>dzMT8zyAk;wU64#G1LF419f`)1fq+ZK;%;cJj%;nkyEk^ zxM3B7jTJ@89DP}yY~B1f@#mI=Q(C}ITk;YOX3^mJnFiy@FSaYAt&lhqj_3v8WhEFN z3?pc|z!dbfd;0oAIum#Qai#iuVRdm*6^z)$-gwnsktoXIq*Un&x0IcyfvY?TODQx1#BlId6=1TS$01FNPDnvH9ah}UQE|jj~=&w%fOl{PNltbE( zyg?GTSTa$LI`kR6wk^_36D$?_KHsA014)ip^sBR1!Czptwa?E4-M#~M2N57J?XKt< za;#nMl}Xwd0F>k5L7{5RL1R-D4ETHPt=MJFHi-HnKB|?7KL2@o08s^FFnH1Q zE;V>N)bDqw%}1r^+Kjhn-(XGvjF=UJk~hrGw53w9$pwzc!#LvwZ(g@{TlVBA{_OPL zErOM<%`Uy`YVq<~fDlcL2B3QQDEsp2rcdPlqHZNPOZNm(FlEIAIs4jqbY+sOWyG8A z($gV)qzh+4!}LfXjUKJ~(o7y5LST*4IC;QC$=@m^YvIx=U+u}Ve8h(WJ;F@6hK~Er z65q3S$?9R%`=ViaEZha2V9Y4SQXwKc#pbyF>bCwh(<%|GYLg{!=*6XG!OEz{Gpnon z7sz$k%EZ+zThKuIWD4kb7q(hxk%7!Ah;9|Z1h}0!Liy_h-*o8*X9oQJ70+nf8{*FF z0OXue$U%a!+>;bPf|M2>|>u<%Wh*ys8 zaMUBTZHbx#dsnb$+CLxBSc}XT0O0vnfnl`tQv`n4(9s1aWOyz$f^mgs7f@Q`i zrbhY95DAG!Oe$sl+9vo)pE%!Jiq64B)THIfD<3Wx%kzxM$z+u#RGZ_>r`pGoNk^$= ztc*jxxK+t$Miv$(bT*YHBvxyKn$!ApSJHPn+9nojQvg_M4w~0rxB*<6_1>5N4`c5b zooSSHi^jI?q+;7i#eQSkwpFoh+o{;LZJQN472S0AJ$IaQy89dV|MTbBWABBz=9<%& zRSFr-iJ^m#2L0wk(zU9h!Rulrk9W5&l9<4&NwQWG7_twC-y?Eu?X#b?$}>#|*mg93 za8J2?^*7mD8}8BgE2pZYL$It-eu5BeO%v68nIGbp2UfNUY<3_X&yN%0YLecs58**6 zV8h#+CGR`Dqz#$~9(yw4WH3`gA1&&x8Ut6syL z6`GF{aDhfziCS>Q-GKouyen;5RMYgOLA8$Dt?<8&EG%?e^DUi>!p}nHzagiLZset zOC{|%0QK}izf#~nV?a)9Sg-P2q&?5&b%vskL#h{g4{oj;KupZuS5XvFn4L0NpPpqp zviz7~e}rgSKUT0s*}skIG*=1lDq$Qgr&MK=QME~{Sl?69xv8|BRE=bm&jylA%G$?$ z{l+Co_S1^zS5sxEHnwA*jupmI_^r2#mQzzN`@)Y_3=PYIGIOWMeKk@tu4!BTe#+)2 zn6!ziy?Xny+pZViE%9Mdb1i6}voJIU&Oq?$NZFMTFy#;nax7({I=Bv1w#XZf`aP@0d>Sup-^_Qk>P|M>dZ7xV!F%5LX5O-{y-zYzyLsQ?{HYA9f-afq zhip(>M;UirVZmIbS_9vBJWjlr_w7@$FHhsj+q8zMH%X1iyBYSj-8X-b0(Z#l_C!TD z41nsVfJfG8<@(gGGiGwzuvga9#6DlGJi`%Y{(TV8-5&7vLyGNUCeYWdoTJ(k!amt0 zW`VwEj3tP#l^3Ibx<3R!$Bxr_IW|ayY9z#RRkEeyi1<_+K%uPjx!r2UF z0wYSF#sjd#E?Jw-?pS7(I=>pDUfn}7%{;18Gf6jjN2c!K?nt2pO#KTt@eYo`+2n2!TWAjuF5;1Y2^iizqCLOs>vWE#Wzgcm9lheq0s#3Y=@2`F7 z_NK`TEZ-pCJ37(WtXvKI_oJdFhQc8d$5OdPulHguUK31_X1R@{^*#_dmZN9z+O0*^ zT@yqUOzFttp$$|>fOt9*LP>k>!fsM;Mf-Xh(LH1Fz4!RNjm(iPTBDvzD7HoSQGS*S zeTppO)^|xq@7T_kB!SByBj?yV)y{`e0X?s)q~NAt<a|qf&2NA@srT z8U}cX434tH*LOU%@`h=&sxaOc(#X+EC!bvnQ z)mrVzsIWaUbhrTW7S{FfDAeQC=&dBw)mZXQVAbh*v0X*@1?Q%~BUA&~F;Xv_XBxi- zIG>$oks%deUn`FDdgSQt?MbjuMa!J9;|;x5`;>Pa1A8UtcMxU-(h}$)rVTt z1bdKifD`VMg5%c4Bm2?qalkz7x4`&@#-=Y^qk9JkD99id^^1aPNcW!K+1PvWJswbc zajYbE%N)kSdY(7~bi= zjO!ozQNLh*((Uplg68iEywn7I)pf5JRtDHLAlbZRDFUpWA+8uw_Fy9d)7Dt}Q(^v| zeh#9yCh)Rj3DVc7**JSizeo2`EMa2Rwvz;5ig0UT(LK`1&gV)llLIQckZ(P;hS9~Hmg(lONCjWzVlv;J^}g+alVdwm@@ zN9+dP2yA)zTQp@D!y@K1qDT9rR>Ap*FDD~%q1g<>aCibgX`=cY&RA`S;T7K3K<`<- zub3jHB@0lO`y`gQ2x)2z+P+d-Zpq(gTt`ePEVtVX8k!O`xLfX-R{^Y=39Q!R6vY3;w z*|9$n`sNYBAz-s1FUVr%qvQ90q0+m^XM9+GN0C_$5~so9&k`uA)gc+bVLvHzLufG`gG9D3=@jt-kPcejmT?w=%&=10 zFWt#OG+L8PBL>!zOknDKOa!Nnwl>^T78x!U=8sjVu5;#()a9L6WPt0IMTnY}Z z4TAo)ODr2Vb00%fNLmeiO(?=$i54E_2FljZoC-ICfj8q0MDyev3GTIW92%l@gaa@y z#Od<7ah$)}P9nQF-s0kxBsQpJ48)I5d1-9$R_QpomU77&YSM@$ORKaolk{0?We@tE(Xzy+ z^k`@?#;VQn#FO7%c4;x30Dm|Ke#b#@N~GX4@(4*NPsZ~qnlLt=@$!v2P|2sm`)b^1 zvA{m0esG$CRd)%fu(dc*=;1I$&0-G4w0cgt7?rZzLr#cl{NMm*6vgdK#)Dfc9*Rr%pY?AXVy;i~Azj=wSM#@s;nFwxmQ zeC+AvNmGnERv6hnmN}-mXwhL)?!EC@HjK^(1)!a_o5A5CkO%j08JqX8QwX@_yZa?s znc#5eqmvET9e_Rqoc?}Sg&E91x_#}-UN9W`Ab_$kvWf&U4Ws5Fk~FYhHSX~_z{`bM-IlLPAs+oXP4)_uKz-lrl$1egQ5c;a(CPWHLp-8cwj<*@ zo-Rq%zi)pB&2r^rd`8UNGke;I{j==Cf2?*!L4Tb2QmmeIqR1{$5=I72K^JL6N3z1A z(ktZf5P%mwX>rVIVfLml9;v#DFL!s?4Xl-{ln+!Fm~e9GT;WOr*!)H2fLUKgokqz$ zs`}hV>}pWIDx2Q}X=2E*b`D&HhFBoS3l{5+l^XtGjvRYlJPa@LD%Kv`->wSqck;|S zUa#lyarK-jYF<_%PRk(`8CZ^R833W!W-r{WW)+A1C_rC7S)~{)` zN_0jS@9Qi^JlBbNBN2Z>wKuGpwkXPqQYHN^RdI%IlYHeq|5NU!SfePA`xoN8RB1=z zgY|qxF;}_^^6cxMBvZthAAic>fPgf=$HxD?0s41k;_n9NA5;ZNTT{EAb~g4F)+UZ* ziZ0eBN+!<#nlnc$>&T-Dq470zn4HzmYJ!1*!+<=2YTSS(8zKV|Dc~tm%y(@pM!1bT zhAw{taz4=c|L!+H3&)B0JpFi4Q+|*Wf)OQU@S54ocDhREA=G>3_XS}L_5cM8y1-#8 zAR&?l?6GSPN?=uEC7a8L_Y0y>;h(8S;WFB59RGmJFgQzFbO_ED<%Pl1H3~akxxj2j zf9bEgD>yd8>IVn7+6dfm22zwVrE#qsZ3h^wSSGM8h-6Hub=5bi(ygU1P;cIGR3%qT zI9)BA3pdr%<6T8dVcF@$kW8%^%OBt0UW6jmE9a>9k3tJpLTFx zb3N{IRM`9N_hk}a^Hy-qJV^HAY8{=RCQNhaDRQQ$rz)IllgR=218!_Vh2B1Q-7~Bp z`VLWT#XVlpQnVWeoLcwM3xOnbiKMIYDr14>3=o$#%< zB`$3ftceHiIiz{Htoa#!5E`$CUg}w)9UP8@cWBAGpvY@Dzlppe;!q00AjLwac|6QH zf-|_@tkeNr&`zEY=CEUx4es%YpPB-6C5)Idd;!pM@d$;m z1I+M0oy&;uEG)CX*%Wo(Y@Ppp^S>=D|1XN^e{TKB6itj=934$;jZFS^|BF?nl}J^v z__pv*c{84sh+??QBq2wmA{h2Zs;`)hX8{ba8{ddlr3bUG1=vZ7M$hytOHg=IV;0O1=TXMGTBURU1I7HXK$b5$GhM4bF zR*+dtI+W42&6~WWgjRJM*@xI}>jJJ`;jKobQfbZjx(>aX8>XL`yvEj%VO_s*NS(2| z0aR6oWhV}Fk(x;1wfi6?q)nrOb-Rv)xp6Kn6F+K?c83^y3GDH9(S4W6jTm)WyWh}u zYnn8-0&|ruu!a*YI%ZlUvX*gm_!~V%M46lmzvZu3QpvQ9bzVX%N>EF)I_Zr^kz0JG zlhP)R5}cAOCQx~rwMr}jAS)_Y8|wFY^O_`*)mlTLCY6ID-GiXAuTAiPyynV> zLGhfad~I;hk)xT^4?#aF)L?R+>NL)=cRhsBG7#PEbriYy4K2qBU7^YKyC{fEXL$)# zd^?3@mIQ2fG`n+krrHQti0%Fj2o#C&o0wlhQCMLI2B6My1!+_c`-7&my{XfrsO zeGU9;Y1~S)%i-?p&F&E^0o5<+D1?d zb|?9UN%9tr^`Ka-h$cgwuuGkgvcL_qW{~Eu5jAMM(^yI60(;QM#K-cE#ggfgX>fbO z+FnzjjTz-Wr^l=O{ifc8@il+2KFo=SXQ0Y^hzdRMCqKY&ay6U(pjX-BV^K7C^D6A~?2L5whc98LMp&>Js> z5x0aSHWp&sLq@@-1S6Lrbp8l-EQb?R!!BqF(6~!3%6Vr@Qm-I~r&i?gky~8l{|ufa z$=wz`nTvOsFj@*hS`L}3j@DO?By0e(i(Ai0P*&Y{1(!=$MY${rWwq$XJhw?~a@ari zajwS8+kj)=92oPYKCRBH3HTHX12lJz{yH)49Y5`M8SGv($i>|!d&-}3IUu#Wj_vF?{^DTQ{Wj&GET$nlS zpOcBS{kw-=%WwPbBR@dJ0=q<3J~m>Y-6!M}0bJLJ(hdgvam#}y6K}%op~xsI(zxR) zj9>2Xj2~RcXj@I_-57c`T?!+HIkJmg60!ZS*qthqxYmP%WJV4d<$=fg9X5p4mQ7lL znW4A3y3b$x7#_=UM)*<{p_f|^h|?@|xt?_TAO=S*Lb@qEPf+Kxxe?LS);xWi#)fh) z8G)J~PVMQkPuwX6rqD1*&c?=r7ziFH1F*jjRT(DY=c*_D#Q6vKjb$RD0`ANgkZ6n| zBui)JWxq}C#|s#wHC&caPNLs~x?Uy)DmDs-c=9+{%Jw&davI1hMYCeyV#6C78tWv`DfZAJV6wB2J8ysfJ zNikO5$SIftc`22ja1QVQRtrvlcK8{i(h!~1YJ*r-uemA%LPZ?SB8wqkc!ph3cnwxd z^Hc&Yri#8^btWreQ`ylfXfx`%!P2$iq?^5{5WHdZMY{O_33>Gpr@dWc&8%ef1%1Pw zfc2xLA^IeA!!K3w)TE^^m_JwJAm+mWe&AQQM-zZ5EXCuNf%pOJiF&^R~< zehF!PKXvoqyWzbeUI*c=A!W~Aw`|xAoA%7gOrYj8Zrl2(3O2igEU>*Uxz+e>1uf%< z3e+x_H8FGFl3bD#L{;<$+!6PCU2fi{2apLPdt^NiuRP+X9<49oXUDxmg#;QWg1}#eXjCYJxE~vJ1JO&pfce|u ztG=E%T{`QWf?{eNbJ7JV#Xfa+j9)i!0mUz@bl{zMzC)KN-YKp#ckb0_ejzC~d;1)% ziysMp;Z#!!?i()%G4UM=A;~iO)O?gcS}e3uf@|o5dxR!(v@@hdsZt{wt#vW!Ca7Ss zVutMM99s^+sgxymIFA&d03IFQ#1im_ew)&bb^zqm@)$SuHaF}bhEUuGyw|^+%|SHm z+TJzEecn?!5Yz`#I@@t()oxx5IEsEkq7q%9)X)~K;Zhz;R_?v`aqGB>nAGbMV?fu5 zUyx|Kq3VILWjC?qhw_v;l~w(0C3d;;UsUlloH&1x zB%4UcHW0CxOXvWO$FFzVGrrlzN&@K>_r~3U&$jtF)L!k|M+*^4jhStj z2ewH)aT)GLS_*wBIwPu;W{AOSqR3CfEXrObOo~Z!DJ8+M5>V%$}qyW?Y zvJcFE#Ne7Z8ZtU?AfPqq|0xFl|E~I!9Sv-qESxRuZ2#YQoHX^__56dWZQapGODI}V z>@O%}6Iq+Li#Z&KB~vGi76APNlbcn#d82i!07(E<02Psd6U!(nT#O;jT$t&0cWF>y z{AF5Evx=`b|N71J*u#(Ie$v|S>-C$n%{UE?BshsEuunoJa*Da<4rBlq#)#z~LJa-` zEh{MxOAUU3^$w*-653@rDd$M-r6MS0vA(;&s>If$5qpHaYBDXz^B}}FV?kQl<4QqX zQ8-&jQ63m0t)C4?>-K7B9@K#9HyPdS{9}e9_t^noEM35KgtLG^N=C zdUu0ZLwpUMNB^`5dDP&O-4gGm6NOqW=4%kK4D^aQ78z@+hc-!IzgN7{604XFO%6LJbno|k-!Bh*a z3WlmdFO0FK74(c-PKH;2^$SrSeDr(u)D>6A71G8UozHs8L|p2^!qAKA`O46)@5d@} zI`vUWZ|EV;O$S(y_{|%bpFhGA65wexxFvNr6X8S3&P9$ z->uW!_e1*cg$&7mDr8iYfBs*ac#0dgC;&8_(2ZVBI&@LGA!)mDQ6AlW)FS8r3bLXM z!M9mVmfo?$xU+8~41#ymuY&4u9Kv@Xf$`Q7B&u2Nu{E<9Zm-L(Y5uq8+}s|Z&fc6D zGDk`4)6oN87{nV!aQIkfYeVUQ<`8`N4iK8ALd^yhuLaMyx;1myA}vrW>-0iFE>kTC z^k2$aYroN>ys2vW{4}%Qxl^n%FMHK~>#Y4C1*rUnc>*s8-j5fox_UH8(`dWXcb-r7 z9XaO~Vby{d$&tSHFyKhWqnZX7GN( z%a-T`&e)jcOnSuf#`fs-m>YFctLtjH-%VHDxwIdHF^;-u1_$Zyy}DmND9tHxRt3lW zV{mcCA#(Q91$}jWZ`L}KBGb*dx7{G?F`=p$n0~|Mj#7{bMAMqBHtNizx>!lHtyTVY zr;Y3APDcCtC1z&!QRx-)vv}NT?P@V@4IkT`{$$^AYs`f@GPW;&ku#CZ@u*+dfrGOO zxr#_EH@aAdw0=y-J~p-cXV%=_!TdQKxD*^c>e%iw>n0gNP7zD|9fwGdAdmQka@Hs5 zZxX4ugk-(CWvhagcye;GlhP)`ldu`AaM&vDCAZM_>*;dX9%YI<(D0hDT)J6T^J^WX zm9Kwp6F%K=CO>{}62|?H+YHSA=@R|#b@2Z?djCJcr)*U#dt5d2Pj;{3WL2vXSDUqn zdpS+xwV3sy7_AMDwQwaaUo{N17mw%Ly`LqUGGw{@3!x98*9@ z=t9+lJrG7c?;%=LMOiOajZajl1A#gBFBXEQ34x7}B?5!Y*vc2M=?czJ@wI0o>ZiTL zsyiwI{wdE`nwO~DQ!^Ej8!mMD-TNqa)xJcSZX%&e9_PF_5w9vzj8vi_vMM$&M^Em2 zt?=LZ`Bm|WyKEieN@A+Q8gI4yCF0^vrqrIj^$+2$ESXkGyVp#K7JM9**eGCsq-G7z z8V#C?9;{R7GE*C@EoaonPVFi3#hs4Bkf*Z42^O8ivR*!A*3Ajnl%NOJr~RY7aJlN$ z*C*3GE0hSCVz5wAr0`aga^%Fk98=Qe5;Vu6G-LTqozu#bB!SCJug?}jmds8uz)xh_ zL)2i?_bQLBgfRuX=XHL9Eb(n38v?hfelFCn^aPJlI&$| z#Hfgvg{lhbUVLi=la_RKtyUZNh!z>KH zfXuerYh8Q+Q%lfqlAN?e4}w#5lb4Tx&b-@xu?wCduG+{tHgPec+m=77f&8aif(I3gv=NR%{uh3He7PZ1G#%$z$ zkGVeOMoMuJvDOIYZJJqK5-){hdGw`TazT;(To|2;!N!Bi{RIg%l4UNk%xh#nHf7!mUnX1WFV%6sUc|qJ}<2ZBkk&nKZLQc6bmH@P# zQ$iaR%t27p7)S9CV)+5Rd?Bush=e?c%3ZIN4La1EmRNRFASBMNK)pNI@f9EUtTxg) zV|j(KAX?c6ejE)AH{P8Ip3n&8Pi{bNIX8H6d1@ykybLkpi4BeS;brOJrP=JE8-VHy zZ{tuePxF)9b*x9Y@SVVd-#_h-4=7+e^oMYaUUu+py}~D3v<>Heg>5k-mx5hU0!fzB zm|rCE7X-m;3z>y@Xr-R4W4bw!;#7W3Y3oT8jECeWANB`u#k+WdYrzCtl@oq4K&F5j z@sfl!mCoIqX)qT#Zb!WQ9W#MH43Yj;XUw8PBaU?BrsnX??(prJ>{4u#DJe#=7);{C z$MLi$9G*jAwI$qR8qw!m(zK+`H9?+oKTE-kD&jo2bAyJBGCq&;{unU7vfB|ZO{_=Y zwiubW>ikI}WnCL*hf@qcZjxnkc0c=bobIB0s<5h$@UAB~F9^2Gk!*WqF10_@T92OktMe9U|qO zK%M9(re$zcws4-DyM69WzRJrSF-REfw+bLIgeY=|C=+u5oO}dP4)T$^hVm|Y9YIa_ zl)HG)ZBE#(TLFe23ePC)N1%g~w&c-J%h|Y#wKUkOOcfw~D`!k-ZG3e}}_pG1dk;IXXOB(pX`-0_!o zyVIB&!i?J}Gt&BKZ!MvUK_hVSRh=%NYrWN_T)JC$&NtTKQx&D|T zBx*D@J>u<8+C?}H9&lSe1Pom@FSg4J!HfK@STmSnQ(l?ph|Z9-pr`o*g>Q%l%=F9A z0b*m2RGB+g2_h#i*ic25N#20zX5`D`6-+KMHCb z?$vQg-z43}VZlT2F53+?#+ZSW`vDlf#z4cDz8H8eF5P+Uc9Q#haI%66 ztSo0R9_5v>xcqWVDZ6KvL-U7X*#~HWDtBGPJ!lA3%a#cx;Wjn#L2P%b|RTe6r%+FVL_M)L2)jNr73qA388MkP#7!O)|`$Qn>zyrzXRO}d*rbFr1Cn|fQ#h+H z1E$HHTz&)yW-_IwaNvZaQFUF%jZe-{$HTtro8J;4qS_^dxlD^x1<-2?*w1@8u9&iE zeuM6HvJ#7gb6U_&50Q+C_)8-}Rf<0*(ze?n-n5Z0%2i=%L#R{Awqv@f8TFq~ijhmY z3wiq=N}0yF0q5qM08Qt)JQfj+&wz2L|5gJtL^K<&4!chErBnOS6qKs_dG+W+-IQ?OlIwry@+wf{C(=* zLyT1S%5ZvO4m!aRxJ)t=yrcuN=vox1N9ioD|~y2)HV9EvxSLB zTIjZ8>P_kZn*N;?)}$=i$Al$ug$|!EtaI*h#ZqP;!W5@$%{~nlT5!O^M0%{Kh7e=A zCV){ta>RFx&3fkHY>j}JZ-GPScGUTNdyi$wP0CcZij%#VB7x4qWv8+JlKV(>@Y!YH zuITgUIi@PdV1@v(*KkFM+Ln_)NtrGkw~L$Xp^Sx4LAl-VjcDe5mhqfD%stNbkQa{F zO?Lxzc+vNic4M2WqgAF=*3c8$Ib=lQ)LM82qK@2ekifcxD-R?SvC zEikdei+9cG{dO9Mt|dt4w$eGl>+0`z0+pTTT@92Kj& z!H8J$_qGYEj7}ukYrzQw8$v{U^?~}Hl#PM2PC1k>3OO7AGi-t55sGl3qE(Kmg;@KN zA+~-zV}w#a(cQIAJ<`cu&I66lHe8&|D}P;mnWvx-?)+3NCA$&Nbf#z-Snf&M%3t*3 zR#8T>ZC;F9?zmtO>IhisOcTfYB8` z-|j<;=?dv=i}w6xvllT;$H8*{)n`_Nq?dw7S=qtqsoyAPs~^LXaT0XB3nRt52fK3q zp(A~u%ze+&pMN(QL7nziW_cW}#6FZ5{Otz550=o+J+eXHmcE%5eF z2yk)a=eJ7?5D>w4w)pRvg780OivJV3Fp-;(0u@54iea+SHIMNXBx>XIltTg$f&zo9 zD&3@zWSL~X>Me3Z^v!@2AR;7xq9(D_YcKmPp1ZBL1GH(7mY-`NIEpvHo+8tlT?MP9 zg=&2!LqC>k%dRtWD1(f+9Oh@*(AX~zgEJCkUw$lV<5SzwTX_`Em?6`nNPXLPNLz7! zyq&CCQAB>w^ZfcX@Add_r(Vn_@RC=uM=`Wc$hpO;+5dQ5dN||_3#BID5Ze*(JWq_I zXkmbSLP5$!A*BL!nsm=4pR9eu7@e?ls3<%f8f7bBa2RrdqPsknKkda>hII~eXYqPcuBIa{WYGF8n``HF z`pesC`Z|ki=i`2f%)h#o$bjzKGn&yg!r0ZJ@ZPd3XvrL@HZwJv8I09_fzl9>Ahi}# z7UjDw%Ll6lSqHmFR2WZ|n!EZ5$?y!z*;`D)k9X*hz3Cjz88ono7e6Wj?tG6N1H(y? zC*F$+H*{Mf9j`nokv1h}J!?!E3x{na#%MHz+UIKIe3QqdI71|M04g~!UPQIu_8u1E z@jFZNgLg(-uwMcJtWcFZ2T$G7|MKh{m)S_wr|`pwQX|bdY;XK4TSH}#M;t73fycM*BlF(9t_~X%2cZ%moUo*$l#f+(1wu#x_D+c40)n`&{=5q zQhkY>bh}X?pgtgmFnhii$G37`;)|3>Gb6S4;`AL;+% z(ung#@C{k=;KOuvfVT(Y0Ka>dRq2lG7iUK6ZV-Gy`S#2k5K&rPZ)2E8wlSle5RW!E z>gO;g_G~}fqXds;R#y1jTuPBb#8rKmx7Um4Xu-%^9vfk1(Cq7^_s)A`T@aE1#g`|a z+AK&g^2j?E5gP0|evRtuC<``CZhgQZB{i+j&8M$TavA`RN%B#(gqVmB?AxM_))ZUE zxeV6|j2zC5FTEX_li4XNEQH{OfuWn=(G1_cA{Ey%>k)*F(SeZP*p^7r3}zyYXX==~ zgVwY!m<(>Wm^4xs*BfZkSH_r&ePZCV%e%HmW}p8m@pu&9D>PgGV_Z4b5a}Hy)#M3M zl_4{iYR^^t=47c~Myv(Fu?Dmjy=(R}m`)**Tig`4$-S(q>UVi{roXtG)s+R5HD186 zYq0G!j3g_8IcnspaL$x8s{IMH^^afp4+TP6Az%>^rzij!p_yeFq2JjB1I9Q6t_^=- zTP^Evd_jqSXxMtaz&@Q{(R%Y`bUYyplH5SW9;cgXjV4+>Z~i(Io}n9U$v56x>5{=@ zt+`t8PBfT9Pf?ac7Z^63DwQJESw5tynm?4>5m&HcTSFf&`1S#jT@H2#QzK{pynbej zNr*iwI9?!^&48QuU0Xn1F_}!J0)6H?HIw`vli;U1Ruic$xhIvu7;Kfn8BCKQj>=0s zvqE|1Vo~q|?b5}nfCp{LWM+d^XjC$YZAK^QNlss5T18b=jv_K5eOvfIvH_5mMsz(B;Z-%PC_mdoUZ$U?0vvS8XxK?S5bF z5#Ubg$LG0l2j@Md_DP?}ftTt_ING)JXa(+ zU1~Ojr1P9!M=uxrBHmXSgl`}1%rSDQL#1?*aOBK!1-XC^LFE*MwYIqN_4;vI)lGkO z8smI?GO{g}xOLK`4FX7ET*Vo@BHbyT=$*0eL#7W=)(0ySbPrE77(-7{(MaahET9f` z7FFWZj0j9&j!Y?diyyLT4P3b;-R`w> zNBv$B@>Be<(>8;%L$$cB_3RXM^jDNIW8!2_htn`u&hOSDVn6hf|7IY2uc?kKJ zQ;QlQVK(ZwxF7zvz~z5WHUI9^@}GEz|LEWTHGXSS+fYL_L;9-L(;sN}2cr`m3eXI; zht?H@#bBUhLmxr`6SC15MZrkia&8c^VtCTk(%Pu#TFq=`;D5xsr0QFCTIWCG`tbUz z&C`G@XwEAl{}y-6%ya){>dUfoaXi!G_W|Ea@t&6l8H!%j>jWcws)8h>hinr|c{&1A z6LV)7r}mQ<57q2?t7D}8z}ic=@7`T#xHdr1yo#}ZfD#cfykrt}i>Jhh5Eu%L{Uenm zCJ0U`gq*ZI52nkvbF^XVr&OOMCyXlbRBNJd*4;rPA;awei*M(}2#s&&c*n{+=fn#Y zc8xS8BZ39Aj&PoraOR@0!&Fo-NsLWeoh$T^*vzWBlp6xhZEJi2Q7}0gPS;th9PZj_ z{YB8RghCW)iP0dW%T!A3=ElVmUe}DoDW6eJt8u;{d}fKQ+i;U|#2mYumMbl*foN0Q zPfg+z8S_!*$678^7tQb@ zG{m-9_M+@Tlx@q(BdTjDI{C%C?Z6^pF)C^MR%!I0&^%i;>(8Pc7xKHX< zVQ%tZW3Dt8^UbF)h^lrhI{^7ik4xXY=7x%Wtqjv0CXSv{5F;dltZBwc00IpZgxeNGg zimj<~i@{=3WcbP&{EU0I!s1qH!d2nZ=FG*b%`Py&L~*mVf&XTntayuLp(%hJnyGw^isO%RC>M?< zzRSCzTIoo!a-`BbWyVKa!IE6k;!3l%)cw2iENo1e_ibJQ?CdQyny8#Tq3eGCHkhgycWn zhwj^vhj5Hyj{#RISa z+zT;mW0R2gK`;$RmU3f(U3S_*xvziAN@jAAe5S`J4|Js}nQaTNI@vnx#-^(^xE=*F zQtfez+Twf{35g9btJwu-Q3auw&4`xdjmBixC0D1u7iKCH$d+d#JUy0=#p|i^G+^a^ z)@Faxh58`sdxHC^M%Rk{U_`IxRTMy^d2EGj?&FJIU{t-h$?>a`)cV!!5IrLjK;7-Y&wjEc4d{q(_%TNN6A z>069)iKG6c&N6Rqfodji%;;h`07Zg`g2Es|Ng{&f@LGr?;ir4Vak4T<@q@et&%3ke zTOH_oYDq4&+`p8Qe?q5+vx3=39fW7Z`2`4E{FHoU@F{ zm*Bw9Qi#sdyq;yj!}R1i*TePX?HI!!Set3qU;B{ii!45XyhMIdgXv`OA+ioWYsA0L zT(CeW9D*Dt!JP6}B(%07Ez*`&kFLf>kE67^X^fXV`qw_z;TJ)-mHv)tC*d6|D{ z7P*hKfU1N%Jtrc**W7KylMGg?Zu|+fTe||KMLgHwVUC8RxYIp zk~|N0FRYO>YP?j*kSDlF@t^T9W$VRrT2j-;WMsXAx_+v4IEP+tJ@vp}sb~rm)`1?~ zw3QX?T{96-AGJ*}gY1g<`zy#^Pk5Jbe*}nZ=0;uz+2d#nb?Yk?m+F9xToB#ynATdoBS@&>fyhy( zZ@NY7|HxGT@t>~q|AMyv*N(=&?r||U^tT4!(#dA}q}TnOKV#f(ErJ)bBoq;d91)tZ zzrI8g5L4bM>3ss6jOjkDwW57rmu2NL#wJp#L!YX`k3J}M%redD=4KTuEgPGryzdAuV8_PJI{!TYS_#BT9~^Iwr|J353)h3Q>%P6Jms# z6F~yCTf6~m!%k~)X;)BB|lT(2t^gG-#ClH0G&ZzO`m>xcUwj* zooerld0H_K#0JhaB&Y#BEyl?`K5Qq%sm;xl*t0e%bSa8kzW-IGG(=Q~=s?X_+q^BP zk?4TrTNk|J@7tS+c9lLpy+KOqx&!tyO)K8azC7qmbzB{wkAhdL-$@;w231K%_TFZnxla>dh^n*&y+Sq{3dz(nVv`MGTFCE$>bcR%imMAp|_u?Qm zDtq#4M{r%6(it}1&J+vnk=&Xw_pT_8QFl_FnH7`wkSLBZ_lBsJ(HB{4yX0FfncEGN zD}X+tZK6HH#yL9=v^USjHA3@xw#*-T-Bqds{_TBR@aF?L=xe|(KgO<9r&`}z+R2%D z@~tnn5$ynIRV(D{J(3^6@eD9DVf-x*4Bp^1^$R7z;Wlx~F4Gks{lEm=Q&5ltc+MaJ zkI(P;TD4!K?rHxIXK(pcN7Qd?26uONm*DOe+-2kL?ivX0?(XjH1lYJc1mCy^cS!Tz z+h_ELKKG0s{h|JV8ntRw&EJ~ynZimF*W}`lJTGdgg>KbOgSQvFEEiksh`ddQ3iL+7^itq~?YDH0=??p=bI^m4XkR#V;lvz;k zVffq7Dz?&hBQgjU8dNrFG$bj60+!)xv$e8+5`i(HBcYYY{;9s3Dl|lJQ|J64)+h4g zfvzEIt)?q1V#BXT{teq)+2J~rqUC5jGs_dc#e0yn<~a>IcpKW#2m>vjOWQ@~*{INX7z$yb9KwSsei0DmNdm0JGUQWE_B3}^Otnna zrPM{?baj>oWH07y>9wWO8OI3E+-%7@^a^1a0=@6lf-FAu*(nsum%I{aaBbp z98t4exd=}BGf$$6gnnzG{OrVEp~RYGZXKE%IJswzF1oz*k$$RM;w)=P8%RAe;#exn zZW!)FV~R~i{u;ShpJA~2w8MxBb?vuD*Bfd??Cu)hAKDVjB_1Kxg|_mo-BlqDkd&e zsCs=O*}`Ybg0Qao%$iZQd8;@J8{`9XZTL7J9G>U)eUJ9c7{cgoD$2h4ncbvQ6zU7B z0TP_=!^?$>FF(>Aspl;*e8gt!Vo2DdJJ1&=s@-AU%hx5H>=MCA;#MCoR!R|a4OWyEIL>_rU^xx5o$N>&plDUflnIm-vX5A z1Q&P6eIiuV^=UB=I6CNY-Q2AM?U~coTXQ8mUV4nNgv}->l!&$HKf#1mZ{nZJq5=lv zsotBT0tWW!Ke7Hv!2qD;atD+phJWw>t9XXu`l_BgE%G*^=P%X?Kj6XO0n);k%O-ksc5*Z@qO>i0P5p(sd^YDWX=uK*r zGgWD$la@LC`{Y7Nfamn@h-0ohd$SuN{OJd?Ik0h4@0N;9ZKF5g(h~#~i0eh6Jyp0$ zCjB^b^-*vsjYASH9;|RX3TH{uOWdXE@yfj!Gr}Yq(Ht(Ns=<>4OTfTNwDi7Ij;jT5 z1FdXqSV)RGq^|1NCIoY6lu8da3=i|9>rj2fvQlerz#UVH#+Z~8;xp||5XY6hb=ZoVLlxpTY>{w+AN14msof_8Z!n+XD zl&fZ*nj{ngU@Ww<@rrdyOB+aEPTBpZUHd7C!D2x%oKJ=B;Fcqlm$5RmhOLgpv?NNF z6$#WLZ)=HdgD2O?N$4w!(s21+~Xe1)#-F zyj?W58#$}mrKS&RZ?;58&&8`t9Wv2ailnLnOfYxLFIAiHF7nAqmmkph$r#J3i>Bq? zriP*6t2YJ-#}dA|;z*JEXtftIyTC85j^}3nqN~Qy3Sz(Il?N%(7zj6jYh=_SG? z+}5T<#Lb-GsG5u6qd@2pVl~Va;B2yxIn34RP}#v}ZKG*#gpL`wUT6w*kTm#lR=^%_ zNOQ6xg>%usn#5)MNxN(lvzp`nv=zGAuaU*MPe_f^(3m zo-V0_9iGM(RIk1nHnZ}GwF*hL+sw9-?$`IDP!wW{A=q6UFLsDjdh)GK9m}JGS8cCI838W99Io*~9VGCl5pCazHs98}v>7 z(qt+@hVOJ!AA}$=uEW=v>?tEHcd{)gas-)ahkr0cIR!9zI#3z+oMI7P4$<|a`Dp?0 zWov`ENcWQ@6^BBbnVN>ti@v#;7;ebqBKJnGxp_9GDc1qrz5O%>$^bGq5QA}2nCp+p zAUImv39K~>{fo67n_wsJd_Ikkw=~F@P#-gG%+68CvRAfhVa6I#%kNc_dQOk~k8hs! zym-+$%B_@s6Q3CUM47ZmLjawbS?Bo7QXp9wn9R*jYpAo}&!iM(pquouG`~e^l23#k z5!%>2ei`tFq9JBw;S`ecHr_|r1E(u&#^KxQ6x7R9%ja+ma%!~D)J^O)Slsh7vTg5@ z1yd0HTp6x2`T1{kzN1f3CjUdTxg2*1y!jlA8r)0!Z1>mR1Yu3 zN_lu6tw~#AwyWzd=xgk(YwYyb_{i!)$ogvh)0IKcwr+_IB6IGdtURn^;UqvaJb6k! zDD_?<$IJA<8dme}^K4JPP#l*bU8&zB}OF z&d1c&sv$7NWQ6l9QzXrLx!7>i@SFhWkw6j=DJd(f$FcjBG|OTRsc9eu%sS83$>^J;d?#9v;$13s;eS5(V_|L^GpWZbN2km6C~B`Uy%WCzSe}p( zN!}T$$C2SZ53Sa=@YHuC3Kc;S(DGfzxG3~J-@b7ryhKL)ql?e?tHAPOhYrcd{m5S+ z(N9v_=RW;g8*?*z`uDQN8Ep-Ob1irF5B^&{RHQ$ckQ>Psg6j8OQM-PuH2g_B+s5Ue zZo(migZg&4crcU1v{w+e)xPam)Q+VwLcQ3 z7y@FDt1)a1#mSv9TTM8x6WG#VXahdS>(;l+IcTzLbS5G$aTq%YVU>pg#WmRULF$ee zr}{9`P1r3b3_VD0amXvu6I{{X(wFgY`<4y4UL6_CMf|(^dxNq9ANZL5pi*M(2oH>Y zVe@dKh+m16uOgdQQA4gAQ45Oz+H% z!!<+LKorq&INT)|3Tex7L1-!te-24|7Ql%w)_hM^g}xl-b~p+;reb+oKo}ADF`Tlm zvDx<+AH*DvDJmxjw2s94S0r+gRmZG1EPm=%5Ac}#fs>V6APaOM%t+lyu=7we0s z^(X~l7#wUKxaELxMnnV5)&4eRNVzfF#xsjN=uXJ+ z$w?gkw5EG3_px&*XF_f^{rKCd0EMdPUpUK~Ip+|(%o`--y6;4dHil+SDpK~% zZ@k|UPg_Tza^m;?Bw|6i3Nd%W86Fk_Ab2L%{|*1PDcw&ufpX+_z9;}fQ7to%$YZ<%9?vQd)TPq+(kp z850%?5~e0(lxM#vLD+P@&N=i@S3~}TP_@B2D^1Nc`VQgnL&3#G)Z~_dqjT;ACx&nL zDpV3iwMdcl_S>xLoG=VU1SrvokbW0Zec;KMxzqrqM*=k{fGinQGvI%>RqUwK2> zz`>IwXxO~Kj7?qill)bRE2q#ol{3HIar^(y46de$*4!JY>rdo#^Q z|C!=w+BCpFIpH&H{Z0x!4x?YYS9xa+W>WXE*GUtFL)nLWtcJ7|U^~IEX}UKzmd7up z*M_nrWM$+2)c5wBfCXDWr@ksN6y|-4=`sy)frpvW^guiF8fZ_yG3~G?TL{ znl}O$0x_5WVtudd_vvR@mwi(n#|S?P9ZzJm;uzJriUL;s;d0RQEfE5U<5dq++&ypd zKB9M@rwLxGM)nT*Oy(Lz4=hqWhEmHGMiyajL?JwhA{}BbH(b_;`xUjKXST+=|=dz zORAPFKLY2-3Q9Yi+NLXgN&o@oX%`61_iUpRyonAx&6nMmAH$CuyDr#s+&}1405J3D zp>9t6=SHTHO>=ZO8z?|2Mak^F-TdOTil`ZIa>lZCU$(A5^^Cnxp1SD3F%Lilq*iz6iFmC9!j;#TA!aN+Vu7YwXI^ z9Oc3vHRkVBBV_i_*>5my54EY*nur&tz&on;HD=@Fe;Qm9T3gQI*q|!=vxX_?bjo^W zkOtxG%_VW0qtrsofWzMXCnm>zGhTe`y5^$<ZXWC zPa)CFm#~h^q5fe^G4p+t?rG57x1foQm2K9ce3@{4ifp{3Yx2eFZ(#i;GbwAmtOJRn z-M=4KUXzJrN^C4&Ut6-E@rr$l=ik`D;uH*Qf0g^)V0=< zZ`X2@$YS=?GYp4OE$qxqQiglCDp8;Q$n{=72r4HI40Egc?xgG;A7SEjBS_Tzo!1t}2|CeaH{G&qQvD(-!FgnT@*F*}QL(zu2_2;;filiC z%5QjP@!{1OF-mMYVPkxC!VwRS)` z4AwdkIE4E;!3e||h8{c7^u%=UBK1J}N2d=O-mp!GrSGF|#saV531j)4zzxF7_g5RR z>qnQpAlg8&YmtVdy4Tb_5RM}-6`ruaBS)__{qTN=)`Qw_n0kFyShU~M9j-rC5vEU?yYHwYfuY;p&f?`t~pk>IOHU|#fw z*znfbWYJ*|;p`F#gh;hJfq5D%L6jnvW#9AS8J-qJFM!jD6_Y5|ElQi1kFEfK`{CI= z!(%tRAzxDfV(P^)J~4G}kO1+HK~k60egs_m-*;8tsq`ZM_QyUm3q<`jr$u@( zY*H|fRLo+aT!%@(xC_*bf8g1kS`aqjdk+)*AmKxxjSVQb+7sdndE4>O`Pykg-Gtli z1El54s`9ErXN`{oqN;)W$|wROr!gu%Am_fCgmUOKI; zR&cH?WuBZ3Vq}6Jj)cg61IvWGnwIGvMDjoY!ZWA<9|8!;8X$BsM2{dM(d zDr;WH=_52RoxKY0SJ-+I-Tg}^>IVzFMscftgPpiG&4~QsdOzdPs|W>3y<>9iTF%A& zE0LH-G4A?)feFrx2IbURklmVK6rTVxFb*d!>{ly7RfNUzXNCsWOQQKPh7Fbv28tn$ zk`>|R7D4J`KB^7V*5DL7bB6xbiUB%+28m3-uh21^QA&e1BqG{FGhHzj_2s-R-`b1kL^*&qpr+!7pVw_1{ir=Tmm3Uos5_+b`;( zLCWNC2{?4jaR@UL=>(9mbT#6*C2sE2kT+?gkY?nA3KphvFnn57V-`RiRut2&yLzMP zyREKgw}aurR#mmTEy+gfa^BrEC0c+)aK~RjNntij9@*eJHO8jvtPhj65C@R z4JrQi9T&wnXDxcv`#}Tgjl*v`jwYvJUxr%na7YZ%%4;1Cr|)Wr-AfZ#fYFJ&H|>hw z2a*7LWIvQK5S#@f2=t5r!H{5xa7V~!EQ~_Jfr^0ZB#a-|O<`I&UuR;9DZ3iPedECP zoM*1jg}~o~w)h5~Cd^?M&$fBLfk4k(p19wQ`;MINxfrR>zSN(=M2>4Wg4iEr!KeW{ zktDm{>iw-ob$ecZApINadXI?wH5a{daTqlWRUc<73DB`Byl~3s4T<|4`zaxb`#bzX4#g=5F&W z$NPF*d~QdO!Uvjva_G*Ur@*@q!oNu2>uW;+zd@Ay9|j+h;Y!*^mProNLQcnE6 zf-#~@+8N-*aIgm>u>e|J1KXj!LMyY_--!_l;B{eElzFgH=(fS25;9<+_#MF{%Dbot zN^Kkz#f@@M$3FPiq_nK|t5vyH%aDj0oqAfyMI4N88!yH^Zl0(x&8Xcub6)N|=<&!l zC_7jKWK>d3pAZpBt{dt~`KoW}!u48KCZd3Y3fkv@{iafFpO;l?aH_}yA7wG|A zjb7+bOz$kNVaj4$Q^t9>N+S+Zr0`ID<&kL}jWIfI0<`FoI+{+0?HPphrXXv4rwnDqQ-%vcCYW2X*Dj&e_mUaZ#Oovt`Q>!A)d`5xtRb zlvxhZP7j=lo?(a6L)&n3!8ILEeF85c8mSUrIQ-Ir*niVl*da?M-%L49bTH!~j^ar` zhpfb|;u1wlGAeWnVUz0@fiEf{$FG}0!LNV8(xaVN!k=&}Y;QyC>O z#Bi{UOW#>kT=myNmO{}r6|A}%5W<;rrcQ~DIeN!QPC438V^*rqi^ruczxE*7>KO8e zb_-?KkHqN#r;6sG2sa7-7y3=ICbvS<>^Oo@xq_pBBVI}vPaASw99~4XM;_$>9y>QE zpnGGTSv#6cOdu%R)jg5s7OF~-ozzW*wCr?{3ErJmAK<<@3Dg&ZpW<*-On}H>OOrI+ z8jvVx_ci4pT$M;<7BGP}6jZ}$9>U}EFe;~>S(0p|Ma%GDi%V5UDay^_k;7>o{^NH> zsGlRJ70LU~;pz?==2A#GE0TX66Qu4l#qa26bWvJQccb2X9==zvp%l&O(3b);)Siva18YXrY%5D>CXHaT-BUNHGqy z(5p8^=qrh&>Z-tafb^X{gZAOrtlekm2;WW!zw9s^g%G$vMH1k+ZAjVk7f57A8R3SC z3879q-BZ25%;0x;=1lZzDyPAxXt%p$H4%MGL;Uw$R#09>i36V*ZdeX|-b#iC_ne$F z4dFL+mYXwPXpj{)1IK((v}U6!PP%JI&7Oux&B`#oK`qu-Nzq_1ID46Yfx75)wz^{E z2xo?qDjq8zL^f=7W;<=W^-=ortjRBEX0@HRmYO z5GR&^J9&c7{EKgw#FqVHQhKT85#Fq%S!$}rh+n8qVr9>w1+vm|l+D?()8|Kw;*^Eh zj{MHLEQ)T(p+T&-wE-lusz-~djgUgm#t(KIt&t%g&6JrFb5vVA4#>Zzf&kYADqe4# zGEo6%+tN4YwXF(le?h&cp%jFC0x*gG{)gog`_YSO69;+TKQ@|(d(VQ;6@gU8I$d&U-#nZQk~!}Io{?zh;w{v$kYjyLw8+b>qaSc1vg9iGQ>0XU8DLR$LR>SSoR<&gP%9c`2>tTgXSU z>>)bzV?q(lvse7`(JK%2j@;!yu!AMO`2Ov*zdVq~jY2S6!lX7tL(-R~!a3%BXeX_4 z6i#176$`}zS)*5E+ZP{ZDGq1N9wNn9|7@o?%^1h1=FEuPv{BmaL|CVfC(J7n()av2 z2@y(3(#NP7lcxc6S_KMi1>$W*x^-e=&`!~M!Tbk&cIoGh;s$~GO-R0xPcko(0!;No zcenI0W3e5nSIzUi9uOQ{vKgEk_u?Z#P7YHQnC=dN74 zS&_~S-k5hS73J*1@mroSR(ozYY!wgKD^oN3avEFQP&)@#&fIDHx+tCTilYgPYqMp( z*BrA6QGP>F=)Czya0}wW8si+5Z1dXrtuC7L6QO4TZHL~jl|$!V==f3hrB9yQNdact z2bP(O@FVACzBjj|yCc{rTX);o$;;cd_;tRgNDa5_>MpKqnvJltbwaU&s-B;s%(HDs zEfX|m@|h#eGIRn#Nn8s98pFZ%;>)lzwt?JNP7!v0!3wGB?k4t^)&j|UmJ zie6D+&W{c~(|5e<7+#Bd2kTED{-J{ux{CU19l6?kl7Y?-s{k<9I3wmi+u4SEF>GmC zT!=d?6YPEJs5h|mixseP%PcdK`RSrm8O8TY));5RQx?;UCIWxlNPqj>2i=X=s@cWw z<)j2k;kiZt2PwOZZ-2-)gU=KS{+oAbLM(0>g+6|!_ zdCcsM(l+kf_+vY~e$syJd;7k-w{YCzCsHSZa0&{D=!IoF`QsUIH9~WXMs`>{NJWCN zcu35ubcMw|SuT-Ji0XT=xM%-T!$Stcq{(YGo;0g1d&tdrcuOYNDqvKZ2*adsn_yl_ z*eG#`CRgwGXW{#AbG)?CdCQ}f?~8`7H%dOLw5C{>99fp>FUX*zrrThEs-`olyZKi{ zZ7JRRK$IiJdr6c-NZ2Bq{UzibuH>CA=hkv8QMjD)9@%07gGcT&sN+P-MCUWOA?P2O zr^X*JM(avi;sI4f+<4_UfnU(=wLZT$EIMOlurSLV+U-&FD!;eQoPE4ZJ}#EsJjml? zM1?z_KI>|zVf}ii0(qyS@A-};|6SDmDdPA*b~I)Y z*EI!7$b8t3s!_xmP;&vO%W=EiRtpCF>qI@L5w8)3D+&OYNJXl2DX7*vs1yhSh@h6E zNpOoYQbtHZIzx-*$e_*^BtIGJ;_o3|3r{46Ymb`KmsK=dZN|MV`aP+L8pqpaR={gO zZ-jwaWoE5aT4*7a&Q0zWM#0NYXdsw57nbA{!yhKK5G#nAdTP4B6wFWw9wiXFI+xw< z>1jl<9RdY3;_fu4uq)}8s_z=qH5MyjMjCRZO}m}R+j{n_J7Ss&H7_{AqQcq8(i$2C zvFtR(G-=gh9>uI(*!osk1d&{!*fGlsP=0PFvMQ_$Dr7AsP$NhuBb-WNFGMfxA-bdW zPM9p5p{G<+m1q!QSNSYdfTdTNUsoRjD&GP1S*Ysig=(#&H9Cpv49>wik_(V3k1t!Idk8dTGlHAi#8huldloeUD|O zOsDVNUFp}^I+p#5o6Sd~dNTQ`Z?{No(~1?bJFemGc1^@Yapzl6e{}=oD@T&s;Bgz# zNUB*6{&cOg68rS1pWB88b_U}Yxr=Bdi~|Pj?1ojjUFuR~&XO9T_V)3C z_84l@N7MJ>h$82(t<*;$f5RDTL2)zNj?ZOo}+E)FE>lcJMPFJ7rzeQr=33A%!#Q z%|eF}2oB*Ihhc+OETw9po(hLi)(3M!El<$fnZrBaC)D3+-|NOMoct<#vC6kl@hv8o zB~6efN>t|=nMx%wHm8lJ)FR#W9KfGf5pGWLu9Z%3OzTh1bYF2>y{HaM^T+*l8~$mU z5WH;tEK~K#cc_d;5iC`BcG@#H$HJ~|pio`sZ9!bYIX7-0N<2i!HEOh5E9%DOh-8fbkS9EIx&gD18L7(mBmTN~P}0 zQpP#1W}lX5apP(u0*0z5CM_P6vFYZcqp0co5@Kg7zIYeIXlxK+?ky)1H+)Nsxs2u9 zQnaMDdV~3z$8DuGe|foHlWb?X+7CN9iyAuLIp!(cGB-^_lAvE4c&4v1-u)~J!D13I z#;08icxtF;?2N#zN+a*V?*#|=7Nx(O-$Ghq78g$S0|25%b2F^F#=s;J>!CIxv6s_#V6CEQCms9q^jVMP~A9NA9luBYyhcUKmX+cB~ zOQYcWHGZ3|``SNLOPvM%E6gUIF?)aNweN+cmI{)qLxZZ!m0&e+B#%bX2VOmo?RpiKtvfs}i(4t~C1R z-ra{X;PDUX5b!U{&_O4z zM!!is+4Jl&XdI&Z#$ z+p$aAeUGLOO8WNC%Wo}~r_mO3%t+gvWb>4eZ+FKo|+-fOu$nBY&g#cIpt|NO^nC(*R%27>Ty*&+|)~4 zJo7qki}LHHL75BZLV#Zw(l6{TxchVEO*_sep?kuZg)_&3hBQUtRhey8$TsL2;bjN( z=9m$Ec)mg@@L8qadoIqC#OR(8zayG0_C{vfLa@q}o+-9RzQl5NLyoq=Ci;s3{`yGO zg*5%^85PX=E5QLKH}nHQ#cWdC5#oQt`WUI?r0f?}yvKIC$Ii0{KNC@XuoeC(tMC)n zTVte)d#czqAWB<2?T)V4cJlX5fH#$Al6Op^1-(bTqEo>hu&o z1x*fS2N(tQvf#MO+t&ca}uY* zyyg+g)=zYib3n&%PSqU*o!-ctb^Ri_inzK8e+Q`!s4YU>M-4#F+j7Ie9n$109%^04 zFX%=qlpzU3diY-?bv91<7^p84p#A^I)TH?D=Dh#!ytsXgDEuG`s^q_=bt~sW7^ixI z;ICk0NyQw-5Z6#jOJITrXkO3j8wwSdTVX--%hVhD-%a}tE~s0BfsNe@8Un*D$PI`;ACPMwA3-E5I^I@9~IDf)(HOdO@VYoKPdUS zrR%Tj|2*9OZ;KQDyW#f#^I1t%*LTGDfhm}*?R#S(BPP8`ImAgqw}xzvAw&pI2Zab0 z?x)@wJru6Y{kXKX^e1(Ni(aEtGxZh4YcDXoO4TrGNj6qg;2Of~07gTw85xchO_uRx zo1fisM$q-|RNv>{LxyjQfF`GJG#I%3GfHRugS-b! zQ@cG}`POSt7|qnoaQ8ljm9h+osfH@leW(p>Bj6tMPa1%V?$|IJSo!ae#?#tJRdtK^ zD=CZb^PNXr8ksj+{aRYO2EA2-kxXIH;Bb!2h$~mL+?c46V2cbexhj4ucfHh{2kgE_ zOxVrsP%&c4r4ye}vs!YstyoxTTd91OKDJezshSo|@;SSk8%ul!pPHl8%xW?;*iLMJ zwq#E2c5fKjm^y9G(tIdchAykG#8)f3{io?T#b@i$n)5S~-jtbq9=b-^@cUj1$7?dZ ziB0neOAD|xmvYKW<1Z4fQm9*5!x*@r6I*W3r0imBTp=;Iga(`mXcD-bm!-f~<@MTG z!wIMz)@e<)N0=Db#z<{VR7ktKZQ5H1i}#`1;#zx}s_0YxUNl;QC;QUcFLAa#pF9et z{vGT`$uY6+M3sCf80mUy?3esK@0NLV?jpMT?E7=mnnIVoiRgj3@`g4k(LesI_Jmhy zx%zz;IE%eI^4l26?$yxHXeSh4v-V6)qBNUvN=8X69LTwrt@Iu_Fb^Q`@ZtH)-Wd7x zGvO($zTqD!ezBU9B1vD4$>dq0Bs*C-^W3VnI5tif=qp7{*7$Gqd6U(zd>k08c z)02>AF4poN?@LKYF)ul=&q?ugQrreAynK^e82+g(Dycc2053d_@1M5Q{KVUIZ-fq< zuT6MgGaN!KF1{ZV)tY;X~sq1NMJ@H|hSn4e7rEGyes#pk)2u zKYOw2Dvs!)sGrzYbjR8W*bFwdjktj;#LGAsG8hY1VnJ6=WH4_d}1 zw)?^HLhAcUY%@elxFQ>J4tT&QsP@c!bGP?c6HftHw!8xM}zUilg={BGa=z5B!1I`UlE1el|Cd=DyMW zAhPhpCB3~W4qI092z!IZptuk^4`>)s&^~qV)GdmyaHGekf4FG(z0;vulaLByV~y3B zXp*{afFp5;0;9WOk2br6beI^%0;;;@GX2WLKOPLxLP7S5$jyG|SV-K)M=>n+AId~R zcMEo^%1>rPS7E~3LO@0_NcbQU8{8df!?{E0N0oedl}oDHZF>dC&)qy;N!P;RiwAl5 zS~OZE?C^_BZhNG$-rJEcOrZ-4Ze0Q*QJo$Yij*?+L{{=tfn0K);Qj$Mv9Y}6C%EQ1 zuV~3V-h4bPhjg+&CFIO_l7DguJr&fp-YLc!p2ffb# z6tf$44XUoG5Qkir0$ti%a-pnBLZHGR?1~e^5TgUe$ceC1`Z|otLhFy`cj*5t#n7JL ze>uLgTU`JDvs?eQ6#sA4q2=v|`GECLv1yz!TXak|0u(`jZrt4M9Jq&tiUgNpg+3=i zHBT(Z1{a*2%flZHXnK;3)>@yJbLzx;FxdF5FoN)5oz)0f!WyQ!}9lup6^phVRopcg(xGq4?zurym zP#NQf15P{mO~fksD#z94SspE_^cxv$b8>YPpEVN7vxwtNo@eiGO8 zLln7-we2Y16u?-*lcIPxK%-2if80L)B8Z>rH}O;B+DSUxaM>%SNA9@Eh#J)pDBP2Q zaxl$BTh>LC8(_89rPv@h1|lL@mj-2yboy+{1A1RaB6=kQxyMmshoA>@+succ$4c<+ zElQNi{mfU6kE|$(mHbKLE$%Z|dpTDe+kS*$PRX)S+fm?C2O_fb#RdX~6aig9$u7U^ zvV5$t&4EX?KJ~pWt)`a;WR~Z^n@u%7_iVz}&J^%0Nu^VI3X8RBtduubuu5UW!0JC2 zi<0eVi~Q)p+3wX0O}w&EmY0tPKgYPHaO3N)l{AFweo-Q-zgyc!M*n+IBNZUa_kcv5#Aw`> zHZh9M4U-&j{v%a-8dsjhTQW+WtRVVR^o}NY9-lyVt>i3Gbi9@p4VC0XDa1kEVewDf znxS%&zbty2LbUVx3s3YyXBs3sOhn_K@B=)Gj2w3TD{CD}KEcFo13}_?-7dGvAdSzS zmu*{E=lr0SKhnyd$JVIA_}1)$pFEOwvhU z6;Wsi%)hpTYQ7U)E+{q}{*r*{4Vo71V>N{4#ufo+`34DxTmO-S5>FMCTJ7>+6=j^* zi%c{R_Z?PV+QSTAve2;Uj?}fGp=Tr{=YqN~!}{%YTB4?YzCA*tb1Xe|Bv$D0?b&H_ z1xAB#>6-78{x+P0aAb$$ok+=gEh?JxU0hi|2hOA(?_2>ew1~`IZn*kmPd7)bUO)^K zbroRK(0`@lXQ0&__T&0H(!Y@aj(08ezeobL{rQ1C<4xqi+D4(DZ($+5g#oc0XtS~} zQ5K6$=;CdTFavjZ60_X2&`X3^TRCIYzL07TQGl@CweLtJOLUnX&6gl9wxN-&FG_t? zzL+f5!Gyr4dbAI}f4e=k4E)h^Ia^ZkR7ATxHg$Ml4zi5+_myyMH@ErxWr1u3kD~2+ zCUupQXuadewSqsE_XIAS9$9I%PrO}Xf4Ua#a}X%ROHm}~{R7F8)d#==y_m1Le>1`N z6z5);pS_j4S#-MIN)w(@OH!A&R8z+NqYjOP7q7zEVX>a|9q}sV}i> zw{@C+vnMHPW=xU(JFKrMG4gA@2dw5=S%bb6cf9>Af>#$$-u9Dh~&CQOjf z!KF^k;Sr67e{_2MY@?}ElzK) zn_k$h%{w;5zu$vKJPnNe0#N9bfWzFoUHv>!LGi{%kWt;ebo+6YhsO$c;e9Fw7m(NU3tL=1Zh!deRoqO;UIfP<4k7^)Gr1$`yuJOA)ZXH zgb2%x2sM0J9Z`;U5IVo_Og@-R9r*Au=}iZuSk5I=tKSIk!nYVvtt`ww+}EV`Sl)0s z?uRbL*+wdbs4|}^6De_*3)ISapCLo0?m07#E@&$b;6H5CI^tp zwMkp#r(8f)^ zGTNYod@9j~Ta8hLERd&g9Z>|bv|-E`=Y&ndUL8W-!Gn8I8TUr%X&v_u1V&bOxbf>V zfbIyp)QVyz1_pjsFp2q&k%bV8ZYdIytjBl7g|X%|kVF&cYt%u|*1E((2kisc@DXDN zeq*pFb$`=7A4SDgAlQsB?J$@HI*QOaNbov{K{-fKIf!z46k&Ix4%Py~HctA94t^(R zHfG~F<8UGx$-#ewZaRMxhl|b0S1~+8{VRhNI$+8}Qrc4uQVY@Gr>b@rhMUXCTL+;)QC-a+##v97p3jpWCk=kRjIHiyjmj~p@_{}kWouU z8zGf;G1H!9Ke5&(2HsT#vXe_1$0O+PPJ+f9G}fueUDw42daW*;$oT`i9M-#CNHnqb zgTkb=PQIy!{dL1%0t`lYKw90LsblA;3<<-ldE?79)7fa80$U2=$PoF{mRKX`gWD5p z89URzOx%)rf{Z4)_X>U+DUWUW)87dHMqd-!2js!sftx;&o1+ZQ;_(cfa>t0vCjyu5 z(G>?L<&(A6cnnIngY9tZ?|Og&H>d>1#y0-3uP9BNeKU8+cSGXxB|t=hf8QG4sn&{z zDpO|D;Bv;J>}|69vmCHJnjruPAG-WOQE_M~7~q!s9ka5AG%VZUo@IfEacs!0tnqYJ zY`w<|9xS!#r2RjUc5GatML|fFn1yk`mfU%rgz<;6NGtU2fO^J3ZCR!+>2noqCFkM1OACaJH2RGTS*=?JLFq?1qQXl?0G&ms zH|Tx)f8qGm#nrad;lF*$!up>y)Bgw=_}~28|58k$iE?s45zNrpdn|%t`=7!()w@Ml ztR0$=wM>{r%sO38-1Z|JR5Kz;UDsNb2v9g*1ym_sZCmBqkT49sZi}SkBu*{CC`>RGV-z4YfL>G2TARcHn3o>_!j4+|WYCY%nrP z*u7r8dM;SNo=1PFr6C;_Eb}bx3iXlaR^Z7n$4r}_(ybTn!r2W;!4?XXC(-i$zzbn7 zf)1yy4ep}^aFto}Zz`t3O9A1bH@Uz(!$BLfZ(x+)=~hHXy&gn2HX92fCR0j-<-ia* zFc4nQw?NNf^s~5O-_lq0@;U`9rG>5())p+D98G1R(*bYdUj-|s1vqO7LAqkKqUce{ zu+UF={8!3K+HalO1-g-Z+TyP#5EoeMW*(3yAZ#X;9#$Q~;!18xgR-&9ch1C>m=pe_ z#R_cwqP%`Km*Tu1qLU_)2r8LFrBVhs{$T$R8D=ido|a$CMzb%W@qgC4T>q2a{VzZS z<$n#Qlq|H(ja~k?=J;wE(;`^K`ka}UW{-iHqH-z1wi_+0>~Cz$1;Bx0nxdie>fwvW zka=8yA(@E8m|2IwDQpaNcGWI+>$`jJ zMLKqiF%1HFTg;qy{K8S!TXKq&Nj6pmrbM;Gu`n7av6}(>q=KiTwUJzVW~wq)8*z}u zI2o;5*yvZc2{dZ4VuajIwKx4;)4nWbg)&If9{4qVW7 zdbF7iF|8?DaBy4lJ|=0Lm?!|{%Vz;K&%k)>~3sB^X3KFmV(k1UW@&@9TvOU(v{C? zfsXrp`o=4aUG&>r*F=7+{ZH3FA%y$gv4lCUDX`bH9>#v}ed-x+yXEWUG~L$axd~VC;`hUJ$I@6YE zORMPX>Ca33iv_B@T~x+gqn++d!7KDN4(!GygroG7bOn;tw91BpC)WoxoQLod9*poV zZX=AyNAPJsuzKN(eQKO*Bv*?eiQn^u7H)1W3jZ(Oz5=SMu4|X>?k)jI=?-b>7HK%Z z0S;Y<6r>xZL6J@g1q76m4(XBx6-7k4RRr!nsIT$A>i3QR-is~{W9VkhHP_5%&b62A zbv8+=#k<3f_nX9xRQy}s-9>&ZY`tCDJ4~dK+#M|=e0Q#1|GhY>pyyreJMW(8g||$K z(;H%x)+g7KM3f*O$?42zE=*CEEoe@;@osRL5NEOR%WG{iC1W%ww3JQF7tXb&*e0zd zKpU*AV=@On;qPgzt+|>j2{%re?agYBHR+8zynVE-iDGh7G^vP^?pb5(%F^>R`>2_j z6r=4TEp&cIhxAKt5$FvxoZNZdI45OCanfv!A|i|CpFdRS8(ihQ%<1CY)aQ^_7Cki2 zG}JRqczz0XTb-WKpxq-p=*G z**dmjk3CojwnD2#b&>|5@rKT=KU@g@ME(r@9)ma>cEaV{J~F#EmZizJ3zR&U;mNPX zY;;J^Zf+(WcqKB;K}lK7UYn%QFyTkC2I+I-VLmsDx*yR$n$}H+El@t{_Zb|V?#h`j zu*KG?-$QdJ($Lo*cT+=;W&tx~c ziuAEJ_t`mK$d4Z{#?;!h9N~1l#@`e?`aJ87xBXCrY^?u@nNs?08yf>pYDGX^EZ3ES zNn_^)IUSYLrJ^Lp~i_uLvHof;Y^hCn%mT>)`g-8@`F) z?&#;$1tV|B7Z%4NO2ncP4o*i9GgTUw-PrFhB764kCVj1nA75{E*lRL9;e=Os*LbPk zXog?sN)x{d{D}mogF{#t8*aSaLdJ#bbO#!kK(O~>TMUu01w@O$bX!;1gwNLfb42| zB|64UNp&E-``%6YH!Ihx>CA|^o=taM|JdlQ@>KfrdS`N~+*KuXvSqoe2QDi5=&1AO zaH%v(8i6!nG;d|Vwei;pO-l9xZ)OsFLg6{}F0-hN!Jw0R{Zw{HjPlbsiR?D$;pa%Q zPiQx=Ov)!;tcZEreinSXK*m`RHG~5 zE}op+J&`SZu=w6uqdmQ+RDf#yz2a1$vwqQCUsK^;xBckZMYaD%Hl9%#fc%=S4S0xZ(W7_8dx+L#5ou5u?@aJdy~U9%il7n>;FROOpkdmOMy zYb!cYxNiKc#({87_3A;$@vL8t|FEe|)}!OPfRkN~ErglS$GQi;Rk$Zb?~<1R3~QN3 zh=|JLwe&$bnWk%B9K!+Wva5(BeRr}pR-;yA9zzdJ+A?slV&ZZsQE#E}R(L$26V|1T z@StSv7)4j*V(uccM8c9Hl2nUHL`)vm9>x?tH^D167z-7Z`HC!zgC-V8F)1-p)R8Hm z>^^1NZ*uc`*DzRjGE6>My-=Ee*p^kD%^f>|fiZNn^TY{zpj-CHf{#Lg(El=d=j@Zb zh^E)oTF4I?uvfwG_N+Gx}~d0^bRXbMmDeRHXjR!QC5%PzLAmw(mS*HP6^J}6^_SN8y(e8c$|8) zyEb@-3lCU`%}8$QK4wt!zpM}ovbc=>UT%SLAtRU=^Y(PQ^4zNB6oGYC3A8oK0c<|j zE~e3KsmDPPqgsEci1!pZ2ImbPG1pG=8xb*gm8~;DM;q zrrm|%?%v9sq&xE1W*zAQ;&Bgcy~!%I#S6@zi(k#Nos4`pcI3?{V5k3VVJM;SWA2&N zLM_8AKSmmLjk-}adU-$!>4M?ISLMQ7-N@KxozviW8v&#$Jz2asiYcXP(`anl@hbc{ zw(N-=?3+5>kNL%Klj=5?zMB6KAD+Gw9G+e@6C*)ElenCJ?_H9i&{3(kd}sNS!dC*S zK-U)l8ue0AJm{C7E>wK2hP>3RAtgP#kQMQ1FMf9Ch2}s+bsbe4l9n=+L|=_6f^au8E**)#>&EKvFDk_h~95!a^Xm(^ciF0QbwT6 z^h_a<2qpS)TFpgklnd7fDm7U?=bW|MT543gMDdp9`SBg*Y7T`XeL(`HM>hPeExro- zC*U9&>zixi@$KQ@$0>tqVhElu#(5t!GJ+nZ9RUFA+tO00c^8?TdH4)B|^w>*|g`#Y7+vj{N+3ht39JjdiC9s{V ztSOk<=O8I4{_&6$WdC7E3abAD$cKQG5WLXL_g5pgFMUY8Ws$tc#m`P#p!N}|33*iQ zLyOGIT$Y#7f(|3WO)4&7RJ|eF9qU<&ojN*x&9ko5lJkj*1*Hmi9|T+Xa(*z%N*yMz zU}5NsCP|-UKfR)m_GW`^{%F>-YJAOWD8Es@vA%FMuY+CrB3jA217Eh% zbc7J(&XpnRGK5mt9ae{d=z$*04NE&QDON8 zFU4oO#cm-N)t<_o@_2da>FUe&leMLHMmaHMHW!Z0?!56iS*^S@CH^4%<>edY&z@7H zM5AhPB7C@qmM`rfrRgA-JQJE_!AC=EtVpHqTeo z)s$XxVoRjdAEY+G;U?#}lItWpK1{tO`b4#%BkUrQ-KQTaPDXAXC5|Az+2`5wNw|rV zFmn0XD&9wNRms~4BL#2v$v#d#TSea!QI+g`!zUxDk*JY;Gd^Kt;tij&~5t zrifrBLj1MhIOoo_Cu1MnS#*R)Kk%`fFy^g)NbgaP%Cb|U$h@DX&8c>YZY|F+O@Z^d zTiFVv9%)bUd3tz11C(fiHL9`Ol*9ELg%&h>lUygX67uJPBr!||!#4IVvZk*=0C z_bWhh%><*~PkmE6eorrLqTe~0!D!#)N!a!MINPEP=rZ_8w|q*>jVkTteuSr?5ncAS zggQPF+I_biYk*4l2hodY3agNJEgC7;Itm+K*DQ+w)l>3Yd z3?+r|=3H9XI1nk>urZJf152*1vxsb4`TO1+E_ccD3b1;(BSOkl->L%~Ogq^ANOn~! z>;vNaE?NWoTNah4cj}JlbNbDyWIv}$$r#g*h73`ya4CjerKFX4-g=Q;kG{#;+y(B6 zSi$*IJnAX3M7f{Jg_<$6}Ly+!-(PnZPUDYQ5LEidYo7EG)Z0T9%PK1aVPOTIaxBvI>Nj zvAa;~CdYK`pu2Cg-L2ma-f@4rKjiT6{Itgiu8dxH!}U_Eg3y+9G9|`Q<16V$F%=}N zhDEl?n7E4R{@QYdwl}KH%J7cX?~2PV!CHt`T-HAEU`9K1%afjAi6h z$+(o_^AO>9SwDz`M-3#M0&=hQ$w*-k;Z1a6e+;T7tcj{l zjN*Q03Bj7>#v9Ff`8jSBgr4b=tVc1|h`jsf*`0>uf@1EyZR+cbpfHfqQK77$h!V6^ zmLs-Gzk#JmsmcRBHf+4ZZ8hfZ7sXeup}(AhuffbaO|@*LeVfUOfSlC>S0fU?Nm@aN zwjPV^@&ohDp}2MRxf=HxitSR6f*91#>K?%eqf}*u!-|~SaaZzGq%EJ-Npza)!=$Lv z+yeF+9R%1BySd?U!uj-pxkQK*Q=pb`0*6seHhBpOe%r-jOqatTTrMio&+>H$L4uO34whCRlTN&N`%zcj?y7L=(h2V1((tS&X41PuV5_NI zx>^||VxnOow(+b)^V!8N`hyjqNyCCC#P*fRR=u)d9cRVLw&LX{f3<#`a5L|6 zP9B+QMUfVMT+K__r&hSLACsh5P4141xDX6&UCL48FAEOgX!9fPPc(mtQIpM($k{qz zPHHRPZk>cPZmv-v4owRNngVrdtWvnUU-Bx`d6SD*oe@w4ai-^@+}t3z_mD$wSDEVw zOE@z;QzAxO5E0ieUXQ(+iP|2qW)0T``E&ZKyJ3D10r&SEaLSSEo;AeTW^Vq@k!NvB z7R0$^`V}-OVnT&)Vck2biY1rLJ|T1bP(Mt9tZ+RmbNn@bHajTL5dMfwU|HZzRSb*y z!_JWh`AIENcz(138;+AT_NAAavRh(IHY7GcwE4*KUJAsc*H)wg*DC4=bv?k%<< zoe(8&xQl{L5IDjh`q?{8hduMs$?3t?zBqU9i2d`^yzJ|QQQ<|I;MaNan{?cTID}+F z2k+z|98d@NdzK!z+nyp>nzeU7Wljr_=zX&OMQ8&E?-cpvRYjSnQNaFZ3BCJ|6aQRX!FVXqMC1j(iL)u$Fvt&Hx7jFVU?r3mu zBsxusKtlS@7YXo_vzrZ%VtRNt#i${sz z(9qD}h<=%l`EQS^fuL@{HRn)wcWZNN^P^pCkogfd@NE|x8wX@=ZhrEj4Gta$3u{Cw zBQKuwS#(Iq7=2{`A}MOJEXfNJx{`YZ9z89?wIE07GJ44z=hFs2BSx6?jw4J`OFK0V}Be{(t^&gq8r}cWaJmq zSJLSw!Cn9kyXpP=^uKNcBk-^Pz71ceR|EMtdw75Wt^f>yam5pg1u}OFSDI(!+ue$ZR$>`S14B7h8=`simE?a%9ztYxLMHG5xeR{hdMHzr3V4Sh0 zQf^QJCf56jG~)ku%VcfcAnqQHpdXmy8IJ~I&Zi6Jh#H`%a&K^v7<~-AeLE5UV(JMp zrE9Pf4~#S4x$^7O|9Y|aPn+Uw`Qx5=dS1xL*J(c=;` z7y4iK{$IOAe-wIYCl8Pl@W&0}`Tte|{@wcj>wR?>^htX-fSf!amOt44Up4yo;`7hL z3LrOUn4SBoSvX#R_@H}TSbxn6%|1ClKW{()Ov?7K2|;^X+dDk4M?_T6Gx}j$oXB)5 zBE;n)@@IkG2I1xn;<8o7iS+spIPy`t%A>2`ci(rM2YRc$@{?+=cd0VIA*}y^3yVXD z6&RerUl5yxW|U{t)tiF{mU4SajRjM6o)dkJybu^eS!vkVx(CpGX%U5+r2RR#>; z)5K68aoObYJmMQ3-W1+*8yoZBP!t_j(hNi#+KbJ9Jw}f+3~c-rpnUp$^MB>f?@iA? z{E>xiz0Y^m|HdGcq~Z7gm<=j}*&uU(Nwk*((Zf#%^erT3W_hNYdbR+u^gxTY16-IJ z8ebYb5Td>x(b5L^kOqj!gID?)?4+8@&?xa9Uipk0IZgBw zwaXq8bpRR`vht~;%`F)i6To-`jD4AQw-{gy*a5$=-0p3l_qv^hRI{1@FWpkTUDd(^ zU_1pz9x$resuu18qX8I2VFGkZ&?X5fnoF{*`?ow%m=&dXQr&_?UgjcRa7}|<;^k|A zYf3+H?N^ogy_){RH61`_9Kb&EBN{9rAgZ=qo26>6qmneAYx#_~(j1>H)h@NH8BCN8 zoxK=JEG$Z-5)`3BMSb(~)rhb7Nnj5bvQ^H?_jo)|9E&GU5Y6vAOTZ*14m9ekSuk!`PFDsJ%vr)Mk0`BJJ9r#OS^aLOD7~=yraox@Oqmku!~GTwGR9$|Np^G z%7EP*p;jQK@vDjmu4FyCFMNWurAG;D@r892iTJx-Z8ag0 zDYmxghQa*N!mJEvhB$6JxYCOvNSxBL^0v}1scVg&-WH-dUg4AA66%*@-mAtV3`ssD z%|YksLC^~ppm|>7X4;H&$UJ>`MM-crOX65rb?e!Yj!%uhE@HHdKw(?>fS;}@@>}-D z+Hon=y71J3dE44*YgG_x!SeRE{4>ocMx*8`)?s!l==IhQv@0_QbTd&L20j!@WTd{KLQzSF9? zL3!S1o}r=zV_k8~aI2!NG1&us>p`1uGWQ6I<7&u_TE&F?{LU-{`EHHUr6vUQ-t~IAE!qpz`|1fW-xDYv>|n#DUC4u zaC375I2$ZTZVtKD4*T6d&;G02{s*&bgMIAnK%NkLrcuBKxl;A+($04W6~4K1wJyd@ z>&knP8CeJfjOxgXT3Z>0=r&d=F=E^WUXjuv$m{|a6;>CC%=ENxfY(&~-pNpDs%DL$p$Uzugf zR`Ab1(iJo&UD5T5cb7mnbdG1fY@0?qjBPw#0bYVkSf#Y6Qfj>}9dn+0qMYflU$6jw zcRNOqGI!|lI0-J(WRlV~&TE}4&*hBb#-|wP6hcXoY%}raJXHr8tABijEXW0HrU!Pjf(4Y;=AJk}RCf`@ zy5eA7Nb4yquK}d>)<PpLQ0WZ=O^{8eu5*($Zo+CVt)00|Z`&6cl6S;R zmxXyTVEnIqzqGHj8`zz5(q1uH3$ACkVB$)L1A5RH0wQ7z!lJzH+l(+zdV8PQDSZlj z`5=q-j<@wX+R|FDm^wQUpz;b~C<@`$$PJu3B#J2OA<^>hI?#$_jQnWkBfM50pEor7 zU2PWY#=uXvxvI%Pbb_HGchiIHR9k;Py|;U8ck3OljB(68(t(^a#W(9zTs)`X2FmyO zoooE2%O{jiJ!Y^_UU9N{l3}|pX}j}TohpgEmDT)cCg8C#!r)OgnxV`YB0DCk$A;n;oA4Df8mQ*TPT~%qrAcJ8fxnX-DF64f_Yi-I+JJO z`o@QAZY|U$192Ac-{G8IC(yZR>);2mkKRWdt#+y**{Y8{2tMvsuUk|du&$vcfp z>~CVPky6nWtqs+-lp>C8}OVN@En)D z{y`yk;;Crg8lUXyO}4&?Vb8p*O>MFHRL}Z#M~6d42eo$fcb-)kjg+bphKTN?r*KBs z0ymWcD+flVHf`2-A02+2UBaqrIe8Eq{0iTe+ZZ)2d}vfZV{?LIe$}8p%HYu$i>iq7 zWA2_ivC4?Gva5j@9(J}51(7zV<7MRy1!JaAX6v45-U;6$Co$&M@t zzH1OOKnq&~t6?6L^#mQ&D_~X=Ur0G%CSMmDbTp?(19w0o#sn|OYkLg3 zDU9WNJhr+oMc}sR(yh%m^3)-$Ldls+X`)@FGZQ54q z`(rBy=#4i&%Miz+nj<{a&i*>(S?5o&RAve$0+ptj0Q2UvAn0O~A9fL_QB=nY&DBX2g1tmo4 zLk<~h4P1}GPS1r-&*E^=ZRhYSpVSgMb8t)!)no)D>+L1$*Cp#SP3y%>>ruFjR7xot zX~(5-Lt-?qRiXM4S*>H#NMKe$QD=M+9sJ?zgYfHxE;(#7Bx|yaW5p?`j><7o-^F<3 z5B$Y>G!#A&maw)@6byLca=j_|?d-XT_EKf0?8=T|;GH#?--$YWc0F&`~L`ST{t4fJ4cGYpKC9G3Tp5Bg$ECXvPCg_KqBNsEXh zj8u{;ud4)43N2cYVr!o-V4HkK$BcQ#YBh*VpON8P=35$jN8Q9ts!yO7W z2t_=|f_ZJ$L^I6@MtyB0eB9eysn!GJGiAylRRXDRL6XGv55~ngGy@%p%#D!sg(Hs_ z&Vn`--#xYOCh#M0coEIS06&w6>`5gXQHbnGBHQZDx50qX^hSSK6r*WHpTQrk$%dOL z4(B%3QHnx@4eEvfvY%I*q;?e-SK5cCA@^xGw3Zo3Lw*lFep`vGEfi}1J%)EZ zLi+*YYaBrZLimS#I`a$+9erN{pzE@#H(?<%4Eg*X0R0-m{~jFrHnBX&-2?0{*b?3<=8VXuo*RNPkYvqaJ{8}C%_s3oK5jq zS%=rDoIk=DF_rX%4Dknq(&Z=dY^?^jMJWoX*}JaXy{u4k>4&;HDRZgTNX+SaoqfyLF3R<>PxY5IPsbQ0 zUkY;aCd)5sOwbHs<>o`?3XnD-7H9%#xf1Tx*{#LhS*@B}SDkWAMIcdzQEM?#E93@T5n%qfd4uN}(BjnjGgnN;hdid>XeXomZ2|;sf3JakX z7!&V5XIyC^-*Q{hu)i7P-p@>1*^t4`bz)nY1KGU1ThA-pE77#&)^RBE0IU1S-Y`d{ zS5gy}k1+jmdlsvmu+YeTVI0ZzssW7Y_G71$i$ruEsm5p*&_X!GA4TX_;|qgy{~fyj zCPFG+AUlu)7y?6Vzk&CMK(%5Q#|tQ^n45pRs9E?9BLa1l)?rl{Y1P+EC$)Z1L3KVY7_Ky3+q_aZfZ`S}Y$m8h_4 zhE31Y&Y++*bTq!H7_ojuB_7e{Ca8i!^s`qw_i-bSTP(37kNI99Mjp4yqV~C4sj|TB zkzJ&*ud$ef3;;^)|48lMHSh+=!2$9^r3c3gNRGat`@U*OUx=)hkqQ2qy=#lrO8!rv z{Z}?I0A&4n-=tk2Ab>;QFPRvQCpy5Ph@^Hpcsc+AK5PwwM+iI!M*%kN>Ot2;`04q1 zFCPs3Bs4hZwzcD(?iE6VK&pisTX4q4EIbb0Zo=(;&VCBFi!f{5r^q9MvhM~kQ!IS{ z9>B1oegm>ua*21mdtj#R=CVx6oHc8O7uWsn4NTl)K+BD%UVqt>PNGIrmg=HG7) z6z{!RU}<5Y`lY_G%nwm&ZH z?=qwSv4dQ!%X1&&TS~u=0ZZxezSInTKf-gjKe?5*(}PGrfQ2)XELzBzL1lV&3x2s} zdk}6{@@xcdkBVAcB2fHVi4D7y`0-m(y6hY9sFABLu(a36W;WoL!-RrX7&6rZy?5C) z0==Wu#OX{wg%Q)4T3=F(*UG<_nV6M`yewMmrV!w%AQ)M2(fMWkDl8=tSlrV;F7Wrc z(>KXdfI5M!p&pR$z8MGoNBu;`{Gy-x*Z$E@WE=l0f7j2y3ymho0R;VFUbKty_!qV| zsv}*51blv%7`wiP1c^j8 zzZ+{6XLmQy4^`3Kqc3RdS0C2{Q)0l!^~inoaRdahI9#3-a6Vt`$;XTbny|KopKH~> zlJWN~Qini)AmRvSPQLnC07KK5L0~33n!Xe9VeHDzDek(+y~cTdm;7{ z2Y!{%zgq}pXIm$C4`-+E=KTl_1^)`n?`(X7!9`TfgF&~Rg#`Q0&Ba26gm%{K_?|D0 z?;z~GC!X97Z1$ZmRiVqCCX}S6RzSJ%j4B?y8Oi`aFj?1DO};)oE*d zQk&8n-hG!DyL6qGOAy|OcrO}Xrf+Zi5;cPQVnVJ0^uTEPo(cU*&+kF%ZPySY+Q~|n zDkkX3$|gw5-j_{KkUbcWeR>||KHPFVf;;?CGCn-&j<-wSpq+p(sIbv?D3)jO7@=Hp z1$zG4%c4X^uBnS}%pdHs?@ySvH(&#HY2Hxo=c{hqqhA(-YAfqDxhXda9;6%?2W$Ch zryN)tr=ZbrpOSMUI&pVGxS54A#`rU;q1>-Y%{i*MnUWvsDHmI~DHp4VC|l>7-(%u_ zq{Zzn&mDu$Js{7`j?Z1rWj3<8$k7T5#Uk;noiO_GdBM$+TNi3*fWD_53*<;|{+J{E-AG77E$x9;4lB-a zB}GaQP-DHrXcwzjol7p^y@RJ67Ffz^${4a7ZloD{q`AZ3i{FLZY_%aj9`iE1CxksT z%A7TrnWT(CA=umklaql(x0D$k`85KD-M;wUPSUf_GE2uH4~<9B=NdneNKfzVu2j67 zU0^_yncvUd*^9cxMYD$|2zJi0lsPr zfvnHy2X&UnY{{iJ@~ucLvWE_IaxOs}w#yEZ3hNBSt#x0?3H19)u~Xyb_RFZJh^qss zx?PVgw)9>9*eQxaf3hO~xstld^3tPB9NpDM^5;-$1?Y+G>2xhT?GS!}|Iv83MJ<=< z+zzqhn@}SSW%!i!nW(!4FR4i|gcl_q=BHsinVt5TQ*z?X`<)y>Zv*<#3sP7HYd|$Yt+JjVZ$lnX!M$2^fFFOF)8z91=p*y zqnODP47HCZK)QONX?%-8{n!(G#{4=NY1{b*!w~tk52RY}l>*eGTkR#S)o!b+56%~zz#bp%;U9Warme>9VS zH&hBBdyuoW^A9F+_a}#Y`{9=)OI8esHK-A19{^e4*TS!i8D0)IF#XSso4;D>zq3de zWD7L3ey0H4_27GRB;fP8B;kPoNCO>hF|VNWYjEsI6Yv}c3jU0j{W|yGmwyf9XaNDc zT}%!H92bb;j|J~I0rOzj^AtE-5(x>EFRr{`#hCSfhCIJc{r6?7f$X4eKQR6X2C{tX zm-UrK{1R)8(=qqxpC6x4qN9HeC78&P`C+y8KePSsHcZjk$=Lzw@B^yy|1Qw^l{Aya{+&m3iO@hZw2Ome77=MhWUb-O>vciYV6lON&e%|M}Oa#zsI6Lk=oe|_6?AV z|IcC8-*-(D;$aDbxP3{XaA3LI(JnFp{6$~e;J5hHQ5=xkTUiZDr2hWQ5xoywQBb~i zSbFhS#B6af@2nmp{@*ckgITS76@ zdkFi@uwIzo&;56(U&a|~1A;htLL3}mxeD0)AE;lwU8)094(Uk*(4A6sdJzsw?4kgI zLR-(Nh}gIB84fTcq%9`A(sH3irn9fY67bwx)L1bSRx_Rz0E*THBMcQy{cYbpEr3YN zKN9+P4c7&^fxLd`rExumWi=0WPE+7^d5^accJ~4R*azbn=!OgkTwyy7TzUUAWQ79woC7{Zy?|E8 zr$H;sl6R4p)zT~BcC96o5O&`Ve1_X4kwhBcOotz+yor_sa2m$=X<@Kn8Nl@QKQbQ1 zpg%*QDiGKa2}jUZud=&)@ZEm=vvLTm60|-jLGk|l9N7{D_3AnbH8n~Ep$dnU71cXlrDpKs*c&O!W=P zKmMAN{=Ql(?PmFNFY~XD{ys_j`lu=(qCUX8jVye?PE2Dwz)PyA!gtq;=!C_T+LbiB z=o1-aQbNYnBJA#_X!CivxVYfmO<}BG2AWP^zRa!6mDQ34zAA$+zRoM2v*JpAsS=QF8IDPGO9W`8` z@jA8BW37T@&dDbOSk>D}tjHebP3EjC6pE6dlC;v}yHXVvFV=t1wMcTTeP zfz+^U+x zULsw|FFac9SfWmeNy-Q7u=}k99-lZwya1~2Er*gC&R1=gV-Y9RPhCcNq z%5~!d8p8ISW7H<3kY2~DMYS8wg|&9hQ^~r{&j~Lds=hZjFI@aJO61#Aw+VQNgEM@los1oa7_oc=nH`aL+K30u7S z2V>$6vLTKTe%$>xpn0DeCz`kW%Ob~5%})p#X(!F2WYIl!Lzq6(%qR(LY>-h8mxI!! z51MM)9)wg;;;Ss6m}`YI5x~z#gxp8>@UHF5UVgXZ5Yf^Fau(DVMLF@Xj55Y5Zm90k zAUaxQApFR2NH}zbx0+F9v3pNmUmitorJz2a39)>CjKHE3wL&SV&Pmg&`ZSn=JXFoH zde*$d=$UgG1xD*(`aUhpXue$*kpJIQ-=!VFZV<~a$JxG|N&7Wg`-2{Tdlm|I^KdrP zh5)CHz8}ECLcxcpV-Wx6@YMzYNa2aW;@U%p_v)CKJ-*$v@OmVJhk|)*dL*ic^@);F z(qDpXHPxY17?%0-nY3RG%IQNp=Uz&Rx=VF8!zR$%aa+1x%%eEi$KOnkWz9XqQxB;tlNH;o zuCtksj*pteI(T7uXG=KaI11e=r}MEF6Wx-RRu${Hy!4ibRWrI9`4<=~=F|eZ39t`l z4t{S6ejjaqXP-NeBY1!X#&{GFU=5XCzMx6GS|m0ie4sm=YMfw6cK$9K1qFjL69q*u zk<$(%92nwPYW^YAPyV?Uhx3`NDwa7Z&pjaPfQ__TIFd{gMPr=CnmQpto3vmU6Tf|J?lSh z(SI-DY5>Cd<6%(O16Uo>6N#6cjOa{=TdM8s{QUMdJWweusVwuVt}-tZ8(6gfx9fW) zLNOw}u2;ZyH9e~XMEkbbIXq0j_u&BnXMyYVN=x#Cy1bt`F{R;i6mm zIEqfUB#&LS5O*cv&Y{r5s6g*y&bH{&m!l3LtQk%f43&jv(kE$Ao2u>i@65D2tyFy{YFTm1~b%}wD zzLe4FVbt?sH2Nq8{D}sqn#vRwibTexC_5W1Mia$GkqJc?_Pn(7UVm>dnt;_dpKM&4 zbUb!4H@AHxSx0a%!5*yc2kD+6YS<)Rt<`Rv}Gx`bW_QcNl{%_naDkT+N9U+V%d`i))|4e z0%oY$2PbgXwXfTnDv+3yIRREj!FS2(#+O>#E03C6%{(Ksh%J zQl4@w$wC$|GgWEw4+bzZmBLSV+s>F1U9%!$dzlk=!=&fJE;Dze+14VN-BnWA(Z#N3 zNKSjXM((cE`*?Naw0nnIUN>0pue1! zp$(c~OG7KKG9W%0k?uLb;jM3z?jfME;&^s#(IEQvTn$+A{cx&+T&5odl9M#;q_hN^!75- z%)wls5{6o&^2kww3O0oDs8NDJn(*flpw&)p8|tM;t|(JoW2bf$X|`{x)*<>G;D|-u zc2VctP7}h4`M3bwIPO-;sY{@!C7c<$PJ&C+Ris$Oak-t8_=2LbIJELJGu#`Q$RrfO zr@B>L2Y4L$=25fK`nt@?2Rf4)(aFyWLs{QnVKM@-CReSf+p&{h29@8d4Xyoz>QIR> zuPMJ+q;_1IIBe_~d3&P!<$lRS)56Tw>=TT$i{_sUD_Oi10IH-x{*%G~eQy1a!3R0n zL!8W%fTLg@fYDd!)FcagmC3I?ChdYh7t9d+a+x4FWYn18JP{XNM4=z^Uy;v55k)})Pl|E zl&qtklD^6@NDUe9R51twO7u5K&X!)&e!6(qKpoOnq#|I{-uz_Pezo=tfa&}9%=X*< zr~+B-cQ6^<1!n7UTwwKLyo)v{Aewm*0P7_fak#OBXz>7M_x+Tq9%S6%d44K1TFq@) zVKd1KxA)%Qqqmf}`Vu-F4VN=++AU6+N;M|ep5Baet z77VBOazGwf)KwB#5nMx1$kYuunSY!9vqNA3XXGC;-mnI-AKkJ3^d*7Z_NZ z14;75`vYJUxE{K|^P03HMbd5{q*#3If`Kvl1}tQ>sUL6yit@(@p$6+tdr!IfEbrf% z^6BY_Z8$4RgpWLa*x9=f`z%Q7j5=YpZ7Kkz>ov<8#N7{5mGHYrWg|h}7V92T;!*XI zcp6Te`s#Up)R86idc7UNW3T+mP$Q3JRS^5WA|pZ@leWpgS{r}j_OFid_ps_W`H=&A zxH&^Sn8wv$C#+C+&P}U?SxD>9Ih{A9lyIXqeVW5Yxwlu^m_>wz^+h%e_Uc(tf!r=b zk(qQxBbb zbX19vS$cL4oaI#I-%GWq+Sx1esVG)hUDLOrDj|&-P<}5QH^ZI#6u5gJQQ*@|=G3&S zp{x0f)S7=?sCNIg9?IKUcFUNu4^yJ;b68WuidhY0s`}|FMA2RoXel2`X9$d`-)9|@ zxvv%sRh~}qWz^3>qKxfScwMzC?7)DN`RRTxzdLGXDlY5LGkE2FUI*#o*0&On84HT~ zr0|a|leb@d2zQKDNvX#ebv6p!B+~Q>m_`)iZjV12d)0*`hMD`K0pAlpFbvsY*$$WF zRdrOR#0)2HveW3RB^1BNyv_pbBchNNeUP)(ObKS@hv*I~Qo&uyAXar=>CF59nY3ip zK6NcGdM|>s^w5=)`<3RZ9nqg_(c3@6vmdu}>`$7MiWVtQ3|I15K@Ogn7<$FOJ+D}L zcu{;ZF}<3Y30Mk$z@q=?ENyxA+2O@47<)%n61Uw@XVg!1V#A@GrX6 zVEXkMkmq9!tIc_Mi@8Abx2Gqy&9?(HB+Y|;&WjkcIMdRwa6XabaB$wC>R%Q#FyQ%C zhN7N0)CK6U`CrPV0mvTe0rKD+S5qW{H7?tD3JDQm$!XtIVIYtY=VWM*TM=ibxp~R% z<}=xdJ_&D4G%b9GdYlzD4>ajrf>18H3Rwmgd{qxEA(p$;s?BJo!E~f@3(rF4&jJJ^ z&UdnKM_yeOKbF({Fh7TluUV;f4;TB@t;x8t(Dr6$G^_or3YnyVjmt)9|J1=cDlO&0}&05mBDIP~1VbvxcljmXPz+&V(92(J|6}a|s z>PlIgn^t-yjcyb;mrc($6*PB9YzSo^c_v&bsNS^Zl!~~~uI#0sWR)fm$jWbW#IjUn@rabnQfTZz~tNX>W+7l5i7Lyq_B7L*7eQhg|GPy1_D96lq6!v=W`Skv>5w5Bm+-bZI|1@M2&;YokW;aQRX z$>ARYIXo?px_`;xfn@$7hvyf0+}fjD_ zvI2MmHuvt#g2J%1P9T5z`J0c9^up@5}gAkXW zhn>Uk-t9OBmio%P;Q{cD2s1K$Cv9LD0z(fNrY!nSTEH+EqQ-N+K17A*Y@&u0`S`v9 z@RA5U?6mpoz_@{(CZ-DvJ>)d8>%h2yoYquZh0@jJ^cc0zvX&iuHZt6Xgw9;7eT5s9 z%J3pLY#!7)ehskh+E1+eHQ@NqL<#~__tcV2Y$wc#!jnDi#kdxV7v-dj_Hm(^I)%l^ z0h7HK~C9l4@x8H&nRlXei;0o;xriNz8VU~u2%o{fG$#sv6SF{Bj8A2#a zaI(#^Pev3D-Hfg^Ejnq6Pv0K7<-f1Wa~Ta~MW0u6yDn+L6mO$B=`5w#xyQ?l(bqVe z!FN2B(f3n<>cK)tfBLQUNQ{%Kge?ygRu0Arm&7LdDMndq?H))m7QMfRKs%Ruhxz@+ z?WB1^biC7>n#{*d9;u2(gwK`UsOV+MC3DN`5|(Utg#~ApN^V`U6JJoMS2Klc}ftW7g1neM_jTngAFgjMQ7>ve}ujbSG?`rns^@8~w==+Cq@QoX)|u zm+^xZBSG8?FR>P)xEG$03;SSYW?kuEwS>=i!QV1Q*pjh`e5Z}D6^-n%dBu3)bJjZr zc%=oNP9{U?V^x>q%hI?;E_2tC6M6^sg?BqL*93XWBvDi+k4Lt$=+mUpUB=@BxG-$HYuA(*&}yVL@CLa(d)c4=caGb;Rv?HXf1KpAh46dbBGDZt7NBl znf&DI{CGIcE+39@EW1L=_uV1Mb8o)Xcu&pcNpB27oIJJ9PckdS(FM5tIi&cNBJE?z zIFX8Ndm9S3=aAVCDs#6P$&XK~IT%z$Z{&fkOG5mU$G*5;DeLM9>N%iI^b;=P_5>zk zOq@h9@a`o_7aSh_o7aS%Ei-{SkJ(w2{8B2^ zM-E&Y?O#0f@7LzySVF_v(MS?%;_yp_*98S1LK2?s?1YAh7|?odiv18^xVovLYIF;W zN5B-5v-KtdQ+yi^m|_t6IzW9u0`ie#`P3A=y#Q^$y9R-+T9UNea)!~3CMh2$X z5pF&eR}{#`jKZClQ}y9O-RBT`y{(Y=7bmr-@HTS=JNFLUE1UD~xggZ`X5L0Vbhcn_Lfcv?7=de0_pdVcjY^{&)5&DvWNbR-6G7 zJdGt}j&ZknKduiG(1+YO*|P5vP@t5*q}!>sqR@IPNJ60z88;W6jGt~!gFMQ_l-rIQ zH@U0LVyEo8h}~9A-0-%jopz@4wgkNdb58R(5k;;XS+#nweVj>of#2{3uAS<1PL-oX zHX^>8)irgYux6FsvPx5z>jG^Ygv;(@X!R=18VLM%2}5!{?Py3tX12HlLvU~%CQL~v z)27Ro*w)67y$71b5GUH*QSy+=9yakR?Z%)V5bP2@y3d_icVi}K3R%w(e;hBnTGAAM zoG4ovZ5&sx2d5W5YeVu7nQ!>6$++1lnUm+&59Ef62K7=WuwtS`8EI}9*w|aY#2~+K z?!^v6+RWY&WQbsQjpQ`dLDE#&r?z(W%hi@Xak)$1BAxKBNX`h7NX*l8i_>M%%&Lnb zp)iN7Jr8vf*pi5ZASFCN%ToR-9cla_ybjge-Jd#hNb&0Rp^%xY^V9pQKG&x=k5Ukq z4nKM<51oB9BBpM3m_^6T-b_7#wLfM8I*?QTDFHO@a_|4PiCUSgyDO=SuYH#RKmwoGj{2%jehfx=m&Dd2tB|l4khq48G#5 zXp2s+uIRj9>@YQjz@B&g;V$x2@I2l8P8Fqm<@{P1qxIokx9eYrj~#}NJ*{O8stCmy z?^erKx~k0Ii-{jI>Gt%$&(d@y4?}bLxx?;Am`2t7fK{==W9vl*hD??x*6zysyVP~X zPtAFuR#MOX@5xdb> zm)qFvVJ!YGgb z`mJ-cRIxS;BmdpmXy)2A6KLdqKNpXQi`v&uAOz-VZV>4J3S33Lgw(S_uc@d9)N6N; zBbN&H4zSPVGwX+1%XNVdvHhciz1W8U)jDfS*T2Dq{?|^-ztF!0XVwuYy4YF43Sj31 zjDK{J7XIoa$-y{-BRYJIW&c-olCGQ;C5aYMlxo2~eEVfDemD6S?}d~V=!jc7{-b@= zr$|ue0U7I|C}InjK76y91J1l!s>L2vC5UNloQlVPRYbUcAH z!OeNs8|BJ%a=M@WcQnu(=trkc?q0dQ_eGd9W$C-qb|8^Ng07d+ATbI3uK)ix=a~L6w1Uh-wa1qc%l70 zw!gZ~t{X0Qr<+GX+1^7#`%3o?NzOl97QuihyxKP+A4aWdKtM8ivq5bQ(fyTDVRY(K<%5;94 zEM3=Z&(v}2op3%4w>_nAxEFqd@4I&Jof0fQNAASrmW@zYBZ<&Nlx8i{ zf4C8Y!J{a{rO6*X*h~)++!$+em27Vcfug2atZvY;72$A0vMCf(vA3v9kXZ4C_Jlvi z;S!yxJ|mgp-RN>&@M~YwJ$^C2+Ai)%9Z%zvc;nT3WowjWw>a%~B&Of31ljMm_L`2y zudlT>ikg5%67~pzozW#XY9+-osjCx1cxxVLZZt^3#DUr$O+Rc!JsKy9y|5NZco&a0ocD3j1#G1h0&B zxFVg90o2?7+zqUn!`wixTPhKrCZJHQ&lRt3wYCRNO4wKiCy|8*kS-g zkzK|PCH?jlDU_5Z7RX*M*T5A{$Ah}YwHU&(5*lh#H>@rsLq|3mb>d zdFGNI!qWo5S1SGE*Sa`UR55XOHgP=_`GduzJGk^H$k@m%$OObV$k@8P%fgkR1;NoM zA;BWFfOSMfu0=Dy5gbhJA5R@YGnyrBg-;`A*iDFW8H0u;3(LR3s`J3dr|qN9ccnQ_ z$50-p;4O4c%S(HMeCvzX`*kCrFJcOHMkH?CvM8P_`O+Yk6-J5JzybXzo};z>hIxjW zAQx49P5zp?m-eIBZtgYB+u2%CCgR*{x-_O<46Vanpw*=TgdMoWgJ#xE3VxzuIFbf zCk>|5Gm$-9cCrgfeLci!@0Z$PLI$sx^2Rs;OL4)pj1@(5XW41hKMuO=wCOLpU_78Q zVN0@y-%OBxGm)g3Ks=$WNRDB-XH>O-v5zTS@TGwsZ3|3%92=Ys_PN7&=^ zZI>lhIKHN-(NbRFPF!)7`Jv=fAffAh@?h}vV(}bKyX1oCvg(h~<;B}B>1gTb0z1q< zk?D6&8LMsx+)1fNQkO1W(mVNy`EXZ;A$vc5O1ua8lC(DvipCDwQ*IM$-#~k6$mH!j z_W3=t=U88d6$oH4%s-k9zhC)_-wepEn!3VhlRp&*K%hnNoVr!;Qab{;W>bG%GaV2? z)YX0DR8mT$BrxOa?bW-?kqQN!N$5+56NL79*KIVA;)@}+d%F;@?ent3F5HLOMhv;R z;utLI*+X6uyv>n^D0rLRHkhIN^-G}7wh166onLXDU6D zH&lg)6xJ9Eet%Acr}`ONPo%Bthy4Dn;y(HedpTb=wwb*C$L!!`BzawY{vUzV|`j1D0wQm0m61 z2J2@4cKE+v!;9lp5O-L)nt(sQEF(UEwUf4QBUfCybmM$`m%g4ZBO!~744Z2)hDu^0 z*BIr|7DBsl?KX0#dpvw^edjpfR^AdCGqz}5cAAj@{2|vcP}X*ALIO(*eew{$vd#Gr zDFY=$m(d>5uy2h+J)2KxT)SC_3Tc>Y1j4jUAF0!5N4)U{qC}C~O?g=?P0TFK;On0j zrmTt!BVx91oql%=^dW_lx zTC4Z1WpNiS=OOxya2%Y72Uycfv-@+TAX8#hA`VG*a>nbEE%V2lkV+fIzLUOLC2vUQ z8g)syO3t=2mJX{vQP?FTc?s*?EhPzSR9dnETG|e^ z2-1E@zI=X2>MMWdsann-i{H04)wX=73flE6a8nZt>19bJlqU+r9Oq-1PbdmLW7xeN zZcK^RrbMRaWsP-8o|SMlD>J+$sx-EX_%5i1Tx^JN279a?tFWU4%_2-VqLXH0@h}sC z>VRtDv$xA5yNp<#bOk!X0cSJL)|71)#W|--lsDKE2s9Q z7!;c3-5MESUe%#Zx@9C^y>;cLG-7p6chgsUdx%Y8{6~V}4Z3%?RpvMtC(|gc==R;Y zdi=D_`rUHkL%NrRr&Qb;NOYqa-*xtn4lmiz+7@0N;fSiW?c_jBsvJ=nr)*!$9Z+$j zg}7BF**l_kZlt}Z-`I~rKC=5-_GIlY;UwgdeLCNeKDD}KOpB!SxARE8Ra2Q8>Ncf5VD_f$?k3g9sLCidTNn@M4=p30G zSRedt9ug<0DT-&6)U_(;@S~)+e5xQy!tP#UwRIt5{`Tn%IFnykMri?Ta{n)d+uyC< z#TkQ~iJi5Di3k0t_gRg|-X^Tkhp6xN1mVL+k%`&UwT%UXWlsww@Ev62IHhCkHj1q1{wl^S=B=Vz=7s{C?V$Vc)NU#-^#S_HcWVHXrWX@-!zjkges9yF%{+Fn| z6=JdSyOrTCSc)R?HyR}~3sSo@dws|)EuN}6tMh+~5cA0yD(KxJ-qMd~eO6;mlS(!7 zD7HvAB=){Dg+`vu<vr=58&)PRD<2@^7+d0os>g6$;OqaI*JbC<nb6f{G zlZF7bLyhUcxd!R+ka>hd;s%97HEJ=S3UK?Mr= zMY`Ae)-i=C?Jk)1uhC+(+Ljr=Q#`Nk?mE zb65~d0aL10%#vYax~?}^kVzzsiY@De$G5Nf*;pCWU<#ElBf`*7yEV!d9j<|2-XV?m=zS!n2KkPN#kZ(UpN;pk39FH7(S2`sWGXy; zYTMo>3D-4t)?AOAO;Lyzr--I{AUwIYL_k&jc>^=OhaMSK_s~3n?~>Y&f_>Kff+uOt zv3sVH@t9hceOU(mng(9!_2%JILewATUx+Qn?~KLv*Nq%!4(p@2mJS`;a&?dgGb5WM zY7hl8ca%$LS@%9+2|t#OlO0gkR)4w^s7;tT*0|t|jsNuW2WRCs7)72j?$z|}>g!!b z1*G!&x)sQ~-5HJiRz4{9%^8h~gTVw0 zFkf6n8)VTg*yb4IMzVzUK%}ZiYAP(tlf@QV?z8_(`E*3T=kDGS&&8;BzDp~d55tcFLFO`e2X#u%}H(P z?rBF1epF~<2!umpzXZI$8`g_MB3VaAXLA4%^Hd)7kt2kuLMQK_v(mP-$|Gly5XeZr zP@dUv(FxU0BA0*olI$u2otW?E{y-=N1D$-8+|EPEYI#ZAZy|^$ov5u-HxM7voD^{J zMW;}Y)(yOQFm*-z{-(Em{o!njIcAiHhvTPOiB3AF_c=1F7^yWRH05}X_dY;8j-j;?n;{<8O&o%dw(qv-cBA;XuhhF|hm zX`WGh#x7vb#M_mROj|!NfLlEW^XXev7NBSoZ$b3uG&Iek+{sB1Jp&-{JCtpQJQEBb( zdf~2A`c?BvA6jIvs}9}Qd7U-RXq_DIFgi}hZsjL`wYVuZnx>bF*=85TrY4D`Qu3YU zo2qDwAh*HWPZYjM2%BZ+j+(lCUPfbx9$w+9cYz{}C>#hq9g^zt3jCfkvh&i0`R&8+ zIh8ve8ycB}1BSWwTCy?)lHXM@tfw=lW?4Bi9>CIuCwZ1J1K@rX{$fRc51lW*Bbp{K z!m_KKBYg}Iegu|up!&{>@MlcIi(KQg zCasGwpOjW7{p>bGs#zSK!$Dx0%w}Q#7#24>*((^S<%>S4zy9Tm@W7$ifUru$9Sx<& zM;skFLWbQ0W1fS#OkuK3d2GkQuA-mcOOb7$3rO36fZ492Vus(;_ReRMg01;fHETsh z32WImG|0J>;q%JtX58pwPA@Q4?s>tl+*#r*=rQ_c(X-%O@G^i+T_S$_PF_5fs)Vw( zy3cG2GfxZks2zQ^tuu(4H5D-wtaO+@T$>55OY3mE`w>a|EdoE<1MGWQjMXSb?xGsu z_3FJu`xKGVA}LKs#M?vrOsaDuBW6;$Dc>cjlRV;Ry+u2j9i6{M;A8}ZK44UIxi%T1 zzM&}F$?y?`%ph#GsQB7vk!a@-cyn8(;)=6b6JzJs7tj5pgL$hJD@iF9ws{lTrh+!0 z+F`w3gcN3lk4K>a5q2?;lPc!X^X+E*&7cN+lY0-$;&vxEicf}X@~H}Q^&czB)h9oD zp7ILOf!mUjyi1C*7iz|nRF7D=xW#>-@**a6GK94YbKOk&#aF(XD8oYfk*Q7*w~Br) zXRmd$nX9*MqwGb`U_{MWo4xZsGQ%bJeE8~qg;Qh%)qa$yuq;23<+}vS&lI0dsOOL- z+~{QXI3RO+kJcK~*GyyWT2=Y^1{9SJJ74wh5X{{(n-sbEDtXN^ZEb*>Gjpj~>mwtt zMxP+p7&lzr^Qw7*l@<6~YV76ULmk#s5k+`cH}@AZyS{juN{O34^dtIYFzz>yY;1`u1Y$ONH@QZ0rEW+YF3Ws4%Qz3D81}qqvCT=(_Dw~+m?R9tR74O1gYApvub;1Xf20H`J;#U znubLI2%!n(u-QAdO>mvXx@w5qmsWSBRQx@Huc}Ijj4-L-ZEEXctC=6wbD&WFgeD*g zry7`nSN8eiYhT>GmTT9{ro$E9}##6^Xjw?86meD3%W3P&N66q^ake6@^6PGk+Gh&Ub1@N zq;7$Cwfp6Lf45~9FSC>hAOk!6O@z$tOhEHo0Ze=!9>Ckvze#)h2O*mty?aae?AcEd zwD_?s=YJL?`TZ3xHm8z~CPq47V%y)khJRyK#s1X`V?FDIjfwx?)eB2+tN%!?d0Fh5 zU$4uzJqMt5YDkn5eFk{3XV*>a2RlUc$3oQ~rj`68d`be%784Ma!HDgk5Dhz9f0g;c z*+OXFMJ~VR$A*H^cY=+Drv`-Ec!478SgP7J?mHz0+D@RbUc0gUgp_)=D~=P=P>E$c zD_uwTg$(Kz#dzVcY z#~9aMP`K*-=p}&K{!taw~m+j_X8XH2-`KN(hJPaDUJODw|2K5Z-ArJkuq^+6^&zdqH?E@w zgu>yG0u1<>VkwN%@E*ux*!pbDa$PeiRMh+0+#6WPF?Ng&Y!?%Jd(R71c$mDMuSl?0 zvKlcD;kehkPFm^~hC*Zu3%lJWp_?$2*NLkOoF|SFB|9Vy(Et@S^vxK2wDWs|eS~&G z{e7f%LW2bO1wod^o1ijT4j0|MD8^S~~#Rf$5)@m+PFbWaLhz#5H~}-Dq;B zRU@Hn*)ItlxXdF$JWf+};5Tj45f;W+3*bGmU^Hd-&x27WHkLp@tg9wPLa)c#hGuh@k>~naJ(Qi-U0UeTGP%*r9Me?1o4>wcS)~ zHEvh+9AZTE99AX4$hJ|`|Nh_uh{#tIB8A5*sTpd}Q5I*oZow5txI!0R7UV*+^P~O- zUQd!Tm^P{e1Zf9pCW$kjo{U1D^8E8~P@E>gi zIIPHcrPVrs=^L#NH~(Us4SuWcvLK{kmb`45P8J2vapewJ;&>^r#O~^tp*5ZGY&9YnSLV$kFcueYJb(pkIvMxz;;51u8B=Eop01Ja*5C&e)x zFq)N-EGnQ@jSc~OQs(Le=lNK{5kh`>Oju%y@4H)${bireUD%bB54x1gjqO$CbZ0^*gsyiVlt*068s31j8{* ziWd^OEDxHvKa_4S2=K>}y200EU6Y~lIsG}x7|r9*4AiU0)=TVJ<&~(oR2YFwDD;tT z{30&P88m4^NcHbB!v`}pZ-g{YE)NRLl{$O$x{GaMZys83>nD@+EKu2$ANx6Vnq3oV zb`rSk5a|ANuS$FLacQbf&q?o9jb-s~d8^kLH+=-Y7MLcBM=~^u3|9$KF~n`)#N<84 zawYS+Wk@;mrp=(m;kq>TBd!@tBx@_Wa9%Gt@09F_+*z7Q!6_}42;Oy?^~E*&*J_q_Y%MR&_+KQXr)B`41|{K*~rFQ z>o(V^Y@v1e2!5Sx4B3YfkJbttB3Kvh-z#E|{+PlXc zL*F%{J|2D{6+4C4QeHDfod>4|##I0B+vNXxpaE3q%+ENxe~51f|GKdQ{}XG=MurTm z?X(avUa7ndeCS*KN~HGHXoQ~Kaoc7Z88L(K*fz-3E;Pc-*E?0%~avAhHgBN{lW(I{)}rG)?SIGyHS7 z3QWBa9W|=AA0ifRs&>j~={v`&Wda#clLtd7uDZUxZKTaeJIB&72iR++3`g$PDP{-}I#v2P3GE&!!_Nd^1 zl&L9T(PhbhT4S?}if!pB7XQwgbfoa=Kth1_?NPX$=hlA8wS|~a#UoL~GHl$4<~$J| zl%Th)OBMnx}8Bu*brsi6pbEB^af7--MJlGrtt9~y^>YXphTrCX`hH~yB0s*l) zQwd}p5;j-H`-bpa{Rb4j9;B_xkcMJmM!@*JBME7!KjioIz$E~OH$Q~a*MoC7&)36I z^&S{hLgcS~zY$C4dp6dy?M-a3SHU*m$9O&1$;;RV5Rut8Kz|t`AZOlKMz5!`g5Jr# zTM>f@5n10f7M!UCmr?i`YELagK%a;={zCu3&Z2P~DPMDgt-i6Q!wR^a4+h}u+N5a9 zmP`0cNDgoFUQz;j+09Sc#exlXqcD`A+G7zkcNo;X6QRHzeTt54Y;jYN>stw z4>8k3fS%BfW_2YdyHf-nZ{R&~CyH$LBz4?b9sHsH=T)l=xEY>Blma5-en=H*)LO0L$<^pT=+ z2qu@_%!x$AL;4{8G*7eel*0OHzu;K2Vi3Am6*f;w+MwN=p$HQ?@U?M5%W6SM2#&_< zZjtM1MQB?N5M#P=AjwpJGJ=h}Uw`ss>8NSR;zjR!O%dAL3|Lq;Qd=HLvmwkc`NlQd z6N|}BPE@n>MU_ShEvd6>Vrn%vE8gkEZ z*|*g`7?WyU#`N2WAsaM>AUEbIWDL_KU9mK~uNw0`CZubUP04|&dBHX6dcpBH8h3xo z0=7!`(~ZF(0Z!}yp(dtE`wYwk)7V|r!TuOFuk8^s?#lHWq?A>Q!@(Rsrc@ZGuUqv< z;cmQ1zg^I?in-2~%zViEQT0pMXUea(Eb`GR4u(31bOF=VO&I!ueSYI%_XjPWRuqh} zg!wnbjXgHscI(HSs^ymS6xP`)pU$$$(NmLGBY#t_UoLK%G)(-(Hf$cPu+uA5B9f@W z_ZE%P-l3^oULyqY_{g z+6U_BNwQ8$c*Sd66F+`-M}cYu5OE>xyIF(SDRK{9scg-Nw{Whx)xU5>ik zkuGSq9HUUr200PpZLahKDZhwBJiN_~SJ>3E0qq2Mo1Z@b(Wme#X6o5@gjXO9xIxBo zMw|iK$4rRDKfDohD$+8^!H-=IIdf6jHWIui`{i(u(dtLi6;UjWQo^-Dk;aZEsK6*IriGaLnPAeT8ZU<423q(kAh zKBdCn5uJ$Gl^n*rBQg?|^zof4}Zz!JLuc|yoSgyT?9HaK|CSo(qJBeiS6@r-Yz zx1j%b-U*dBNRxDZ0!W(4z zrV!@ugi_I!>U6ctkLft~93<)YEjmSl={W7PZcidQd|1>>Ra+JuAAAHCt=Jo9e6gXy46KX%DX9bH!j5|pMYDq~hB-m5;(etG@U z8`epTbdE8LxBFyT@0{=mjLIcm97btTc$Z1U9Yu4TS=7B5yErGXk-u8h-#7E$v8a-+ z<_?a|MiSP5*#vInPx^%$76L&(kU;pEF#css%qDy3%;`8vqL+$dHV*` z_;-8gY&GGoK$vdhdgm5S`a&M)w}52PLI@;_U4l;;eR~1a+8+LVM9oVi6aRm9hri#! ze?y%g?kC<^S)rkr*A8HjceQrfz}N0FVS`5m_hq(4U!+uHxWr z&fJZ>a#^fP87MzWKk^;t77XhpgxkWp?Z*b?eTuEobyfp#UajSE05|c^8OOil9F@%- z%pAR7TlweU1~$e62L0MBg+af)90Y4fsHEs?Jl_9r(^kIXWM|T1D6w|6{6LsLBK%=&-m#FuWgiwnTpTbwOGZ8Wbq54$Nw_qS22aaoDCXuI z_@ZulZunO00d3u^u;6ADfqM4!Ar19xwJHUK#U0cEKL5Q8hmR78B3qsfPn`zB9PGd4 zj+$`I&KKv7bQk6t;4Z3}c%6E}yW6m-nXu4Q+@EhR&ya}HFzB6#~Tiq~mcZMmoh@WP$ zTRW=Ed`S32)(=765p#n7a5i<#n~OZm=}jxS(*ptKRamUY;Led7H)3 z_5NWj=Mv5tJCu@3D=u6FO&`DSMHX9-eyfg@RZ_E$_bRABz?`2-QTF{=`Di&9Xm!aQtqHe!nGW!~JOoys^L@#&B z{+Zf$vx&4HD#XzysN8HCA<}KQT3bSETq5$WyvBJ#@y7YD8H;$(-An=v)ArR3DU53h zk;WR~_Y(bcEgxwO$WLIl$<)%V#kF7vu64Ff-!TVGX_ZCX#LlIZNtGuV(NuC*xt zurOA}CDYWk7SD5zDSwQy-d{Iewt?|XK;~V=F}EF)f`O_ULBbTM zr=E!{!=y7E?e|t_lgti(OO0M5Er*QGkoXQgbGqH1?(Vw~|4Ho0cywYpx=RZ|1^k(i zEV;VSK1pi|`6@sMZ0q^H>HbP&Go;c;A;CrAZcq*@t14yp-OI8XvgqkWtaS2qNeyi5 z$HCEEq#Yu>Qm(5O>BPjjf?^M5EV!*x^FLKTRgNCvNS9VV5K_N#PgqU!727DOqqxm$ z#c(g{o!e86xb`hlhpT>t`nXEU;8zkhmupg5oS}Yj_s~w?wD>(|`wt4E!O9~RBLuFh zi!zn+`5PtdZRra4h)QEe8zd`sG4_>onq>Q<};f+qF*i9?V?5a(Ysa~e_1W{BzaY@CA zI(1CisvPV*E6XK~+~pE3dgna^o1nOO%G{E>Z`6XB>>KOR<4yvqJEU2yTHVaO#YwD{ z`s%P686xKJ>~}Q!=ABpGZC!y?#$P_{w~qqn`zF$#tk%VVQ)O5^+!1aJC~_Z zfDxy`l;$P`Jd1*2;bVZD>@v|fg6AQW3Hi(|3u#cy2d&3d92V-?5>3F5_BjOg{%nAY zT-r0P)n#mfZjR_d8dMoUI<08{h`pk?pmp#@LPR#t9k6@7F%sYGa=@SCBQXI!(hFf; zz7e^n%RLu{k8Fmnr2Y*bS%wJkk?;T?iSWH;=oKQ{60a?5<_}^<=7q|a_kkA=K!{tBfKK|DePA+yV8s?Uu^>`Ys>|ujJeK2p= z4|v%Emv6lEMWaseYgs!7QE!0U?`6~arWqM6?RZ__6L+OYdMg@~M39C6id&F|Y)LAB zdff#(SLx3PX$S}95nbdKs6c5U=s6)bLvc$vK(p{^Dcsim*X6z*4@`x@K;hSb$XJ>- zMntDOK!zDzyc7Z7gU&AwzjY&-2O`q-3G|7pKO=|cXYjvi53QYLAhN=jYP2UplpDO; zK@~~xmKcXRZK+0_I?a(zkK>C05U(H~f}5AVkKEG%@QBf7klAOdr$D)O7*G!VCs1w= z=%W4?K)EwG7X=K?Rc2rz=xfODJ_L{F7$=%o(+@CmU9(^)^G~_cQBSf77^Lm_FPr~+ z3UIML(ML9i_}xB&8St0SYo*wu|mAOyiAur z$V;^$W3x-3Nv9&Qt1IG3;7hC!%o50HRiXJ|V5i+M-anBRXx#LPKWt3Cld7bXpWRy` zL!-`M`}EUSe`gKmu}LOVw(0(glQ(gNUSvy@UdD8!3l&sPDR7{9s;|FPRM@CE$v@zu zO3|=*mQ3x=x)U!+Tq&ugxF}o{$IUh=l%>zwHf{i46cL}!V&29pEE`vDV!&@#kIqw( ztW~c(k#;QgLL4%eb$Pi=>OuUbd2K&_#1*uu1M?gVI8uylFLuG>%vj_IR+`^t>6uHYiWSGC6 zC4jS9+;-q@Rq|!rH~?iP@KRBW4EBUxSatXoras+P)%0T2^tb%yE>FI?yWL;sgjux9 zJ$bhJV6%?@!wu5_+Gn01S#vXo(hrNmW+0=y|EPM24@m-vg^q><2l?*Z&~9%H@>ZJe z`yr8PA;Bo9K`5m+hy;17kl3Y}Wz3`%2k+d7tP6ZgZN*H3Mib%RFmz|%yT0v>kLPu# z*(V<@T$Ps6wy&kS>rp!3M%*RO7JHpoLt=SiRIQ_^YHC&Sp<6$Mdil=rfMI?{1hOHg zO|*U>BA+}-{Twq_p?m8mqOTfry)SICb|*d8$@HLp6MNCviMNrh95igeT8xs zyIKr`l2(GdQNynV>@@3gs?24w?a`}E_td7sTZS1XOfV=_l*%fJ4pJ#hNagk7O$l}7 zC$QfzU>uei;4_d8ez+YdN;LRk2-&;8?Y3cAjmR2ppz^&%V+FkAZ+$H`65P*A)WjXo zBDaDuT$hyL^_jl4{w<4TAz_B$75u_PSbx+lxjldflqu})tp|Y=1-#ICL zm3d0s{qWh2`kzG+|9x|;2sN<-8Jx9^EilLDKI=ahnETx{{0qJlXfv8aq2{nM`T2XC z`%cMo(Gkq1e~6A;W*7qqB@>rK4rh=Xx)g!R%|-^O+z535$VQD3sN4vl$9p^A#(TR0 z{SmPUN* zc-o`0>Jqj~UIy@vj2tlmp1kX`*#1U$lpU|NJNINaDx2&q1XHW3|#JpWk}& zo@XPyw`s8{iL5ff|2rWj4+8)W0WeXX0A^@@%_rng%PJH$OSkVxp_VTgklQQk*Wl*` z4c*|kraAl;8#pN8w|;;R{@`il@L$XV&pddd!83f{%Gcv2X*1MwP8ZJetZ1%UqDTmv zOECJ!Z+WqMl{0YzGEJxSMbLd5sP5$DA^Q;2iG_)cPaI&1Rlc8^&B=zD3(3W7q9(`h zb){7@98|fAZ^(8)-TegJ_3|~Yta65c(LVe;3(|K;gOIs31JO`~_D?o%HKbf=TJk&| zxb5~d)+em+`<>)FHWeSO`YtbV7cf2k8X4_F^V!8IErg)<1Ayg}@`xzmH?j)l6v?;` z=B8_4Z+tf0qN3Z{$CgB46h%fcr%rTsg1S|9qu9Rv#cil}Qf zp|Pa3aqW_gps>+cUnVFB`+n4Rk)mp^MN|x-)KOFOn>Ux-U z#}n_5wHXRM9yZ(`bWIrE#U7bq%dO{ATB;hHNm{T#BoW%DbKhFvK1xg9kl+yTUe5Qv z74D7y3cb#f?_*T*U&Neb~~$$r))P5-J_8wF2g6t->M5k7NAKD@uBL3+qJYiZYf(L=opLsGD!zh(aykKj3rj_*%+8lL! zDP|}f5P70IXBaL`_@ckAtGh_#X^fR>1So2^;Z|O{#DxZzgp;7Me(l;Fx0f4{z@-V9 zBLctn0H6?m@oRkmf_UoJcHw}EmM+SI4TiXeBbdNJowY&dj?N;<0D z530`5J$%EyM}AX&mRa!gjCW*=+@>(227l?%{j|2GrFTnvBSA*r7#Mh3^PhZBvJ5m* zt!a{^Yv9{D!5R=wpT~cF{K%)UC^cwuN=Ipz_>-HgdiV=Co5HC8eST}!IQ!8e`559U znUB~nZsx7?ZWlCiuQ%sXPHh%|nu;A~hRWqB>r@@66{)NK3-O4$3ahtQ3C;DYlJVB} z+%LOc$q}vEPvl4)fXd;wOdp%7&1JHp+?JfsJLr?d0bLLz z25)CQ$vtT+L_xNzsBKl5Z0sqm1W-CfO$|L7!G_zTqmRwL6$f^^vlak30gkOxl*s;q zZ5rAd{ z(Q&xYi81h9!6&|BnPi`6W}E!97x{z#3(`kcq#V4r^kl@f?5a$|r5T)ucH3m-t{;d9 zllFOTukO6s+@Z^txyGDlzl&oY|7>niO{wBr5fi&tIQPyCm!lWq;tDy89>WXYz^ z0=n<8`no2y+QL;Jxol6u72YLulEhVuKMfM%y@fF5@qt%M(~EMntA`@9|K11jfyX`} z3Tt~1dfgbG<#r`@z6v;-X_;M5#C)ZLIf%0Mo%;CCi?JyyOe~oBUR34yC*G_%)&RLH7%MLtY&sA5c+UrC|El%Se#$(9*MF z$wb97Dch0h5f)7vt)kmjMby;|#h}jD^Kx_yO5n-=oJ_uGo+L3FEf9Uw8+oJ>^BHp} znm4E1@M-CtfRq@7m~q=gX42J{nj9rEgwWc@%usD{A6uPylG^GpyCd<6Zj`kc?FXOV zjrt1b>iez1w6!!O=G+)3`%5~h_g$P0XNiHf)-*G2?1=lz)HN$guc$ZgI#tGomK zbrtgr>1<2r>xmXpQ{5^ysO#dzgeQ05CLVW&ZyOU50%u_n4#Zm?QK` zbWzkia`CHCHh}UIkC&*g5ymk3{VH!ky#7$2{vN*dn7K~Hw)!_L{u=YN$&B86IWjd- z{&Op*;ugJgIF}89&u;#s&%XG$DueN~W-teI-g1XU_khAG$Hj$q-W)1D25p9wmB&qh zx(bzx9D_+6${8Jjfg&zNfUrLFp)LUQYgdU7fwJIz^w9lfI=zirQN4{Zz#~2r6htqZ z-X8_Zg6;!=UOaafXx@FM1fqgz2=mvT##VAw@KpF3c4_tRrc*B1MVg-SVCol2NuB^J z*!+tn{2$y$6HkB=`J1=LMuA}p{^sq+VFML_w^xR1kA(vcw!VoDHf+r7titB+9vcPo z_ELX*4_ffIf2Oeki+nn0=R7R>+o;^g^EpvXqp&gMss`E`cg#EV+~c3Ly$&nfps_^) zlSF$#I@P5OzcBVDbq;Vg8Pg^a=5q~e5x^u-eK1Kz0HDo-*2N(W6^zDl#QSc(9!pYE zp#HUDTuWg{&9mxwyAd8ZD!84~CN{r0XwnT|HuFBJPcqgN6Osqa*4=sPG%3OzEWFZn z(N4FJel4!jO-%6NVL!FcSvsN=g;E9^k@lEfz|MeC7mrbRcwX04-opmGHCNJ`0BWq;F%FwLBnF#0MC#((aL`^UM16Zo`wAXs zr5j>sf;%f}JL?(~+*Ws*zqZaaz@PVrq`_}-*!V6wxPUprO`hxkUEm1+Nfg#Uv}3_N zUyhrw&oKkD+mVaDmp z$J(WjqNS06ynH3-^1Ieq(z|^&lA-99vOmP{zG062Mn69k{^IIQH)Ku2^^X<8R@MCh z(8g@)VxB=dpR1<4@%}Wln$ZjQKn((>+2mlhsig*u7tYfnhxH^UUw<$C346}ecbRxop%g74EqjW zDqWO({(Za5%2MUQ?^h2wR@dtF&DY)j4|8uFRpr|53rlyGl7e(2A>AMyl7h6vB&8F+_`wf0(`cQ4NQ_TFclKW>;~IEGH2=eqCvieLD1 z@1qTVX}8!t2-V24J*Io(h)^i@l)JNehpycxxm}MdI_is5hm7W%s<%%*nNL|RK5?r# zHZb2kN#ZR=@soFaYNazLX{9E}YBexKLrSB#f3)tUcpH&7FB|?GkXJ zd6_@ve9}@$$HN`9P#H3a?&qwn5;&olml~Ovuo4wISn6rq*0Vr^G!q>XAI%whn4O@6 zt7V`_fk`S8_ml?u@ld?xDdA2?d!)zCSLO}{;3sv5s59iPJj@MS`*4+h>uJhPCoqUL zQKq^#F>NJg@io3Gh8Y;dHbeH9D;}u;gIIK1PT5E8p)8z=n0%x;3$rj_5Q`Tmm@kpv zJ2;9g#9LW&_OC&#LH|;=5AZtwK8XE&$KBqD(!B8qu>J4Y?Z1c9?KQFXjqi}_O*47I z;YI`w`RlyJJ!GWT5|~9uZ~(^^EGm5T_;Qwt@nHo|aboboZipI3utoShR{jgiBgsg~ zNT&vL6CwP(Skq5Y<1LKfDEtU`BSJY9SX2}BSmXX`%MZs7qPJf_DI(1JPd~m{q<|oKc9}GU(c>;PY4(`@${6uT#)+s6eW;{*s z81eb5>5mItV(90UhvDFzHQZu?V+oZ?0|+;9#e?rL8n2O>?gk!BAC&Xf5=?LS^=&Hb z;1&Cd?dT1C0F9zV$(nSE!iE`@PCE85+k3iPRZg;(+g@smFdp{uTZ zFTOT>U9$hBA|y_zU6$-Iti&QX8u0mgWsPO8IFGrfVi@!~C-a`J5At+u0I!Ad`8Y(J z6#NO}Bwq>yTZTW$Plo4^=*55}AQ=X#q(f@xcbd_*`AkGSbR8&(*$?q2Uxyj60l$pa z=@?Brk?jlvP5EqLp$pZzP}3Al=H})~tfHy{g6!na0#PHM1SXfzh38nwJ47^visu#3p=w%vjX~YHYWq@j z((>WEmqYRqCs!k`*%Kb}7%uf0S9;kmga^J4`6h;|u0L2lS8$Xuk@cy>(?ndYecwF3 zo>ix*HNL)^p2KV%RVQ2fTvek|*G;pWn01X(y;2{7<@VBgBB^v7TgeT(q#E0{H((cR zeEN}3s|tbTo|vZBgO}Dz{uBcOWvi?^nxUCmh9x5ikimh6Q(AYx2B8bzkf(g^9lu}I zTu0kc51OUt6SjdgMqoKm!@RJL@dACOjduy{SIW_yGgqY3uD0^+u3jPD+qW45 zi^lq6)fr16=?#XZL&k&`5UCtG=)XbwdF(bcNT70R+@^1hV!uYVDz$xeJElA&xtT^0 zMW_TT14q~PKi)>Ss}vi-{v=g*`L4fRg^(4WoplRuj2ui$<*)7hy2-J&HQ zT#E{fnN%x_o}E~>4`wDkpJPuJ?sT!7y+K$>@&U-5T0Z)KEus&?ATO|LeUJuSfpr8d z<+77I2StM}06Ta~#oztVoF8BZyBasFjT<*;De{Up9|0ef6}A1{=L_FEH6{D69Sd3b zyN3}6t;Gm6-#JiWLmtd@yEAAY*bTR0P>(XWAUJ!IA*1vQD73&e45_ygd{zN?!1r~8 z%G?4!Zrp06RE-+lrJe_G;Oi99c=c zIsF-txS`L-Q#Rn|N-7(WBPX!{c5szQK#qKf0ocJ^A#|~L!D~NtbU+Dr6XgM_j1ufW zoH?fehNBM#=YB38EYVT}Aop<$OVrJ@rK9n!j-~HDD7bHjx z6LAOhedfQ)jOOfPn;StQp?`dSw_m9$0OrHq>MyNm$3qMNNe4c}0KBjN)F1NWN4Zfv zt7GQv?g=g3W8J?eMAp+7RRJipYmHIeUsPr%yZ=^n&l@RLC)>RUzDu#`Awt(+#VNwd z+QLV;6{5O*IH1Vz2a1exfFv2F0FWf70K9>qgvInyvmgpkWMBhD1|m>oC?Nh(Wc;kT z76DA?R<{IDWUSx)cQqIG#K^}x2NnuJ&vrTYG5eIlLQ?P7^EV4&ultxH&Tf3&%|yD< z9U2p{A|49LWo-)-`9NrP;9$HpY=8?c5DjdzTOx%viu!%!0cv7cPn3 z9yTsQ*dzla6F5kL1m3Vv>Frjdldl`C=Q}W;wigVE%8@MIRSTjjbC2hrJ_~V_o+Fas zvX(br<<=+{`F{AKXP&q-z(4+-D46c<3tE?kNEhx)gi@jJ6DqO^ODe9igM~ir{)7C} zV}TqWn)YF0Tr^xCja~TmB*!1@$2EGZ#x@eD#(8=}=h3L13@JwSf)EVn7Wjw1kM5mJ zglb)N=2!U^;FZ#dC|=7bV6Y_=DF<84s?TYLA6q2yQOIzuc4Ev`#F+Lx&Q#5u0cG<} zLwV*NMc3tw5r@IRo5;KM{l0_iLIv^i`rPSp159(Ck;fcJ1eWOZ=_n>El)?RVN8i2lQm})_Pnt?L_U8Zdk zv;U0$0C~6Jm0|(b91E4*3Z2mBW@stqdCSpw5jQkdo1IHY<-EWt;(~uSN}=Z4&Q}8~ z3=i-RI%uKCTsE$qM^+u_8orG)G;)M)dc%sBqDW9@Oto^xxU4C7Zwnkft(Lb-E~!5S z2)CM3^cjowKE|4!heP8s}e%0+k zDPwB{NDF{Xo&(j-|2ku`{bR;tgMTw)>ehM91Xwo+xD0xxq;d*=4{3utpdZWt?u`&Y z)biJ9!wFrBkOX#%DzN@b*jRJ>pKuIyK%xE)@~4{NCz$B8m@aGKoZlsuX{d8|Gw`Vf zWD=R=!oToIs!7XfIJy16ohS0dl?bQFRKT^9G6JBqM&m7gdx7H8-C^+UXrepVcr#Z^ zBIL*Wt1nKjKQgRDzHm2$qCbve@N=JYp+@2fn?_+`@49+~cVDmIM+nT-6{Mnpe>?yQp@Cs; z6WH}u*B_zzY;zIWiW&CftW>Z0=L^=nInBi+#I(MIl&E`tyn&J*-^DxG+ku*wOk|IBu+Jo-HdNnJYKZ<@JP32&)KxNp?rWxFuuGe@ZWJ&o}|O0e1&iNbP0*_nQ9 zbd8ig;|2D)?>VS>auRrtOpIBCbPt8MmsMLYd3f5WXlXoXbqcogK5q$|QN@+`kayxW z_^*nD*xpjcL_zjbmrqLS|-kdJAdQT+gF=XyJ z)|4tXL~i(9uzXLPqJ#jnoqtZ`6-N>b(RchH@=-=biv-937~qTfla2l z-N~m*fZ}oNf&-He#`oy0%*uirIb_wJ#z~40+H0zeW-&wML$o!mxY2h*dKl8DIH3oE zaLQ5g*K zin;6ibH(3EM2bC@TH$xa15Wyr@V8zBoP@A2s8J*_ZoQKcG9S(#(Ssfm?>eP|3zeGm ziVRpLJg@g;kJ^eCN>p=@w>>7+GWnk2unOWrl3&_i2N^8hJM^ zJH2lcYAHJRnP7x-H-GrEz>*?|9iM8tMnhr!Dio<*nKgQ15iPB@>z*hhR5dDNIZE=p zPVStt=#q8J*XCoFb%gfJyNFsOy$8q|nJg))M_tC&gXk7IkBo|I*(d5OI4iddigx>q z3ARRzpa!71Me3n9dwwwyFtEz|#aeRW&3ykP;tdh;kVep099R67~{3T?0ftL=?u>WfJ9>@*(=V;X9IkGUvGhHeVHU z`?M1Ttqr3t32T0~3v<~Pc16Dqh#zAkKpqJ3IpX_g&Q?YAA@9VuC!$)svw+M4KkM5m zIgCH>!3L3b%m~we2#1wEpj20~5VI^M%8Q}P*l6CFJGsNr)IKX`?p?1|h|~FS(fDbr z9rFYk>jxd_q-%7R?;Q#j-!;v>9&$wUmn(8vegDB%TT_~L?R91Hi*`W#wx+NhIQicH zmN?P+Zm*P`-@b}-ENWtb33|m2S$V&GlTiih&~_>L^AM}@Ssh0nDq zcaop)omZi>9k%;BEau4tAGYPLFWsA`E`2W0vMg;p5)_7f8yW?S(PtT5vT)G(`zP>WS+*z*kH zj-nMPC0}K`1+N~Cvke3ZtL|!sYw9MzGa}2}m7J{kwQ@SepoNJ8 z)ckM25tbYR>WsMZqe)U-5R9Ns3F!(EhE5Du>Xty6moQrRmamf3)|SD2BMo2j$Rq;2 zQ&E@s4rIgMhu>dN-eEuc%(QRl}Ru2D~`pN36~Y0fI-#jws*AtfvlDoqy{SF|W9C?x=4V=v)ZeX68G&%r_kUAt$B|G{rykH5sgRFW~M_35$%n zr71KNK`-GFW6E3Hrq-;aP7I1cyt|SpZJ>8uGLWx&ZjC@GCZ@CR(y{^Y|CD|uXG|2y z`4j)$5hH2tYHMP3V^L1vc;}`HW+z0aMR(amRsWv*iJ!G=ZofD;XGB_Ag0>(-S`8-v zUA<{p%9i2BeL1zjPBFw~zC$`xi37TYs2zHA8oCz5n<5wsZ^ox>Z@IViq#@|sw}HO9 z^4&$INM!kf1C{bCN0<4qHXM|^rI^TXG*nO6{cKLXUDCodWHzTujrV&crNCYo`qw7B$?$+DZs@=Lk&7GlK9j8>dqjc?0E zZvtsNPbKey|D?%yqmtfR`Rzxb4^N;QOmi==3%kn+ca^b&!s`Ww9>}uI31J+D=g5%N zTT#{UJm@;f7#c5f0bjeMD|%0ZYAD&cND6$8MqAmcrSe|hSdxnkSc#EX*~BZ_vX1)7 zv&Ur=+hL@oJ`WR-m{+atq@vp0C*I9|1%}E9-CM^mPUm5HPdCB`I=!PLs5+|J7-n3} z7_|5847ZY2s);wCuKIh5HXtYkN}ixMyo#GKfA%X0_J$Sbk+PTnwlGO@9hK8g#3>Q(e0`J zV_OrmpFTTuf_QSn_9y zQPut9d;m0y<@K;$l_knr-ZNG^p4!T1>!&^KPiES}SU$N_%#3W>25lLe z@q~hu<^*EM`W>9FRXMY9WVm?RccJylxX^Li#xa@~@e_>|^bJMqCV1bSdfh8!M*A~0 z_|D$7drcXAu2jxWlQ#2@*Cn>f>q7bRPIoOV^#bB4HnbDQdv07Qs_S(T8{dtx9r;>q zD~62mhzSB`{%SlHo=nS_fD7h=$wv@0+-;1}KwDU72~&tE3ombwQP_S8ljW0;ALsyA zLl!W1#IZF52j0i5`6@6ZO&SO%8Cw#mD{SEJRKtT^1F&a=ccz1U-Gp}*5ilOwuC!xe zM8KrGu)Oe16c8y4D@382Apz0K3rVO6M|{y179w zi3&@ESTe)zX+XXqSP%Z7t?* ztJt?Zs|0j33=Yi3yLh!N#XQUp&qjyXX+Nfh8z&~FZ5k3pW#-F7;K^HU4kYecS%l!r zo1RK&&gaRM$elTDNt)=R)n170t=N9>CE4)F;;z#OCv-V~Sc7OFi)}Ez>6F5bQjI8~ z);ZO&VsoF|7Zx7HskXwA%}455w^}n!oIh>ByOgg9%aSdHO)76{O0X49)W?n-W2=|3 zvKF|sKFWMzcZy1P3RltU{iv|q)rg6=&bGiMAKUHS>`S4K+Qu;!KtAm(`l`sqDD+6> zvS5;-GfQdN_rnf^n#y((+iNqZq3K0(eF6lBdE^@x9K(5DM=RZ@=LzgEC1KlXB#f@k zD}EEd)xLK<@;wh$`+hvx_f)8=f)G)n6uL5D7+L?Q+X<;hZ55eOp%10$d+1b(w?yzv zh3U`=zAz}jQ(;y>hj9(r*u#f`X^lbsf#K-mX!p2)xo<1X)?JF25N<69x=2MCzIJ|? zK}j%ExykF1cGA1ND>HhITlAr_!xjbF+&gdXT?!6!P9bh{wNpObj5zRRnG>xYCs+;A zW<8J$jFyM!;14}$Uwmr3N(^H_YEsfQULx9A(SXDog%0(_mm`Lero@)cd#WOAiusnA3@6j6UQkgmy?iCwo0BY8d84&3q5(0Z^=(1f0YtsU$R zLaQ4@nBUH&gZbj@#G-(^u!Pn_*BVSt?RDE7^a6=m0y0s@@GEGg6(Qre6*SU{ocg%h z1i=QF9f{W8o5=lnU%0eo1=FSRSJ0s;Lg$Qkk##pHT)sSf?@9jUL>Fhd;TkJjh#u3~QE%aKVBW_47IvX{;YA0VGWb(-tyZu&?EU8&4yPyI=K%1c5Ea0rY z5#rZ;eUm4qdE)(82lgyF(toXsrv~sO>~5y;e+*pyThL;^w}x)tz^c{&AJXz>cJYU} z*e_fj$uFZ?%|DH5`~UA6)&3X#KGp#SvD*PmnpUpB*y5%^{1?Zg8z?>VA06Uz{r8BgSF>1aem?~Rr?LR$ znHRb`+koMC+0mVYx~UAf12Egzor7bct(&nSz!;4Ys(|~?=Z1s75a1{Pvk4$HiPob0 z3jv-4d~hXaJrP5q1#Fbr5&CX?l=}soT72ME4j6*gf&sgft|lkIM;Wk5IURX)KWm%} zlHtjqt5Qz*SqzYDzkki8m&ol50YH)n5x?v^kbkkDE-`^sMlwITJDs|wd30b@KTBw&nJd*|Sr zJ)qo!J`d0u%vIkrv+V8OU1NqVg&~XarX-a`i{@sxZ8`oUE*)B zg1^Ri_wF0cd&TZzXO$vC-?AU9D#yMepKStk zWStff`vpSl13lCS?w|jX1irg5pg{}717Jz?mk0m*33Pjl1~7~^1)#x}KeN`K*b5Ut zWNlwqv7FipZCs89T`%y}Dt+g^6d6ulg*Z*#By~rw#4_rBxYfJ7TsqWTMmnnqQgj+d z8aaawefWsT$u27^{!i-H$%f>hT8FAwa*0;?c<{sDOtp)!ce~%!6Qpy#rQ0%{ zpbsMCx{O^{sE;L9usT5Ye#w?JijPHAkQ7StWL#3C60-mrQfHBCH#vssLo^PiuzP$S z0G-FU?l|Uw`n<*7TW8af2dsUjvV z`bu?J$)3PSFwFy-BIIt!FiI|EaAMakb}7t$GKeq$ckUx&fgO$XXcWGLU^t8zv4xff zDK9E`@41@I(pxY79WSvH`;GHe%Is>Xs?)~H$X&_Db_ca44FI{(NS&~SRI5(xaLU># zGs;}_o#45&mR;P)CD&W)=pUDlS9W8 zmiYo7)FqD*1~S8*yHrnG&JiIkj8@!R+vM?cmXwamV%VdmLu5h|EoS$$C~@;B(bzI{RaLwf4a0cafXi^hB|Mc&JJ{3YYL2p?!wut`kl zy}Z&Fs5}WnT==MAqZKz3xK9w|%yjIvUC^R9zD~z*AS!>(C=l_HXSXJY$Z6-R)@bV* zY`IBR|7qUkq?L^#)aWv!Yn`T&e1(=d3Tll?UrF~p!Brxqf+M%d7ImETk<~e6UZsoe zDE7US;O`X^F5eBLvnIi*~bDhC(I3TneT6F2WxJVcGtV z#qsUM(oa`u)j@kn6FZ}{pjbc813O+q*toyd#03Y@QHkL7f9F$i7{B1Nckyzqx zakcrd=BjDr0DA|$Oo~+S@CA=XgM$giINnq|Vg5G-h4)kgKif_b}^0`Ctg5IP$;U!ZP^p%!izpiUs9rrL##X5pE zSwXGRIb1o;xFRIfO?QI6qFZtPsZAhp6&T0Pk^)U{P*8+ZgM6AI*Qa7X%YK*@Z>~4= z(8b0Aqm%v{r`KJ+q#yxF$SnB~MIhTE(MwsRlb`peH?D1aGXS4# zVrkBHV?AO5%p%>~_}sYraQoF*BIM$il_k3hoD3gH4oNz3AAO>B!l7W+)C^4P4yt02 z4vuv}>kzyDt|>$<7=jnrK#?~K*BLb~gX#33AX6AReE5ajw`S>t+xZ6@0pWSbv?njE zw}k6N=GFk+2zbcC&03;6d#`GG3UDx&lnjsYmfkVk^BG&lE$zYC4$u@`5(CUgaHz^H z43;dlwQJ=U%(B`XpKQS$N}dQ~KYB#(vS7K_WnExsd==FgCfZ4++-OcHZKEEdp5n;) zG>}<^Qj$XDW&QxZs(LRzbif&^;W)Rc-O8{Et#Q=LY>Bo`S@j~>h0{#%p>h?FvgyB& zG#DIxV`)V}Tsfb2qzlz2X1jP4+<2G-o~bJQPIgj6QZV^a)UsLDGg@K;bt^z4&@(Yz zJo>X$zJMNUb+qTVuw&MT{+_-rcaJ&>S}Iff<(nRpX%gpIMRq*nzN{0~%Wfr0gV1O1C~FTRlJ`TH z9Ei`E{5X_|EUKEA8q9+HxIe2yjl>gC-; zRqFP|-;(3w+iyQ{9rv+bj(-FKruQEM=Jqo{$^meM1SBnhH1tmZA^4Zl0BgIUxF`a` z$sehxtl6(rbdaRoal5-ABvcDVm1*X_OB{-3d*HOX?Jq@neHGa&V8mB3DmUV9A=w$5jw#mgU5>XrOei)u z{<54P68vQdN#?40|7{q*bn}|jmZ9+LZAHiMAHxyOMP#QtUamv`_g|Z7==|L^>b216w{sJVv zy&PnvxwUAKwDsw?L#;DVinH3COV8m#9LquVN7Y{H^$&5>&F;;)hZ197$t+wwZX#=r z@q{=K9`)sjycx*Lx(hAVf?C%2YC_|Wt$QR}N()-jbGus>N?uJsRlfm}AEbNy8GjVKo>9xAg;4gYhjT zA*80yI*1J<<~EGY(eQYF5J%%r5VMDSF00{(5JzyZsdIQopsB<@@s`jdBqR*uH4J}1 zkc&K&!V$qmipL`Xda%`a%8`|^e+u2mxSoirkxb3&dOKiLY=yy^?5g11PRdGF zRnd(vQp~sz$GkSrfE)2W^K%|zWVIjVWm|2)5|y5%G)}hrELuR#qK=Vi%UwXM`B`W|^_@)*sJJ?o#x(USMI z>!s;``&yT7zi&oe}-fcLOe%Q?h9P|C6o_GNp%8CA}T~m7RFG2uhJz7sVx8^@;nm z*`XF1iKo}wAuzj2Os-@O&J>&9Tg{kFPyY0LWZ;Rnx%m{UW|lc((!OvgGjw!X2$Zff zS|?~VJ#MJ!IH95mQoyo)OlPMPiCxj!XtUwGSTo_d3l$|}v&zSswd&-X zt0CPR#9-M?ntw&=_$Ys|0kpd3qS+^t?lN}e+Af`eL0?23ind^qlCsw8O*8fi)cs7% zg2Yn{EP3%MzwpconTl=UvHrN^pj9rLPw=da1;#L8*A5LscqVRxgq|U;5H&ioRR{tU z3jsQe0L}AFtIgKN?@$!%5tpc@IFVI|fR?Q|I zAA8lQKTs*&k(v^;I$|1B%NhVrBKa_s&3eI4l@-@|Y~%9>q6F8?V*%W%(MK;U_N5A%Z*BIC95eHt23qH&Bv@MAJpTjOnWNJeGU?^ z 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

    qm4Wk) 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 z zyilqUq;P>0&~q%l02J$AATtUX=%TIqIN9ZLI5)PR{$Rq*NH49pp+kwK=E|9T?j1y#_7$?*W z8#0N|6-rdqmW^SOci7tA@c(=q>#yi%)jSj2^tAQ<^yD2K;{o*kRkILGXE~+AT*+fOc`Ws zA@db7gpf&tj2>j>Aj1!tX2|$L<^nR9kg53hih`aqLFkny2t9>@(6klWTPqZ6g<`Ex z%pZ#RLot6S<`2a#q1Yu9`}exKgksoG3>%7JLpp3I_U~FHLa{_BmI%fEy^=Mdm?jj{ zgkn=r?i3W8f?`uptN?m)C7pS8!~RB$Cf#4`sl5SncW92BLVJHetPbWDJfuH+LYHht z?yqARWbYR0GBN&GgpES;acFMA4ftI(lwb32&I`@kp}8Pbug4Lp#}3tV&w)~hp;Ufo zz5vzl`PW|@nx8=Y{v*Vrpi+`h>$~?*DNU$Um=jcr7m^l0(jF^ljtxXrD}i_c#P408`ovKEo@{7o6Oi-- zlHNno&<$w*5aMAF4|Cwzy^nhi8PGXQ0jyCn1@sInht`l~4utlmkP(B7C8Prv`(6zi zsX@7FHazzg&K-x@jbbHSw~<|Sdu0S@xk?0xv_jG;NjOh>*Z$u>`^Vsq?vKL`>g733 z-o|g(6br^TojW~5QfC(E#aDH&pWQBa5ZpI&!S0Qb2E$%%_YldSS;Q7y)eUOhF5ofU zIU~XD$zry96hP<;m|}ow>~>GO+?jwjfGq%~1{n0F1ld>s zKLYp_z_d(v2hRxZeMw;VBA_=V$W8!Q5#SPlxdAo=m;zwXI}c=Q0L%z*3c$<&>jDh6 zE&_Vzf$T|u?E!8C80`7L6ksZVL2omV%>ghmz_9?+1FQ`&*mpbVZ3eR802=^Y128|p z#sGtTw}akmAlnUKL4b1rW(QawV6g9Y(0dJJ9|PZeo2Uru}3V?Y5HUb#zI}r5l0@>yOa{`ZFf zCk8$P_zd6;fHwes0r&;r1%Vd?z7_aZ;QfL32mTWHOW?7A#|AzT_(b3}f!73n3iv7D zIf3T{z7F_0;N5|D2mS>36X2cknm?4{Goz01pfBFr&C% z+qyadxBCjBqPS$1rQh@{bw7oJ69+49=DgMAQ5jkEV1uwqr~&}k_1eNfGTFECj*3b zfMOctlY%f62*>X9Fm7I*du_UF=x!GD0JaAh+Vcm1!S_x=z`nad zZwrvk2{19hssNV(%mXmkcQ@#50kZ1=HUQWe;AVhD00#T+2E8{xwmZOr0Gj|@3$Osd zVBg)K_Xfy50oWhlAb`67mH-&+I~4Sm1liO8V*{)Ra0$TN;57&K9SV9&g6sl-H30_y z(k>eT76usXI~4Tp0ofJ+a{_Dta1FrV#qk&HI~4Tp0ofY>y90cwb+&O*vE3snH5e9_ z1iQb(A-w-<#d3G^MECYmvFhq15eTRufiw^#0|5aLI06AL5ZD93lvaOh5S+aEv>vUt zvKYlays8)X+3Y6L_o`k5E;-Drf(&CZGs0%MJ{BjrF%~DAX%;8lWfmu&Z5AiBeHJH| zpDa$Jzw~Cc(cV>hGQX=VOEJ_MFMVG;#Mn@ru5K%@u4E_Ao-qkCmM9`@mQi7K8Z6bH zRdKAXOv5+Pswr(L)>n6v2fsTbUz@%OGZr5tY*t8Sb(-Kam^F@pS2pXIX{98C$Bdbl z4xYKzL1|}kIYU=*d0AKSyn3*_x@L&{gi@&dgj$&Vgi5&lgvLwx+6<)F>=cyP>>Sis zm8=$lG(K0nGyzwhG$Gf=X(FzaEH9RISwfciSY9r->ppJ&p^Mi{s!P_KrAyarq|4I0 zq|4KMQR(C4T^Z@*U6tx|prbq|P&i%fszk5960K6(!kuR7iqF!uT&^3@JW)yDoTH;W z-%>dJ&Q+P-cm<}?+`^yc;!4i4w%nrI*L+l&>b#<(yx>1yFk3w9-D z`MV6)MQmBCByj1_QC|FAI9-3FOmDpst1{Rkm=@=w=&h`Mn`!Gt8lu3 zQiK)jZADo5zSONdCmyv~3;HKr#p<9FT+=NXCK0Oan+B z1Bn47fdR=Jkia1cJCGbe5~vCakO)GO7$BJd5;sV~3M4B)vIbSb0up~n0X$5YUhNB&^D|u<&4tI9)r7w8 z+U!+9u}5QMW?#^6`Q0_))iX^ZId) zF8Xn|eDn74imvK$w`}vb;||@}<8H;~{o@k<(m;t7IallLuEJcIya_Ukxu-7v4cCMg{Yq1 zNr8|g6w-u3yiiC6g#5poL|htNr*Hm^@1_q3t8hnKmxMx^P$(9JPNrMYx=Y;gZ@I1o zdZ%PJ7y`buqOJdOjo<|HOW>)C0qg{WFzk?=%{@pO^kW4{QWDIF3&AV`FpKDJ_0xV3 z?%{&MMeg`wP&5@pV?n)8Pf(0gdV}E#7pkZX23pWS9Spdkfhri#L+Jz{eHhAcgfhT# zuFjxB>7mn`x}+xe!n)U^;KBT=XXx+7^PDgD=eu^F!l+l?Elo&Xnf8$H|2`)Afps{9 zMGoG$<8l}|v!53;ju~Gd@k-?3huOg?Sr>sk&y}4jL|Ddv9 z9y1iPptazO`iZ^Y`9&kjMx%Y=tsr!V%3T#65n=5I4{Q_u+da_#_fu}Q!NGh1|8b+> zJUwT3iaFBI1b;jGF7v&H$>n#Rc(OAC0oLx>ZEi8NQgN~rE{p;Ad)96{69M9*f&RRW z2XB&)bjvKH!z1M+3Rwu%IjeS6CfZqGFNylpWwswuw>`NUpq9enS1<6k^FJCO*S+Y^ z_5PN7-hFZ|c5*Y>d07zl>EUABjMXYE3L|bzm{fuMH`yX_pCO6JZ*rk$Q-5Ds&2A;V zJmVs(7mSShdK*nag}KEoEJ>w+nohycr?gd1;UcW|CJD<*C0~e^g4<(OYUpFr$H!BC zl&rjV9r-Ea$K;(BQipgBhf}s)5ozpkMp?zR_YCL#{?tL#wZy1jYh`-<8uO(Nu0G>B z52+BKYcOmrJKh9XCx$ID;&hIWioAA3e2;anKQva3KN@jhGZW$;hvxA2Lx0Q1pR|n5 zi3AmlF8+1=Z?`mjm@?>SV(YKW*JmH=V9EZ*`nu}VH)c}BEc$j#T@&BddT2~23jAuY zdYiEI=(4%BZZT=iA$|hUQ=Vfj)z^e3`KIrurvPSY8<2` z-JJ+2Rd!KAd7)sG7*C$(WsVz}Y=%`O{rcvf1|OE`EQRvveDLLC)C%5y*cNjo)Yd^H zcUr57QKu-b^3O(3xhunrScm%fbT8nAJi2JY&k% zmC&bHNcaQOY;n#?tj4$c$NZB*uXB4?>#Ix37d&_jd~|+eDe9}wT=;%wKT$l@@o7AE zZ%Vrn_ZmT4?e-AL99?u|^)ATa0Ka(p@hmluvt9>je)oZn6 zhKQX2x(IwBqTUptQNIrJw~Sdg@wmBtsKgaWfp-PJ+ciF|;VT{zysXtW(cpNiyFt7c zxiPFdO9Ce_DwO5d8k#Ie*V#{F$8GxgLUcU)sNQoXv6JyPUI z`sa$DVf=>UzM^3?zG5+Bf!iVj;zU%#n86*75b_ZfDyk-=Z}rTMH%atYf^Y{UR(tgt z!!Yx>5So{xIYi!0wvSK#KD8&SMeFJD;`8AD2sagAfkZo75U4 zfwPuhca7Q4GTJ6^_J64tx(%iC%u;P+IlNY=|2R4+?C{Mt^3$J2hhW0%UI!1XA?Lhr zxAc)5#ob5rBrnfD|8jk4&R(8%zE?jU=a|D;qNPC}Ic1&K6hw&mXb&ewAibWgJgr`= zJ)#CrpT$2+Ry^LZ{`w@EVaj3qwmCLgT8jJow;oa#c}&e`x%dvf$}n#jh6etb4#~%v z%z?V44;4%0_5|Zp+b4afp$X>8ZpL;zD@nPqsJ~ zbisN|Xn>1TT=w^|{+9-9|1|lq{COVb@;?HIizD;k^HD>}ZTgC7K&*!Kw zOQhji#G^>X8MEwBK5eIcR_2{u~XhpcMKY zxlEHet@BG)wl^wNzJ$Bs1B`aWr$?qA1*gk!+_ni)gl$~i<{ozS8giBA$$Fb6B6nCz zAD!W4r`SjAp1PVA=-F_78aJasg8;`_mQRF*at6?tR4n`@OiPB9wT`aaX4vDX~>Ugs_!T8OLW z&9z)=a0NL^XyL<{={KQe8yTK?z9*^yes3d1naDh12KJcy4}ybU4csfE-OFpO+r00V z-*@NjI>EW>U|YVdr#{)??q0cipy=q0LCvD9sBE9gOj^o@^3~LU&_Bp%)m3ci^`o@5 zj+$)|JYt3p#|e05W5*;+=zKN`CZ&(j zf3C0p=IOKhMfAb>S~~;BKt&oz*<=1`Bw0x`E^7=U7aCY z!Inm_ddr6HjXixW%R7{@cQU(Amu}uI9vQsX=5cI~U~oIux0n*YM}|KCmA|GF$^=K# zT4DUR&wsN2^QlnM*4{o|R?mGD+`U|_eE#DTVVSPKdH8JTApl)r8Yb+TaW5(5zyaY^0JL#sEe@ci1dGqAe4Mb z*@O7zCZAvndkM3jPV;ij|3r8X+>iG5_vPQH2j(*BLrm#-B)tcC>q*a2M@{Yeb6l9- zTgeZxz*P)WXm{8JUgQ|rwzN#XbLJ_otp6d32Ul&Q-6{`ndcIgbUrEyP+<3xyP#&SL zA$&Jt&d0R&hknygI&RR_-gU(n$&-T65q=;B) zpUU62HyiOE`qnPfOeu{{$H+Zl$-dF}vc^S;a85rCuQ67g5ya4I6%dRuTAL@cQ}<>! zX|83@*rd47POIc!Gix|hkN@!#@f#9Gmd26+VO}nsS@MrlUj#)4)z)TLbytUp_OXcU z3t=MM6+2&UEAeqejn_|K_baha_+oYlGezwR>YDfTdT(R8Jz70FK%AtE?!f-ZzD|aK ze?((Y(~7y4m-D#Br&Lhm<5JRL($D_W>k2;yOjR=poCAbjJaa||=Lj;h=fiqkjl9ns zf=rqG-jyvSd_n#~TSqPTdCOtE_*H>ptoidy=k(|8KIqKWnJKd@>&)uuX6p9=^3G>D zvi`YloP_fY>}wvm&A&h2n;RCgXbIkq^H;VdfwvOsbC{U4xUpp&#wA{UXr5uy>J?ho zJ0%$UPPt#c;@^D6EEMC2%wk7iI)vD0o^ncc)6KMLSm4H!en}V{j!hVhL>EHE$yCXs zYA=hBfn<7R;r=WtxUK*(f0JWId;In_zvP*@cwiCB&6#Wbb9aZgwE?0%*gTR~NxoD$ zpUu>#;pXpM$2kO?hp_fIr&E;8H*noaCfYk_^9wEBXeGJHIjAOVGA#{%-(!qmbbKuk zb4c)K=!`FZ>a$DCJl(If#vq)A=l-~V@`okIpOohLOI=CG1D9zOtUlSsC# z0I!8!qI_&mitXkh-3GFU=dtM~7mRqbAJvD6;dXaiZkS1XDfbjr>l)u5_dvnO5kKYe zK&i*$l-%2=<-whFTkm<^G=2!Cu0NnSY$GNL$GoxpG?q-bRsX@Qg2h23<`a9B6t?=M z+@ya{xVJR?h^si07=~$!)x#!&NzV+Jmg1Dw#Kc(bT*Tz>y4 zURWJksuEhvA=Za{yE^|?rmz_&w<*wWbj$r}L{aE?0=YIU}U(f3}xO@HQhq3=SXqyW2_0wlM z+7yhnFPa=_lvnt$_csOTcgV={Q%3nb-;2*f2W_Liw~UeVS4zV{C-T9SQejD|X2U_( zzkLw;;QqlG+ur&I%6Mv8twE&^Q{LSt!I!H+xdnHBj;X@;>M3Le8(8?ySrRsFk%f^n z{@lVMkO?2de~z+t8tulzY3gM9n@2*t(7nc}saYps`1N8EO+vSnjoyRdw4(*Y7atr_ZY}$F=Y- z&M{+rH)V-SWstDHIWO*cUB@6yZ~VJ+OaIHx3(q%K)nDz9yTQSkWpAj6n8aM`aQe0= zTrG?^IZZUy4LQE3+{nGx_L<_2)Rskl1J89$R(e%B-O_~C;XFtt`?NXrtH2Te0&_OU z4-4yO?u!~r9_J@|qe-@;#XJ<*Smj=V@t99^cvxyk^Kw~gc4T|$spyf3mp1K(M{_=r zPPRM{CV8jLZ@S>ca{pR-Pj3u$LSHrRck<%-bM$3i8*GA=-c0L3`RxxH~vxTVd zK3N(u%*3pn`~p8(et@&KgO)1CKK&}sP7)iQB*M@_WC>uTRDNNnXnb{k!Sr5v244L< zN59r@&ckUQW=es6&Ca&bq-HSYQ>!k>%Xlo8r{<_zU=zmuZH;a$-5m#s?p3mxQQGbo zw8p2Lwbd&J362wlf2@2KHm-Fj6lAHd`JZx+kZY$qs7<{plM3bQOc4D3o{u8_jo?}O zn;D@JE5sDC$>$ANpMwm^?4YBzExB?-Gxx@xgd|)2wCvUy|3!g0b1@Qv6B?7=pnBV- zP%Y+*aem+Ldcj*hZ}Um)iLR*67j0?Xf#>FJy`NL2b2vpD56ZVOnzp!qZR2uL5H>10 zYJ4a@vl`$EA9mbB%f8T=>Nyp(G@0e4C}}Z!_pP$5F*)5H2d_p&gko8GWdSjryk_>H zi11g>T!n1=Hx)>fQ6#B2=cxFoIO>-d_zIP{C35DrFFijsrjP{tAZntoGHH|0Iltk1 zLx0S+<#j*#i)%$b^Nw!CVdHhfSNs5&0CGT`{oyNrYa~X;0@?iJBwfrOJYnMPCeHhRZY%b8me ziAPJ5%UF?yejqXuEjI-tW8`f|b$+C4W&Gn%ESyS-m;0>G=n-}Z-wPjiC7+IWdnWP^ zhlHNA?ZkWDx4W-WNs|zB(Q8STlHPN233sBql1Fhc1by~A;2o&aTy2j>T~P_W{bARxoNL9#00FQw9pX+{maGkNLU0Y1BEAr(FMbf-f9E`p}NuS=}1U-su( z%qGO`q%UVg{!;zFhi&^bFc21j4}=*1_2`ZN{ZwIDFIyW& zA6Y9eoB#NtuGSDOz*LX$&fSi|ohOSekBz^G*-?3AbpFs$Hp3@3(k>g5$8j0QAvjNL z`sJuvW>#uLjEb}_!RPky2&uP)y6o((#(fMj(nQh&l=AZOtIt;JWyXd5*VW9Ed+W+4 zF28mMO^To7-sc7#3tvvm3{wS=NY#!s(frP^?Z>02FQR-zsJ3X?+sn620jsMxy|%Iw zPfAc0BiSS7J)otcN@)C~CXQDz&wb&L+rV>CE0i`d`}}dY>)?(6!4?{M!lp87zV<1l zd0=+DM9HQRYks2@clY?ObFog#ewN_Gx1E^@Cp+|1p&#iacefNBzYiq7xI)90)H~%R z-#_K4`zwao^O05mHaW(^=*$_pj^!$zu%~(3U%%6?KkG`IJZudnX?Ui{dS^3OPCE2%f41aWe6mQ9+NagOQvX9gw(AuVev=y~~Y>DHk7l4j=+ zcXG5KH3A+{&Ncx}b}nAUkE?TQb7YCEM!X#&CW6C`(mn;l2YB_q?VVk<;%)}mS*XnlZo0_z#BW1G|?)__J#zn9ibcW0Yv>C>Kj_y5=x<$qZ3Ow`~r8{7D*p!H+4% znDq8-`!e+}#f8V2xn&`#mJ|;}xG5vsoLy{ch>rD`{ZXA2M-+!;%VcGmCixUw|1fLn z=Q()b4}T^>ZuEX=qAybt=w=sCQhida;j3$0bWQhpmm+fprD5B2!==%t%+rmG(3J6W z$hL>w3P+Y!{L>Ma4Ic)CL!mSQ0#iO6Le`O53-5anIu>^v&XAIkK)`_Yn% zMaVCTkCRfGCsXuDKS%U`an;StWvoy-Q+&#tw8xif>CShEjaA1Yo-r2M`2fB2N|h-D zQ*R!BuJ25z-#VDho>}YEeY*Gw9lL4@DNlWSt9j+0Hiz;z%_D|1B4$qlW-Lda zWxpK#${p*ZS(tDVQlqNC2yoEA<&4RqnAv7v-!i;$lPqK0IW~+hv{X)@C8icH+q*3d zTt=%{i$k$X$u6aPTrD}RKHR&#S}#3x6A><=_Mu^!_;XJ91UVV{O;h8o>DordK-Je= zQa{s##8Z#gQj@xV?R{1k+TEy&p0pedJ2{Ka!)0xTy(WIQj}(vEFo;*U$NK5T4mYjh zqPRGS48_uX^QEN7^&i4dPZy(!;#!VR9UDYZbB8=&_z8-zxq5xE?L;}ITGHt-!cNy= zQ6UB{3)om{76ZdG!6?IJT)B}1@hg$$5@ANGHF}v+Jmj))keAnp*KB?{*)jtKn@)#rtT#+=$lplM^4)^Lg0IeX>^s2Nqf;lm@oLekjQugGLtn zvn7LxZ?0}U{p2UcNSy7ymSxb7Q&;~S<0QDZeczF>mrBU+xbKii7OvK_HiM}}nZ4Bd z>-gi~Q%A`Xy8^+oAFm(s!AsaQBie;M3ZAa*FLGrTYu^&#<(1_UefY=^nlZs zvPN<%w7Ze-#hzYE)msi%McwXxJwB!wQ~T-i>H#;b-TG{#tEz4zSO3W)likw(h1)RJ z?<6Zkx!QfyIk%YK-JE?}v0DP>g94EQljROe-+mK)luXY;WQDf;W2W=rAEp7}??oRn z!i=Rkzl1EN77F68xff2!BcNdX+{5h}l)}cVC39f?VuJZgtT+TEP~wX$N_&#SgcP_( zH^LW&yvf1(TS_bPzZJ=;1^HNRy?oe8F}TyxYq8&uS3|$@vK72GWu_M|pIPy}#xqOE z=5x$+Eebd32sURZ$Qr01M~FATn^XFZbYHBSj?RrR6M{GV$g$}QelZfvFrwy)F(s2i zA`*MNK;gR+?hNf}eR!Cpu%Q5g_tI0gzxYbx56TXInHn-$c91UFUdk>-{pzo;u*5&- zjk|p(v|+bvr>Q)}`_sGp>Vrb)9YI+4TMMp1PQIVS16POdl>>u`j<^QAGS9>s zG{?j1_wz*US;BMD?~gs>Niz!s3+`;B>gEJ(84yU`8a zI{gizH6~EB2}O;)QU7}5F+`ghkkTt^5!L#76BAF2(AT;K!8`=fTwLPiK}zpUDb|UO zNawH;x4q@fJ%-^RTRl&(P9z*D_`zR2L{!Nx8YPorU(<&QYo z6;m>%NV)AKixGQ;!h%b1#-BQG^w-|!V(w{wrZze{c9BncJ~_s)IAKRARp?FQ^~&Hh zVp@btkYB=GH&_O_GYM_ z94!4!gx13Ro>u*euDi5Cmx1lawreSKn{TfcDPH@>gL-Pl?66B$fsaH%^7e=U24z^m zR<;yZS>F(OWAuIXDPERYpIn_846Gwv4eE-}V&Po9Lb}7T#q0U~z;^1XKJ3wZ1u?q3 zO2)>tRIJ0uESO)6Pefz2@RnTTu^iFS?opfURP~F)Nl_&O55^a|!Mc9+Yi+8R-;s-% zLmilVsOJ=)4JA&(q875rCSH6i7Uk}to9gWRqMd2~Ay2kvhHWUZ$8A|h$&25gCbpot z<40*+zsq9E>t`dijFqYsy)tJ{RR(l)T@#);}Rn02J0j3#NMJ!b6T(U;@S}-#SE#tk(n-&I^s$S z3C5Jll17>4!tP*1Oy2Vw`F`Qiw-tC^zcHOUBieomzhkwP%0eXp1m*t@qB@)Pf)n_-f5#>geT$SL;+R^9&JMV^wANqfPs#lEs$J~2sF_w?$0 zI(euWf?9K}o-nr_+W0)abz|F5b*}J*>XQMCFj0u z9~n^8u7}p_u(^l%RX-0=lQ#i>O<%{A_Y(>ha4Ku&s%7lH5z6wlD8@NuMlz?HGFPB7 zFL@gJkfT%C_lU`Fn)oNj+n6;v?3)3^$5){rq%TWMj=dj?{CKkHql~w*Mbr*FWX{e-1cRbteZ0oVwW!;fwBwsc1VbpK51|`02D3 zl{RTye^jnAVJuS4mOxA$4cJxN`4pL@{2hB!Q#Tqjhr<%LRDkAbH5@iT_I{I{$i=YU zG74v_1OK_2XIZpe>4!w`Z^3&ZC&6cX6_*b%wkCu`Jb7Mnp?!%J zN6!^;CiHvr9fkSZCT}mMv8~_;YKzZW)7(YRwF`OcLx$f?E`@Fe9G7iph6`~fu?4u{ zWV;F3>l?UYnk3>pV;f)KrvI#UdeneVq}C(m+D>Tlk*OViL|ko$v-ncVv3vJVTJ8sH z<5<7RpXnKBSth(S8cP`Bl6yflMLWyV$JB)%da^>WU+y8dGcVcy%~4~2k2~z!mx5^5 z?$d9|>#fJ*#andJmUgRQ%*Dl6NYu$gdBmjUUv-0O9(^ZMB{>U$((XC~c+ji(PDPT25;v04!O@kv(yxCzOvZW&i5aBS|E zkGoN6Q>t}tNH#R$EplX6&t%m~E#_g9M=leUj^zA2^C`tS(ojG)_SvKCv%Q=T*_mhh zA>$GUBf*D`+at8h191r*`g7<^d{$Ah=0?LcC>++yA0-a?KgW`qO*XdKY$|^cd6R*$ z%VodG11D*Ng+5%^$VX782ntKvtS`VL~=^4MlZX;p>reniy z7wice1OnP!!{-l!%{|1XzH2IchT|X9$OxBUFnWhcyEsm&DuiDZ6DC%-xW5v&X z<#Ag3F_e&N+-7A$JDB?G!A%*v_Ot4XaozT|lnUY%MKd23B>n33l|zjD<4_V)zf!o+ z7X!78{0pir#M;1#M&+>VPz$b!E9QS5$K?DjkfHJTK^vV4o`hxRVw+Hf06CN#+QMk z3G9JD0!+s%+NLk5bzfMzrL}`&L(eF^wu30}B@1an2imUC60S&9cf06AV{%0m8*jK1 z5NvRs%hf#@|IX|aNcD(Ysa3m8W>?xlsrb`FN3O?;&#)Cg=8kw!Y>A-zrXX@t%8Hod zi0H2GT|G3SR16!wQ;%qJIos7sB<40%okEhPcL{pq)+!keUw=~_Z0OI9@?!k&a#G^& zc7!8L6r2qqcAfs2MwAc*JYmMUsn4EzF$AC9Ei`t$zBPI1)sT?;j+Rx3DkKc?Pi4IV z*Vxa8{d0Zy1-OB1VM)6)*Tm4zlPcx}PPxFh9Td?1+lQzBALlO1NdM=#%gq^&OlJ(J zK88u^he{3LAjwlO%{LH854>cJeDD@235lS#nN}fM##*-C*!gljNK^E%zP85rVD5K% zm-9(r&@XsvVApSjlg>5sy}#=xgHJJnLU+faG=GL|T&|p4ny=r_X<7&&J|GO>BK-X^ zXn$wQ@%Ai(Z}HLa?2HBBO%B3cJ_?FZ`eWhKM4v0hTh)obqL}MZ*aSC;*H>Ja5)p|y zTliOeloGEJXK-*ZJu=I4CPTErV`_ zS(H|v{#n6L(NJ?y%7M{TVNvNjjSrpxt^j@u4hN$Py$^0X+6w9lngI^{=^>4&d|UP@ zMjwBqJszB1EcUbPqVjioQ^oI3Of?tf7uCNru1dANt&ghD;F2PFx+)hSU=>}T$fdTZ z*_L%m(Z?QXf;L6Jst`c6<=1zP#!1tebV}D3i^fUYnR?38H;z_E)0uqA(pQ64N86cx zD$;j==1$Z3_LQM72hE+fGwoEMZw2jyrZeS~qpt()gtjx|RHE+&^D5ja`Z-E44sG+= z%#Ot#+9O$1g&>+ubfX}#kdST(q?v2W$_4y{$6RDbi&vL1Vf3>T~Z-e)=Pe zZQUhd7kO_U%7`DHA+?X0ZY4>6);mId(>^AaBew2lktMjeLXPn(%~is!hmF8yF1)Vp zllgN;SbH8(NVWMVEX9T8eKuFD%jNcO`W1smGKTGek#@LV3E+1_ombegf@%lXR$*Lw zx@wKRzc?%wslKBJA)0f1TJ0;=X-cudgr8TnpS$RUxmR%R{`UFJrEK&a`>H<{7Y{vl z8TV5{;lj+!G1{LwA2|l*)uTQ6Mxul!sWI8=V-$0PV+{9^J+zx`(dU0g@-Tj|ug2Be z3^?cPqP;FZGf3q8XyKr!bXpT-ZvOkF-b(wAfUgQ4`lwD65@d!ttuU@|`kvgMQ1oO{ zTAyB`NsVw&>=!x^F7&aQ*;0v&*9tf+oKHO{z*x)gZhK{o;qPDT-c`|K|MAB&9YemK zwGK8bo^aFtGA?Vz81fL4CB2OY2E;@O0ltc42K(O(g$|-dSMTHro~)4{Vn@oFTxg~A z-ITJfPGGm=;y4twGI}kReu(%>TUR$(ClK=@d^C%N=SeV{IbR>T$0Dl5%aZ+_8igyA z;2G3Mn>2mD3~z#7A-IPz?V?AHzxy(bqG=&`g8roQq5Ek%?>1KOB5F^B1^FrNlg`*g zvNP_0HB|Q2J#Fv&rJu?{_1X~)S8{c_jq>A;-c|2eoq7_&LMkVznhh4-4Nbh~9?mzZu;xtkerC==l`0j2S+IY>|7t-t zqiwyM!PPT`aHXXDV9D3K>o1ZjpQ2n_Yvnqw&Xz;Nz8>HCBVzb^ZTad$bS+vfzRGJs zC9HGX)$$=%6d-c$9{TJ9R$y&8aJ5z{Bs*-?Y?)v=QJ=+$3CNr z;n-=|<8-DHBelRW>K-CAZ5$$GT$I|bcq__OqviWKSLkTTX{^^d?Q11zo0(66&^wn! zEAf|Bqq9~9%fGioR*Qarc+xUO>8jG?x=6B|R`MJFU3;{UaJp&5#en$U?hf;~k*Gs0 zJ$A*uzr9P3(2JfpZviZrjsB<9eN6jZoM+D`pKko1>csIz;fze-&He5|-jIF%YO6=-3-)+MrZ_&Q*!@8w#U@V^QBF0S1r~VxfY`{AB7ewl(o zdje_Cb8J7SQZOCe=A^Dk>q2KDtOfyj7G-4xjiX3 zqW)KHZ*b#Flf%U`Z9W3b(;|1TpDe?yR2OSn{@g_x2G+Rc(GHK-rN`| zlV5vVoebWIu)N$!RTRDPzj7nw#50n&QhXkFU9MzAK>-Ab6W{N6-&h1#ECNy^a`ESTkyWqh|(28 ze(2pn>zmvGCUiL?=+eFqO;pogKfNXCTpjIq7u<=Fkx zf5`u^ytmbe0gdMcW_Q2ln1U_e@|aT7zt7k^o= zZFrX@i!f3aTD|JEtgX|x0EE!7tj^xwVJJEuB3Q=3M+>qL=JC#6DjiD^)h?nKenLEn zH^C2YDPHVPI4Ei4&&Srth&+B%nwOMH;$5AypNG#@?N|DVQ8vP}isvu-mF>WS<@anYAhsmD)%GN&-NOsuP zv6;)FXiR){Cy%Aeu9GH02NWbu+@R5cSdli56s z_$-h$L+Ps)_rO795Uq~bxpI*Xrv!#DB|W|!MP%ngE?S~U7wp^-X|-*dpS0u^QV2v! zT!YJje3_3g@Ho-65KexUDMpIWhlQDZJ zi_wz;p74}ZQy`vyZ(PV|NJkC-la6gJ-45am$vGb>xlJ(Hlx7C^=#@`CXX<-pR)Q?G zZ`PPi3Ng&XrqwU?vwAJdQK}Hf)bJ-7`IPXVO=__4DG_t6q`JaqKQdWjtyE51riOob z$D{cQ1L0iw3o=<8(X$B_bbc;0LmQqPV&^1gOSBck>X%00uTyHi(5Qx|#m_r&DTK$n z&N?Qs7v@X9LJ>whEEhZH!5n(*uq#AC7KguS^SM+S9&TrzLWDVlZaAr6!ast)X&omb3=^Vvf=Q`45!53oCq zW(%dlGxX*ixzxj__(nU;U(F!-aDSh-Y=0oR;PVQl0)27h<%PpDrox3(cPxizPiaOz zxJ*m=CI4}0!JRIYlcIiAk5YzsZDiYs!i$vKU*!J9vOK)DGj-4D8G|MH!j2fG9onMX z7*9c+^oMZt#i7?^x~OdF~-c9Pe z>wo_-uZ*L;ob7W*S1XtQ_%Uyp-ikNA9>rbD(zo?D^X5#%U&|RBRS9rkqLlLK>&U{I z2r3tj?39TGmNXjVgFpNKeMk`HnS1t{c$iserW!*dWY+&4!8iAeN8)-wDAfMa2hEj^ zChtf7hVY($_lf@$_I>ag){lM+1r|zysyUk+!(cvbx~K)soZXYq`BSEKy%OgaVi=z<#WI0V+TEZ zg+`+I-#zZZr-KWB3+}3DczBIR_7o}@HJM467n{8lOg{g5@uXxW?eT^Uhhw_YG(|^x z)lzJN5&wSHj-9amce~eo&KXZ0Tif=Jc06q_+En7Xc;>L5X-213ES0xyZ97@1?(9vZ z8DZ4uB%(-&lw3uMyoPK-%=v?_t}J2yQ;sjks8JE#J5hcef0Ae;x8%kbmwbWia6LZz z>pWzMXFnf{@Q*iaP}MoM_m7;tFeDql@oDgo?kKfot2Lff!-X4DDZfx0$aFt_S>9@a z$4yl38c;&Bg7gESUKTxjhopHw41pW2KZF_kg^bDJ!{hF>_(TGNlku@fg|V3z!50J@ z$)3&)AM`mgtp5*f?-Zn4n`{f$D%<8N+qP}nwr$(CZQHh2d6jLu)?Z)uK7a4n9lK*k zpMBnVF6PCIdGW@`d@@Il%nW$b;0LB4*-~*3SfFVvD#e!WbraBx6NkI^8HxNzQGpKl zIklot>zQwIF4FCzP`MnPz{RzC@_w)hBIsIF8e_jU9@S~wcw}CIwHM$ctmp9pz1eL52Crh>d(D*Pej`P=2eZu zOhgsKdQ%dRV=^DHPi#&sS#rc>w!%?H+65HL{EDnb#xhHs?+Q7HEjO_ZNE-V z-tNQ~4!FNQQSk5!K;(G!*2-`e7BA>l8$Mix?$++m+ttUA*fSo4tTI$F90ju;y@Hbz zyAR)$Oe#l}E-uS#jU@Beej_}#C$%^CxKd;M!iE)_{eW`{G%8N#K-!&#cl9j`kvY-u zD_RX!jM8Sp)UoDjSoTNx>8`CB)_FCWx7^(I6^r96WYMNSc#A%#E$*QWmg;TkZ@-2i z<$l8t(5=P94~BXLM_&0MbGqu9yvvSA3a3IXe@3%W^@{@J=cc+1V+tl-jvS9Q?7&>uJF2!KU%1!sYZBcU+1Cl(+Xl2h>QCD~79duFMU1)I_5b8gT{47m9 z?8=ybhtm9pm0cV?PjVCRh)~Fk{CE&C(!Y>%Jea)-?}D2ZJNQI&mjLAu$qdaLq+uRn zKN=kIT1{h86AR!QdR51c14i8jX@`ZTAx!uX!rnt*^d=t_32Ach>*1wR{u#86Gaszx>rBdFoyGgKJpm71dK|1w0>Us%QJW$Pez>0p&#`p*<`8dqz z+}?kfo>nkiVrGrpN8f*EIXgNL@MDE|Qj#bs1oGcFfz#)5!Sc?sb(_ay?%dj}SFt-rdI1Fi0BHG_${N}KD+c}_th|E0jj8c}@bL+g zHc0fyA-=LC*(T^>;M7Tyni8Q2QnZBlEM;NRL`7lXL>k76$&B@gsz`7dQVS014f_3` z;%dM|sA0@-!E7#q6vf&>c>!Z>}B-;*MxJ4`fp%S2RxRxf+*F(k&)d;3ET7o(JJ&421`u8Ex?d zHkYnkixW4#LoZK=mnTv_dNhl}Scq%VA!8|oiw5dQ7Ik)^Kt(4CaoOA{oq2VcnQDt) zMl>rm8LRA@zeA8Ogs7@Y6g8(kzXw3#vLrMi-Ia2kMbJrjbPGKW;>Q|inu=qVjQ=e3 z`MgmpeKlRoUHJXA;r=wmbtS_fMtI9-u^FuR(E7j+hX(J)1~faUZatHKl3z6K{z+pD zcfM*@H!kX z`C({eac(4aBu9kQ)_?wTDn7gPg89(>Zn9ssPR|>dauppPjVeYD?EVS-)i0Xvehs@z z%mo5=4c`h|?p)B~F6tm>pFwBtx1?6V7N=-}TAy;C5N33`*q}Pef*U)MIp2n!HkM&` z0cK_wZ?LgBm87DzkN-VTV`*J?exhyoC62S3YzAJ~KB3C(cpZpn2NH|#z>(~#m!mR! z1X}bHVojWDd4-=Qllku7I@#peKyfhv0RSMs*;hG9AYfzwaBy${6IVHjZzTTzKjH5u zTL)8GeLHoBS4CwEkcG}tknq9CYGLWZiqMLRq7y^(Y-s&I}rE|6ecb- z-zeJQUh2WgQ6?^2K9HO_yPtlqZVECv2@*Le)2hbz%xhlS zEZcF@tj70ITwZc4vlebLgROvNqxihAlV4$0IjPh004X~VtqN=KbxqhXDjD691t_;>z=r~ub4VrtO3Qbjir2yZQp=zj0)V%{daSXG}z-D<+w1PiNED+y*YfN~0e5xHedc z7es(JB}k+UHu3X_9W7+@h!?y?ymsnOHtBW#FqzbG3HM%;9Q4rs% zfSBkJS)~axOAeDb_Qnn?5y)`EO&v%0wyl)0-mmEpNrWXlrrq{ta$dp=ga_H2VNDta z?L8JT)4d61r%*=>L`kH(g6ZC*JvH;X=J5Tm*q3MdXMoa0^g(>|Z z0<#XIas#GIm?nzSvQhL=(CreGIYWcNFe%MGt2`Rg{n>J?n0NRD`)sN}MZ6m@^sKRw z1RZr0C9TNns(zq&w&HGa>4dSQRw%|HTJHs;Xk1=Br=cpi^4dDLrVk93C=xL|k;?2) zNUk7ng%x+JN8fCkDY~x?SelwzCy>#}0_#H3$iApUBB5NHWq$fPs`h%SXTT)Pn^jy9 z@PeY^JCM^Lb7f3U$j@lsCjCp(*&QM6OQ7qACo z;abpqdXm$dEE zvLtd2o&MI@MuuR?QCB;yoa@C~Z7OB_>P}X6t^|fV zYOP=h{|u;ua^&=+X>uIixU1gq#fI1X7`$ETwXW*@DD3R`LixE`BC(@AbI1+_aznBl zjYJ$w9F~QnM^D6&uyHV5y)UVp8Z7A&(5Nb=7ud#X%Icio-^EQ$v@o&S{+6+`n;)p`_O~G8%o1*(wHM+%;f@|T_2*)B4J~Zk}&GO?9#Hf3&!gl2p zZIckrJ%5I7=~JLmlRs(ES#--8wGuVN!fDCUh7zAGSFG69d?lxc^C-2px*a7{rio_U zj$tsB5zl-;k!4BnG>BK7AoJvaH`;C>3a0rk$;N>AjQ52qlf;X#DZJUEisx@Zapq14 z!XnKhn4I2!F#i$I@mOXQQLuH6kT&>frahWaj7(((4jLIba zzA-ic@R5+_E9})P!t5hh)GG|+GfMQrJ-LQghwFQg{gt@?Zc#FPT&D=)&^S0?a@Z+H zcrMcJCgE{Wa%AbYsJc;127JvvRk*ma@XCNdr7H8RDHCZiF`3yU`@obFbgs@+@5mcz z3~iIH6~Cxhc8W3DQf~f$Y{A~!pHNk3R8EX?bY|Qlgfl8ho%~}hUPPBuIC8M`2IC4P zn7pZulmsI}nsI4H?Z@?EW-t7!?&;)q9kA~x$_v;t@6H$R>2hx!3f@3p@2j^vtn04f zCN=OC3QZ{sx|ayz8F?IBAF|~;vTDHkwX&8vxz3M2>{R%I{SkYJ;|Vl8O2KA+7E~Do zS>pf~rWAE7?j-eN6A-?uj=(*Tv$u8EVNy3~v6`cU_%lWbQ03%czq^oh-h)iC=d2KV z2^Dak@I>ga7hn@h;h1>umOLZ${daB?L?IK@=w1Oo-8#RLDNzdw}s6?cwc4-qO z=Vczwg@A03rB{hk_D$^B_x2zaS`eSZes!hV^a?Kd=rr&r>%5N-EFTZSR2SEEIoF(^3|f%sWGxiFDwM%u7{3}(b}}eY z4@13&>J+9~&%Zf>2tUd)ADcZeR%kkv|BoY!%gxc`$aF|?oJ&>cDit4?dcmNvjSeGA zAQ56v@vP!T(IvX;jFTE@c;gY%SsGYFQ9`$iRtO%xl}3AIGWV>PzZyAgKviq-i_`2J zr|A)P-D9(S?oB>2NdRk48|!GSBF(3br@)|J=c}QC{!aj@(XdTyL)PeeVbu}+tPDoh z`Z0nYCml^^oDOGQVvL(N`4xjsv*@np+$SEWw`#EMv6L=au2&%+Z)^8|OX3DHY>Ya;d&FMQ{vIuVKZ1XY zs{Tu~O#eTQmcN5(LrWubQ*$TU|Bc}LKYdPIQCvpwudfUJ_4U7Jg2l?)ihomPHAo6{ ze9*zeOTuHu9i%ih__g|?3*Y)Zuttl|2mE0SWInU>}mYw;yPV@Ki@}le`txY2gwitwIK{JnF!qAk5e-T zWv0RW9Oic9FM4&%p@rh#+?ySS2OPVpEB=|%Zb}@s{L|(>$nw!_l%tge@P$e!ll`h4 zsZTrPs9`rFquHR%c(FcpnHiB0rU(0)shQdWs0CagE$rL)!pdmfeP@B$=sOZ^)@st>~a0 zEW`MSY1ZDbM)6i^gKYGqxhI?Pz64Fu&M_jh5Lz1Q9>ZBYTh>%H@$3QG_`$ji+S#zg z+5-vt%j^$iV3M5!C`c)pYKOum(SyESkx=C0s53|m;xma`A9nUd+)CDNEJfPy|YI~HWU^t9_~@kPV&GB9#=KmiBdZzyce zb-|N|E;QB4WB=YYspJQ0cG${dhvJMr{8N2GADu=|j0j&_9=KS~6<-ng#tN^exgY1{ zaDb-BX@wOX>p+vd706vELd>)59d+It_?O!OO~CFOP7uKY>`V|!0~uRWV2C!;*WU3h z_6N9RAeX>z!NoA_csxWtn=9|A$kBVINUnu$oGuhtN6jOZN%t!T#tm&&R$|EL+=Wg7_BvOgXwi5H}sFS2(h;iJjAG~;~S8#et*9<}Q6hMjy zco@R36QLv!W7O9soFuI}H+qFA{Ye99PO#KQMiVw}_!ch|6XV^qNcP(&2KKddE<-m* zH?ipTILuDC-Y}v=XqNIo96Unt?~P{w%A59S-yDSXw?F;wUEyD(#Q%(k_)o5o|62^^ zY;9od@L&C5wZf#$A|En05~qtLu{9a;TiziIM5IO@AYxPUdJ&wUmW6!-JnZ^v1T>C|gH9-y}H0uUfHk^J3) za7onRNs4xZJqkg5#QfR75^zG@Cp=CRP?ubM-IPzVqtCYSKp`XD#|KuQAGswM~MNDaFu!wYztpu7NxhNomk-DsKL1<-H2xZf*pY7ahLj z@Cv7K08*?ZxJZx9N5YWkeM!YHg*RTNBVEYe#pvMF-(caC95IRn$%Qtlp@Rg4o6tjz zZkh{M@p95dbLdiv*5fcCHC5W_K{cy4$(!ZAR@!beaBi?5T9f+F`_RdMc7+jg#_&VA z2G{E$@FZv<5>C)?ww&h4ne78{llW_;2ce~+{AfZNpsA!PwS!EP!kYrgA)I97Tp~Tt zh3`H3IRHIVVY7=C3&5$6P9bFwCSca-!WWU9v-+3f1_&pphU=flrZC>2S|8WMyWgK^ zOK=b$$c#0xo#4`uGf3>Igd2kx$T=j%3e%~Mz)y|Lze-O!lPYb$2%CN(JO~;^%c@8+ zo>6Ppwl;t?`h-Q@4fuSocfN&Ho++M~`SXoHFz~5G;+Vgfv0R{kg-FSN2a(dYM$T5w zj!MQh{{%@DO-IFV@wAJhLqbl@Z$NSZO>&E3X-N61a!3$~31T%e1+tdrGjj(qIBAEy zaR{{QfM=|pJ+{J=Kw7RoaC1=;JFi=Qrw@qVBWOAwK(PB7oS{uk$rw1gPdb*@&ApG8 zwzbX)*S0?1FnuIh%X9wtFz0o$gFetJ37&qTq;70w`oN)XY*qTmqHI^eurbXS4sB3wT&0ORMM08+vRNRU#wIe~ zCELjt*^Q)(&545shvh>M!Chf+7-O*NtKw&e zM6^aHOj%qPhm(>Hur)d)8=~7pEKG9cZ_wYhIn!O)v zaUYoqxAGK|=Td18ft#{P6;1q?ON!r+a zTpnDjOpl!tvZA=f?#5Z2y24ul-84rz-B|seox0!>THFofyPxml;eatcI8c+kcnN*P zFrS^M$lrY=n8@qyeaSWaasHr~;)g8|Z`6ugh?6$d{}`p0u|F)j7%1N@OimGVakOQn zR>>-8FyYykQEYd%|52gk2ZT$b{21|y6#n|X=CqCH2y?Kv9y`^IUM`xl22Jx7^Sq0xRY!X$(^s zQsa9~^|)|=tyYtex3s88l@`9`6{`c00F*Cws^xM^&8;s<4A?1}5zglXnOdNy9WC$` zVJ&DjxP55?&YnrKqteWeh|_*hOxA?fY?)tk*ik~>J?deScTQ0v(lxmyFN|(}RVfnK z#+$%mk+;D@o@0U=l4d=S8XFE~rVy8e;lJd=H3LRa@2lh6x^Zpd3s5pN38mMmEC}XL zn%Q4!_`;jC{dpIBK+e1>P+!bHkSTZsk!A>^X2r8;jn>6LN-|oSGg_7Obt3L58VeOe2p#&m@lOc~?7@MN;Y?B0XpY^SGcq8aA4NGpEci zsfaj|35i%@Pzq3vlM!-7rq~WlaFxa-?Qo3W1KqyGGkuBQomTg$zCP$fy%jTguSQrW zSmP~EvJA+RTli54Hz?zO3D9~M8R0;_u@?OF=a=oUCFkLD!U5&tu0!yRl@I8y!^y}y)HK@ zzl${_rAJ=q80NjYwapXVCVs6Qrnn%Ply#dP^1w3QRi0EEfPI^$o46TI`}CV zwYd3dX`EbxaMjRgd0A?ZL^T18wd3jdni|%iiMD%paPKfVBA5?As>H|7A-6^g`SJM4 zDYuWA{gtQL?QLHGx9Ba7idCoGbSO=p7Visq6$bMpG0+7giBdFDZoq6r)J~4+DzQsG zqV}raT`wqGT(;VX7T3xZ7YO~9uAo5@s}Z2QoR!`<^eS{&E5?lm zqZEYL&&}b2_QVDC(1hISH|o31VoPFb)&hl&lWkN7mnZjP!xJIes!v+4yOuK zOdFrFdm2IEV*58!n8_odGs&#u2By2Y(gJj*2emV=t0%NGR{iB71hcEIjx_;tyo>GO z2lWoAo*bk5l&mX#giKm$&iUdepRwmizpkXVT`Y z-3QazR0GLRH1XB<)Q+Jq=#B6uwU|u^s&?#u97-nn5vp)lQ?sQR?DFIfGV=4AO)C-i zD_goLV9(gfH^{7JjjqAL>d5SFg?1n2yMkERl5_^Y5>F{pS2bq*$xr+J@;7|wFGxU? z{Qv-X`;H3!dwhueI}w4PvZA=$KS1(-@^x*;4IyN1EXfwCgH`DYmkc;Lb9@)`!j`!Q zLOiB;MbU6WuqaLqUXj*Uo8KUeEe^(y?U&+wjnktfF<23)C zi=3_Q=Zp5^nnT_%uO}?O^VKB!2rLE@JH|jwjLj7MotPkXp4nS{oq>QLS>nyZN?{Cg zDr0%Se#S`*s>!CdLDwr|IeoH+thwecYtoB$|6b!1j8zK38SoDsqu2SC!$%zYPIPT5 zcjoZjr21t#R+s2xV?*m!E0rnfkXH-%7UxRKH5}2_z)$aqWju|XjfR4sOM`iM?LCW& zr>j154jVQ_SlB7-S;k|wOISxG>a~|X^;Rk>VfJO_3`NIU+tH}#3d0L5fqKByp#hac z%IDYD?7Jn+$MZ8{%ys2}k!N|%4dg;Nt)q1hyhXQwe@bMd02gD$alaVVQE z#vsP21M&CSp9`b?t_+ZH6Tgq6a35dP%NPjTThni zB|;jrG@hw?t62-?9ycVtS1j4_doQ)m!cIqvGHw@2O9CiAPPQZE50-H*cV0albC zABZe;?6U?kc7LL+iV@ztYA%>$xn083@&&P3ZEt{2gdn~Ujvi&wrXWl~OAaX&yqL@Z z3J(D>tTYauJU`dybi`=EuG{|20M6P~M z@c<7`lTAv$Z)I#i0N1nDOevPRq8<{pFcouI$S_5!7u9k~F$LE$>EzErk*mOz{S`O} z!{ZWCR9No>CwYAjA^0OH`q7qAt&?KuE61f5w&cgbH-!fV?w3+jUH6?aN@k^RQllo=h*%gC8~ z-kdMM9n1`h5xUAfL9e2neWsequ>C}6r%m($HXfADh5&XHjHwcO+6(FWO~grSdlURX z;mxtUfQo<&3E0K~OY#1O02B}sL7FC@&`xPiaGY&VGZle5Rg5n-!J15F=(4$lN8(!NAFi<#T36B5BLx@99VrH_<*S(z zoT^*tRQT>I%_OAKsgrgvk^*W{BQ-boYJo9`ZVZFg4w~4oCx`r=X*|clL!AvXA^-j6 zNk!jKvL52)Gt=%#76KdYj!{nTYKu#($t$5H1cfR#eZ><)bWX}&XwawZlb6aO)-PLq z4XN1tj1CI!;%t^~P_~q9g}XFo(94caHM9x(N1; zHzXt&Br>IStInG#ICN2&IndduM$Q|SqMEO-T_MVwXp=xNxx0=q#ORQikiVF?kfT~> z*5qN_`4itIS3jq%HzLp{j>}+Cgb_J<=Hs^0?l0{f9ZRA30xu_w4)rqs%$Z`oAYVIK z#e(jh`C@kH=$rTG(5C%);=p;OO^QOD!TufmM|m&(wBKRV$2?{oa0@aJ8I731ja)B; zrip&&q$QINuyzkc3y=_MK&Oyf8t;-ed@YfM);eHj&Xw<+^T8<2*eFpIw%?`rytAo< z=mqx^;PM54X5YI(YKk!%ai&uUm9SIi1IFSOpdK%dTfj?O7MtL;62KuHFMdm~;)O8@ z-6tWAB;N@R@i;b4oj0fg4u=m(6gG~#52T;}z@FR;5wcntI$wmHcK)6LLOmZdjcoCm zDkugo@)QE4laef92hKw$i6H)ZOz|ZpVm2;{H=bd+=WZ80Cf`c8 z-EU7;rhMb)5iL35C>=}rZ&c-W;rU)nIn}dDN|-W9f*b;SbE#)6M{Qg%lBc*0Q42V< z=Xjm~nPANC@qRT{!C~J1Onz+&Ntq(RQ5FR2ZkMuu**$Krb6)Vb-OGagKd^hnf3|xC zO~pky_%GP*P(DI2WT@Xa3o66``!7Ft#3JCS!WP&2Nsr=2SP&6OxP^UTdHuk!@i+<@ zzfC=9KZi*%(iYl%Rr6`X)^+yl>wX{2Pnb(FPMAEhVJWuAEvp|1gna5)3>|~Zc#cEn z#G!UK2#58CR}BTUWt`3g)JN1#m#J;VS>ePt>aJSD+H-bOjdA-*xyre6rcMiHAf-RH zZOa9klZ}h0%zlcybzB%8Q-2Pn=GqDR%^HtsD}@qTF$2ZC$4HE}y@yf-9dTG85Z@eB zIuu`*c+Tb7ZX4p(%*Xqttecn^f?vVzH8rW zyd-q;MlG&^w8^u&Cwj|8j-b{PcW?yH-WrUA*e;$V*@AX0Sq`!_=kmJ^k>#q! zg1FY8^F$o+Z+w29PfD})bdz@{IRYGh6+*Z6T*Sd*W@(%!Nz^gS@G6W3#I$H|ben`C z*GTiTB4d@FJaSSo*{G~!C~l$|vZSz+5pke%p-%onTahLYJchjK(I!^{*2f3;qpa0cmz>G!qj~v79f_c0o=bSr=?_;|RXke2s=gF&>!_-8(I0Qn)E&~K zm6GbBr(cgGvG4-G>ubG1V46{9sqePxV!xlxO1JGvcl7yqy~F9lK~@T~CkKT{C2T85 z=%&cBM9?x7lYt&RP}#5}DdAq9r+~If#FuXoMM{m`WNGCRe0{xDy?V{O)tsokR65^s zaPIyn(wt{$LLCguxO|B8ntJq?U%K3llZbrZWboW<&Mq+YtYK#$5$^c)>|wI)6lwf} z67aWa+LjGdbIPwW*W4OQEM)^|?nU$g%A+wSRg5C9{OO;mmpT07%zG7{gW7}Ux7v{e zH`m*S%vb8j(v7%zeCA%1=zWSIwz9__0brzcdA)-!!u7LSPe1;fw z+BR64qd5u&LU+xX=b5x?uB~tF^XNJXH2eK57N4-U+^iyAHtl~*(!TP<5{7$WGo~54 zz2qW6)GXQ$#p}5_8PrgB9;^R8z{9ELs6|-L($OKO&n2{cf3Lfm`loKc9 ze6L1Cr05(`WR(9?^qD@$hj4TivzwL%8$;oVoKY9w85SRpPrj!dN8H@WsNLQ#4m}eG zGK+<-Qv zfh|}8)xE3gCSt?^6;{TyjVDnU!}RcFnQBH~Sf4pkp2|Ec^*RH(cg0P*kYEuipq*?G z51A%>kXZdge%EiHW8fUpAEXz{r68{!)ulte(!Gbtw%=oIAjY6_EjrMo3zf+u|6SpI z8>zjR)~(LcdUvz@ZeVZE<912lHu>>&LBV`^VE$00R0n*W-YcL)TQo^w--x0{dNz z&@>s3$Ygn-C2E#IC8~y-Q~KBJ0}E|v_VSKHAgAGEH3bq>8t%$z36ialHWbt!UTun| zdB|F=_FR`GZKR~&kEOfi9S=D(;Aszi;wz!)x7|QAGLk@=FJyaE8>K;)sdc(6MdtRH zPda4E7DTXR%hJG>@uX_O(=^}a6>tNCoZm6qE%&6N3^GRxfw9K3(e9?O{Q)B8l;cU`snv9C$KNj=shY~6}N^7 z?3qlv#HKY-%-LI4E1|4Xf8!@EoxECIM;=Jmr3swY7|JR8bK#GWk%80cq{T1%Qk>@< zrIF3f8=lOZ`ti#X>$32**nHk1{QBiz-fdtKazs)LQ-ut<0&q2tIW!Mpem#T!x<%`uvfZ`L=??A1 zq@SUW?_TYrC%Iav`|8tP()zciu9n35?Nb0d5pzgrXOv3JuQ zY_6)Mw^ncLF!LU^!Ko;x-@aBo1`HhQ-{d|hpSt2)-8bd!pQUKY{j_Z{*f@;XPok{R ztZ~z6FHmYPaBko8 zR9Z+0Wm{4SIy<0?bXU|48{-cmZQZ5E=3VlF7joHccoc2mi*z^OOn`)1+Pk+97ZD}> z6bKqZHbJGcpL+6hz&BFMAXa9k7k3jlQSWcNPE()sp~?@S;v_hQAvlHaT9-^&@l53g zh;tZW`>>oNc*ygop^ev)@^BI_pE2|cWle}W>v>nt35$a%^`SV03mb7vQo6Ff=+vi{ z@BK0MU?5Wujfm?<*Ft-quj-)|ST{NKht z{9v}i2&R1JQXI@EaV#B}&R*`~%qJcu{hb_}4BlZQ1 zGmL152e6Quo;F?fM25yhl=*m;&9QkXpSsE{x&}juX@dv{GdisNbJ4!*bE>RnQ@LMX ziP`AdZp_#z5)OCZd`*v?9osJijEjWQb2pC7wSG$(ClFbf(1FoGAVBMQCljVTX^UHW zZg^Q)shfp96l!xKCdOxHBagKv=vr^4_KGoTNt| z#S`6kKP5IHH=mz7L9l>Fx~ zRG|Ej?K(k@%$OBk32Ut~QmWjq{rwEJZ`7L=##@$ZH`K@9vTC+(4$H5iY zNpa%JL_sN1xoY9?LVWF#Rp-=0!}cMJWk-ui`RKvhdcKvKI#j8Yw^B;1Vv7bCIRzK8 zQGe|T^0{9$V@0OdalCEUT#AHX9sN|$uRBYl!OpT!B+WV;7hKr%}J~mAQy`tThqLSMeaXXRtVWH?x$g${kH*f7a9OY1z)^px^^DR72JM0 zXJnx5TGXnT<~#H_~XfgZU|O0ZeACf@Cu;U zb#02m!4(AYu--U@(PIzOkJ)Ou_B)b0&+#luXz@$1ocXUR*S;V%Q*^K;M;ID}SGu5V zY3pDYzqzFY50=Rkmx(p(c$F6e&4@Cr>nV|X@fqYy7QSo;t;Q=xbT+LqL% z*3is%SQ0-+gupOjjKTk6bU+X%qLVKY>WvgKffNc+(@V&TUVkj2#vqXkRNPdilCZY( zNR|7cnFDn}*yRs9fAeu}Nz$1h1{yyBW3+G!VJj6;OK*C}yt3!QB~E3{bFE zb977BSJt`c)3@td_f5scncpUAy)wSQv3<_i?%r}vp5YoETfAku$yp@7Q4}2{EgW^x zrvv8voKIMHP{MSyv-g?2;k>rUPO9jAg|(U4DB&>0Hn2H`lI-Et4eClH2GtTq>6O>C z&+c{)#BokU=OsDPY>V7@fpooLe#YI&0qM@h>CV+7Rv~@&!Ym~p7n(vvqSq7?LQ!-W zp_s02S{l7-)_h?V^fpf}8^GKm$&e77fO^rHn}AeDQ|#H?a8^MABA%6(B(voe-a@MM zG=`U{EPS@duIuo*`CBICcC_nx|6M;t{+BI||MMY(|A_$juQyC_T)m6{KfLhu&xQy{ zmal;M5os%OVG1NjM95D2RW8)jR-71+eE*fEgsy=5Z-Ea_gL0OJLuc+(YL4AUqE)R(D$^F z8dpi|k?@>mZ;Ve594{zyb0?Vekrj>I2OFGJ_B^WfI;n+b=+}@pE-Y8n$lHa-*SG`h zI(6AU)!5}Ny#R0iwBh>C@t4b_+J)4dIVu-FFVVNj70Xf~o&5Rn*Cow%NJTpLoo4EM zml*&1OIq~bNksoD9njPL)1RpLcm3O9mv$?JKj=DB*90MiT&u9yPe?>(K=cJja$*WV zd1;))G!B;oDahPKxRZh~VWK#_LBM`q{3|vU@Ga%7&6TP4({^_g03Jx8A2`kgAW zg@%r;=B-xwrwmnNH#~w~%P!Wparg>U%;*IjD^2JN%z)MpoSZ4WEUsU1SFo>I znmTT*TZJhSD@%}Uq{=OVgh44OAlYOIT9mZ(P0=-m=qgD7%CM)jG2&k z3YtcF6=bDj`*}msAc(Mt`b99AZ9E^$DqaF{SGIwAkH+$uK(+!LUzKi%# z!_5j-MVW}>LKSccBk?oI$_H_I(^ZVk;2I;QQwlxjA2DjahnXe?I{5U^^#vV70BbEC z_^&XXVMT1m*dK{xv1|1W`!TZaO$BGA2FO@prUKzZLm8d62QjdWPoAH8iQt2*jp?)V z@;%&u`-Ymhn4fO>@v;U*y)5od;j3CiQHEO{UR{+@9n*n( z()xh<%NQ&$tD4ikS(%4_NhbbVwRT~C8G6QlvIT_=86s*RO=fgN4ejYMBl*ck!!I09?)D+AQQQfa@QqRvZ$3?@q zI>h5HDag_69&iz1k@izh+X87}&(Q!Qg5b44^NMPYud(>%;=R7xoN=MEsrYC~+u@qA ze7{O|DZPZ<+dm#+VVG#2AD_s2GCCM6AX27 zQZ5KNvd~31RPlV<<`XuGaD`?%lxpvKxeNJ756xtN&tVTdCg6v#>vWNc$j(!{OJM`V z5`lX|rbejI*~Of1169BOxCNO90xv6;Xo77KmH?xOV@u8h=1WD$AT5}U^bz1^Q)ROg zX~>dB>gGE?65kiB3(TH9JAIs?Ozkr4`TJQU&Vv!+-2@nirX1SVWtwH`t+U4%YWuso!p`ba9| z@UdG03Wjlr+2jM&mJVxo${~lPMvVWK$;o7g%;XA=uXgK($<6!pwvLvE%O_Y!zrm3W zwW6BN7*#dOJ*7rVOAdL}A-M#UTqPRDOwxV3LVk+&m?@eiyS0v{aT;}-4q>(JxyYgv z*3~amV_Dt>>&lw#uUR>R&>DeC62%(=W`NvG_n;1&-0$s>a%C-h9Srre#SE<@>86`1J-KP!OhH8 z6_)dw?|Ci-Nx#iDI&4w5JT`0;fA<^h=6{LFZgeb)rFzdgU@l^jTWBx{rPe2o8Z}`L z+N@0f(svPX3A`%2I3F>Q-@an1J;1{{YLQhHDSqquZb@HcJ>P2pPbn%f?^3FrU+RvL zZcLB35zG&ed>@vQU0gcJ0 zpBatV0jio%i`2t$C6KfC$A3meK9QNUyJE9)w4SWV#HAI#z*@qNS31;^gDP3P$vmsV z?AKO$X+Ypd(X~JJL@1)8*gpricnPVy7Qy9{BZj6y5_=}=2bbn3P)MwJ=X)&cD3>Yg zsbtvn()<#-!Tn82&|{wiyAtCdEMf6MEEF3kq-yoO!clWqR&@I}OE$+~^2!a9^T5)N zbh3;*$UlzQPg{WzK;wxq2ME5}{AaHh`OKbT179Jhi<%{|N%Qy(NmC_EQVVEQGI-b! z$Mj*2dTyajxLuNO@QB*pX;i?pNvUmJA2<#_pV)M)vEJ9 zJT;#09COU^ado3>j2TmnhK|%J7k>v;5H9YDDa!9C_^Fy8YuZNVli7zJt9l8Hw4`Ra z35UXdm0#!`{xqW%DHjf}C=XR5bQHKmz(k3nDVjU&(QHi&Q3Mardrd7NAl4_R7Rpy` z`-T1HxF7=5j0lk2NoAw^2z3HJS%Md1mWMc>Nm4me6ZnOk6>H^E(4l~f)f9vpGl)q? z%Ifh9mhKYEIG-T_ggZD2rN0xJe9H-qmrqzj2ishAEanwLFWBqADqP1eT*oE~WoOP8 z(>^})Kuyg!ScN=8FQOYX03_)1hFE3ReFf2q2ct2yM_|dj{^5owx+9b!CrYDHsZfJn zAc&qQjh2HkR<05gRXO7Z%~ijEs;2l3gk#+ovG}jTC*KAbRgJ&D(vyF?o|gK*d0YN> znEhY1toDB;*|GjcJkF#SQq$+qh^b3RGZICLp&nJDgT3)m{>oZTLX-+Fo-YajjJcwhDs zHVi>mBRvNr4~(EDovC7>yReQ=$?+q8aG^+ilRSFQ+~j7EWSl$}LrO8m%1n-{Bqfxf zM1U|J|17bC5tf_WM%YiiP>fI>l0zcLkB@JPXXT**)mN`J!5xOKR%y;#0BlAEt&+|q zxyz`pP_?5(u=YRCCw@@2p8_1?Q2x zOm1%FU^Q1qz)=;i6O+VGF@SsB?`o`QU*v#~i{(iZ8KJ^G2BtCRWnp*Bd?tk(SD?Jd6~$$jKkoALQe= zNKM0{p;8~wBN78l>C8KMyH1NVU^Zc}l*dI!qla0E6e8)%+sfPfU@-ZJO&l?HETYv~ z<+(la@?q7ihFLpO*)254S~RA&9*@t!M`JnRuTUi~aLXDr+`$vsSL!iP!ru$k9ZrPR zv=;8-l-V+aiE9w;^W4XcWXi)f)%>zpN~+3mW&x9>nKonL_Kr9l&C?kMdaSYZ`w&c| zfLODKEIW~Up;cFSgR|R38evWCCw-A#$pyZ^Bzv%Pn`%~zF?{638KIdX=MKI=<%=?e z=&#Z@&}ph5B(tdgq8wM;?zB?RM8G6zi_|3XLa&FW^H++;XYb6+7%Fz9XmZUah}(7V zBF^Eg{J1@Ia;eSj60haxF`mY<$Hv9JkgZIz$AQDibT6znwC4qd-2IeB-uT0qtf>5&dleQ$DI3dq-QyX zpJ0rxtzUvhf0dR0d*;xdC}_7`hUs?=5u)+yWJLeS3CRKHNZabh@JpQ;59irYf!rSG zr1+hnYgc!HVGrbYJHm*OYaJ*>BYaE#ZR?VG#EK-~gx!#joz?181vipZAjpp0qF#;; zo{9y@c5pa$Fo?Uf!Dp;O=|<0IC)Cr*UT;WHAjekyG60^kPH3f0_+N=*Ro925zFM7IHeQkwNl0o!sOf*$qI`R1dv``UD-Z0_UV{b3 z>@-T*p+1qr;{V{u51qS3Q{;=Y^wJdh4EkjM14ciF?}@~PXWt3^QSH`iD3YN=cGpDj zDF5^exoZZO;EI6dTRifU^N>@>ZO&oG{E*zFydN06AN0uLK@!P1ar`^XPY6R_DBY#V z??33P0THSt+=$Mj4~~zBHq7!OA86WZF4{A!j;1g{uK>|4E5dPnV9w!YYw2a> z{#O@GqJxNRwNWHDR^Gi)DAtyLT&q9ewk6}Gm5xxsPb@I1&dJ*ac4Pmh`K@KiV&;z<0a(gxPe3ZZ#JTu`jepy}k3 zpc|n`J0!5Y$YUHsQ793*ahj;!gEpGYmMC>C5{f83tb_kv^&S@J+I*B;pGY3}3yO-R*+=SWYTN*QSk=EjqirDSRz zgrKyhQqkTIlhH_bWekwhQ8(7?wZwx=RSo0AU)w$h3F}tY1sLe+m>a2w_e7sR2Rnsy zG>Br8qDh;p1XRc^xr7qicK}em6lonqSsqsMBkh%&!WQXjA@h&eEU{EJ23l}PocP1f z*;j1S#dI@uo6I_DF~q6xFEjW!;pik^OFNsWJ%2~|xR|UiSVQRACRE3mhph10a%(Wn zCQjxdX!F7O(>|liZr0|~bH3tNPW6Zef8|m`K8Qm7E$qEfX(+LlwcC^5{-(qtw z!u;)jxsa_Qg1b4%llaCEe^dp=2R(Fs#8sb@b94ttn;-npKLrMN1-%X7=sSs{I$lJd zwpi{s^6aE}cmmJ{T-qcl$$R_3G8E-g27sbF>*<{B!8`<1w{v|E1lZ451xV_YK7ZMf za0z$ewEkCZAei!sGM}a5jU7`ol!IQ=eNf?8Wrij2@J@R3H`I-fy)?6l+!QwU_fc#= zPSo_TDp*~r?0q{^#brBEyQ3dj@FP#EOwq%G4_wm*edd~h?{8H~=v65!wXysrZC)e# zQ6x|-?l^G6Kj9QA5u#;2a>${+n)2W_2h|u36>yWo6lP;EpAqTOcCv1u{w%>J#?e01 zz%QVt^_h3Y5;Nfh6Lg7~{uz2zH&fG{<14PhjawpSTfmjl_m4X~2ew6XeFRGlP@xymcmH$j7~N;xyBPG;!&}< z9nt*|S)x|rN#_whk!bHnl3_4!SFjvxoD3J8XJoEeq3^8X4byd3G1CrjcnEJ9O=-`0 z&CahoZBBE`kF}vS1rtE_O!kAVy^T58v|ooKaXrc8N=PazQHmjanR(zIb}|b_n1SU>X02yD(W`nPRUOj z4WJgQT*@_2#B!dDKslm*4weF#ENhT?du>*X*{I+DsEC<;pX z+~-)z&bmQjXv5YOzJhHsjaj@0-&MKi4QGor8XA6|X*J-wlM;^IRk~+?3TH{Mm*gT? zV3N6-b7mGr0C3=9XoVb@w50AFGPJIkxgTNr5==eoJ)>!7xVKXp9E(iyDJ03i8E_B3 zGApa?qi%Ar85M%e?<3}e2p=?g;<}_(1a2oly*h^~<^C@i@0kr9I~S058&bg1l)yl4|5iO)qweQy3#qGRgoniEDPU}NzP=&GPlDtG znp?^>)lZnp5?`6Z*^;YuDz32yl{nOj~Re+@K$LA3spc7nJudhVRzrf@Dt7m8z11NtnN#=vp z=?|%#eb9PMGQ@#G81Vj0AJ>3QpQO2WVel)?XYG1v^z)&VZx5L=l8ZDFHFJOsIim7> zS_#o@QdW4BkPEM5hhxe|{xY)yt|QiQ-v3g-rw8;vethSz#9D|<3?j2LbL!(dHlGAd9ph*Y z1s!SZOy@KaPS@k#Wa}@newA6^@F%mDUgvuS#aR!5{$ssGaq{rMcJfgEhtVqVJmK=} zAR>REWapypu-Q2V?6J}Ec)R`H-}9=Q_2=j1n_wVhAHtM3(nzS)odL&pMja;V15^hz zek#C)I6sYv&qSP}&kdIVc_^jWeTkNn1l!`k?;0$A@@&PJV{5=$Y>@9r% z|8xp9E0njRXBBsDZ#>s|5GB;_!qPpV+oyHQ( zJIRA?pnpZrdA--YBICPHIk+T?hggW9vrL`}DK~pT9NDBef5D~8fjabK1O#L}f%Cxz z3ZG>BAF}=N!A4=up1~|NzO=~p+iY-gFA+%y(+HE%DidFIJ@e|6r z!**hMYOIvaQe{lc!u6!8HVTBAlVK($S{12}T^iAm?q^jUvI8B%Ld73o#q+_RZgx!M z#?1yela7wnS@pT(I#??gbQCI`@X|AAcd9y#Q+@Ev7uvOWoCCS@WNzT1t!=pFL=^fV zKR?oO#$^@0in3ic!6{ukAnYA@o%ioryMJ>>!oi69^eY^=%2;oZ4 zWL`=POe9TYnhaQ&$TyL@8fiq}f>}-5wym(U*9=KoWu0^h7TxY$q&TZiwUuerUCgoT ze>zp2SA+i{!N=k)HJ{MugOi0H?^>VGs#03^!XBSGGvKd|VOuEvK?~Q|=%7~Elb`lSm&yeCENS->^2gwTqK86(mF*?pAFI>Y($(!ISDv9;r}L~mm9Zta&B8VF z6)h;hoIlI9(hWrqt>0UIh`|t9Y#cZ*uSdbz#VMRR^?I3n$8curknMbcVLu}HrSK3M z-hlD<(IgEgIW|f0;{DJNVMQ8Hrqxj>f%r0<{({k1at+km7JgjF{TwWANowgOpIV{ZDS&56up61 z7~eCT#rxsvCcJd}*>e-;-o7e$JFKn1!o`JXF~%LdcQ;Y2{=!(=8ustB)#ChE(g|3h zZQ;`lBFW-b!~zGpborXyqMX@ho1G)!e;PrS024k0qag_S`py)IKU6SY<<=^!=3L^X-vr{=gW-zu;CaS z4t4DkrasYoN51IK^jjNq749FW)m%nWPD&m9bt+3N*zFEIbz!l1*^00?koMZ*3M}1M z6}%zWZSTNRJpsiO*JYd5DTF1P<|$7~+qNlBx3Vt1@*c_pMk(FE6W&4RpI$brZ^Qf! z50JI_m~_7135ITwGzH|W!F+EIa)aHnx;*p}ex2-P3+HJa zG}LB^^!6KT>BNG)rzoFXCOLRku`=&4r(l4t_$8>!1qX z3Y~xzg~xP(Col@q?_4v|xUzo}x)UC8(<96NB)`gO*N~4>Ga8aMl+yv1+Jv{H%NdMg zk}FqXX+`>px<=;FRaSq*&lZ!^TYtoPgWQv(j^dCtEcvQ~VN;UD*2lMD$TZ#?ig<0r zzkS60nkJ0LL~J{hLuZ0{HNqt6E|IvISZ7)sE6L5O;(D5Tq?CeQ);vI&Wlpmg!;9g^ z6m#ymxpZxx%UL!!$jTq99HT0{3o zBiikjH6`zF*0p%zkDuhd>F!5x9zP3M>kYub9U7v$`V+W>=XkR-Xn_&TZRgi&<5{2S z`poxp)lA_}4F2?f&#!{LfNdp($%eF_=eg<9=jH%Iq74;tC>;&Jcaq|OnL9bh7Lg`+ zc)PEuxc4yXPu$X8Q~J;Tn9Bm-J0@e{dFDuO`@TP49Aa$4WpU|@kvSF}WwUUs=s{#~ zMc5q)0jtPb&`KivghgaO-+0m>)Ng*Lwz}dJQT8Pqv+s1jKP zHv+|&oC<;4DT?EY#@+eCi1$Oi8;z`j>jvzZ6>12Z*+VoEl(OyOq9@P)etRn5^Y#`s zNRoBOY$y{pX9jw2>j3?hJKEfZ_&1;98%<+}Ovy;zh{~laU zGD2ajP`SA~<84-_OxbZ%au!v1`pB5-^cT~IQQIOad~;DrOnRgx{LQP- z7@L-bfaT(&m*3?{*S9*5%I3o4vVzfJ4_uY_xF`DIa_GN zC|_8Qp%A2)Ls4u@k0yNC}qW6K(gKtqt|c%0xr|?8$TT^9#b4M#PFEbE@nDB2yPdl zZVS5Ec$yigHIb}L2iw`J)FMM-e2q5BLTo8DnrIG%Z4*R#i}pJG)-U_Z1&6I)X6G#q zm&p(VJ-%OtcL|NyrF>W2C;7g!Z~3kP{`VjCJyK%qUBy8y3r~7jpE7WP^x?hE%C!E5 zM4uW#fhR@1<%Cc-5hl-&VcTx=aIeZBADN%?;yGsp7ITWH1>dg>hi>W_Ua7l}idxTh zhHkDyMrLy#2=`9|dCq!=-d!7Cc1)fLncqd=deJhzG;6kz!FSx}>reSH^-E+yZ+l`G zSfhe3OTL^z$1$Au`5PU-8@IHt&LGgvA5Fs0nv6zm=oL0hidTDuW2rHt@w7`7#^mW0 zIaQ`??M|_}0_pcPv=N%3QjQezzb|{Wq?~ZI4~)C!@hR@TDAc*#fl@N6c_k%&zQHhR zctNX5Q>4e+MqM_#QRK^bNOCaWVw4SxsIjChC$C-Vn9x}e2C%*e?Oif{g<5;qp0@N{ zwOEUyc}RIT^ulIr^>wJ_+#Fr|g-=&XA_7+=J2a75@1&gZ&Ksnw9$z828~tX#P! zN?Mwq*xkc9TEjOwzNMc+>a636()(}a(XZ05&ELT)HzTcZtD}I^rDl%tY(sp@53c z>h^Bdg=W=4J2`Pwss<~JPLEUO#?D&aO=?71Bu5k8@{~R_A^AK*g#;3?DOvselZ};C zIFeUkN=9)yah{fyan~^s{0Y;v zB`XZ&>|pq2F%ox4JEC<#JlrVb;?=_!D>~RfOtAw|X?ouDcxL);6x~2~GWOkYUEE28 z@`c+AVKIL{p~SiF4N>|ec|hGCg|g+9@iyK(rk{DtXp<6$8>tRNsa7f z5GDgPLM?G|7jdPXz;5UZuHOgaUM<1nzi%Bd6IhlL9stBq-|TZ6%_9zO#_49!U}9ut zC{8$XEMrzP`In`mD(^QlKaP%mRgQf^JaENl##%Ig`q!>kETNyN0p8FJKuY(qz3~Vh zEJSJ0!-6cRmePTJr{r?uB~HIjs%(Hf!!yC!EEB^T}i@T_Dxr@GBIg*r9Q#7_5}j z2#pFtRspL-rq5@S2L9n8Uw1naM=mW^NiXX17MUM``mH1#K*p3oKa_w!R>mII zUD4%57rv}S9u8R0!a-nIP!IXje>D?nlpHGKB(PN51&Ya^Ib{PmRkbcb4#3U|O~p>&n#Y_6Q53U+K@hYCnvo%r2fQ z?CY!1yEkTIZ3Z@%gqw6Ibn&erxq?ZmjK8v1XsFDd2>=g$ZLtmsNjwzUfXjlSYE)&_ zBQeKw{)Q?M?If;hdiJTMsz(;4;u>Cw@udDr#b3BUdAexwT!Te`JV>ejYX4j5Y~vw& zKp^cyuXKUmtzM>A^y$YO__akQ_6uGHSD{n$gs?&79Zj9`vqhTbJxBn2X#|H7X`E58h%Q=36g6I~oV0k#^LqB?I?rESIBB|V z>ZPJf5q-=NxpP4IBabU3Z`@Xq2P1cPr6UDEIJ#|__X?CUg)CFWf_F#Z!q!|^aqP@x zIzNHpY<|aXcxmUyHqSMLA`_HWkN{(0KEKP+8M>^gV`aI{6pbhA-Tpg&cQGLhxkN;> zD8EY@9xnIN`8E85#`PcOt@Aadm5qZlZR|F2Sh#RddH3DL&Nl|T1H%N2HdeIN?}tr7 z?mK(Kob-l!x3BN&=fAH1fcevR&2}0WBRPeXAD%w?42vsX2c@DXI|!AnA3*;B_qndv zX!9HN2~>aF-!D9-{N|B8b`ZG7$wu#!h+COPb+Tv% zS;o$pdZw&GNySly0=+7C4VKrKG=I@wA>~p^aIMZ?IE{+z-f3oH*h1S-gW|BUi4w(e zB1kKzH7{Oh>aFAD(LE9zr4Lpj2shx0+pW!XIddkeNMyMkxx8H$d z#~$z3!aNoYq)(^qvC%<*goky}JywXdWEfcz^^r$VMLN=-3q@k%p)l(c`B`kVn33e$ z0AQp(b@3rXL64l?c=grD24Y$G`ITk4wV?&hqeh`EeAg+9r#|CWbq*5i__B9$yciuf zStm?F#ds-ddL-FTC(Kmmc$+ghI+EzyRC-e}w}mqE5#1IXU>lD4`4k=4k-hEJ|{i0ecLbS`zWj9h0=9>4p1a-MC<75em-@*=?0gg4}$@q;|Gcin?Lvvwi+_$j=&PahYq`0zku z%RtWCA9N`MaCW;X+6ZrgpyNRZ*!o3-BIKR$ZZ0VV;)0&A{ZPt2ko%-jb3yrRLIk0> z>_b?Ceo}a$?lS+l3PAnh{YIEsGAoSgN4bkAzi`cfy2Z3B3b8d<_Ce9-IqBbex^);E z5C4oP`;OdqI&{d-=IkPIPdSS|_v3*%_g!D;o_Uh+rvkDdWq@B{f~nis)(TS*H=9Bo zgnHxo&8>EmpR^0IrG94AHW9CXf~xB19OxS&AikLGLb|Hf4$zYDNH= z^wdHEHrdc`trr2r6{-qa1|x`sAx?eesMB)j4xmYP-DfI;S18jsz^Xo$u<9$ND`# z&7SB5!0Ov(l3h|^{7=Tb!(kMZy1ziF%g2`Yee*3Y9(ujf)h={xFONLFViHtKuP4=Z z8CzF!iw2x&USZG=kO>>_qb3FasOJGth%41)biguDFq7h9DuZMzQ@7X>Cas7w7FF`) zX}uAaoxe95U+v4RkHeNoR0H0orKly5xA!&2^}V+|j_g}xZLE`M0i|j2#{3C(8N-Eh z#W4N~fSm~Fv>3Ii-jFOUKhRSPp<>6hlI!3)kMnU=wcmu4p0>+e(|i;hRTl?pzm8#J zRofA0gU;=)v{$qIQzvNbPOKfmrui*%Y2sC)9!u&6I22ruv<=fxBSx+BLDHyDatpv< z$+W12H^#e~J&3m>KN>X9xxL8IZ)s>waI&XuE0S%kvFl6G^(2?O;(xjDFW>vv>_ga$ zJWX;SsHT!WL#>J6w5lX;Sf#ek6Z<)APH%Zvi|lpLUjqaatpQNfXZH_WcG^+kFA=Lh zRoKPPplj?Fs?ZPJ^h!{|@TW+Ce!?iV?Y{mzxggvvRlqZzQ< zQ_dzWro`llp<`QvgS|0|d>VlJU>Zc4J~YlWCJZ4LX3u5epIY`-*N|=0hKU)yq{>F@ z&!2&|xD9awQL6tPA{>%@uSP-v)%HxaW>5KXVkLb}trPvtsr9=H3#8q``M}!G*?D>Q zKQNt6_bgF-!a71?(s^5&5|g*#GfCw$%6k=kWlvaXQLr*$BtiuW)5Hp<=X|vlLUPXu zivuv5RaNfkyoBVM?Th$cBIPwp+|C9gcwQn}!sJx-r@u^2KhgNXB+oQDF>mGlpfq^l zs<&iap9k481VhR_1VfICp|T;3`V&Z<1cLis$ikjgfoX(A8UdL+&#b^7gn$468Pa#E z(ic}ZOv3WPckhk_!t#h`Xr2khg_L)+yj{yv?0{^AJIqtZB3{GzU*1A>D1;(XNtG0J=BL?7YO_Ie9F@G0H`~B8Fj& zT})H=clr_E{NoG~XDvOqyE@Ort+#8bZUaFnwPQ8wxuO~7S;Be{Cc9|qACr$r?vQKl zTt1f_N1cW1)U?JSXlprZ*ltT=#KQIog^CG9NL@=ArYDtT0I$CRXZ24rSC6-4^hvC$Vu0*qPBF28B0y{nKhjSh6e5(p?nUxKgI zpcaiYOsR0i0lxG&n0@MiXpUxhUj9D6N6P>P&fQBGKs@_Th@heK2zP?=PnGD8k^j2+ zVZ+}PqCx!j?djiwIQjnLd0ffd#njxv?SC6Y|K$ngsmm(jYNCBQT-;)@lGVik%1RJn zYNsa;l_zMSjYRjCR)>O6t#El_NB<<=#_|%7Hk}r!VALkQf~|{}I&@5nvZy3gxh=|U zx$U?IilM8^&*m{BfYPW7?{B-#@IUd^U&jZ&os1TI(-UikC#Hk2Y9|oFbhsfW-!F?q z1iK-|??YiBY4S5fD1>iqOFj5|FRIbLf&)1YNwnJ%$%|*Vl>lECNVabpZY1B#rafD& zAn$ytfw(?(!qii7Eb@n-di$W)2tJ(U`0k+eV(RC0qc@{S%F)dhGsC$>LRf09`w*k zVmnluDAU#YZhVPWx2l=O@yzUY+A7?_(ELWs)H_^hUF})^Hx53hf0u`L^*qMbE<;bY zy>+y_xIGh;`dU@eq}WoeXhxihUl?BO0?@W`S)aGZN=I$a?IKdu!&X<_PA1O!p@3ww z)~B&T2QCR!>E2zQv7!sXI6^V@#G3?9zWy|{kz4B2%KKI+f3Tw zJZT5D#$PbFL+xsli=%WM&$Kg?ujCLV$rXxgR6X1$wzwk)dxOcZDEt^4N7H96RS9oC z=x#2?J$|@bbJYQ=eYm{x#t^`pAWP~Ewb_Ko07j~4YYKd-QqaU88hNTxdZDrI0KXCn z4-Lw;L;*M$#o+U#bAhR36t!uwDQ26Vai*X3`ocZG!6@KtOe>0OJ}z}|iep1h08iDD z%>zgLZ)-@d9}ni1Mj*4hb|KDmfRxDJSXZ+5#*K^{E*SYOyaLWZgCgH z?YnlX}8`u4q z@KF!QdhlPIGZ=F+*$V6r1q?jniYO-8H5bFL-E&Z5uXxkVkjUI0^GC1j%x!G3$Rf9Q zko!fA_FiKM7w`!1*Mo0pA{K|5;NgMc*SJumh!F(?oJVn9xJc!pkw|z}eP8rf1cmne zBy32ll5eTAtPJ7ek{<;A$i#FUMBgEMM49$&ZQ$KD1BjXk^S_X9CH&xX?RPhKm4J#~1Tf+n(7y5zc->wXjGd;P4xw z1P~O=;&JEYbYxi>QH^86>(1F7l2oL+!Ep#uK3c0m_zNDz@|sf8ISZmK z;e$?iobD&9{mv6r+av+tdPD%}O%I|{loTXAIVn9S_`p(;*b~=em26_b@SUeu@00)b z;yrio=i^|)H-`QT5kdoR za8pB|;c#^5XVsZ@M;>c;)e+D688`GoNN9fQxtjmht!sxqYntR+0z%-|z?Zy;rUOMv zevbC!!XKTHM;YkuB3xaI0jEjxbutgP4VvFQ=j42?$GY*_@+CI;mOLX4b?$7`0LJE? zCKp%gW@k%xQ)iAGz=j$nYZoJ+)9m%EuhUp2Gk*B1JV(2l%@Ri=YYoqptbCKi_?2Zz zyDAN~thEf&PDVua@BPdQx!cG-H}nte6{PeUh=d%Tre1S(a;io@gVWHe9!qQi(`nh$ zW&4c}yX{5zf;3be^sVZJQyaRUwb!T6x}Gvo>N;Gd3_K4$7q`SL@@?<>Sxi7+F$x*ePcoPVgV9%Y8zvr(9m4%v z(JLfSeV?fE0hF8ZUI-`8;yAk>*F)BD``AoQS3FEZ{2Q~6)?zO$hnCOe=L1Xzg@@uY z;oLC=@AxJDGbjf8STH3icx!28$GQ*1CBG}^2n!E{zfq==<_2ryl-{st>WIRV2K$0I z_dqv(!`?SVC*UVVBrLoq8$qdU0vTBgH$WAwG3c)baloo~UKS=>Xb+~XRpOoc**)KQ z3pOT;+DpXp$(qUtkh@6u0w<@IJmL|NCa;3q4Z#1csTB};BcWDVeEu!Ttm3|jrvzfd zkqJdTe2J%{@|FFy7;xNzaQW+`>f!Q0u*ii?O;QoRyVz8j`=*WXL8v5IjBylHm3j4V zOuJ|JRk!AVW5hY*gyTzZLhA=u-Z_fE(Sb2$K;kQmYSsu<0ka92^A8PFI)+7Fno$A< zBIHz4#QFo0Nx;G@$~Kf&;eot|Y}qIugQ{Xbx(&*KB3xA)4Zp?N08JgT{xBIiO3;rKLI$dEJq4+CEZvXZm z=06W2|G(VR|00e2i!7CD*emH-q6chmb<%axH4rC$Bc_&T)Ak_NmCxZwOjLq`0VNi) ziX8FLX2{98fZXaX0jzT@TYXs75-z6?0dK398U=q_NsrDfsf~JEJWpavN{;@1UYoxy z5PXlsFL1p!U%Nprn#tpS>N@eC<(}of=04e8*?GO1{I(tC2;K-!3AP%oDxxBs3`~qo ztVygSx)N595`cnT6j7KQ=@yxR%DO!e5EQ@?!y>#p_#~>j38EuNo&G7Twokk#K({Fw znu~g;%zekaM}TqXOk99;Crw;{au-RM@Oo<<=CnPQ`widdlK1 zJ-<=naS6EhcJ`}3BH-@wpiJcGMru?@b5v<%YbzrBl~=;6YjiTQzjlUHR1^}DXLOSu znKmrC|A%NEB&0-i34zR`8jY``r-Gu^Lr!^?DNO&k9Yd`yDXVI@$hZNksm`St$*4~} zdmN2b-Ws%n+Mg_JQzIUJheL^nTQqWY|21&aIc(^aI;EcqnZV9o#vIv^M{0iOfk?`x zGq&zw#dB&`k=CYmF9u%wc|Cz`=KNOhI8!gTJt5o=*Fib0skE$Xt&nwGYm%$G5@UBv z;c}p4zvHnzD~vCRKjq`14_~Qe@~yGXB-w^W3X%ei!>B1R%6`YX9VE&*3shh3EZzK& z1w5-s9p)r@nkrTPto?8MV8`YX;5J2KU_a^3SXMFj_e%N2!^>@^NZ-_xS-97P7D`A; zaSLve6qNep@RaiU6x8x8Rcf+l<7FGMphb8k%c(>;Z$MA(mBR zv;CAqP(buWjUk8W?xlbKVH;W7!J++gLI5@lI5ed*7eoJ(?vC~B)-L*SO$)eXPBsP1 zcTs@nrSxiRIgL!&4$0ef+s1OEiTx2N&ug4`Vvaqi&}biBQ$`1mB&S$T=SpKP10zeZ z)kah4SXRCWt51gVG1ZJ>xZU`7CHeyyGUDfAd+5AOiiO>i|FP=1(sP zuCDx_F+Q}>|(&s~u9X8X)HQK`JL@PCFC8;|e{+hHc#izBixas^#J}l`;Y%UQj zmDusTtb!K-5mi&~cON?O@t?N5)su4B8rxePEyEZshm*^OOQq-SSGhAsv2rG5qn}_> zOoNX}Wy=v__c;6=hhFIXa5xvsvCXH2u>)ag9;{zhEw_vS@JBD)?HR$C%e&bi{0dRj zqA>T^^W!3S*cINGU(TQOjnm_r(&hK~``ZkgGCsJPsC>n@`0)-MaOhj_pnUV;n7be8 zwcQ)PQa(JM8wiE*b^}!*9m>gmpY9=CBpDLA)IJp3De!sQDfszPABj2hkG!O-_MCd| zde`li4Po?*a^Sllw3V&-x%KL;b*jCLMNhm%tts~;MEd(_N}5j7-_PkZ^IWn&ce~E9 zH6AtFf44t`2G7K8^sFvcjr^H?yJP)UAwkKVFzvoa^aw^J%DF8rcyi`$7>qbsGD7o(dGu^ndLH#;{5V2uoW<3)J z-}Sp(BWPJ>jC3OS?uHau8b|h^ZISogJ_{SBrtm$~Jf93(LT!|V5jk77-;*92W(6H4 zeq1Bj65hKT!9`4WG*MR5{Y~Xbu?jmtgC3`P@mTrO4`d2L_nu_pC93KOvnqe5toEIa zK3x&`jYfy6zzX13dAdwJ*x`WjJ(-Z8ZaqM`*q zQgz7ouw`HOR+Gr;jHa!?%M>knVOQ%3z0ta0`Q@zthEg?>&1mXhJ)8dPg`wDoXyVys zrWhEuXK$q)>qt3?Z@#?`Iv`VkNhM+tVWypmT17!JEIe>k?B2x9I(P^ZTyfT}v#3tD? zo^_pGZZwo%wUyZ$f}64SdM{u}UY%VA?CAFn6m4=&>MLbPexW|2bgRMkuI}qW#qW%^ z9_l}ctEgyy%$GX-U~!3_NpN0I8d(33aNKuqA=?voMiu2e8(c@?jHj!(xdz^wv;&)X zgL@a(1y@tP_MgsacyH)8ML0WCAzNt~*V7R5CK4Rbh3aAU8(@sp!eU;Zt%zYIFIkj< zoHiLzi=*f_hT^0#q^Bpv&R?PU!7qgWyfISB7RK-YzApm*ZTROu&+m#ln*EO}2K8A- zTy><+?bp%unRV&SOcYA`(o~cBtqwK^YWYB6k^b7ebS`Fjas*sUTgRN$q;3R2P-t6U zl4v^+MFlV?i&!ZZ`EA~mrk}9yD+md)PA%1Yc0>MmjkuYsx8wH36esIWm-pMGprF7v zC#(#x)8VXduQxj1>P_WFyuLYf?NL5z_jHYCv_2>Am7P4h(@b|whqj-Ez!}XPnG(jJf|<%FbRP+_5PvND=R8&m&UoBqvH{KNyd$&WdiC-F(R zuCy=>k3M*&)iv3u3dP*YykDoqXG+a^+*J^tLXSAnXfL^aS28A{kB3cykij011u<4Z z$5Fvo@LiI$eP`S)<@dmadiNNt3+8YM-%@!+nNwzG4#KN4p!%LgeZ)Jvq(R0+fXSs4)*ua8=65WNJZEWNF7)UEF_xZ z?1>n|Q0MNK(8uPcVW#zAd1TJwxiZste{$#GR2-HT)ccUI-%V zs_a638L>g1fRGfUiD17|l&CD|GdZkRcF>mm?%p04LZ2p78(GkD8GzI&)+OTti2<3! zA?!Kpoex;P%q|t>4oA@waV{IWT(FxjUDN*)=34(*O`?;h3r2gZS!PuDiRPUTH)G6# z@dzX{beTva11d0!rClLOun)v964{TeNsiNWO}p%pZZX7KS}NBzBhjnJp$dKp^^CdS z$BfL33_ArnL*P~gp~YIXFs)XRdUAFh82r@P3}4A%zY6O2BdFJEF&y5goCB{(#81wU zi(Ppef_*;x!eWZ53%Fe-Wr+N11!@mLf7>y#&yh0;uh}(nomIImS!^%z1Sp z9CPN9|F`E&{c3Qxh_@lQayEnpl8*`1g@)yeLCigv@dnu1RTjnSCn4nTkE*y_tr(RwZ50Oa&_FBB6i9#MnU|uYRj* z$jdn{vBT79fw}DO%Ec%7(sL(=T(?EpWx z6Nbc-rCp9VC!nh`1MWK@^(2cihOt2RaDpfPsMOY?*q9ydFGF-gA#-;6H!H2O`?>py zHJL#s``>4mTX*P5OLmJXJ4&^~7BKHF-}G2>q$Fg!+Xiiy z=a&02aAROZTwho(+E4khwy8sGjs{!m)~L41zxd$CQ#z^3tg3KU3U}20af4I_mE1E- zs~tCtNLrBXQ83r@=B9G2^GH8Qo2|>vgWRO_Ss9`tx5I3h8I^rzM;TjY$-6QBOq@zE zw^gN0o0C6{{?Sxr`iuV0hjOxoArQZ_y=3>%admwz{uIg9zv?$((yl+0O1k<47f*rVa4eX|BgJ0hO@|0)- zQ7~)|_J9<4vE9gO?9VJC)^UsIX*LNoytB=qkSm*M_qJOtza5V|U0#i5=|TE;&0@6H zFYfUS?w8hH6-&j2-dE67z0&`~+B-#87C_sA zRk59llZtKIwr%soPAaxpv2E)lso1t{+ezo%*W-P>*YDo$G5YI_{d?BfYp*runsajI zRuFH~Y>2y>a)jQ^$|DBTl(dHZ_>kcEW46y50Qf|vli(rZ@2zZugI6EEbiK_Y+c{ex zFHQc5?2dRrE0hqVD(OiQ?kqh^JrbWw;*%f}O!AQcXORFW<;c=r!A-W}pzlsp?n8!e zF(<96xOU7)wPAaYoos;PBPQB715jyXgNT+&iitsuSQQ;pH%gz6-=2^J#S^_=E#~Y4=!=Fyc%R_-g>ZixqX??AtAXIRHdj(>q6H%Hm{Q*VJbRWMqba9BaOZ4rBX|=37oegtq5hsBy}O5v4pEQ zxoN!IILU>ZyZqO~ZKf6aVoV4o%3XURDq8v^LlXWoqQ-0~r}%F?kJ(lg+KJP}MlS8b ztl?TkwoGQYyn6wE!en+<7}X-bljXViOz=K4s1kEW9daY?lswL)U@Vvv%zMhCpG(G^ zA%BmMXy;De^V=)UBCS05xJB6xUh;mrMe@+T`X+eom}U#hZ5i}1;QA?pGTSEIV>MK= z_r-8#g9y9DVfB?2gVDC)SCz&TXq$#e)Arc(+#UKt%Q~paMiYxVoF6qVnlS5IKQwP! z`&RS-E%bEW7z2<^;?A|IS0sg6cMvx|Shkforv^($oG`U5!qP za$G2@Xv2QoPb#pI##o40GG=0R7Hzs`1gX=$?%%@6EspdYJY!gL@d-Cb*t{iji(kas ze3epdDz&gApJP&tVRi{OAis*iNx5*RIICo*APhra6l z(EJl!=W2TMULcM%c{{*LzKrz4s%iMm+>0yDk52=-<5x{MJ~$?k-sxc@#arA2MxAra z*R}HHf|loL=Ph?g!lvk#>JQsxe?1$>zB!`>aqDungpQdQUH1?<*SYc>vrl3ln8!G? z5MCCs{%SE|-TV>{G{QO@)xu$_RX*fe9Zoss(s3dRBLd0#ijX5PywK$&TLw>(V$*IJ+L8ufv*+m9^3BhKW5;E^4>`*2D9+HrsBnD9WBB6=v zh~^NTD3ka^6pHtd;>U~N`M?O{uRH}|6nO|~3chW_>|PP)O=mtM4WaL*$Wt3)Pf;*p z$4W|>2TU0jDIYqClu~_kcot^cBbpMAWU!FDtCY(66U6_MzaM><0gTf3KT|gy0_K^! z6XpNJVf@+U`9!Ici6iiFW}?A%WoNy#Ob{yU#xR#iIIcuAmxM{YU<1l1i7cBk5as6} z-7o@$>Vul;^fn4G?}+f8auR#s!0+aVaG0gKd*q?T-EtC~NWLYBi2YGu24vcUJOp7_ z2>;e+m<~n0#d%iZyodg@28ZviDI)$(Ujwb=FmLcjH9_w+zGrxFK z;)X;C65C$W#Fv``RCML*MvDKY@{CJHv_~IOf4bS_g#D244zI?kIR1o-Y7w{yy&;QM z2Va=~&#|mR9p|~=+pHD&zg$ka{$De4Vm1K7|Ml*mN_9h7`}zJ6KLr2+vn^z_E zQVTs@tR_V{jR+Rd(^v+UpQ}p0^Giv{j;xL0`I2B7gWqgE2EexrIge#;BIYnip7Rds zeLaBXGs`}tr9E}2Tm3VD0gt(Fv!UbY-S?=){OS55u%-*b{+AgNd~5lPy{s^*5><7D zd-xQ&N+E0M-~B{NK9lF``UrKFMMgD-h(vBPHKi!jJ^K`v8+O?gjU#KTnC5gGr9l(o9q`C2g4-7zgSXaVj*P8sBoQ< z6)XhI5n`@AQKnTzq!Hm&m@n&@hT26MBU;T);0?HuN3?;UoM)hLtars(NY9#ydGshg zD!)ya(}{zKC0Dzefh^W3WYH@;RnL%4!I?hcJviZJn7xwJ(nRnHQfsr~br_DO5c(!$ zJwETI9Z6%Wg?~Z>J1mn^;Jj|Dh&b!PgawL)=VByoQ|gTRZ^aDxQi^kX-vt_tBuyko zUeumf9Bz3p;f^Z&a1p-ItY+I3n6F^LqvTlV2{To=KYHhFZK|)#BnZiCJAVV(9P=3j zseu&n?mYNKbEXbd<4V>4#Ep~fv{%{cBh{nxD`kvL5ED=}^n(cn1h9?@eUOK$@}zk5 z5s@;S;W4Du7HLvzaEj_V$uZuj_LLf0#w%$}R}ahaA|tu$go~YtvP3I*jA$e8SB59^ zzs~m8smim@6rg1gjpYP}ok0RufWSemRV_Nx3HO*i{^mQp%tHaL?0#jgRr>_Qnz_DB z-P((yh=>z+P{8cnii-vp-1zD7fCpZxz2*=S-PI50?DQD0`b^uHydy0b1&RZhW%z54_H1E*TnSEj~W2wJs7mf3KLDW~fQ)h6W| zyMK3Sezxec>%zw0$0aj@DVMD~Sb{@@a#CRq6ks4=T(NlSY}*^r@g=3C{xiGJl5lpS zNa(FUo%17sSnUo{yD=zqu{BrcM%oI;Q!NNzzvfv}|0y<7{lmdC#{lA&AQ$)`c!&v+ znU?2GR$qSHY*tIK?e7MY;J0Lxj!8bA>zQQRxVh}FK@#zY;)i?75tV$WqygX$yvw=H z@qVtIw6@i<(%D4I{MF9%OU>NOB4Mx$6%Sck-Fo@aWQ%v@3#R%47V$(^w z7d`$!+%dK`S(uRuqUo9yy1U*5*Ke45*d}u$bV5CKzJG*>scu{KQk32!n5X(IbaRZ| zeAAzY{VHZ5$W5+~UGznexUo^NnJXl{m?B3RCQdVnrvApG8k5Qgk4s3TEWO zM%;;=>CRO2@DNtGELgz-#*$s}qTuJcwrp^(^*2vh|9{Q63*qQ%tbM`m%CyMq-w)wD{QFYg6`8*?pqV=zC z4qIX_h>R9qQuw@GHXK#hY0ZYMOxt`(3n0XK2Wfu-o|hf3fcUepkO~E6cQBay{ijZw zUtAm#z>Ius&{a|ed8C0Eu=&>YJ!UhH#{S`dLHMVwA(;=$%mv@TyikK5uB>5CZ;v-F4#w9|^YszgCgn6mh{?UfrPc*VI5X1eLjZ?pk)J z=5G_Nw$J+#fL}ekPzi2i)VYj-yR%WC&X{y*Z8*bauHE>E*3Bu==yuJls@?3hI`wIt zw)=EB+Iz%>jSBKmGGr2djULK<%nWl1j-NP&X|EbtKt0?QU}sysx|z_XMJ(-IeyZ~E zEhith56)}Z*GkHl44-YjSA6GQfCx<2q_od*?|Ujwkzc7{I6kXxv3!*#SQ?2($3#(r zr=2pBa+|Pa)@RO&_D&1Pj2_tu3y&nRJ!RwPnB3T%u&;w3tW#)eKY43DddC36Q=_G4 zYF-oUw>F|y`Q>8%mp`T67@4#pI-o%ULN89HP6M|%G1^uQk1zeHY-qI0a-+j=(Nt8< zEL||*@1@!~SdU5os2a1sy1q3FJ9(It=i?&pQaw(zcJWf}QlSG8c5|)gQnPnjHel=N z&M6-mp@=*SA(f4VEO0T8C>TNUHwugCf{ELysoPk?d7G6&jD=gyQ9ML;-yMWrFA~A1 zGs;9V2ZN}Tp#k(5Tv=bJVQv5-9MGQ~KFYZFAE^v(FYINkKcYj1;XT$Raq2Tu-@#t6 zT+OTxGcA8Eyr6qYC7RlEu*w-w25#UhkNB%fjy7(bS{?w(>zv+N0(%B`B2!ls$tZ$o zipblJ=Z@Sd5%?-oDL0!QA$&(ia`SC4A~$o&;`5So%esu&j4+&J7!exCPm~qq5@_PZD2Ld5D-dIb>qJcN zN0>>db+E}@)mt-n_!{YT>!7hcuX@gA#9-f3y4|;FSD}F41+if6f3|T0o_+@!t{%l{ zLTe@{DX**#&)x8ahsg%JQ-%+jbEbnEiEG8TEyq6&=X`fcgds5ImR zED=}5bDV%m;c<>MAvI4Gl0K#?)h_aStDH&1ct>0_32{s#NXcWOa0ehQ<>AQiz=KB^$r z@gL|l$hyN!K$3*0N}HID!x-%MGtuOD4EvdT)-rN@J-63k=GIr{3&-cj))D=Wbph5G z5y=B+_{vK`JDY? z(*&0$QA4rmEjL`?icT`2a0W22F7LvsXrL|wC)V|93aCB{)xyWs*$yq>#!Wmeo(n89E8?PrGk zdH6M^_Bvx7PKHcG7~|Fr)!fkef)4DX5M##5`=ArzyGsvA`8HMEKw=lpi>fmI{X(4& zU!Q%g%a-TFhCkk7Is{mVGY=~ZxWdnjGA4n*0Gl?YH^JK+@L&^6wStJeHMJ@S6AiX1 zGWOv(m5?{rxxA_IYU4Apg1TZ(_yRSTnm*bus!BUPM(1j!-N7Ybs|7bVHelh%&8k~6 zoAEO_DtGUc^I6bY-RzSDD8m!;;n#MY(j^iomp8AZuWPE!>62CpES!IlaFp;%QNf;++)%v9L6zL{Nm7k;eu-R9A?s@1s@vczkkf(=#$W% zplfI*CmYPXlbG6I zgTtq;LS}sCg1<&dqH?5JSA`gIlh2{bC#WorC*Y!AQOAUyCFnj(m>&fqN4n~WS&!3} z!M}(Vdvnp!;Pi5Zo=~#0w0c?5RH2u+rQ`1DNP!$pU>F;Ez1%;~SXOwy_+K^136CPy z6^Qf`B>rwv5;_v1(cGjaxi7iglPG12j3!D@LNlU#Tgv)I5b4%=ohA%O+L*W#+~mYS ze_X6ZwvwZf=UH+R40*AjcsVd*ro;Gs&N1JsF|e#an}YHRZy|;tfD6p=3JJGHV}XDF zw>A>N!X%H3&Nf%e?y1Et=ndtTK7QP2$bGssIePJ4&~P6S`vstdzCTevrnmeEX6}S3 zS)cxsj7>`+kd^%IR}cRs4Z;84?YsYT2vah3a{aN^#h}S5At6XWSo}j z?lf@?LGWMQjON0VJX|0%cQ&94;JWzv@OFmpr@1~t49gt~N4CI}Tw=N!WV~A(t_}B* z2Sws$O$1eR#jCGnVi1eviQ!Ej)rzsuy7nur1917|>&5YvMc6Q++a@LH5@Peaw;6{K zPG#|h%uVN#HLHaBEFU@f`|N{q*<;v(TF+@R;%rNKhG`dM&p2M1V3mKm~TrHB)gGEU5I zZ}q3Mb+~^=i^OAw3mN#$oE6)6`u;vnGLut_CG4hP1DV;57eb_O>6B;|kqt?RG1$EG zR+2K#7mExnMPx7)#b4Y-#!?FpnMaMFfG(_RPe`?nu;5Hv&s9BT>(FtJV={5MV$y$D z6BOo2u;K{Bs~V?}_-W3dEkG}aF&*mLgva2Jv9tLHF`Uk(1e0iq@Pu2{C-q?LxmV$f z#Oaho2eV{~7?w*E6H^e;asTK-ST%y&}nn%S(s*iSL&tf`Dz*jNGur!$R(kw`}$Z%Sg#bFx5K zVUOj7QETZv$2Sud0s7ssg6vjD~;z7j!I5nHT$$!6&49Bh=?M9-d)3DO5v?SgFN zeTh`Rq&n=f&Ou~yn{(4IcGIN9;V(P|TlxbtM93SV&(MctHyY$W1DPzWK5#<6 z(}ae;3;lmCGW~y71uQ)LW91Ry>vMwB2|z8F zKV(5)pRVvnkb&MqWtxOo{a})VxrqY1EOCa_-Zor4uo`-2id$NvPJrr|G>KM0)4t_- zcrle;;pyTE8ylGk=Uo5yl(?wt@@PFU1$=K5!@D86Mkg1owR!|rXZZv_3|{^o4y8Qh z5)J_l-f1``p~DUjKOzDdp^Ns$K(KX+$>*p3%vw_@Jqh;N`H5z3$_4gu#5sEL(kof>5+YBrSb3aycTcmBvUp=pCdRUi6PwR;SMrB4Tz&bp zY?!O7Y#F211rZ;(h*6-Y0N>SY$;R3_oU_SG8B^w-Yp6eHn9(CR+1c7?Vd3eBqnMSr&9N)*M3aUlVzCYD2vg}HjGr-?;!3-PH-$3U0xH&|Ga)CXRb#IX7Or zQC|x)gv?y9V@H`H+imp6sHo8L?*L=8w@R@>n;5!ES)6_Wx=ImYphGYSc2%Kus~(G% zs33eOL-mZ6R>6+2dw0m&!JXvGd%XALsJWCzd6`TBc6$n{Xu+99RR~z(4WD7FFy^9S zRY<15nI-5??1gX@WeS%@MPaphz$^ucxDw`(QltorH};gHpeUxb-D2FYM^6~kO)h+x z=$IBUu0;Z?Qb5%elqgXYEOxcIjq`edkTJ+=<3paACaYDhn9#$s#^I#}6LVD#Zd303 z`S?g(NL_K=p)k!?`;7wf3ejSy)(}}AP1t}llGUJa{7iA(UKKaH>$!!6jUI-Fm%H*t zNI2W!xdFz;UhlA&?tfosPE2(I8&*1YQ+94gzb?V0umdLTFV%RbJgl z2Rr+wy%I^4Q9<>tH9{oY)N|>kvwGvnHsRtmb<2%t8=L*JEAgbLqG>#eCBD=xn)G@y z0m>!No9>b5gT|mtbp8Ancns8G`f?m^*4 z(jGE9^VQ|U0Bu!bsLc3w^WO-Z$Vv^KDVQUtMPRBw$AJIH@W1mi{Y#JST|ZpTUU>R! zxip>zM`^P&;GSdWI-OVLkZUHOllNX)PoUf8IVs)pW)udvF3}06;5M5bXv52HEpPW| zKY8g)EzCRCF@0ZbcFw4jS#^`IvhDE)Rhok#k^cCY2v4sjF#O|Li>0d+6HBr}7nuY$2|IA)>MHXP3r+4t{_J2Kx$t6~s= zq4#JCw{Brg@=cIzw~r#O+TJnB#|V*k$W4+Doox-4S7)DI!()1b`kdAW(_UqADCHQp z;Ydg1AL~1yiH0%ul>TQ|U|kh(XbuWwhi7e2;`LX&D&lm(vlU+I&Uz=_oIXYIa+iBN*A=m;qb=>tD6m=*7K}=E&)Yim$c1}SuHYx4jmToMBz?s5nxL z4X&d2)>T$#2^7XYlFPsq!B^(m&DpZ4|a`CN>m9*kl9hw%Ww?)^MIv*r$Y8A7 zmj(|$iiH8eI{KzVmiI+fzEErF+W87=&QyW3?Lw{AG6ZT1Vi1*BG8keZS<#i2HiHwh zb#qOsM~BI_u>hNek2^I^2rO#jycwYCk%R7*W+nRAYsR6iQzJ)4Chn1%x^W!9N;i^w z+ZPGlT#>r8b$S<$Lw;{8pcNn2hpfO-v<3~OG?R0_tUO`T5Q|CS_G!gK$eOaQJj zd8-!NFmPr;>C$NN^Xgm1JOClBQ$c@>8n2hPiF6Mp705S(k7_@Ldz#sD11;-*h97*o z^~?bjR2RtTD^^=7Q%d=Yvgaai*(Y6S!w)w5Icog!FEoG;Qo52J=1=at%b->kVlVY3 z<2s4vN;z2aQQa<0uV7JF_Xw?*l>%>UNKuRPPh^DSXm9DY=akj$BG>0KP{Gx3*73aESz2ew|#tltIW`_O}hEIas-OI>ypPH{H zr%~*-;-ntGsC`HiCx_D6jYG=OzPsuko=Xy)Vl1o8B}MiWSCFC(o>h#YWuv`%Ebqf?2+9#TT8QbtX9QylUqBoZUplY z(aK*T<<#fRjtiW*_e6^fCg`82Hs|E9tY1{zgkO$$*)=bNqO4Z{qehR=d0%uQwFj?q zf>D5NO4VcSpU6rjeZ)LqvF9u&mc6gHWUsB^li-s>@5Yqj3qwmVWGgLC81^ev`bmL1 zEN_(UJyiZZ1$!$qX1=^eDv%YRou>-7C)rW95ys!>`N5{LM;U?}<_PEB6R@prfT66T{ zZdCT2{pHLN;j+KilDyZV0*R>hihK6li*xL5R)+8?YklTE+|{ln&i&M#o)B7BUYBQv zKzqST8ms#lTb9S5|>R&^P zsWkS$W&*#Wm1!(N)S7a3W;Par&7%$lj7X5CNq5p8Fo&TpLewz#_xZ$`GG1ebdfu|C zTKH76);$9>EQ)=(T6b=C_i256x>{E~xM^4~ch70DKNl=wd#-va&;p5L8djeQ0!mh? z=&qV@3z0A`v|Dvr92772iOvsU?ClfdhGvegJ;o|w7w@8;+d{tnGtiL!o}0AsI|JSs z>%UqE$^W~BPz>N``#-?033X_9l?C+AD;oe?K#*u?7#P^NSUyGR&pMibo>~bKDAhA! z59q+eGzMnD=|wsv+on}5^?yE;c1=p8NcKJOaayTX*6iO#uN^g|5?@YR86zf4EP@wL z=v_e0t4*gV-lKPOFE76JM@&EHQ5+H4OE?3POQ!3p-|LTKVxVr2I}Q4m@k5=rt@J@} zHy6LlAOkRiu7a+Avw`2}@{r8;L9mShN*HXA7pn-J4KsL}$5x4N-BmR36E}tq>V)-j z;-bk9Zj$^<4xX@9)+njYQLI{Yo+|x$1)~PCe7)s;bME%ue0k{iVQ<|P5xPvaAq7=n z=f)uPZuUZb-zC`e;CC_Kmt%9nN^?f{%zK}lKx?qvb$8;DlB3e=#HiCE$aW)7&8SK_ zVL;7DcFP*E2K{ED zRT@qaN*5O~&Ma!m1hPeKSQcT;gA>l;2_@tQw(@22B-+;Ft__xLs&h#e)_Vu672_I> zD>CE>tXil0WsZHf#w_T%zZ!}M_QD&>Xj&wi&Chbi$(Tk?p46u zG(CuUS%_z3a3B}O_ZERM&8BL%aEUEpQz)|cjgo)vHZ<=GQ^h?l;(gqI$J?OdX;t0x zTznCl9)KfDm|}*cJZxfIyqh^SJm&Q(ntnKR;40C=7{B((94QRIi49VJ7qEzz__ z>zz=GTtOZ?2C!&fsOe;)Nom_&tn|+SR(=!w-J|4=0iA5)8r+G?+-Pr1MuR7l277{P zV7*9F$k>aKb~CyYQVD_)VJv2dJ#JG47)hbz#I)57NH2 z^j&hr(qb;mW+UeKLA8y;P0eVOM<^Jl=ViUL!_fbzX8v)3L4A9at3hWpUmSWU4;r5z zvH1amnCwGB`Y9gzTF^{Kc@pFkv`t!t7MN)leUHM?NsMjXoY3fuIK`2GnF9Oj*H#@1 zv>R7|z33ocBQ$_%4O!WrcaiU)g!WdTn9^?!*bpi3ejRdFR~xa^BBW(@A3Y_j*q8yF z2@2*coTI9r5xaY7>i@uZE~B##ZyBJ=?D|#0wuoB@g&+ar^{Eehmuw|Llchb*7UA%& zRRmullGn^?)|O^Sz7w*`SPaJ=ZB$w%rZ|0WO{ahV7#^?zV5w9OfM^9!$i*hDNg;$e-g}yQxc*Wdtx{~z{8fxusO(WxE`S0 z_e}b$VJYZ_`hE2up!b>97h~}1rn>jI3m$q8k?0uLn=FcdSN>eX@Er@M_ZjvRTa3Aq zL52o)58$qjZ}P$Yi9E=EQ^T+byEU<#%TPX*k39(9s?hl9hUs;qhk3OJs<~ETfBaL5 zszFF@F(u@N@UbBa{N%uIvAvmPSTu&96)m!_6?cguioaB#;iba%(<-!^YfOJ5qr3Re zZNq|mo`vE&(0%vay-e;>$x0vl0M<5NGCKd+o2E{YtComON{SNWLgkV{D=Ac;=;dU* zO_E*|l@TI_$7wGOkvMxJuAGX$gCY-jSsl69# zrpr_*elVOS6MbN2mEFWes~`Vba-=S!R!?u)M5>02Lcq&O`%4*9PfcBaSZl4ox$ux` z5+K5q1xH;$ZJIk`EO?H2?Gj}H8K`drSVwJ~$#RoTpmMP*%^#emL zM7*5OGB(M*Iwyb0{3Z)LQw48-3-|M-)hqq5a*13=Y59da?97J1JA1O_z&;U#imF*a zwRFN>)h5(y@r-p4LH?$2J(8LDeb-!$JLKf4`Ei2zhQ*)E+kFZeQ!9e zsLiB%a5TF$2?6`-T7CK}cWOLvOM#mHe4VWfN44x;&oVR)2=b&Y(yi1~Wp*uGf}O9H z*__hSm}X9#C_yMoBLmVSrej(%cfl1w5$@C-NREaMqU62FS(yKph}eI*=_`ns)fxvI z%si%KN=wzJCSBh)JdoPBuO~{AaV)+bBvfJk1=te}8FUkm3_j>o*Ku-<%DKVO&tkjo zAYr%~D0DT#I^9!^o~j0s4Y|AOh;NR>0ON>jmV@8!f^-vzX_C-?IR<$g2dQcQZBL!N zak}Co_devRV~(xHT@NOFe|`|*(ZwvUMUc!3p;YW%#JRcb=R~IG)jO*Qd**UD_Jpg6 zaJOX{6!#W_LBVkVZt_>| zUiOk@;TfItz#ZOMVcXLp^tg!Jct#DtbA+_Z?S3PYYz#woCY$Rb&VV9FK%dll%+wA- z`>~u(aC9q#o6`~g`q&pdSJcOTg;7Wrd?3oCK$6^@;$fRc4{Hqv_1Wy3Jw9bKs8keV zsLs4G=qgf)w)8dppai#zuH>ZBg~d*K@`03Do6^428OObM7z!vJgc=sdAA({m4O@c= zJ=`-QSaDKrjs@Q?XuFP+ROGYmmHq5}LXUnf9hPi6SPnzB*+I+TZ5AV5A!LB+!LwY_ zXa{JG{EwOINwiV_rI69z?OL;RQOFD-o?uyub|!Aj7F7?W(QhpYLsuvL78xzD;_bg- zIBtoBIBz|yO;yPUZPveBgNG>P*-E9cTK<`FbtnE}qN#-+Sf0Fng&N#Z{8cpseThmF zD_`HvBkP{sLv_CYuLU-BM^nfD2oqt7nOyIm8c^agb@+wJO@HP`OYLsv$UdJmC{NbF zV*}WT_zNS%AQ1>K`KpW5y^-G7`x)N^ZG+rqI<};V^&89Io0g! zu0khXYpE8`IIVy0lsYo@RAgmWs%$Bpf-aT7Up$b%Wz^ry#MB|!taKL2C7-FU!{O_U z23!@<>;`M7_$N@zX7ir_Fud>j*Mdg|z7Hh%ZH6&fH~Zm@c0mvHt7CEDvjUBcz4vj6 zd{;n?(nYcybklzpu>NQ@)Dbk*(s;=Jz|lLpzJHkQb*gVmK-6>rY9ah4Kb^bexwEFG zx;Cvo7aS9l&EludiQlh(OVG*M)QsbrZ2>QTciJPYx8_5r54$gJDw>#EXSRCxULVi+t(BVrE%&xdY8@wWoP zW7U7jCuGj|Y6!*>I6y*(0bNfsr^8X%ja+|?Wr}3SWegMbNh*yjN5K(O8-Hbowcu=W z%CMCZfz1m@(Ta({i?v}#Sh2!IpECTl;!rC^sZ=7a6~psyvLdNgDblDB+oNNJKrF3W zE{^FfC>PqZ|HZ30iFK%zrErFYvUJ+7J!a4*M~>f_DrzbIs|Zgs$(4fwniPIqI9wZ( zZ;2U+DS08~yRxPX>pKP%gy{YN0&Mv8e*vTKhGgJaI;dOJKW?~Y--Bow?!oS`tI{>> zkK5|D`_YE2UrzS}LIG4fjNrFqWU7!g=}vy(Wt&*oc9U9+8;T}=6!oYf=EOXgZ(e3G zR>O)Ge#CTD$xgw1q)vUbHp$g`Auo6E+$Da7&DMau)r<7@J^uf=O1wLWu`2(*NX)|h zuf~6-|8D&MpB%WLv9l$>?tg3oMOx6_DhmtzM`UU2X}}l`+tx~JVeW;*rDuRK54ns#nx5nsLZCAC{u5hj6mQw8c zYP*_9#}Mq^ifw!9>c~3yoN@%X@9YibkmOTZ701%;1w*vFJv;Li{6)*59MDvvNieEI zlP=UaJ!mN66OS-eqDkG=p`1+I^`_(_A2@>7+bQq|P7ev{QSuT}a!D=kszSJVdNjqB zbJ7f8Q_@|}6ye4jRgH&Z&3j)vJr|ZMO>oj4PkhAbk5@x9vM;6F+M91 zuwDz%f5pzHdb~K6)x`BscfNxY=ntq%J46q^ixTLLFTFldA&faTuDQ0SzM?3 z%=hZw%!GRE54J-mEc6P*xOEbgh}e{>=?_5!>%bi33+J?8Mfa;F~<{PbDNZ*RTFu)Y5fz2AjD?Y z1iAxjo$t(=_fGU*LeHN?X!Ka`)MbAz4pKYcBaZh}>AMg2mR{Irze0Kdug7YiRjFG{ z&u)C}c;o@QPY_@JWjuxheLcfU)Y(u&`O;eQX1m}rMNY;uB21XFbns&BRYYGGZu+eK zRwrguVf|cbAhvbx=E}9ym|C{1!A90gMy{x0TzxZ>#myQ=aK*hA_EiJ>0Buwq44Vir z###!jA&$Wa;dlcgLwU?vI!tIcu*6(Gb> z#uo;zN;>LQe^YR4)M?d~^#1ot3yEdRC6qTNyjy=>lsxxV>XChT>!Q%xd)L=dRs&4! z)D>;*ndy*bdl1;s3(buY`$9=i26G#|rSUGv-#Q56C|V{>Pj};R;(a5(YW0{MC@1ah zDurW8X>prYJC>>&cOwI-iPJkYpmL!>xSn0PU=u6);@W56aVF#YcV(rOt5&o?^K0d( zEv?NICPdgS_^uXM*V}aBzY{>Jy#y8559V_XchEC)#79 zA8W>irbUQsb_7LX}7ZRT69v+*j4QZwb4|I&qg!KS$-o?Rq@T$7Z zuDQduDe62`X}Z|{>P(C4Z}S!OuOR0&3pQ-!$y#wHtyqdyxieUr=46`7_UhS&ppuu! z0ts4;6K5MaIgcg!X!fw*DYZvk5%%7kANTNqBY!`@&my(MFC|dQ32drbgf=9tEeXEb z%MTNyeSMcBoX3ZW;HlFbl6-e*GTx)q;@43f6qwi|uNEcxPvOMOhPXSHv}R1$8V6ft zV1p|~h`f{nrJXIJs{}p{n3`mL^oaY^qieNZ`PX**57Kzu}Q=&Vw@B-JOW~APZ6q`#hHe} zD-m;tbuUcVgsoq1Y*G3K_hXxe67GyQW-_aC95A^HSkP|wDVtfdSP#gMPFOkh{!LosA@s%!O>ZX%t|n_YS*1=&(Hx3KkbvP9b( zm0hqo3JF;0|8p`>d&<Sm0wH?KDQR@U0xl!O8;@I z!BW3N1Iy{_tjB{NDZRN7>Lua(ZcYMRpKMy)|73#T;M|2DY@t}hL)3KbVy2)6*rK73 zT@;i5J>{3}wZ6`gabM%lxR-4oD)c(xOT0|o{pmSf7+UyX`-(6JLpV*r#Ini+l`NJa zRUll%C|krBJ4!CUNWp9wiS$OtYcs26X`8sKNQs|l)Pcrb3aK%6?B&XXKMx(!^M~=J z=Dka@vvIC)2pazbK=!43uebq7flFEtwtPoS{E~!}`NX(je%Vrb550N$Ic0>sKyE}_ zBd2AlY|3S5$ABG83L2&sFCd4a!_0`J1I}L(D!>t!2(l!T1nRYD8dyn5hht(3n6W(GhnF7lIZ8qny$`EZfDYs%p zJL+?i$^OSmwj{~;D{hZ0+oaqupkwa^EHU=LG6dVM9NCIweI?$>urNgYsA!g2hE+&HH5W8=_mBdQ?B*rgU3rnIp zW{55Vf~$QX8zk*1=g_Z`Yq0QWVHtO7H@$r)U<)6Xgdwg;^q((9kDOH|c1{7}6U~GQ z>a#!$jc0b5)x3yEoA=q&Nj-0;Ockpt9sz?&XBjry_GbT_<5Vwev>`Sh`y$>+n4F(e zpejj~z^No9k~TWhG$aVZ!1=OKxug}7y)&Aku&ko8tV?Ar^Wm^Zd|5Gc*nHbj-}_`R zvGUvu$CkoSI66L{9JQZ7{eHw$W`Rb}<$Y!)miLC@pKUo-{Y7rlon|2ce;>x$Q>N6? zJjt56>AN;U5C-h~Ij@wHBkDRW|H49`0Kb<_~t*BrYTjULB&FrWUR}>K_a8F z$Bhb}IzsFKB$UFeC}$bh^r9R@olVqHM=$$C_?`RQdT2U&j7xd9qKd%q;JVf#C$L&2 z+@?kHhfpBJV4wBDEI^byvEl(0=CTaD2Z3aem|s)l`j;F{45aWP58irhJ_TjYN8$W- zKk9jX&OUa`sV((gxk`2*SU-^j`f1G2&L8EiHVo7b^-1B|2MreJcqb%v-MK&6=duUS zeg<2Xw~dj|{}Sc&%*mDPvzEIRd^TqzxGIx36n5gUm!R`2{nH4K4rDw#iPSTEuc;G$ z(>0N1XO=CBp4rlonGgiK7`ibKSx7k7$Z+`9*B3851kXT1V#t$CBEX77wJxB~4C$yc zyH%gPm#3>eMN1{rk@^XE+bLi^h1fIn)Uw519gnZt34(SifjhbgB$eA=`X!40L zPqT5Mb7QYRoNCXa;Tr+(^Z8;)q?OF!e?%KQ3peK5i!nH&45X6zN4q{ z9_0?VEoV1;H(54PT|;X$U^Llg3F`UYRVnfm`?*pFbep6OI?ySvjFQoeHEerd} zd3>#MZL9Z+u!Nw+RTtpU)xBOZcjmV9c9VH^ zV{uhXuHcKv+no#27`8b7h_Zx0(v%3}s$fWal}kj)qlBsCUPMv-@aC!z<@GRYZ|! z3*R zf-P)54W=as-xyLn9qf!-RgmUPIT7M}H0Scy0o80>Feh;E$pB+6CE#&Zxil@i*e51P zw$!w;)Ri0ERu=W?coMSy7e)~Vzwi`Sq&9>0$oVQ41xa7K{F5(+HU1*E%1T2fULk2H zeNc{*X@BC>FoL?+V+Zr@i21&k#+?a&)cO^}Es&ac(_1Xt#dQDeGRpl9>jio7y_G-= z-x1TJCpkXBTg>-lbQp0qiU(mGEkBz$D#;+Ur^6ylpuyHIJytc-ca3A}uh6=H# zg^5?6lgi4paKR;n0b_?D1~^()=gV~kk%)gWPj-Z27lJ3?M|^jYm1iW#J$HE?|FnuH zPH#6TSXTvS1^5GY*o$zO>TmBt(X0YmtTs&9AR%A4GQD{iDh`nah!2y>-evj!i?MeM zvaQ{ch4(Jowr$(CZQHhO+qP}nw#{9}uKMad-O)F0f6;yJTyy<=eymtAbBvieMy7VM zTt;nBZzsjR>5T;0FpP4p1i12F%6-AP589+V_@P%c2{tL_s7XLdi+zENX<>GW*Y-$+ z794r-UOQz0^&EsXC*=X!ZG807- zp)6FMhcPoxTfjz7uG*6#|FJ-I8J)PSZ0!FXx=jiHXT-K>z`Bg|3ZToJFbcr>dq`WU zQmkklb~b=!o~`1&rK;SpxH}UAZUy77G&fT@4DYuQ5;xQEPF_n*YKa8j6scVm&McV; zM{>YhWM10S(Xpf%oUTOSs{_WYsvMy%aARkP$vvt$u&%8B7lQLcv=i`dQgIh0Hh-xC z=clTKI|;IT=~+sEDBC*Zwoei(N3R!oGJOl%>d0Of5NGM zT3;O8?w#QjTDFDO99}yCCKPYBr?T7+I-&9k!0KP=M_CW98KP}Q)_Z@FaYufk&V3U; z_J)0}&iMqo&ToFUh4c@zSw)86n{9(OcK`PCfb^dXTw+@GpxXABH+OGlE~>im1H=ma z66qD~Q@q>m<)8Z?B;r9VzvKk-3Z9#>e#H3;e&>#PzM0F+?7!g-lm*RnMjJY2JEtq^ zD>Vr1f$RC(1JwMC9OUm`sn3*+CtespZ=JxeaQUi!08fUn??^Pq2_7QnFc5t=7N5Q2 zU2|P$?cSH6ohy1+i?GX#j?G-N5M<(P4My2uD zfsvfqhEnqwjfnCc@naz|+I##A3&uxWvMCd@n8SDpYgKC`o05S5YIA`WL~r^@%4Ckr z-ZJha3ij~&T~PDiw5~u|_zkbJx5bPb7oVmP-Am#yn!nO#FY<-YV+6?I7M)q&@yteo zRs8|(C65kM_Z@Zf=|3r?Pgfg-viI!{3&+FWZ!Pp;2%a~mrW_11jMS8!JI(616deu+ zH`Ozfi}sZSLbLLo;Ss=!Su+pJCMYwni-_OiPySL7yJu%#c~0sZydkCxE}ded@<>>k zm9NBA1BKakrf5;Gh5r5Bbcauc>^8)1l7^GK!be=zRjDqo^^4$uf;R+2pB$^~C0DyM za)vywk-yT7mwAcClE$N>r6+Z7!=jSAyGbkcbO1bCRlCWSF*(d~1C*60amJPgKrwd{ ztW`r*T}^vQGB?yRshZ9=xUEjF(UdWJ#pHWjB4{?w1G{?R ziMa_Q!v{Lw3|dB5<`iYfQ~~)&F|bTPSs}Ti0N#QQyD(%Hz%EW8c<2XU&1C0@d+08wp>_?f!03`uv!1dQM?&V4@D+8#cLYGc3Pu;X>m84o?f`2hoZKjr z05@<~%}B9D+;`Dlg&N@KlqgeRFfNnW#{_oRRqoydW03?;#-H5W6n2{>1!#G*t`~LQ zl86|qmK{NZ&>05Z0^NQ2jY%rltVn~uP$^DE3ETV6;p6!}Jqv5k66{1TL3Wt{= z(wEp5!}+x*9pW+CIIFJm4TWkDZ{-@#kTIDSDa77VBUj%R4q-9UVJ$MC8*NQ;4zD=| zq>>0)ew#@}yJ#I!?*qSomwFWWj!v5&dD5^sAs?na|RX;rWS)2!m1p`km|Jf$Ptq_S3l^BuKP(>%RH zT5=0O#?Q|yl zCU%6lDX`frpTa!E2!P|wpygM1Hmd6oRtMrU;=Hjv1fcok!`dmOZH8M&t&udUO=6T6 z#qZS~w(>J_>@d!-$rT@FZ5_E6OMpz+*Xb9U8sMV=8rTj3nvcKh@{-P|&F3|nx*3(2 z(@7oeQ_h~(lAHi)c@PA#Lei9P*LIaYV~)+u-PYK8bgpVcYu3b7ZJKb;J~PQ#hGpwn%TBp=Nn49L;==3)oPiVa6C%2p5n%t=oM7 ztCwv+3|j*hvIk+S&+^>5@lCEFR)*bV-5LqX#AzCo^vrWaL`nhv*x~I z#)jx1+IEe(Y0Q#aPbSS481|rM)i3Bu10$`rGhLNzS|tlnr&8U;A#`lH8bRbDm$z ztc0SB8OhMPOfR6&4W-;AAh>KvSHoJS^EalXe0S0Pf?K2ft4Nr4(u6uXQ;xzQk9eN{ zJY^^wK+l|}#lReEC;&o;Tk0z1^wM9H)3A3)S>19X5isoM&0yKwOsU zS7(GH1d0W|uKekDM@wh7Q)gT+VPf4SW)FuH$w_gTK7WQ#u%Y5WpB4}MXbFYWkrPh8 zJC4u8TM}X1P8)HmlRs)v~L)|Dw_mvVp5JGa2xW?C@{gpuh^KVGh=~TJvww? z!LkB9GnEvrDo+C6Xe~mJm?N-vmZe8#7>2oPqr)qq_vIN;M{*{XoOEO{0eS-8o{|2U2UvxU z+&7?TEvPoHC|B>uc)=Q65CvocFzB|bsA;K*@hqZJ>h8dVCTVrDP4_oO7x2o?KjsA~ zS&i&EKyMLFvzMfFObvVIx%q{UI}8A#zA2!`_J_?Xr0(Pl>bmoT_XccI+Fh2iX2t@U zH$%xsi5sYCIL7a&3pWQ{Q0U`srtS%1AgRW@(rkkUKIeF+LAtnzQY|EZ4~YZG$sid2 zjYwq3JK0uDOwQkZ z%l+@ce!novS2)~w%1uCSdFCkuSF{*u&X{W=$_&CSafDiG`g|z6$r5$`u(^HtR6COG0lz8|nsTM4XxSc|MZV%h&}g(VfcynyqUI z6Ci)Meln0P-L+7akr1B-&EL_Mt_YVXpC%B>)cq+eg(rZsd%T^#PQFLsF`5ROoHYJDBzz)(6(EAdg=xucWN#TbGp-`1k3xzuy?bmn0ZjA+o(e_=a6bd zC@QBJjKqoows+O*ps-~dV;U6py_`i)E`fx|B#FQGF1!RvhTJoCgc5q%uOHV76} zh{%OxNjuH}T{4RJGa#e0+;3FtrnrM{-YpfFSopk7WeB7j2#m(Y@keZLvDMLikBWcMqV5X`>Y zMP?7jT8+W>6N{k@@^HL=z!zW6{!+)l3)iX*6&4F*y9~X62@!*MTXBj3o4%i6r+#(3peTQ z6Z@>Y?APnZsqQbRLreJWGz2#Wf&+{auh%5s+=#P*3RwFdwL_FyAfne3B-C8{`>aS*u9*&4OaLBJJJTp8 zK{}H(bMeB^>DKS|(CayWh4sLOre7k^tM$0k`K})GwbIM>V z1;*7RqY#%*dctBOgoyG7XZJ$E=s`X+}N-FZc3&SLDvN#*1% z&qVE&#a1C-afiNf(_<+Pc(ZFQ<)n};CelHMofAC-rbra6M$$V43e0+E9+{Mah2`oZ z{ZjUg`ID4VN=?fVkZ&Ju8vzL}8NAhmGUN_e>_2X<4lV9t8$6-JqSav!pybrHmqf&!L0Nm>^A7NcTN3-6=VY474|2s zHgSi<%o$9>FQ|K($%zjc9tirotz%X=S6WQ{j`ylS^{Nb6{r1qc)rO%IjI^0H9~bc8 z8MQ6FfO>ZB$d}-$JvKwHuB>IqclWHYIcA*LPY?n1=2k)k$hA�!!ybUdR4n8i&a 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≻pfc-p+kq>A@&EZJ32ii;nzX4TDQYlf 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
    gy>fqEPDaO`QF}o` zs9I@ZOerHjUt%Q5vJ8VkS)fE?L=;{Kt8xwo-r6Z!f|B{^gd^Ist0GNh9-CI1w#JgV z&401nO=G>GqG40g8k+-}!g{7Q`E78SA4j-OTx^{T=z?OSXl`>$EUN0eP;i^S!GIRMjTxQisMVB32yjm@<8(oVY z8vuqj%}q278A(>NulJZwGBeKLrr@%Fc0Vr%?hi7|QcywuzD9t8YInBW493|Kbg{pj z(iLvZ`R_gMzT)*ezA9R*P5h|PfzF%SZ|qnSNExJz9(`HXR+)5qZTJ8Q{3$GVY3=u< zkTJMX`r*u427(mpvWX-v&1L9uQc;djiFBj%-2tDBEW_wCt9ot>B?Np&JaR^q{9`^f z*`Wf!VhP7Q)=GyfFQ|&_mk}8KibfO$WIP>Z^%`~^iR$}pJk|tt(>H0vp*{Zj?bbS* z$KqeU8A6UQ4umMH8)%KP@`^-&sQSV(ZKv%7eOm`+`v^MW*oR0RU5;J26J5)DP)q>N z+HuSCE<}CwqJ14<^9=|lzyhb{uAu+o_^S9|5;sP~;62})@Q&{r(?WWQt47D>1>ser zz=;dv264rNMpdDuyLOY%EihmRvx%L;=?oS{_Y!B4h35}N%19dZWYfdGXQWp>`}mb&)uWlaz4`p5wiBq{zv!1y5k*j64Q|46 ze(wgjQ4LjU*fV_3=>J%TGYMpjmhN4@9VYvSyLV-;E0?_-~V9yihbbhIr#xI zyKaAI*{)%$s>ji+{12L`oI7Vz39XeE!%UlD{|%3~;g<_+E$(fmuw*jA6Iqllss*W{ zcnj6{IY6QS&b>Ezz8e?DqkK>S4{k9QX3KCWSOO2+ULKko!$te7Z zw76vRI~CQFV2Afuu3k2mr2|A!h-Brn5M@+Lww?79oamP}o=`m6Af5h(65Ou`a@S@K z>`JE@QP*wtWQ6duND4fRrCBcy_FfBAPwm;t?*&h_WVaFSnd>AODGdBAifFFkyO(c) zrYq{uL-J>O_z0oR0|N3GbkPs&sPGow`@@Z_nNq4YDwjk;2PxDHR~uV8raFI`$E>t@ zvRxG|d11aqWZmE#$P7$;km={JU(-DOcHf<3%iq=MTc7AVD%ftzLI*qd%up9dhh=y~ zMz*`u4Vrzlmy)pP;zJ9IW%=L#>wP>vj9~^CN?!E%2x}Zfd9_GPnFb5AkYd zxMhn0XJIUPY}S^*I}2aoM4y0LAT|Obcl&^x(Ro$Tr>dYsC6)yeA%i(cWk;wqq8cJM(ZYuoR++#>IH-Gx&*zq1~t#+->?)4bV zdoz^NK2_hK-jB(&@6-0FQ9}26R-FHt$a_>&x8$eP{brl{^$r`p;z?3$S45G7F6vSs z1@~Fuk)2ra(cqsj3ED79(!~<5uJgO8g)ZdX!oX_Q4#oYX1whnw4*#CFQfQ7C803?Q ziFW6jk73H%rb+w7^FU2xu4^^4wM)$!eiMo!G@pBi6`O2nN?%nyy;fwvm+Rw+q z-CLt&4&o%|jVbSwt&|H*6~oKi#0eS4u8hQsnHKI>$V4wC)}ueO!8i^3kHKHIib=d# zR?XQUr4Q8om$l`%kLf$zXu0rdiaT5dck`!JrDi^@Ow)z6=2Pr@Y6ib)eg(e9*L@>I zw3E>G=Df=qrrm?m#Ql9`7E6-QYnGeCE}x;`;Ms}OImP_gf}=p17|eks<#ZaFFju7g z#ztXV)k?P^2L148I_lLfggx$XO2vf*hj<1}&wRGgIj$~>cxDhU9j2b~&gq}Z*c3lR zdAc5xWLYw5-OCVvF^(wYc{YBwC(Bl@`>WoR`nV;Uo@p1=PnQoy(sRVRu<8$hl6Cq zx7#sOANK=8UfoWEK(M|Iq|c027qmyaXZf!7h@S&X=J0!DZxE_nEvb?>x$%B@$bQ=td*oa(oRPc4dbmZ@H8#00x@gz84AUJ=9u zy@fL3lQhr7DQ{prCrMxCXE`R~n{UP11tX=xM>}W6%~HJCE|L;&Yb2>?JBn^vI=MZG zGJN4cNvpuNEg(FT-i|RXf!wA|}*u#ljPI!J6 zz-g9{R?g9T;$AB!uM{V**ql2};=67ry7s>+h%Ixn(KCOV*sPw7ET>fUB=IO&zvR?1&EY0fbm3IYQ#5fC?Op)#8vP2MJSyIu*g2&P zDRqiWMYBA&Fb1i#9P^53LY1wlA@j2O-LGF=#OmF#ymr5^i7Q8^R?YR_^*x$8BbI)g z#a<6XSa$bnEL>xkOdTx{JsXx8vp@!En9G??M-@qw+@& zbB$vHKy?d=m;cD-}F`rg;3UJL4YnxYF-@{I&V2c2!5^(H(gu-f6r2s{Tjk zti&~V!82R?3bpD{eDM|S3{SsvTJ65%uuT05@w)VcFavw9e%?d1gsB?kyN|Pod^lD? z&XM{oY}N5uNjxtOFO$ee=99e2c?Q~phrhPvaM!?cD&RE&{MGcyG5j6&%~<6ep8TA{ z-@4JTdwltd{^1qlT=R(%^mVUls=IghE!mv-{Oym+(PvuYTTtU$QuZec=OK=VJL0>y<|W&0(-B zu$#HIxwhe0F&ceMZqXMb6D0b`?mJ;WjcKj`xv;;&(7D5e0)>=MIsH?8-WXlt!o6!q zNvL|FSXkvRslJD(&6tv*633QswzDlSVBinVP=wgg7z-J0IgDC7*p-+;GSySLLMFYg zIWvjQ%DF^G^begJu0tG9xuQ+i8^jRf@h6=pQERe!wRY-ma!P3$rFj}JOkTzeUPGs< z->Y@4;G~1rrnb+A_EtN5))xnz5~`y8>`th(Pw3KGXM{4XYh26rr|-F$C}+uDDgkp- z@9p8Qn0&!={_bNYR0>Ub!YdItNj8eSn)B~ggS=xG{X`Sek9S8;rAhft6Lj~~EK1yw z7o|8ly)npcI5c{pWmmYpPBm9tp*jd0yiiejS~hly{78^MK5dp@#SWWVJv8*Z&$Bid z`)eCVc9F+%vu`RZS}>a&A!|kFm1R~~{W6)>NzuX1{+G|OXZNZvq$~s*XQ@Le75#ia&Px_ zlvLPpU$AjO&QuZ*tS_r4I zd%Cw(9j-fqeUl>#Ro`%X6b!DNu{%Hx1jIa+nraau zj`4eSp~ zq(Foa_gw1(xT7u&NfEBsK2t#NeSQ9-LI|j{<=G+v0kM8Dv;V7{|9gY>|CI{y9~uf@ zvxJJc!e}2Qj|}boNFY>X0s?$VoxKjIU;;l-0@92N2?Ks?hUEJb)-%#^N($h6UGwi1 zd&T;GQ&z!mkih(2jIP@-MzB3CFN>HtNs~@tsU4By=<(upbar)rvcdcL@vI62I43{u z^FqsRsnP?s4bzt&N`?rEL!U~hb%3F6p;&J=>Zr~G9%rbD9CbCSA~Wmjuv5Xgrdb@Y z6C9ETT#<)CCt+=>&V(Qi^dS!N$rFsu{0Q2xE}UWgq5sX2QxjmVI^XOr(tPK>Mlmzb z)cR$$(>27}+E1NLYyKr$P%sXe(mtszNE&w+V%&oH18(q4K)gx}YH9^XOF(h4)~zN@ z_h`!5dZQ>krK;NUFyauak5(1}TpKzrk46K-^-!u>Zks8woYa1c&ib1g-6e{_w;Z)3 zq&evt_8ieHqBiT+41Hu9O|JIB3rm1veG`M~k}H%AhrM8c5p2kGM*(IKAfs99$S)uk z6HU8+BCKJPsaoGlsLxD0DmN$uFQ@sDJXFYvm(Z=7`u}6?ouXrHw{79rwr$(C zZQHgpW81dv%-F_^ZQGf_OmgzAwf8>zTdke*@AbD+H&v}J>ZbbpJY)1Rdhd4LJc=m} z4LtIKjn?`uII;|pXvdxtFa7|F-l zUu7t<=$?Rf6osCqI$d-c_{=K>GW3kgTy3W#6!Jy<*fZ~?n30r8#W5hT(6~yihaRA9LFdO>?clsHDC8&ADC0Qsz@?22AA#w;eQ{Rb-B+GF`3Ip*A zD(9Lhhk=VBKppbC9F-D1{6U`U6&%W%@QQHmP7d|tm@;N1dT5zVZyfEFF2I8M0vbb_ z%>{WYi7LwLAMinb>bnnEz6{8?{({e2SQ=I&^zl+!+WW{8R3} zJjO=3W^2E%KOYqd?*D^dD%*w{4K+DF<8azL1Cz}DhQ1B}sQTwvp~ZA_6y_9Hx--L# zL4aX7O^OU02G~c9bf}D|K4hqmDwX59-E#2H-InlpA=Pia`{B3V9e#>rg~<#c$h|t5 zAtijYfxx7*QkHm^7EdpVU~#%sjq#NN$&l#kRl&h^K>OmIG<0vs0d=LtlF8<63441_ za7dMyqiPGGxA_U#XzV+foxHVHKk)jeU6ullq;~PjWQ%nK9?l^TjnR02V;E{R)5}*) zis7X? zFt3TlJd0N5$G6@+-EQzq{#);U`HZ|OjO8{CSF%ehHs+-Z^vZK-Fv_rvoHo93;=~Ia%ig!vSHOrmL9+Ir(BtTRa=Pj!EE$fvvzRkVXw(rd!iYYzj zJ@));hQdg1#^%RaoaQs0v$kf>IXAz1f%3s_y!VE1ix{xnr5=#suM;ymOV((o>2EU(j!0WB)$-`CKL(b6V!69fMjvODzz~*0Iog)z3x|JWq}STIwYp zo5Jgj_Y2aS?Z*4`QWdQ@{UZOUVtTL+$u6~ET1t;3LGg*Xx=I)t(BR03CPC$yy{<(R@i0isID^76tUcI(x+kL2QzL0^Wt{9(#y*UUZ8eZJP=ig(T65Rh>fxQ} zOM_-9D{8ta;P`Q<&K6mpt+p3Y+Nzi$2I_Ab+5v6*{8Q+hw=qY^(2WbrK$v7HzW@=o z-!t*d-u#GaZ3I!TE!M07WO(2T+iJ%4XYwECkj;$9X4^tZqy!W3Xqj9Int3!!dC0dS zjB+tk<5XXYVN_dv^tFi?3R^)MHy9HXt>kUejlwEcG)Qt6eEYKgQB^h5g&||BY?P#t z4dp!x?y#R{1!{&e#k^|?;WW*(*ReL&5Tg?2L-MI+WHrc9P8^KFIWFZP%6CILvI0z~ zYBQ%Ay?jKi5BE)1e_otmS37yO6D(p_L|lKKsWX*M z!tpI0xZocf<-$MoN4g57?vshY&a=EZAksY>V){``L*dhjG_h3qXv8d_3K3Um^0633 zz)L&U!dsh+wlr#Dz{*sA#@_8Q**xvK;%_6wvO6|_+rR!IlHnJc3Pa)I@z@AsYksfC zgv3wOC}i*^IhT=4c4W@x{g1F(m5McHQ38$B_dq5Bx3SA z7+h)}3Hw$Zv9L4DHgcytpSF!#?S0n3b2~P{-|X|2^5is1<0z!_mS7B2BS{l$msqu3 z(AgW@GV;aFIEG}T5Oaq=5~^@3kxehvk!jx1JzU?G$|ktwG8Wi?1epTa!xee91A}RU zafr)BI6faKApN#MzrFC`-~fsQ>Q(@3K^N<5K#%PM0*C&bG3=+uq9Jj{7;=RQQ zbhdP@2j_Io4zMc3zkzvjUHU2H>$f6E*gz2?gtn>UfL|=?dy- z*j-`s;~WTH;U(zMBYc7{TGAt!@tNW$-k=MQ+>D$PPeDIOyEEavBOdX*pcH*7a`ey{ z5%w<8$RQ|NA1YcOf1(xu9W&rENM@QDK(+H*&Ts)PN=1hx+1)&HTu#rba;V|IITgQ>5$;Ut#qWce*6`alMg?DdO>nfc^>EmwZeIoJp-W3+}-pVC+%$N?$J2ys0J{1Dg_l@ori1! z;4YvSYb(#p(h<#iP!m|;Glim;Y;@dUhm|-em5LNfddZbK!HX7) zm5k-e#-0Zh_0Y0}7x@CLOq=D0>&5||@iWNiE7X&|px_K0nv0ji>7{bXnvUt5*zf+&<21QG%bsT$)Wvn55b%EySP8a)t1=YOKN#_hXH z9+>&ZR!BG)I8t8sLv}O=PlZEE4!Q0R!SIF*>99h_Va64by;RMA;DGg(H^(zJI|%U9 z7T=>Y;bmdQRVh@f70KuZW4S^em$P;S)eWyzsye4IE<=qQqhV0l3UiP0y=c$Ru#G58 zP+Z@@fZ>HruA%y%9$be^&Y|)IJ4(xRF(O~Qloa?T$8woJ@ns_X&Y!ty7GvgMO^~L` zNC?=t@k0LT_d9FsVo0NR^5!}~-+t4xefF>y{T1!2`<8=y&&9=5g=(URP&R;0d&Z}C z5^Kp!f(aZiA@$<7MZ&9J+fI?F7f!W%P8j@p<9!Y9yiy6yaXrp4PI0&0aNaGh?GtFv z(ucd$+4f_|rgJ{qUI?V=`o zE-9~+i&Ee#8<*H8V{BB%`>3m8d7U@Mt2@4|8~^kZLChDz!_A)Hy?qI4u}@k?WO;_# z=M@8L#!!rfh%72@EnXWJqxeG53}n1$Y{ zEp6DZR`BrACk&drvxEDfWT$%Bm0p-A^hN>eVPY-#Cl$aNC3^eHx285~b@{@$i_01^ zWwK%cZc#xIn!?oKtoN2_9E1J4z6RNPuJcSykCpvNT*d07Tkfl)@OjOnbj2mWP?l#5 z&}ZJkZ+y6~fVi)OxUX{vsJxate-4TfNy{=K4>PYRq~Ay1il@^+-i5%Q`n4tk$wX}< zubG!#05w zDSe~?^^|b;&aST7+jp5#Jjh`hY*P+0*X;$3V#M$m(~x0!Qn25LG2EE0a>)cAfD^D( zQc(TyAx=i!Glg+>K0sZ5sHbo~*nb?U22=*W-t5akcRU$^If}A5in=7(u~W|~u)9rW zs+sBPfA<`4!}kqBhtlN8#qM$>M70yEZGZ|Hv65k;D?FkX3vq-j#kOYLfH-g|GW~`9 z2UL7(Hx2-&-}<4LFpq*9_Xc@*Rpdt&B!l1&Ngx?S18_h)!oC`i_85RR{88(N`-HB3 zs!$LO$4vlx!ai+C2Xw$~u^(;7ySN}8 z@(B9KA#W*xd@=z#A#O2&d{O~AUWE>zxN(E{5T<~*>KW85#LE4w%sCP1#*41W1->ZkC1fpf9}eZRs8^%Goj_K zho?&OA-h|_o7BLd%`R%eonu#f1XSE*LRJ`ILt>K{#uXC?>oyZlOxw2yynDtrSOa^p zTAAUMwzF4Cj8MtN8`&f{L)g90{Oyt(BT zN*NyY*UB2<8|#AZ{^2GEE4^t;{T=VujsM?Uv415E{|Aen|LM6Z>-oLv`H!Xb|I|=T zelL2W@G?8%xynM72xw9KQkWl-tVf`s5|B^`2$om}rP!*^XfIkEZXn*UOqn$Rv=QW4 zCJ>}**ad!}7{VQGj?yBsxz6TfcE9Fy=lOhkAC(6{%jAO6$Q8s(bA?iO(HV|}GHr37 zja%ZWWj6T$mIs4bO2vPqVMKVYZMNy%`Q05awvys@NbyGjs*V=S9na$Od9S(J^F&Xs6s* zew(<;K>|7`G1x(bxF4GiVrb&Boot1}(+iAKx+kT0X|ckSP$_nXsK@}!Q?O-)=_0c}k#PZBSYUJoqxRRG zXN={q1mR=jq~#zx4A6ntSmhO^>e3yPTJoZ@$|&fiMLm^LWI1<1a77##%368#Pm&N+ zFCb7abQqndB!n=rE7ovM(I)h136)cx0+GU$ijIjm(eVFKfz;C^zaUJWM1(5xlY~ue1{Qf52`)}~eQI%H4QAPQ*+qup# zw9p%L1|pGwfZ;`eh{F&L$C80D0{{&SyqlB3!eDxg&&8Wi`RQc%ik=uUS#MaNDpaVZ z**-^=_KBDW&90TZu!Sj>o=&9Vc=Pjj?nBOsyO-bFN!ASjOkYePY!a%)Fm~7GF6r>( zx8IlI)b2FHb|g`tCf}6knOANc`)fPG2zN^P2oe3mpVqM-(p_EHBQ+FQ4C9mDh+VVq z;9WjrrDhnDhQ)*Jv;;RAzd?*DT%9Lz#xkGJ`=;(YQrt#CnrWG}>p>P-nS03y$RwL< z;&i-zT6Mx@oF%o|aw2Oo=e6Af4OV0~aT(ZUp0QdJH%8u})4GLmn!P%(SP0@=4=BA6aZCiPz;4*KC7Q zEsI>UrPPt7G}N38j5HoiWld^ERpm%$t${9#-*UFA{Des!t32A?O=ThRnq(yvx`Fo7 zCweVh&EcrjUgk-DAUXG@liq^YbcZ%e-DFDz)+j7JDc?xlxf0Va*)?kfE`g0^;Qymz zT9~Fm)OtEUJ^fQ|M2|N+!hiB{ora^zWI^qGy+I9b;!Kp_Op4%B1=s217r&+0i4!Qf zt?r})=Y>?3Q)-MWM!m};LBRou+?fYp4i}dOSIjkonoD({$Mzo-c`hc7GGkn8u27AR zK?hBnU_Po1f>-l!YK0O70*AB(8-R-`ogeo^{K` zbhbjwhFWxkdq{9WKbmt5e2>soD0&OEUSXdmZo;Ykca!hQXXf9-(G|fz#$3S}9bF>H z9d+iDIFy!>IK*NK3mhShI>b8jyQg2ECX9pm#c3s-@Dq4dY>21A=)bLQG}K=wA8Ov+ z0_^*XwD6eEjjc-3*A1t7Cyn5gL-~$JQP|CyO)d+ZDj{@KL6%{AVDJ)~tKt+zNw2tX zQNEq~Kr@rWrBQ>F9=hCK#)hfj43nwE1_jkly1k%2TR{>o7c#2&vi>B*yCseYTb#?? zd#mu@&b*iBp1)(U0xdKzLFuTx`wNiNdYylu_;2AE{Z_tJ+XFl4G2gGlDZg zA=HeZswk3FD^gv~S6&{7cg09)Nc@~dBhDL^);p|0xe<*<)FOY%W8+h?m z<(2lt$NG8gap8pFGPdAPr(&SP>k(+4Sj3Ic=!claChTY? z@bgRouxrrb&nXB~w8#5KKy`|2wCy2PEOeWJE4+sn90!Q11!yz*lkb;ZF|`WA{}5&o)~z}8OH&dA>NFNNm+Hn#icU7n-5@g0he@%5d-H^~;l_G;h$cIVZ%_vW|n$z@9~y)NLd08UI=476#)x#+RgAL4&J zSbivCx?(&S^GIBXi!u{t8V_8y<3|9HnX(wjOqKmfhuaN~CgV9CjgEfeI2)zp$NPN% z3C0jC1{0(W+@VEr3nWayo<%b=>l|gcRWS$p6un+hC02T1;S^AI2@KP-X_H!I3C6ZB zW23rY`Kt^w(>J~!+cwKA9&C!mT!Xt3)2Az4+R0i;_PiMhk5##nuSP2~y)!B?XKBoJ zw%pQ`Yq2YH;yyMxV=_Z5z)P2WG!sJ}Q?kjT*wafQiyfYmCL$gM7m@A)6i{{vd0iQ( zao1%iRO78>z<|!4p6elLvC?vX2dA5tr(u$%vEJDei}u%;3?0OJ6~*4PLzba$v#n|d zO)m2+0x18AXDqe}=3;d6Q7ovXky@D|hq)#7G_^M1^l_?HR&qdU)~cxX0=L+vt5DjK zN+dee1~)f1=CkOH7{_SuiA|YBN4TKTTz%8#vXbf}T>u^VRAI`#aOT+Jh-$nWbf}4Y z`U!2Wl5H;B9snMMVV(ubCDOE7sI6*>Sh$wh(tC}J;t-Dq+wemmH?YSUd|t$cc>paSc)+w%rn z+5E2MFdHfr^e_SUunWVm(kopsf;hMEjsKX=vT@{L!?EkbI2J!5q8g_398_ebvcj3D zXuF<^@cGXN9J?DNb92m&n?E#zrBNq7bg~h zg>MZpHnxmSLUC6iIS@K^!htxETRV+NB@*E0957v(4fP>Es~W;teggwhLyUA$$BQcK zyUs~D^noyPhXTYBM@t&Gm!;!tNbj zr-oeX+NVH5fw&W~3FWe^?NYnxfaTCkszk&sgD1RYVe|vDzNIO-RoB7HKII;G}_QJ0)w$=`Fu@CZ6TqUCyJ(;MRUK>j9fv)vcZ2tl9oqk48~f^kO? zU65MC9KtMGQYxb#D^LbNU6NYjd%_~yvm+TB5uwB-+D0CP#!53B+Jjxyw=j;b>!=K? z9Rc`@u>NHC+)lDWMyen+w*h_hXde!K!SPP)>l1i6PvEec7L?K)w^&WwQN`pyD0wGX z_{g%Tjd?~$-Evd4NTaNo@gh;y#bi>3*M~mu|xo)oq z!Y6g~u|l1iL%pCQ?XO@xjzkW`tlpq>iu)w$JQ~w^Eg*FwzV_81Qu=cLaSi;+348;# zzB7mQQ3mZ94>4C^f$zBW-UI=oH~xU(C7)K!nfQHLm&pRETMhuXPuPeA@UH9Eqfrbp zThmtG78)LxOpAP1utVrHmI2C8&xO^A%|Z{yT?SSWI(&n7Vrn`ATe$O&s(Ds#W+eDq zn9}$kC;j)^cVvbTpso0~R^z{36yKlzKTI#o{+XxXO#gqL!u=2Ki~sr+IeCS@$z4*E zcD@7g5I$SGFH%}HRQxDDMfy5+9|1)s@2b{rw0Y}p8Z@3v&leYgBxPR6nn_u2>NXlwiObp6uA4G3; zz;9bZ_sf=RAE-!SRY(xXma<>N9%NYHDV7@yXR>OeN!U;lNqs-f0!GuZUx8lNPYiCG z1X-d($J@@=**88XuI9&az5bt|0a}5BJ5Im~jzTX|k?$Ud z`Dd>qYkGaabT{u_eGRn<%^9+CcWN~^Qa^sI*wif$B3#7|UMWa$Hs~5K3}xcqbsT^u z$gkcr*w{#pb!oI_=YvnTc&;k!trh$7Eh^JTDsrBP!`pRTZbcbZ%AY(OuS!wu#4&AQoHO;8_e0sqRJIat&@3oeprNu=@}Ig;EbP zWF=UK<>D`5Wpx{T%c88M`mKG^HWDtM?wp(_*Bh*2k6Nv%v9(QVXyymDVud(qW_e1r z7P5bDwOV;v7zNtk|#0g#|K!qTjmF70@Lrq z4C>HlfN|Pu&lK*&a&5wNr*S<3zx7PMtjDpjh!pf^KZT;v;#Tc}(d6^CS0i_c^-$;cw#AIb;(>Ji8 zDJfU{47@c+AYgXNI50BDtVc4$HWbf>3pT>Kp+hAuX{E?RXNqA%mhrIWm54wkqEvCn zsM`6L^nuUf*``=^MYUYl;r?WnG>_akUhd+!1wP~JNv|tJQCE1*hd+4H;=maYjhjTd z@|4(NZ}W;iX6Sjh(a>g!F#CXj1^T@B&CZ7=9_sI7sW9;c<-w~Q7P&1DX$UvLoqJu#2n_It|;y zrNe$W2kq9uf$H<2*uVt#@}c;MYIZ-P{I#8vJVV!8@_h=p{%t$wUt12If8!z&b#yhf z`4`KnoFq;AZ>{*~SJtHD`Fv2T&Jl(AzQ7igqr@))6s-g*sPJTo+g8Uk7wSXICIu!1HUmbPFrxTP+bDwMp5N_$aRIhWGRr>n(e3ChKe3~17U*_P{oVB$4~z8- z(`_&BdF?tkFV^9?ItL=`7-d{URaPS4LR6%CN0YJrezm+hUtdCO+3hS?w$W~m2 z1+1pR#ewWGvHE9mD8rsbm~CE!8$`M5=x(}8u#le}l1Fjsrx6^qKANbQrtioLWVO%5 z!eH8c%1$<|Iur3jTs@&Px{IeA4db;0T=JuMN)awb6{|a!-1}`&wf^C77z$N6hyT(t z)*QwzPj8Q=hFSTNuZSS#sMMPzD`l{qH=vo%iL*AOz{8ipb_%afl#GY=VJ>G~*fg5F`!RR7yOO~LZ-5i zO?*Mr(DDHUSEMqeNmThcT z+o^h<9$cQ!5`Ju<1R2e=cj#(5Y%;lHay`UqPn=D5G>kciD$^xlUZoDh&Z0QwJTnMS z`CQ(6F8t!1$;UOhxJWeZ8tS$@OB5`%Ul8Bp<&i(8pks~ZemInN-fn&!wDOGYWPZyQ zWgqV{R*-U)qRFvNbFAaDpF6tZVTny|JyWEO{GzVZbXwMCp@t~}*Q8ak9dzFGs(gLR zC-w>95_;RpoS{FX_L`Z$Qo5eoL=uEC*Hhq$O%}y_?pmmtq*jg6Lsn75&(OJ$GS|Z+ z{g5^3Ekf^H08h17XGhDfw7#WOUM#ci{n0530CTnBD1)pa**3DN)G}pjf8Wxd2FfPv zWtLFoDyqgSUcy$t=+v@b(RxtftkY7JS|TuP8wyu&)7G!wf+_Y{ViI^+sBukUAu81` znGN-ws;nDL{r%7!z8EISEf~2AVur$9qfbg6A_ogX}`RTxZG$RZjoah?sp5B2m&kfi%Swt z9&wx(vequ605^@qqp8?X35f+Tu|m;`W!9R7@(P(~4R#2~L%^un8Tbxh``w1|>>hdO zt~r+UsHvDDyeb&8j9xa;U|gW8;V~&~0JvliI@w480i{)WiDE}jQpZ%fE_5+cC`D?Z~sYD)u?MaqkI>TUX70?7)Th22tWaVKqSax_0&;NU`C+d zE7$$ukvTK6rAZmr4P{{@yOBWGlR+gfm1y)<5mG{yDK8|dJ+I(@D8EVSYs^d&At0@a z4(&YWo*SCqx#M|Xf9|n=knqJC;O0i;LzY#wpC<|TZo&mKmha1e%o<4yJ5$Ys-uZwa zb`h}ZsW{RFrsY>)s1<}UBK1o_pcWZMs}h0|N8dr5L_o}si5Lt-5=5n`u2MNs;h=hg zQacT>H9zLpJBOOWx!@}2XDifq4Kg{$nsEhbanV!BeLB)P9^Ld#pol~(w;pNCxTsNt zyT)0cw3uiyk0y2x9tgR^QHEpTT27*nha@$Mp|F6N*f3_6D$Ku&txXJuT5`luOSDe0 zx6~V5LzqeHYhLPPUe!G z&@G_2iEB+Bfeg#JYCmfzOgc2s+is`!SM<^_gn42gZ$jM7uQc^;Vb% zS)TL0(Zp_f2JxLC;_PwQLMUDuUl-c2-lcN=`Q@KK6&}2i?6;+XFGf!@Wo8K|E?$%n z7MFT`0kNKkQOTqS(opMoyJnQDy(l>3rcsh3VFCB3s$HnV8|~HkVYMyZwJqyz$I#LhttSoQJApQ-qK? zkbDYX0x^$Q3toRWKl#P9)CNPo;<3^c59%4!Gm&F70h8*DA*I!t3`!>V!Dc^}*;p%? zjgUT^4vuID_R<;uk^!F14KUjgaPAXu?iYAaqINKi&{6eLfND*Sw1f=lmUf-=w* zo`$l>@8V-LIBr%{q%o?)u+}~{&%3kMX)n1q#YZgC;=9U*WV>L6Zk2eurp~5w(;Ir_ zZh|DN9tBG-NO+IA%+GphVhx@SA1@tvB3)DGP`^)x4MVcsgmqLO`ANnYrBHZ9Hi5KZ zU-&1qsw>AB<_M>ZL#_x4T_GlFwLhu7EY$51XmiPKfa2N;K0xS?G5M__&3PDyy&Q?3 z*cuF#QOd-Pf;j@&s;i3oSLB$2%^FQ%n|-^ORYRr&UWk`U`ycDqUp2?b>pvzRuPddC za+zTNG<4&~wR>gx3ejle-1gVK?s|vo`hipF>e8hpLTReZ<{yJ2X>g)MwM-i=+1l%# z)K;`d6Y55xUU$Wi@F-mrIQh)#HD0cDU$`6+)71hagIKO$Y z@SVnrcc38=QoQy^e14Np*7}Bq73wGS;i__fh_>83oquO%RJjG>BYM+IHpV_|@k@Y_ zQq}`U9^n>Z!aM{n_6H*68=mSVGBb`yYEEk|L(TZqN@AtlZW9aC$#EAgQDC= zDJs)D2!NTEf2F8VhGswsh>6v%px$}_g?Dut1W(%Ns>Zmio&Da$++2bnOFM@;HUb)*% zQ9C>rF%GgVF4yncnbL5)P@vZly4v=sF+`7w@kA|m(|j7#P#rc z0kmH#pg!Yzo_pN-he&U;<8uJQ)-T#YijP?xeC4qr)F-N&tPM4&o@#h{0 z`^@e2GwkrH_#j(ggGo!z7$`@bX7s)mDjLVYc~T~@&4>{)?Q{C1Db$!D&qZ(UXa6KE zV&qRdEZ8{jb#$BJ8t#ArjxD`SDl`ZA{=&$(yNJkl4*~}h@}PGo zpUQm*FqJOQRQ1_O@4g`7G8%U6#I}T%IiA9UD>KUu%c+N8N9ZE!V2$OEKn!d20uFEP z@E@PAMwWJs=~?&k<(+R52G;~srrC*%?6 zCX~<70jj!7{b&l-3j-P30pfQo`T2aq&%AhEHF>F6#^_)Wsk3l80vnoL76~M02xhKO zJfk_Yxp!KtQtf!8S<4ZNtRmsN=$H6GnSH=6@MQjynP-Nbcvl?cVfFa1Qr4nhVB%(U z{%jn{5ExRgrgb`&Y~~X}?2STZig!&M3Eu2lsgWq9B+CP%j9i>jK>9*Y_JCP9jZM0n zcg!)wH#5yyZ0aX4o1`0R7h#fACZ#W4_?umwdAV97PFkkN^pg{wLA`zCHx86MjMYw& z`8)RG>&LE!8FXDpAFjc6UKh$Z7Sc<$rylW0(UyeJlq$3J(1t0l(N=a^^??Vs!Sn

    zdJ~vYP5vm8YCZ@qXwNq=)Ef*wfpu# zhNN(f`*Qky5v!I3uZccA1{u~CDH!$A*&>yfs2g-VTVIcd*n(f@F5dE7)8;T2wz%-X zetmHtj|}5vh1Wuxy~#I z_VMsVOvY`cNT-cMZCaMi+ZUG!p9U+ao#c&pn#hqu!~Cg!W>x+=<$&bcpr1{p&s?A$ z+_Lh{!@nokx5BW2e~#!@d|w*cm3EECsybtz88E|;O-}3JiV?ok(W+@Ow_c%b38d61 zH$ZcSiTSz+=y~gc2yN;80t)3EP2)Q4NJy~1+Azuhn-B-%JhbeM1&Yj%wRmKrILJhm zGmooYNGF^X?bsq{o_vRJ6Oo`7@t)DV7%Ji;PxuX4v!u^0c)Uv5Qa~!S3s_>i%alWP zKrnR>DeayD6^G0MVQX`|JtzO%{wvjZCaxQqOa~hJkUoA)8IhU}jKW{=c?q&h-eB}Z zrEb3G^pyRdp`I>Zf|Q%zEV<|Zl_mdoP$Xt(<81mbJj8#Y$c8VoxOE-Aw?zwDl2TU$ zMktDCPKabk$SS`_w$+%)w28Pgi|>*DMSKXnNN#rs(|Fhvt&OdO} z`F#<+#{u|M%MeCYksj8o^tB+-4_$!LpgRZ~uqigA8mbRRu+1eM0|VYk7<3pGlB6iE zr|d}_fzg}1E=;=XgG5fdnV>q|LKDXD@GVp0Ig_!cB_7NAy951 zRJg8cK9d5IGN{pdM{itV@HUxlb}3#jGL#?YZbY9?+F4AHyMZ#PYN_qZNQLBxIuwDC zcj|JC$Ai0c5|42t%x*YYIzP!RL|a+3SMK5*aM z_!Z`s&_14)Bn;+>;-M#isJzSLV~m;XxIIyNHOC#KDJJ*e7Gc4E13P3*^m~x`rt9L+ zaYFK#w(#j#EiQr6Nz~RV0%Fr_jSI~}bwpBQNK^e92RjaWF@lXf$@eLU*Un{@5q)$H z64@>|DjJ>gzBAl34LF&fpwk=XhIVKUa*3LUp8GB3A3mJNZF!*^-ykyj8;Jh(DAM_V z(nc$rI$0XpSb7=$m8||BP4++A=@vC>dz9}&YR1jIY|AbHO-nofhe`ic2;EVk2Axz? zijiePV+plKhFsZIpPN}u4y|rwKA|A8KSYH7khZi9Py~i-v`Ep2^bkf7qn~PT1tXui z8@FyNI^78U32)kO-&{}nlbnY;{u^CTguzL|>i#{1<-)S)COuGbq1yvVP;p_1!f#U* zl%XRte+W~KS_6V$1|%mBsq1V72PHgZzM9<(1hxG&CLZt>lpsPW+F-&{Bnyr8XbKEf z0}76k-R8c?W;<-FM*X&hP}7l4xWCw8RNT}IHgAI{4D+S_;vQ{+_E82{^E?4v7sHfLKS2L5R+0Flt_3 z@98|q<>##|e&4xzwGUZ-=8F>0i{6iTxr6XGDy*Z8O+b5e3yW8=#hG#!D)^_ZmkH^a zN-c`KrJBaZE>TPwi>#KZv9RVcmKm|0?Vjahi6V~;G_2_1`DPcDgX5JJ!ZUltRNm#7nYoD`JTwhVv3*)MEappDj!KwivxK+lA`CJCtfE}HW(5-? zKxXU!yr~P8rc(t%Okep{jC2>g#n076H*L18+9DF7m^ZEusP?9`{KnX^x$k)UVrfpo zW?STE!rSEIptGT7fXk@BD2+d##k2&K0D$g9BQLg{w=;{-XGDDG)kkHMpG(pJ+%P+5?#lWqzb}m@fLPUdP@|5C0_>xnnS+2uXls1e^CQ(E>2lK zQPJ5nE^2ihdDp${P#*=6vucDR1_?g|AoBbn0VrUCM&Q(@SxsZtbq}9jgtDq~ipa}0 zm9Pa1jd9to{QKUW_!>iUds*w;y6nJA3%BR#;;`2OFDBY}DW0#|EOF*;phq`jhv&S- z$Y$5ugx05glq6XKXw*`aj}XS&H(G%Y6b3sI{Ea_rb0vJf7EK{zOROmm;2`g_$GB zu*eFZtv@z8Gj;P^CQ@hKOLDp z{F74MOCZPjqb|O0#pDAFtB3T>{jeP}%k7|fa^5b{?ZnbO;0@jKH&uy@K;#rSWt$;4 zez>E(T9DiQjmfDy!yNoRVJU4ti_IY2wdJ)9w|SChloHX*OnRk{(Bv8)z8E&LW`Ogf zX`D8mcSBqeO`1rL&iRhelemVSsx#=-_l(qjVJ3qc8!0;36&A{88ND+DLN{K>gS1NI(p=)iqZociz> z>lQimUz{EscdnA4_u`IyDBQS!$9rCn!^Dz9h_(I9?CczH3mOmhK;e~dZ%}!Mb3Y*P z@y;tCi4(=FoWb)Sw2gZ=_V#WTHvr1UifXSytTnJ;{TyOBsY|s6rfuMbfTF^O|B$1gya){zApA&?=uE+fnf{r7=j@oAKA8Ilxg{ zYE%;gm1Zf^OoG9F@I_)O|H)MU{x&i0ZuO{92CbPtDuAe&Ee=Um?%2_bncPtMXQ8KZ zLV0T8ooWW5P)sumBYHpa33kN0{)2vurwJ}$Yvs{Y3mpPzQwXlDqEEM4L5+`SuR7JF za#W>WxEe+@NyKUSnEVjlEEz9BDNDx2vLuC=WvvI`G-tk89|GNxa;e!>Zn-9IOg;wn zvEU)Az=vwk!ISU)7Q_iry*@SZVx5t2Q3E692zWJsj$z4SzN6N)?i1)Q2>OCwRAYP( z(AfVrK>Jr+KG(kiL3ImD8`Hm&GHTlH$lugFnJx2~ix;#lZJJRe;CwS#ez+9kaH^5D zMZ$dY;)RP-qFlyQ@J|6iMSUL;eI2UaAL#fB{c4)hc$$;uABdm8d5gYgWavUtQPykK zxtwVqSN8g|Q}+H}_tZaF_>yknW+Kwj9rc7DppmrVQ5!J&K_LxIh{qx{5()NnA%i^X za?EZX_JH|(Rs(Wg%7LL$UzK7AW<@iCfg+LA@+CEfMG-r~6Cs2J;-+b2=bEM(Sr;_Y zb5RJUAWpLxU^f(D$g582tlvN4fO!Y!_4Og+o14%ktt8LGr86!mmyd-?z|ELaX8pf7Fol-EFuRmy!o?&ZaX*%0= zUem3q#%_ltXtsPw5C~WA}&Ra?)e~e-a1bI z%0>oi{EAZ7WLnXjvjG%u15$NLs-1wS5%nwg-nnvRt~Il3ZsVR1 zy`7#d%Q{rv{px$7;V08nN;^{3lNeLZDEnh#mPOJgqAZ1A@}E~kE9Qpsqom^~o@V1YtWX8z?{_QJ9Rvo#yjMeB*r z_fHAI>uO+k^Zl8T?73Y0Q+d`xmcfuGmVC+V8PwD4SE`PHLE)$Zx(TVTBWdON)zlI5 zwzl5fd5yIp)#1`vEmZXwh>+P7ETB#Galba;H51JTEA@uC5JKnMQxDjTYl{vj%W||0 zfXaoo>UBH@c_xz_Oea4GU(5+Az?(HTghW~8b8kkGM zFx>c^9S7QO!c^iBq1caDwLiLqDetp!a$k5zDNFfgb4Zl&iXZJ38qUwId{+TOVOXxp zHl$Az>cyq*=YSmD>+@WKgww;O=1Lb%qu8Z(J*^t4ACCYx;9|Yfjusl}s8qpkO?Q*F zxm@O|)yTqnNF1RNhU zZYxGiatR3Np_Xw4F{D#eHw+}>@X5C@e5-fD41w6+d zN5|#fPo&_t1efnj0Gxc+JCeu;MIAQ4?Ds0cr9Xe0>IZGdy?l7$GwDpT-;3tl9-*(5 z&cJ3$It=_7L4Ka|jCr{xI)5;J0PAm(!FG(eiRodn-0=QbGnr!?qA&?B21^w^hcTY> z@tf^z4s&a`dWdRADHmpCVH^8I-=Kv*qGwtXAA2?9ry>-l$ZgpU-H452+0Keh5j4Ad zSHz9+G(TZC0^5m!&L$!=;V(o_pH?Rc@D7GwLk_G1%}v2ybHC_kVdgVbVA?1x`Uu`$ z8tXa%OD1u;BwHl|(b#PB_sKGTcFib%;-8jyU`O#04qUepa!VbWr9|*NqAZp^FhQg; zm4p@-iNpJJW^|TIE>2ca~sn?moWT?7?rQ23vz0r1C;M_b=3q!&@bUT zmoU5glFelBdQ@aBQm-bKdioD}tb?sw2YoI!D!{xu%(jp(X5S54S+#$Vz~bKPpJnjg zr+c2QKHokUGJfE*O4Qq^2Zy&rI@4S20}98muNQlt6Phi=Tbg@}Wss z4|7jO$aN#x;^{t-$fK7%f(MpK-L7wlv3f{1KGq|MQl=q@tZWDPk*Em+SyoMwi&dTx z!cGSYeYl)O$EWd035Emp_giDT>29W}hnC|UGWgaSFLiyih+B^y6vjQ$qS0lHhk>O!gI)h# z!KoEAy@hSz`yPg!$o5t2t9nJeSJL11=fOl5tInp?xeq_=1$Fi~@Fe~)KRv;?= zgw$jr)`o#-M1WVo7JQ=wW0+HmoSHX?69`u$BpuW`&5+{D+NM56{|W^yUqp{&E0%H| z0E-H_V@@1&ye8A>RF!QI5_0%XX{1`-^oYV5ObOv$Mu7Nr46Q(Kx6C3)bcJiOs@&0U zahz!lzx(Bbi<6XF%2--+N7W602L68lH91=+IcKZ?@NxaG;%QZV zNKvPnR&u+nB~jvpqS%udDiS2I09X9cJ58qFXvj$XE*JR?+BcYpUqciQj{gVp8klc-IJewfstX_5F$y;iFtC14szs{+whlUTNJ8O&X+cbY7cdo$!6))~AE-S&Rr z(QU!T+4cOZ+dacrgLGTbmqg0%h}o1%0p){e#OKts<@~EwqnPtdVZ!YAyeDSyJ z>sm{@J>EZvWJ*Hb>>dbFcK;Poy#EAI{}oQ=u}fOZCATeg(JF@|O5SG05-K5qDiVkb z4TCN+1y(LbU!FF6FI-`^0#x&|HsXjLcwY#%Qe@G~kbO?N(|PZ=R~${x_bbl%KU`Gu z`SUTvD|U!tB@MNH!qTN{YNTT#D3ut_D$UVIyU@Rm^lM~fT4d5sA7DBhB2o?NWYv6p z*gD1XSE^ZEY+tom!O$>IDLNmdoFb$e=jre$^i1lOr-R;ykSr&j+HHWj@_E;yZlikD3+;3WJRhbx&9h{- zt66|`!syGC`K+26^AAJS^p0O0OTMssi~t(Jth zzg47ay_e3ITVNM(6@|3f>d(cMhd=h=Y+iAkPF9c&WovjWCB@Ol@y&GaJ>JMI2kxfQ04=;;{FtZcmw z0cP2`QHDI`azmlud_$#vbm4DAUV|AW7vP6YmieMkcYfKPosI#~E&2((F$Zq!%v{e; zqxU}%fL>c+&gR!3AK*~tdgTLV181PI=O_i_}H$Ydk7(sR`u>`#62_aoP!y2%JV8 zO!pN<`+u6nHE3hDymk+&Ohj_N4@Un z*Tq$BL_~;>e5sj^A1iW;u?-_HreVEGBBPwiMlcLEO$wRW7z6x9VGqJv^VJWdhcv;q z7B@~){A8lbI5H{tr;*rXeQep?YjcSa*|c&}zr>CnS%~$XaEUVUZ2?7fjxs1B$O`Y%;Nc z2$a+m=xi>$fRqvg_!bdGSX{*Kd2qeR6YB(|qp0SQN-0s2!q976QSbs*)D*9P8P(e4 zD6J70dqRRGxlO>$mbeo|r6WR{%mJ#Bn;S%ic`oa~mP7dG?gY#yBvC5rf;*f;Ev0PQ z;3?(HwI!56ldwKJ_Pgf0KfMvtNcQ&rpdy?VME?GdH{$QaPv9TmUDVCc*zONe|L?sc zWnEiT5b5jQug+5YRko#Gr}Yt!vrhz#SQgg`4M7kwA+H^=TcVJGceMJ`cEEeDuimYH zp6tyk;TDKU;J{2?DL51Et+f&Er#E@tKab~DeBk?K8r?;Yg`_s!c)Af8#x*z9c&wBz z)XOGi9*=_w#iFueJ8YNbbW!pa?+-BKQl9Q4+7g`EdsCq3?ca+^B8+4~kZW69TC|$0 z#~wl?xa0Hb=*_$dJi9Lr`gJaiLcRSP##kNp^B|mXJ!Nil5PGbBo5oYpo`|e#@v)9D zWHtARt5IV&FTbdgDn^l60P$D4I-Dy+`U8e^8<9hES&}7XaNv=7pe@ip#EI*oeht=L z&)~PT-A)LFAb)qSf#J`n#{KK8eZct%nn3NTX7oKpbrq&5TjP1XHAAmNcManoSR5xl>Lv^mAsGxILx!qe5Mb0 zH-;%%_t=-KUIyVi4LC!AcGDzuvLyvDeJ#M_cvm|^3X|En4~vF*F8va|A9?w*eImv% zr0uS;{&==WV}v9SLC`z>%T@b#=zaMI(33PWwsA6da{oK>;{FsN``_cNswH)%IqENc ziswhgbkV(|rCLScsX;sE!Jjx5!w=&}%dI#dU#WaPcwZ8SDk*$ghxiiuQ!vz&QX0lQ zY&JLp!0I@5{xY7D@{{*l`^QRq`Y=b0IeY$K2!@^LzFs=bBqyCYd(q%QrZ1oTcWksF zzz;p;Eu*j(aJx54&Jl&qf~?PwL@oB8)4u&~kPRlLpM?|7ZXaxDJawor{c>mpN2#OF zHG`%v3(2#i#O(SUf8;Y!^C*301#PC3Wh7Mp^)l8g}9x>I8*NBQZ1rt?%@e!2x$RA;O84x?48F zH`%b^5c(sC#pfM&Ifj|YM%^$I^9tZ@>Kl_?Pf0i&)tQtd0B%x|MK62AZvXc!F4dM9 zn+|()KYqsZFKnpmEK1?oBD2F~S!d6k<4f2T{-XB23Fkt)6s_DvkBK6FlghVUAF@#; zJkA5L!o%s9>`RF10e>43fFA?`dXB^3oSFA$_*&&GO$^CuKgeU~n<%~93JJcN`WXD; zN>aAHK}d*sySR>qN(oj&{6O*`BSm?`4H{AMgP)`!CJA3iZ}mZf>J$Lg{##6_p)G#5 zy?`c4+}dXhI~EiE@D%rBG^O2!i8|Mb*mKI2TBRC}-eGySN7!?8xqd$FQGb;lyiq+Z zWyk^pgl?Q&=es{Ag+|C5KaztGsrVN~^6!ZJCyJz?&3}MVWl;_tbPck@0}#L)bGC|# zifUlWii-S*kYe>H8Y>$C?6UCIsWvBv%!=P$VZB+}vC(8E%oJoEKKOR~UMK=oYqxvI zr}&-b%St@Qn+ng$o^G6-5&a@#*dlXEQC26|@#EsQ&3h(E%h1g8?5ks@m1WI@DuC0t zV`f~X+46eIy;s)VDfKU*r%lR+q+naI0*-@@wEmk=(?I3ASjWYrLZnu$SCR>%Z zSgqlD%LsKW6FT3iWc$YI{F9U!3kBx=O#_cAxrrd1$8!7iiBkX5gM3^cwzv8(hA?F0 z7@D|HR`W#GU#~`V zfp`11RWBUBnJEs7+1)LEKUN893_r;o4DFKM3VC#uJ{7QA45M0=k5_9~n;(qpeRyU| zAJ+RM3`Y4bZV$E3oZk8MB+d*gPjyI-w%*w81N7qSZyK}#Yn4EObus0V-f)eAeLNks zg@Ph$`JW0{6F!Y=5qOE*%{DSsgKi+R_H3rA=B*8OryY%2M*7UcL(k5I+hL9X@su-b zTQ4*iC&{fto(c8qshXJ3kNvA@t}#~y{s`HDEF9+AT*xv#$_s)Beb)Mcv#bme()!#8 zUS2L%Y+|m@bgjWuzW_mZP*uBKT3a}^LanBcq+6U#2^xY9njcSheiI5R~wHN0$kiy%NI1QrcI&&$;iN)|Ux?x2}K4 z(%0%$M5s4}Nv(~f<|-%ouFuV#Ez~>cA}8;h1zw1eu4t#$$qh*grd?WKdFayVRGO%) znVy09DG8FtQ7-@J5Thb%nVt2ixTe*|{ID-iAlP}7U7b$&exyX;&SlMBI<>t3ue88~ zYnP>)YpLGcEwMIjEjOG#W$hQTWips_@rTYsBEFdP8lmsyt*XrX7P~oz3L zpzER*Y(TM7mX^YPMyh2pYhvqn>oQFwNe;+d`|xb}&PT33W|V%&$|t$Es1vTcZ225n zNm{IaB&UA+573%_96t$bwZM)6lN$3rnKa<`kq+9yT`|3Q+CAQcheAc4ENyx*UKkzA zXW#I7i?RpJj3v6R@7k=|Gd(8zdsr0v4p@*Z{>`Iyb7$~$&@{UOb+OOd%1}bEg;S9D z`>aJIBd$!5a)Hqum`?sd9j0u7)(Z?_0WRpL2ZD^QE)Hr2fg5gA*O(+Vm)Jwnfpe^Q zF_a1{o14xI!4+NtJ0^RGImi4n3~%>>o4$eZxq*13n_QceFx)@L3M$iDE_s;HVrpZZ z!i5gw@_ytCpYBhR*voHJ{w` z^{i&qIGD}M^nkQY#X^x~aXzHYY|B<(3N+Rdp`dx{dvVUs#)~o$@Hm3G4yQv>Qs}Pz zxD@peYd%q-$idAM-rC>`?8%F3apKF98OvN zGj<5gu8=pFA|GC;^YC6$zZ4osK5aKHz4Qjt-+!|1sD$*YIN|)`APQ5rB@lxSqQPGd z;@>m>|3swwcUkb4{#=Igzm(uVbX_dl$ILh9!GCL%uY{K0o1LpMwqoX>@0=T>B%dEnj>xyumj%>`~n5G^z9! zdjh~dYYiCm_LPX)!!1&jP*@-+XT#(jJBxgh+C69g%3L{*pnf!jOgbOMQ;rpe|335d zc(<(?lRaTp=h~okYYo*>{5^9UNymo@zx>JDg810|ySUP`vwV;}(HxEx0EHb@fC1aW z<@TyfOqW1mysqFzl=jS3wDQ;m5W2&e$CxV%{H1%!q>>ss4bW*u%ok@DbD|OkCSgss zg?WE2CUUBmZ^S-WApBUsg~AsJW8G)-xv9T=yUAzVeHxH+<}8~L_eK<18|XX5R*85P z5vXO20j+Z)L2qpmd-TJG0Tdn|PVSY3+6SBDEk0mI>Rut+%eje~^|a4IA!PpbdX8-- zPf^iV>Cj|5z?5+#wObpf8%H=5bv@6utVs0wIRb6mOc;J33npyLJzfEdo~+CnO5I)> zIm9dA3S%W}gsp9rxRh`ke!=vQqJaMge?EWee$f@TCc)?|a3Gx`t64?)BO{CpC~uQ6 zO_Gx)zhOg(j;j~vL#At)LE7?-893lgn41@<4cld<#V$0lrn{2s^%35Xc~}xrfk)iO z7v`FF;V|$?l?My$`}6NVI}v(ixz|V_4z~K2s^ISe%s(ke|HqK1+T&JdA zW`L|sM7}J|GB8hoRAfYFh9WCAzsXq$gl8-`RsdR=4!X=0z4!TM{eVgk*-rT3+wZxZ za(YFqx8w$@2tY1Y`v>{?Wol$D@D>7Bpuon!0oyOnl*wvfI+CW=&INHbg)*o+w5YwwSmA-DU3s)UM z%Ldyzx+-&(uUo_fnt)bGC-y~>o--q`1(k~ks58xYs*O3p>%cc!*ggnKL)6MTEcyz* zY?i2ONiJA~=tXeyX$`7+Cxz~)&^%t|)K#fVzUQbYF*3({j{lNdK9pTF(Ksnsgh@a- z4SSd4$-UPB9vV1@{oaY}SDkiWS|9^smMS?_Nb8b&FjH>0moHX1S?URJthV&Q zZZuF$eG4a$cbz-wV{)!E4`Px%10ba8OH;ibB+%9)Cg}4eVrl7XW5rj%BPuFn?;G1= zUL&}^|F#4&=>yX=)5XTRgfJWI(rm6LZ4_SH)`@^#c}eZcVPAv1rkkiqgQM~bz>8BS zArEL%?VB6!rq~_9JJ~O(M4$~AM6X?Z0vtgAV^|YntqsPAHWF^4`|UlZt6jLYCk1u`nn`|q)YZW-#!G)pF4IuuFa46s+xehkCcg3HlnID zPin#nE$_F=8_e-5%9J+=y&?@V$&?u-?!MjU5W4QXZ?Fs-1|vE-O`x{MG3yip^x~~} zippDObD&U9YLCi@0|}u7&YYsmse*kmcDEgOX!8~HAJ=K%t*WXi2-KASRb}}nrLMB8 zxs##Ue_(o4Z51>#3;lhSZLnbUE?|m;o=^;mNmdIiM8Y4ej$R7}Qc^pc$T`hsnSPMM zhGSQ_9UUEF#=Z{++C&A4(9NNMg+&2})|TsOC+)>~a&sm#qnd#FiA+?65 zZ=#M}Djc&K8SFSUpiZip5=obp)=*Y-ixmwjB5(`Vl4K(f)P8fs5*6~NhO+wMb`Lmb zY9=s*#9ClAwfV5^_kulx5p*8papa3u*T;mMOi%50T^|%!XKXFR;mv-Xo+&F2OdOPe ziRhhE=T%a1#6d6-?i~NB-N436F3SPn7B1x0O6RG&o^UXv9{q9_Zl8+usqF>fc@BAPHgiZCAK0>u32k;8WJ%2`-XaAd~NNQ=@HV(lk=7N;=x+w=?- zCB!k|u^f)4zN|@QSJGIv?o6yMX-RzQ6%3{85V|bJHP3AkaVdvSOo>#jQke@qZb8&U zkj`}2;BohXObkV^lB@$|O85!JJN5B!`wJnUx@2?ZBQ zo28lP0%B_>tS)*Y$P4IWW|F9Td7&A}N_IlMlC?!#LDR9Vv=eVXuLV+9$SW_`1rG0$}TH-zGZdfjytE;2*!?G-!8F$gz=F_P>>_3VH6 zWNne^DB7#WW;7NUu+J4~gkh;dcyeiq>Bq<*b@YRAIuj&S~k4QSKL`-Mf=7zkiqY#Pz|Tz@)LG~>t-9c>oFU7LL2(6 zC}GZ(9o32lq3ZNlfpwmx`R4^Gf#nTDv|>@{REVRDvSYZ*-Qu; z(_>gwt{Oy$V}~r85kZW8nAv{c22qt0c)*z94KKE77TijpQ1~=4bAScb=j;N;{`C_Z zr)vajM^m#j8>jb>)S|q)XBrMqDs@Vx0MV1pHHveDBS;&)fOLAy+L=mKbL$&6YF4xO z;Ux{O1}zeG_A2Sm_WKpz@;SA-twq_Ejfo=laez4GD47gn*AZJ7 z2RFl99?YFdZGvr*Q`-Y1{$UbZtjQ1f)L#Cz+f4zr@%ceXl_?(y`Y^Q?z$$K#mJYp} z-pg7!S06&FG=$|slEQ8*A@5~aIS5`{KS5Upup*PYf7_Wh2%WNtq!qru)S>c1mKH9% zpFpR%*aWcoa=MO@&p?kU?9&;#L{htF7Q1(L;tpvFQRX6>Qf$+wr-&Rlm~iU|xm@r8 zhhIpqbK7zZ-48tJGTI{Q9CX^5`2vi4T;ZK{IJu8^8DzdWFeChqn@u+z32?>m(aAlo zs6j19T`F{xJlFzG!JW!A+ax}V_D`fVd2)Rkvr~7_op+Ixs4{JxT5SRK+3(hF`JbN~zI>pf z8piI-36v*aiAL!%W$Dtu?PB3iVg|~fbCUmpDO81RFhbadht-5_2s)I8<%YFn5zCg+ zNU{^}gJ_Sva7K5>QPx1khJ?jK<-qCqGz{9A#!|4?ykgAd++PJ)UM{`lb43_s^O@o6 zu2*AUt;qlY2k*T4YU$VNv7G#)Ycm{_O3gijD4koh>gbcirgxe@*vIiYOFy&>a!A1w zJ>o7@tq7mS6eOprs(D4iBM3hNhD+_nCvZTXjLO#<0tQD$%ce||!*qS-*-n$To9GQJ z69;r{SOeO!1u1c>{2_H+36!VnCi!~sIG8YgJjZtrpKvG#VFt&wm8tGE2Rs_ z*af`bdA!6w&|1FX>jNLpjDeuPF3G4kPUz4#R^MkA4B!*?O3Ev38&DTHl?3K6;3jUa z5^c;N%!>DvVymEE2a`Vv>E&zdeZ;Xs>3)=Zyvj7xFpjNo^%ZVO!X9&$FRE{_m@iXz zTxxr;_)MreaR#&ciK&YI*3%3XrmXD{}gt zd4VwMxmc3Bx=Xg8aEI2uTAAPy_ITU&xL16Ctcl_jJhV@qLZ_d|?zl)jU%GO|qmoRk z;+C_D^21{F7L`2n!c{g}hL5E-FtKP>x*!{RPh=v21P=HBI2_)EGmb~JBQXZoFQt3%!xkn%#LhRuOj3cb zv4+_4x5sb9Uvf7Nw2!)58UVmKZIl^OTFkwW$P>>K43Xs1B+VZ_({}K!h z3afbzVPn4N`G%Ga8WVezW&5}Y+CaEWwCVHRvYkEhI60SjA^+3f>pEn5j(w^@tMqS@ zD~O0fbNqr!gq(L!*AW_KeLgKf93;BO|7Do$-;2I~;^6py^xHF(hHXIe0e@A^M=c=1 z62qRW3q=!%ekG2#lYkI{A|oCCxTpcwaA{&kp>>{hYlGwk{j<}*gBVppLZ``b!}Jro zVE_@n+lhWjVM}R?NBtLX@B5E_Q3=#W_DzBK<>+>GJ@EF$e!F1hup^Nwzl;}@FD23r zB(F35+^CpVnI@@X6sO|!OB`;;8Gn0ud3nobEm*lWyDmpOgO$>wA$vXQKzR-!kJw4T zF(ar(n^}Gdoh?T)%He<<0#9Jm9Tb55rE2*ubcbt_^eZJXQiYe`PIV>WH9GSpG1AFF zn@GFt7Gh6}VuLOgjhS!oG8Of>;8BpPg&xi}s<) z_5Z!PPU%{67ta%3Q}%s*i>?wQ5G^A=QgT}WFrl`%!kBTCsM*OTr(y?p4R-uap8Wf! z5yJmyoxlEn!fOTxSa%rq0ha#?uVo5@!fR|gl?X#zma5Zt2N|7oq?GP00<}Nyp|;p# zz^_MmZ8P|gxCdJ$Yu8qeP*{RNQv&Hx{GAh5JHX0@xM0J$PKPq|x9$BAb4EwqDts#Y zBhI+?wzzooyCUo|FG)mwu&O|F0|tDvX~?V{T|4F05`3j;16-(^#x0)kzP$E3uQcDT8aU;JK4JBL?^EnW#QkP>ot% zqiOI$8Kg&OeTrW7?f=C3v&mqUt&tLY%Dtcdu(c~fHXBc_Nk;Cbj!xgLUa5LSkB=tLr?^<@tuR#3}G7-pH%9zlTAt_ss) zooJm>1tpK+QbCeF_H)vS8g*WSxf%{jp}X}%{U*0f!1H=>=^A02K2^f{*0N4RqwdsC z%!Uxb46gc~Pt2#G=Yv;r3o}K>h@2d$Jas7%u9&o3?Uo_GsCj2ym8P~?D7y6kPLT@a zHlr=%zv--O59^3&Vn-%?VI&e?OOk2{7&Xx)mmBC1_wCd4_k5oyaj^0lbF<-B;m#}? zgP-9F*hlo#grREKF2vJB4886y4GxfAWW^aFzC=Fm>4kgX+LmrK73jiIND znqe;A3`1IsOQK!GX6LpyZ*V1U%q(AAT_=zO%U`Mh+{BBIUiz@$H|RYm-+`F1uV$in z0Ibs+P)y!mZjo)OTVXQb>yl)2f-su707+X^BA~KvY=R-x=Y+U5aZPl`aKkIoh?W3? zV!%80hWaKZpP*5R3fAPx$6|rbJ?H?BRDum~1vykmnuidxN0k8mvG{(24dh1oWELxF zi@`vuX~Ugt7@6cXHZtjY*Kq$w1}L}U{eFG?W1bx= zFt@QNm6GkovN3Pl0fD|TXVU@!m*L1w=~lkjM5=$fgwt8(TmZ=(QR$YISE1vV1s%aW zTl(x}IFh!onz&+cZf8WcaufBYCSoSkH}Oy19|LjAkKGu6+#|;t6PMBioKAcd+d4qE-XL7^sq*fw$)lcwckKCQ;79J0fP(rfDA@Z)hWZ^0gKtilkofE!3^QwP$i5i zQszhFt$BiGG&VHlHfuY^YL6fM4ZYQ5GliG}?BWNar%N%W*eZ&|VZfXe3lBj|vEqpPG`KoLgDuB9gnnL6_FQs#omiGJ zD@_cSD}Rwd)=qJ8g15r%FU3oX@+{aMZ~Ut0k@iW!cGLsTq5|E)Ds1|EorD)|NxXZ7 z6)n&BKVIR<-D!DyTU51>sZOdTFnVqfH5*3tN6_U$9_ z1Pa4_-w?s=O6(0-;#aE?#I|(&dKK=5`6N>%;@(RlAN>BXhlq|&TqhtHd;wqsqbtYh zJ2?edaKCAOm5L+q(0#8}5#hDNZlxnR5s0=_FZ4>EWV3z8hCMbSA-^%wOvF78D>KYI z0#j<@I#Ze6n$EiA2K!ri^c=DtZ#>1Pcc1V=ynJ?dqE4lZsCZM}9%S%`@Ziucv46p- zuyCV~oWB&qw=F3`v^lXO6+~zQD@I?zWyauYic|~;3soKM^tQ0kW&U+&qzB#&CGMQa zZc5ocZf^hZ5z)5y66-}ZtIU2A#;IJH@F@LC$YkHTm2^V4#s~+PAA1bR;@h6*qJld= zdZeM2CDuEag)iLQV&7VbIYZoi716p|T0JDb{)q7oq?G;X5vvHME6g+0R|%$d;k$-x z6f?-6o-;{*@o77juAf}-6B5@%O_F?h7dmnwAmkDkwofegA#BD zn4$R@L4)$K?Y{DzM|#XTpKU=7M&nlm8kvio4*L&58r3N@44Mj0-?2jW-x@95?BY&R zR;?oLBNSs9F&SWzBivlll$Do0yEV1{d&%V*~V7{*w!t~dBSgP5A0A{ z8J^6RwFW86Ur>ML=#szux<8i>oG^CUKh0ZO4|+Dy3LS) zDsPmkG0_u=p2y0NjG-rTV*Z!+26h1SgW*SPk{hPO^xm&V6G8n4FLY4$3^}z)_0|ZZ z;};Sl47%brSwd%cB(;^}j4{jkE4M!1SHXT}(=U4g$4|jX`}qZhHYnuooi8t;!CWUe z=H_Q5d_Z*sd#o+VBjdBh#}i|IKS_^viMynfDcXY$)yOZBd-5^6=<6~v*OU`K2HGL- zqpykBizfDqclJ;2iHEUol%=8TXftFL8G`4BcXeOb_NpbIksLL(5{JccMjRShEcYDF zpPF7a3mm!S4<*gbuCYV&iY-w;#p)QRXK7WQk67xWSd)$G z_UBZdb8lx|th7#f1AUU5K>3zumFJJMYk5n*%d+dGY#{b&ciu!H$W695cn({SzbyDd zLst{#+@=pugtv>XT=UDV_H~lG1WSYpa*r_BS6G}W%Qjees5s_HHQ$Ftkv6noC$uC@ zzCriDjZXTK2!eT5hP*Zg*?Zwma!61KJ}bVEgf2rc=+Sk#$8%VWTWlr6^^nC*7W4#w zAIZP}X+7|c6AfzvsV1DC{%_Uf?n4H!&Ff^wPQ&-y9Zv|`&kEASK zzmIbNVfy_>_yydK$#P2zt6W=eAdO0cNugFxpHFx$!p4Y6-(V`x&|s*CP1v_bc=Jj1 zvzQQ+yp%M;3BT}o4g$$8RLRj3^Z7%}`{T_s(y~cqPj_?${J3g*wnn157^3~B54I(L`tRT%` zRAH7qH6@mPokzr@9x8xto5}N@siVG8Hi*YvgmOnP2x&){E)jtfyOy}5^|tR8Zd zBv=~O2_Y$Mf*Vel)@mD##nL>Y{N!^sz(RV?W(vEU?5nyj_#YKg`iZ!SCx{1P|Ahzs zy{Z3Cs_cJtq5jg*?^XMstu23cpoGk062oHrQz@*$VS*egtS5!EEtF~KVQi-JS7WWV zOqAgqlogw(!db_PMv4%SueOBkjj~wO){`gIO}#FB6@5+PBpKt)kHV0jGaTEmz1JTz z&Ry;re*30={M31hiZ56}W=nN&O|12uSb*a^LuS$%y@FM3Z`@%xIs0+a%*de9xM}TiVV%qhCJbizF5&E{ z+&(I^?ncW7OBQB$nL^W3mwwA~ENPGSnsKs+JO%SF?bju{^z@-}qj3KzY=&~jk=U7Z zvj+qB`@{$%Kw=H;1nLRyJVmWUAIDaV4SgNH#OKx8GDm#g>f9ys)aF^t`6+XEwOg-Y zJOb*HCIqNo7GoxbW!kA3wT-2qq2;~>yjuz195zn6; zyYHNp;36hbI1r77)EUz_tbNOcq?0v30=%@_iX8c)s_@Ze)%_gw`H{(im`(c<9&tAW z)`Ti!B)*zaE#sVV`k}s!sb2O5I^*mSF(MtmJGvW;8S8J+7TFst4y9zNBO1)FS(|we zeB*3`Ei{!XdHT|^C<{!U?{cYlvs-0zW)z(er^(@m)aJTbO};Y7J7{!SDWv{7#t>}7 zQ)BtyKV+7W5RN~leK)5U?AlSPB1D55D@hh<3w7jT9BctweplAZZvqFC9fyvaP|_qb znG!TK*|LYkQaR}q#YnQ#%qnLRuV%)?wZl-q$ozh<>g87o$FFjU!mnnJI1j1Dpfo^Z zv(X%y7JJf9NyA|f7s}K6i-cLJzJx75NBdZ&nXje1HngWG zU5WuTpq}nwxMc6mSjPz`=qnE+J4ERB+moKJ((+`KZoSRDxbp_1L;J1diW!4dBpP1| zm*d#qvBmpLch(U6Rj+$MUlPV07M1&Jouc^7c_o4m+@>{EAhASujq!MYu`=C5;1q=^xNcuqdiOXQ2S;1>PR*dhJUr{>Ho zHzsr&x4>BH{Ry!to>XWTlnI-M1^J;WEcRdPw_F{D-*(?k@#?b)WaHtCqA29S5^6>R zY0?)lzdLg)G?-+E#swa2uK^~>n}y{av0st;%!|NWvp#LBNXX>Q1btJSi`(UFDP3(9 zHhe>hP@X;esW?Y&?(V8s6YPKiHmyNiIjp^%A(r2vzCdD13rVkfs)SntU>{;D*{$Zo z9V=HGRMosG5np-VcRh>%+HLdM-dy@(WA9jmeCC#Wp~Mb}(+E&Tm}j!Z+I|(Q1m}5W z36%@KJYUXQ<2uAK`efQ5v++mwNz%(de!GcZYiOd2*33jeUZ0ZwBv9Q0n*OGp@7-oB z&Bm)+!-|Bm=U()wF2u9|JFRWySeWt7elMHsXM~QHjKb2Wz4rmiSC}9|1LvYmVhbTh zuZK@{$XE9|qTU-|&I~LjNy)KEDXHrCzp{Uk*Rnj>nXs&NrAP)cm?rj;8wro=H;xjd z5Ymf!&I5gVj#4~};BPuiF{(HuM!bU`@CY_semAKZSf zSUDpTk{MrA=lsSC@E58}iqV{-vA`8x(2foef!e!1eg*f7Ld4omrZrsa1;Zqu{8%~ms%nPR(Wj4W-o+SKy<5U)7YopcnbZz{wg9-MgYy%yrWfcjZe3PXO7*W08o@V zFzJav2|Q^qBzSs>gy!r*-tzgP26RCG(J|!Yl~L5uxAai9xzRN=V0HF68aaas*yNGx zJ$&9oXpiw^+NMpSG;D|L>hf!BID1fCnu8|Y{-of5hWCe|;&Nmz3H>R#2 zW#|sLyfl(psYW+X_uBgltIWI0Xl0C`7{rf6mkrn2R?7G6MxHT_=gvcXk{qPL$}3H%MvF zOS>WC3#03ua9O$CDJhdIf;htg?*?BYDy6ww{IoDlnI#wVwNMU~-~JSt1X8QogFy0Y z42WR-{|AZwiTwIUrdQJO|22m0-}38pB7-hw(}3v3|0d^(LCHBa+EkTPKY5V;DqP=U z#Mtw|{Q}p1ne_um_4Tvl%ZK&{-EdQ20Z}TQ6oz?Mfc|7XdhlNJt4K2#@ zG`#_wfi#J1y)F@E5RGOqVzSZe^0U^P>OdE^r2-pVO@$FU^pxIphq{Z-_8hzK3h`8o zXsJ4QXum72y*j!@hEnE7>?v__Bg2Nn_+qx;6~}wr<@_ub4%cT+@Z(Rv*RSPl#s z!aY(jqj!B-c#({h9DOY9IWLxwr|TPShRM8amZp8hSSS9U?A#)sLL7snyjTswHsxTM zn7G(6i&65c`i#~IcMM_Roxw@-uAP5NHdnew;X;nZu@01D0%Ciwb&@CIv!r*xC)P)d zp~?ArB~W&56*mEtolA&*0j+@>`}JhM5dv8(#d_61M>$iBUfI_Nit$Fht0`f9&BHT^|P5Xjpv zTNIIk6-j8PWr#h&cet#&s&uvchW30)Q>sYR2J~Sc)M*D&TS%ix9t|^SNJOXFr049N zX4}YRB?ZQ?RV(j+d_+q)IhrXX*b&`90H^cs^!Jo5(J#$mGYI(TPlPkR_M8YD?o?_<&YttrBqV*d5tUh+OHlx&WGrT zMr)*>-sGD-GQr?!7cX`%@_~%rGtAS+>|u%RNn)pOc&ov54CXi33=IdX+-Yv*VGoS{U*&P@^kf;-1w`1IdP#(&ai|F=o@FOBvLW!XPA zl6a?a)o(*kWd|v>!v)O^ehd)E$-z*<(4wY-6QYjsSg}fS3fnHTDg;A%!Fu}`B%G)A zo%c)NPyb}+9EIH}I6{{>*6TIUPJ7>1?zfLb0%b6GVV`wYobASYV}tq5c-=N)e(DS( zso_5$u>J_gK;~tUi;rC6_{vhLj(~NSWN7i!b=J@Zn`EO znCl+N`ZJn+O~^WAMN!N`DFXc>+zhmeq~VI{#||b-GhRv{F{q*p{ozhIaIW%;814%t z9cgETGQwJNXK$G#taJ*d0*`+iYv47(iCM`W29K?2t?R$$Bmud!^`AjEYwdq+Z2gl+ z^8b$N`p>?W^1s$+$Mx8w3Z(_s*S1pUli76Aeky`gRHA_lB8p+_fa5kvmD^oNAk@9U zpnHf021g4Rg!PCMpUL1W1!aBLa68j^USZwGUtah1dV}lexurvGEHUI3ztuuAkKfG* zMH220jZ_5+b$IJ@TmP}$s=+c1;RFRVb@0#aR@TEm8t+~~MV-o;elr&g!5^AIc1Ge-ZF8$Eqy?N=t7h}Sd<+8#_qFUA>~rQhmx+@kg*_LO_#8r`gLd7OIqUi8qH`mn$BHDKUM$q%gHWt6l4?Ko}xgE z!{?-ay_eVjkF|G<(RAC^hRe2X+qP}nwq0GeZQC}wtS;N=ve9LHwf25dnO$&CW#~1w?uPowl7`)4|*Q_Qd$W} zH6}OBArgUkQPna~krrzwzYm!EJ#Yy6068(t$|rT1G7x}0VStuvm+h#05__3817T@LxHMx-#Vh|T5BI*cL{fnT`oSJ)Ne%)Nff!&9_&N18aV%7gI?DCD z{9o7tX=FVz+jlLD`9Gy||Ae+JY3F8dZR+%2XEaCs%^T$q)z4hgjct;kGXjC=gdiYz zOIFQWG#?E_**GbmBp;DJN2Yfx$Hbj%dRnOcfo!`*wW=q==)C2r&|*M27yK3Z`628R z_k()9cW25Z!vq|NuWQDq?TP!E^O*bChxzOEnx77UVz-H9qFzO&B3+I+KnjamLDjHq zw>TkrD}!bI#s$g_%eTB@wbZC9`|fx9_Q=s~dpqt%ju@?$MG%dlV`lXfxJi<9VbL??>CHDyLCRw1pL zExU-Q%ei4+WaWW}_Rh)Vdb?3tS8V1`O|-32BTq8t+-Y3mItl zDb@?EImfC2RR?Jp%Z(Go4Ql8arV3+8kD%TVvR|u98#bfMgm>sbpF(5$;Wy|+J}BFb zqZ!4;OTwwNVrNT`XT~xrKIoieAJ(&zIAKYrRznd)p*?GsjJchHs0+*q#+Holz!F!@ zHj`cIKWiN6I3%*wTf;XxaFzxvQ8K^vH5+}65h?}0wBt(*r0uh@jf^ZpG!u?M{nTbr zf3_D=EYX1k$k+%?QLSPKMspOoHsMt7@LNY>S`r7ii!lT>_n4@-WtEmM73TM1P@SSI z#Q$J?)%8&HsWP2e>>2J@WH3HNT)7irP;n5q=s64y_jQf)K2gxB(*+i(1AnP9aJJE7H8(SQyc(YVgZ{lU>aW;{k|SXB zMn}bSJ*%Yzqsfr6&H}F0hf=!5hV2^;2J+?XXy)>IJgtxQUj@iT&!Z|@{; z;wGrX%GF%fym28`sW08b?WSh;)8~`3ekSWJ+1pqx-NUn4xxw=*+k5iR9|p(b8xoIh zH%$~0G{i&(141U^UZ#nOcsm;|q*?cBO4;}mPVUX(6D^OS&)aDXUc`R`c0Nari$#k| zZB~<6win0Iay)c>cx>bvaVj-%EvCT!k5i>$sDBZ^7gmsI{4v?kA4 zABe_i;6{b7p_haH(Dah@yhMN$=TFqsQt8lB-l8Ev@$2RGl|Z$o{Z-jXbtt#GYC1|N zsFJp)k(5ZbJW7f)#}&8xn#Mm`C4Ki+*3pdw)~K7v&c{RBBaCXKF&UVK%36LIN*KR_ zaiw<|L8NynXCTcm02oCQG8!7saS}!^(C_Va>^~rzo`0B+Tel>6IKTeTWsWRFJ+Ji|yt$;?tnYJlG$ht{etQPno@u*NbJ?TYgay?< z(Dnk-7Z+3GdSq@~eW5+a-AJBN*zW~?E@In^x_0W0DiZ9Spte~tqc>jiBpGEs<55DN zDYE6^j(fn=f3V}TCqh^aLc1{a2Y7NU2G!=Iwk%ogDOjbi$Q_cWMa$}fVfDwBKk>Ge^^E_R=KSJW-CKByW(9On zR$8?90D${QfqRGXhfBmcuOB0KNcmk7`axiF7HF+2uU7ee8z3ibH;!GwVyWm8<0M~< z-P~D!H?{f>l<98n(=x~())t)RPF^v|@=QUHyOM7w(}4ev$L#U>O~wl=QC(GhiIB{s zQEIozX_R3G=^ce;Y{DUjrra~lnt?xZ)P>|XpT5}l?k0=@hk^QFliWS`kh6tq{t$QY z<>FXn*V*LA;aoyLw&#(vnp1ejJvMK&^VZYF)Glk#3(`1gtv_s&BW#1&y`CT37Z00W z58ZD8cAp*G1Me#}iiLFiy*+7mM(7Sg!H_|4dchN ze_{WMR6Jx%-(tS(|8u?dPsa2A)tLXb<|#b0U25a#>YMvMK1$$pcPwv?&%Xz2P1=# z&T`Wd!BcC>Sdz=$*j}-3m+@_#csG^F;J6_I=L~j*@jN0BvL``96!%6=6xqYzp^#x} z;EoAqHb9Wd6HmPuv@iK#NzeU zZ=Y9oQ-1&v?xi#l1?~#mGrZMp6o-e_iyq26cA_j-xRz-bLk+FeBS1@3(-oQQzDg=n zfYn{6E0bOD9?eMG@;=LZ0FswuG@MF1AURneoxrPB;RTe4-F&sN+AbMSl_|u2uI11u4b_%Ede)~6w_1C znah$Td1R$)tQb2gSf;T5DB#j{o!@3PXWn!p=@Fi%wZnFg53K?}1;EX#AFX%T9W0fG z<{%&hwI!Yj?c0~Ev-ewBgyOehJ>Z~Y?p@GS9QNZ$*$daLMW>T_Yl~O3C3U;k8^dWs z{FlRCz8qh@=gUYa#Ii*vj)+MfwW{tG*4ZD-yiph6IMl9#<|Lrd$94=DDa~El5>ZF~ z#(`u*tA&%Qvf~o*LN#O5G)pLW;vmHA{68ps{gRoBWfm^x4p^W|t|m|OvmY32zMR7L zs1Na=*%Z8^{b(9B@oOS83$zc*QduW&!sK}+uJJ$x(mI51RD1>O)Uv~zuv02Q?gqyc z)WY&f0{)5lX@bf5yTLe_>tn(6BF;Nsi>q_Y?pNx@8;P>bg3K>l$eFo7VK{jAd z6EpE|sA;VR%dPQswgXf!&5Rm;u{MS$?CFPWvCWRjI<_cmju)0M{=e5bKHu1~fC_-z zPxDyh-B6P>7Nakkm)VLmqYGqY7WJ=?G%*`TPxI29oLSWKtUL>lcuxEtA^%fb|97MY&oJJ zvP==#uoWxg8lACb;}+?Lu9453{WG*oG<>>5I1;^l<}>v>=?Js1E)<`Jj1T91&f0eX zUN$rL{l{^bJb;UiT6~nS^bf*11Cjs?F=Pp&>Y#YKsbLZ%40VPA1ErtIftI1UTu(HE z-}C^xj_HqYXDhd?0_UHuXT5vRq=RrC8#YJdo98X`{1}PLym56JrF-{|U^Tm5-w8+T zQ>wLDb~R#}&FgIJzS6r49(MX?AfBpM^pdbi%-v(H(~DjvR}6>4Xq%{&#a#xR?{W%N z4)$y1tIbJt?PTAc4x9-)t1{K>F@`e*BkOe4pT_8q91kTWr~ter=6n70w;viy_nvC!cZG58ktTA;Bu+7Hm(? z3{7$#g~~DFBtwbJ0+*0ZWNE?PCNOO$C~EBc7Y7}X-{P_T zdxD+&4>a%Z>B9eHg8iS%A!2H5?_~HLBl+*0MNAwc+yDcNXrHuYK14(ebuwV%U}X9? zjA8=yGg-|xXg+z6(E$K1L?SH`7HmWR?rGua{KEq%9s?2vBov6zFuQR>o6lT}vljB+ z#BCEROUhOGbwVktkwx{=T(RCwvx@sG5&>VvnAN^95OTq;$;`IeX@t(nRXz9+{&z`5 zv%7x-H;~~xlSx6P%9UIPKOxDNSTsa%zxqs{93i1dpK7=dJOSTdQ~ica_HpSqV;c1v ze)|6h)c+rZ^M5@b{{63%C~w()`-6Rk?wAVJXjFYq>`Q3%r&iswAVP(!WEg>r1d{Y& zm&tOvW@A_L81z2qJN;*%l36D`@cYIXGc*#-i7E$rQ{Q#tn9D+YytEZCR*kA^8dZ`&osCEGEDU|56 z*WSdhC5@YHhvwq$ODPyJ`^ABg5*osL4Q{dT5K#!4G_=(Syq4?h`x&@s4Nmq4;Dg1{hgW z=4iFyKV*M4Xn7xW8)#*RqnfBzSwJ|a_Ke`5+Xr^D=Vl(;^C-~=?`XDBE8zZEH&|<2 zGpc-=OEoK%ZJ1DeeAJnx$L*K6Y0X(pv>o_+ysUV(3F%krb*%mb*0O+RG%;A{2&Qq$ z|0q#M81$scG)%}P@Wx9UW0G$(O+1qJ0eKTh96OZ}J@Jh!T9f0!Ph_!ZWD&ZcAY!d0 zL%j*Nz(1g}>}WtP(T+T+6{Um`Oxe!4ZIMUV87CK$@XKh7M&^sbKpW9R1}oAXg>BSs z=cF}by#s6{m$;0M{{(S!seEt zT+RQtMNF1dMi#^f-I0Sp4&4o;fublc*9=C~0sKiSfr?e6N<-&?8HyGLg=xjqAVshD zj_mcY9|EkUMW=EL{0_VQj(@fx8~wAygeU&9^Yq%YujY7RB@P>aCOV5FwioPSP-z(w z7?|vgp`49eHl1Us|MFCfWj{Kg32Yh@gNcErzKXFi!@3+@*#<(M(qiR0oIjVGk zE{xfwkmd*%KmT1`bKM3|%$2M@U3)C zuh5Ptri@iJF{mA>Fh|+I$)afwDAdJNhiC>p{fxB#dM^Dv-i4v+eJPm`kLH}8ol zPmzsmt?fQzvGZsaHNUm$qoS5$UPxbKi?15L=)TA>OUh&pjcs! zlGPt^zw<0cY#^KT$1yP^cX>KtqsbUTp&@mKNCOtWQapgbXKNhNQc`3M;I)uAf(Ly7 z`i{urH|?;11~*{K&Y0`wYg(PBFUDTG4|6JL{RXDK(Y`9 z!d>*sIUqcf#u%_?E;-D`768^*9QdzyWEF(%u4nkcCv1Db9k3EvZ;I5_6kW-^;u=|F z)u;8@x`2gJu*i%-n2JT<4)W!au`wpA5=j*{5jjR7A=X|NFCR1Uv!L)bf$qpK#21aZ znkAaQv$J;EF65lh;rcT_DhJ1D%KD3%1iCNMCLv;063&QaDutjg<2MZ zg9F;Ss-*kyqL$8ZPc*S}t*7_}J&!=Ul($$j+ylZQ@(9y(zOoSM`MoK%y-FvLygB4e ziH^{W>&#d3cB1f}3?tU;XfIt4E8;A?N)}VSrfxGElfE{|{CQ<4ukfl4-19is&ba=o z;Q#7HNCy3WBntkA@5|pE(Edpil>B!ph^3*+e}*RKs9UFUe?D0&&lW?RJgIk(XHvEWluDy^lLRB6|N6nEWb{wSCL1p-!N-z9i7-V@r zJu+?ILvxtgv773#8*TL5XagIvJE9HA1N)lfhHhK=wl@-9#i!grbliou$6?GxI@K8d z&xKBVz1Wx zjgD%aYnA#bFAeuU`@3_HO~nMB96}|_>z7CEs~CD0_?YalaaEb5lI^C0&N`s%Auc-3 z)dD3p5&_t5nERV(qrX~CkUJCDwPDIMilN>DXWN2#)LKLQDo9NP+vrMTsWiA879a0Q z%`sUB%)NSJ1(EYCYnbxaiy^qzy~fGU@5jM>8VUK<0J7e#JF^vuSRb@n*VO4^)35UR zly+qrR~Rvfa}xGF%;v)(M2v`j-(%@|wb_-KYH#~OWmd{saEq|g+bh~08;O|Xq}90L zjPKn0e+YxY8mIDdk*`W?4f{-GE7dbLm(5^OV7~yDrn!qf$zdJ^8;IR-4YHPe$kx~@ zRy0$xa8BlW4~9)C7Orvj)Ne3MDN$CtSc{-Nu8L#e7cfY~W$9`7uN7N+mdXcn;&6;R z0oi?++818HdKBv?*M@V#40oPeGLE7CNQ{i*IC?*U847(t;CLQAD~*Mwk3~ zo$9Qz_wd)|)4H*AiD*MIz557&!boi4K#oy)$7hxm|_(mGYQ zQiINua^qHs*ldCh9STazbdQ;LLDqAh?3GG%i}{WcEiD-j=NHGt^Ow6E!}YuaPLI$T z+Als>_kB88?FQLF+tu1Vx6Oh*!3GB)eTFZz4k@Us8nE>QED}rON3Yk%bY(Q{Ej-jv z`DAgZ)C8s5lF+)FKiM}T`W&EZ!%#)`-WK9qkvb2z1GwbJ^Woj|P+Wy@mznmq!(yNr zUkZRIo2{$2dfTkzr{Y}A10Qxa_s&IwPx9isd9m^STxL$h0|2mb2lbKmEZIV7k@l?F zBYddlEIwhrJ`cxf5}?|jThzl)+{zqazr%w5bbn#7PRl$!ghkt@yGx>$8^>;pPX2t8 zL;?xN@~&vYHJqb zyGNXn;|lb%Fk`spN*eH;FWvaErG&T|jyFd=nKe7Zo`G8<^_{8?9(wxB4ADni-c@v# zp-1l)AG}_Of$oKRAAx4Wsper@g}80O62_i?uhb2KS^r6%xYN(*LO^+ja9B(s+Gx&d z^p#1Wba6oRtHK|iKwP>3I0xtY_X+&sT@ogSy#C;wbUC(MD1xlq&d)ViPA0Ae#Rtufv%7d2XBn&F%x?JN9^JIxow&e?-$(Iq0Ac#*0kjE zQ{$EpnE<<$2FLlFu(#KE8-CXfgE%;2I3UljM?R|(pVW4JEvjPOX4QmwJ1y*@DJEPE zQ%4-*zT9ZF;uQS`rkod4NkZ1h(ujNZ>^g)sfRxJxl6gs~nfT~fu}=Vt&;VDA6cDu+ za3lCfDWG#wRM7!9@cPkmWn{n&Ist^L*0Q?h;zx+W`6_J>iA%AAEg0c zX^MM5sPgDZM#lM5{jpti7QKEdB(A7eJjCY<9 z$9+nUg2c=X;BSY$uz=K{@QhA;SEP5S?K#0Z<0MFE&}JGAjk;2CpJ%vdBP2I1#nHz)o8-KKoInn0fd{rKnrKGCDEKV0vg3HAJY zH2_WY<4MLJL@9_^q(dQ_pgnOsqtTi$K!mO7PGij2V)-j}I#({lOJeAL4*E zQy=C4`-q}@rftdHz-aq#Gt7eLE=V8wU0?nP{M{{*?ZG$6cLaVU@7!qo$>)gZJgHS3 zW*lYeJcjH{OYKo`c zRJg)|`K4!Ci@+q*lY+IoUPK?J!mKP>n$I}^Yi`9er1oyjVw`vKYtv-DUQ$x+u$X9x zZCA-)O}DdY9?4maEoY#_RP1@TXH<&;trWiyT5(!vm3m7E8F#*cxNjwnZ;`Js88dQq zJfF-qKXBoaSyXjVQ0{%Y=qMO9u9k142JZW0cM;oodQUA# z4~A+tmVueM7E$pK9q=ONlGb^&QXvm2E>8G%+AUfsmijV^!D^LdApT^S?#H%E?ptfF z%%x65J22mfHtrO=k@6qBNp~A#-0w)nb;cF0dj4rspV6o5zHdahIA_g7cbD^~9EH%O zE(D`RjUWujf0-B4Qwg_fNcNQa>|Rx1U1S~G7p;lIN%aJ#?oVyc+Q+v zrD<2CS%nz~(`De9_CitS&yG^6XI4Iw?-0KZ94V@2SU#m2ZN#^o5J&|F$iB2&a8UoD zyj3Ra=HB4mB^w-byoVA?q~fu3R_lRzO4oUXs%?|C#U)cz6n-9(hg!Ty4#2(1yfo@q zTn?niy3%(4l1tYpQWO5c=){{7FM`cP8I)qMBb%~nhGrO%elBhS%~ndv`R zC~fv0T{hEG#t}5~94-Yk2E+(klEon5hjq5Lto536+)WT{t*2;w;V)%J{XT|3h>?+l z#-=^S8_Y#U-uwBww*fI@>kn!*&6-;i^!*RpRln62Jy3zc?#1?TpaE{xen0QLGMS(< z)!pR9>aH%U^wQr`VL-*spBS!=+}&dPpz->HEJoliMuqeJ-!Er>h}Y}tKou(+#lBIC zbFKtiaNO|%KHJxLAo=?EN7~~TMl|+EOwo?5X|E={B%hZ_IBt!!5IYll9{}65$EHRk zcmEiY#Uo*2rxWT8T<)0SNzBWS@gHsEtGKa0;bN09X@p+oIM!aCIkp?~!5hJYtGDA3 zo{Za5gjtB?3B93_|4|b_ig8nezKFO!v!SaaSI`6OlhkfEL35-3%FPxvnmXy4kAe#% zclScd#T5|av8`SUVuV4$A#pzsttzL`*ig$vt@1cjp1r@2KLMnQ=9^+gfL4i;T+j0Z zF%?=m?4$^u__CyX_o?wqZ!EF-ZZNTW_50fjO_!l58lQNoZFsIaV6I|LypQTkD(sH*3ci(+&+Q8CM$_jjQ#E6c-wQ958W0ryBA+b-YPutYjzYHd4JA|6K zzsK9y|Ja27eZ&>}2hIB5MCJcMHvfh#{hO@(jV)P1Z_sJ~q%u&f->(2S6huKqfhQ={ zm@8IN?q2`bPQ=#DJc99)gq~#%fpnrIf`8)qS1V;W7QyzEkF!VKHA5Iaf1eL{MwM|Mo z1_shFMrT*@XH|J)L$eu+BN>r5hIU;a(d@ zrS-*IYuuBw%HOHPLb8c!jbSTCvHN6f*R_a!Z6=&PoED4iPn+dyEJ;)yWTaLKoh)|p zWSL!SE<3F_(o>AlxTLL69Vq9iGdH^gOI7`hA?GizP6ivIUwhU`?1vNEHwQjRRCpr` zd9=0|S)q2=a=QLn8w67}b}9QV!rEpJqg**SDILHMrc51a;uU#XZoo6Yqf%*RZu*FD z({eGz+<_^OYVB5^dc0c}Js8 zA6B>Qwa_`-x0T#@LsN#QH)X-5{*%NPNK)kV6knL02tx=zc0oO%u#Y$pc~N5xVy4g=m=JQRx>)BukWXPv&Qwm-ao;A(6E{KM9z?GraFj=fpB8-YMcxb zpqY}yr`>Y)o`?gwhg?i@L^8!ZnIzYf9Pr_dd4x9xn-We-Yb4ZD?I8~458CRos&!nR zq;@E27<@AUYyQf0$k#?ldtITYkg$Dtf)T6SPb^v|4V&Rd$u@Tr*Z` zO_F3RSYRtUx>ISkOD<=rTfZM^2D{D5W0Od-itUqNY!Y?Z#=RyNbtc^sIR}|M(SZgl z_CsHbGFerc5`IC_09{hsXIyc)yT%ms{oD$4w~AplQ95no*8dLJ9<$3Y&+1;ZQtRlc zR)b9(I&x8VKgRS@I#mr7nVY9DpbCj;1IUYm-Wga3Zbh(0+Lb2Dx`{n6^$bgKok&Whm4^y|jXqsXMg zv&wXtYxECGT@PLbK+1%d9CIMeq-m9@HBVhsH(c0#GU5ml6%^h9*WhrG1|`{7MKX=N zWx$Fr=|-y!sP(hfPg9>F1C-+-8p=IwQ1qLe;A_e++`$1nA{`9FxYT%qF!?zn>rT}Tt#ti@j!Z40NZ z?e&YO;{giwm?Q&~6|#--6))G0ql(zg7*ZwhQg=6kpe?UxpF3@|D^6`}o_eT(w4oiq zZx0aN{h4wsjy$q+D2upPd@Ecze9k)Pcb_K1OR$kUnDZ-s8jQFt)7+RhLA=T9D^^5m zMPd4Ii(0ID>e``iw>7n_9bBJe7KdhH7sh2(Z9gBXB=+z(J<4q)b@ zakD&hT!Fuj3H^{>%XR7IUy*7?EKvGRl!sa^izfqm8RfmA6v}@B{erhdncp7QmEgt; zQ9y;KssBNN<``lYSr-i1ef+Z|9u6Rq1#0VOh5Cu!CW7B$sNpHU3h{CJb7vE!Ed?nQXxby zna?`cxoCHbk%R(&B$yQu8;k7H4|oc&QF0szWVHwd;(>L-VCH8Ef@sg1g=CJ-NT3NM zLx`xM-*~HTx1e5BB1l`J*LiwFMJV?Y{l{f>^Lr7BYIeKG@|pdzQ}ZY2!Z^-3Ao`Ct z0iWm?)ffAV%tLNMsEoop+PT{IU;oMnPHOB0qW<3c*g^hZQ}sW=qW@P#`VY-=PO|1- z0*leFtRcsPc5>c!d#STz45e2fRD}{1Dbx}P$cT6k$0@e0i3VzXh}#?i&;Tld{Sa`H zUWgqaMz=y7SS2Mqo0*I0cemOK=r6<|zs?gYm+C%xp3oRYKkoqB z*H~_V6Hxkl_DvWcC>ug$E(Sg9PSaIc-!?~q&pFP-dU#;|DKm>K!$>Kf*+LyNlS8nq zVwLQE)|Xa@s3sO1V>%vHF}V`PuF0F-uO`)o;HJIv+(^r*v9WKlns4SrQUoJS+=_4L z%a}Tc7ip%=ZR^(Id%Iz(d!DN%@~~4$rzRbbDF!EO58Mc|VOsNT)O7sWG=b@BT`N5O z9@dt5MlNJ9`x_5Ru^@VKtv^gsIyAMEQ=prU z@~$8&8kW-kCix7OcNQ%D>HDj#I=)8gD}A?B#s9Od{*#DxRXa<^|B8{zQQENkKD@kH z?T(oovRG0bs1%gwtdN z1H=lAXoGSik#R%1Hnf5E3j}PLp^{WWE#<*7GGFdm__nnjbpfTX%T@BXx6;7pCzWtL zTx=jz!l<^U8GDg5oHw>8@VxFq9>gc^i*D0{-@ya!lx;7_8?Y?&OCt@enXxDaD~111 zU_Yt8t2_dGNwv9_FK`2iwrwF>xDn?Wk&-g={A!p_kONu%QoHd)d$mL%-?l5)H#=K- zHFfQGpGV_3mCHpNb2#C>x<>Aq^AjUgw8Mt=9|EP~Rz!O{>tzc>i$!g>0{~+GQqBt! z%|=T9TDt{j!fZH)!%A?g97A*0HiPj#C63?`PSHa+YwJjJAD@$ahx1pj zc=IhAR~Us`tN|j^JzhzhCu~rrF?rR0D z4}h*8EBxhTK&?)Z!;nI5cs|4!fxDipq<08wi&s)gOHd3{0`*-W2M8@m87;Jzj-p{Y+r?8o%=(wq2S<`(=`XF2@8tGg>E$1jH~b; zdsjOyHsZCoUVa47VXUTuz-fkbngb1+wJ*)z&#dO*281B0O+OT=E&u0?0_Lc=CIy-p zT#MRM(cWL|!JB&#hOALcnuCRcIlbc!$6t>oyC`y#D~SP+GFBRF^?{mLk%~1ihed61 zhTl09xogp3(%o3imVe5b;6v>pGVN`a&S$J+%&dD9eW&Vg?2%KbCMd_?bC^UcfHexE z3g(<)?jo~A;kYnhI>n*x(i6>v-7-JX#){11)kPy|@)fqj9?@*BnUl>A;UzAIO&1>c znfV2zd3hm$s&L2*Am)na;Sc`Z`5G@RlF-BTpZe?T` zp_7iwDS3Y#Rk(3L4Z-hfnDQSyj=v8X|D>D$zZU-A$2ECJ?mOUTq>r*$It{e>PF{qz zyrp>pst{dD0XQ+4#S4&aQ}^xI-*Er)feZ0;E-(;__aq$Hwlx9gipq#Y?Bbnxph zhnY!!^Fv#EC8xM_zUYQF@j*7@3C!4nSz&he+^KO>>6e!08m5OJ~Tz2h(6R)^CDtw5p%c zE`Uu_{F?Yo9Popk+GD~;dbqeH4vDxy?C*OMdV^@SU5C5Tz1R@tJ+hU)RjtAUto$}QGGF0xNkGY+pvCFkA^QJ z&JDPtAn&7;Di`Kd2UL@}DRh`PA816bp$s|@-*&#B|8=~LpEL3tzmGTl|Jm&S3AV9x`h|(h^?KI9yYT}od%;0ZxGxkCHV9}#y75FK1XGiSGuPYKNJc;h&0@;SZoEy$ ze}pR8^nGskxFtdPFb)WIdZ{qm-DWb4G+^p7TYV~PxzUtfV&O40HGQN-A-?sRq6>?+ zf3y3697sbOYEvRaLN07C!nDT|$!3zXHk*e2*Z4lGb*;cmY_@rmS`@0YzT?>>D`-rq zQ`B;#X{v9Tfmzk_-m~^sG$Dezib(~wi_R!M+6mlJ5N7HTJqO6ioBDE2qxG9!gNa;6 zqnegb?TvsX^hIT|R{dr-Cu`f-V!#7U+|C}eV1nMRvhEvgYzd8KZ%@C38OxoHb=kfM z6|NQCgJqpg^I>~YY*B}rW1G=3L-G&6fJ-(wn0|K@8=&5)$`Z z;*cTEp6qjrRKTKI6vD|)Wv111dUH>qXr6$yz@^8Livwm3cve!!A=D^)%sCE6EB{Yo zw2McfJ8x1xH+q^(J3#!ome2%BPqQH+kj6 z6M05RG2!{Jva4WnKwlMzEXHA(aO;kX#^_ovrtI#XW)QVGBiazg2awHa;nmpK4P~>@ z7S~)`bJX|IB^KOg^GwV=O|x}-JarJ6t9mAeN-JP zvTi5{Q@nlONPBFdIyWSFPTkxx^uJr|6<`bd?BbBh17ue)iYE>=esBfj>Z;7_JmHn2 zMI0%PKbim(D=nOcS!~3YnvFYJ0-g3|6-TH8fC8#4N8b4t(rY<%jZgFaGP3#)GSlDv zuKrQWu`sl>Gd20ImeZo9tBkFR;U~wp>O+GsmM>+QrKUXqh85Y;f>MdmUm85ihETE? zM`|<3G)_mBB{zIKeX4(QQo`O-6Dv0yd*Wee{!Z+*XJ60fjYN<7o|doDF9y)~2_%q-P=_tbnX1wW>P0Opc!pSMK3^zV2SH z9s%Q{PlYtvsa~xfBE><#(3f305f<2=ys#1{v`LfVndsACd5*eVhJK`h4uB3yN}hBR z*5g>8J{wr;^cMF>B~CY6VrE!b4pY#dP>W8B%)90Coj+tBycVBbINMOA>aAR#MN}H2 zA&=|Es=i05|!QXOKLZZ&MRY#+g(k> zv|DCOqXs0PB@v7Qa9WcAvwZ3wU#Zma80$)sthkW6xC@44l_ADU4?SrF2vzHoZirRKt5E*yV(BCjJ#&-BBGF)|{%m`F!zH zn>I}tT2oaS<6M*6S~FB*ac5SKD2gg0`)M9K+gKQd!7@I5uWrN7qd2YKyVXA$OVyc1 zc*TLXh$>0Jw;D=GM|e52f0t1K!S|`sH(d&|dkJXyLGW@6pl&l?vVl0FeCTkF%n@}r z|0r6ILs)-YQRodiMg-qpBfp`wjN9`k0gP?B49UC9D((=7kFppg9f;inF<-)hDNGzH z;m|C5jzQsjYhr&%SnY64-AGJjL0I*ZImaU~Rh?UEWfAi&-#4WqQ zLRG?V>6`v!nZ8{S{{#FE?igAl{)$}nrhLTd?l1F(E9Em<2Dd`a&#Q4~wMMGX!+lJJ zvtGtPbdXQ{19iPh#ZZED4hs*g0&+fb0Z9jX!o$nrzNF%Q#^J&cfB(?M>K1?Y&n2C3 zm`LMz)6b?nsfX=#yVuP46T*n`>tgMD*D2R4M|rUxR_%6E7f8}t$*V6^^eLsy4{!g%r^B-)bEI`$iW+ysZdhq<5=KF&T?16qK+D^)(UrFS>q?#X<;i6S)Hd3tHI%>cwVo^8t2 zXPRPN(Ao<tvYa^t`FIf$lX@wl2eQThfW;ahoM)hA#Tad;FIy5$ZnI#aWS_| z+o?*8+SF%?g1aPX$`wUsvXnzvVK1_lHC~05(0Fs*XbH-Kf&Ypt^7FDIfnd2uz#B&OL>+e(67c^Z9C=nA~ zJTDK&d}c9S^@`SK93@GXnTd^R0we654IQk&l%v_FLhH=l{xP+04HRF{r&y9wl_KEW zBS7u+tA)-_W2qqLmsfLO~7Cdakp=QYpi{XCr&L`;+ z!;3Wc5|h(Y`|`LY&td2E5NO9u`tA#&Y~C|^E+&ppMx8HKPU~$h#Lf!`=|L;l0YtJO z?!7o(qACy$XP9wnPJCMw+_r$m6Wuu*$Qs4I6ZxDwu;=&k`UyO`|*1B-Cfk1L~1rTAo0{{!Xz!B?HSB20hCh9-fe?71B zf4|}VCC-`tkLUH@fewy;a6QEAo&Ey@PEplW$5utza+hE-#E^hgpbbb}ZVm-WYE`S5 zSF`+)nHeheBU0*;L1tjq1k9W)ve3SUfAH|Ggq{vvjoKpZb+zRk_!9#E9sDeVI|%`( z`Npa5D7$B7?J1kv|MTtq8i1*uq&p@%{G4bzfq;O%0G54Su|GLH3rVD#x&VCPvYD!L zPzKzK@x1nEp#2c5o7@oZTKX9PUrM9j77;(9omj|_!^k?dR^^Cga#_}xjeWYmmf6Kj zcF+xFFhiM&mG*h&Re#4^%rDCr;#9NAjKd_w7~*^_(sG3+hA@G>#z{<5bIjHpd_<^tJHLqT(;`xe2%^%pCS|LFaEO>3AD`Nt;g~}i}JbyfE8U#<`3T%x+6`j>`bfZQ=lEt=) zq-4lLagRTS3U7xn_QGPO@VjpW z8Dbfl`dHinb57w>%u?n-Y2#$DAdw?Bdx8v(P-Ff1>FI1LM(M!m^Wr@2FJUu|J@Mi! zzBQF!1q_j~C6uaoSq4f+!17InH)P8ywkgU{8pXUh^h=bnZA!nR(ZJL=O z%b8LcMi?GwkP;0xiVd8K9BY1KYNlF_&nhG`MmL6=VsgbYXY>11bU;YDYa}2J{)iUD zNxMawXOc4*3zG4Ux5Q`K0?DWqF3lp`8AuQBVxlUKWH3qBKy08oFs`13Ue>CFF^5yj zfa&@3Mt7&K@U>~Zp8M)(S1H*q5jC=?Lb^ajq5A7Q20PQ1+7z9Yv3o`J@lut|IZUC0 z!L<(_WGLM=CsUlr!((sLpV@WByzED$h1qtMSNvej7Vx>!S# zIcTRl_ml*%({g~Km+zbH2K55X0{`d_%lHRmUpScU6?lgrecc1bv6sIk;sy+yPxe3& z#1e-%zABzE)=ox&V8tQS|3JVaA*rhhWNxAAbh%5OU7pRBMLaRfLVg5KP%4&3XcQhc zkYX5EWz9Nr#Fbe#@X!1AKd|Hs)o21(j&>)PFA+qP}nwr$(& zvTfV8ZL7<+U0udk?^^q;eb##-HolCEjQsUPs32tvjd05X+s<|VbtM1l1D*oQk7iBWDH`|`c2nUERo4DDRp_mh{2dxd{M&Gxzx%%bO&as}d0zj5DMoRAUrdA(GJOdOL}GeC z`mN>^ib9TnESA};MuN-kV#F!dh5-z^BL@b`A>q=rhFsE{F3H@>CLDUt|S6gK^7FUW`Oa8}qVXMFK+i@pbL& zbG=S?!$R-}KDQb5rH=h^A>rg3Tyg94>a7AWnEsnBK(ZfiZ%c3<{07*5Ow0h$u1qQr zv-dx+1}Q+t`qkfFANt=eDE_^w_`hLe{Zn~sXl!fpxA3Vb;s2BssU=eY6h6blDL*YE zYVkaR^pKdBm@I(AZ)`fCjO{uEzhykHAUq*0I(qr>V)-c~JW;nlBTb8eE%E0DGgcWJ zj^B?swcUQQW*pe|EuUGx)ULZwh6Sry7R#tD;4&J}(qc=dGFeNA)&b_7RpH~z{v zLju9F6Rv10fWg_s=)>cXi{+?9T=z#V&xX&=r<{T!m7N<$P#;Ouwj+*!w3Tg=eyAh& zP@BxvqzwGZyB*sL=Q=k22Z)T zZFA*S5!bP_NQ_WTHV>uk!htV)j0yzOm4`SlGkS5#(1f56Lxz=&DaHsd@7c3mQ8T`;WrnXH8gu<9Fnf{$JM3{|8+} zMJIhHb3*}VLrY_)?=BCKu#J<0yP~nvKYKh~Dw=jT05A{UHWzd3qW_k?O$r)}cFu_N{oy z{%Slb@FNC^$;5T{HYvzR$dz=XHbdo4rf3Y3GS-w;yh~BxX)Kvp*dx`5RVva0O@rMB zXVu11*BCKUuIj#AeQ?y=4V&TOC55K*_0+60bO^BJWOdVU+4d~b!S|BM)+ny7<0jV9 zw5q3thGXBFn0B28pljUVparNn_Vp@m$~2k)m0Ift7RAML=LDN!z}H#d(lEK8^CeUx zLL^xvG@=5FGv*jVTEb+@C8y=Q0La_H`Q}d{+3R){X6>69aV`V4<_b*~_c?4^uClX7 z6_27$>0wfYC$!Y69TId3kJK8VKgywT_(!29od&|$ND-Uj&tJuYUpqI)nQi7NgFyrlmq%?$(fXbrwuhxfdVXoYd4(@2J*+uj! z-~9=~0IBayh%6d(e%4`Rs8Z7JMg z0lVXSPMQQBY|c!Dl7o`_uHlT`z?o@VQ_RlCY!3Q+SkS6SGZGBuuUnB4K%VA4i3xVq zo?E(79{`RW=I?#KNUqq|92n+O-xbYZ@gdfnk;X)DB5S9DL6wrvc5KcdSeGb}5aG&6}ro2!fbOzdY2b=p~QhH%q4)X3`mfm?zg+?kc!4Mj-5*io|MvSs^JrFve zSNI6w@!&cU)bmOzWsZ*h{;76Oa$?V@OcLxYhBs?pf& zh-TXmC}4g5pgVbRrdX`f1ypp&T&B~LnYPpKrWf13KA!-31!;m99qec;Qwp}UF$@$W zRETdR7Er-ht^4yo2Yfie-dJ$$P4TQq(O>|5rIzjk3AGn__YB=JAnYeaL!eftgJ?ko z+F|H*+PW!q8CMR8VkJ`eZGmxt2Q=3I42>DBAnuZ1yEE0V!eCuFyPr_-;`~;whe~Vd zhN9&VU_jb>=?2rp!Hof)VnV#oZ7-ZPSMUa2r)-&dCbf|*JYSU$cJ#3nkv|XdDy;AB z&YZU|0&9cnN3^GrUV%C_Lk%7W@N9oOgu!`wdwknMx8_T1OdYnOg{J3U1Q-YrG9ZO7 z#z_+4%`Qf~aywwlf%_tPB-VieCZU#FLmNs7zV>|OK}O@}13 zokD*ZIR{+@6;!4AA$mts@}Y#5I1FPscjRozXprh9>h2vnLucr$XFG)F12u->6f9;3EFTotXzE;exP{gHk7d;# z{~(f2k(4kqeIKQo|5il!J4!&{zb_&PIy*Ri13e6^jHS$NERBt%%pIMG{`wGiGX4+7 z$CRq3B9bcHr^#_|Kiz~jl2ET?thN%}up2)-QEo*o0v+02}kQRpmLQK1s6X8Ft54C*Kd}oUPTF zE8jcvUocwowdi#UjXOvY`Y1Cg20#T|oKt&2c*D#a@TMtCO|#&o>QfE$f#|Dp!Rzp7fZ`wssQCvG)inji za^vh9!xCxuqtc6Qo{Ac!L}tWJa2hYhV5~(XrB1QIDYKd=_OtPh^%@{uBn5xAL$GhWt5*O}c2PFDB#5N%TvB*P=?hm6kteOOs}FV)r?bvILUu~ki3 zV3SW}Ua&FKOE-%tHamyxR@EYB&NI*(WF)Tjn}U~|(g;kjbWzQc5En-#hIpGg1XopC zdj6(rAdzqF}Z{C(*yokvw6o-E-he1I6YPNBP+{sUAo5RKPOhp$34tys~HY>_$q4? z*y=}>sCKFf-$vSpy+LftwPPf-H+bczAyRI^{?t5YWtqw=@!v~A6Hh!CK$X=1w2 zr_5SW9p^h2U46r}5!y;8953;|u$666(KlW0V7s4t4y~*~PCGh-bTEjl_~E+*MAC~a*5=@@tp!oL}N3F%;9)*Dj<_U~Y2oTiy^nMCQ zkVTJ1fU)QZIv&7C3>Q5De{a_~n}WzBcSjt+s0XzVI8CjrObIcKrCn~-syGih<7JasMT3uz=!u?Yg5L``A&3l|9H6~b{T1>Wi3tp6 z@>^lL#{nCYo2U)RfutHS+1*v86pmI(@P)k25L$LA0+Q=#1N)76HKie zNVrQ$HD42)vsvulh_}$LwsFOLU`Z=G>bAKPP;(MX>tvBGO5t?nLO_2ELVR({Pf&Xu zPh1yPceX=7pjw3_*p3!Z9hZB9{RR{WJBV2DTWynop#^Vp<1+eBgt2}$!n}1x- z@HgsX6#c$k{QKVqY5YB+qWYo{(b?lVHARSVWtcgWI!Qw5f7r>>} zq>3Fmn129dUr+~{z*H$=hmF)OO*OfudGWw$@H`-N0 zAFZ93bTDB$;-v3C6alzcSH?Hr3zhS4<)Xir(rEtsrBt+aa56R$&^P_(S_a9o!}Rk( zVF}{F!N|+WDFy|5|G*Yg5<}|j4I~D#uAej6wMXLmC5n$lL}o^IQOCrH^LE?0`I8Jv z@Il}~5DHA*;65JP^BgR}t(pBkX>rI@q^f(;f0o0f`Y!NR)Sy*t(ZzQu43&dUt6^?h zM=O6hZ7y(knxh6*Qs%fR08TT7f`*;loVc!ynu6cZNLXb?ms|fKgFp4tKB7h%kEt;I z&Xh5>VHN;r9c+80O#Zq00VMw)<%Qd7^1d@i!IF z+}6R|$z9&r*xC61Xh>IW7UbZ9zxE65&swF)8!w9Vr{;$Xk(7R(NsI3iP$=VY;fOVJIcK)M z0TGnhgZAV*80$`@1#iRnJDe1f8k?@rwUb3V-4-n6`cD=LtWG+0h6@U2w(%OM3Elz6 zmQ;xLoS~cB2KSVor8D3RGOinE+Le~Tb)>N)qn;SDF;Dr)A~r9U(77s+Oe;4|Ae7|L zaNf%_lhwi{+Kgt1lQI$CA&YA(=6ED27MWqreGAlac#(OD#z)uC2bn4I(}~RXJ$ilK zG8EvhOT7JnHv00ztKX1o5Y_m&@1lw^nLF>UPcJp&fi?C$TaDmIX0-A5AeIOYn%(+n zWUU2z?R3o6v0CRf1V$>NB!3$>aW8B>(@zjs=YMZT?Cy z8UDFTqZG7d*XfYBZ5Dt8^swplyrQFG62&3+n!wB<1q3K=ejweRfYdNcWQ~izXkP#m z#XbT)7Qii=!|NvSC3{~w&Tv2Jd~2L-J^{dL&-(ik17?P0I#T;8BLI%DCOOsYZi4!@ z5+zJDzuA8ZrnUVCQgmLW;>3>~m%+25o$!bZ8j=J!%WcU=8=zH{#EKwvZXFWf*uz}X z!1$I;LacyWyYiAi^7A&N6vUV#1mlIPUkF;4x6|_?N&0jPT17pGn%LI z`0b&ZzyI_9r8#Z;p|R|xST zsAAjoOhuNQ$|noQjVM|%AYpp*;B1uO08nm^SA1w4ws>{6f2d`mMM6hIlK?gBJj!Gf z=HfF2_S1t(o_5n!f19 z_*#p?c0&efDa$DDYwBo=f@68Nu0SD9dy`Suw5o+tduhKFD|3{bStNYPm3}?}28vTS z*Eu{|(h$OVc)Y$6ukxXez~oNqA%tjN*|7KP?D4=T@w5G28JHveYvt?$eh6)RuZ!}( z`S-sE5C4O5jF7GKcfKp@U}WrIZ1k7O(EqDz^dIAC&N*B#wX`H4i;&2O`FP-DfPw%+ zCE?)6rHR8mwpRrA$LlKofF$_>BY+M1;r2p@Z3m<}JA@DRsZTI=G~91ZUQNHhzU`C# z`T<+6Htd27Q(cqmk4+nFoNH}jl`aZMIv_uP(y@a}R#vBcN zVS^I)Ydb~}Luy!1;hKmOqVlOhj$}k($b_45?T8QH?XUp3P4n3L=iI)a(5mG;AjdKQ z<{yzSC7)P+f`x<~JGXJ73r+5E5{g3Ay08v*+2>h2t_}XF0g5XRJNv!?Zl-4q)X^zn z#T{w&ozA=xaq%p2zp5`=XNi&#SNwt4yUrz>`;RW&gDOm8`gef0B0yQ}@r%Nci#7)_)`k4tg32CX*-y;YvCeEtJ(L$qKBu=%}z8vd;X@pm01 z(|>P$g8xF@{9lvfyEMSPloq=_Kc8e6#*9Y$+8?PZW=5sFHEk=)lDwob=xg34w~Cc0N$4CzAcW?uJ1h^ysv5s z>|HI|R|ySnIq(OLAJ}q4o=EZ9*pTFnU%I0`k@{KuB}xlu!L1I?k$AMGgCjgrjK}DG zu2AP0gFg_l?v!zvq@O0lrb6O3EKO<^cAN~37WYWJ zE%I25giHbvc^iUwVms-Z3q!suguC<2W)DsRyZJ?M&&6*f@wc;{Qqv#IB7|b3ARO)#&(m3YH zC^3~vDa!S0gqB8CqDx~QLFXVXR!$SE{++|g&d{bzm2G;)k^y>33qgL?erwfytqsle zSgX3oE785&VwYj zh!`j}X%8ftsCs>?5<4i7A|SsN#1%0jfSl=UQ^wUcXZd_$-8L`}E405K^;Ef%KYgs_ zteFG~IXH~l>2V@K_TY_?Y(pQzhNqeKC%H?o&ez()Y{>?(OW z1?4;qo-+lFkZ%|-->CTIP3gL+;H+VT0JZa;VJHYvS%4PHe_}{tE-EK7^=;7sQ-KXF zJvNiL!jH&VDKpI@Mw(2b1{px3K7q6=9N(?Q*Mq$$0ZuUmnl)Be5F**2R$@XV?7Quj zo7HmvMhOK)^eE;Gp+tgp(QGO0T}UQyvXM2Y=wX;vy*hN>!je4 zNKBhMwQ0ZsN*dT42D=7xHcv|ScGw^jr1@aND$p4$-!)XwO2O-MDl&_f#xF3SBesHI z)F~@7qgz@>mc1``i_gz}6?$f5Xfk94-P6K(Q_{0g`UdHpN+-~Bwr1V=azLRSuh!*y z5VE~3K!osz1M0U6;kTb6-lGweo4@yq*>VAvdr7u1^CPGCxg0((Y4)+_1W!O0*L#x3va)a;Z23|C)p(Aq659tTb9e_kU;$C@tcs zQae#FND!30h6z^IL1P}3@E`qdKWA62mf2#0QX83+W}S0S1XOBJJfiX52Uj+j8$e4` zX*xqG2fR+hy|3EWqACc;ieJixiJ9hB@T{#?Ala;Jp5D8dUQY`M^bs0+%M4O0oMGUO`)g-l| z+g^5XI=3_Q`?kOnZBdk5djngms-xyY?!pNhRJ}^Yl=<9^zBLiJoO>l3MeFLS_pxa$ zDEN1>mSX|`qSRUKSo5$)J!d_2YO0dq8O}Pq%{oR@pg3btg5E1#`ViAtxaYuT+@o9w z4|$;i#$}_tITXYmr^mc$G8QjC)j7nVf#AfB0@JD=%nJXL_#=e5lp{)$^QtNS%$k^O zBek1{7`B6mX{JswWxS3SP(G_gEMOpN&d`)mmY1^$UUL#C&{dqY4p+3UhrQDD?RZ=L zD&_Imi_SaD*I_bbXT30hj``5N&g166ErsZ_U!x~+=rL$)A*1`P?R=bDoCm~1KB8vV ze3)rheGzw3qS139AAqnxkD?z3O~yP)FoG@v;^Ah3bo_nv2<=sE!Iq-W+Wf)?646 zt~8gICvsVHY+Ysf)NnAOd&pIN;dBXFT#eMNx&4%?qe*8DNvhS!S>qtfZigCeq4WD8 zg{yGUqOMAfqW*OdP3lh}kQ8Q-`=ru+&wqB+Y-MGM#?8uWC5(a`UV)MINl;rZ3=Gg5 z!c?mh&Nm$bRBa0N?$9w%dhi~efqlqRV-IQ|9?L^{+KX?pTWu_B2~Kg4H@oWGgav%F z)=VsP5+-47ca8c=D)Iy7x=_lVmTBUBGmS~iZ7)^FQ2d5)83Ds}^GUi{m8 zE|Y1?-wbsEdk48b2D^o8za}TQaO31zOEKh`)yRzmwlG4QfLccWlpvvCsH*WsR%11a z9g!Zp-K~_LQ$d=j7#kLhuakIUGndRWkJ*!u-fHvFIoATPnGu^zl&$61c?B$nwNYRu z!K|VJyPnk2N+=G$hQ<}}ps9&|T;y_eCm0^uy?HIpmR8HcmcU#`N}Tww2UvGmOyo9Y zA$WEuLVSJBi(kpHS*Yxn=jgFM?hWu=FiX+tfWw(KMIV$ncQ z%9+^5S#ZH8D=X*SUn--#AVFr1A~i+7p_(j1yKgPSWiVyLks-|nxCq3#hz6<*GM_CM zuLTF~LMCQ$SuFMzP@YBQYJPwS+=OR1ZV{~ku-RxzBP!izS8{j57!By_pw+=s6o3{> zp@y;+U=5GK+{#nD$YVK*a%jk;GIH;HsOWO0_FmVcvzEgkgULf=8Dci$fS{HM*YroQ z(JUfF)?hJrYU6zuQH?eClGCp%;E!EuARfmLw42h;kOBo|B)1%Jd2Gy@O)rih*In)j z*B^JWTX09pAM-ymfl*cP`s0>00&%n^J!$eo)q#v4q^dzYqI*}IewZ{|<7rX*=%BPl z<5?n}n$V6?Ox@x7ulEkmR|<~8Q;pJ0@dRr1*-R=D!j^0tWo9b4PVpZkwM%MuVh6g) zT%~5xw|UB`X`gMyz+<`|is^o>dw*=#Y#onsfD*cKqq46|&bgxn-P7Zs>QOZ3qWqi` zrA*F`YPbX{iW+yd(=A!52&iYZGsf!L=z%Y&iz?8nuIVRUfoYkC;$*V3a3U9VVgm3$ zry>1rDoRi~eJG zQ|SUH`l^UQw-`egpYBOMtOlXqmw?CgY#%02AM~4-+0P6UxJ-(7;E_=Aivk$`mcoogEyzC^12aGW3=}m5 z52T43Mu7*crMe;66ZuGc4cGt@u}Cs}9z)B+B+1^*n)9ANBWW6feMJ2Z*pff?Edl6Mb#f@$7>Ehj2|OD13n9p zi{n{u2%NtsDBUtJdjw&0Nkr)wPImT*c|jiUSXa%JC0Y_3nVT}Sl|!`5PH71l1Qo2C zY?M1s;KQ`c1tr?FaIzT0%5&=Fg*TcYn^PydNcd>>Krk!t4~IT-V;f|86-`pU-`pkIZ>3E{!Z!oh)8aesV*N#BnE~ ztu*;1(Eexgm;lolK_;a$n{2XPMCK9S`T-y3wqIpx14^zj+W<(S277x8N4xJ&-9~5M zoC;-?l_OsSL|4PaZPOq<03{jK3z6@ZQrjd_0rbzv*j0*R%5+H*O|^Ex4x9jVpOMF$#ydUSnu zSbK0bd4`ZWqr;j8`75J(YYf7Zxhf4;UczG*67!_7tKKXYh?aG-$s6t>Kn5RT56rv7QQnX$N483-BhzfWtT{x{|4eE+3lG`YH;k$lav$&aBj~NQy~9 z3sgB3O8!w*@*ouo@h?z1?-1FjZ*utvqRxzqrMuwi8O05&Vi4zw+~Hh&`nX13R|95` z3yKH&!v_UwL^1kh7bUbfy%g*h&${T`I~ZPB{ZS@s9g))heJpr6QT;(0WsA`Y6>}lB z=0#T{yz3I125;L^Aj^uS#TrT74>#!NHR1-70A+wDLy12yN)%GLfCZ!NHy6-Ic?*wb z=-hnv*mUDi<{_feo>QO_p+G7n}pZ(F}G#=D9Be5@hjfM0V!LIA9WGOwr4MT zitK$v^FC7z9*v?NIl*4A8+d<#TGO*QHX#(KwQzF?;__KH%*;@65*Ce&sa70dA57$! zx42@L>58Oro$}3U{AGl!`d#(ohi-CJ@Y7<2A9}!kM6v;a$h{r zzm#orGg2F!92Xi!i|{HyDu}Wl5IKsAiJ9EQjglgcDAXJH@?z;hfQ{y9rU!X!yI%tj5Iju4_8hTZ&P6!$HVR$+`-6vSrNq1C5*9!>f7&l&Ys$TV~GjX#-Etv_}Y({7`c|08aGwPa@usGED)r_ z2^`VO+V{@9tyQFfN++v^6hIl?0mUNcrEpA5*(Fal9C|m;o`#z0)VT%}dHyY48flsv zkecxTJwd`NF=zZeg(qs~wmRk7w=f53&XhXeVZ~+aSnd4ya+q!D)qQFa$fkR|+udT& zah0badeZ`&bfqf!224fOhqm79ty22XB0)mAOxyE?pK8UF8SbUrkBm1kh-ffPxTCCJ zo@#IVPTeBkhSh>izC_GyBI%mpbt0;!U$FqXb*6nT(Dx)D1{0-$#%^E_D28}^MYL{k zI&H}bA&qhsrr!FePCazw`Eq*n_Yh6Th`w-Ii?1$C?Ci|MSAlr2I)@>sTdTur&5BuLl zMs6|UkD0iKvr5k~@W)Wujw|y@X=FwP{pMpHlpMbr3M6E+UV#72s7Z_6X2qMFaw$6C zlj-xrlq>GYBxL1W9cMv7(9}liPfC5?dy&)|(nAR{2A4&bNJ_l)T<-at7Ek67n%rGU$``322Ab?IBr& z4^>9Q;>6Og!RdxX;lzv;90WC-Nvq=ytR@o7WdnhZqnL(5W z_^c!K69(1XWvhOd26WX_YNr+D)y97^QdutMf+V$Y zA4t54(Sr+*u2d;UC+6#MK73Ej-G({>tP0Uzg>9pENdkwIulv3EJQq!sDrV}|h1new zcX0sgqBzIDos(0fB<|z;wF#n4J6A)flgmhp($;jCNbAh>gVA9PpigtWyabakiv(P2 z!(QtR$5lwYQ@QTaR2i3C@>e=R_NOd&8C`GP9I&U{xu@I#F{UuxF z^HW}6@bAO;a9jubiaxd`jBJsd`aszrq-tFbANI{==Fg~XAVDdMiDY?pCGECRLqRK` z%Dt8KmN)GxT}UO>h2mRtUu24G?JH`o4h|iOe#w+`hW|sJ2PLJB-AU4$`9+i7_evRWldaW25X&3qq`nf>j(2x{LA9Q=) zTG3VAd2ue)a@e5Zb=Y06Zs~2zY^kn&dg%Q@OX`XI@iONXRsF&N?-^mdV~v#Vn;+2~ zV1JZzT711nbYDZh-6*=d+}@{jxWjs(j8rt%UIL%oc>A5D$?yOEQm!XnH^6m`SQLdh zH?(#9qc~b-!W-vNzv!Lt!gDv-lh^yM8_B{e#wkw>VL?Fd7AF*F653LG`ui1a?gJ#U1LH@xIhLro_(~hw+NdJFh#c4Q$s25qFId zMqe$TdO|Ubqze9Ct)SEqf80g>`#t8_cE0rJDsWlKwekT#hwJAlONm&?u=KFpymX0E zQ=$z?QHJoTiDEl@q76<_2Cvnrj)M=Fx?T(X>Y3rRJ34i71#uDis0+uERi~BjPj6#8 zj$_k#b8P?V3YM(pn|A4vrI(+Ncr>F#j>2m(H67N*TWC)A$&*v8(CshM$B=yKAbyjZ zPf&UMdzcfNZk}`;RcTJ$%s^SZyV%mlGt+IHQ8Jn&SpkBx;+bCC&OYRr{j+o=O+yoE^=?54X*#GmO|A8v<|9+5yv5T>T zqp{$>p8e1MYLSwpETa53!DPE}K$Btz@`fK*jM_h67$-TFuUtePMFdqaYZhM+v{*6n z%ITc;2KJ;FGYZ9CU#pF7*mp;l-pAF1YzCTsYQxiGx^4R@%W-CMrboBu=cpb@I9hPN z+3+EW#(?~5_28_(6%e7k)=+6A`$Vc%b&$Pwa9d1>Jz-=9fHm^eyt1Kq14X;K4-+pX z9tu$Uy-Axvg|VkNbGe3H?c>|B=lD20^UA%j)bv=M}PH6Vv++AUQt!JuLfKGB=vMR$TL_QeqhLsXs?s;u4p~ZHqmLL0Lh4=ClbsE8 z0-nuYsl#=nJx$$7MB4XM=l(bSGdElIIwY3n+=aWTRK(x}Y5Yi9Y5|_(+qgy}bysJ< zB(e0C9A)Q_jKc*9+cehe%N6s$2x>)=CGFZQOfAtu9?XdTh z(_$R{VT{iOTWz)~n5BxB$pat~Yu!R0QJ?zueC0aBzP&%a{q_C`_A5-}=kblm z&waOsU*Ny*w7Q5x?m3bjTIKjqY-98hoZY?TVXjAadSeXMV_2BFV>p9 z*I790&eH%rwR>+)(W?Td%hxRspOg6>^UphOiT#}F8u4@0`$(gE2h-0vSvfg1WuEi8 z4(Aw}P?*RkirKCZ3s71%#d5n*0;w0anlh|MtUx$9e~+);XPR6*F3AcB9W5A;pPAV= zY7v*XNy<2W?dHS$!QnW}6yM-lw@tgYwNB{vnN_d=EA($*CxM>v*hGr%%iTSJ`x0&l)|?R)#hboe^AGQiT>AX02b=<|G?gMiN6#W$JH=-f4AqSf)&Q+o2ksXZ*tnOQ! zcy534O1FXE=ky7#kh(js0c02)#*XUj7BVSF*hQcNpf|Y!Opeiy04@ndVz@GGr3Q_3w>~NecRQb~y z1Hz#BIGJxW={E_|$^`g|1VAwoHs;SKdSq*uzQZ>=cVq+DD<=R{IGQQveHV0gd zmuGJy3Sa$qS0mPv2k(PVG`UH6${oS|AubntF#LOTdR=VcwpqY)#c5Lb(Ig^S`zaUM z(H^l;%cL`Gqj~LmnPgw#BhQmHZL=~PXFajGT<5kqip7x8lDW%>^n9!x$>MX$c<(5L zZgd32^N6xtsBj6XC>~+r;F)UOqC}1ibdp3bPqIc(BlW|FO}R1CSK{Ld>E7<57NQok zc&N(B=SCZ2SVLnUPdXpDBVKwR!FlDEk5Iz+D9KBFn4(xBeD2(A;oyC2iPnka&oCk0 zhLLu`I*kuCYN~QIS$o^Ngu1Tk*y(?AJUsn&RwBNcL!kf09QwQ63;*xz{y%K~TYvF) z>#tJ$7yOfkCWwW)kuNuKUQ1#VQVtIp2^haf2yadSd~jk|ZA>Iu+bRU~Io{{TH@Fr+ zVM17d>z=z4AK%0}A-R#ukN7&$bUKrrv*YveegX9dhl+w&UaANPF>(X?pgnz98Z5aA#(a*DE+KHFJZ_0Cf9sYibuu8J*VEpu>RxS=Oc%ZId$^Q0f{c1sEG z%BFE}A=qB5QT|!OMvtza9hRw;-IW>X;4;r~r+3&Iz6rxK%t5nUxQ|7j1sKYpra`Ds|j*a}_ zf{;dXE|On}&r0nEYH{xm?F;tM_tCNbBd{6$nFsT9{*}S@QglX7qfa*&$@WPOA@rrK z#k*L=Oj@Gq1MX6c8}B0xdFx9(BirK~-L(%NqjXeQ-rTJ@d%|v9WhYuJnLUw}uc8Ug z+sG~f!J^BR2KF%^+ybsv+jK^?k>anE459o3cvXmO{`he4AL{g21-2MOFW>@E29XRS zr{_rOFJ#xfTk*zh@Onm0Nh;}{fm#HV1%N}^gY7@d0*l80EamJ_Nyioh;NVRG+ZRTK zfs_S?$4n%2;d4H~h=Wsd$%bIeO^dc83;=S9JutF7 zg-JXJ%?XE=psQ-(g^k1|sa~spY z@BbpjZQJ?3ka(Jjb5-WVeUeHOJZa-cOt@PwP)Jx<6Ch@(r{B2ZDocy>iyC z{38b`8|}5y6W4#dYGmh}ttp*=c(Rlf9q)Q?GjG@f)YD7qyoPg`-kYaltvRy28BUrm zb`o2(#t$;Ohc+2;*!DaVmHHt|W@eu=!kL>NBl7p1eHy&jmi0|xWz^&hnK`yx$g3UN zmg%<}+XoeMrW0dEL$}YC0>{cW-E3omJ%%>@wBNwV3cCJ)`Wg2)43epszO5k#LeUh>p-mVY|xfxxH+=_Qt*~@C?jXvNMhn(_8Fs(?)*2 z-O^6gGVhy=FOXL*P$JY&LW76f$=J%kACZqI&gjQ2ad~4a=;Wu;Q|R_ihr|ZQ@+t`Q zTWd6#HHaX2su46|q3*-r3yH!U`;9bSWs z8@5cJgvWknoA<`Jk93Y`4OtXx34IGBDyP}`iJ#`d;3g)P_aO>@zV?sU>|U;#pZcj(2Pt(}&wGh(i z!LVaxg3|(b5$Hr_oO06GXH&*b7l39{f&2zLNVa&#h<3ytd3Eo zyM%!$j!Y#Sxh*z9?kl zHV%(9h~cuKLa0nPS)Ow|jk_J$@Q#{Umxq}edI~%bVu~WauAh@bZGi5k@(E#|6BS6c zbC)f}nx{Z&ky~||-fx|l|6#{o4@{deO>ZTpNM3*Ejve3HuBg=>*DOi>Ma8}0NMTBS z$|ihE9Mt!Q{d?MJZgQ*szW(&UbOOdaL}9i4oo`B3R;O-8jiW-Hn_)3aO7=>K`-S^e z@)%Fkp$d4!MV3*m$?g827B$9ST>~vAjdNN{W`h#`A=I#qbgEyQIlYP)BPefn{lImp>1-^DIz4GfLp|6?JYY#uxuF-)+nO!BWLK+7n829YFxGTJnbh>M zsmQ`pQ{sluzwZ}Q<+TIWedF(6e%33~Dwb71ai&Hq<~JlBzk5x%O!Od|MQ)7&b^XXa z7eKlx1{&O^dvWBmhFkzW>4`CQ8E>4W7^k6OVUj2oi-?P7#%HL)zNjF2IFKG$-AK=) zvM1Au6jr6D)x}@6G-~g}9kc5s+apvQwp=J|>QM|k6ljPqCE{D}jZ4f9gLYYwnwx+M z;;B^r$|D1xAG1&m{2 zE|CbDKr!-tw}+f0s8wcY97ndNHLUEsQ`I^N)KfesTJmCc1okijvborh-TD4m+Zac% z=SQ;^-U-zCuAp2Dy&BtOJS~~tv?72sJh)B%0@PhdB6nS(`{f00NDUuYx$nX~uAcg8 zBeWwN@m&J^F1U=CoO53h?ea;)^-);Vrmz{1*j!)MZ@98b7#&gaC(ZzBah9+G2`~nz zPGnr?ZWv5YrclCtj3MqxEfUt44fO@#cvfiM*+?;EReUpkkhEL6m|JE@t6|T%e8J#` zHk6TK8Fp&e;&qgtcw52qj4id@0UH8(tdmioMcD7FvF*(B;4dZ%1g*h=P*RLaGXG2wQ| ze^lK+F!%Hz94{l(LMOifuEbV?vRPi3&$00yl~~V2-t^F*h{ge?Q>^{fHs{l| z+|JL4vST{r!z=xjk$}DmzXWR^Yb#$0?>x=5=96H753|e<&|7u0u|Ka}Zn7w0bMlnO z&S6pAAp(+!m^nhzQFv^~HR5geRQ3cAmjIKg;qhTRXrVJrn zg^z3z>s-<5CEEfhbb&xu{*1AhttW2^inSthT?~Sac~7y^K$nx)o2E{B!4qxuPFtcA z{oRssmm>Pa9_2=&3iv!lqvMAhBjSVU`N5S)cM?vu@O-ZXsX}XjN?_x$wLE*d39ec! zqQ)>Z9w!&a%C($Z{#w9~wTPCr5Z?#(kOgG%Qe2tFjK{mozT!^JLq5{!54#SSjugDk z2>au-I7)XLXE21~7p>k<`rV#muay=(rPi@EjQP6(COpK^6tbohqPev0;vNru4K;IX zX)k6R{gC`zlc0d*G{t*F7!*q^1J-^P9vC4Wu^%An#ip1)0;T(rKC9My5T|An`K3mj zIQJuB3UV|*|8{c&Y@00RzXH7J|8?Hy|3}GG(9X{Ks~hE?e#C!CrYbsi*di!A^&d^k z5>O6tL!ht=3;4NYHWa}r4HlY0B~k@zQNnsNYZd2FICd*KPv33`Z$R8*N~m-RfN%I; z#0!ZC-Ge`a*qPf`Y%`ik#wIqrt}>jiQrpwJKYeZ?en8uj#|o;@*^#$akmv4|d3T`o zhumw+5k*Y0+mbjSH)3pt?`&W+8M@1DM_O?v&8{=zF4w)fHQPc$w#}!zZaqYHH5=W7 zo9Oj5j|$!VOZ(q^5=HOw$me|%q|_|4_Q%IwlUDaGK9N<&maqS^Q-shJLu z3dK#mcDYg8wqQ?bBGh>8MbKxt#ZK8%v|DM__9D*7W=`q%u0nfbJJBdvp6_`czXJ|U ziSq?$a?rdcsMljq4lI&Xdp8lf=FQg}W}n{GpB2KK?xQUEhr=Law6PqyF+{}#megAM zV~x1eHqoX*>XF0c7rF$>bp{9-Z2gK|tx&o2;@-IRBgZN6<3HKSlark%j0Cn*!&RO4 z73LgZ)G#u8e&$x~vDS>AT3lw+@7xS=SdXz@SLhy;Vk+B?SFtQuS^4b7L~Py)EUy1S z(d~Dt@P(j$gFT*!9YX0-A7GjKL3{I>YY;NM5cHUrAo5ZI@r3f7U8y-a|~hYOziqwLprRb=<4Uc-5fW&4|17v2=-_!p^CFVqx#@6~omi+Ea2keT5Eq zV5oBW;!;XIg+R|Rykad!<6>de^iHifx?@4z+&$-tCu+jx1AU=kR-urgqCrX#`&M{9 zJ=DG>VQM}(gbsKnG}OD?x`m|Sjx9Z#g534usAwg@v3vL^PF%4J%<=4kbyP1N#hOi0 zx94HMyW_7`9}tXyO@VhQz&gUDBzsgk@c02B$J(WDv}j{~gf2fKNpi9%ZMRC;hPCcl zeVB$~v73_mO$tkUuq{98PPEgM6}yVCIwcMH&{}lS5#x;a+a20f!nIV{Y6rJB6j>3w7On3=9e0rt zW-8u_gTT z7gwG~WaS?@0qaD!8fvOdv=;vKT*6ySZX6F0X&hnfXF1<%Sn=DA{J~^;;B2wN@SsuL zP@s0$SV%+)g*6{x)(}BB-6da}997mc(x5_V+)$UKv&5`Xu51|VjrQ~2*!@*equjhn zrPP!xQiTVgHhPj+8JVUQ*6Sz}5z% zC52Af_)S1$Ty-(_9BRPasDRUVbT$I`6+{{g+iqD6GtB_)upmCHRL=pBNxK$LlNdmU z8LoU^rqr+j9H%k6)kr>vXtjg}VkRBhF>K&Z`@jI-cupCU*_0uvn$2L0`2e~&AaL^4 z{O;b}6K&ciYrbfb*hVGwCbSGDnMck5%B(=;>00eihKiGxRH z5iTE&J9vXsLvr8x$s#`9AI=#+0mh3|oW8Kzx$VgLMtkzH#0&VCj@-DAc%ew znl7q(g;0ae_*`ep0JfJUxV`kdoOAh?T(@O+0r36|bzlV0sC0sdFjcxUGKhs9zt&kz zg8uY{GuTZX9!sq(V`iie6@OjX@%F8)-Q<-HQe-5CZg^=!{O--C8zWCXW#1_L9^cE? zgXZrL?y`*;^V|px84$l>`v*3hvRdS#QJy>oc!o>HIR+j;xHH94xb*ETafw`DatB?4 zwtmFz&XFaHmtDY>RJVfT?Rz2+X-^C8@UMnYo)5qhPV9UY{)ax3U8eR!Fz$cgu}2te zExH{``d$xz)R*7mT6YE?8yb#t8aDSMTuF4l(4LDIKH*g5zMnf0I_zCEr`f~jWm?ez zMMv}Qk4`cXVz3V#QK)K%N%XOcPa5qLlYD#8Ke#l&A=id_MZ$l4@>x;(ggL*L82~c{ zxBY5(VeLDr65=dWKZ%YEbsq}SAKFc8;&a;P`Va>$oqw@wKq5n|^`Gb-h z(>B8~<#UYr1l#A0`>QczK8)HsmsH253sWT8{PQ;7*Mvlo)w-Q5aJ?&Kr8autg6s`G zIW<|mklqMF*P=GX9Hoby40yXFeMcMN2l2H*#x?!XiKOUnG4{;PF&F12U7@_@i#EAe zSqZN)H=#<``R~^}A&sK^)rJVVMpo}V4+|F>R@ci%O`)J82!&U7-~DXHf#&DP1*lK7 zjy0ueyP}(%#^R+vIos?E)l$N{KvY`4k#;nNr)ST+$erAqMcvP8_gkb{d=)(U&;(*$ z3jUsEde3^rzpaARFWUJaa}B*Va-M|W6v&2sMe|gTek!m!mN_ro;aNDZ+|f;j(Z#^{ z;yY9FjB$PQ%zTsLd_i4(Va0rbi~rP8oxReo5#u?6t6_GZ0Hb!pcjzTsS!ZS+%n@A; zDW+6<_QiwI1==N8Oahx}Eyo!IxTy*R1rzAY@}F zlG z)F$W$Kkud>`NxRn3$oIa+0vmN#+@Dq+-Hc$TW0?~J`VFIs2_XZPB#yI1cNRrQu5@U zaUWs4nY+-frq#9Po=?m&mRZSuBl1=e&!`nX_8E>_+%mZ~H~u@|ugvVdyDc5s*CWjG zzv49h1Lyr;fr_dI)-ERhy}P(j`HNI0kI1v^a53aU(Li}6W-cUw6Nb!ht?450tyB^E zXU@6Zgv##jN}^NLT6X}La?Li#GsQq8Hgr^5?X{t<+oAi^M5EuwpAV29F;yTiZn!Hg zYGma@m+zz%M*Tw|*y+GYc%k#2Vmb3tbHC^jOc+#sW2MO?xJhwEsAdS)eP~@UIz|Ez zB(KK%Y5g5P*_Vt&6#7=-_vEi2xouFuEa5>XHugKet6v7!ddACyQ2CIDB8jMaN)Y7x zOA9@k3B;$PmB1P&l=4(6mc}dhZ2UAzycBihRB`T5s`>SYgMHU*=u{j=8GCZm|Bd2Z ze2Dn-;`+yFvo#ASK@Rjh?V1VzKh|NvU>4O~5r@C$gj@rwWSKCgnlpLU)Riu2yRPNZ z5Xl5xroo!qb#^EXPEY^UuSlcgO{HRfulpd8qg%-t(pkqNlOwXHPg?J_eqB2Bm*1nV zCViCGLjbb>;IBCjfWK=kS=bfMYx3IS*Vl3dckib2PS-(EaK? zB<}LJznSG?Wkg~xUv0Cq|4nB8S4aWZzn7U6O`J@eo&SLw`v+s}pZ)7mF#^zE$X=1p zhQ`^l?Xf8InW)}iHAGMWdHd`Td8IkgxrP4LYal#HX)yEv7|fKHiMQcv{ONUEpy3pQ zo>)d$Owph$rKsB=_bzs%x_p~VWo#Q11J`3&-F?vu=e=fKj-5)aq+KdVt21aiI>9W| z5(0%+UK}V!%QJ-i5YGG(} zOOF9L!Zr0;@uYmh0Bb{dvz>3;2`!W;3xXbl+~8f9DeLc!U_Ffb#|+Mxp0GZG8W4`D#&HafE)D&De{3E>3*&$CeiG%!|2iodm5a|60nadb z0pQb{-0q5=*D!|ImLyH2i@q5Ud_6JWl_&(|R390}&nIZwtDp9uei)6+7#%aiVsHl( z?`o$>+p3hn6Oq!G-uW03(J3NjkRrsLv4%7M)EwU~is)Lfg^ZuONSDXL^c7m_7Aiwa zU*sWkLmtVTi({yYRzv><(|21f-B(iMK)W0ETKrQ5sp!F$c;f7$ZVl}#b#B?yNbjmG zh)ml5I6Y?VDJxtB~eMr z`ip$~RX}5QI*Ldxn+E(%lK{+1`kaLSg#^?*4KWZ~UWW=5?Zo{JMUEw_c4#lI&Zs|v zRFFy#@|z+XO$16aWP$4zDR3za?@ywSFgX%L80e>{s0%h7mL%`3_bjI^A2&MPmuK!D zIPg{&L&7)`#)TsijF`hHMXXDgYBxW?Rmh}w1W+MZ%u{Ao+{HcdlGcb7xv2&tQR=Di zlo*S59Rw#_#|<<2J^EsemI8^1%%7_$jo!o z@=Zq#h>t!b>Ak2t77NIpcMo4le>Vmq%^NQTWBH!NLQgNlj8Qd=@o>khS4ncO( z{g0660Fh()6;%rt$sUrLE+P$dqtk%5-G`y7)Fjf=jk?j=u6t zaoD^WM$U9?vJWS*JudSW+{?ywTO;F93sod$dSpZR2$|uPfC^iVFyFEM<0wv>vrdJV zy&ZP>!~|0k>r~#A%)KA*!!yTuo4&a9ettARZxZ)Iz#y((pKy_3$ZQ9%$WpXE@1``~SYnz@}bgz{_6w6`tR=nk*|Wyzc?@!cDDZ)iy~1`Myj75(PzCVN+!P& zzfqH~CvYtSqhPym@FxYN0D@)j9$Sd36fcR)n~tX<%Ga zhnJr(n7+P_5FQK_6&92Fg8X1ygb6BZh_{wI5x4Qk5;iXQ!AN&4rex9edHu-6S}*Ap z=YA@)&rdE~JV*<2S<>^Lg#BG75Ilifj^%dPNmp%M01{`Mb?D#@e6L?t5ZYL3x%MHn zW!Qg;FhXFX+Bmk|eussLLo{JgcEc7H4sNgcI8!>!vfQ2}|0fl<;>~(PEu!pRzILvIVX385Zs1tQ3 zE@3(N9Yw(HoAd1_e~Wj@t>;&bk3~9k#p}g0)XZ0+L#lxSTc?xS}P2eO$v`S9#q{sP^VpYWAoWLk0eugGC>G$_TH`xY!YW#JT_kCsI|L1LF`}f=U zPZFz=i{W1c*8dXCQ?$HM7IBCD$T|AS(h2#0@DtP`bpf^`@5+W&=pf+k=HBv44u0i;eAY2H&&hRcge)83? z1{oBU?-O?OB!9kS-F;?{XT+=Vak*ge^L(HT(VWu`O8=g|1sacOwbp|~2w{Zu5_*=v zAg!A8t@5CV6n#rL02&ua3T=Iqr(DE4T-ae4C8mi<+JS6S_Z_-*0_PsPg-IG#kFMjM zx|K>ISI;u$7`mlSDprrK&(J?HJu&b|J0KaSOfpl?GVzE$U>V0u(yQm5zQs;LSD&iu z7`go(b8jO1o}^SAbZv>jyz;OWe60yt4P$<$I2uXJP`O&Sei|i9ylJ~MTp0~dote9( zJQm3%Aq)5m+KNp}S@ z`C-@emVk>EZ$C$4)OjwIb_TJvWM{|_S#>5hy#f@@5mF@urXH8JsPi|jt4KX6K#>}j zYxG4s*Lf{|zdvDmYp2dy%Fh1x%9!f8Q454ii)FmZ)i5a|*QRn>-V9b^d&-#(`ZyhY{;qlfcWbUr<)s z{A1$Hi}aSO{KUnFzry5dyGt2BLtd8>1}YnjNaiswhatp>kZGJM7)mERAW}uVu`3aehoiogzSF}=E z6;SjI+C*YthQF{;0NNI?4Ds@Z)op=2+l?I?Yr8wr&0bf}&LxXT% zfwN@PqD|+Xk5q+5f45~*)Y#lHjmT5US_gXh3Va!WI$*(-=AVaNk~WN8)Efx>Y-^+Mps9@Kepn70%XBquhuGwu*ppwIHexR|1!k?o3~zUR`@> zbS_$klS#d>f5#dv-No7o%dY7&a=d@brah8$}19z5>4Mw4M^G?znibbGDT zFuuq6me~vB6SVZP-(10-#(EJ3P0jbwB@&Uez8QM+`0itX8(oOdhj~X z7mzJmtcFYQyYNJ68)tW$VepP@LFZjMmgZ|W_DbKXpRg&E7MXUgvp-cNwT^s)rIu$u zEb<1W-<7qWTZ_oDh~-+2VH@{sgoYS}uRVxSm=x5TB_c2tE8} zZPaejl)CR0uH65m$5j7XeE6{dZjU$M1b`Nr1Pr(H+)|M*1jT9t|4u0ggK|$_|9wL%h zDILp-s=SQj3>A>x)-7bI?HJ5dsSr{Jqrloi7kPG3BPuY$d-|v#yAdnWP{io~ETpox zhv5p0Iy^ErNVMX%_egSMMlTiD`mq)8WYMn!%65T!gtebV>H@5g_x zihX3GazkPEy<%^D62=hZ38!-Zd!EcEK*?$C&d*FXW-n88T z0^WFl>ewJsg_3YuYXTM?^ed8Y5%S*Z^&?u_{?VK7imfmj-?zsXKt9p|18eLdIPaihDbzN>=1t*Re zyNo%}{(HPV!(9z!dp46|Sc`vHm+?J`a&sk|r=<_309mletrl zJaM*o$4hj8Jw{4{d2CniSB(Y`K>>)kT_Z+GIhH9netXSd)l(fAXL?c``@nfhjq9uv zN$Mh#rut6oefsQw;@$eu=dHb`*z<#x$MwQc^1{Io@lo5~M22|AWC_d?fHUhD9#-&_+3Hl#0)4ybnqbjQjjMzV4b{N1**0Jz0tIe>-IV8ecR0dxz|=sSV-= zPUe3T0{`KRMMcT{B|HS{y_Hw$xPzis3BzUyP_!YU^Ymf}`iaNS3HO%&Em38h4iz%P z-r@DX9=^2k0f`qN7J~S6*G02tYVcAVy(O4u@@` zWr1uFHR4?Jr}@_+RHrtSRRM@5fOWL8#kjAzS}kNpd1!U=+HGZyOQCj=ag~=3^ahQ@ zKVmZ~R3$T5Jv!#8hAp_rNvkO&ig`0Gpqb20u>E9gMTU1F+>~%~Ltq{w1xgetOsNAZ}8j^mc=Gt1{#SqadNdJ!Qkj0}4 z4NqC6ySSo|p&b6HxgwX|2W`9GBn(9!{ilObXNscN+@U|pc@iL5L)*eTYt5=S>79Me zMb#+g7>QHDTtqn!=YOcPq%pi?I~|spR~U(wkS{c`a_7^oZOCXVY%ZeON;x}n=w!ru z5cwO6QG7A?M8A_rxixe;NttPh%jI^tv)7uAk6pu4#WblO%Q(AELWUr-Eatak6A#Fx zi0&iAYSoKa1!BP{6|=5@n7b~OX8xKQ5S%md7!+j^4n#9vD4P;*X>D$2#nHki3W0J} zX`o$bWJEdJZ(A(+uEhn_c`95;*7kBhiQ|B*l)RCPN5Z=t|K%{~O*)gK*52*@ttOa*O8U=l0chQheoIUxT}I)D z*7d%?p?ynWhjw0rnG69>w??sLivZvcxMiWnI8{gUitJSBx!LwC>m1{62KT%5sEE10`ls27@| zBsX$xc0Nf798xA3&`7R;#tn1DUp1wEt}evV94UI}m<=xp2bO9eEUE=JlazC0-Xx@j z8p~jwMT;OC6X5kECS>8%iyw|W)0^4t}68~v0z*$d4MZH#GR zDl)mSpF^N5TKyilY`A%D)Bw9Z&lL$~1`|q8zf5U{ioA`3m zDU_D;pbgKIPVarLYNJ9ZND|g?Xinn)7an2iFNBF#_CgVE0BvT zbo%>Bs!S2v*%S?^M7`Y`C8n_k!jdkgKIto?e+y_AH@Rqp>bo(lVO!<%!~uQ<+(XT; zGF!~V*~`&L58v6hL%8kHAzbd0MBpJ9<}}GU-ZJ3b=##s8)ZjKanneY1Xs!fCXW$J8 zNYI<7MvXhy+;4kpZzG-ATR8Hsao%pLdT$0!@7y_C^C={iiK8Lm^bVXNO_bhj|7@8g zUit}#_lCiDv+eqO2MJqZao1UvEgUU|Jy6PQ_YAKV(~EnT=B-&QV{(*ZA>_67N&6Dg zVNMdNYY6vKMCh7UwrjL#eS8$qV#L?X(^KgCHN18>p8LYDWzWI(70lJ$o_?> zzC?eX!nr<8N0^xCHd?(XgV`hG;ez6V8~|s7PZlwR?U%oa<`$ORfS?W3M%SA#Ce{Zb z$71hJ!_DXXh7u8Q z0emvgB-=wQf|&4@7D2Mtt{q4!E0Og;?hHsa=Ary4_?zFLx< zKTjLlPnd#5GL_^PJSN5{<4!u3$0+R;cw-nSbQL`b7j1(DNcE$t@#(T}80xeNAe$(V zyn*J(@qhG&@8Ui2%gJhP^gsOe_uSN#xh9eVNU=!j8wmhbxbOcKfd1QLb2=73w(#O=R(5dn2bKXmCBjTxj) zrt3c#xIU?OiWk_%; zk5?3}CCOgI^!JV{f3eGkh#1nN29bWmgSC_rK~0vI2#;1n()ozYJKUiT3!dgMb~JT#E&BIkpr;5E z;fIJFmA^)JqGBMrbJxp+!H0rqz=v~(3g-3~N+hNcq^TS$&VdJOBAPzgrXM4XV@>9* zezIr>D0ch`k?;_Z8>WNJ{Fw08)aN-@f?zI?|4 z8?YdB;QYn`Pd~&Np>UcK!X$?29Syy};jMmroj=NmTaKgB6h3AT-BpHqng7EPA#p{0 zvZ*$$F;Xx&Zb;Jv`={;qq)3CZdRgfAP=#$TEDoA+<6E-s7-*%(qEZ*6ggurP95{>% z^8xqaTa-q$ylF)%!ix>E8^NC~>2`c*qk~Cm`$!zc=fqb8)Uq;naAFLDfLrUp0}XJe zyA2BDth#Gi*0gEPQZb|D1D&7O!BaS4@mrT(sMh z*!Be%udV~<<~zRs6YaX$RD&#(Nz%0R(rwy@`u033S&f(*RqCbmmIR@)DKb?()CHe_ zAZb4mr=zwYyf14FWTz=ucgbdI+Iu1n>aki8Oz5w2r%RgZg;&&M=N*gvQ+*}Ob0Lko z@|Eu4-}{mtx+3_F7m}%2dbyMd2rUk@j-}5KYoogPlRFe-?7G7!!`Vpo9pM_$&F1K@ zT&kR#LuA8T<}MwfmC=5LyY76Xr=k}d)RtGe3RWPadF?&ls81iw(Ari|(%cRrB%RWi z1e3k3bEUwcbdso?gR}IK6wECMq&OKhO^pJajUpyQ_@n!1Qe%Q0X;jA?R!D~PRXl4| zWQB!gIltv1XbSSBplEhjWpxgK`Y}80m2=ZXO5U~D({ENc7~fp=rE6!2cK6T?v`%!N zco#6d%E>-X&(Jc*33<2i``hrMn_l)&@YJNPy(*Z#(d$;57HG>!xrr z$dB^GmUg^bfs)69pBuR00Arr#Nl`6Abi+Q5q>p1N?&4KLMs=85@m4n#+M(zsh~2-i zugiW10Zd>v6V0GUCi`foky`6iP{!D}?59Pj@#g$rdE14Xq&>eS!l&x;lTzFNym@Xq z07KYA8i#qD<9^IW*bgAuv+cM5Bzxq#@M9j#AL;du(v-^$yK+*tP0$7?w;Z&T_ie(2 zY(c*X+JW`aS!JxY+c&Z4+TgRn0;7Tc)`uHi!dW`~=r6&Mlr4ypB6LU;y2l+a)SAfn zrZg-sTy#ms?DsvGDZ2C)cp@I%z`p}ye4kXEn4XkbFNF3Mdf-6iIiUkhO|tED^vpi+ z4c0b3doc5sjOm7Uh1@MJ-0fGm-LTsMuDify_||CqO~~)S=CGmm2ANMS-woY?J97tK zOUz^3adTq~F9W|H!wnL+Z%I~Z)3wu@177AxT2^YmRZCHcZEKQxl_ZwsH0n)2q(Z&C zdFvDE=;8ydq-nDYsOKjoyQ)&0%sYb>UuA2}Qpe|y@@Y)ok*erUr&@V^aoK& zTCdbK9Mva>V{dvR3*(geOMlaoF(Xmhwrar}_Htru!2 zRX`aXmM6>Zk$xeuJWx_6LCBZzML#=0Fwge`hk8N2Z8US}^oDO9IkKSk_~tg6 zy<>GtdOxoBE2cB@YFuy6<3+23#4jfKfSR33kCe|V>g_y6a3r5d>_Z|l*$;{NKu@Id zD~lgz_fzE--!R`>%sS~4#pad==@)(&?rlnopn$h3)Qt$~Anq8V8&z_Pno03*?8iMW z&v_2ZKyF)2l2L!7nfZ219z1(cy%BDp4cv&?&Vg9`S;&Sy0P^zMj){ANY|#QX9OELXC~jO z6)K)!+Gx2vDwaJkbhBd5T>ebbHET#lHxdBrih#06dibY9nrou^+BJ#rFOR?JCX4(a zGY5`U9%3J*q;X~m=|rz#b03#D%4j3?fdpiWELCUVCZ<5S;~7ER?T zMGHTZ#5rXRbDld6l>FBFE#{qfgE<#kA`>~bxPw9-S)qW;po}U&4%MiXN~D|vz8C4t5zDLJ6n0*5ojSEaPqGCs7+I5#EWsWM8P$gRa0v4k#m`JTAy{u}wFn?p1W}^m;vRU}SsdlYu z@Bn6+PD5GEv7(lUv<)(PIh{k)DH@kV@D!=Rqd8hTq;gpvqMcD@k<_=xK5vcef|3hJG52G_( zj24fnjF7`}G~XiG#sxE>E#usob@c>`rSwdZ4usksq-u87B-rQdnKG-_2p~>5j64Jj;vsd6=L5aS|1F%AtB3Y7zFek#OyI& zSfK?#_d(|Sm2b5N5sV`t#;l=bos)1i*9G&bm^0Q z{-0!@SgIb^_sfxL3Bc-bar$+f?zSxFw4VUIz3*!=dvQ0#+xPCea|WUAO%QO(De-o3 zYz<0H!1>W_@{QG*lW@I@9KKxES_vQSh_5`5M0b)EJ#&Zr*SxM~TsvkiT`v1SN8wwD zxQszlbNl2G1}DmhxStHpaoNDN=iP@$mjhQA6hxK z!%SKI@D)y+7dk1jGuIwbz7^&7SS)#cR@Xg_mc*-S=?!Z3O5wo@f*6g%gB0UI0#klz z81e_G6r?J)0R|c0Vrnt-qv{z}*&$GeT1%KT8Q0DGwTUAOMIltNv}z|;Lh$lo)}w5- zZD(k=!VHR$hSefLA2B+g+Z=cwvDRz1S|GRB=!TSrNZAdwqxG=Vwx5O)-8WjG{g|tU z_#&-tsvLMW0ldYNEzy08#*zKhoIO7Nmu>VXKyCwcw1d2zS;}iJ11x~#mGI~Ip{)uz ztdp&?4~7XhR*w7jwA!gRfnJx08t7WWK_F3rZ?*95KqCG zmxB4ZgvJE&`QV%8A-xsTi%FF1g}}#SBdnpxKf`iZL|j*Tj2m2WX>D2v;G)lzgf2cfJ-}!AL%fo|5*jZ8clXLzJ?d`Zd%nZ zlRZ-;I=gd;hOa~^%!RvFD_GL+F_{{Yfptv6g>e42z{_hPLSs`ElaOcfORT&k35XY; zKhKt}tEy675t^HWUYM2Syj>5rQ|6t1t1xrk5umqGp|f*DchitfC2!1uTYUkYYdjF< z15ociGEZ9#KG$0u+eaSgpFgpuhJ-VuJj6NdIVZZ|RPh>a1*z$4Zfi{+@&A&uLE=D= ztkHmgxW0-?|7TJEKPbZeE3qNq=xE^a|1#`1GeJuZTMcpeb9ghbw$nd|E0|x90KGVMNTaI>e#6uoje%sZ&;6mV>{^=C%hKTOqf^HqWBfvB-;AyhR} zgWk%>j!Ho*&FORcY9e(N|MTS%0*I13dWZFQSRT5Rby9vyxLZqd)GrS}wARSYwJRt! zqp$;UH1BVN`msYEHn-J^+ScLF%@}>25VlQEn5R|mo_Q;4RgY(afKVjwuPI!>lYcg& zv)t|jdQN^L+o(w;;^wD}VUn8Z@-yOWpdFWLjm}jZs1yID}QwqqMU-e&n&q7iYHNpsq$;W?kQ|1(Y%{g6$s% z09!7xxNr#pXigd&UxXq1#WlLn1ZHeZov{2}09Yst@)luEzeWXp-du~++RnSDXZ%fly>i%NI6BEqAi&=B6P zq-CNX;Ncz|N+}Nxui9IGub!^yFgc6UDQf)91NA3GiFjZY!&CQWDs&02Ah1qvFfoI} zcl?BJBF!fiqls&2795u$ip}m5T6#oU*`}7j5=4-Dn}L|I0#9F2Pq0;ifP73Kw*7wdY+ zjC56d?g-w13H_Q0{?xdy^hmvW0!RxTgjEd_?-Eg!r@CI73uM73h}9cn<_=I5$k?@5 zR3qCDNC7yc1+V}tvXY+|arr3;P}=cEtgOk8QbbYB4wF$1YhtefGc5~8+6^Gi^lgJO zEIbAa{r74Tr-sVCsRS7k!Urgv#?XO|Sd<=6^^QY>9BK~xdlMe)3ewN`foD~QA*Rp% zU_QgPhB&$Zm|j|}f?#0u)lAUxm8kun@3Q}(dj7AwOxe-I4oL_LixuyN3z zOYklmdHezyNG0Kns+_yRzJuSw6Blh2x+*jJzzl1$bp(=lBjO}E^owYF4k3D=ltsZv zyzAbW!IWZB|48UP8rXZHB)@TRGm6m%58Ced~vbK1*2EG5tJAzis+gLqA zg(jn!8&ofo8TgOVZicddl>luLET$Og7 zn}|z>Ir!;pZYg7Ihxin*Bg>n&LLG>N5p-aG*@30kdmN1=Pbh#@WLsDTe~ zt(>wzN}}BiChug6nb6b2i1BV!%Xo|66KB=#5Khki7JsWB(Es7=9h@T%*R|c5Ol;e> zZQFLzu`{ugiEZ1~#I|ia9ZzgdPS)Cc*T#2hf9ss8?th^1tM`4L>%Q)-!D>bh7`GGo z?_Go$ioO+;>^(Wrqx-NUy=JSVLtA1wyale7tr$5^b<)m>$n3wx=$1}2wEJC1f;UJ5 zv2Br?TrU2(MK9dq!4>?%Is^V!1=znp>Wc%6o$Vbx{wtlE^iSDc$fw-=m#`OCdm43| zE3}y$m68|@IYJqg3OcN$Z4ZQfxQIRmZw;P!rgs9>uB>(UyF2Azm2DPljKzLr_RXaC z=d`E9-;d*ChHuQS$eR7xoR|ChxKHs4v&xcrlqtyUq&Cv4Mw**Tuu~q>h*KEruyqwL zLZ*@&tRlAXo_I@EH!G%%UZFvKn*lX49yk6>6L5OZ0<+wt=(gX`frvIy%l?Qw5rbeG%a zk_}v9B=ea=y^nGYC%g-}e@q~jB0wqY?J(mlU_CAw9=jtFi{GiTUPeJv1FO|s>^AP4 zQ&d3bnE#NNhS*5P@A>Y!Bj3d|E!d0OQw25?6!xe728@E z#5Em(Fp*I$MU)T@$m;)*M8+!%z&S+42dMQMLn#Dx3@c_BU!U}ozZtrFhV+j36QSC) zp<}NVdph+z6lhg59hiUG@HE(IW@nup9tjoR*fm<#S8{I?Ql8;Lc;I2Ln>Q3Z%nAa@ zNnfYJBtTHy#H|yyo5z^zVTK3{cSger#jFFWp1Fojv{T1qJj6IdS=Tt3M_)l!HenIp zVn&&?j&39E8ikYFER*NP##2?lJRv>G@EP1f=bRSfG`6``C%p8naC%wL46^;X@_nh^ z&&)N?Ke3cJDA2HY`u0iraR^P2X{M&<-)6RcV?dvy7_P1e%bZJ4-)gd3?;oq#RRA=`({Nb?tA9FZ0V#e> zX#lR~068xH;ONvN(Lo=$;?~lDu^Md0o_LPM3g5D6cpHRF4Id~kDpK{W>-zZ6q$RC)EO&mMRy(u={#q?a%{i5!v*ZKs>@~d!jQ|?xx=fFmuO8IE{np|rj;40 zkFfcN6A8*r4xn@9(EHVSJ<%6p7^Jnv;L!5tZy!_ZoMD01r?y@I$1UB3|a?1y$COWD>hbdxv>mY@)5viXYS`_XvVWXECaf=_yp-Y zG@5*cX-#u@61ri~IgUBLQF}>XjH{kaW{v=xqe2 z@CCVngO9;S3lNv-MHz3a($N!9E{tNx@|Ir)G{_lv}S8n776Qa-DvhB)HtaeXN z@o2@a=dJRMp%9`vALaG}+wv$o)tcUij;GSiF2c1$c%to4K>#vyVyA~a^T5Hy$03^F zFE$J@SuK_eBk%_Jf7V4CVy-7jm%PCS{v8Gr$15A6ckQX7Jg^gfr zN_t)S2j6Rx!x~=4Bq5g|-H{>%*@Ub&f^6^2H9-<@*;yyY#Tp|O&*vb3YK(NMY*e!( zsSKz&7RzM$koC- zJ$Q;HGWAJyG6Q&VInNVxD(Ra)fUr>Mai%%`{51y>k*Q#a;IT@^lN5**GUllV@}l&W zw+D1mY?Ih8Bsb$TT}So3*}rz^3M?Jo-#@DMiPlsdy-P*Kxj|7m1OIuwCmpJpb@>XC z6#lm$$^T^b{)N-Ve`WUm?K@4@uyj{l!t$N5;Yi<%ivyDjfP@63kueD(K^3GShLeAX z6_#r9Om8Fqk(lmm1`@ukZM#%qt5j***IckvqP89&W28&ziu6a>8tsW*dxQUDj$ms= z;x)&~{!(^dlx!x^>x+TQe)8&h$a=f)h{Xk&4Rd?f4A~mO-6ECXm>8iWdq%c<$a?9W zFZQM1JQ_*8NhbDgg7kV{joe`Ko{Fsn;)u11)LhZ@Ww%y>?hJ0-I>d(9C+8uP+}_y2 z?NIg6Zjw1%CC9!U%;+3;f85?|8F?e@q!#{g+{+7jD}MBGJo^69sv$2x>2{e|78@KLP_zf(%L-`m#$CP+3L$_N6tq_$pK_MzA2peb z3L$_>vSUXMH1k@P#aUC;?k)8-=UlZ!FmtitaK(-eTyrm|BTJS{o3r6fwn3+yNjq(g zU$rS=$!g8(QWMOQ8B9@SPGn2a3O=a*SjipS#Nm|)Z>7$OGS`4<{SnCl@)f zlEc~o{??LyDmUB=YEI3qtkjPUdTj4CpLh|OC|g95d}+%H9%YfchAH>(q=K=7QpFsd z9T;xoogIJrhZTHu4#gt1eZ0ub(Ken3xCUUh#kdAv-#Dlch-Wsk6<6gFY>XEooH2tU zEsl7L_LnP9S?v8y%IA@dX}J(qz0;h{3wpHr1}qo1uHfThOuLv?E-?VKO%nMh(&h)n zpWB|Z7Y15>;bW+55H_ElQzq1eUK++DS6UvBNK)O-rCDw@%|7@@ySEdn?t`VY|%OQ&~a! z1o1n?iac(dp^mlz@CxK6S9vv2%DQ@xF{&U0dE_%3cI`rjV*YRo!m=g%YQe%7B~!48 zu{G#?vabC#@s~eYY(a$=_7&K?m^f0!RmQ526wKIlX2GV4vg9GC;^D-z=APiMlhd=Z zw@MB)E7Tp;x=#kuX)Yu)KgzS~zonags9H7!H>sABRI!g*Me6aObZooaAzuNj-I>Ys3GZ7ZN%hfaZ z%7CfQ$uS1TsWCJMK#qh1G~~b3r%_}hb7L5qFT_4?DKXZ?MEStg8lY__`xuAyyrpp~ zNzRz`=nnI68<`ivOa_o>mGtMU15VP!=Xm(hX7@H!d+(;MbQwzrO|q>F9J#RvadF~4 zog#~EYH2*vopK=Q^bAkM_+7mnXQ6aw5TBO__Yie5gsIPN7exQQu({~VB9}VU)%Q~y zGa23uj^c2+Z*>Ex<;F2S5ug+<-#c97GIkxVx7qvHXU$F8C-bYgBf?IlDhT+s3)WSU zAY2(-o}`mrPZ7e#;LKhiKwb9Fr&wz)2u9(LDbbqTTKH_H7r>pjH8FH>6MhFA;iCW>Q+nT(me`U@@UmM~@IPkAO%d`|Zz#r$u zt=kqkwN4DVN&U8iy$n#~yLQYZAW%_kpmo5Jj+q|v08PxpV?TM>q;NayYX>vFMiq_j zlL$gigLe7q9LqanufTOFkV*GqU*34;OG=@&3e0zK2dk;Rw(W5U@MUC$rYo%ui1`+x zD1JZpVWwu17q>RKQwVH(N3y&r9;ka7!# zPnRh$kk0}xroaaG5JWHDVG?yUkQ|;G6u!{0m_ieXC4tuPtJaE(!y1naJXxu8 z$uR-aI{vYMsI{t=f*p02y6TE`rQ)sFM0iboenzo17Eq6r@tnfIoEa7M3(88@q-3sf zceJ|XEt^soNvb~)xI!L^QAY9_jHvNrnEC68dYYHzkLUjAX5Epv!P)@%L-2w$U6+n zMQvJiPd>h%IsV^3u}1~w4-ViH0s5$4{Ltrbm@DeH6{U83ii&zCmG;HyL+OGsT~~(@ zSud9#=xa{(B699FVeU9;)VIy%p*BJD%=c4!6l+eZ(3i<;C!*IyhMMAx2|Yytr(fx% zw%+8_dLeN50?gw6uWG1;d*#J2EKaQ?BEoSbR5T0ZWKHUdWGNw;CXwH3P?imPzm{0n zpv!yZ+xv+>lAzgFaYlYKYVg1CF{iDNICVJ`w+v78E_G1uJ)9G8Jr;O<9^{3+oWH>+ z(xMlL(h`e)bNOQ8#1LgfAT;_6Bp>?8Top|cnz+@QD((+bk!Cgl z_{j9?8_2pf>#>bziOp(0y77O@9K979iemrhscZyjLgiY77*qw&s~^AAkI!izKG%;^ z#bU)U)c&-3gzxwichnyGUhWdFR_3*Id)FP;d0_M`23nA_tyOb zIr#)w8eOwd{)v#JZkk3PQmD~jK4xF3O+@6+;sVVn+0RD3J`Jvw#J40I{{_=s9^u4F zd*8nKrbtofQ)HIP zhq5|s{Kn7ibmomY7Z84t58>>+l~wGN^8RK!J2sW}4({B+B`|xNclHJ(_%*d9@t}|a zi*rc1O^a0*TtQZs2D?@WapqZ_juAj_&1G{EsZ+y z&JgvRb`=>I%i^Vec~h2#&dz}N*Q^R^Ee;gh>Z#_uu(z7yupPwPft6;{LZA3bcs!x8 zLW_0o5Hg4Z9@dazE~~R)O5Yi$69m}+fg>)S&(TOK^9~QGgtzWqnS^&9x%8tx33vNA zR`qKi?v(-W+JlaS)Ka?c{m&o&xF;D6yCpq;HA?k=ZO;C4()>T~N&i9=M$ysK#L^hx zZ2Diucug7`DmZGmf6+lgY5g57>#VAWWaRwWg|7syb)ea?MK(a!BeYXZ{EIWUoE!R- ztGhI>9<=QrYSeNoV@QBe)6ct+wfwK=ezWEyPV7wQIk=&ExQ0i%Jy%aWJNACZ2|J&E zPcgnRdD8*uWkceH*kO~=RI1Xepdy=~nQc%_C-No%xt2Y5Ol26Cn%e_&8$5EzqD0mOcr@Ft7N54!tHKt z!`3b8s|(HwI25Qn`}k%}P+hi`?3rYFPVubN6)@1Adbcf%)YDar+KpsK#3{_nf&PM( z6`3kurRufRJjmKjRaUDRd{?)tHCSLeOw1KrhuB*{{gJpDROr4Gr26B#MOo`)v{&26 z5Z85-HuR}97KQRYe@X z-M%p(!zZy6Nh(CIDuSU-`h~8B1c@(XU*C)ffHJJ1A5F26V@ENNTWxz6!3eVtZ zxbX^Jf+}N9GjLm~Ler;?q&lZJqZTrnYI7|?A2rVDo6HyTgb_eluZ`g{z{1e`FBO*~ zUDDb!z?F7M{5=~IYjry<7OdBxzEUxp8!scl?x5W0;@Cw`NkH0+_JY)p-h~#2)F*Mz z-h~U`fZC4OwY^8yC36pDb3^Q$II|0Q(){oR9r>Bn#822dd=>~wP|rOb0oo@4N+1*V zs%H->fk^R88h~0UK=vGkg-!CDwKM|NP57L!%iX78vs)B2<$vkj4tQQr6aGXdFNqKz zX0I0hD&mE^F`@1f;9{i(bQtjHzMfxC02}67L@wLvCOB%(iub*$2R0*19JHH&hZG?} zTfS3+l?K#5y4wmcrsR9hnf`k0^T_QNo6D~IFkk3Qiwt{dm(x5d-n_0IX&n2`WDW{U zB`WHC%!^l>a^2~cc3Tz>-#(^49X(vopSI;geB_cOUmX=(!8lTf*$eE@NJ867?eMTt zwacXv`7t4!+Rwrq;-OumL4A&eH=OcnxYZ|T#f?KTgg#BKx3y0<316P6WXCvFppNLkc0&)p8mpNdp zP_&!Qv^JFa54q?lP_`4C-YR$Ble& zk83``$*iHGhuo*$mJOu{L)ZgItP_!f9-!xR#*+x_$0ZtpRr7kiAw!D?L$ABD3?0Pg{c`y!D7B;QV7;wQ4FudJm0OrkyXSS-w#o8v)-Hqi@I7OL$K9IscjIZcXa z!*c807@4O%Q|IkJTQD?Y&g=remNaz#>ofje7@a7anwdKOW9t32PW-pgNwqeVyXuO| z->U^1Y(7CqQYOiOK5$wy(m^v&kU{!5BtsoS5P58b`9xO645UIVcAO6Ky3C>Q>_%7P zP0r>(k`b~d3tFg9?8K6xaugni=4Cj`%p%*2BB}PG8ek*QXWP}OW#cYF+tSl%&2i2} zj??Am{psP3_a4YE?4`Ka?B^2JorI$eA@-g4IRlwH4rU*{jGl)oJ&4hh4x!Dc314pp zNR-szvn!C3r0gC9!mq+-(CZJvi0i;_z9%CB(0u|@cQd~4lwpYUGItE$-!)%zL2p#v zD_I3l-~||Z8LsWYp55LPw-EzAQ|2;--oO4mch;7FCE!1533{Lkpf%nj zpy`wJ!Ro>SlJajQ^Lbw=m9`0`N5if8(_hQGp-1ibIaK4QD?rjSgr7#$?~{8mFVv0)tky_>RBYB#qrQ7pt@i0u zyMi?^r8mywpw#8ySBBzDl|RCAyj!IR_p$%cG#-{7VJ>epm{Lz$M3ynB-YaHIWv5`V zOqK4dJcd@JJg=L-(JUB}ei~F6+ltOaU6kXkV@f_B8%)5OntWRyU+0L?-xlpc(r9_F9QnwS*eJYg=~U~O_@P0u)O|o9(|1%;C0~|> zyNqb_RA(%!YGA0D=Spf;r?*CJ6>b=BIW?W~UY>>%U|cX~TUM5`BwMIJIv20Am(-6% z1;n0l=-|rMEsdJ(hhx)U8}=f@doH-GDs_^ES{2fy4|XrznDDC9#%Z+W1q*YOtkVLp z6|{Nk_1>!Q={Ld(N>pj=iH19NH?{6fxPd16d`NGiW~RnK{`jLq!PjqZ!{A-07HIr8 zunar38m3Bk=qi{H7rON2lMdcabP< zS^MSKUY6$U3)xfGacFiRWvCAADT0t%UMwn? zsy_}ioH&m?H{wDX#I0A;aEtT0cjLu3l86Oz&ebWsaL|hYxGzgC&T{03`ia7(ra;Y@ zXqe$dWXX+@vYJws<%O|icp4z-b;@|11bSzov*v4zya#ZM{ST$uyicG>Q)#_}5D73` zs~BZ6u`x#34J{QWk@oH^>6n(Tn9jM0mE!4kywdJW^HN?X6j*K(J54`+KjOvi<|1R` zG_9;Wn;~sxbYp@bLmFtqYY1a%YPo~#Og&1(HyU=3WldBZpvv+ltefI8)+hY=3 zxNiQ|Qr39MSN(ZwC!vbdDMrK=>8c5ngSIhN<&-G+o18N+E*!L7mN!HpJ#0d|lvQDW zfjkCS#QG%d1d(`qkzAApsWP#XGJ8enlGv-UQ6TT! zfp#nP+)sZ7)N|L=thi7uquZ^-^%b8Qx*YN#PCE}L?1}AZ*3)I>{WyQw4~CAUI2T8O z_&F`_XSZ+MKwp>a@fgoL++s5?s*_^6TsEgPvj4-QHJAE!XtTEseUMfIMaw ztfzumtx5YtgRMk6XeRTyO8ZcQh#KkT3z@&*IxNp+<=zLoO#lCx}t*vJ7~;K(*9*&?r?tg0#uE)Vqs8p6+m6zG{8P)Eq!!w$*0zk9Zuaq2H$U5yo` zqkDF_5-U6LW1_0d9~^`+L_+1@JwP$rLb9=4PPV;X|Fk)&&BiO2{qfyH$Idw_Pyr0? z*=TD^JprK1hToS)##0PtV5^=Q-K)my7xGx&JLCxx# z*K)9f{@2)p=vWvAKg14tv>w?o5%^|4(vqa@R;tZ>Sb}g5;NA)+~E;ju7!q5BX%*$ea>Ataynd6NQBL}(V*omX%KSD-Q1fajr zLwM@42weLONdwooZ$iCRzq<;TF4P$t*?8$jRabRhWDuH73@S;(92rvB9ff)lneA`6 zBlH0MB=|RO^n(xweBHLkJ#?lw_dEH_xBCo;!T4f$_;!@GP!xX)P=yITiDI=YShpwM zF4liK`4f6hXH>qC$j>;A`?8xNx&7`+Y`}>hLE4Qy@Bl~RtOU#c^`1Uv_@?%J4Sl&k z+Bo);!&l=oeV_BvL9;WHmRA^wiiRRmQcU1Bmig?0r6x*PLpdp%8vWZQR zXdbc!C0+vf zNFdg(gwdAkywprHD8;E zwhf0jRA;@#je_}+CdajR%p?KuTDohMpW}1lB5dsrYvU{WM-1ON!T#TYXOWR8C;1q=Vyt8&c9^Vhv*=qR&8j~MQ;C3ayvUQN21rx&~q>(87XI^n;cdEoN9KtL~Mr+t;p?R1=6b<|}6 zUCxS@J+R0^fBpa--D6%1bws#nRJyRIT}0j_74r4)<6e92UQ3MczmPDC`e_bL&h5%&kx?F>A_Uri8+UXEW-d) zL`J1CD1R^&Hl`KAOJ1(!gHT8r6FS-`rA< zFRo~I^u%aCU{3%!PJs3WQa+gqGj6{Xx^nIoH;;yAZDW}98#(>;1+&Z`UQIwE_E5t$83vhq&ADGTT-784iyvk)~DEU4l!C3t6umS<%--5+`V}2WH zXx7nG^`g1L&+t%Ej=88q>zcHYW|Z&fG`b@G(XYbJs7_srqv305$acusb%}dOj@Ke6 zkCSb=+XR9hDdT+^x+FNUZ{e4gPnmU9j$u43hlcrx403V8YuAZ9c|=sjrNyPG0~w?* zbI7qgD@|IrQk?L~yhxNjYQh$UY^IwqhB~pRQKUY0=%Lr@fj zyyk9dqP~*P#fPFCj}46>hq}Z&B0t?Wqo3|XFfNE^z0OOeJG~#A{S?}OOCh+m%X-FV z2ybczB0FKyKeJN4k!u{Tz`@ z5|L|#(<-f@PqKYos9XDIo;0>_vm})sA98{P4?Z% zi!&Pb(f$I3>v5+UzxQ05C4oTLVM$Ms`S*9Qzw>+QKvlEaqQ`WH^tB3iJTnnm`sj&% z9wc;zy$N_2V)N)Jka%W2mEo3g@!an#72m4s=ghzP9p=q^(_g;fAqCRBdlFQdZHq2? zgVn|i^kW)~+-P~*>YA5ZuMi^`tTfi{;duI1{!R8{UK>+Q^5b3`%Yrh(c-tzn2K0n} zbgW*PektAv-Y$Oo**U(_$qQig4DuWNwg0C{YVa5K!t+-zRt(AiHah(SVxqL}J+~Zy-h+kMq`gE0U(bQ$!snY=LUR;W z?`}2~nJnAB11%)gN~0xM=fprWr0~|M1zKV(F%tQFjsmF0ac75*CSa5zr1Duj6Mmq^ zpySYuH>}kP?BR&+hNc)0Mnt35lDhg2#0KswHprRWENLHSy@SlhIqIP~lo9BHfU|0H z{i#DUaPTz(J|j4rm^lgpjFPp-W0q^fihWue_#{a)c=xTZD}o%yNbo8309J28(RT3b z0-)jJ@}(9mEFVc4%Z=L)7jkQz`^>S*}Di9j{!aFA|0pBONeQev@ zCK1nJ^86Ipk$!OUnf~HB7Sg1Whmr&$p>FAk(tY3mxeQ336~J))Vr+{48)Nf7ox5UR zzNr68sqgRi`92jHdRsoCeUVX#YuM*8|F9aM38k5!Ze406)8izZh%!p zs-Dfnb^Qj^k7dYFPjWT^cXk^W1O&4kyvta?xS2_SnZU%W*Yha9UorfYIhoP4#b=X7 zu8%oRS9~wiFVk%lV{U%F4{X0+Q&6)8EpYMNmHII09WTggqMa@hoI|Tx*^x%DbW@nh z1^ddPsKBVjixJ#hT~XIP(h)RFOiXpv;(9G$S6U};02v4@&@qPU!w;DHN`kc(vLeHH?`BD5bHsT>Q&;I81ew~kDF}Yt(Ke9c>t%$(3Oyw<6M`H;tYSp z<4s{pRUOZvr6!C*%pLh=w(rtyfA^zxDQ7KD=zX6K`!!(GBr9IUc!5feyYo1@r}kZ` z)vo`-5eW~)oQ(jgWOQD5{D|2csL%aR8Y%eJe@uBMkaDHdjW$^ zTj~H;q~*wE<>2loQ$LXWk5)^suKK9wUrMP3eX_M71-RXk0IPqUg`^sT4%J|^K}h0USt*uUZ4tF8113AR?BV9WgQ<=v&KSkaROP-K3QrR>-3vc4uGz> z;M@56(5IF#_r=>E(UG#0%#5vF|8*(BlIgb-&6AKm>f{=KU#sTiS1(eR-RaMbJFd%@ z_wT%SBZJI$HB7|#B&PZ;-WAHK45{gQh_jW4j|5rqizqTn4Wc)V)@z@u(H`OckB>r5@>?51wU}q%qJ+2lB^(i>I#~x2oqbZ|?w^Tr2+wFl z)fhALs}d|Q$RFS6x}b=*8sM3-eIaj&qf!JxJItk&r-zs;5j8&waq&fQp1No2&BW+S``iuj3v+D_!%W)lV|#)I@8_L zD^;EVTj~Q$Zok$7%`cGrZ;bB^LR1(}T7fbuDN+imKZRHw`OwpBcZ-{&uq8sGvEuVa7Mx(n(@|%(jv)u)E#2P~QwN4a9zZSv8tRxy1{aNOv z?j=i^XkGT|7o)YLHc)^MjN(WGeVhU20VtI77?YUoCwC=*2Tq8eApclxn#s3?>U@Q0 zNdMOm&A(_m{EraLzgG$Tr|B^AznBhN5iuS>m|#DMdC5u8Ww}(EEi08cW;s2M z>AU6>SxT>uADVVxgmLHDg?8pmPX{kzv1;lax_C2aBcSS^EOmza-*&Ja1GgZ7v9az( z-7vD6ay$R{3?@MVqW`Dq@c+kp_rH$*Ntyqhn@rwuLKQ1kLqxq4(5zKjV|l1ajR z@(q#$L1qgxMCEM*B}0T&6q92o(K@S_xv-@K66}8F9R?z(D=8=aDh~HgkidUdc_x{? z?0V3Q@oC#=PtQreRG4voI_LLz+(r5Zp&^@eBZN=pZLv=>iN$FqJmP@w-9H6oCy)KS zNSf{OBiBK|yx`Z27PnfjrFWlP;V%Y<5S)1{Y)wSWh~=)w=cHZ}7RXwz+YslKWFR;W zj{iqM**dJ&`X*YD*pacK=?%1Bzm~3j(572VI;t&(Pe*Q^Vetg*y>?I> zdTUrg9rcTZvB2_s%k(VuQ#pzousrBW<0lh^rs3WtJ^4L0%-vMA=X;K_^t$BbkEl~Y zMSI_TEyIaXE24MF+fWVwv$j-N!!=aj#8IT63)t5RY^Rl`=h1MKY z#v4(SM&^?Cyg6JOE$G2A^DE^&vI66sDG};|gFni2RzsD3M51pG^MEvb8~~%%t(;L5 zC8N{clY?uS0Qmt<=vHMg=NDT&!BU*g^~W2rBJ20-NGK_^xPz_!cj)wnYyD#0#)d=v zWU`8TPimY=#Yu@vuBg%++RCU8+61^iQo(8--Lzh*uTP)t(EiqHMwIo6s?V7v2iS3} zwm&pua7)}~358_vRI57)JG{d0%EdnPCMY4nUHi+@z^8pM26 z&tpfANOFTjB2)a4etvDCr|1aV^$L-M{=*g1C#U>gbU@2}4D_+t2 zMt?8FD+cYI_xcU|&}c7%DPj@yp%TJ^c^F~5*O^t3V8JT-2?14BBW{M9S2N{iQw&A*$wv}p!zGM(5N0JfX;_}{cgJD-KA=}4mOR*ZW;f^$#zh9g$E6GA87N-OEbsqZ z^2yQZ_l17}?|c6Zc>kY#^uG`p{GT?@|7cIiR-gJuJ?&?7*Po`A4OS~)T#+D5(0*)l zOk$j{vT$T(iCs3RBvZhK2@5ICatFXoPf7kA=Nh7y3?eSiK(b7ilhEO$P4d@Zu=Fp{ z;KA=i+f`dl#@<@BhaPt~M_oHtT^tQ>TRm>w;EMg3Sh)Rn+#yV*dr>i@`m>CF->A_| zoYV(oxY2LwV{oTWIb$^reiLWH)N9TER2pFZff-c+gse4k+QHx#p*C@^V{4*By;YO9mxPxgkfc@#po+$pygK84oZ(Hp1La|yaZ{9BgUdD*ebFdo2; zv7y{Oou|4f*Y~r`jLWELZ544_OzDni-*R52o5n)TA*?k-W>E)Dgb^b%X;b1+Ime=P#l+eB&ky7=-EL`0S)HE@ zxJqd*b{YMpQ3^`aJK@>X5eB}$grzzaw(nh9PSf`b$WYQQmbmGRO?Dy0VWSE}+oIuY z>uFom*>ue~=P3@rYx2wt!Pr9L<+rKrj8nbpYgntWH3ure^#}f7FT?2$IsCBCv)d(= z$Ks^(Pd5HR(vHV@%<7UVF$| zz0$TtT3Vb&&oiW+GV};|_sU;pkQy|e{c#I9(>U0GE)bHRZq+S78?v|ktmHoAC1>}B zx56_2F#Rnb6Vkdn26%sl8PfTJFfky;4D(`fPcUT6ieI=*i+um%zF&?MdWfNqzf=hX zxL6_y@r;kMhz&3pQR2m4_XbfAM^9Q_*O2U1Q?wI)sT%3;>PC-2>Q4z)IO!@$;MI5s zKO0d@^cw0=)R5m6j{r1XgJHU`g>*>Lw8W)r3@6(&G1rjV3kkUVfZz`(@rEXA!+6Oi zoay!1fBnJyj3n|LzWOO^KV~3I+d$`MOI!bhnnTVik~YlZo>FC^GzgU;GoQosr578m z#{_h54R_)~+|AidiYQxVp~IQh!n{I(z`je*5-47A1l;rZzXTe-hkNjfg82cU{M_a= zV=QPTSoNbUWF=T*#8^+HtrybBsTLAa4DEJz^%c(ko=WR+OXF>YTzojaJt4S6NTiyI z$zU7%*c34ZGh0Rl=W@~ER5Z@%@N6xWBI~xbsf|EQ23^oDafB5JKWuv@*p@3}lB-}9 zbcgYh|NZARkL6E?!0^|jLjAuTjQ-~}kL&+_&HK+z4p~b(Yg3c|tmT-}^72+)%Kpsp zqDVJk4#Gqx43bcU9GeUxMCcRjC)q;^`yL*^OA9{+Djtd@OP;s9jM4O`&~>Z2dLJkF zWW45zusFhw=5bHwt?^>r>cVcPdZ|gr`thyfX>!bjISl5*SYYh+X5F+I)GG zFz|sEtmYmG)p92xu)a2C@ZArL&K;ldle{az5V-66Bmb#;w0&Fm)Xds*y^qJ>dn!V- zeZ41eV=(`whVPplx+D42GXFju3V80K{S0LFqwUSThOpeG>&?B%VZE9d^nqX4H8%+IEa=5b?~!%d}thEjtaUn&iHgQKr@HsH;s>>86`)@Z|! zXeOIOO##{YN6pwrvtn3^MPJ;Ps0#|Tg1RW3a%yZoYhNXC(ZrIvIDKD5twKBF7pqV$ zw1-->u${4jhFgJ5-wtl9L_4byAy4J;v(K@M2N99vEG+j z;QjoF9IQzfplM7zO?GpT@w18|!D(zOe+1v_Gr=6yk=;dtVUK@__MX>B?a&s^&E5qrSzV^*X7rl|C$_)nmk$DFtMMV>3vs$)Z2iX0qiBm+kK#AVY7Ms~@O-duzB`rt57<=Xh+FHsgQI>N! z>fM%x#NPH}br3^I6=Z#H_FO@uTTom7aZH=?o;nk{dF2+}V2O!Kk`48BE7NGEEbaLj zv;i$h)pndMKz=owAl{|9f_mbot1z`}8wHB(SdE3ZOo?S{Au3LMx zbLSRcrdWY+zDHQrVb&cQ^r>)s&4FN)Z{67-$T`&IbU`9Y)Kgm~Np^Tm*h%Svlq44q z=~SGHEm6orFvV#5;2K~*+|v-CY=LjiD+T-|*m50xswUC)G6JC*O6e~ZTW}L4gTet} zwIbe+Q57@mNqpnVwQ8oRmgZ)3^Sg{9C;YR>B8xlBH7GHDSoJSnR~rq|rA28+38%em z+w*MsQp^#j8oNow+LwThW_4|7_b?;A9~AGg0LoU2#w%gNE8#v}(mj(VQ50b%`lHnp zmWKS?)oV$WVls$F**t27w~&kf8IlIueD*C(OkYhV!!|sp#x;b6X}sQMKARe~^*2?& z_qIHf>vJ8Nl0g5eY;bm1SA1N?kpzz>wP)w{c+s?z*8`d9{TP&am3o_+Hmw z74WLDDR92A>)DHT(x7l?6nQFR zrM|qu1HQb1^H$y3yCW?QX))@Fz;3}xuG+#9vaqodmKC)TY(fMEy7_%)Wp8r$g$GSBc#I`N{AObz(C z-vgmeSXOeRsbLUBbZs}EIw5+%Z5UTdTF&WPE;=nV({>IRB#OQECUd7{ZE}uIA1~7B zG`tFIZa(KwDu?lgIhKavwXkX_DpnwMKg`nXe#)vAe~UPMLZrl|N0zVddgcZ##Btrd zE)bm{d9C8Qa0>}nreFw;8Z=vo9y5nY6m2wRu=ygKQ)EI5!~WQz5WFo_uzG39Mu@k* zVXe)##k}89Vbs?J3h#$s2=!TvidD>NCu(NpkJD;LTDCuQA=W-WiowKCCTPhf!^#OG zj6|SAnIvkzS&-qyPk-r{+t|BWN1ddj&DtcrDsU%FC8lm@{aC}7EQYN^^L61pR`3M3funw_T!$dd#;qu6aIswwFOMRarUDUlk3zCHjYPv( zJu(;@h{q~Ye^<=u14CJV6$tJ!9o+Yo2KZ2F{#moPc*}YrM>VPwu`cS+Ur5*vJ|Sky zU#~9j7OCL!)>oCUSk}9S5cavQy%1}BS4ZUxd@?#Bg4J<@3_dV(e?g%<8;}|rvQhp( zvN16wkbYJ4{6>NR@yd9H?ykmg3v%d#xm98H$W^azrOM5n(~i;pM@evgs1@|^ znN@zs95)T^5(#`B_DeJNEy6M^)iE08v;liQ7E0>G78XtrIXqmd)F(r} zNA6BmL>)5u1>)RbD(!=ZwB2iB@W#2H?Q@WRg#!&gJ+;tT)N8^<%sGIemcy~Q15pg0 z0z4y$MX!rYW%_{4&TIuOHvc2ue6q4&9^#Wx7dnEfTF*B>Hp2lDJf+UTM^pTJXz3g3 zVciT{ufN zOhgweyVt z;fF#k>gXtkP&N$dumUODO`iwJG_Db~(1Wgjcs_w^4S&6%M!K-^-95H-<9Xo1%&33t z)`lsSt+UO|^}1pax`^W!gQ^iLqL zW&tQP{4KLk{noQ!Eqy|dbItom+~v< zl&i$L>W3-Ji@86sE)Pd?zU`@D1sO^-x^3CLu{y7F?2J(-89B$aASAYgDpo_)KBiSx zFpX1i$2X6k8jXvx-tfVU_qe-@hP@KGF9j3_nn10aEQmW7kJ2oVn(V7qlrtEezH20+ zSM_7x!7ibQtT1sY>*dG~j9;h$kEI9d_}d|-#BJ*^OUX3SZLbBQJAfBlwey~JyE?$( z9c!A)yjXK>xXr%7-i!h$0`c=AngDal!AV()QH*v>28-+wFz2&@7PQ440Xg4$J5o~Z z7+D5g3PBewJ>ri{D;&7fP%I%MuuctK9f~Dp_CZAK9X2fZ5EX*D74{&;#I_jX5odBov18#oP~N22`|-4 z+_)I9053Bp_j$~C)xzAKlHTEY4n4E{+i{ObOAxJ*Ww$8DhKaN@arTu58zbhc(|!)O zZxfm$wZEc1mE(le7R)RHxTNS?qY6^4>VTBTR_589%kS#aVUo2i`t(oKLCS8XPf7Ii zu&1XR!xP(t#33Jcv>0kEv2?`OP7>55jV@!wDl=8~hZ#03Q>_qs%YL8_!^&~n)Ur0r zu6m2z-O(o%55rjZ9;)LJ6l-JC1n`yX;kBUz-x=zop46Irrx+Y^;C@%I>Il*Yp{IYXSRtUcN2tQUc6qVBxc^~BS^92`1KA+TQ?J?uy@%}n<> ztb5zlC{UCnu2#6XYLI5t6?0BPj=mgNevy~qs(p^lzqY&*4Gt|}iLE42MyB|%W1Yl` z@kj4YB=7x}_x^#cn1G_BQ6dF8c~3jI%bwnapikZiurZ5z2S)F}@g|1$W%9%=%RLYZ z^rrpJAhUJs9mPl){_W}kP5-mvGN^S+%(=bCRO~upq&?@gU$W2*Bx%T(a+oqV=;n-@ zU9%N7(#XZyU2%09c{`vVs*={!uibR1gFTv$f_+k2`WJAbPBP1vIo@>4q}lYGi} z8I?mj)aToEpiD_%Y}x|)*{)|`mv?-ZcSOI_R_Lk=T9(cU-z{K@+IL^3lgdSHk6@`2 ze0A-+!UQ(jUZ=6Ga36I~so8w3W4zmz0z;o zC~ocZ+u1UzFW+6$B#LQcU|b+ZuY&1fl5n}cWo!}DzP7Y(-3jgJbegrNSNh7K{GqkZ z9tGa^otHxNrGjq!4dRj^v4L)%(hc?r_wDIOQpFuYd;t_L>j@`OP2{EMm_YIcDZGkU zCyf&=?o$K99B$epE`Z|-0|69W01P`oepV|52P;~7C< ztv@6kffee3M$ZBUt_EVTl48Up`sP3=m9{|x^O662TBX2wwvV&ZEL7=tJcIg@Cg#;4 zC#sr7W_e@QU3v%}>us6=Q?O|1oEls%{npoGT~hWLc7!T9QylRkl&YWTGk0TLG7+EY z1%P+-)8#MvQ0v%KfPD_+o^!K>Jx%7bu%}&(0VP4HdPlgKu7`f^x`3{;JVZBO8!Liy zyO0+-qz|Id4~|eT`YXptaXb?|Y$E~996>727zBI2NMNoC$GOcIt)dUhL$%thsPAt~ zIZ=onzK4y7Zvg@ulDC`!ojd-M+#gN?opeyo6Yy_FA@6iKooR=aIM3uEo~Tn=lDC=M zUv5z}yTZ&t-wdAdEg5afAX{kf$K*v|u(}~Me9B;(_XaQMfk*2v7Z+&FHKPz-pa2#d z-jFY0MKx9uqepXK5{#NXqaboUIak4m@LF3%NIjJ`AD>JJRX_AakeSfGmHvKnpxk+= z>+Wo@SyH(h1JZlAydF-f-9x1yhI-|i!RQp|V#eKgr-MAJ%o^)JlRH&&#$Ad)yDv{3 zJivQ#+=-C;HW#r4qPJ+Q|Mtx33tJuS+C?hqAEC~r)&J0Z4?dpqNhO^&cY=dlA0evj zXV+v#mU+Tzc+>pFAkHN*?KltnRNxS04 zA1qz(mfM=l6^-x83lZffVnfnT_VRcD20}bR zCyEi@0vaFQZwoZKN^5Jy`DI|D8UOocx-DXwxCV(*%OwS!WzTXUirH4G7;&MS(2Z65epTu3UqEY*Z(xs<`&5~{Y@}-KoFd|fWTKUB7LzCC+4Ml@D|43gV3>2?NMuv-5lv5hBjIS*p;!UcaX8dSca|Je%bqkHXAhWO+pI7-J^^^ zFMO09&!8-+8LA>`9BHghA2iP(T1>(EH|G5mtSn##<%|bI4{7|v4yq-yA<_FoPR6hwLi$qNkHJ3G}Sw{^cnUWc=dYeaYf=|e+?5hv!tYq`vrL@ zBOm9QYBfM|RdJ!$*X1M#7?3(TP@28eazB^8tyCB&DSb4Qn$4YGjQvj6NrRwZS7H5Q zda<f~XHDL?emU>Ap&dwql?F zYcD*VLbq*2B0VD{l-qlYvvqnJ`>aAYBd4DqlU$&4mC|c*68bfYccdKHHa#B>JATGxF=O}KN=Ab&)7dFpw*|8kP33(X=6;pHbEBo5UhN? za^Skd#qkLZHN$m1+plHn^C687&TnaGO>?3wOH=`&^K-qBLO*TOh|Iv#{M$L184U}A z%Bor1j=^GS$+^t)v0NP4BTn=9rKWuJU31pNRH{W=(-jL3VNRUWb}>z?Y!DQmlcRI{ z^UL>|gP){njdJU?o_%R~9cu=W&{ba!GR^8DMHEyB1o%&eUU%Ng-(30dPpARNVJj%Z z$x;PYWP}7HNOv$SDdo-1>gXZi>EmP+rf=^0Al>$U#OR6N(qn4Q+>npel#<*qj@i*` zew#bGRt0G?jPnRIAJ!j}AI$vr5qyt8uyBHEKOYXSSKN`o#o+|Wu~D=8x=CHoLwG^d#t#Wg z;<;Nd{yroX365tZ>>foEHmD57QB#u}IXvPh;6nWU@xp zpDv%J-I8feT;}ZLisuvqvO1mCr$c@o&OAXWm*UP8Ug>>JK|+ZAxxmdD90Igqxm3{D4#YLr0d_JMo(cq?( zy0My0YfVz0gmohJw3EaM?DJdqNQEj#bq*AX5;ho-@hS6K1>%{wU&s?`5Y;~{_MFE% ztLqYWm_9D+m1<^{;C8^)(dK&wUnbZdr@ZeLyV!dpI6gcM^@k0;)>er zXciX%rd-zWSH|A1%GR$Hb8E zq-9$BJ%RO!8S<5M?UnuIy_-7T3uVu^me`U0UR$~K_e|VH-!WE2RhY>+St?u9vq!D6 zJufC5+jwH|3-$6dv*}ePo)${$l{*QOLG+YYTkWOcwT(R#uD6A$mSr`^A&YN zR3m=L`!^QVw}sW~{W|XYM5Dc#0t+b+6U_>p?SR>8_F%bls|AkdHaq{c?M&)7xOOFo zd9c~w>gt4XU5b3qeD&P2^W^pl@N}BFpuBBO@_d-O@O<_lep{F7beg-(Um;fF{-z*SMzWck2>D-E_5cG z@wVzoJ4QTw4raxPmW!|cbBZ@a@Hcc~qIm>aP{1)wVhO&WS#Edj%H}z2;A(CqPc~|W zayEF;q@VmD3$kl6Bqv|Mk9@u;ne4&hNklEN?8QCuS?Q9=8TmsrGW%;N1vuTggvIo$(f!`ITW`=cCwr)DD~R#;Q^>D0+5vmv8c zGn@F9-HC6kcCT?9P z-)xLDJ0o1^T)$}w1n0lusXJdrt2eWP#csPa0v@qR$Q`(io=dcK97t@0N5X{b}(2ftta}f=@(H9dB@Q zxdZ(7e+i82wXSo`xtcDV=?>D>AWU#L0;l{_G9I*)<24K6N$)m{s zlNW>ge@`I)vK;#-5%gb6&2)tgIYgyTwteO*_<3&#SxO|am{CtMK*9%K;S z7riC*;bX%jOD5Rc?E1NPsPyV|6Kt2O?s53jI{Irxqvy)od@tU!&*C(1J}Fvaob}D zerO)1A@O)vRndmt*HEH%CNy*oLiHhTbvu29j4Nalz@5=uNX8|1)eNb@8)0I!Tkw@o zu%V9ANxUCDMb4aTQnrC|O;mj1z(BLRxo)R|_zq@mXe4iI*ETYp*g|FcQlg=9lzlp( z0oUj*;s^IYm2V4-(mHecS5Rq-<|B;+q-ItRrOrxX$~DcOCYN%BFnuK{R0_}Y)dFs!0(ot2-< zeCJlirsd>z;~wXSzH-(utQK@%g2?gH4Vhuy08`eGg$e+4x@h!sZ4G|n76yGCQ!1_I^Pe*eISrIta(@N%0pY4{r%WR4jzDK1DEu6Zz_9~2u$QBD`Vw~oODyAA&3ujt(ozrc zZ?m46aXBb3i8ul@cJl*U?g<)w02(Q_=w+>cWCO{roQ1%>?Av~G4 zZ>cWhq>9rUa>K`iXt72n4j8!4vVD*ABv%68vz>KOw`tK4I`LlJF?3`EB-2pp1&cZ- zhvCPcXnVZ@{OthYpeBDrT}bT74j~(~4InU4a*l1@g3e*N=mt_bthZxqe8df20?8ah zf~&6e$Cu6BC1|~nEY4oU)wdul?GdUtCb8n_P@gxO zId#dNs+6%cq?xiv5=US!(2pJ&Dgjz-kzbWdC@U;_Q;QOc`sSCs%sT^Bq;sy;e5=ZZ zUxQq&>Z`2Nq3El;0S-U22gW$)G<6N!YfhLf{NQdICNGep&y>50EF~GSbuOU7FeS7y zgAl0sLtp261!g1^###^V2r~^%M^~^lE$+2Iy^;^D26~Q-1PI`hHj)wKw7jqqxk+J5 zUCuUx;%<{y`jbY2hws6coLwjZYh$NjvQh`tikkkp;ku~bFY(Rjy;VjStux2AW8nK0 zQ2I8;ZLrmML^vB&j-Kepim$%|WKXD`Y#}+{*^zQs=$)hN*^l79KcoK9t9vNZ5bytl zR5bskMmJ)BZ}z(mTu3 zGmLkH5g1sEWRHMU$m=I1sI=}tm&Vv}70e;YannN73s`LO!WGXTKUNgr`Jp+X6Js)Vg`VEIw1&J|Bb2$a%_6mKm>^GVrmclN=BzUV(HHaU2Pud4(0lQ5<_=Z50My zQL{4Mgf|KVW~U(box-h66LpvLb_idN0>P`j=j3D?M?cuW&I&?NNQmv1+0<+y zTfD?nwNp;>jH5u6@-tw0snzr8omuiUXP|@wWp40XYJz2_tQ&#}>%3CGRF4f?K7oYai+G8yb zcvdyv%E4%t8}}a6Ch*|^ z-ZPz-h7F?5+QOgi84quV(w{33!9;b79>HvIvJqczAL0$0t&5+`=Pj`NT|53Q0#cbW z+VP9u_5dv}p%CdatO@!NnuMeApsIgl%&HWcFyPTM@?I2m8NC3HHR43ZiLu3slkJUk zy!#dW4`Y8kVU&*kL_%`^Mc?G_#{T~S-^%iDeCvu>FAqGYnVOv5rDrEOUb*j;OwnT& z9)tom(nh0=n$q-Ijp!@zmD8OzvQP8C%Gi|8`UCx<*ffqq^E@DELE{4*}_ zu&ab{K-VS~DdCvsP_77kjpjnZ-VH2Vg+KP8qgrXOJ0KJ%(XpMliETf9?hKt@%e*Nx zb-500p6t%dv-d5!G|_9hiO9438Bv!+bWT)PZGoEiL4ueFK4=={Xs?-xa>~!ICdh?? zMftYM-ym?r%gg|9EG1O_p3U`PE(Hj*Et}BAR|wN7yRNT_3HLTjfA&1x*mVdjcJfIgZ?Z_Z^2@jJkod#^h3ZYCBy)(RdA&l2CY5YZ_MHW6sMQ~-_VLeKI$SFd>+}h5E&L0> z_3yXzAAlre4eSi;?R9j`4gQ+x8AOUhex-#MC_O;MV%{DgKOER31X1$!eUUKU=QqSl z2@kT{`oa;P3{jzO?%k0r$E-}ho9)Q+~PaOFBZ&zM@8 z3V~4>>DTjTYz|8P?GE+w%=s9J%lGYA1J)5bXDdY?yghU|(?!{dg(Xm;J;!E}9gNpW z?yeV?!Y;`;pi-uFNF_x}Ul`yYU?bj1~0 zL}7SN`q=vE8lizjSX^~zh-g9|cVO^e;$5^^IC@>A#5_MfRaaF`RL?@!637c4zjJwS z_rpnp4uC4Sy3syq3XKvTqdkE=x@tLrC^IYuzl z^ucF3BoXqrn6q9R<|@XlU*zb<6?C4a_Gltxc?H`|JKM|^jj+Mp-fBI<}*l$HWE6g?K`fh z+)@h6U?sksM=NL+epFLtZsTozg8gg zr2@Sv@B~b32=EBQ3>}Z0GAIcH1!k$U*d>}U0AUMuO#*0&&`F)Dcu3spx;NCUc=RD2 z({9-7u{IP|>ytj6j>2>Bq7pOpbI?hhexTROwHH%zvTkzZ2(S@;N1TK&AJQ&njRMw! z9c)BQ!3o2#^z`0a!m8kVn^8%ZRjcJoqX9-_jk}qKA+|)TFKLrfCwaYM2spNJ9YmK(z5heR<-<+FL({C2{Sq(13o>p4MFG65X9Ff!zxo8${vX*Pa)^TBY(Rj4HipQ zD|xzn-d54(0)y_zF3W<|;5SpMwG_2Ytokqmoj3K0nUDHRTg3epkp=kuPhAXuXD3DL z&nXBg#J`;Slgsz>itmes@TZsm=L7%q>VLuPTj*F*|5sG_drai`hd=Od7GQljD_eU5 z{r@D2Y>z*Y`b_W!KMI|e1Ngr4nj=@n%aY*WL2l<8`^vX@6Abh@FH_mutdy@%23m1> zXNJRV;v4Gj$rmc)!aI+gVY;<@%f5i#F@RR`Sw&n_^DOfgk z?2a<2wxb21rus&YKUPMQ6wsSSqttg@LbLGNG(M>!BN=g0TB0%)KJ6Fa0_GT&&1n%& zhC;1Us$N;LKE+&#!rc+srVp_@m!@MYZs7cV!u(P);}cqup~@s7{(ED8FC|>3qR=_z z0MeAq2q_FCM`mFzEkEQ*L+-a3D;{Q--H=R3cO27oyeLawOc zBla3Pc0tzLVmh|~-F~H54_9Vl*sm(z2!MUFpLQ|fbRcf!rQ6+FXg-6_!yHLl9-u*c zcEp{zLkzuCC{ZD0N3;TCx~LQT-D!v}NQ!AQGHQl)J*g$_az+`1xvSbkS#d;1)?_aK zJIz%N@%P+;^tcSKcJg!UsI)aEa8DlctsmEzWspBoT8{~+k+ouX7L5%wsfe~RFA^>2 zpueb&L^sO-U;s8g)P1ym0QNnp9b-M$5AoIuxnNNICpX)apq~HxoBE*;#+$2kvZJes zk&pW-Lm-zQrvx-{yNL$|(8mr0ct|tLF zyF*N?7sq2b5nY^*Hd?lbjND>RdAneFU*l?vc0*I7t>cI_Qp#y~b8p4kf)2>r+-f}u zjzT3%rc#uZ2dOUQ04k@^Zwyn z4}TuSvfPL4-#&d7?>~GN2?zoL0_g89_w%2*oPwo=mA;9g$sftcpS`C~kw=36@!@~a zwaRLk&GH~|)~*qmwA4G+x7?L_QoKpibUan%OPdC4n_`=yx~J(6I?n48Nf7nFqkww( z{R9Q|cn}u7$jc^c#R+y9T6H^bHyY<0i^|mM_!2w`LmNSe&CJJOJu_&5?F49pDb8EF zwMo)(6;`q9nOs&7OFoN74IlxqnZ14I-j^{kKyTl5X*4}4hXbUpxRL<&Ut~j+3{aqM zQU^(K&pM=>**1k*+Q5F@iy&A02ca)3WB~U*vV+wH`495f`q#LLr+ZPmzl-b)1 z+!&i%YAv1v7IOvrSWmVEwxD@&PrVBXO;n4M#GBc|@3+6NEvR7!0SfFnY~3VD0$y4e zLY%4AV#VX+xg6yvogvT^y=XCua>nc|$^hq|r(EOl_=~_UmG#+!`>N66o7Fmv`CGtA zIt#1gxPY3C4$M!AC&dUZ#1Nu@oP+ZdQd9}e}qLCe5W%OTtI$r z>-FP_=DX7R%H}O20X#Sa+G3a<=j|@h;3y8pc)RbOX+>jy@}!i{_#XHR)=B9%@g8Fh zA&iCyp|7WwrJw z^aIoANKxI?q>t2BOd~TEKdx)np$IDSEp(||rT+N9U&)F0jSNUMx!VnaDyvi0sCH!M zCdq>y$Z&uk?}atANUFtiT^$a(UbO3wfw5SN7bGdPoLYGin(^rwbr=D~bY7v2E+d&xB9Nf91%=q%Y)kLom(h4%ql)1UU{-3sr*Fg8`(b zEm1yAwg<5M^+kdlR0VxTcEoXVz;R0OC4-Z4*P1McK)({+Pli3+qG~`SXey0PcO%;z z@BRoVDH=Q!A-j$b&%2Oiai zbYyrhn3;z;Ng&{wIna`TGz^R=`wi@m!o7QA$vEq?!b|x};r{nJhx4DghMc{Qy@?*5 zgPxgz{U04GDJy-0e+AQYdCAY76%wbFA=^yi7QeB~7i8q@x*;IEU~lvgqCQ_CXeg&j z2R`ruIrBo0hIgp9FEu*ZGPEr;$6$KuO;g4>aZcRp?FZ{_`yCx0 zZ`a5`z)3m5x+I}s(1IcuD1*T?6UHnnK*)MM0Munxm;*)$(`4Ofr7@Vm`CB@zoxtDe zggdT=OJgl@(AkWZNs?gwv}>;z+pypX+QXQz&0PgW-=d`%CrKmO+BvyGUZT zckeQ9Q%V(E7f?!_iCa^()x;Y23OyCT*PP5)sp`9{EP0!i%qI+OgB4*sJw*|T&r;&U zrKbkO$i_BVyaQ-)u+Nt36%4#$Qwq$^PZSL7@baFrmG2le<~*fgcxOcJ9s20ihS|k_K_QHAd#mBvzXglFfz4NmR^UbDIwLiz|50Fmbym?5?Ocy!n~hO z$#T`YmK%yPjoknxasnkHuOG(#8fOAZHq1<-x_TEn!alhxDG<q35qew?ONLrln<(zTlj9K19(RlEvbej89 zgWl&yRHPh3ICt0Y5ulbLwj>G8+~rmz<`DLKKhrmX__t-hN~NniNYCK={3wPHcUl5b z$k%TzF=T4JzKsQIa7AAOqkDkXGVdwA`K_B|&0%O3%%yjIi3*fSlgAf{hVlQ`=!`cU z=k)Q@#a#cNI;w2{|6J_fJ>hV6$gjMgy_C1|3NWxAU0sX3S0IqSK7iA2%Q}luwe+Ls zB+iV$aGTkEiuClYCM}^k>pL#3z|sK0V7xwmma7BRUlx`yIj$~N1f=PM6YV%j9)+`p7%Z%kgxOFsWE(C3-_U+3}PgU&w~ zCjL=}{XOU?>XpQb)qTYCaQ`!q9h*(zUCy5@(+XF~ zKTkV$ryb6JrYG@nZO1Y3XMYSN;qxkNx12p!wDneLN%AXV(CD*w(|1=*+j(3$v;7FY z{D$o+PkQ$?$PM^M3)#<56-JJ7_RV#9X>A7&Eq|;i;TW+M(t@I~W@DqJArEmg{gQer z{_!gixSjBVu~u1sbufA5(s@_vM{>)b`6o+jdFxEt^xisYVj&E6jk<4j3z7z^&~8T} zfH6-R7_6&F1;|P&2lLW)Rg&#Ix)T(MG@8k}sz5uGalP~{OVz1XD48%}+xlsg-tyU? z;VKtvfrr2t=w^I&D3Y}|23gwES8iy7XG|z*rQEzad@Ei~R%0=R5haq9dIcje2HGt8n!zgx1bp$H8P?Mgzz5Q8d%=L8E z6MuTC=wA-Pzt;Lo%7`EZVbQ7LqC8_Oy0GU*wu zDoG5REPm7vX>J#+oj2?U8MQAHonEisaDa&eK?-sXd+d?ulOwk2&PUJERy_&p!LQ9V z`+EU7$+Fe(-MY|{%CSjW!j~fbwjkuRb=sst1yOpt%_ZBS&=$#|o5k^FwklDZDRqxT zzA(*RKe`*qG>bOLY{~3Fw-B8C_s9Sljp^mk)HdxnbS)Yb%Ze#^CXj24d78WVV*(YY zZ0b%2Femv#+`IWQptx~K8ptl7GAY$xB`K}Dl5XP$J!>h1UBcJYSCVJw2lL0OuPn0oByJytWW2m`7%q@*Muo9;lHWEu#Y2 zIT<%RJGgK!F+6zBi=U5^SfGTtg!?YJ_+8LV*txApHzJY*N*B%M%wU1Gj1sh5!1&k2 zW%zJ;xx`&OUti)`Xl@u9e`3WOApOfxPB!)qI#sq(z+_cOd?00W-kxli0*r?(ZM1Ck zwXeK-@0h;DsFA3ojyXD8QpnHFX+cpkNCe>qsC!#MYKdPtBylCQDpiOzWyA7(L-L4$ z3D!_}I?hpiM6s(4fz#aR=;f`ZxN&@U&H6Cz);;t5Xq2Wo8%y_VZ(_ z4o}?f@CVJc0 zpJ{;tJUxJjxrMHEpMk_$tl%it8p8rL{O>18<}QECZVY>Gp_iW-6EOO~p9sa@WhH3z zfX;{UUW^0xIIIG3NFrpv4@g44Yz+(x;Vz}F6FzFtgx=B5PF6xNzM=?x6UT7u=btON z=PL14`!eqzHHTa6`27h;T?Be%QtSMj#LXc2ez5&Tp=aNqho{5z-- z>{K1f0<87Eg{tOhHmiogR)PiUZ!6!!bZODwSt%O)?5&ZSO#WYl2z7dswHr;9e}j~D zKr6qAlio>*Cq%8526^heWPqYgknN0io-3PN+GiXig@RqFOS3j+5m7~|jy!9FsZYS@@ zl?TJoyd$phi`+X=)vJ^7gYX*Uv8qAFSwmn`Cty>0 z-rRYRtHEs&DSASnd!z_+n1iL~5E$`HM{K*5LChG|*MM&RIvLfot4I%bguFYG*IMnD z=2gwCGcKx*5T}mfuvXqD&Oyoh9HR4J?4+sIVa70mVHT4l(n50mIYC>Jyth9GO1)?& z(`TOp@sH28>;L`K7x-rp_V1_uXWjj`@G38EHNyk{K5t{O-GsCp|9~IQg9v^MCb%ap zj|(Y+`~{Y`-D-@?<_h1Ispw6~+8Yw~7044wcK}8q*tPqSrZWA_u_Hy}a6e0tvo${L3a8kg{fK?el_*gf3ZTiP>MGt4d4k zOHm{>tCGNIXQLGQUg!+X&ORgL4t0eJL=LInn%qQlYSu&|2SZUZQAqN+fJHEW3t*Z0 znC32VMq}q=59@Dso?*lHG(-dffo$`|ht1B9V;Eps))+&XBLjc8c0D41njMW+Q%N6P z)GnYRvsO{Jv4J%}m8>)8u&?$}!06~2|F}ymkOSHj%&A2S?q}_k%fqsdaT#Kb@9L4) zdZ)h%fyMv0{fuIaUVGuluE4pZ$u_y-JMS3Chi$pG8$XQL1OXb30O*HM=Drq`(csFM-d!C_v z=>>tbU`BNP5Awv*&gvs^$GJKkV{KYidgjuQ)fTMN9n&u9t?`qXLzoY(45nSNP)Th= z7>ZDtjvTHRE`c%>-eLZzY?%ge1K&Oq%&Sk6`!93*JLEy|ADWwqrIERTz15$K7;^u9 z^WRg=e0j5Wz%dO0qM#ID9#TRPaI<$|;DYvxxB z&q)E?7=cc5ui?>^3Jkkwz;;l>#huH>gUiIxgO*mu*Gbw+UVhvFBqBzMt;A3h7)VI6 zTb|BxTpu*#TC($^WW6Eho`lshh=sU@dQJC%t_=E5xt_!WyU|MPT3lCHxI)i1wb!S3 z+%0P*Wv*U{VMjAIr>1I3``(HLQlE|jQfMtO+jMqU6;(#L$A&v!cBuF^63QcP!{pI) zHg+u?>BKY2?n$NCMCYX;>XfuSk!9H2%c76z<5k*2)s%iGxm@lBJnMrwzGL*H^`XfR>-+XMA&Sg6Fsg~9= zobT{Tzv1@AedMJta-@0`A3sqszt-R&1o5@j-Pt-f?OERN92QcDEM(O;SK-NMA$k(P z))#%aDJ&tPw53#P`&;IL1=0s^;Y}YBK2fYK0-kB$DSUT9IQ;;46EvcwyJ1sG1etzQdgSoH&yOl-aI9g4@As@}H0x)T0Wh!I#xHBaIfmVe3j|@9x zKqri$1AZ`?D_s9s@g%q^NdATx5q6L&dD%1p=*$8oq`%R^i)10%Wd}r?&v~(E}dwM;a+HGWM9J} zPUpy0pNf@xUf+HMwv6q5lV~WmSYfXVmG^qv&+1S37~n}NhmsuCRu=CSP#T)HqtOba zV1oy+4U@-Z;#yEsc6xIXUQxxe`l&h{R-F%nL29WS3R(5&=EA-8b<=pe|1x8|@)^%Z z)z8r3^sHS1Yy5#g^gv$tJHA^RFKCkA6%)mQS%{U&fjv-k8b7aa%kxhL;2HTZN9mv8 za_uiY^1s*QEdR_V{&qV5s~B%rHnCQlLw-M>xi%M##2T!|SEJRh$9MTQKoqi*%rfp9 zl0*>64~;|t^_@J1P&m<--(-oe2j#wiFdzPFABE-cK1;}`Ea2;mNg>jwB&Ug2J$*V| z9ew&e^SM)HMux#)o#5DQ&_?@3hug$;`bC=CZl;&Zl?BjT(;*KUtp3fFw>xHhWe_IG zpdT!Ue~<%5&W;RtjkPirSK{xb9oq@SrOB&2bvLo`jKnA-On1!rD^Boh8-c+GERyIQ zI82hh@5EwPWr)I8{KOf(QM)@X&G)`YP7;G*wj5MSk)s+vMRlT%oQHh`r<3X0PW#AN zvh|b)OW8CLy}e5b5xxzi_P%#_Z)SOW1aYTH$NlbpOYd&tnGY1oc7HovIkInDC348ADYNzuRp?7SH)J492e()y9pMic*)Gz_awPIRQqg zxiQ^M+z3kB6atQXJQtE6_aHlU1@8s(#^y@(UR~ISP>SF=Z*QyPw3x79+qkS34{-8M z18-N-+Uabw``F49$Q3A60ma;UxYN#%)y)2Q+0MD%`R+@wY%^*01&m1F8i=3W{Ho91 z*J+fln>Vo6x1s`eTdR#D9s-PcEWn`64oQJx~2r5tTc4?p$kS z3K?rmIh^{j3hSyr zq|3xJy+*30a~v8sK!H4&fJGhbxoK~q7B9WsHg3iPF+Zadlb^6ZL3#uFX#=nu2bS) zI(@E#5$MeTreO}^X-GiEu1q7P(8I{a|-X4hXI6FqQ@E7z%8!F8DcwE#)QFLw;7z_z!I^aNWI&4L1-#NvA>xO z8PY5&g0vI?C*r^JbK$Iy@N&j+D;P$TM)B?;3Uwqyo=V>ni&F-i-3&cPjMfpPC^HnPOqa zMBR1xH>(59)-6+R7+PDashEKeiEFLV3J?;6z3QF>>0HiaPlkN#-=v4cMTQ`4YMpe? z@B-=V-9|lEmOX4hBn$;|)Qq~uVO&ZnRsvh z6xuN~fjlXlzB}v@n(ZULzK87gl4wTuU+*%#xTmu7=Goji9V@rgg=LSUdsZ11W$Km8 zIONMG^N&rZpsm%uvAU1HS9Kv6Hbg#8_0|pTkB;NbU7p3E4C_5P)*_T)w0n&@7xN#D zy1y8DdVh~P<}&ea>@w8kBPqsETY&D6T#xRLP9gF$LEQnBW{d>$NJ8?Ciu2A=?-b&Z zNTkppzhJtsPcqeB-41dy?T%esul?k@{549cjZF)n8{SP?@v>@L-=>k8n(AAfSN!wA zi2JZK_O!X=4sQ|kIv9WEu6!FIWl&xo-SZVM=)S>TD?=Yv>Q`mHW(nie!x&95&_q8%;8nrtsJa@Ddv zRkwbI6R2tYLWTFVu%NTKBvb0BGfh1F1RcI`5YNQi*pMBpGUZIOEkHHg;dORBP!r#> z5*l%V=NQj_$c(O2S{T+c?g;ZW+!;s-6L~AhTdoIWci8Rl$5iId8&jghQJrYBvl3j z$KsnNqV~dyG=xq`>oZ3BwZ`RJCcTdk#-}*O=M>84_nuFwhR>v9`XoetA*fA0| zIwTBsFxpvAw0fLeMfU(*pQYD16W@|UL)tgK;w!%T0_7m{<+yvz4mlap>YUPC_VO2v zc|Cizt*M%_=2lyRd^_B>%Fu?x3VT#8JDovFr$zMUs(H=)u1RTx$i#Z1YZtYy_9^6*@}X(%++@pWLQGIJDCI{HJnZn!*zS}emK_@#;S(uQw=HX@-Qv1z zpFj?2M^;dCiPiEq_?gs;)FYmQr<0k6Jpq*f!8@Bvp!^yPi%IxM*SD3_}q z^g1|>@C(Q=`g1g%IK<5sosA%gfl25!?EsA+{=knx$iA9yWSHcUA(IONCdK^i&Lj`k zp7O%ym=eCtDVZ70PN!^yb_(s_xJPUbIIeo+d4f`@JbJ<|;!w@gCL($9imZBlGm*${ zvv-9-A(TSs9n#xibEz7II=NMQz&8U8lt+c4xtlsC6&>GVhB90};QCSg(rp~V$?gW; z9l{_OHE>N9xq?jhgj7RA=E`NGftA@olgL|=APt+}o=9~<NH@P?*U$9gc>ox z^(@)P?Fc0I_Dd=qywRg}#&7BRWo*$6hqAzLBYMs&i`>I?rQWa+ z+cz(?#+uBdJzB_Q7pS^xmIv16iG6(sOen2fHlI&QrR09VIDI*JMDd1dQkD8afmpSw zI}4;H{4q@-ZF5lMWrst=kLdN?*X2xAiwjdkIyfTLZup*SVl7RMfVYy;g)Qj_izG{p zB*TnVWd%~&GyC+cGIBFi@*(wrw2v|a+bRn1~$<_J7FEb0Y?H0C7`sb*&4 zyxDVRH}dosF3tWMtLP@^EN1fWOmXza8TxPbf7Lt)tiluwV7`6J$NHZ&kN*TQ)c(69 z{+}1Se{oy>!ZH5!^7q=ue_ZksbY%7gQHMY08|5a=Iv1>(F9**8)fsmpT9W#RXr>qn zhbVAZ*!f`&nt{<$+j^FqNak!6+=~39vk6?e^A0pqg9Hi!|OF*baRBbw7k*#p|iz)B|Y)&&!FB|2qJw=rCz0jWTy+(Na7$hUW@>m(kKtW`rlIEiEK2tf!g&z8{JobpZpy=$oLzroRidFI77CL-9HK_Ep@+}HsoORdfXl6s9xQi=RsA&o~U~M z88SzHuc?c~d{Gmk_|=twFr9nxVoEx;v#bSWvBIu{L1#0!qY2w(zYpJc zs2-u^fUuAV%H6nNS5`JJT_G?9SzfkTBg#SDa7Cu`mN;HFkBQDWhYkzg=)NEmL`a1{ z*fE~xHV7zWttF3roNDiJ*Ybn2IQZS@`lPMlCNYo(FL^aziZv6;%OL4&mKAS9N)v${ zDPm+mKiyMMjw6Md?~bAejq}-L(a*=9c{4H5p#Ak{Aw~jt2*EznAwXJIb_X}#dx~lv z%Ib2(`O(zK(=A(H?@9|@2PIgj!l72Pr?UeP)E- z*&r)sxLV+emfa6j*Whfllr3PS_X2{=*~c_l>r4xx08wg{t1W@x{kjx=wLd^M%Q&ak z#<^;QotaVa07+Q;CKeN2`Y&ep$1~s}i}Oo?KIV(oCo_c-W^;E1o4*~AnH6(S=;KV& z8r=&SVk=$RFurFU=NS4-WZKQTQ}Mh2h`Urq5H`rGxEv|kxMPX5VdE?dQ80rnWmLRU zTmnrx@1Vq=V9<4egD=U#!TAq7D<_UI#6G8-D&>rBaa}hC`HWZ{1R^|tQjcQiL9>5P zxz91dqoMr#8^n4=uzvaQ<#aaxtJ8`9cTV>oB?i*}gOs>aeNzQT4fS(#k{rg+U--}O z5N*|PLlLQ5I#eBNnOtlf?f z*6wDzQsE6g!*W`RoAQ zex#Yo`ZMWajNcQq=}!})tIaTB71h?&W;WB^l!$2zIx_K~qS}IVsra`23DH;8(7!E* z4Q<+n|L8#bwk8Nu>s2u23oG_4&>MajV`>4?($c9O@DJ937Jq=h>Q0BW% z)|WhXk}6|;_wUR1kI5WIm&n%Z-p7Fp>bxQ!rWFy(l;xot&1@vh#s@u5wpfp01}vu& zX&V@g+t_m|WRrSfSRr}~f1ITIj-p}K^m|_c;h?4_b97ef=3&4MzEI)x%{oNrnt}W@ zerWlw=F1#1q2927clMbwP%6LEv7aW`>w=EVafC4nR5F<~ILC+eGh^04=Ns@~TXtu* zBp|?qibhHw04jdULX4P2pQIfBjk0 zx$&Dbc-bYh-_u{EX`zs61+1ZmXyivSI@8!uGH7*&g%UKbXBToQgB7H;Q-Lcwg`B_F zt>ob8s)2fV9Qf?DU$ao~ckSf+j;%YX^0LF1qv0wHi!t*LiFheEu<+2M$+^#nAU@>y z*tGH4j_CJ>3r|?rp}7$Fpd*kZX%Hi!mt``!)UJM5ysxej`GzCE^B7hgu>~l;268!& z%t@&1vcpoc!OXf{>cw-xeMBJUw53lmaTg)xv&>l92r=#9Kw`z@P1zE4_>c7WND5Rb zp(A(aDZRl5PH~qdAn$R4Wcx0xs|9w)3MG}A^9q}wto;aDbY0_^@%xR#%Kr!3ImtG$ zwck07pq!)E(P~G+rS`OkJlzZeUnoa={e3aDfal>-{Ckm+n#w-U*-aK3tI7VCh+x_6 zDr9N22?&P0b$WKk(5e7&MjA8Fg1FI75W{b;@EHc+5w27h5rMiHL>#LmoT{XHkjU7j z*hsiQKZjSun81nCk*EQueMqGW_X3~wEVMU7p584yZ`?S8^2-hfwi#M$(spm;$zolQ z$8n9|+~105MKOJ*e5Oz>{i)O5=jw+9r0^hGH_LYL=;Ca893)H9uODN(e1|ZY71Z10 zmR)DYpaM)&@O`VTlUU!Entvm&h(1*kL7LIMUt}s5B@nvhNt_H>9@K= zDMJ`C|D@bcJE>Q1%dnUrH=mmDz2n*5@O^vx68}cOQWqbG1+zO)NjpMZI0iy*J)n7 z+p^)jf!*&@<~y}WH&Yn!+DFjm+y!$-ABH~o!3P2hwJIUPZ4ZKEdb6d^rc561BG z2ixI@D>rhf$3{Jwk}W65GGmU;-a+{6a2KtQC1UCI{J%FaA zd>1<$J6Y5XkAt-`cjWrH`x3l=NnqmB+06G%IZMA}BduQ@N!L-g&9($j$I-gU z-P^3K$yK*)^6j&;*^ZA|i1>8E$7g%I^J?=@;P~Sy^Hu-m{1|~BI9HXE-WRhcrk=2t z4MwGw?k7R}N;Vh-Pdy_HkKRT?Frgdx$yBG$D}|7i8$olYK&Y3?U8kOw>I;ZSQay@8?@qjn5>R>FYzSYX0G( zq88Beb}Atdd1KxdS9#_87)dB&5zB&@r`{AT~9Kc8Y6r5uL)DD9)S=Z zAPm=m9DicpLY zQ77qa+t^8x9J;KUMN4=D37Z-h>P|{>V`5v_%3}4|#cI9O^9Rol>AFc&8*J>Dd@UtO zT$=<=ZgvhJDg)D0+&wut3owZsUnqC+`XN!zHy4|UcVZFFt}dY+g96Daj)Qy=XQG;0 zwzC7Cwvl7Em^C@NQZ}n*rT!TyN;1i5VMmLfwY;iKU@O31+D&42e*qY2ukzs@fEaCIVGKNnxh_%9Aigoe0iGVZy4?$5)qO836k zcG|`(dT=Lin-w(4#&iR-b|iVavJy!-=(z>&YS-AHH?R=A8My|Su-c7B;}3D?!U7U$ z-b@e0)S(O@%a?P2C@)snAWtZjztnrb2f5?inpEb*iN>pMJ*p%t#~3QbGtK?BW(QMS z{9G>ITD+zZ2XNKJELxo?h5wgc^Bq2o6K#Q;W{Ihxie-*=mY%02^ZI((;MY02ytsco zh@9joVP3}hB9>F(#7^LT`jNmH;p?OGAv`y$c9PmBO~ecb-Nd=7ze+d1o5jrYGP}0G z>L+%8$wSM_rv=|*x3C0M=DVDe^t|pHT=e#|+M77hT-(;;rzAkL*v_YP!1j4|oF9>huke|WbK@Rj&FnM@* zL~m$kA|3>@i2OaswOonlvi1XiRtJup}M;`hO|%!(;Ue&cX9VO4}Fz)#Q*_Z+yg4Aab1UTB9!m8&sD z#7w%Rh-qda#@iaiG4oQ2k@Ur0aolo(3XbvUJ8LU{)+N3WnH-dtm(MeFp z@#AfaUm3ZyDWWRiu1vS@iN#bGFn}yIRWFQ_ut}O@N$b0`9|jt$klh~dVooft;r~*p1HCFi!P~d5T*z#D^uW+UEJ|2a|tBs+!Qc0OY3r&;nf2`w`n{AzD1$EkIUO{9NIW>y8;DPHrJ{16gAc^5it!N^*eYI+nj4CrnwNdlxO1Sso zV%5yOCIUTkBRcan*)|@+lcf8pj@=9wI08MlfB2ngD!1GBQGgGBzv;JqGHy+2Ox#D< znqLHCO&kfFO4Wm;?jGhzp+tSVXpGbf*{{}MvB6D9HT12J^H;{7pOH(45^YSim3;({ zSG|R`pZu`come6;{l1s64M@GU-8g~nw+S22ej3yIaYweWx^4Pm%N3S`)xDy+5ztPl zD5J1PJKR`@s%+h1PV`?8OMGA}XNWZVL-y#99OQ5wB+}lt!gPvJ+K@xd5M#RmCcKQ{ zh?H^d`?~C#{mU=Y0Y4l)j@gZ7mA4G454u$GNB#(2YP?Sylz*5D$|os`ABqvRFH@{G zXz4pNnqO;9;MASBFhjE|*))BHL*EpBVhEma-0^ng*UydyF!7$xD66(?aGoc+7)!2f zj>0+9WL9S%AJn>Ke-gn~(NJ#%^I9=YG-!vAWK=&X(mw4Wz6BX|A`G_VOZ9ly3Bhep2@js((IG$22T5m zImxQN&;m_{cImv8{1Y2(*3MoYu z-MLN^T_R=*s=AS$D+UIHVXv)SS-rj`Uj9-T8Fa_Cyi-J_Lnh)`2X^R+5!f$R^qoZR zlR`S|$pQ6))*r3h5-zjg%h+%u)_zHG`tqBc{k$sXwvP)&wR~2BJ+xhkihDGZW$?ug z?DI9?fcL~!X^&N@q~64ALfV%(5b5^e%*0PF4fpx|(!TR#vp}1sPmpl`V{bJPMy?Wu ztVlR{YHqYeQT(ESUoCMe%Sk0WZ7tCwT-@RJ6|gk#8byIz{=-^kqI;%Gg6Z5%^hAP| zMAlF(_nI=E3f7}^F?Tp&05QzI7(4lV-XBn=Z!Cj^6BvPHvC?QkK=nPbT|MXJV2w4X zv8!GhQ6;o$Tm#&m{($>bfa<1!BnoU{FTNygG8Jcyd3X_~oWl@eW*sO+&Q4^%izB8y z8VavNIb5a{NXc4H8M}i#y8}56r<`V4ks+&XBVm(4R)8^$|6O@tf-*!&WglF-w}b48 zsbr$hK1{zI^jv7|_#R^H-j0(OJQReR)BFZ>bHyd4Q=DX?PFT5%*M#Og#*R6w6%c*?FW@i%N4}9Y^~gX06>aKz&-W zbrDa9Q}COiB19y^Ev|4Zi8|dWm1qG_X0>X5*xh3US|>)YVySDE?}9bBBx%YLPG=N6 ziZkWIwIS0!iIS#FEl=ijgv_-lI>n0`_J>nA6QE@TR6Z!2Nrk>^qZIgsXE`|nh)T6( zs8AM+Ag!1{n=k{kWw%&QJFvubMABq{@Q4yyQD^ID>7k62^op8?WV8#cejNHLFDhmm zj9ImIYpRE<6^W`#tCGchP~|O}&S|R=w=Oo#YLc$;d8u1pFJr$of%{brT@|FQk@~9d!m#yWobX?D{z`;iuaqUp zn&ea{udPz`h*LFOFTI8>>-(j=>-4oM?S>h4`&f;akhC#!o@+F{M>J}RSUS{6z^=iT zvVYao#S7OPC7msUr(VdZmVYH$(}5rKM!T$IPdRLT&9BPyE(_onMk_lYr^2j`&uEV_ z9(5};DPjI|s2~3WuYT|$m9k4h%Ll~v2FJ3>F2AWwt1rC@n5oukLVGc_shlaJ74VCt ze~g?;F~gHsdQ!-Oihk~!!OS;|dx9NO5Qh=|Z(2PnJCBdZ*Yv>d9R9CF{;x>>>(ajW z#r!mU)nPUFc>zra%axF zVI9f#eJ=_~~sn_+;aQ9fmZYCGHnOpn` z#Q;=2TR=6th(^X}c@cNTkRtBbC$wYuV>dE4{{WdD?fv%L`fm}sKqZ4#y5KE!VSAap z=A@Z*<=?hs_w3!Q@ifdlxR_f|0|ru0+Z3ChKV3dW z=H6o@p9IJ^KZ7V=BkRwuIMsdR*Q+4zpl+~|1v^bW3z@AT!?6SM0lB3_l;u#jdHUS` zbXnh{ig#4nrZYT5#-MP~JK`?QD&ypLC@Cyb_;w48=S8O4^>|Ax^1r$Y7xnW{!0K{pEt0a9eK?M)am4#(2et4!KZ$mI%GG2 z9_t+MIGyQAsna}YmC6MN`)1|Y{+ks?$=EQ!BYEVJ&WQ0ROC7@IV#<&v30X2wnbQ}s z%bJ?kRQ>_BM;{I!7EB<-S!fqiS$ILPRk1?Z3$(JvvYnU7tz964jp+7iOM;47clB9S@gJ5^6^OWKN~K=Rex228ghSG%G)Ra!GHw4oPNJz$#K3g)@u zIePL%H`xgmxssUaaO}ERlT6jw4SmVi8nv3eR5>j%WwF5%0KJ8Vj9-sd;6Dz;Y~zL8 z3dUI_LPn?kd!iF@S}O}kKr-s2+TtoUez(s>>F$eL7vZ#yMaBQ^Ich9Q_fWj)Yvr+3 z|N4f)R{dAGWrNd!F^8>sbomc|EnBjNwIifvJU}ttP^BAY!UmtWC z+_LD`1lx;uBc-g_VLs>$_`#-p;wQJ9MdK)(1767UReYoe3JI|SfvrmoM@{#L%4`pR zB8`|!k53ME42+j{*Kc)>salXVMz=-jIkqpi=a1`xYT{=deq&E_>CXLJXfN*sYY6AP zDj${>JaJzf9n5xLR5}$~IuH#FF>XoHHlI`jcOz0x27 zwL1{~OwSn_N92nMMgeBKLq4G|nQEU$hsCV0_yMcB@x$M`ayp7Nk}OUwgcjH|RLlO$M2$NCC^|+J zhHjtK#G+LJmPoDQPn%qkDrE$d`rX zm6i__V9Y0`V}^$}rBk+I7Ay`(vHZ3Gzo^a*eVSpwx`zvz=71D3fCoH-8&@)5Wcc(u zme_+{K1L0wZxe~L4Ix8Vb)%T|@3{TlNE+5BmHa9W;t|^2rRlZIYRCbL{MLo&8!X+D zACFp^DLRcXgY6Oc{WBSV#HI8uciR=)c-|xO-zMid{2T3v!C#>CODXm z_O-DJc0T#?%`=Pr-Y1d-O5$hT_d_L^Omnu?{s_Wv$7OHxIX|TOWXimYw+bFXGnU5k z=0}F?ZM#IvB9M@+aNzyABIQ!;va;*LDeT{$bCSy2`HadB>5f08)h81}_+H)v!YQ5G z_6(HhoPVgiYvJ!1d@yaQ$9FZl+U_WuUJ{pi)8#oZ?Gt&M1#s*F!@SZ7HQFY=YZ#^6 zyVY(rB8tp~s!4cDO8q9|z}H3bryYpnw06t{50dgSdeX$UE~M$F;l*o9+0{pOR@Do` zNyDf3#)kW6_{7KY5*a>2&`+ypB&)BSEnDs-0iAX?mZ7=uLs^Jc30k=@)MCq z0sOD_L&;sQ3e)G^ZPOnDE8A}rrjG{m=AS$h#M6r|N2q99gZ3%ui&!U3$)Cf$?o_sS z6^|^%_#Cy6WJ9nk>~Q7%*gAn?q|1!Q#!Wf#>Ois6&36c z;UM1;{=(H6q=nTdzXtT2vHed1#(&}f?EhW4RMybT^IsUiKd|#;y}wHTfNe_{on$dY z#qe--B)THSgMNf?w4(g)y)cLZmw@`7c-s`4W^vh$>pqyy8JKrGaTF4v0-~EK0#jZV zy^J|GkW$OX^YaO=Y44+nRXM+pms>nRTo!2hvhOXl6KH63m?-44f-(Eh)!`>5B&fP5 zX2PjweH)1I2}X&?N5uhDfaDH4oDJQDiw?uXOSuxv6>@tLH8O7O- zuuR!|Si|)kD4lEtSilKO%(EHu;_^8(CMho7{tRiX^Xb2s6RApkPFAz-&HsS+BOxT$ zE2A2Ro^#LvApDwZz%q_+X_B)RZKpd2;eicH2{@bp2_~t}!^#ZGT3Ku)(~ON8u!}6& zM+zL{^YZT@;fl~}<(G;1Slq<=rqI=xZd*xh?U_gvu~v3wCbuVQSGXdG_s6G#Z2Xn2lXD8V()@@HW*D4 zx$V);Bl%5Hak}4l!9{8NcZ8;u`Ykh&iX~EY`ZksvaOYud+2&>);E&lvXDW!OWeJS1 zUzl?9U<~0zFqaqu3<1CSS>kYTXzYsuA02LUdz0{1bdeO;auo>mp!J3wFsoeb3u-D6 zE-XYrqVogIgjo|rf0_Y3(5&=ZY@_=S6dF*hdffueiGCB4WS~BW5{zzhh+hIbOT-vA z7;U>6g`W2k#4Q?62juwvM81fyCAzKyRW@}1{2WI{r*F%{F(;Fa(>Uqz{_vfgb^3W^M#N;?8=cWR=;;llV#1r5!f55n4N~SEAY>YzpjkT zO@>rr2+)@E&`%J&FvytEl=DzZ5WI?(nJFU&YIBDcHn71-CveWkcqyZmYhTOLyi5W0 zCd->O`d+q?bszFw5!!VRILhZ>l{BVDq2WHhEk1@)9#>UT+HOA~2bgLcfURi+=O*w{9nbve>FTUjhf1|FtLYf7$Is z)ydG#+05R_*7X0=z)kJK4n+fzZ<%1#qmzi#2Yipc(Pt$(3JTN$SsEs<5r|@joQc3T z&hA{U-teMn>8!MD0D*KYhB&DlVaD8|2>L+1{G~l+E~J#(xpS4XPEV5T#rSwDE9+|# zPFm|@j^F1C&re)@3lD>koHsF11J*4`uX z3|@$d`n3IJ9UD9AXVvfalP+|Y7_!Y~TuFmz*1&rJ!R;TKBYD z3@!D_I&K^FCzsUhi*a&<%omB0a(-Losm>3#@h9{nWEs4Ho+XkL2`>CzPg%S5mC(4q z1DcNWT4(#HVppSt%a6EIta18!%zA-q1UF!ar7L}8WL3m%SVFqwJEVc|O2x#=9ys|@ zD#H);&`Uq2tEd%qI@Bu2zgMQ}3sO2zu2w~LjwkEf*`?zEzj6fHXladZYHO3ghtJrY zK>Q}nr7jbMM|-|zA3529$>~-%P;OKib?b3c;ILe)KTAZr`A(syG_6F?q^82IkajA# zjJA=GTvdPXS#pU!d4@iHqF9ogZ3gKd@##nmTNulJjdcV^`+Zgr$Q|~J_X76>=M&Aq zxg!H&zhBtX1@8oB63ga*%>`n<61iLH?~KXe0DFb$kuvF>%E%Z75mA98qXe+e^0{6*f6bzD^4DsK&&jP#8!cBeH@ zmi^_WBHao6On>*0gu^!oOFmIQ2qIi^gGe8VQ5M;3EK#Ilwhx?v&U=d^GGT$T9?(^M zXyEESx_XjHMym_RT(^w;jZOB!+Es_CP>{?Fr6HGASPLU4xxS=0KrkS-d`2-XW$Vg^Ts;0ndSO#ckyuqYp zG1u2GFX+FcSiGfl9?87?;9Fd^{n;!$N?Yb8IU|w57ouB(*6>tdJB;bga!($yrsm4? z=eh|WA?~x(9#GqMN!Vt=3}6NPHl~-$G;hFR{j(r(=pem*Iuzpw8}RfML_-=&dqV{A zT|mb05NE2SMSfQ*Y4L>;$DCxHAsE7)7EK$1`|u} z5nBtUbP{AEmDPXQytX8GR^h9(z`=wyOx9xg?0cb$8f!>aB7oNnLBn`IdC?_WQ*b+6 zd&1V8hB|wt*F9cuDOPcsS5=BQjKlxp}FAQbgVoVz4sG zW6Ca6-z}a0m z4JUekG9F!~=>a6z)-6vv`lI;raNH_Po7+w3WH76#mg%-;36|Td`{CTzEg>aXe|a2- zG1`Q*|57oeJf>g*IHILlB&Na^QRQRK$uT+c^(%KVs`=bzow#gb?2+{224CKRRO@tX zE;OILq6*?eMZCg?{d%4;pgRi8&g-3hn&U%xl)B*D>uL1Xiz!vUnAY2UkpE?8gr+0n z7hrlWq$D!-!rF=HPgQe~Z5&!soEZ{~;_IZ9T(pa7R#a&{vWG9Sn{&0`0EEG&+h+=Q zr(C^L4#-SAYsuRsw_{TMv`55ZFaGw1mv-alJk3V;KAkufoi*rm&pe--BBH<{CVi2+ zX}MMvZ)##59`ZfM5~&wUIheMVcAJj5aqdN)GlHu=^4qbGU=nYUeTOEus7anyf)si;;R{He0*Lko&o=HT8P`bgM-)N#(J;+mO)8ggreWr_ zO;9c@@g>)i8|w7|g5&@#1*_Z~@NDa|ba$q95&jp<_a?OSj;$y7PW|)w0;*i=Iu5?f z1M03S?#q~cWhWv4$suZM*dLyo3y+;vN(~0r`9dTho)w~+@($&Jy`eg@cz{10rUVro zLo#S`bXtql7h($iGt$-cx70OdJR4;ehkW`vd9G!dE0qd1a%L<>WtYB$6J+qw zdczy1A zs0X5T5nO=P&l9}GuNxptQt4?4((=%PZjXDI_cc2|l8SkWeS9PNR zepxW0`&^6z@E@V`4LSTbh~R`u**%1VMA%y5LCm>4crggIEy@zV8yGr(Zxj&oTO_B+ zbcQUJb3fmh=8-GdamIMqi> z^4P?nU%b}d04kvpfKx|?EZ7f>DL!gBRU{g-yhPCrTx&f*IDSO9q<|!!E(@~iNt~;o zpxr@uj<<({ry|-Jhv#c%!bOg-82pYzrO!$`d5BTXEB^hvPbz|_)lyO%dR|mPg+84_ z&f?Td@x0}HQ|r1-9`OxyX!wY z4GaEvyGz{0(1qpeO!z+vtFx5ceo0_Z8UvXgMitGTYHV^#p*(u)r;3*zWaeBXs0ex}Hz`Kk=Pc)u5QKVaUJSZ>TWr=fB7|aWe zPOeyA8>$Q>1IzRIB*?)C>8WA$kih?eG3FjrT*FuiM;L|nqTm#o1KVkW3@bL4u1Xr6}*&k14167n9zy_PJWQ>Y|X`t}152^8#$O#J~%o@G14T zmO(<9K6rvuW*=l0*%<7^oNSz1_8@S0&R;oz0qo(h#}}db_3NMhe_KraXAbaxsiXh@ zW6}Sk0Ps)pe2e2Acjq_TRuxH|y~YJe$$O&Gd}y(7)SWysNd1{1Ei(FOyj5#b{$RhI zJjqb#*ynHj&`f9Cmdf~u%Cr{~m**2{EbR>+53jEZ-{3DZDEFd~O;Nxqu{0Utw^9f7 zRAqnH!l}a9V6PZa^6m$|3yKq9R*EBrmR{a*qSyI*!@`_Q`NzUh5!3gFzJ-tj-bfg( z59mdzjhZp&um*rSC$!kL8K^w(~mE zjS>sKi&;2@(9tl_=y}7iyzl( z)(tDihY?Q(GKT5iET}Zqd{*SzqS+Y&MMzg_wnXE=&U2PG?LKI=MACr&qT3jtOBysR zRUiWDpYqF<6_+pSY4GLGJo3!y{5dDe!_-lp*?v*h*tj{TaWadZ*M;TPxB#0AU$_V| zC#zLK@s$ST?-ENTuwKXNx;uoKEtR1p*UD-GRhoQjKPdCLTbx9(I7Y%(na~ff^*K!< zD#dz$O|9Oit}aSlNWnT%7nhzFh`PQlJG{Weq3bs)KdT=}2`YFTTdW!RF))YlyQac` z@ea-toO+fMzbaZ{#(5;}yyqvO^kyCEA#E^VQFV))C)5G{)SOeMK-4%IAa9HxEby1V zUPoYraeetJ=l@FP`!72Y{xfI&SC6y5J80)$17S7LKHymrcvxhA788MiaFSW3%Ep6d z+ygbnk&==H2Q3v^ls0WmY>X-=EaM`gm$0TcR%FN zr_i@2SG@EO-_|@|cr&;IMi*iW#|fMtTaVB0F6^%wruogc-lx~Qzs*F-2(cOpr;E(t zCLcM^`S6E|`v~=8fFw!)&s?{#8bH@`Q9CPyE)`DrYV~WpJzF8t+!V?Rkj)#+U%SF> zLmIJ>zdaX^loWXm#h8onV~CPv-|u@0c?czUQvTeA-oezLyLLjvan${(54E$-nYX)0 zcz>`QqVQXtOZ056-jhUcy2$`O<=q!}c{% zy{^uMS|&{vn~8kmq6v-?ykM)6F+Ci()~fi|8v=~P?jY{_?hFne=uyA}4R zu8o!0IINkFc-*p;tmu=`PA_tz?Wx>lT)CM+9&|C0NC~et?}2k^qPUraEZ}%XEb7Gq zMA_m8502%~`SOf9RtXkyH`c7kdA9-W6Oy2j@R7^+7okorbMpAf0Qx|DY;^PLtX*xU z5=DHO5?Q{uG41vI+O=NE)3UfDK9N@`Kb?2}HOBLcJG{mR>Z5W;=44iv+j|5GX03$R zaz(5%hN3biHXATHQ`wcyHsxX&x<_2Zhr@lW{qMwCM=Iy5+YCl(_G2!)6n7YZe39v(FD%5)H!;t>-r3^?^zlG3UmuyvC752>K5uw<6ajVc+U4KPp-!eV2qz z7yVr4&861`e|Dr+ORu+uQQbI*}0h_eh=n`{o0>~aW9r!!4K zE2u}ttWSR|E|wdjRR*9XJ%;bm^kdO?X$QQY=#rbcP!uX^OhV0784(B3tx!+8S+*6m zYNTfo4fLAY%E0(Ry6;sZ%1b$Gr&HaBT=V$|1VId3BFy9=PQ9+BTuu*)x5p1*a#UFp zn?*)oC6nX>P*!W1*zNFn~}$1 zpNzmE$jB#ZMf4H9VG6_@(LQNKl116D+eDw1T^o`l!0+O2?ZFYTgrQ#fi}Fs;BABCu zz*T?E^?|85K@^XhVMOVp^&P5j`TdM`5dQ5`H{jtH00!7cDbHG|$Jx2cS&4HHtA#Uh zFUVF8cC0VCl}tA8qiwoU_%*+o>1tCrS~*O5Tt>6mT5~m4MgMTg9iKi=^w-&JChv6R zv>X{eN|6D({^)joNX!r3$~k>;lqDGB+=DxlQ4ZZSetx^c=TvK2vF}r{KTKMywe`6O zIL|odA0=;KCV-099XA(RYY^x*gJ(bIorU!!?l7e}N0V(YoW>212?x9BZ5zL?x{J3pqk3w5R55WG-2oSqy_aJscA z(TW(jVO*oLOj|N+W06e8gfcrPC% z_!VcXm%NuJM$o>%MLw_I5qx~xf7-iPNxY=GLm>EtIIC$Ed^TO^w}=0pcQy-s4y7JM zcAoKcKJs)P_OvnID-y0Ta@WAOu8DU(0Dq=~Gf7a>TUP{RMqTeoTmeqyYh8$d)H1}z z_swC~y+iC``#-Ltzfm6)?jU8+L@lCl@)UBndoK!pO;nLAg=;AK0?|Ows88+z#^ou^ z6div-zS64f+P{wpl4dS=hoqvZqj~M6@Js&5lBRHUHs0(S8zPB!bV`+&Cn_qvX zsf>j~KA)diKn;i*e7j(MX9MnO+%Fot4xzofRNM`c^NbT;F z&(QxWIsj6+T2C^-(XzJV`xtaBZ*Iha_fxf_r%A8i2 zOB}5-s6LS?5c{xQ@Y$YKD6AQtXWf^U(R`-&d8M7BsmXU)zK)O5WZF!4waz|G)<2haXQ)aZ-G7VN_$eHkC~7 zZPDKb_;_Pl>k$po2G6<8)%C0s|D#wiHk14Ru=b8omZ(dba3w2k+qP}nwq2Q(wr$(C zZQHhOXJsWO>)f91zGuGab!M&a-`@Lo?06%dc)+w#^ac{xHCVVPz|fXhM~z0nUv(6T zM97an(5(s6D|%899Y-pFX{EN@u*4Z2ePn2!D6DLpYSxIXjd(aAur9>Dzo>tx(wfMR zQ%;&F$Pn}?k7ZbWD@mt8jG@_S+4-P_p%UpsTp4SQuCx>rXB)Ff)i=0XBAnU=!pcC| zZ-IEG1RPn0LrtO4)3|uJb{3Ss2p;_KWIrK@d)WiF3^W0gevTqBd&eB3V8?ew)uQfE z1)rVx?Pq;NVgNW&|HVr-UD&e0n(wL8nQEbScSE!7{VL=N+X#Y|qEfRGuk7cyr1DM> z$MU&K&Hah@K*OO>b2$3~;38CXqhr0PoTa{wz!XQn)>5>4V0vBRqjO^VNmn{TKXu)R z(X>h$`1_yY6B}G9^1W7MLvPsh-m(+C2|Zdt{wlxGcubUWpeHL>(>w8>FzhfJ^Ao5O zCS*;tz#J2r6>SPS{O=e&sCfKl{^erqv<-oK^p#3ciT2;8|G(e*{viS=Wp3~AU+5pv zztq(#=ElxM|KadlsJL!}NDs#yzkXCl9HY{ZzzHliHz%EqnJ5WRIwyb&;p)tyvS(3` z>56Uk2|)x$0UKh<1MsD8x+PIorV$`ZxVbIJ5pPEznBY7b?{z(S_gAE>H9*Ll!4Q5@5}{1SA_FOqZYo z7cF9!Py;21j%NHAi{{=XF_Cp8N&S0zu*D0aS(xk+SJ;Fs5`xWKRCvq^QHS}+{}Fb; za#uP6qEnl&k*;>j!U?=JvxOF1Sy%XO&}bq4weTd+s`Qr~USHMB*p=x}Mkf#;80>ML z;`RXtW3YAKTy}_Eo)`|s6HA(+H(8!<^D?KN!&B1pekjZVqcJ;m)?}UjzP8frPx(H- zaOMg&HD^2Ua+oXoH**2WGjpQ{c>HV$R7|x)lqprr-CN#o3l(z%?hBF;D8B5a@1an8 zN_IQ&9QSbeRIDFMPkZ1%HV@bM0fCIk1Ghlt3PycL-u8Rj2RGmAr;AM7`|hwVMs6zh zxUOkyo_wCwlMm&*2p=;7 z4=kl7fX@LhJPrg1!pVdqJ}C97ww;uS3L?x8f+8d*1kx?aYsP-SJ^_tg^yNbKhV}+` zL6tc%b&5*polbePy8NnB`Fg4R*M9Z3*LS!+R)(Q3Xqwywsusd6Ek>V=EzGbYlv1q6 zD3X{E-N#SWc;(O*sl;~GJ&ZXX0Bcz3+dNxuT0E7L#L(%_j-nhM?ih@X8sA?D3=+|Q|vO~h)i%~Y18XiK;*!>K_{q4kJ?!-z?nnn8-MVxtq zif-!ZPo^%z{!`otWBG0abCGg}+(O6dy%*7^Dugp&0X<6YT**M+TITSk2I?xM-Xb zF$gLU;z7s~!JrB@42LjnO;yA#bqJKg`$@c3DZs|lNL{QsNTqUxHDGXz4+q1(slwQ<| z^8f`ex%U8T=V%?T1JCtiU^H^n95p{m`(+Q#i?Ga`PQ=8B)m=$iA)cqHtw#@1n0#Jj zDGPfxpv%Zx&!L;z-=%ao_}*Z^GdjI|Ob6*^>TH@ZNHy(2lAF8Y+#QdxzjgLPOFnX+ z&1It*>PdxYTs7$K>Nn9Bs~L7J$`e(NZpSnJgN>V*lm{lApZ*6+IiNI9-qzTUZcAi8B=si6_oE92D2n6=`AWH4ne=)uZZ`jg8cVk=LyPFPPn$Pzf)3H^ z8eG&12oM&B8f-b zrI=ey@;Q;%VzUAv&p~am{7S}~&7=Oc(#LyP_u3>4X6_IOiI7(X6>Z=iCyYzOe9d(e zxjV%#GsOIUBEtYerUFrYAbCGtdMboTn4F$9KJI<;AMfae&+9{Bw6zf+#+e3U;d{Yu`0ZR}Oh{h3oBwTeAjCB;XAex~&=v`86N+<55P2hey{BqL3 zhm{LT8^L#w687v;X_mPV;;^EQLHTK4{?t1+^UW|91*~Ph2AEKNdSud8AlCI@FSbC5 z&bd)bDpNbL?pzx@;bjOLQ}|Bi0OU+_+gc)6QvF6D=`)d=9?xkt!C4*;QjN+pS*Q(~ zp>-O4R2D=J@Y0n+#IEdwS_64fliRRA7bfzif-h*8O)!o|(ktJUHr1=b!>OS=yMDiLxZtjE2ee$M0?Vm!Y1wr?I8Q_bOa(6)|6&l9n%bXnHnF%TE3W+(rdh zTY=b2y&L zCd17~VFJIb2mhAsXyq}EFe5zy%V*&|R?gB{0=i2%?D2l>SgR^*xUluxTp}qur7P%H z?9%RVnSoddP8cBvJO{IP`5H4feTfts@_g?L$$G;A6p|(2AEM-?&4jTv4P4;+0Ib?u(cd{@bOj_E zUvU?{YhL#Hp6^1VaCZ#ng%b;$i?<-8wc1uVTEaSSf{$~zj}9`lKQY;ZXS?FG(oWF1 zxW#)HvjV=Se2<-R(IV^!CFq9w9a%ew2}qmN2@3HBB;)xG=rE-MfJimYBEc)4r)veY zsE?Ah>l(DD2QeSPpTch(aA?XSSEid|`vf~y%m13$>(Ur&=eL4l`eVI zRjRJaxC4c4cs~N9gT~Ee{1v+c^UomEx%{eI_caKS{{Jxu3F_M$i`&>6+t`~sm^&H& zrzSa5Sy~ZG8Ht-)7g`!IC>jotM}Q!--v>QkPly2A35{{|8$GZAk$id<4AX;y?Bhd> zk8!Kr;Z$^Fkyd*o4Fh@Qm<;OG8~!iIp?fzBG*B`1C8bTT>n{6g?(44KTW^okKc>GK z$wg?lL6MydB+y+$=7ZY{_cGN%B=gAGBD3pPjkeHm{W1YG0k%--#j+tg=?R9gG0=&y z8C8p^CEIU`h$bQ$FETxS$~#S@UREE`j>XfCpDAmVSzX5VmT#ssc`NSzbnz-%_YD{j z9e{eX^_HW=AWrxkA_g9F1OpMT( zi&SPbY#Ai5zqMR1+SN4BT98DSrcGxrw&E}zZ)TZ5?_}clQ<5>VM#L!5K*UPw7N2AX zzg424R6$-}gjCaExy-?HAK@ zR$;Iow?ty2Z`dAWLb=B*ZyUZ8PGXv?4u6UAud(ZQ!dA(rbi`902b#W{TvO^BmGeCe z3TX|~Eql4|GCdny6WM^U>!kI!Q=Nx}u18W*9m1YErL{Uf`7se||5OyB78Q_{>|^91 zHRam8hixpgZY8@N*??wT z9Ui_Y>^EEWo^%JXf0pt?Sq&YDq4Z!|%F0gB@P}%;INCd`o#MFhwqdmP;&{0UKG^wM z)wG9gVMV3Jyz|x7m(#rNH8C4&vpo|6=vl2>E7$p}dh;IA86LQkt1Wn3WG7+nsI#T8 zg;iCWDpT^c#l;-?^gQdJBL+gJMs-a1M&c>ROrXN(gHRx_66PGB>6T~BWkhjO!wzza z_Q)}D23rS+D>B59XQ#pM=JWRU#+|EFT;7I3qK05#)^iS3>XvrJjJ^A%P_Q=J1lmP# zhkdl}>Ko$79kw*KD}GvQT<-l4JK%TrKcx=3ez|qp=$P20r9) zGZ`@EB%w$vLT$xiW?xKAggQKZQ(Qz!7Be zrX#q*kx72z?4F2ii*27MGI0yv_o>dJ@^-s?a3*jPDmQR_AfN4LPP{LGa}mvxNVX5o zzh!!~cQ{fMD#!3Mno(+mucP z%g|lUG~p@;jWLN(0XFSdAm3PvWs+XEX^jFF{tT+?5@zfwr%bIQ6zg4Y;d^psL%C$0 zdUU3@`{u4t)681;*;9f$`f&pH6z)Q6Bx`G(AxgQc&|~*Y_fKPTcAagd`)W#z{}xjD z_YF))QS#BF;-Wu)P5XT-X7hu{6*s8J|;35v+&ERbW9{P4tb_P7|+P2PG0c#bDE4HqS$y|McK3BH)+QzcMS2 zy{6coH|+0@by>ZEX2L1$9PsCThHYbl1-YPDcj%&+41h&l-74UR>BsuPadZy!r3S^J zX$N!nk)~zuV;Lh|&`p^;@^-Z{j;bx_T+FqES)!bbm=0bj_k}X`$gB0^NQ;8*xxA$X z`Gw^J3;R^$5keBb)IC*vpEZ{U?vZh^nF*ch?P?8`44#l6sgBY~;UcBZD^%@-GBO+t z&MRclU}i;>*!_*zzRdl{k>vT!duf4XIz!v|m1ezU@u305@^lp**CQ{kfQ-GdB2#Fz zVgPn&Z|F?a^VkS0Np9bQ+lEJ0bT~z8lJw`}L@5UCPQQfxq57PbNJCJ=2d&*`j--=y zeCrBwBq0*hYDo@H3g3*y-M)WzDq^1HlRG%hk>SS9J21v7u@2%imc=WVUb&$zimi!a zvm37={}iGGF_?%Ic9&2gNAjkk-4y&8q$GyM2!XsdJLcO$--xBNycI@%-2)*yXKv8) zRC1o8(zPV`BT;5R^fD|y@war>N}^={R^KZ}lb)C;1~&(betlG=i@@MH2Udb|3kOBY zT&zHI7^?%9|0PG(APhDT6|_NcPaCHRqr<6dKHZmoeSkHDBdZmNIjK_gbYNy>s*P|ovG50w4K?XRk>p@o*U4Ai+X7|09?F(Y<4N&a^xV- z+&6cy-J8xQs(Cdu_s+XOt4G*vy|HvnF*POTp$QXZdk-Bu`6en#+haA^HdVr|IBL^l zcdsJKb47L(I$;_D>!rJlFQ@V86#QY+UkBE{nsN9Se7n~Dv$u&Wl2Txia#B>Y(A4q+ z7lq%^my0YvM6Lotb}@?UUGcRa_dX}XEIAalf=U=0xgPbh%Ex?M+>nj{X+4cTxck_L z?-Y{H4IW85Pe+Ih1(WWV=CHFpIuxg5oV<{SZa$VG0Rylz1s)**ck*ECIC|f&j?_F_ z4RMzpt!}EKm_O^1bFs)tf}l4(O_>bLKHx`Z#$_%5d3ykXouUfAc3oL7*8s&xW> zFE7;lG=W)2ze$mJ;Un7T9&aFX9n)MCy6vgndBkKGdQB}Cal6PdJ5!v=U?3Bv@8M_#fp9XgM_;Nr)>cZq}0Dh&gnob;*!7D2IBT=}v;C9Phl&Dl3y$7b8~{~Vh@N<760Jy>iI8*;fo3=c)mAtl1RY+K zZe2p+M`%kJJI$oMIsX7N)t$b0&$^w1K08bhGEFDpjyAwGeZzWL;pl6g#cGxg19+D#Eu`y(Ib;bHHb((qc)6(++@%_7m3brE0d>CH+#ccyI=Cc5N zZ@D)RNtO%cd5UrsY#9IV^rmL))#z#VzPq+%GN35rM^kAgj2W(Rnh;J-bFdW}52YDa zc*6m3pDS}%i@JJj@Mz{HIgIBV$jhnDRLV5&uk!Q6ogc%c^dYFc@(W?2(mlVKiXZo2 zhHf4=$8Cdlt(-PJ$#7@u$+O3QH6*XlJ8r2ZCCl1>0`l zz+dG2A^-)Sd{$#`xTfg1IwcuJ$B5N&n2IjW;1SjuU^jEYJ_wngnA>sNSUvGsguq9? zWI;ZX0Y5!cyJJ>F?thw&qXc~C>C+xK^Qnjp6}b}uE2xH;3!WGIj+gq)2>;t@rC-C9 z-vWP&_-l6Dn>tu-bJ&a|nEyeld^{QioKfAr2GFT>$hc<64}J(ys?65NfobIwoL3@1 z9#Jga97J6Om99J}4{Sfooa<6lt`=WB3+WC{P+L{;V8lrKR|PlQX!}p7ZG-{mhr-9s zW2Vz`)y$#Jc{)#f#%~Bs%dhcEvSvZ=g}<&l8>ERJ@kAlQIi*k4W0u<~ zpHYn7xQQph3YY-z`gz zjH$fh4_6pVQ3&60L>#VBV9NXP7o$hhD)6P`s}*AZTPyrKc=G?4TKJ!AUZOvr{(a&s zRN4NMTKGYuRVS_`PdKL$E@a6JZWcyBfCm9jH%1#S3}3ooWivAOC$$i7qG3L{>q*xP z*Yngr6F#Ms@wJHYUGjD5Gv{ez5`%09vg3mNc2A@8xdqF3^}DWMNJlQCkc` z_y_|jbLR!Z@`-kd_F{dmFghE{6fi@EFtQ>7HeLJlC0pKz>U=i8QZni(A@U2~pdWc= zy_a+*i5?|5(S0e3IMMwns!#EBC`=yZyQM+GL2~LXb5Ce)L)gyb)MI^QV-33r5>eXt z=IV1dQiaJv?A!_EE>(0LoOucfzrf|MOhb@HN7h_h$9n3ZHV}|y{d2GnSq$8-F#NL` ztxrwNstG8enxB*}wYc#Y51X_KyQ0Sy89-*c;-}e^L5P|3){0n1Y`JTBWqAsfH3@3{*H2lyXN63}zOS=sqZ7ytA%MYqU?~CGW zYDAe9pBv?rEyCZ=<4g6A;~;|I0Oen3ygIOM`En^u>m3OePg|A`D8(6fpkj6K2nHmF z;i|AIW3p? zbTi(P^LssLFzCI9!Sh*G6uvx-B(@P5va$Yrd$&u}7yC;8%vnWEd31V)H4mF9 z+bqwSXA|P}%+?XrLwx>ZTnUf!?GesAvqelkd1Q?bXb=#nRJulKm;-}DC(kbL{t@qd z-@1G6Mf?M1GLx6J>qq;>aCY}6sbgHVfAQMVYy!dZ3`YYmS(k5@Q%*#1$qX4Au3*46 zKjZWsT6Z{#7p%1h7C29+qz8oR3)AZ_PY+@G&BoW0KIEQdB$yzRF_GtV2HgB9_mXFk zzLc9;+qLeXt#AFzaS;c*3z9d@GcWcxL)+)lfeR$wJE-%PQT+5#=O>VHZ_=mAgzOS? zd@W*T-McfC0mm%xuK5bl&K>=`sv%Q@FxCRziuP6+c&kieN?2F>VHIe#Px5_Bvm3X0 zTk5#Jz}`Yklevl0`$*n?PF+4k-eELdAviR2J@#n3phc|%RJ3|owED5A&GN~RGZ}qo zuc25XPO5y`u-J}~Z2+(AXg8(%E%Kt7FeR1*aFeu7awgXK735?BsOYTzJGx|*YnY0? zJj|j;2BNHX7n7pwR&rICA=W!D{YZo?3clx`Lnl=4u)fKsMBT-=rEsJ;G&jh5`{ZGv$ z=HU5vE-(K-8!G=l&56H2=>MQds%WZy4VWKO;wB{Mpk-QRxx(=9_PrzpNMqF0a%PGG za()dB8l31RvALtb@ww%X*(YBqKCo>nkjl#zofU`vpFOC!@91Yd@%UP4$x)W6!Cy4U zL~JB z(2I=4FE-XQ{ER_dL08GuAA6Dd&8jrkCC)h8{9PpdS|i6 zQ`VVrQl{#<7zg2KxSBHK#ET0o*XpQA`{{5V^QoGq;4-Rh(x6O#CRrajQwrBN6`_th z%%zrNxVdUqtNT5}`1iR6&G=m|;Gjwc^N)WC2h(ZKAKS!P8F}8&xE4fC{2b3I>kvbR z>Y(D}Ssv5IV~g>}=`Gt73;pY7)oe7qOGuru%QGh2j)`y>%9`>uSzPB3t+~k0pHzMp zwn)QB4PMdFY4$>(kF~duzP(TijjH8nY@pb=4MMrvK!^#UVl*75w0}kF*oaprkB|aV zE>B22=9calg3>8@7%#x4!8gOa&rndZl>weXyhrh$#%Bj0p{#dZ6S>N z1kpH9z6kZVpDf?tfTC5sQfFG#)2+$g^vw~2ltXD#_f_ZmFhge>X!lcZ%-W)6o4;TQ zVqD=@;YZS<6@3V@E3QRPOrf01NV8%+du*7_&d%J#V+K8(hs)E+0!LCfj5{Prl^tF6 zKXIx*l-Zz}bn>{c3l}Cls&-d5S$*-})F=vfcpRZ4i@rl~egti4^FC5j;rP3V^S$w2 zx)X}BbZ;z=T&$N0eFq_|%_V4Hz)&Lx*Z-?uOQ4zR`b6ZMx06|>D z-gB0LCzk`VVAPP*{o8~SH&_-Tw$rmq$y+HNEWo zq+TK?m}0)2%fQ&&z?+0L1amx77yFT#q=Yx3;a~$J_0n}6pqqv1HCk&Sd}((;U1H?j zQFPOJ{@VktT>)s*`hK*AQOC7?sx=~S++AS|v`mBy60>X(A)65)m%;@=&z&I|!)2)O zA=6NqAs4!Y6fy@cd*3P?5g%A}m>kEIIyP;%N0t1N#q(wjun?~}#Mu#2j4TGBRu3Pt z83f@^3b}OqLD(b02g2i$LZ@cmt@AKX-ckQxk0SPhBobeZYxLh5*Wb5czJJ!Z{*%o8 zS77yDOYtB4@n3x_Gilm>UFZvK{FyQ0WV9?DAF~7?L9XN^Ath*T?$ywei(g~|Q~=#@ zm`wEpfw=A<_CRKQdjP-$Pevc~>J6v|>N^Y;o9#}IFHrxDN)qyF(pk~I%l*^k`m}rd z^<|a!+x7Z20Fu0{K47_cM1DpeXUkMN#1EUBBa$CWBDXYKh__x4;uUvO96xMskDMSd zUwjyOq;_GhexBm|;F0+9bR^hQgwF;?Gbck~!~&>Co?oM&fEL~~5nilVmhLb5Y@1RN z-T$d=jzpPOJ8r?6Fa$WMwE#8QO0|>W(Ng*g8sOHreh3%~pSpduLN(PmQZ3T^! zA)^Dhg@^2iQHy57n&QhKSkFgH*wVB#zbPFvhklKLNCj!iy;7;LUeEi*Tla#*O`KM7 zRh&uHZb0V-ghr{?Q61vLGI`Tlk=J46!LVYhtd$t%=7Ue_C+(#ixGPM3-=lSRtBZAz z&{%EeoHbSjkBGINnl@N5`#H~We(1y_+^%k&ywsv~l`b@7*k!jW_gGYU3q8S6RNnT~ zqguE$SyWhu9I5(asJcNNCV?&x5`pA40_?2AM-f41z#Lq81i{2s#V;%kj6@$r7{C;! z>7+@Y6%%^?riSzBwKVgLp_eBiH?FmB!+dR`1q9*~T) z$Hikq0MgUO)STtuuryRMal?nqKD)ULJaZ8G*Kef)kOKNgm;+sTI#BEujA(gJqyx8% zog&?OX>Re>mRyoXEeOSPgQMeHhEuJcc=9h8wcJpiyNIG%@6|No7V9oVzS(F$KH^Xn zze=NZgyd(0TRopUrNBWC>io|e~bAA>Oy}EOqI%?fmaxGPDgDG$|44v{kAL%|! ziLH&V6GlLsl-lFN`xF4hNY0KX8+am-6a2bYv-Qs@9^9XF=Qn=OnFD-^JtZ~)vNL{f zIZ-}q|E9rK7j1R@b~`hf8(eYiaiGD50hkiThD%%xamxN6SMCset4XCiBHc{a6m8g9 zVV>+*XN}yly!BIEt4#y})@(5I7fY6N<3qfkR}F9Qz~`SPWRIlkKgsw&8zQ>E9I6w7JQ z1~Og?>+B2>@(#$19i@E(wa#g95N6`?^33b~d+*-S8RWtK=+J9#a9@$pf+rNwj$L|i`cC+t9}S1zwt!9b;)0(%X&8m zwW`$)CWx=3e-xp!X}E53Yi}jy6b3_(y=uTc1InCU45s^ia3>`;dCb02$VsE=@Dc^> zLpP6&0FLF$d1a!toaubC$+``jJztK_wOrDqy;jA1b{6l4>`;-DeGvED8mmJR*ak%T zI6mQ4i7=$*$0V)-{k~$;fMCxZFa||UJ9qr@dCNw5*NH}!x*ww2C89BV*LP20THOaw zu4Senr2zh7vChP31;h|X?XeWs!x+%A;g+n-AvI>y{Piqo_!=u;7$Iit8ZG|KWg z2f;J`BOI;RB1zK2p6^S(OK5n+pcyC~Puk*C04blI0+ z&<)2wfm73q<_;;gPIBgV4^r`K0g6vdCOnfU0@as0#IulA-gM^$MIl*6b5(~iDi&*H zU{G!4`-!oW?S%U&IdlfSuvP7(bG)*kmh7;X9Xd#YX)fk(+M-x*ilRuE&R2Y!nK~-> zv0Lj@*Gf{21^e4Mw)%eq%1*@0ODBs)Xti@HU>Qm$-iN9#>8~{H|50s>)`>R}jo%V! zD=Ju+#3zvow&BN=&8Q?k(7mHC`kiuXC=UZXoUn!H_(p-;Z1O1GX!XnLCvu1Vno@{& z)LJ@nsDdr2`k_t!*!X&Sc+~{~7{^FeIy86g@;f6hvr;a!jAbAISuLaNqDspmeXx5j zRKtrGPK`sdGf#E^R||PYBvPQ-HIzi4DGfv6-t;Bp6g!5RhC_j-b12vuF3)&UKR@L@ zN`-|q3G-Zk)Ps2ZaX|1li1^JUcA1%AX&{S}c=5z{;;C>ik0}oQRooL~oMTEoVsBhQ zxJb3Y#e{ed1K^f<(T?e0A<(wSdy&FvIMrG*c&7C0>pFx z^H}l3%<7gtaRutRMCNQhF;sTj7q|;iKd)q2r3q4Oa74*A8KP|Gkq7`4XMmjo5OT?d zKzKyz6UuQm-l9K6maFrCt8^|B!AcZVsH znMa1nNiZzo#WopmW*JWauw=1B5i#Y;BaUi&dtsF zGMGU-8KCkzE5g`q^}lzTJp;IT_;3JH$=HW%i@vj292;mIu38oxxPgdhqvyj+=k^bW z*#3Y82OEt#)7_F@i&1f+_nVP5OF*Qp!uOGtvxk+88cdckScTPsNp|X=tanNt-$YMN zinH7SMZ6(Vya)REiSPebLQw9MsJ&ijBSa>?6*5tFeCv0;qHi%Shk#(;Bnlq7>R<{3 zyD?a-7Bo%aB9_pL0O2Pch}ygzyfUQTx15kSFVGAJv6ZC=-<-hSS#Xk$Sf}}01k@97 zpQ;4hxU4A@i5ZlBUr&nNJ{_gILXSYliAKkS;EECdAR7>OSJXn3%~=^~q1U84Lt%1$ zabaDdtWZv}G@DSnGZ@?gO?8szwnhpL}!+EfDSQXJtTC{YvpUV*;}vXmTdR(n6C zSVYS{{@VFnX%i?AzNlxo(Et6A^mmo^Kg>M-n@amXMrLKrKYm>wMVc#4?MT8x!b(C5 zO(EfGy_jSw6pplku@G>OkMpQmkjjc`k55gK!;)p`J`xcZA!+eXeu_RApF25KK3Ryb2`EOQzE%-ANMM`Oa8B?vaSe;+%!{ zJU$-aO5M&EL}?&B_r5Q>cN!YjP9e}+y(*Lv`*kx27zRrAdoZeV?AFj*6(OICFJ`%3 z;!;GSPIVOZzjHM&H{^{vJsIFZUUq!gD~aMMP3-~421;4517cN{I&BH`3tQ)q*^dY_ z#}?kuZ&`DTl#uQ_&4d^&4A*aP6e~M++EX;?h6t+d9x$88`XQxS z*1P6pidfkC>${?Tpn1?$rwPLQLsP+NWv+U1zo-JIXX$4FJD&pl*KnzEMW|+T0%Y*x z6iJY^(wxkvE}+E#zm#ep@6_#VsR0*2Ks;{_IhGJxKPt!+FV;PJ1tlSp#GrkFG7(O^ zdR<6NYAa~O+p5^xBR!TRpHeoLVk--6*p8qtCFD**A|jW%;gUrDH+7~FVft))C^uxy= zhhw5125gvB=vYOa;RP_S-Rwe#QnOy@p?@)CF5ATIK)&p9ivP_J;qUO8#y{Iq|2NC? z|0b3HzmPr~l{78?{25K`SEcLBEz_Gce#m1^7CL#V0!P9F%9m0D@Z*xK=dQM`YCDnU zeTsny^OIAAOn;EwPS_y)@a?LgnrNL!z2-cgSpD^}f3Nxtr3zWTrxg$?Lshad0J5dT zP;vN>;I8D{?BpvS2M7m3mchZz%SG?jXI)T#^~3DI9bSAHxyd1cXV2Hs5^gkRz3v>u z@XMI#cj-#^us>(tlOWCe4F|xMEtlw)k&D(f_MPblhU9Q#n*tF)X${jW)M`^VEgFh@ z6zNs8C=mSBt*>O(Vb%}(=4nCERYX%2n9LCU(*4n!!K#>f544G@bEFI;hiHn*#D?@2@6nce zEuK&p4{>?AJBZUziTa*bM&-F$AIsBnANhe$mq-$ZE(+P4-^kx}OXl+BbCLrr6#V(q zf~d5mQ@J3GE@LwB)h(K$deSs;b33E`QOvbNnso?*RUKZKlSax&cG-L(;4GOefQy)f zb7Ex#S$)05j4(zckG>o6;E&%xw{D>x;5LrrWAl5n8d46${vc~?rk~gN`Lj={=o(1| zu_}o1Hnm$`?LJhexe7$l@6Q0ufsV?^t{0`^t1))k69 z7%*p5N{&i_a3;cL&5-KD+uM9jjVOK(P2ni^CsXN*M781xIpq&pF;JF(^(G2L)CF(! zrX)amSe#%^eFW8&t3@RlOT6Zu?7nMW4aS%Y3gpJ59MLR+-+C{G5qOl%Q}@sjV=JS* zSNoA{6qx+x{_`yzEGTIttG6o4+sL*3*V!X>iTXRtzNUtl zdT3kfZb}_J=)k|a)^{kH`K&L(G5%NQ`Y)!*-@BH`KP!m89|iu>`2Fp=swDm6%jV1T zyv1&xqoIL3J1__V&o0MCP6q@&mpn!7wUk1Kl9*RNxC)e-c(&xvNn+<=+~_3d5m3^|- zYUx|O!f@@=0PO`q=fZiAJi0#R(PNjs2OPBi7STs~2dzb*UO<6nsdfO-Bu=AGELf@M z7&c2X$-e#$cu#o*%rk{o@foNm3*WQsUxu~|atf&Wl_n4pzOBn$$;PQY@EC!t$!Z%f zlX1sblQgP1fcdb@K(5}w|atF@PLJsW{}|p!9W3SfrR*Ti$JaT`AZsU zMge~(Rwy!tbr&@0gH)VN&c7}h`xY*T!L8BcR1cWQnL>Np6uOTAHaNZU`B20<7 zjD^zWYnf?DvC*FnAgK~+N!i;?g_3PE_LFj;($nlAAXv)vYrDoC ztU)b9fs>=12Y~E8{Mh7}R4-4v*NG3Pq!7 z1Ez78-)+!Q_1LkYkg!_%!)s%TO-5LTBA&SO+wnnF;s{sHtb26EVxbcdRCk?=`F48=$OY2 z=IQ&*O%*SY33u2K7aML^d8Ba-MvzBFmG(d-R#5LJz=ysvlJ;a~F`6shC@u}k@j2|v z5V9B%5xg3GfUD`6=Ub8`Ndz=>fpr({J&ax*Br#~%iVexU7&93rL*b?oanbIBbdco( zWdbHprTebPQ7|oHE}D?3x*rQ@Way%$LJc5!ea`|F-Zx4NsgjeD80cVR*rlTdUx_0| z%{k9f$`=f>Fk{b3s~9H`O&FGtik_m}$2c{@E;1KWTmb)Rkw1DOk{sdBMvyb#ww&mE zWTT+OEhULq8&Fg*Yos+mj81ER3qb=;26^Jp9a|&NDmI&PxR@xD@)>?h;rxk#T5TUu zbs+e9zT4aFJI=6mut%+xbkpQ>hdd`bBoAzaHEak-aj#fF%1ob2Y}DcJTxyQBGv>~K zGo15nrk6*mQGs`4+JhpMs<%RWpF)qUa8XW7lH@!sJzaHs4bT zxzVG!(ZE!DTj4rVv4@#7WuZNLMf9uIlFPXD~P+2|^yIi9=I??~fd)aT5*- zwi_^UiMM6H6Qk*;h~GtEc`!9|I;gSA)#dJHpDMcrWr?E78CznFrCE1-453Ze)X|Zb z!cWr-Jz`O+<7lXL!_wmnu>b;`2*fKn_n=gE^32fqO`?@&0It?hpa zJ4$E=)6_?*DUa068B*X8mFAu91HhT}5}n7cc-$N?0dSt_@|h#CtP7x4mFw=+ucYv3 zv;Z*1#9ErrnyMbqU?VS52`hybuD~v|g59vfU8;XCF~Ke|&NQL2MroF!(&w@ms>69_ z6XAtlL>m9*X?RdS9I?QE{*bkHtBr@5R7npJE{eo-U2+QpujaGR5>Uyb`5fy-FS$Tv zwIprHE%X2;p+-BVt~nYn3xIAHKQdibF z-s%c)lL>nuzEE>;uLGCsvsY!$Iu;uV)Y#y-Ld;wyb)pIbm?H`J)4xFvz9do&o zqDE+wOEo#_nEo~8JcrBM?E#{r5QE=MvXEyX}|j5Qs5 z4|OVxvt;AOV8&o1kwxkUk{p~1hHlYXhg-4g;je1hSM~bXb{$Bht*TU*|G=?b^Fv7h z{iaOGbKneN8_n7|gF12f7fG}BRpqKP<+&0|`*yspJ{`)Na_@|y6PI1Fe09hUPIb${ zDfMsVtE!tGd8cvnku<@VHp%k7_$aHUo#{{LjcsO#ldM72s0bFJ}nuaUa>H7PuNcs|fU z`&nK`#bRQWg3LSobFUkGp$WyeQGt(%rL5%7Re^7qeO(a&xRGJafiipT`~+BYM!?;e z=e~!=p)E9yfYw=jkfvBLgp#)3$H~80FK{9rH@R7|A$m^7>F&;jR)9OiCJMlJ5;14= zj~c!Hb!&hB){O1+>p{F(UPYKv7a+3!>6kv>**0q7k$p^piu0(&r78 z%SV*mrUjj2*qEj0g-EGI9ZEB3$r@>^i`^rzstT<+gbOc|&zr6HJy02=x{_y(CUTET z(^|623V-0xMv^9@3ozQ~&|MU(+jT2UfdBG2wn_^%)s9~u*U}h+B@x^TQ?9!7l7NED zirKIy_V3zZ6PQ}*&_Zd@uPXEbZJLQvj3TB9+^3IdN+Jln2vP2PCW>1n?HHS9afUb@ z-1uLVy>2oC@(fI}D=)n5Y!PEOXagC-3jZD-R?zQ`co+pwuSH`*I(| zjng(z%S{?L>1RlqN0ym4?VG?t*|Z{Q+E6XRIi#`{_iUOlR1t8%5my|b0k8|4uX80v zU;vz!ID^wa6YcyOsI6Ux4sw&#>G_3>#;K*K6miVbR~XesH2@9))?d?D?+iGZdFL`0 zn_~;}Mru$(;rUvqVTDLJCaIMxxhly(4~SA8G1O)bvIE!yzy3I=02pZ&tk3g*Y)Ns+ z(~ft>^2*^9?7^v++O;HJby8|=sS=$}@$Snpm4bbwvuO?5RM zN=#6^z;B6DwRZ%tgiFA?pm&|ZfS)$S;1{MxciP^O&WZA+<4D{5^dYE#<#~uI(@+&m zzDI5BYcUMu?NF2eIb&@2xah1+uA(W;T&dVCrD7LXFtIZ{iBaAuQCV9v) z;)x#9B~F>Huv>nd zEo*AoT>QxMBMi!?J~b3rZAPc@;=>AINzV!#t31_O!UCoHI80dXl|p0q2BvY;@Q?>h>T=c2^(%8K3{@;vv?3M*j-gpJC(FFWgRiDGk>`9}sA&!xuKUYiSk@7S8@P2lp^HmqWxD$yLB zWxF&Z+@$Pim35=D?jXZ38A0-uu4ZV@Qvw@)HYN`YXRL`AT8r`hdK2`eevf~Iav_}y z$I^T0y}2T}8&yHDY7~mO40C|kU3Kx-jh7Vi(e2fCvi!1QRsF^08+2X67(4nA)|xVO zb}^>pwYmE+3}%CRg`*z{8vM@B0g@#cFTdfZntWZe2yQcYIFPdXx_`^&yzltjNx7$w zVTzh(k-C~p>Zj(@RyDwt>rFt5H@Nj z5@Q{ern*n7szNGH9S0&``U)DLz!&pK%jfhem1O$sJ;8>t!865IMuU4gfYc1mE|*Zx zjcwrVNXRE)4l=2(%-@GPRCsTV(ys>g`t|)E1meHtWPfp}`_J9g|K)1+PXILO@9fyf zpM~V@Re!W_bQDBHPXWqY_dU}5K~fdmS<+Y5Em{3B*Os-d{UfH|xnaqrVb_NH0r2TB zrvdQ35C>_$fNf|<`O~MfIh>~LKAn!OJ3dZ6#J*`zi_HbyLKu#UIslLzQxgZ2A=D1< zEy;=8FLEm(=aL%nghKS%I<#>%R z^YmVtd$69qR|@_i!|vFiT}~s%B)JdxPGsY&B^piYWaHd40jrsBZ5uy-TCUNgTvs_( z|H!;zs7*?FIuz^A?kSk6HXFkPg+`yd%N<s{4zt(n4~>z`MMKdVfC%aq zryAP_F>tBin!A35>RM;cg{FoBn4)*krxmg;`407H1-C$Dz@wK`#JBAna+pszl8y}% z12^{`^|4wlv8kHRx~5?4MGAJdk_&ye6*VzIL?ykWOFX(Dw#?}L0F-}5Q|o+8<6UEM zJOGK=v0L&b5UsTlUNy@k*3;v`EV0M5r;#YSN}$7xB=tl?u1(gF)gQzU>53S9iOD0ip1Z^S-Xwpu`ndvHhI3zt+jO0bO*t3XJb51 z_5lMLqSY!49)eePMIg@&g2|fTu3Th2229-$-4&7O*YvWUP$TM%Q%*w^;aN6GP-95D z*vf%h&6m2&^3>Yo!%-vPu{4;fqM?w4>X?YDp@zQ*_4Ta>*aySufNl?i=fHUA^iNR+ z6qfVB&EMxn*QJH%qp!KK`ajsO|87u!QC$A7x$%G2bfio?{w*#q`X_{p)gf`2jwXni z+sL1r=*i~cT?{BD|RqGd8Rrl*@!Ih8G2NAxW-a&gz4dvLW9N7G^GCCjt?tVXvfP(m4=><_ znfGAC?Bhinf!3QBg3b2v0NU5P4up3Tt@oEecMnP+o?i0Y-z}pFylFyNy|-fQKyIe+ z(RNi4|0Iihcc8fK=0?ILZ?H8tSgAxqCKCuJS{t_nVvJM2HJ${ zU5s=Skz5>rmdPuk>epA}#!|uCk=C%IHZtN(%X?G~O1vdz{FH5b$4T~~{CKIdNe!h8 zj9N$eTR0l4J$PdSj^(YM?HN;Ml}#f2&5YV(#>YF5D5zMuTUW*}nV(5Hl-81>GsbjG zNeOzgB-m6!Za5R*#oD znKX_W?wc%8smV3~w(rExu3P;X4!In}b#i#n(2>QQUcy=e>pku%2>(LAt?0iw$Tr{RU^-Umka6< zG)`R;+NS<#O)yQG(`XmKZG|74L!Rl@o+V%~aAs?f>5vXM?F9>>>}wMwtR?)BkI@Rr z2HkpcSQh{;O(3l`b@}aate@3``1A>QNmlTbEdeL(b59^yB90I38oL(rX{{IwETo|= zSebLBcEwU0mMj5`H`Mhz-_Xpv`!;_}sce9#t6_{^!b@AEufZOqR<;Du&1Hy)}8Zx0#fB&NTrqZzs+i9u)P2)TI zo?#G62@cBJ6TYqYLa$c;4V(K$uU*|pj2lcRH0i#GS*c4sv&h>uh{1f!4%SOR>!EV2 z>*drjV=Jc4Q#E9SDv??%VHvs${Wu(W_ebmNVS=6a2W9KP}|l^m++l(me0 zO6W`{gZ(-gWsxLhF|*m5IIK(>e!Q^j{jU7gPg_lEUl}L2&ax9-e!TD8re9Xnve^{K zovT47rx{61W?`1Slf#vWSNDYvR^?_;_~J_(ir*8&sMAt?e44Qy6f#qv2|4et9M-uo z)hu^9-hwJ)zC8eGqG!LQQe=Tt3N%j{+22Wze7nZot( z)H#9l?2Lgwx5W_I!|ul84J4F%$Ovh~6jbCjq3Lpnym9f5umGhQwFqoh-(j1PMt(*Hrp^-)9PhW1$z1}=B+?U& z$n!*F2A$2?6$EWWRDDg0gSvEZ`LkrokT?&g+(Cg&g{)S>$>4hBWw66^5T(&6_5`wd{K&-K@P)* zkVvV$nA~H`KH(Cc{&zFxg1dh?#Je@sl3x-+@f&2D&L81hVA1;PE=JZ*+9O?&h&#bOf+6y5=n*_ zk@h@a#pAn5G*Aw*aEk0grO`PJnT(fKc8Ea+JMnUH;@)}aS9=*krM=8X zfZW2_)Ee9Jb4+v6V3nY4fJ4qINa=#$1#iehjI>rUr>X+Vff9M83pR{*%Dib|vKI&p$l7Nff)gw5q z!)kXw{ssdAtfEg@zP8{@(Em4d@!#T!zj({~w|L@jfBrw9e37cn-;B3>pGa+*&+gE2 zp+YM=i!G!Cp+o1B*~$i!lbcr+bNgA_WRzGt2-X(S5D^?i#YP;kc_ElMqxCWs_!a@? zfV8;lPx28b)(mt(6iPhDt2VD0pX`%No@d+7*S8oxAmLjL1h3hhz%2}Yr}Qa(1R-{0 zVmtPqh^PeuAoj^8*WmQUhTNg1+3ARFu-LOq7-1F2B_SX~W`|wwjyu##ezBhxhToo~rpqX0Vth*r^P60f~*kdaX%}4_a5oLai?P%c)HH#Rf(B zLP`xFVslX(H5e$;6fDJs3v}oxrH7FKQ$N*3@3k!)U$g>R>j7;Cq0;UA8P)`p_yiE? zn`oZ%!+F(mRij&qA#kx@g0uv0^V-8IMT^glg~1q}ER6+11G>UrDZFU>x&Z=sO%<}qkUOk^@?dAgh&Ik6hmGZI0JDi_Bcc7NSG`cwpw3N)Ffjir^GVIifqM@YXyt50S8d+5lJ;Y zWt_TfmBchM8ysaRq0HW)9j7NY5mV5@n^L zX|GsY zgU)OlN-Y%jf-6{iE3%H;|EHs)BElLPa}>v4@1Z~fM!$(Y;L#A{ZHvW?4{jG>*K<+| zJe*E8rYOY_CFKYRk^AQ#L`+}7-akz5-8sw+(lY`8RsU!pR8Ql@fc{z=psVgP@I}5wkB$c>yj-*mU6^k}ZM<50WXDD%`bt>YQhzsWEWt98TjJI)) z$!Rn93L;3$yKGS|5~$%ZZ~v}hwP+ZdY8K+8=08e10+JursJi#h}@ zfWg2hp?%8eaBkT!!KD7U`u>7HRrUkWRGX(1R=2}ypE`TM6rG|_H3?q{?l))@oib3@ ziz@CgBRoMpNOVl_YE<4!Dy@MsB@>MB%4OEi%C@E|HZipxn@-J%nJdE^R60#Klx;Z) zy>#NcDT^w420bsBJo{J=VRj6}SM7w4`LTBdfMLi^p+cI)RkE>zgE_UUcHHY$W;HnD zq7qf6#1}Z&eO&*2UlrK&36@;=H1MQ{T+TMI=h-I=EwbcWPxB3=2gA2+#C6>Vwz{5x zcalqOm|vQe2JhMN??4K-MyN(5BjgBfzr5TNhViR@74w~f=Y9S?El;V&1|a!GsZzlF zUkCSJjAi~0MB$&1^S_ocHe|mv1Ue;&vRp7~ZRGg*girp`0<!oR)5&4uUx0jr@$#>j5)Fd}8-3W{9H(`?a(tGvKVSZqrHVRZ z+$fkd7i|8skpc36u`_hMH6n~u+OQmQAygt2(NR_Oo6~-;kAuE0H8c{gxVrHTheiQC ziV23?;V+t`YkQiC3QgXW2`$k0;xemff(Ps!g#?iWhWSnEbBS)I2?X(9TC%EcFj29` zFcbF20MdXap`dw~ZFgTKGjkb?_mWZ3!)a_JF)W)}15EIRyeMqZNxWSt2^JG~o zRa0jbf63o~$cc{3WS)rq6d1qjPwzfy&GZp)Zq_ciN0~WXPHxX$D<*_+EW)MD z89qE$4# zlts0=KZe}HP96t_jX}BEY_rMYxiI=T=FjHIqu%qa+LaIp-H4pZNK59U5ZcBHs9YyrI2y;dGIgBR22MwSKNQIJb%$b?|&=Y|50g42^0SefVDA1B6d`v z1=hO68S>qvlB>P`hSHd=E%STQn9OD(d#vv|UVUcP&t%_5P;U+fv89#T3>@ zSQ>H0yY-QCeZ8>o@o};IkyfwC8BffmLJHUb2rO&_b>r zt76$(mLBQWYaQynqHm<(be%eAZW*T08|={Yj_IZ){y|S{D!uVw3dlb|wt}e>DWS$# zk0_=|ewUPJt>`qKlNOs}fS7=kJ+Nmyw#i@#z84wUn)gV;+7M*Rlnm-DZJ{=BFOH<@ zEZ;%S=tpfPxVk%M7V_?tj}2ZIs_SUiBEg`d$Mz&{L61Z(T#b!)UUF**TxUsIvB$F4815W09TsmR(tG1 zok8tnq8CITa)ZNM)g^C}V&S|l(qo?3Bl0$y@0^e-75kg5N`+y(o;bt3j^foeey?v@q8}K!JmM*Rvq1?`nXk-kFi*ozRJ(x3 znWV8I{&ji@HtBiT1mPJ0!n=Q^B+Z5N?{98A&d&IJF&lce(GDeNO z(P2KP4ia+j59@47JC+O@lU`fu=#0jARst6P5LJajE<=}1nR7klDr~)=a!ZPI#C8pknPS@_lNh6 z*W1;@!On9Jcm?J z^rr9i`t0=A?uK=`8t8pcdTtg+vz>Z`)MV^akNJqU94x_Q9(=2lx0G}?VcKIg%Hk2C zE2u@YajrpXP7{VgApKNff*S65$hLGhU$tpjC?DH@tYzqB(jh6Ys(;!_G!S`gai^X@ zn`X(gib4s5WMbtU+6?8<)>1=!6gIBk#!GkNLGkeYZhRs8P7%T=Vx<|wQ}o#Go{Rg$ z(T=I5(Klm16PIL-7?eQiV}(?NSZ>2`#DLP-1u(PXci}HHe zL874YY`(9OzTnxG7q?ZWaD$s9&W=0Kiz`d2OJq7%15Og>W~}tsbdi`4uYW)>p-2VDHCnY650p-^-7oHWKqSD;%0SFzMxbzoJ;g8 zi)UIwhJSUrmvN(x-t)EZ?+4PvA+VZ`y(o7*m*fwzW1kLP+5rJr_2|b)ohL0N?2_vg z*!=k#yf=rR!?dqZr1r6{rL3pLX7E*+BI(q``8iQEMl6AuIW6&s)BV5={^aoqLE(<+P{!H z%2$ozu5qm`a8ww?lMXb45+uWiVai}0F@GVs=M2LqjzY&-DG@KAj4_Kay2n=*)@S!G zpd=@9;veqsu-(hmeNEvCJB9|mbE;m zk(r9#3c3YwlKJwV2RiaF;BRW>|t& zC0m3<$Gam83}3$`4x8R|_LG*9$u1}v-doa2Il&)e@H{oyy7mx$2pez-D`f92?`JhNEO$iFgd&BZ|fhw&LDWyNxanG3D=^@0PG3#B@i9$KPhI2n zd<%5H*ei-rQ@`n}JuQe_!A<7wG{A@{q=#&Y-z(kbK0)W6teoEqlc4U%5vp_^-wOSI;oI!dP*f}Gj7To{fNh&*LNfV@EE4L;D z9{M?To|8(Ac*oxcZ1xAf$H|1g6VLCBBQ6eU@vvh9H@QN+&k_}Ad6RLV_VE%4VCgo+ zZkv-3Z*T%RseuM<70>*RQj$C(nBHLE2ZM}b@dpg!=^VcE3HhBM60;O9tt<|)fC`JI z(jd}w!v|D(*C2DaOR&V~4t)%audln(&RfhN;nNDG=SVSUnNh+|M|!rM6QLk{3>)n$ zeZzyBKgty}aWi16zh$g_b@i1+QcWmV4viiEYy?{qCzL({-PmH*>FE9M953eeAMe^P zO;q83EWZ8se8~9MUW$J!>Hg8Eid6n#A!>{NB0R2jPECRJ`)Yh2)9dvrluiX*E(#dISf-h;SOXs(dw7M?G-ZA z!KmmSGxS#Ji$Hp7kgA*{lDy(beMij<*}%9?PiCO&Pir91pU!Km{cno?cZk9BGQ~GLb2(hk%fBraaFW5pBuIRIV`Z@Amor;ro0y1nM^n z*jmg&^lLY_7R}|gIAZZbbIg}XgwmMmE;fbLw3t%o@K=G%bhfM8PFoo>`!QU9f^;6A zp0R?&Q6Z17$BY@A?Btw{zE~6}=M_3FvT#`$q=URhjJK4flAn$SA-X`Zodhd2RkE0A zwAL6$2sJn9-(E>78Es395n6Q)k@4GhhafT2AWhgok6Cq_N!f{(Ax#HgwsFgSV;QHa z5(@h%)@7n0m6}6}#B98drAgk^C~36%K*My<-I}C?rj0;~UcBV-JvnCD63@b^BjTqm zR3qPjxS(I?qy@;bD7rdTWv=aU6RICry(1G1ew$Q6gZJqf5kt5Al=Gzu4ghefALL zGKzPg6cn#%+^`9#o4s0}MkM8^zRd1}EmWtMRtRH}7jRdH00R5(A6MDsJ{6wDn`-=e zRL^JIWRT*HTFTY&4xaOL+J4oNTAs?J)MO?}liopNqxYy_M;V%%K0t84HszFIJZw~H z0Mn1-sy5?V8xH|oPZ7Pi@Vk~GSd<(a7Pn^H=tLo2}u&g`S?b$z1C(sDasORXaF8wvl}QChf4%cwRg@>-yJp^!>c^1qg~xv zkqeI8E0IY!7NUfU*k%@BNIZ8FDBXZHk0Uv*6X;OmAA5-$e~YP0_P}O7J%&~Iv4BzT zhimHGhWWw7>5?@Y3$ z@Ea#Dy*#h`6TOs})?Hpt(fE-W&VFzzt$pu>Q*#+H?et)b?KJfHp~`3mOtVL@_CNv8 z&Ic0#{_~UQX4Gw6!sRe^05PVrkH_^>?*q~7PPdsf#2S?;QIIIDZXGU;u&F}AB z1e~zKwwa&WJ^;RD#Clgc&gs6Zt={f)eZ1?~=qmjh{r&+=d}?0APk;?uDe$wJ(1)sm zpFs~Wna*!gPIK!b4J;nyU&3r6e!78o@PE5y*LU{~9e=e}=WWMVpz}2i52#k4Q1Tt*6$F8>+BihpZ`buu{X+9l@%9E6!Y{(Xty` z-l%^G$@CGc_7ZD;8r|2?xJ)v-E;91xsFP}bDmw6ax8vmP3yzte1IL@#M{e83 ze^nkZv%nyC`+<`)u@9}`y#}hcX9c@cmJ2p zyHIo|MT!OQoy8&vtP;5l+8OWN1g8+14$Jr=xm1C5RJ%o@(5a^-`FwfH;^5=4JomEn z&5Ce=r;`iu;(UG!Lg#U(Xj`XidAD^ju3Y6~`gcqhGGm#@;f#b5pC<$YCq-hE99&CD zY15|DsXh5a<*qgo?1*edCO>{92*6UExfC}_6xN%k?NAGPx7+kk1%##43wPGaA_6zG z5Dj#Qrc03u`~gYCqY3w>&3gW9yu1f7ijF+5(KcZhFYkJ01v8cInGWGx$a<7yN1xIe ztf#OZLioibjlp1}`n~_1yi%!eo~|yQm9_CzYqT&13-v}+Uh!SI2hHuVypK0yLmnGF z&h-fna&+*)0feN&ZCR(COQm1iOeR|Nc~e!?{ll?Fo(G~1BUXhOMW8y`W((NTOF#WY z_k%fWia(C&)mqgkw}%xsHbsh%qgjzcHc`U>OblJDCqUb|v^HF6Y=+Fl8duN&fO%r5 zV!oFg7A51*z?V{_h8Hm`v}Zn{+*a&G>8zV%P{Wuw38ihgEU83w&&&wAq~KUKNC->q z6kSHu@;saFtCRBxsa6CY;(b=L$(orB5*L)g)+VRn$Z%Nidi zGSss!o&GqyibUc68j8Db6}NrbO>812>Z(IoM!MDJxF#}GjeHxsX%8Sv*2>b6T>o8L<6TygyPqPm2^WGqz{E2 z?n=BRhXPi_jJ1trILpW*Scro}an1r}cx~f?;cbv-gUO?$^)})59L7E;ZbZncsn0D2 z6IwLw>1ZGaB`8~s3oq4GY#FlV$;?WT@q*yvqoPuCT6UUE*2$q&Aw# z^#0x}$gVu3`jSMivST9<6-n+E;P?v0%`Mu+O_Z3!T>q z6*vjaMT}1k#u-fC$%Np_c`#yWFRHi(&}34&GlI1}B`(VPiTY}R5b+ai0U;{x8R7C((4AF^;!fM(pn|d!9%r@946_(l2o_ z4fd=M1imxSlLJry!`3drVfX@F{UzwCbfS0#y5{px6*f(m#d0InDTSyDzfSNG8rp+R ztYH?1Uy$6Pv{+G9T5Zw?m@t)$r%1NHr$pG%rP`9eO;G=o=v1thN%-csYg$Mm-+p)7 zOOwRVPG2QF&ZMR#UhjgNj3sUV&dgxJT@#l`2ZH2Fc)}MLc!YZEbp*KHRy7tD3xNe z^1ybYD@%}<(q5YvkyvlWYX`Vy+KoybL@5f?fL*s)bqbAEjJ8Z+*Ay(DF@El zePB0csxL|0Ua+=BP^h`T;Oh%PVD@i6D z)r`0Vn4|h91&m2Q*VreWvy*zv5;A6(oIKBgX=0;sKyN z>`_IhwxVO3G0W+-Udw97vfu0}n&U56iSi9%Tl(j#*6xv_ScJu{kHo(WqoK|G-&Z1g zyrsG{ARp7^)1GoySW->kJud}T@?@%bCy_RXHGL9~nzNc-*@yQfmiyqkk7wwixfDXo z)|PY3wz@~_eF0i^6LXe0)6R|UQ*-C6VihT?{R1(}U0PYxotp)y*_IR1by)pK+r}a7 zgrKA`HR~fOI73^A6d+1ttlv5({MWudBmN#ad%XI6-lP7%Q$g)Y$ zjVFSa!zNn$Yg&51a1>$)NtPY4AI8!L3sbzsR7gX2NNcXLr?mdKSTBk0sY`BUdaV=_ z=pU{>$}UhgTF@<~t3!9s0u68DXFxYzgXW$FHlRf~1`Y_)CB+IpJdc`yM`^H{b^>9_ zSpQCqC1Vjl+O{(&2yN?cdNUuafJ4f3RJgKR0PDjkZ8|0q(1<9LI;DwD! z4F^|594mwCOhy-+0AElBJ*mr@SY28qJy}SdDY}*_)dr#9Hd(?=U5sm8vdp~&AjjG?W5i>T8%AHq@zV@0Y4J!#NnsLdN8%!;eRy11k^`I?koPLi^3-xvQ zt)M&*M$pUrTdCe_UbfV;wtX17vk|qRzXR9jX-;Llm7v-b_%HolYoi_%TXN~h__ZI2 ztVRE<*?_yX)LGhe#LAEPM#>r#WraJZ!}3iDz)hKKE&%SNVRAVma~tGE%#6^2)D0d> z3&2!Yy@k{V(tc4M?lQi|#ps5A`y9NL)(r)nR?*cL@rhE(1{>Ic{EgWh-JOAWNYYN- zyJyl%8hha{h$sIu~NYgD9LlIL;Z4R0(?H3Mo_KgiuhbE;HGHB|=Bc$iy&>ZKoi0zZXnTlV`V+*|%Dx_;E)~G?jOzPj^>);E8 zUkVH$=Wcnvf2QB~`4k-%OVt^Jh;x3YUHlnRq-@wWh^Uyn@O?f>q6B}eP%qY*I&VPH zQ(DqM$y6f|H$t(nnAmEi`?xxMGyc$*m`zD3-%RsV7h0!o7QTo$qPa$*LR>Ij**NYd zot3EYWqF?DirD`#J$6sI+KnKN5RL5JOOL6zkX@@Ri(Qo@^8JM5G**K`3_t^c|` z#a7tF8LhU2+W}`gc*QB5y4dqRYdbua`wsY*^IP%TEyf2b*C`P9gmu^8**(<*Tc;?z z!{S=L^(MnzE>{Pc_w9PuCmDN zA}G&n$}^E@89E1U&orZ1D&{oZqO%9gEa?t&)?de`4`^Z~EgXbhLTU@Rnj+WpGL0#= zdC#R$Pjg_NIafvSrwp%T*LMV6{CIO04-7T$fo8l%+hz|Of4cMNPPJYo%^#X>7T5?= zK1rZXwG_m6!VF(^6X)O!F+Q{+3-N}?*Xf35ffxdO(Hc&3QwMO{Wn)Xx1*uWO)rqd`wy`993OU)F(*G7*S5csv0ywIC&fu5Iqa& zCNtrv)2p%}`PsC!3AS}Ja0;9C30GE`z0N_Xsg}|)8&lqru<^~~&CZv9$SPrs(cu{& z(lH{d4I%D?89XDt0TYHEh(MA?FsiYaI`sE7y|Xf>aV2EMXL6CAWwEV>gROsH%y*-T zII*9ilM%{fPcjUuZ@XeM4!LhPL;cQQZ(3rQR$XaGo~$ZX*Lsv*r|f+Z2-A!2Wy?<5 z=N+~)dwWg*<=jU+6GeN$V!-FiY;3#8q^8E@w0?~1+1XiIKJRH0jwjD#8p{6^c3+|$P4>N18t5%;ct$8U*FkXR94lH!tv(I zd-0BblKLcHkf-(_Nm{-6ikYfZ^i(W?`|`Lna<0Zdx^tY;|*!RrdH8tplET z9g3Cbuze%+eoE9PLiSvw(kW_{gW?M-V+{8;FCa^#cgrE#78fM%S;S5?NPvPC{rsOm zCN5-xP%+XrzX zsFerQs^UaGS|VO4MBEl)_QExx)Rdd77OCpjaH8;)C#}{*+e=$f;|g@#jvBgrMZbN+ zf_>(Ou-o_bl^Ruk6+GdqNpWvtE{TYzeGkJ*WPnTx)S*o4+o@9|VZ@uJFQVINvpA0E z@7cd(a3ozospBaiHm#TDSZC@_mk^(Al|Hvq_dJLz%l>KIgo%1CEUh3X9H1Ehy;N4s z$3t5`ofd^ra@LL*jJqpVY>_!pweU-hbIW*Q!K-7b)+mFK3=5qnv~0m&V}i|S-TG~F zL#O1E=m(PtuoZE&^=Y^5!bYSTidkJ#Lx6@6NzrXcjF%z{nbf63jo18!pQ3{tB@Q{y zm4qC)`es*sH+MxM`tA$_gT;e2e*I(OUbJ;9PKY1ZWL-4K^Mk=I zoYNpt-v`c2VJtdMS0{)o=1~KC(giYxBiisDN_B`MPsYVUYxaN(V8yA8H|v6_70%Iz zbVWpa#bFB^*}ko1;vezt&3S;wAf&JO3CjPAK9c)u7}vj68~@F6|80r--w*$?G5ZGs zR;Bz;Yuy%`3DsPFRAt(5#p()wd^HhTMT*$azMpbJT(d(aDb_8*zTrK+Yz1^A;>^5n zr*^Z0=-1chX*Qs7n1l{&X&g?+Z{1%%lbxTR?hZ(*~?A!tmhYP3v~ zJqHjd#8RF(cV4U^Epm9!~i zc9qBuCojjK{Dcu0(qNXiCrM68#G=%sFW)T=XNasw?Je}z0>AO%GCAei7sd^(lCeDu zWTjPgpSBM@XH=0kP!thlRoGNzh${341P}hGzy@uA85k)`J^tv2yUN&Z?PRQTw>nb_ z!+lcRGjVrS<)*GpIlYu|lmC!9)He}^D@=v@p~Al4Uyn^}Bv2feN8+2Rk?)9Z3|qWV zzbiFKi{oSeV}eO&#z8S$)bogvfRB#HNI5N+dDa{R_tlSI>y34lsh+zukCnRXlIHyq z$B;Q1Rh~VJQ;p>30=p1qWO-Y6>5>eFs88wC8*nyvr`+=)u%myMThStLDLDx!W;n3i zZV4X7PLQ1g)@NEXH*iB1mple;UREUj097EEH%2HRo7IX?o(V6)GZEn>vf(9D`YJk1ea%Ds4=1DZJeLgeY|+eu2YC=LESwP!W+iU{ zm_1Kad|?W_VV6?AznfTBA5;f}e9?3P z{~<5=Z;+YuuNC0GK<0lt=>Ah%qN3xppo+lL{ux_Ejz{cZE+i$6Rfl$<~w9qYU%2Vu0GH<9>r4V2^J+7Rt=tS+FJ zkvMYr>2kB(At-}f68+? ziWQMN4*aDwr&CbMf+hGie!rpBa`=bE)ZmzcJ}=j+q&Kp zxXg|8nkD78-J)bPVF&v+-8wg;tP>8+vQG}iZmUh^r@^Y0IDcOQ@KYb6yp((Xp-#cL zR8z-PwO#+=RJmPkn@s9_>$uUO$};gzGYz=-2wcN7>!Vb^8DWi8!JzNCf$E?M+UQmd zIc1QXq6!`tPRoEHS%$}CHPXqbw5B~Pmm-x~9oyz)N3?_{_Aj*ATG$VYsncgL+%vXN zc;q_>5RTZHT3-i_DMO`U{6t632uO-C4itHLJNaR@TZ*pv8*Xnox;q|Ynnr|E4@Kft z7z(m3SSn>F)|}OHT-OaK0WWV@Tcz%%@|k%xKfTq6Y@4N&Zmy2BRcNWKbcJGio_*ma@>QN(Bn~hjzP`#n)4!$ ze1PA=WS|5a9>2Yoxd&Fg3Rhts69A?9QLwf@z=*>n0!TrL`?yfD{T7~S_0~f-E$~T- zvbmw+?t`TR3rEl+-b>a#_Sz$v(6c^%CUKvJ+JP0o4?))@rXAkF#q%IbEBVf!uk?spMQ(5uVLl3}!->y`_cbLWHKu6#KKSFGFoLL<*Hr@hH{d)) z+uTaQ^jP?XQ2JgXZD_>Bgb`S~jDdXyB~(xtqD zTWt}Sk_rx(+?v#X1mi(HV4^+(^dD)5R(u9-1}zWBMX=CG`kWB@8(Hp5D|APzo&yeoa0QXc{T;zS4 z^k7UF{VgB{lpv)C#NRI^fL8~CfDk+o8OSHzm#>ma^b0+6Vqi2-_zbAX!m`S_7R8D> zm!+}jV@3c@-m<%Cu3Gm=`P)0l`pw+(qKow-=k0HY8+tz3&C|#80pRLyeU8I)Yk$hu z$1$Ri5+Tn?{zYGkpmzQSzKI=gMg|0GI{WFE2my}vJ{&5ia8blJaz5oc!dFr0#+{k< z&fYws)GqAB;HRu*YinRe&<52Qeumn_BtkZglYT>FiBqI0dv(=zadrj>K!u@WNNbiz zzs3kGOxT7K|1FpX%GJ~1s6!}|8X$*A{sgG@=K0T?~vf6{o;kqy? zodP}KmltJ_AZX=0i%=W%Q~MH5wWU$Fi;z5 z0ks`Fe^{8hW92MgB@-FGHY)=gs)$xqC@reg?65J5OXCnhH3E(GV`D%a8axEeHq;V} zU=#supX2~e5T-UF@7y_@8>V(yST*eXw@s1%9r}3K*w}_+Ww_%BX&J?TWFPS6zg)W3 z(pEz$kgM6+dscR;Tuk)Nm z{e3WAZ`j2?FX>Ohc;C3=H!r~@zUrztU6 zh;P1En5~Uui>QPocBBp_|1zdb5HPd$Y_iy8DL8DP$14Fdci5+QD7Y6@aDhC|QwXR< zdK;*sc&6#Bs5|~UgyP_joP<+J5s){8S{<@--dRj3sKGok(}9K6F-XC96%N~#YL>`? z&py7Bra@n4^hXyzU&lLRKFa(XvvU5}D*H>35ysTxAT`ov;k~%Wyw6LqI>rs`h#C^ERjbPS#=J#k$nw?EXA*wY*x;XzdzvyvR~e*2VW+!g=M&4OZ~jc1BNkY7f*a|? zU*Brsz0NppIT$^bK?5~9f4x~Xe$~P>MYWZnlf`V!`;+P*LYILJx+yoRuIy z2R!suWNE10z=mu!BB*9(zg6uxBMAv1W9^P`Jvs~Du#iTEG#$2;7mFuL6NLIjrG6_QWvuy#{?kpf5yTD zutLP16A&pFjJ732fMDbSy#*ZQ%v;jVMwc3?0%_|sD2Kx;gx_(*Fo8H|yniWaAS6{tv#H%^;C3b&ru z3?Ys^P8+cQK*B;?P!>8>k()Nej3|wEUX3ZS(g()eRAoVCOHBJY!uL#NhB;q0pYcgsvfCW#RBOPKayD1O$Q|S$&PYR?zx^ z>2qQq>YZ>hHUH;KwwMzXG!#*MnOL1Qg; zwGe~ahcGj&xq3h?ahr?(z7hel$lSgZ@qIpZhI@Tty%Vf;2zBP2`Qpsu1$-JO{@F~w zKi}A{)+{2Uf|IJ~cj+I|Jj@K?#BV5Sm$3CDKO zd>w0d6JXcw3ai(gH+OgP^Hy25LyWfdg!R5IFwF0CXciktd3f0QTUVO}s{PV-QbvE;J*%D5vd2CiqQ8e!SmehHBHcSgc=6Ik7?V#(ZtR=*gJI94Oe0iT)7&?4i>Cn z7?@cWOeVPQX&&@9bq*hPWQ93U31i@fFm8vOz}z$+s>sL+-4z_Jb3{z2$L4NaQXPyz4q*p$=LG zNe0d@!z2SWti4G#u@xg@<$Z2tmxa63Q*&`V2+_9b}{<|<6U zWgcqWp7F+{7J{@H!nd}b__!a1HxqP~Zr~d$`B9&|J~1~b zpPeu`-{YMV@78u=LB^>K5pWc72tEBVo~U!satQ z1Tf#STTDZj5j*5%z)xAAMCnM+u$oNB3*F8SZ3j7IrE_?I@ z@C46pY%T@5Z?KZ^J#|>rh4(>gSMx_!*#jUMSajkFTjG-kR-zHO5Jc0}HPE?Ok(ur~ z%kMgrqE}@O7KGQuXJFDLbTA5$h6IHQXJ{r|G!H%Kwk*?hBVL@6U)Jfm|1xy{yu+lv z%b?p5eVcq)r{~p6>;83@af0G-+4HV4{v`a3A?SPlaa2$zx=ZX~lw8-{pSop!|E(p9 z!Qy{x$)D8~peSkd^^}{6MK4%>FA?J+lE)_aWS8M@|E2kMjPnUDuqA|B9FuGM;|b%3 zvtdbiSK`lSN}2dwTCYqiQt^kBtlul}b*4SZvDnrKpdjR+b7?@A;rM3=zWPkw*ol6@ zqPR&6+wcxmBk*_T2|`#bp=JY_-RvJlz|o5P6DCHu`>nbLWJ^zJXqg}&!OjD|kKcp* z?UI=FO65339gKO6Cm}HciHgCSxJzeHL=N z$76$stASyUSejD$kBcD0wEX%q~d+Ae!)M@J0g*w!@Eft;dplIh9Cc&w*q=L zyhll>9S@S#m=H$8`%TI{)T{5Sj}4j@TV}n1vh*g)C#D0)LCecudps>E&42xk>;bEo z$Ll-W0H5w1o4H81&mL_q{&syVJ795-k2RK#0oK%B zf5=Fl!0#q2yseraql|ud(oDV^HlbBFTn3b^11y6CEYjR2Bj@apI@%_@zdv!|Q5AGv z!HpiNj2;y=A_>ZWIw^~oL={h9NT*RV8LQ}zo#!zP8lW6vJYGR$7I9=0K7@hTtjgcs z&1h$8^iTmVhRMM7o%TwN-Jlw;wP4kvzdsrs>0r64SXpd0FK`v`_N*DDAM{#E&Ydfb)5=79@m=D5%7AUKKP;oU& zxSnH?Co!IdkO%;)D(L|Ry$2-J1Nu2!2e|4yStK}X@w>D@x;J2768j0&6)>E$S^Agi zSNdm~PWdbTdW0^7teAJK14K#&HaDA@pFfPj>Ij(-Gdw-pwBXhU%+m+u4zJCca!Jeb zWdhJ-=CSs1k7*EM?*}vVRMSEaKp|V|NAQ6XDa-Nv-S&~0*%)xoX>(QNB~?Quk11;9 z>NbDeYQR(Q@|*IxQzLz$ano!XR*?HviPSjGnEb}xuTZHTqz zcnE@%*t-UN4;@f#2x&T;J(--d;?FArN}sr zB+WD@HT%1@DnCLv_H@ufgE~F$97Tgxqf9Zd=LJJ?r^4855xHw}-z5Vbh9k+d^q4lT73O&V#rp%0%)4F*2xK%T7ww%XV=aZaH40KXcoAC6KvASFJ*GuIKs^oW!HZm8(s}6owPrU-EbH3;;xtn zWA=`QwNH7fe_u2f#>j{?py9Y)D+Ztl1P}zG=uSePaYoNn=Bx5^uV&>njj8j&geB>; z=H(d1VYj;>LM%6OCJGiqY&VNvkrp<9O$zVaKGl#!k<&N$Lq}&Bd#@NTnY48Xh4I&) z{VE5e)ZN#9^`QbL+UG4)lWMypeY<4t3$2SQsf)@>{lK(~73T9-HP9y|$#XTvcDINw zYfm)`ks0knc_*upAeVuk87ux;5ikV%YcPI{&0O=}NXmxqfpxBwEN4A{D9SzxY(Efh zK&s<6=Q5!|Ei)g)?iE@$kAgQJ11SUwo>Q%DF{3VC!wx01+Xz0eUuZkFClJeP8Sdig z_zh%5Gm7mD`dIZ;oB|wA`Friy#pi9aG7H_%wFW&SBCh%uvx6(Re-*s{jJypo;roq+ zSiL-O7DVCHe1|ccBRbJUA?nF$hQ=#Bji!V>l$kf#{QFmNb;FY8r2Zd~AqS%sdqHv= zGGT*GyowgMZjhqxJcJttK=76VUxxtmt_zCAQO3el3KImo`%JELSK%y)C@E1RajdVm zYT5gtm0UY=4O=@uxZXN~9)zsCwMvIvpisNqmRbJfo~i@ktYpC?mfORToZ zv%lgg6IJw|)6K)IMUQcN|PRKcXc?7>ZRr)fjpV z%ATCjJbbr6p(xXHj4C26C1Ye0 z&Ey*OTE>{CYz%0-JCJLP0P+$6(IqUbePBS_VAng_+hkiOhW4GB7jFgnH>WR};TOk{ z$Xp_cZD%+MCI2{ctc}40D_!}!N8r!SVPBqvdbD?Q(NeV`j4B&p^WOZo79C-V1nR#m zW6Dc&N=4Y`RR!o{Ac#9k3(>S_BAoM7Lq2hT0tWF+*wr`*Y8O)6uNW0d1$(Yc5fW>Q zPUtRnsxG*y6d9d;bKBJ@=PvV-PYJ4;rY>uFg(K*YuyHt#P+)kU28%M&IJli-H1_w| z`Z|aI?$}+2)fa4W=I-3`FrqMuqBHm3DvP0swPv1=A?v+K*i)+dJyg|{TO-M}nRm?z zMkIkTQ>>pb7=u=+zLrXc%^i#_BB>ZGRNv17h-FyGz}KpwW~f(O+8M+`5|OY~oW*Cg z!Se$3JVa@q1eh!rfIEkwfm!~8+IadUMExNGqB*TlQygE)R$oW6wS{ous= z%Gpt%os$e6vSAW<#A?KW=*qE&Kv{&HceFW?w|86Qe)tamo7*<*v%i%FQmtV~#<=WB zA57xxKkz#OBoa08LN(2s?7uBXk5UIF@^mE)kkY9~4Gg>k3`o5~D2A}z9R{b?>n`OE zE>&9vb?L5VwlHWRt8%giQZBj3HZ_ z0%oMnNT1FIoyZvmW~9ZOP}M<<+{R6XqN8T$C#7IIeGf6exnXQDiugjJp5#k{r5THX ztM!3$@L5uLL`^sT@{o5fChVr@mIj?LHZ`yNf?A~SIUqGhr#0?vl*SLK@-1G2ptdc^ zu-m;Nv#B@7&O?r0a-Ui2$yGJ!7y4tJA>P__YiI8D)zZLn+Q35Jqf8oSuTPG7Dbv%5 z(eM}}dB!^}Xc^02Jr&%FN%!QtWI0^)K$G}zG`Chczt;DImRo$XBN6%uX`2T~0~b4G z$tNddNd*LZEcgYu=bgZen-ivrBC762Jk^1p$!)RS7(T z`_j8f!rn~SJ}*S$>Jq^v_>#i_csrPJK1x_vET)t&jjsd>CtVH$cTNwQkl}8Vs9aylzmaXkx{V@aHP+t?Et$+}mPT*UT4)Ba zH*-s@md;Pp=sEz%lI}xHA`RXGT=0+&Qz(I1=%l4st@NTjmx$W5W3(Urn+Y7X8;Q4u z@46Hl8mVJ_Ho>gdjlfxVvA3(!nT;#5U?eou!Nyp&2%mb|P{X_QYE zi&XhLnM1AvVQlJCG1!;NE|G7{(^ z2ML#5*C~cEFm~rqe`Jw8K|KK2h2y4Uzwq7Wjc^|2^+M4n0#m~rA+RMYdCqMZSTdm;a4l zb}J}MFVDCsGZudVU~Gr;qLdc$C*kphHRh_<&P^f#d9GzVsylj{N^>yr{(8BA^o?re z`m=2T10v!PJIve|N&e6leS^i2DmP{XLju^R2i6>x#-4{tBT4CtK{KK7t6c9G&2rM` z~@ayL_8 z@~0l-F)j~xpbd~d2^CgFW?D(>NrYIo8}ESvV3KV|`*}m59Si69-L>TI(e(F)K@d9i z#_S&n?$;{E{bjU;Pl4JP{)G*j#NeSY7eK@P0vnz2j=mOCp-EEDT{@6_ar ze|CwO_|yj1zP`q0EpEQQ<35?r*m<@bST`N=|{ZO!m|Q)fT@Q+LhN>wlk-0YNewocGbctY&s7qMJ zBg)$vT5ydsafD|MLImB^S53i)DtT%bOPGk8I0)e65$<;3aG#{Q=tiRe^J+ z`~2>}EaVYK{X%fUuwfSgrx=8(S1X*|mx12|dCBFTtVMea*#?Ht=B_waa+)~wErTTi53AH8~-5L=Uqz(23S)#M?>Kw|_pQ2wNtkDT=4(B7a zpwvJ_T|ae6`NW_GXwl|$&=P!Y#NJ^)L3Xu<#W$(68Dop~Jf^vy+@{!{GA+LzrmMSu zj_4`&Q8J(v2e~Q_!RaK>%||R7I~uACVNE^Gj&($`+R8-Q8#w9=0q+N?#nzzl^ClCx zBHDz_3gageSBkX^z*U$xO+_hB{y9l@BWE4%nPL<&rLI4;omW2yu5ilm(fxWKQaR@c zP}(gwT-Ag+=`c=V>=;{wrY_J(g1E?S);B9Jh`0%#oYWYtqfF->oY7oR8b6F4vIS6e zk5=DAo*j#r_^FmW3Z_>($V4@t8y=@Oh6k?XEK6I@Rv|HY1ffFBLG4o~_3a{IO?nx( z^i}k=ARAXIf}-8VoO;kf!oF@fh_E`Drt9DG9vLOoZCf2T!pH>nP4B-vs$_Y*`UD9y z#KBr`&L%@-81>jrgv?h-X*ce3C@-r!TScjIz11AVZyxtgpzYV=mT4>!Ch}z%&7opq ziE6Uj9|FQ-0Su8`17dv`>3j=H8H3l#QR)0TOK=eVO>HFJ)wGex`w95H~FSH`qg17i12GLp1HklaA@;2566#`0{p^GJOr1 zLj01cfAqm(oxoF&za8I@BlVQ}JRtsTdjSvM6#66a#P%Q~1(HA}Vfd(ulaUD|$SKGT z1^PoDL+JGV?iT{3pG2~Vmd=Ks(&~Jo&d@KlV;TQDSYWfP=}?n5MGZ_Kc^=4Xd97hR zYkx?+Oa&qZqEVri*qgUKJ2!e}vN|t&x#v8}EKHKIiCpSR;ZmNS=|Wk)e{C_GGW1-a zohbSUfDLadO=_`Zv+SLMjNyiJD99AY-Ks}NgL$<@{l(3~wA2JnP;Shj#cGKv)Y(kj z-r-YqC1I8`pDGWfY{!}j__Z#dunYcr4~;LB(S~qvB(oee7|Fd zRg`4Nlp%sz1$66G^I&vJBf!f2_Inhk?q@PMYT$u-Sn|(~S+MMUC%=b#9km^mN=grd zs5$qPV^3U5M16N(dB6FjPsG``V;$V%R>+g5Z~LSBzam@H()a!Mgm{mRdlYU)dT=EA z8aSHy(E;?49##c7w09x|!Lh>`_ip1nHXYP9m~+(e>q4*eaoz%>pG z0Fn4f zqOyC&)3sLfwNxbHqCVECx3N?2kpIZeO>Kb^%HK*(&TqWr|IN<-Y6SalGF<-E2v*9* z(DJ|LY!swr`}mMDRUv?d@I%9&?QVT>s4xof(O~0KV{>unHd5OBg686z&>nQ%7;d&< zue+a7BW?U#>2$0z&O2D|Oy-u)hnLqme_*z&6Uj~W39SkY_M!AbE!GpsMZ|KbW{1;& zg`Ik*Bo+HiOLSFnxiMlt8QGG$(=ZM;U4b=I0u{Xhn~VHHW~gBy*w@G=4JfAUlVi}d zdE?(gLEM2Vym;QLy$Xu_LzyLZ;!Z{4Oo|X^Pg61_CbDc$SCW8%(geO8XptFO5Uexc zS_v<+_X3_am4FIObQfqfoC6Zwq2RtZSAEi-=L*NJCZ@T9pE;&Dj2Qi8BN$a33jQ$-E?(He@O)6!GCcu^Q}NyJrHo8T%RFE#5`P^)SZ;m!VTkiu zE4NQ>{ioi5YT~}x&5P&SP{sh6cxl-rtGA7ZwWhDs5OHOIfr5+<=)~q93t7nV>Y?)u zHaP#zKmT_j|26jr{hPVR+`&=S-pJVA*ytaFivK;IsA6vH^56N$QV~-b&D+^wH8xWq zolgVKvY~MwNE-4U!k!#j0+PQ-p=?>2?N>ww6(E`8p`u&B$2aGBW(o}3acEX{>bU@G z%cb7x&xbEee{084$Mjp*wA<9^=f`&%`bEYk64xhy8(cFo=>AzpH8)PQd_rn7GF)1g`zjMHDIy;-z;)}r0KBP zLd|bVU=sWW@NUH->E{|JK{cRdGg|~RmguqH;pV%5i~}gZXw=u^1<{$+IZBg@KGbM4 zjKnK7kT*9LtOJg+>5tDboPhI>4_eGeuFTpLD#SfT7tWl-DKh2NzRA8X zQcV$IdYjML2oOefln_h>I+d54)0;1fyEO)jSXrqmbcyCI>F(AgH9CI_uuNPfdnm5# z;-WNP(nUJAOH4JE9lw0ul|48tcKf!R&XsT41W*)M}$3rShm8}Ef2RzlhJ#sS= z4UAN)uUMk-chxYXtrwh;pt4aeNS15rxS&MWzMEfCUCKs zmgo4_BmhXQ9$`QINU#n+dFUKSPd{2_&%rx-Kd3q&_I=<#22%aYKzpfhEzy{PYf$I7 zxX9l;b&fHh`BJcrT{f4M3z|BNCg4jy2C8greCm1R9DgHNN>mr|-i=9ZQoF2CyT2$y8ri99=XE{Jb*F!!=p3Qy>zX5Y~H z{1^EOena}ZCo%JP`u2G$yrE1sjo{>Z<2^x0(D?jjX7vv2kzB^VXahA*6_Udi%Has~ zW)5l|%?7mWV0S>a5WV@#rrkMmSx%X2NYPE?m$lV7A@FG>ZZFNj=JwMzAP6)h(s6v|Jy+kP z`g`|&HS4t3_-rEvpqISIbq(s3$y9)p+31(2KWe&b5%>VJqZ7*EO(BoYr7eE2#r1mN z>M05R&jjPJaC%JgonVaqiNf=*`_jJ&U@+OimHv*7z@deCLeA59iVbT+dx2ey~7Ou|k znV_rJI0(E*#~<)mr6#n5(kest%yJ{3ws0{E+i)TuY+6C0zreO@F&ua6e{w~W?q`q| zxk;p#6uAw>5dNGP`swDT;x1bB#BQE_w|A%P%HtdCABS4#CU2q>AB;u|3P(lt;eQ_u zkzi_h9iH3aPrI}&`CP}O3qPd$uxIJraXL&N)I-A9NuI;#P!{Pwn<1r<<^;}|(O3tu zIJ+RmkrZ`A6_m!wddUczuKl9LH9N>$f%Hy@c-F>R%+RlGvKBd1NkfAnPF(Lvf}p~L zn(`T%cB#RtA6c;;QOdM`7EQX>iUaIob^`-E-L?P+Z?lCatKsz$$4^;5i6v!Q=xj(~ zLE@a6*3z*akgY`}^Jm;95y(zc(3mHw69V0ZqO3KM^JYMEbVG!;o&|D;&};c)%{ z&d9#e=w^$nUa9d8Cw`u?x>lBO@7UJ^!x)F!4+=R=L76rl`KWnstx}o@5@G~7>bTK{ z^TEJ4sD`T29x@0JC2mS$d)-@oAUxS9{cGwtEb79<2+LWxEpzl@uL|t248C39*BJJj zGbqyxuY9Z|fIrYJL4c0D*RuGodxbVwKOQ*83D1UP;QMXh5#cd0F$|JWPz73(tXef5 zMqI4-`&8mVY-AZIN}r%ex>Hae+K@qr@r&67m|xP>U{ONhfQ~~|4ukw^zsbcNhVBSP z^zH!U!Xg=J(#v%kaaxfqnFQYvN_7+%1i?9>BEjydcY(HA?~d-^&HA@0)g;FM$YHt$ z>AD@nH7^Sy7&jt6V62G*R_U1}@WmcpsYp%0L`+$gWR@!TlY4VSJ_S--#f%lG zZb~^N4UL~_@IuPktEuWG&sb5|$%SY@%HccrH~Ngtx-2d$z&cBf@qd{mBWH{Hr;Vl- z%qpcfQfTGjJgA_ZB5OjchUH8|{cVv{j9$&Civ0MZJr^fEiWDCPm(25Q_-Oy>@c8cc^+;X9+=2Nz~~9 z(j=houh96RE=9|c}8YZvA3nN&Wr1HGXIydwUQ09CN~v@b9^(3RF3pR#Kf(*4}Q?|qaZa*qbkfL zEsTERpdNk80ZBQC9YfbVNj4GjZql_H+Z^;GCXW$vr~{H;NIN zO!9m4;A_p5ZYpFA`R2D9=ZbH>Ra3^q*N~*72E}(A%R!9k<2g#`sLG&%ll%qcqM;u} z<#|Lz*f1%^GGfW>>^m1rhY0n+D>?){!Qelq6gPh8Jf*7a=yDsA%UciV`o5H7OP@EF z2@@-1UWwIi#_e8WN(Fvlgvn9L7pdgQI2r!TiBO(y2z!pq3gxE5K7s_b%1~s-1hF{E z5j3o|7vUJ5-4}-cU{TL=j^F4{Epkr5YO|KfT|eiOlvN`0@QzLD^tG^ug=}83%#AKs z4XCrOhJklX%#9%^#i3*u)4<+VX9k|CuxxExi>6;6E^AsYZ8B6^A3amS^Z{Md zVsQSuzPU+kb;u%P^iDV-(>(O$Vc5F%H&`-j$odq!{DNtb=H#w*yT#m1+}alwzNHBVYBFLX0xUk-T^{?LPlJ29|3LNEe>~7 z+!N&@tL-(?Fb~p@7`Z0)Q=pS7#!}W9<(3 z5f21O{ARqtc0M#o&&99*AdV9>f>=O(AGIV<{`WQTUqv%w|K2t5pNZq&ay2VsLq~HP zfQY`Kqm8}We_aI?|3|Kt(#Ypm9;$&T%-Rx~$d9;c$4mdh5qAS-F@2kDo(J@h%4n(uQ13>9-0C z?Qm~ojG0teC)_`rEE$Q4at65)P6#>z2MbP0<$E-^Tr-jNK3-V6Sq#p@z<%CCf-VcY z_OSeSTzqFg*bpU&Deb#T6uV}F3Al8*0p>!v!f@hI7sD>Iv?`JN;3*0t*ZiTeg=^DY zFrVg8COf|#3EnhC)BKEi28MJorgMd{gKDM9*5smQLzT^QvZ+ehK|S=E4jMScI4hP2 zH_7-k^ukwN6J=~4j=|e+#$U-tZy=WAXnm!CwJyV&I`n%7g4MeFnbAKa7A$mdz`-| z1L~J7yHhdcAJE8Qdf!yvP+d3bJ<@l|j!g+ha^ijX>K7f)x!GrWA=O?~?c?BSnZbKQ zo)zsq2Pk2H-^lSx2Fs|X@N3IoXvDg%f%9U1nuv@L_5E;*0CNlZ?H1E8Q{-WmIZOq2 zZlpxeC7F6Q+yDnIxB8ARfE~!I6b-k@BVg4INsN4jH_KRx9f{mF(*?=P$Io@mIrR>1 zcdKs1^Pa%&SJ4tl`IBe88lT8f!NiunG$b_JW(R0N_a8M4M*-0t)$e*n)A#-1|6SAg zHw|o+0oFD~<|gL)23G&~`jDjZpLGlrF_h#&xv|M6jq)bwJYr-@6@DscJ$@PufI_uo zUC-PkV8ewCmA#N*t4_9czXlGrGu=SbIx9oeYE%;o^TdGg3To`9!gMv$k41@It1a5 zrrXYvH13+*q|+AQxTf%_CiKTsBX(ReglHVK{4c3r>>|(#tn`VHDr;l&1QwR;mJuZ> zl(woy7R3*R1+~FcZCg3VRY@&r@t?7wFtqLuMl4b3Co7zH7}T<)eaaGXEgt-t4OsD_ z=!nZ?ry{<>OI|%3*l^(rsP_mQ6Cj?USam2?D zI|bB7D=xE_Ut8p}t0AO(RVur_Y(Fk{m%`P|y?UCMkO%H7xM<3y&^v~_6tf%HN`LUKI1CB7;;KVe?jpN z(OHXLL%7gSOGJXI#xVAaV(t8izA~$`frXCwg*2EXL*P%2nm0c$0MzN*j-ZD1H#W@uCsr|ky){xZ zVt&K;m|{~oZ~lf%!=xtk20YANGiWvqdf#QQXtHUAmflTFw0l7YzBDk^Jw>MKbNokB zUmT|c%)D5Z*V0Opjr$AIQf;5W&YiUfkikO{U0~ z=nSGTbML2AF&Si{X-@G-7u*xdzkFueh-u!@&w`Gji;M$4{p8^DUfuaY536kig&u4d z;6QCMODHvy66^e^&gwV136~joY}#DiQB0!fiF*K?QwpkGUX=@BNby$u%#N;xB#IaQ}nA8;gls0w{O@$PRDR$i48dh z=UqGL-NRhDw@<23UY-f!G!G8aUjeFF(CQkG1?Z4Y{g6mIWfV&t{z8o^R*Le#Vrl^o zU2@j9VGlqNLgRc7?-vH`awtGu#w7|Y3g8U;@4l72s=tVB7K68IftR7P%tMPoOWFxP zASNxo5`Xn~#*QbutaTJ}gda}lXWtI;>zPn`m48`FXsy_4O&HGh#z)|iaXgR8y#<4# zJ1fdZJ_4R_C;1s~x)x4pPe>M)pUi;EY$VYdYEGBIpjwk>zJ+rvb2VmP>h55N+m>5<+l9|l0|EnP-7 z`r5n;R)=i3iHV+=OJv9NxZ)7eiXA{uoK%akQrf5uY0l=xsSST#{zu0LsNE;4;JZ<< z{7(erf9?42{(Eo6zjl27w_$UqiuSja*msYhepNcTs-dx}SOwUc9v2$Cwt+YgnJnLr zskB!BvXpeaXtiz?Izt-to%HiZNQTZaRB`0gF;vzL&{y>GsRxUshJeimB{=tn-tNkF!T#NGuO5aPFi&6hymi zTq`P-5#Xx1>pFw^HTpPg){2{{^zhL^s2WN5H0)TQe-2X?TPtx+w(b1YbBbUpKo&J! z!f=qL0hI{jl)chn#94%r^;K!I?$@qWYqyT=Lh6e+!9fuwX`H+|i4tQ_MuA(T4ruKX z(ixJPwoN;VH6TbUx2nfZK65Qjq6Bqkh&hSApr0q<9ZKk=M5%AKUp`yE_atxR*OT$e z5Pe(|g&1W{pMv40-6+x3c!MK4#-=VIGiR`pCh z8b<$lx5M|ll(}T@bO<@YrDvrlYMv_vV~D;tCILg_rr5tc`02VU7?F)!k6lYK@r{_* zS!}l&iAifXGMM(dD7gB%F_?K{!4~oif`w`0a4Wv0V27qoscVK?Jj!v#9QDk4+PLlL z3{}ASx3pI(0T|i43**@Ocv!A&X{6M0l(UCBy)3po%yMwGtn$kbSDqZzYv>0qYZ#1t zm6j|=PN|GrR7ue6%me(-oGZ|I8XNTNoU_^#$YG2(`}cu1kQHnsPNLT$0mpyyXubukYY=7zr?@2b~CVgIVOn(n&D2{{uD zfj-mqsQK>uV7@}%aty;i=Dss+j~wF1=6!3TOn_pG@R03bVowNI(8T*eQ;)SFez3Vf z;J(lky~+8^Vh0^_cmtCE9g~*uWya4)Z*L& zb0AZ14Z{>nQ?6mm8H7wnd1Mn^f~D>e=axhN_Uw26?qb z9AIi?>}Uh{N9$4Xe?9z5x>251#1cmObaz=n4-N{1#urc$;a|}$i8CV^CS*bx^s<$H*RY{y;Rt+|($sZF+`5@s^L&%O+2&rfSo7u;xJzuZJ~HmDEcCQUne zyKXcIpkq38JOgs6&s?g7?`PPM5ANO1vr~kGnrq2Af)X`>ikMD@9N%ayrp;(bNUe2f zYt7{hR(s2cZ#PLqTkE4!q;YXvc1GJ(Odia#Q>0B|Gnd9mmXqaH3+G9fl3$2FAkL*u zOK&ZzK0{Y*R$+7)Zw8BUOeYgm#p(jA7~5AN{h~j-_V1kHMha(b8rwAQ;-?^@IyOm@ zNmRglB!Tr`eps&2VHR89c61d-61BUiJd=}aY^Z22EHk;NOV~>Y9syXgea;JTM)PEb z6@bPJ&Qb=8&Q9jK@fk1EG1fabWol;7x%s(U?m9=K3R{R9FD(gm#gj+DWI|8YFu6oo z2B#=1z>idqxl%{tL($#Ge(FqpE(Pb=@CLe7DAAx;4G z4)_o6O(Y4iCM21AyRV)Lb&@lSvhNtx_k=ZWlRw#}de1hoRs_4;_Lp|hUO((Hdl^_k z9({W6<1gn0gq{$H?I5d}YKGVE^|w{P34k!b&l~Px0mx=+y$|p#=eY(<$Sc5hno?1) zLrOdebjl3YNdBNvK0%rl5$lvrib2mg2_^?Cq!%XS<3UwJE%Q|kx=rT%P`C+gWJ3S22ZYD&7N4N2Nd0z zl&kzof{0(-5gc)@_C0Fx9Ut73LqcuWO)-HRuCr zQ~ZTN^LM1J^3Q7De_BcH3eXyE1?wZnAgLK~K#pgU#20v$V&A|$e3gHQQJVsQyBUO2$F*BFszwDx zcF_l!EL1sfKL?jb%LH6$xJdlZBy$hWRXQY}gjI#^&}iZq`jpB7`)#@E_K8EmB?(e} zT6xLqti+{IEk3)cQB7;*MH+4Q_o;eiJnchU@puS1c0*M(@^B#L9{`bGXPA?uJm@;) zzo)y&ckC)ge~gKf?kp(8P3gY{t4n{^-Zf}@2v)!`q90VKXCktn+)wj}dY4&M75!$K z{EmDq-k8t|-pcnI`s8wac?QwWvxJxQjoQ-K-3Ek)4uxs(T^(UKX)9xc77V7sraH^h z^fx}y*^E16j_h{Beq0@fIwVAfOV)uTm4|b|hb34CC7Z@b89bUPL9B`zDhYV-3ScoHLw1f+R>&^)3GcbpPQ;^FNcUzXyr% z|67p!+kS-fkEef;bpC53t2iRt$B2ZRk|-eVfkv6gjsl4vpxunFLI{?x=nopoEXzo0 zgP*jcdQ-{ap~M7HBJv;9tbpID46 zx6s}&Ls7xF`&fq(zbhNSA+HkOwq5p4^ZPuSI2Y0j#3x*`a(xr;EQrU~!FCNIN(F+( z3lVP6<4QOsi^y)f7_UWe-HE+WvL@S|$9wb3X(`x`PU7hv_;$~qn~tu=yyZI z`kGGq#<+qFzzyp`Y7m^XaooDhd2qhW63LbGC#!e;(`xJXzz!27aGiosTpK2}ZkD~F z4%ty-9_%s0Xm=KBLtQsi&2GbD>pbC~xkrkF&5;h_B7&S1NC`4JRz2l>*%}TW#`w1|`8mcP(9JTZe@R#9y+Xfzeh>CM8$%(k2tMQh z{qUW6Uj5DUd)4V||Gvw&4D_d=QV%@%3^j48!c+(V{Jb>OK(%MgRWtLrn+HRgvYD)6 z1!i64A{z$Y13jX-+z|S_{NWS9N8g16jy|HUQ2lGNV>@vzzQF(>lEJ{y*)*2Bha2MM z)TmH-McsFSEdJprl;Z_F_k;^WVb`hU>@)xJ-tBH~Y}ILE2F;Sj#bRcj;UpDw@=FV$ zON$1xrHR%Y;CWSLu~-hISObfgqP_=zV3hLyezEZ=h$?opBxxXR2x|P9LXJ6GW;($`ANYV2w+JhNzE$?F)Ak@w4f$8cj)J9*+hjuAft7w{kY@vF8-(-f* ziI|#{52D)DR+FFZu5s}GRc2IIH}L%&P%LM;kCPHeDSi8C(4M^F3;+>t&_JV^d#(2b zfY6E?3njg|*^(@LTioqzpQJ>7ekJC!mvrT~WzNDJwTQPqPhHpCP)Jqc^5X(JVR&n=J8v zO5p?GnGYe2$G@VC?IS0Z^B!(=cZ$$<)P?-i^u(OP(~Qzj%`Slg)h?9#Nw(|-AYqxo zZoBxR8^>Xp=I4-Zij2Ku;e%co=5ZGdEM-Z2?hmJCGC)rGgX-4r1 ztvn@uvr3?&f1PMxBukfuj@-#KmLzr&EM9rQrltBXWh8)UD`QD{r(PwfL z7a1A;%H}BUWn$9dVVdbMNt{ab7}8+OD~zV17M&y$fe@8ID9sx!Y3 z;wv4DM_S22ls*#|Z#?qT7ZO1|)50Kl_I&sWI)FWhOR_+zsc`UH@CR_u)Gu^Z;)c-+ltuzMm(ZxqpjzC#veH#t}+ z#mg*Ni@Yc4qVYU{@=zYUBU3ODAC*CT;l4IqA899(J4cN9WKE0n(~um73=}ZB&y+I6 zBV;>~R8_@nt(xwCwAen8RaKqUeGdwlKJ@6FvQ2z$w=!9 zSx1xl#7n01jbdu}4$I&{J>^KQG&A^eOC&fN-v@$$gc2217mCAl>;If4)-;=|}#`LhB&8?hiMhEF$=56>F@ zA6s2@ZDbceZopAwZl?P6^1~1?3;Di&Ku2}Hv1*>c=)0Mv`DV4P(R@XE#Z2`YVt#}CLV#F3!QQ6G)(BQ;4>ahLF*JpESD{F%gL;c5N+y}XKQpn6LE~Wc^@Zy zLh7_VbO&}Z)4=3AqD@?FnZ4E0@6OZ>7GW9FLB<(MS*`+{)p@*?^;GMF#cTcqrpWFI6}Uz0DO52f0Ex1M zN4XN(zA6+U(RRftFpbSegpvS?p8YLayn8xpO|(AMD`uWuUa!!QJG5&AuUkq1LB3Po zS#K)eTd3{IM=x=Ws8O9dT#(8oN|GRbW%jPwAtvO z@EbwpYfn*(0rB@&@ITV2mt&)9;Uksk|5s&1nSWL`|2v)j-8lZGi~O^e{ugRYe3zXS z_^_~C;jWUW-gNLIgn}~s@lyJW;Sxy%tz)-a7+&<%>PM3!S;yV=lBiM4eOv!zAD( zq$O^hxlQ$lw-mYQcfxUhI?E352w5&&W|{{Z3{yVzG!B%n(!-A2(V%a@TDa;Mh(&9w zxzB0R0TsGW5AYF3^6PubTTU>99LE@-f#U%?VPl#_lmTMx2l3=O7dB_Mm)&uWI%$!= zWX0zZ`<;-XCNQ*CE1{=edeH}u)hkF^ZOK~!&5%9?Bx|AYt7k-HmZ^jW!>IOi57IG8n zDm)I_UAhf1^Jl3q;JvZ(r<=!1+jj+;+hiiOR)aXI4vv{TYacSsoH^iQlUL+ z4ktVOCL@M0LS1#N-UE-vUh{oBIhu7<)gff->>D+XP*s{{6oGpQ0*2F=KIKy0b$Wan zW32~DWc$gDYKbl-P?uz-+3&EcVV2JX-!?o&Vbn{KhXLaYWbBU18HcXk5?WFGNjn6* zX!QU&b2PFiJ{MsZSO>-|wmyf{mT$ ziD6wLhyqtGEwizB_=1)(Y470Li2i3GZAn{7P$tO@_U{Fx`qc>Ts00Y9?*Y50*Cd** zaZg|_eXAnJ`#1Q@SnK&-;i}ku_{-=#zW2vNv%C1t;9@<~DEV*&N`Ri&FX0v@vW_E&;qiolm7yrGSxtwgy z?{O0>S4g5YM7OimmWlI6-XHg8DSAFv06#RonCS~g@bpU<#Er6k^7dbS1Cq+u73pSl z4^_Z(k&9PK>I+ccZTCZzu=#*aQ$}Y>Q^gpyb{8is1=dw=qI@hPl z2%UR5Dszi}H}e&jOt-Seb1}NFV*RpHlII)rLJw-nNKV`M>ZP?3O-*@RA7ataI#eI| z8a$f2g*yc~0};3=RH#AmdP9#na#cWHv$kl&O+v+6ju?eqM#P;!#C0QGB9SzF9hoij zNJsoiS6Ngcsg|l(>%#ZoGiYJZvWU+~w1HMnrylzMHo2M!?uyTG=^$l zg-(|4g@u#Jpq|#T)^8b1Jvzq<8?#0G$Sn=@RukVuP%=Z@9i!p|r#gWGaze9Yrn7PC zx@acTWpH)`h46{tfNTr~rbl8Qx#(KDDyz%F?(#tnvWSV1tQUi>taBRUy2b={VB26w zWW|ldqJ9Og+1RFoVBK{AM4ONDL{w`fQGC<$6#}}GLuYGw5b|jq?09U=&@M*JqTc9tlvah6I?!bF(E5_sYW)V}@Rl?SDf4BkJG~!K^SguiHx)eU<>gx{cPwVP?&v z^mA_~P}G~m=$#d)kc!P0zC}*XB0YG)6irzQPq~BzLnvs(gFBD_)97-PZ1Q_2(a&Lo z1HHssGE6z#%w;C*M?`}8>gYgB+Rk8gIS;#yKAaF?$PcK(Mj~78%c$9V(~9FJ#~C7y z*ga{&5pQzaY>JrBbp2#5!*J_(2wtETHeZ+l%r~X#Yb&;WRuM?lKA-RU_wVpKBUf1C zwHa~_w2FGD@;&Lnq}2gMox3&SHAN+DxFIxkmZ}d%?*2}dog6-H=+Su0xNOgLShhO| zCQdX2j=1-1x-B?;5gc-24h}2%JElFs{O{{Ju07bvURoIL;R;`26pLlnV$Y%X0r#m@ zbXQqzT;&-f+j~3TEmf6@0@ypwRQb!(p1ceWsk6veJ1HFp%nUD>^gi5h%aB#vZ;Nt0 z&X_0Mpscg+d*vMokkxYLZGD4ot>>$oqqVrDRx&aOR{AS{cvv^2}J6pvm%9gFJ;!P75#j z1VKF&fUnN*e12;;7*1{luwDnl;xST%pX0Y*=RnG`Vo`=OpvJoAkdQ9WqCmm!S$g-lH2;? zY{bx0m!91+8^p`1nTs7EnlWoEF*eLOdlOHh!wOlL-t^P8u`_TE$u;O|@5}dMc_w+( zEa5#H%?PUIU~2p`C40!Zj<7;83Jpm!G8XI!lq@^cEGOaLBBT!ZT9+tPotsV`A!3!F zkPe}gWC|gD!tpw?LnWkXD24u4{bKSzyuy18FIn|86TK{^2qF?^ZjQ)Q*8yw&%W zBZIv-%LIo3aP0gH3AC^w=~`TUJ!COi;T_G(jQB;1>&RooOnI;_k+ILEc|`ubVakg4~J3k zD=z=~#BZ@L!yDAalNkd1w-e+qK$hTHY8=^601-pw;#af9+4#<0e1zulUUW%Y2V#3`eN2oh%km%-p5QXnq5W>es;i-h|sr2b7iF2~#d4Y=I6Hxd^ z(d3WL!2RsIV_qe9KTGRV8^9Ii`~w5NB?7dV$OPi27`f{i4w6Ev zj_RyixTi$dEAZkjUI*|!lZEB;{5_k*kgA4_uTpl7PqKor!_#by{57)mOjFh$65t1> z5e(2JiI3w64Z>OUw3KQqd1c4;Ij#5+v+$)#?1o9L&@xA+)(TBfpeXc26H2enNd|Ir zQ{el!4XjD&y4s2Sm?N<3(C+e$MGaq$&=N{rW-aPWuq=hvYkQHfMV%#!{PbegNwx+#6m8-C9V=}$aUQZ76uPMpg}n==d4v1|j}bnAy3u`H^soPgV*dBeU-O@} zD*v~EHtGNE&%aIr8WR3RI{)CB*}AQmAXCZ1%zMQ(Qbu$>_z@{oNF=}@3VhJcSCErW z=-RXbas*I)E(**I1rvpR?t}mn)+yoB=7!GfY0OUJX&Wu0qYHKf{GS;e)Iy@m!O`q( z;1(Q&gjD+I@Hl5#W?jt9&DE#vGrs!hd%3m`GHO{7TnO3T8LcpB)j)Zigp}VR1lFG2 ze<&=h-1UoYoQB(HxZzEst#l4#At2hc$RajEZh^vN0U@6COf4-?o%4xx*4bfuI?CjZ%Usi_2h5| zj4S6LT|>OQ_D%2oh!a>TNE3{m2+hU?vafQ}ONZs)gO3RmAD7at(>nL=g`{|DOvLs@ z_nK)rAqMraQU@b}+z^tfbJe4ati(WwguL5{)_z70S&BLh1NE0FARfaJq(8x6eiPtl zv_j&392p2_+!;FX^xeS`F6PaTmv`Z(_hQs`tX5w~Oz>Vw?Diw78PjNy{?{`#kQ^kG2n!@)UK~HLSApHTX6BuAQ%szUai^SAFDTkPmcHqEC!B z*6<5-{hHA(Kca0_unWX`i&5pX}YeQ=x(FsZ{BS+GgW3YGpA0;N&0>7Q2p^n)0Ig;l*m`k4B* zR0ElO=&0?6V<^>rW9pv#Oa#Z6kscd2VM=L+Qmytz_mN{I=M_a*>_?=)0a4`};W#WP z;WnU_cb_9B4IlVi*R9eIBH`peV*LRBM|I#iat(O;BlrI@7ySGDm*t;T2MJ>nTW1UB z|IxweNY+wX5&htpUda$fY{mv5_>&jr^)G^jBo<>*rf@ZLY)u2f;&0+%w0ekZg-z0c zcc?cJEItQ9Pl_d{(hNUdMNfrF-jj?CaDN7UnYkQ2TUx8@a=Oc`qj`UvnCJrexusxj ziXlH4m65N3HWvS}eOR$61R$V_b&wjZpl*)hhLP2m>ESwqIn0iH{=%1h85Su==8Qhl zx`%ys*1pHphBBLPawxk#YsuO{PNXt}C&awqTw=O7pSA4*Jq>^MYejWzj@C_v`PkE2 z|DkO?FS_eJJ~s6WZC_S0l1xm6MCjgWEq$KXRQ1iCr;CuAtrZTrnJ306N)7fFE@T2z zli}oklE})^sKttAS^jTH*9J+g6B#9j7GP}ovTN1hU3??&aMocy;{sje%v$^6s0f!< zB9a^?tf2~%O{MmvWYwvCo&d#kgw}F&a(Npt4V5qtolM8Q{aY|OwPq#pmUQ*dY{l5> zuR#o-blkkS0}>xK+~XFJWmd~;y;;`l;>l*`?l;iTdyCk9hpx6??O;d@n~~Si2SXVk z=<#G?3)*W^1(6e^&h(R8gynM645%|LQR&Bwe1-+O`!ykg{l=F?t9(`H_zTknZ78NO zaz{we*T)QxqE0GH5(I2L4Ge%Al;}G7I!){ zH0nFqqqG&XboqLLiT55qP05{N7Utu_%q6qYsXpqTTLE3E4pbyF$n z1HQ+Eilv;JOVj?5iY(wOE=KQm<%^tK3PKidd;DW#(rt+5n)8AdgM`}BI{O)Sy&_pA z+@~f@dOyv^dth_-xe`0E_!j8_yzCC#v##$Qu{*fLFQ3f4;LTC)Pz8|qH0AGNl4bD1 zz87eagq_jIjSGui!D>`xoz&x7JYN0)IL4V-wAL``Z=h4Iy|mk@*H9gussc#U;O(M7 zeH}P;5#dMBUFmmu&>Gi86m~kV>aTiqLBpS=#f99nmO;2*G9#8CwohkWTHWuFFd2ws zMBzw&1}P-)RJz{*P&PtJgUs4z1HwX5Icl+P8B>@rvRStAh|=(0F&s~z4X0dF*Bqyf zp`@-5N6lj+X%dP1qY1#DZ;2MmiSD94ardk~FG8;3m~Gs`?s_fxkNDI;aAi08cU^X) zb{ayR^{(iS2Hns*paFBi_+j++sg?Rb=k#Wy`Pgmx zog+xM8}c)6PXiCeA_ngue5T=skOX;oh?#eS+9UStpDJE_!4~2AAE!j~Uv9Aej&J@S zxf*}H+4xVchKiOQ&IgTgF#GnY)?t-{zTYBYGUB*mjXqeB-e$Tuk1S8tlMJOjD$C}i zS|j7OHGsXp%a35Peb--0`!h;FiR24qKWCek5pIEGCG8le**^D1%UH$x)APc{XZ7Zk zK^FRw*rB%e_MwsIcJJ6;bnUsCO!6H~2(Buo8?Fo*>#AxGp&?6b4ek9sAzj-mN2wt( zu6gGQSn-9oX-x6TGTZCoV=p~utm7&xukz?4*VC%*Tg{b~8f7uo^u{^!^V5bkdWoSL z9N&mr-nkmpBb^N;_#BIqQ}{VfX2N#jSnK$j<@H8zuz|>Lwo0jG%T=Bgv|=sX^I1>y zHOPuy6`A-wC~8`^BYGI-$$G3WPg5LXZWv9a=mx-qhGZ+dySt;td-*xM3}zel53%)j zjFqY4n+&=mS;L__J15SWy#WVsvO{m03aTZ%(xR(Ww8564m2o!knyv$?kbLyPN1ws! zCwkT&r|dQ{#w~WbP!c$r8K`7uyw+f?IAS`Lw!LE!@nCvmgK+%=qGmR=kBhXA)VsJXd zVyq{+$*GLv>vl^xMemE@6~a0lnmFcW)ICa6k~3cBWKYJb zlo++KoF2i_583OPOV;hpz4H#>-0-G~M)E;{i$6_e9`q4=DEk*$fIHI1a#>uf`w{YQ zT3yYEV~mv`neHJmUH21h?>`EOJBi{8KKsiWaSULQhLVF*&4>@f)lLiO%Ib@nI;4*? z1WR+E_M1g9Bl{1w^n*mzg+XHfCOOQk5>FgMF~G`U{|0~XJJQB-oQD`Up%op!haTg^K56f`7P)Tum0id9^wIxDZ#K=YQ|AP5ra@H`s&|X(%QvML43gNd&^y)sRSnNI1Lfe7eacD(rQO-CYedV~f&Htds&< z-tq$e>-XU805pLZcIr)AmQuyka{LXk^f^BA-r4MPWAon`fpK?gAwY0pNMG*I4>$it@)-#&dyyd1Z!{LH2hNnm=n&U~NA>xRGa&HELi z+h0itot?s9Cppb_p*qNfxpLM4vYhQ~S>33#UvOBSndd;%@*q^b8FJd8fH1T-sI!wn z=QNE2sb=ODrQ-*L;&2ZvvK{Jc9H!?JQ(xUa|3zEKwm3&8RLHpRdn`s)p|t>s}2mu2Ob$CcPh@sij+#;z5NKHO|rsZk9n^1%|$l=s3b`jzCBefTOplK~u3 z7~&ctwZy${wk{Z+>LnJ#!NbA9y{{gwe%50PFgQl!s+UP~_$|RdCE5JM?$VKayAA8` z-fMd3cYt=_Ih|Ql*Ck6lmwmqL=5~Z8kjO#yYkp&i3vp_u_Hg*KGsEbel5)NRB!zK! zzFHzqP!s#2S+(nL)C$Bzt<++V-Hqy+@c(<= zo}}|f3<5VyR&2{)Ek759Do-H`RANdLko{vc|= zsm(g3$i*~q+77mDml}!etbGd-1+CH)Iu!)_RNL@wJYY+mh3T2!dTS_xxCjU`3=Un} zbAye}V$R-5Qqu)$2`KpX;|$4`74R#ARca@~q(&!Bl@$wJm%3{6dpN)ttzF&$7L?lb z>yX8TFtZeAQfjtaY9Hnut1kNElz({&B}ReSqOZ7srHyB?Ty8L&tlbmEWH${5fw^6e3 zO;+#{{p=&xPE_gpuV{0}ZtsB9pathT`r=Q{nV1ZsVe91Qd|sw{*Cr#}s!NnD6I;d^ zJkUF*Xy^)_cWqzK8GO)QF2b}VR8uS9xDFt}P=-mwbIKO{@t+XG6g;4PIU{syf6S@n zA-?*pL~KG>h&P9Qc-)OP`0H;Y;f2KVv(ADTYLB-_TKYtlkcNr%TyF%OC_W8uq)5F9 zET}y+_4<=gZX|?2Wgi4nLH<0aY*lgoWpxm@kdc3KU;kQv$9C4N0G}mtcte>tlPHsK zjl9RJz?b3NC9 zXEYqQ4VADht_GpPnP6xb264Shv)v!l#d4ceOA?kjLa+boWD9mq&YnL~4-4u)IlF&f zl>3Lo&Hqllk0cW|F|u>~pK(E!vdzbu+y`-UJ;T~VBM;-N3^I{LtTZQ*i^ll7eFS>_pI&b!%V`BKuo`~Jzs0wGk!)r$kedBn+8vlVkpP75vh>?$Wg z;xWE<7v8OC;oj9dxGWbJeb=bu8MHP6nqwj?lf(~b0V5sTnc+HfrWBu9aDQUMhqLgY zd7n@X>qDrmN`p4?j z$b2^oV6!T~0$0HvL=3$>ECJ@bwIxU8CS9h&fo(_SCN0Bnd)XcyQ?&LzevA(h43Kq| z>VD)DcMre_2rR>5F9>A5m{3+ji5bZlfKt`Q%=DmD?(3ur`h!1Usyvst4`yndNi(ZJ zVKOz#2kw$aM$tWqmLG#q6_7b(#i9h1b;mQo2LC(?_9=(>^jVf!;M7j~&3{&h^%X0v z%haliCJg4NhaaEYef0v;RGM4NW~QqzTl8JK}`~GNunGS*}Ux( zc|2Iv(7-hSC>xHS0zZWQwb!EzlrZ`eX&esgb*f`{8CJj9#HMHpaZ6@=sKN}&2q$-R zEDFV}jBx6;)>G;RipA5z|^kcG& z!8fd$@#iSIhX$;Im$&AtGv-9S3ml%WO`r~YUDC5r*%ih?fgg_&!s;;GUc7{b^QPZK z*{&Hki=x>c`1G#r4r_fwcsdETN`NoQ+Hem#*hA+<99;yc|y^eEzUnjj7jk;vN%jgz;6^p zQpp19xrsuYx71tpNuFu-m?9uV!GX$XVNyd50f(k|r=O|pz}3E1&O#mtsYJRFiGzhz z$Ma^VZETD#zumvz>wTi<(|RyBf*xVRQnlW#vD``sW(5u>qj7D<89yjg>0RTT4aQxq zqOO-0R}H;Jdu?7a;=(KIp6LI?JHV)sblDr3X3~2?yd(%*qCW>* zN`>D_-7!4zDsqsp0$|uzBTUjK77~Btp9fK^VJq{sDiZbS>OkV9+&4GJS52-}-3irZ zQ-~CfrXRIJOiCUv@w?zcd6Y^k&B%rMD5YPN$0;T0Q|jw_=od^|4_XDI7&$W+z9$Zmz9+1&(J7R8nK-bK;vC-u!-lO zs~4b}0Qnq`w&gmIui}9gOAV(3R-407U`#y}J&0=l27^%=0B$%YMs&vURRtL;FLJl# z+(~ceoWIi>9LcZ%gg|ZN!hXzg!KXrPYdbk+h3^P#0!~?X}XpM5_RX$RfC)OYnK13s(Sq24wWAd1X6&&|#%>PV+&g(~isV_*A3}q8V z89=V)ERZ2 zR!oC7K6>)kFXkdEGl5TAm)d)?P0ez@%@ge3O)t-wXBty<5%5Jkm~&%pUjZJnuAyg;P1F4j3Yd!G->(FE0PUToGHl!P|#=Td+q&|2?V$j2|`57jXSOS0(} z@OK<9bcSJjb)&q7E&cV&t>54*ZM*}nYwWp(nucWUwIM#yWB997Yzlr>G8v;j{%LCu zaTiM^mOIZSdWf?+p-$-i06$K%8Bn$ZH{P?i-Pv2M-x>7fEVtLiD-|D;-F}AV{a-DC z96X56`bRt={-q`Odpv!(EqtHBRR)j0ggHkCnRVu5Pd&ONO z@ZU`x8XQ>IDBIT2FzX_5>ZA=pVE(PP0mV-w62beR5`y)`)=8-4)}w);2mI{F5`e7Z z@qLxxGByd)bz>WsVkMzNWi@JpAPAYKUiWlo)^ib2oCezyR-m*3%S-mgDq_r4YWzq6 zUGi8yA&OF|FCsBKgTlqvrjaoO+(|BaOmvg}YmPG}NKwG?`8KOhobVSB29;ECD5WcN z%EtBNEHv!E9^y&EK~XCgV|`ka^^ssuLEYr@pQvHMQBgNfY?j892G*hdGZLsB_Tq3Z z+W7d8!*dyo@rRU5JUFD`&0qUXrYPCrpykFZ=e6Tb)tE<5gAK*kvk$nO%OVc~FX4r6 zZ$zVzT+Z>U+vabs2Ke{Tth<>Gmy}iloO_w9Rsm zeltOhX=FNwnt?APOq*X{E8tgTzz>uOvWoiv!c=gAOM9f6vv%Z!`9okd|F#^q?%XA|?1BTe z>Hsj7hi zKlvKkY_0Pp3F@{uw5j(9tS_Du5dzn`*5i_-j3JIvVD*obR!(rS38+i|H* z-Jd*5yXaw(950A&LiVNHRs>f`#guA!Z6|WgWa|)-jC(O4wHLXQ()7bJSDI-bf3rt{ zukkQ(QJ)9*keOS3Bz6Y0#e`EXOZU-tmJ^~$>$_R4N_;8D)BDJn38@jY=`vP=p8GU$I9zkX%qjcI)|N!}$W3{5W{L zEvbO^VB<`W%9`qI1R7zxqqDTj#~d(2Y~z9|iu`aL+18Rk2X%-iMi{V6IS4Jv3vl{H z6v#%f4m9mc|0}EkF^p>DgC;=z3Y_GyzIUw9p-^fyDp?B;{nnZk6Ml}S z4Zd#nt%0AO0^D-A)i$ldleqyk}TE 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 z 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

    tyv*0yP}nk-pv4zbBt@DbR|3V7ZQ73LXi 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 kF-h#lNtCW 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 diff --git a/main.nf b/main.nf index d197b74f..32aabbc7 100644 --- a/main.nf +++ b/main.nf @@ -44,7 +44,7 @@ if (params.validate_params) { validateParameters() } -WorkflowMain.initialise(workflow, params, log) +WorkflowMain.initialise(workflow, params, log, args) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/modules.json b/modules.json index 0452434d..67813eca 100644 --- a/modules.json +++ b/modules.json @@ -7,17 +7,17 @@ "nf-core": { "custom/dumpsoftwareversions": { "branch": "master", - "git_sha": "bba7e362e4afead70653f84d8700588ea28d0f9e", + "git_sha": "8ec825f465b9c17f9d83000022995b4f7de6fe93", "installed_by": ["modules"] }, "fastqc": { "branch": "master", - "git_sha": "65ad3e0b9a4099592e1102e92e10455dc661cf53", + "git_sha": "c9488585ce7bd35ccd2a30faa2371454c8112fb9", "installed_by": ["modules"] }, "multiqc": { "branch": "master", - "git_sha": "4ab13872435962dadc239979554d13709e20bf29", + "git_sha": "8ec825f465b9c17f9d83000022995b4f7de6fe93", "installed_by": ["modules"] } } diff --git a/modules/nf-core/custom/dumpsoftwareversions/environment.yml b/modules/nf-core/custom/dumpsoftwareversions/environment.yml index f0c63f69..9b3272bc 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/environment.yml +++ b/modules/nf-core/custom/dumpsoftwareversions/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - bioconda::multiqc=1.17 + - bioconda::multiqc=1.19 diff --git a/modules/nf-core/custom/dumpsoftwareversions/main.nf b/modules/nf-core/custom/dumpsoftwareversions/main.nf index 7685b33c..f2187611 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/main.nf +++ b/modules/nf-core/custom/dumpsoftwareversions/main.nf @@ -4,8 +4,8 @@ process CUSTOM_DUMPSOFTWAREVERSIONS { // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.17--pyhdfd78af_0' : - 'biocontainers/multiqc:1.17--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.19--pyhdfd78af_0' : + 'biocontainers/multiqc:1.19--pyhdfd78af_0' }" input: path versions diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test index eec1db10..b1e1630b 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test +++ b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test @@ -31,7 +31,12 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot( + process.out.versions, + file(process.out.mqc_yml[0]).readLines()[0..10], + file(process.out.yml[0]).readLines()[0..7] + ).match() + } ) } } diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap index 4274ed57..5f59a936 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap +++ b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap @@ -1,27 +1,33 @@ { "Should run without failures": { "content": [ - { - "0": [ - "software_versions.yml:md5,1c851188476409cda5752ce971b20b58" - ], - "1": [ - "software_versions_mqc.yml:md5,2570f4ba271ad08357b0d3d32a9cf84d" - ], - "2": [ - "versions.yml:md5,3843ac526e762117eedf8825b40683df" - ], - "mqc_yml": [ - "software_versions_mqc.yml:md5,2570f4ba271ad08357b0d3d32a9cf84d" - ], - "versions": [ - "versions.yml:md5,3843ac526e762117eedf8825b40683df" - ], - "yml": [ - "software_versions.yml:md5,1c851188476409cda5752ce971b20b58" - ] - } + [ + "versions.yml:md5,76d454d92244589d32455833f7c1ba6d" + ], + [ + "data: \"\\n

    V0GI8SHG1^dh_*}1*QM#w2kyE^nW%>`QZD7q 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 Q)8RG*JHk(BI-FkqACU4o?*IS* diff --git a/lib/WorkflowMain.groovy b/lib/WorkflowMain.groovy index 69de09aa..79426ea9 100755 --- a/lib/WorkflowMain.groovy +++ b/lib/WorkflowMain.groovy @@ -24,7 +24,7 @@ class WorkflowMain { // // Validate parameters and print summary to screen // - public static void initialise(workflow, params, log) { + public static void initialise(workflow, params, log, args) { // Print workflow version and exit on --version if (params.version) { @@ -35,6 +35,8 @@ class WorkflowMain { // Check that a -profile or Nextflow config has been provided to run the pipeline NfcoreTemplate.checkConfigProvided(workflow, log) + // Check that the profile doesn't contain spaces and doesn't end with a trailing comma + checkProfile(workflow.profile, args, log) // Check that conda channels are set-up correctly if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { @@ -60,4 +62,16 @@ class WorkflowMain { } return null } + + // + // Exit pipeline if --profile contains spaces + // + private static void checkProfile(profile, args, log) { + if (profile.endsWith(',')) { + Nextflow.error "Profile cannot end with a trailing comma. Please remove the comma from the end of the profile string.\nHint: A common mistake is to provide multiple values to `-profile` separated by spaces. Please use commas to separate profiles instead,e.g., `-profile docker,test`." + } + if (args[0]) { + log.warn "nf-core pipelines do not accept positional arguments. The positional argument `${args[0]}` has been detected.\n Hint: A common mistake is to provide multiple values to `-profile` separated by spaces. Please use commas to separate profiles instead,e.g., `-profile docker,test`." + } + } } diff --git a/lib/nfcore_external_java_deps.jar b/lib/nfcore_external_java_deps.jar deleted file mode 100644 index 805c8bb5e4fd43a12a5891eea5a68788309629b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2291171 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�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

    Process Name \\", + " \\ Software Version
    CUSTOM_DUMPSOFTWAREVERSIONSpython3.11.7
    yaml5.4.1
    TOOL1tool10.11.9
    TOOL2tool21.9
    WorkflowNextflow
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    \\n \\n \\n \\n \\n \\n \\n \\n\\", + " \\n\\n\\n \\n \\n\\", + " \\ \\n\\n\\n\\n \\n \\", + " \\ \\n \\n\\n\\n\\n\\", + " \\n\\n \\n \\n\\", + " \\ \\n\\n\\n\\n\\n\\n \\n\\", + " \\ \\n \\n\\n\\n\\n\\", + " \\n\\n \\n \\n\\" + ], + [ + "CUSTOM_DUMPSOFTWAREVERSIONS:", + " python: 3.11.7", + " yaml: 5.4.1", + "TOOL1:", + " tool1: 0.11.9", + "TOOL2:", + " tool2: '1.9'", + "Workflow:" + ] ], - "timestamp": "2023-11-03T14:43:22.157011" + "timestamp": "2024-01-09T23:01:18.710682" } -} +} \ No newline at end of file diff --git a/modules/nf-core/fastqc/tests/main.nf.test b/modules/nf-core/fastqc/tests/main.nf.test index b9e8f926..1f21c664 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test +++ b/modules/nf-core/fastqc/tests/main.nf.test @@ -3,24 +3,20 @@ nextflow_process { name "Test Process FASTQC" script "../main.nf" process "FASTQC" + tag "modules" tag "modules_nfcore" tag "fastqc" - test("Single-Read") { + test("sarscov2 single-end [fastq]") { when { - params { - outdir = "$outputDir" - } process { """ - input[0] = [ + input[0] = Channel.of([ [ id: 'test', single_end:true ], - [ - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) - ] - ] + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] + ]) """ } } @@ -28,82 +24,189 @@ nextflow_process { then { assertAll ( { assert process.success }, + // NOTE The report contains the date inside it, which means that the md5sum is stable per day, but not longer than that. So you can't md5sum it. // looks like this:
    Mon 2 Oct 2023
    test.gz
    // https://github.com/nf-core/modules/pull/3903#issuecomment-1743620039 - { assert process.out.html.get(0).get(1) ==~ ".*/test_fastqc.html" }, - { assert path(process.out.html.get(0).get(1)).getText().contains("
    ") }, - { assert snapshot(process.out.versions).match("versions") }, - { assert process.out.zip.get(0).get(1) ==~ ".*/test_fastqc.zip" } + + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("") }, + + { assert snapshot(process.out.versions).match("versions") } + ) + } + } + + test("sarscov2 paired-end [fastq]") { + + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + + { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, + { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, + { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, + { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, + { assert path(process.out.html[0][1][0]).text.contains("") }, + { assert path(process.out.html[0][1][1]).text.contains("") }, + + { assert snapshot(process.out.versions).match("versions") } + ) + } + } + + test("sarscov2 interleaved [fastq]") { + + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("") }, + + { assert snapshot(process.out.versions).match("versions") } ) } } -// TODO -// // -// // Test with paired-end data -// // -// workflow test_fastqc_paired_end { -// input = [ -// [id: 'test', single_end: false], // meta map -// [ -// file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), -// file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) -// ] -// ] - -// FASTQC ( input ) -// } - -// // -// // Test with interleaved data -// // -// workflow test_fastqc_interleaved { -// input = [ -// [id: 'test', single_end: false], // meta map -// file(params.test_data['sarscov2']['illumina']['test_interleaved_fastq_gz'], checkIfExists: true) -// ] - -// FASTQC ( input ) -// } - -// // -// // Test with bam data -// // -// workflow test_fastqc_bam { -// input = [ -// [id: 'test', single_end: false], // meta map -// file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) -// ] - -// FASTQC ( input ) -// } - -// // -// // Test with multiple samples -// // -// workflow test_fastqc_multiple { -// input = [ -// [id: 'test', single_end: false], // meta map -// [ -// file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), -// file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true), -// file(params.test_data['sarscov2']['illumina']['test2_1_fastq_gz'], checkIfExists: true), -// file(params.test_data['sarscov2']['illumina']['test2_2_fastq_gz'], checkIfExists: true) -// ] -// ] - -// FASTQC ( input ) -// } - -// // -// // Test with custom prefix -// // -// workflow test_fastqc_custom_prefix { -// input = [ -// [ id:'mysample', single_end:true ], // meta map -// file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) -// ] - -// FASTQC ( input ) -// } + + test("sarscov2 paired-end [bam]") { + + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("") }, + + { assert snapshot(process.out.versions).match("versions") } + ) + } + } + + test("sarscov2 multiple [fastq]") { + + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) ] + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + + { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, + { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, + { assert process.out.html[0][1][2] ==~ ".*/test_3_fastqc.html" }, + { assert process.out.html[0][1][3] ==~ ".*/test_4_fastqc.html" }, + { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, + { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, + { assert process.out.zip[0][1][2] ==~ ".*/test_3_fastqc.zip" }, + { assert process.out.zip[0][1][3] ==~ ".*/test_4_fastqc.zip" }, + { assert path(process.out.html[0][1][0]).text.contains("") }, + { assert path(process.out.html[0][1][1]).text.contains("") }, + { assert path(process.out.html[0][1][2]).text.contains("") }, + { assert path(process.out.html[0][1][3]).text.contains("") }, + + { assert snapshot(process.out.versions).match("versions") } + ) + } + } + + test("sarscov2 custom_prefix") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'mysample', single_end:true ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + + { assert process.out.html[0][1] ==~ ".*/mysample_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/mysample_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("") }, + + { assert snapshot(process.out.versions).match("versions") } + ) + } + } + + test("sarscov2 single-end [fastq] - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id: 'test', single_end:true ], + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out.html.collect { file(it[1]).getName() } + + process.out.zip.collect { file(it[1]).getName() } + + process.out.versions ).match() } + ) + } + } + } diff --git a/modules/nf-core/fastqc/tests/main.nf.test.snap b/modules/nf-core/fastqc/tests/main.nf.test.snap index 636a32ce..5d624bb8 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test.snap +++ b/modules/nf-core/fastqc/tests/main.nf.test.snap @@ -1,10 +1,20 @@ { + "sarscov2 single-end [fastq] - stub": { + "content": [ + [ + "test.html", + "test.zip", + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "timestamp": "2024-01-17T18:40:57.254299" + }, "versions": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], - "timestamp": "2023-10-09T23:40:54+0000" + "timestamp": "2024-01-17T18:36:50.033627" } } \ No newline at end of file diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index bc0bdb5b..7625b752 100644 --- a/modules/nf-core/multiqc/environment.yml +++ b/modules/nf-core/multiqc/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - bioconda::multiqc=1.18 + - bioconda::multiqc=1.19 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 00cc48d2..1b9f7c43 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -3,8 +3,8 @@ process MULTIQC { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.18--pyhdfd78af_0' : - 'biocontainers/multiqc:1.18--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.19--pyhdfd78af_0' : + 'biocontainers/multiqc:1.19--pyhdfd78af_0' }" input: path multiqc_files, stageAs: "?/*" @@ -43,7 +43,7 @@ process MULTIQC { stub: """ - touch multiqc_data + mkdir multiqc_data touch multiqc_plots touch multiqc_report.html diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index f1aa660e..45a9bc35 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -1,4 +1,3 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json name: multiqc description: Aggregate results from bioinformatics analyses across many samples into a single report keywords: diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test index c2dad217..d0438eda 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -7,12 +7,9 @@ nextflow_process { tag "modules_nfcore" tag "multiqc" - test("MULTIQC: FASTQC") { + test("sarscov2 single-end [fastqc]") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)]) @@ -26,20 +23,17 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert path(process.out.report.get(0)).exists() }, - { assert path(process.out.data.get(0)).exists() }, - { assert path(process.out.versions.get(0)).getText().contains("multiqc") } + { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, + { assert process.out.data[0] ==~ ".*/multiqc_data" }, + { assert snapshot(process.out.versions).match("versions") } ) } } - test("MULTIQC: FASTQC and a config file") { + test("sarscov2 single-end [fastqc] [config]") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)]) @@ -53,9 +47,35 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert path(process.out.report.get(0)).exists() }, - { assert path(process.out.data.get(0)).exists() }, - { assert path(process.out.versions.get(0)).getText().contains("multiqc") } + { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, + { assert process.out.data[0] ==~ ".*/multiqc_data" }, + { assert snapshot(process.out.versions).match("versions") } + ) + } + } + + test("sarscov2 single-end [fastqc] - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)]) + input[1] = [] + input[2] = [] + input[3] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.report.collect { file(it).getName() } + + process.out.data.collect { file(it).getName() } + + process.out.plots.collect { file(it).getName() } + + process.out.versions ).match() } ) } diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap new file mode 100644 index 00000000..d37e7304 --- /dev/null +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -0,0 +1,21 @@ +{ + "versions": { + "content": [ + [ + "versions.yml:md5,14e9a2661241abd828f4f06a7b5c222d" + ] + ], + "timestamp": "2024-01-09T23:02:49.911994" + }, + "sarscov2 single-end [fastqc] - stub": { + "content": [ + [ + "multiqc_report.html", + "multiqc_data", + "multiqc_plots", + "versions.yml:md5,14e9a2661241abd828f4f06a7b5c222d" + ] + ], + "timestamp": "2024-01-09T23:03:14.524346" + } +} \ No newline at end of file diff --git a/nextflow.config b/nextflow.config index 4b3b98de..4d098309 100644 --- a/nextflow.config +++ b/nextflow.config @@ -71,7 +71,7 @@ try { } // Load nf-core/circrna custom profiles from different institutions. -// Warning: Uncomment only if a pipeline-specific instititutional config already exists on nf-core/configs! +// Warning: Uncomment only if a pipeline-specific institutional config already exists on nf-core/configs! // try { // includeConfig "${params.custom_config_base}/pipeline/circrna.config" // } catch (Exception e) { @@ -91,6 +91,7 @@ profiles { podman.enabled = false shifter.enabled = false charliecloud.enabled = false + channels = ['conda-forge', 'bioconda', 'defaults'] apptainer.enabled = false } mamba { diff --git a/pyproject.toml b/pyproject.toml index 0d62beb6..7d08e1c8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,13 @@ -# Config file for Python. Mostly used to configure linting of bin/check_samplesheet.py with Black. +# Config file for Python. Mostly used to configure linting of bin/*.py with Ruff. # Should be kept the same as nf-core/tools to avoid fighting with template synchronisation. -[tool.black] +[tool.ruff] line-length = 120 -target_version = ["py37", "py38", "py39", "py310"] +target-version = "py38" +select = ["I", "E1", "E4", "E7", "E9", "F", "UP", "N"] +cache-dir = "~/.cache/ruff" -[tool.isort] -profile = "black" -known_first_party = ["nf_core"] -multi_line_output = 3 +[tool.ruff.isort] +known-first-party = ["nf_core"] + +[tool.ruff.per-file-ignores] +"__init__.py" = ["E402", "F401"] diff --git a/workflows/circrna.nf b/workflows/circrna.nf index 5ae33065..10ecc0ac 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -127,6 +127,13 @@ workflow.onComplete { } } +workflow.onError { + if (workflow.errorReport.contains("Process requirement exceeds available memory")) { + println("🛑 Default resources exceed availability 🛑 ") + println("💡 See here on how to configure pipeline: https://nf-co.re/docs/usage/configuration#tuning-workflow-resources 💡") + } +} + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ THE END From c8dbd82dd33c7ddc032d4657821dce8a801e886e Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 1 Feb 2024 10:59:10 +0100 Subject: [PATCH 102/491] prettier --- .github/workflows/download_pipeline.yml | 2 +- README.md | 1 + docs/output.md | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml index 8611458a..8a330045 100644 --- a/.github/workflows/download_pipeline.yml +++ b/.github/workflows/download_pipeline.yml @@ -64,4 +64,4 @@ jobs: env: NXF_SINGULARITY_CACHEDIR: ./ NXF_SINGULARITY_HOME_MOUNT: true - run: nextflow run ./${{ env.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ env.REPO_BRANCH }}) -stub -profile test,singularity --outdir ./results + run: nextflow run ./${{ env.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ env.REPO_BRANCH }}) -stub -profile test,singularity --outdir ./results diff --git a/README.md b/README.md index 9b16eaf1..e13dcc3d 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz Each row represents a fastq file (single-end) or a pair of fastq files (paired end). --> + Now, you can run the pipeline using: ```bash diff --git a/docs/output.md b/docs/output.md index eb711ae2..a92ce05e 100644 --- a/docs/output.md +++ b/docs/output.md @@ -162,7 +162,6 @@ The FastQC plots displayed in the MultiQC report shows _untrimmed_ reads. They m - `SAMtoolsIndex`: Directory containing `SAMtools` index file. - `STARIndex`: Directory containing `STAR` indices. - `SegemehlIndex`: Directory containing `Segemehl` index file. - - `pipeline_info/` - Reports generated by Nextflow: `execution_report.html`, `execution_timeline.html`, `execution_trace.txt` and `pipeline_dag.dot`/`pipeline_dag.svg`. - Reports generated by the pipeline: `pipeline_report.html`, `pipeline_report.txt` and `software_versions.yml`. The `pipeline_report*` files will only be present if the `--email` / `--email_on_fail` parameter's are used when running the pipeline. From 1cf63900ac6c569a964829dcae73448e48d15b90 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 1 Feb 2024 14:24:03 +0100 Subject: [PATCH 103/491] add change to trigger test --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index c915d9c1..dd0f6ed0 100644 --- a/main.nf +++ b/main.nf @@ -9,7 +9,7 @@ ---------------------------------------------------------------------------------------- */ -nextflow.enable.dsl = 2 +nextflow.enable.dsl = 2 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 7033540dc560a99926b3d3fe0431a2d0066c41c4 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 1 Feb 2024 15:12:13 +0100 Subject: [PATCH 104/491] linting: fix results wiht params schema --- main.nf | 2 +- nextflow.config | 2 +- nextflow_schema.json | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/main.nf b/main.nf index dd0f6ed0..c915d9c1 100644 --- a/main.nf +++ b/main.nf @@ -9,7 +9,7 @@ ---------------------------------------------------------------------------------------- */ -nextflow.enable.dsl = 2 +nextflow.enable.dsl = 2 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/nextflow.config b/nextflow.config index d2c4da73..8ed4fd36 100644 --- a/nextflow.config +++ b/nextflow.config @@ -71,7 +71,7 @@ params { multiqc_methods_description = null // Boilerplate options - outdir = null + outdir = './results' publish_dir_mode = 'copy' email = null email_on_fail = null diff --git a/nextflow_schema.json b/nextflow_schema.json index 71fb9ef2..654a7f80 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -252,7 +252,7 @@ }, "segemehl": { "type": "string", - "default": "None", + "default": null, "fa_icon": "fab fa-stripe-s", "description": "Path to Segemehl Index **file**." }, @@ -388,7 +388,7 @@ "max_cpus": { "type": "integer", "description": "Maximum number of CPUs that can be requested for any single job.", - "default": 16, + "default": 50, "fa_icon": "fas fa-microchip", "hidden": true, "help_text": "Use to set an upper-limit for the CPU requirement for each process. Should be an integer e.g. `--max_cpus 1`" @@ -396,7 +396,7 @@ "max_memory": { "type": "string", "description": "Maximum amount of memory that can be requested for any single job.", - "default": "128.GB", + "default": "300.GB", "fa_icon": "fas fa-memory", "pattern": "^\\d+(\\.\\d+)?\\.?\\s*(K|M|G|T)?B$", "hidden": true, From e092a8bed8db19bf00140d5710706b1f70e26caa Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 1 Feb 2024 15:14:18 +0100 Subject: [PATCH 105/491] linting: fix logo files --- assets/nf-core-circrna_logo_light.png | Bin 64214 -> 67266 bytes docs/images/nf-core-circrna_logo_dark.png | Bin 25192 -> 25216 bytes docs/images/nf-core-circrna_logo_light.png | Bin 21840 -> 21837 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/nf-core-circrna_logo_light.png b/assets/nf-core-circrna_logo_light.png index d3cd49c1fffb4c615ab9d6e96f131be71830d2b2..cb307a2b40d6de041c576c4653e1fc77e66d7459 100644 GIT binary patch literal 67266 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 z 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�ev`Q}H7y#R1zKkC5n?0_OP7^FqWWeXhX0t0pNK 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

    )bNtXB<>| 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

    V0GI8SHG1^dh_*}1*QM#w2kyE^nW%>`QZD7q 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 Q)8RG*JHk(BI-FkqACU4o?*IS* diff --git a/docs/images/nf-core-circrna_logo_dark.png b/docs/images/nf-core-circrna_logo_dark.png index b48e7b08c6faa330c043d93a106076880d4157c8..869f35cbe9b6efda9efc5db2f2eb063f17c534cc 100644 GIT binary patch delta 24563 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 JZR2zMe*kpKTde>9 delta 24534 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 delta 21156 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 VTHWu^B&-79gF@OOo}2n6{STf|Sf>C0 From 3cbf35951bc98f002f38ecaa1e0e683bea67a9d5 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 1 Feb 2024 15:31:55 +0100 Subject: [PATCH 106/491] fix error with args --- lib/WorkflowMain.groovy | 2 +- main.nf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/WorkflowMain.groovy b/lib/WorkflowMain.groovy index a2ed646d..03790911 100755 --- a/lib/WorkflowMain.groovy +++ b/lib/WorkflowMain.groovy @@ -24,7 +24,7 @@ class WorkflowMain { // // Validate parameters and print summary to screen // - public static void initialise(workflow, params, log) { + public static void initialise(workflow, params, log, args) { // Print workflow version and exit on --version if (params.version) { diff --git a/main.nf b/main.nf index c915d9c1..61a893e9 100644 --- a/main.nf +++ b/main.nf @@ -48,7 +48,7 @@ if (params.validate_params) { validateParameters() } -WorkflowMain.initialise(workflow, params, log) +WorkflowMain.initialise(workflow, params, log, args) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 563e4e93f496e5283ea94cb760703e4735b5fe15 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 1 Feb 2024 15:34:38 +0100 Subject: [PATCH 107/491] fix required yaml package --- .../dumpsoftwareversions/templates/dumpsoftwareversions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py index b10e0a5c..da033408 100755 --- a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py +++ b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py @@ -4,6 +4,7 @@ """Provide functions to merge multiple versions.yml files.""" +import yaml import platform from textwrap import dedent From e806c705ba9673977b69f10f88d562fab620d7a0 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 1 Feb 2024 16:18:51 +0100 Subject: [PATCH 108/491] set outdir to null as default --- nextflow.config | 2 +- nextflow_schema.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nextflow.config b/nextflow.config index 8ed4fd36..84fd7b9c 100644 --- a/nextflow.config +++ b/nextflow.config @@ -11,7 +11,7 @@ params { // Input options input = null - outdir = './results' + outdir = null phenotype = null // workflow options diff --git a/nextflow_schema.json b/nextflow_schema.json index 654a7f80..98c9bc80 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -27,7 +27,7 @@ "format": "directory-path", "description": "The output directory where the results will be saved. You have to use absolute paths to storage on Cloud infrastructure.", "fa_icon": "fas fa-folder-open", - "default": "./results" + "default": null }, "phenotype": { "type": "string", From d6ef74a7ae3a38ff359f8e7c369330dcdef73969 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 1 Feb 2024 16:27:41 +0100 Subject: [PATCH 109/491] fix whitespace for pre-commit --- .gitignore | 2 +- bin/check_samplesheet.py | 8 ++++---- docs/usage.md | 8 ++++---- nextflow.config | 2 +- subworkflows/local/circrna_discovery.nf | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index fe288886..8800274c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,4 @@ testing* *.pyc test_outdir/ nf-* -!modules/* \ No newline at end of file +!modules/* diff --git a/bin/check_samplesheet.py b/bin/check_samplesheet.py index 2baec583..95346faf 100755 --- a/bin/check_samplesheet.py +++ b/bin/check_samplesheet.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 """ - Borrowed from nf-core/rnaseq, the original from template 2.6 kept breaking at: - "[CRITICAL] The given sample sheet does not appear to contain a header." - Even though the input samplesheet looked to be perfectly fine using vim :set list. + Borrowed from nf-core/rnaseq, the original from template 2.6 kept breaking at: + "[CRITICAL] The given sample sheet does not appear to contain a header." + Even though the input samplesheet looked to be perfectly fine using vim :set list. - Strandedness commented out should you wish to include this in future releases. + Strandedness commented out should you wish to include this in future releases. """ diff --git a/docs/usage.md b/docs/usage.md index 5e105b0c..28e1fd7e 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -135,18 +135,18 @@ When running the differential expression analysis module via the `--module diffe ```R colnames(phenotype) - [1] 'Sample_ID' 'condition' + [1] 'Sample_ID' 'condition' print(dds$design) - [1] ' ~ condition' + [1] ' ~ condition' ``` ```R colnames(phenotype) - [1] 'Sample_ID' 'condition' 'replicates' 'location' + [1] 'Sample_ID' 'condition' 'replicates' 'location' print(dds$design) - [1] ' ~ location + replicates + condition' + [1] ' ~ location + replicates + condition' ``` It is recommended to construct your input CSV file in conjunction with your phenotype file as the first column denoting sample names **must match** the first column of the `phenotype.csv` file. diff --git a/nextflow.config b/nextflow.config index 84fd7b9c..04b028f1 100644 --- a/nextflow.config +++ b/nextflow.config @@ -88,7 +88,7 @@ params { custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" config_profile_contact = null config_profile_url = null - + // Max resource options max_memory = '300.GB' diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 8501cffb..70aaf854 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -165,11 +165,11 @@ workflow CIRCRNA_DISCOVERY { DCC_MATE2_2ND_PASS( mate2, star_index, DCC_MATE2_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) dcc_stage = STAR_2ND_PASS.out.junction.map{ meta, junction -> return [ meta.id, meta, junction]} - .join( + .join( DCC_MATE1_2ND_PASS.out.junction.map{ meta, junction -> return [ meta.id, junction] }, remainder: true ) - .join( + .join( DCC_MATE2_2ND_PASS.out.junction.map{ meta, junction -> return [ meta.id, junction] }, remainder: true ) From e9d50a1423afc5ee27270aa91ad394a50e21ef80 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 1 Feb 2024 17:14:34 +0100 Subject: [PATCH 110/491] prettier --- .devcontainer/devcontainer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 4a9bc5c7..4ecfbfe3 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -18,11 +18,11 @@ "python.linting.flake8Path": "/opt/conda/bin/flake8", "python.linting.pycodestylePath": "/opt/conda/bin/pycodestyle", "python.linting.pydocstylePath": "/opt/conda/bin/pydocstyle", - "python.linting.pylintPath": "/opt/conda/bin/pylint", + "python.linting.pylintPath": "/opt/conda/bin/pylint" }, // Add the IDs of extensions you want installed when the container is created. - "extensions": ["ms-python.python", "ms-python.vscode-pylance", "nf-core.nf-core-extensionpack"], - }, - }, + "extensions": ["ms-python.python", "ms-python.vscode-pylance", "nf-core.nf-core-extensionpack"] + } + } } From 9fc9fd1f9f67267e1e29a3af6c807365c893d8a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20H=C3=B6rtenhuber?= Date: Thu, 1 Feb 2024 16:15:57 +0000 Subject: [PATCH 111/491] pull logo changes manually from TEMPLATE --- assets/nf-core-circrna_logo_light.png | Bin 67266 -> 67279 bytes docs/images/nf-core-circrna_logo_dark.png | Bin 25216 -> 25192 bytes docs/images/nf-core-circrna_logo_light.png | Bin 21837 -> 21840 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/nf-core-circrna_logo_light.png b/assets/nf-core-circrna_logo_light.png index cb307a2b40d6de041c576c4653e1fc77e66d7459..85a200b325d8ef5ec381b5863b8300262d646720 100644 GIT binary patch delta 34092 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 QMdo>Ojot5AtKAO$KPD9ing9R* delta 34080 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 JZR2zMe*kpKTde>9 diff --git a/docs/images/nf-core-circrna_logo_light.png b/docs/images/nf-core-circrna_logo_light.png index 961785e725857841cf4976728e6244150bded2e0..611d5449ba941306c58ea81f5a3ac26ab47a5c81 100644 GIT binary patch delta 21156 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 VTHWu^B&-79gF@OOo}2n6{STf|Sf>C0 delta 21147 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 From dbcbf1a301b15a5de745318c615a8e36f26dfbd3 Mon Sep 17 00:00:00 2001 From: Marieke Vromman <74721287+MariekeVromman@users.noreply.github.com> Date: Fri, 2 Feb 2024 09:31:11 +0100 Subject: [PATCH 112/491] fix typo in docs/output.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- docs/output.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/output.md b/docs/output.md index a92ce05e..9e218636 100644 --- a/docs/output.md +++ b/docs/output.md @@ -133,7 +133,7 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d `nf-core/circrna` outputs quality control plots of normalised _log2_ expression data from `DESeq2` to assess heterogeneity in the experiment samples. These plots can be useful to assess sample-sample similarity and to identify potential batch effects within the experiment. Plots are generated for both circRNAs and RNA-Seq data when the differential expression analysis module has been selected by the user (see `--module` [documentation](https://nf-co.re/circrna/dev/parameters#pipeline-options)). :::note -The FastQC plots displayed in the MultiQC report shows _untrimmed_ reads. They may contain adapter sequence and potentially regions with low quality. +The FastQC plots displayed in the MultiQC report show _untrimmed_ reads. They may contain adapter sequence and potentially regions with low quality. ::: ### MultiQC From e0a01236bd7b092c4a641e9845ac0f97fd80839e Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Fri, 2 Feb 2024 09:33:45 +0100 Subject: [PATCH 113/491] remove redundant output declaration --- nextflow.config | 1 - 1 file changed, 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index 04b028f1..458e66e5 100644 --- a/nextflow.config +++ b/nextflow.config @@ -71,7 +71,6 @@ params { multiqc_methods_description = null // Boilerplate options - outdir = './results' publish_dir_mode = 'copy' email = null email_on_fail = null From 313ba3a9c918d8c2b695688529e825622749fa70 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Wed, 14 Feb 2024 08:58:37 +0100 Subject: [PATCH 114/491] make /tmp dir in work dir (sort) to avoid error on cluster --- modules/local/star/sjdb/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/star/sjdb/main.nf b/modules/local/star/sjdb/main.nf index b2e0ebc0..557a2f3f 100644 --- a/modules/local/star/sjdb/main.nf +++ b/modules/local/star/sjdb/main.nf @@ -21,7 +21,7 @@ process SJDB { script: def VERSION = '1.3.4' """ - cat *.tab | awk -v BSJ=${bsj_reads} '(\$7 >= BSJ && \$6==0)' | cut -f1-6 | sort | uniq > dataset.SJ.out.tab + cat *.tab | awk -v BSJ=${bsj_reads} '(\$7 >= BSJ && \$6==0)' | cut -f1-6 | sort -T ./tmp/ | uniq > dataset.SJ.out.tab cat <<-END_VERSIONS > versions.yml "${task.process}": From b7f37683d957d5fb88b13288cefd854508952c84 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Wed, 14 Feb 2024 09:16:20 +0100 Subject: [PATCH 115/491] add tmp dir --- modules/local/star/sjdb/main.nf | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/local/star/sjdb/main.nf b/modules/local/star/sjdb/main.nf index 557a2f3f..8550647d 100644 --- a/modules/local/star/sjdb/main.nf +++ b/modules/local/star/sjdb/main.nf @@ -21,6 +21,7 @@ process SJDB { script: def VERSION = '1.3.4' """ + mkdir tmp cat *.tab | awk -v BSJ=${bsj_reads} '(\$7 >= BSJ && \$6==0)' | cut -f1-6 | sort -T ./tmp/ | uniq > dataset.SJ.out.tab cat <<-END_VERSIONS > versions.yml From 0660b3e4c5d88f850261aacd6452c56ca714c4be Mon Sep 17 00:00:00 2001 From: Marieke Vromman <74721287+MariekeVromman@users.noreply.github.com> Date: Wed, 14 Feb 2024 09:46:26 +0100 Subject: [PATCH 116/491] Update modules/local/star/sjdb/main.nf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- modules/local/star/sjdb/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/star/sjdb/main.nf b/modules/local/star/sjdb/main.nf index 8550647d..c2a52a9e 100644 --- a/modules/local/star/sjdb/main.nf +++ b/modules/local/star/sjdb/main.nf @@ -23,7 +23,7 @@ process SJDB { """ mkdir tmp cat *.tab | awk -v BSJ=${bsj_reads} '(\$7 >= BSJ && \$6==0)' | cut -f1-6 | sort -T ./tmp/ | uniq > dataset.SJ.out.tab - +rm -rf tmp cat <<-END_VERSIONS > versions.yml "${task.process}": mawk: $VERSION From cb5f8ff8e57c57d389220e39bc56b5e2d9faf1af Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Wed, 14 Feb 2024 10:13:09 +0100 Subject: [PATCH 117/491] fix indentation --- modules/local/star/sjdb/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/star/sjdb/main.nf b/modules/local/star/sjdb/main.nf index c2a52a9e..835f4e21 100644 --- a/modules/local/star/sjdb/main.nf +++ b/modules/local/star/sjdb/main.nf @@ -23,7 +23,7 @@ process SJDB { """ mkdir tmp cat *.tab | awk -v BSJ=${bsj_reads} '(\$7 >= BSJ && \$6==0)' | cut -f1-6 | sort -T ./tmp/ | uniq > dataset.SJ.out.tab -rm -rf tmp + rm -rf tmp cat <<-END_VERSIONS > versions.yml "${task.process}": mawk: $VERSION From d8c6073a9446871b0362ae34f51bab1a91fe3b6c Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Wed, 14 Feb 2024 16:47:01 +0100 Subject: [PATCH 118/491] clean up fasta (not working correctly yet) --- conf/modules.config | 7 +++++++ modules/nf-core/gawk/main.nf | 2 +- subworkflows/local/prepare_genome.nf | 10 ++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 52b47439..d0b2e405 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -68,6 +68,13 @@ if (!params.skip_trimming) { } // PREPARE GENOME + withName: CLEAN_FASTA { + ext.args2 = '\'/>/{ gsub(\$2, "",\$2);gsub(" ", "") };{print}\'' + ext.prefix = 'clean' + ext.suffix = 'fa' + + } + withName: BOWTIE_BUILD { ext.when = { params.fasta && !params.bowtie && params.tool.split(',').contains('mapsplice') && params.module.split(',').contains('circrna_discovery') } publishDir = [ diff --git a/modules/nf-core/gawk/main.nf b/modules/nf-core/gawk/main.nf index 854bae00..a8f2f741 100644 --- a/modules/nf-core/gawk/main.nf +++ b/modules/nf-core/gawk/main.nf @@ -12,7 +12,7 @@ process GAWK { path(program_file) output: - tuple val(meta), path("${prefix}.${suffix}"), emit: output + path("${prefix}.${suffix}"), emit: output path "versions.yml" , emit: versions when: diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 84d932db..fb94ab3c 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -6,6 +6,7 @@ include { HISAT2_EXTRACTSPLICESITES } from '../../modules/nf-core/hisat2/extract include { HISAT2_BUILD } from '../../modules/nf-core/hisat2/build/main' include { STAR_GENOMEGENERATE } from '../../modules/nf-core/star/genomegenerate/main' include { SEGEMEHL_INDEX } from '../../modules/nf-core/segemehl/index/main' +include { GAWK as CLEAN_FASTA } from '../../modules/nf-core/gawk/main' workflow PREPARE_GENOME { @@ -21,6 +22,15 @@ workflow PREPARE_GENOME { fasta_tuple = Channel.value([[id: "fasta"], fasta]) gtf_tuple = Channel.value([[id: "gtf"], gtf]) + // MapSplice cannot deal with extra field in the fasta headers + // this removes all additional fields in the headers of the input fasta file + if( params.tool.contains('mapsplice') && params.module.contains('circrna_discovery') ) { + + CLEAN_FASTA(fasta_tuple, []) + ch_fasta = CLEAN_FASTA.out.output + + } + // MapSplice & find_circ requires reference genome to be split per chromosome: if( ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) && params.module.contains('circrna_discovery') ){ directory = file("${params.outdir}/references/chromosomes") From 02a5eff888d8e078940456a8fe1bf3dada2a9557 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Mon, 19 Feb 2024 11:11:31 +0100 Subject: [PATCH 119/491] fix value channel for star index --- subworkflows/local/circrna_discovery.nf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 70aaf854..80ba9a19 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -85,10 +85,10 @@ workflow CIRCRNA_DISCOVERY { seq_center = params.seq_center ?: '' seq_platform = '' - STAR_1ST_PASS( reads, star_index, gtf_tuple, star_ignore_sjdbgtf, seq_platform, seq_center) + STAR_1ST_PASS( reads, star_index.first(), gtf_tuple, star_ignore_sjdbgtf, seq_platform, seq_center) sjdb = STAR_1ST_PASS.out.tab.map{ meta, tab -> return tab }.collect().map{[[id: "star_sjdb"], it]} STAR_SJDB( sjdb, bsj_reads ) - STAR_2ND_PASS( reads, star_index, STAR_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) + STAR_2ND_PASS( reads, star_index.first(), STAR_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) ch_versions = ch_versions.mix(STAR_1ST_PASS.out.versions) ch_versions = ch_versions.mix(STAR_2ND_PASS.out.versions) @@ -155,14 +155,14 @@ workflow CIRCRNA_DISCOVERY { // mate1 = reads.filter{ meta, reads -> !meta.single_end }.map{ meta, reads -> return [ [id: meta.id, single_end: true], reads[0] ] } - DCC_MATE1_1ST_PASS( mate1, star_index, gtf_tuple, star_ignore_sjdbgtf, seq_platform, seq_center ) + DCC_MATE1_1ST_PASS( mate1, star_index.first(), gtf_tuple, star_ignore_sjdbgtf, seq_platform, seq_center ) DCC_MATE1_SJDB( DCC_MATE1_1ST_PASS.out.tab.map{ meta, tab -> return tab }.collect().map{[[id: "mate1_sjdb"], it]}, bsj_reads ) - DCC_MATE1_2ND_PASS( mate1, star_index, DCC_MATE1_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) + DCC_MATE1_2ND_PASS( mate1, star_index.first(), DCC_MATE1_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) mate2 = reads.filter{ meta, reads -> !meta.single_end }.map{ meta, reads -> return [ [id: meta.id, single_end: true], reads[1] ] } - DCC_MATE2_1ST_PASS( mate2, star_index, gtf_tuple, star_ignore_sjdbgtf, seq_platform, seq_center ) + DCC_MATE2_1ST_PASS( mate2, star_index.first(), gtf_tuple, star_ignore_sjdbgtf, seq_platform, seq_center ) DCC_MATE2_SJDB( DCC_MATE2_1ST_PASS.out.tab.map{ meta, tab -> return tab }.collect().map{[[id: "mate2_sjdb"], it]}, bsj_reads ) - DCC_MATE2_2ND_PASS( mate2, star_index, DCC_MATE2_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) + DCC_MATE2_2ND_PASS( mate2, star_index.first(), DCC_MATE2_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) dcc_stage = STAR_2ND_PASS.out.junction.map{ meta, junction -> return [ meta.id, meta, junction]} .join( From 994176388040fa777ccfab60b5c52a82b6fec0dc Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Tue, 20 Feb 2024 14:55:33 +0100 Subject: [PATCH 120/491] resolve gawk bug, prefix/sufix issue and publish dir --- conf/modules.config | 9 ++++++--- modules/nf-core/gawk/main.nf | 4 ++-- subworkflows/local/prepare_genome.nf | 11 ++++++++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index d0b2e405..ec8ec07e 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -70,9 +70,12 @@ if (!params.skip_trimming) { // PREPARE GENOME withName: CLEAN_FASTA { ext.args2 = '\'/>/{ gsub(\$2, "",\$2);gsub(" ", "") };{print}\'' - ext.prefix = 'clean' - ext.suffix = 'fa' - + publishDir = [ + path: { "${params.outdir}/references/clean_fasta" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + enabled: params.save_reference + ] } withName: BOWTIE_BUILD { diff --git a/modules/nf-core/gawk/main.nf b/modules/nf-core/gawk/main.nf index a8f2f741..f856a1f8 100644 --- a/modules/nf-core/gawk/main.nf +++ b/modules/nf-core/gawk/main.nf @@ -12,7 +12,7 @@ process GAWK { path(program_file) output: - path("${prefix}.${suffix}"), emit: output + tuple val(meta), path("${prefix}.${suffix}"), emit: output path "versions.yml" , emit: versions when: @@ -22,7 +22,7 @@ process GAWK { def args = task.ext.args ?: '' // args is used for the main arguments of the tool def args2 = task.ext.args2 ?: '' // args2 is used to specify a program when no program file has been given prefix = task.ext.prefix ?: "${meta.id}" - suffix = task.ext.suffix ?: "${input.getExtension}" + suffix = task.ext.suffix ?: "${input.getExtension()}" program = program_file ? "-f ${program_file}" : "${args2}" diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index fb94ab3c..d35b6b5b 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -17,7 +17,6 @@ workflow PREPARE_GENOME { main: ch_versions = Channel.empty() - ch_fasta = Channel.fromPath(fasta) ch_gtf = Channel.fromPath(gtf) fasta_tuple = Channel.value([[id: "fasta"], fasta]) gtf_tuple = Channel.value([[id: "gtf"], gtf]) @@ -26,8 +25,14 @@ workflow PREPARE_GENOME { // this removes all additional fields in the headers of the input fasta file if( params.tool.contains('mapsplice') && params.module.contains('circrna_discovery') ) { - CLEAN_FASTA(fasta_tuple, []) - ch_fasta = CLEAN_FASTA.out.output + CLEAN_FASTA(Channel.value([[id: "${fasta.baseName}" + "_clean" ], fasta]), []) + + ch_fasta = CLEAN_FASTA.out.output.map{ it.last() } + } + + else { + + ch_fasta = Channel.fromPath(fasta) } From 9107e83f98cafcbc7ff3a2ac0ca93ac4fd4f0307 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Tue, 20 Feb 2024 15:28:12 +0000 Subject: [PATCH 121/491] Template update for nf-core/tools version 2.13 --- .editorconfig | 9 +- .github/workflows/awsfulltest.yml | 4 +- .github/workflows/awstest.yml | 4 +- .github/workflows/branch.yml | 2 +- .github/workflows/ci.yml | 7 +- .github/workflows/clean-up.yml | 2 +- .github/workflows/download_pipeline.yml | 17 +- .github/workflows/linting.yml | 12 +- .github/workflows/linting_comment.yml | 4 +- .github/workflows/release-announcements.yml | 11 +- README.md | 5 +- assets/multiqc_config.yml | 2 + assets/schema_input.json | 21 +- bin/check_samplesheet.py | 259 ----------- conf/modules.config | 8 - lib/NfcoreTemplate.groovy | 356 -------------- lib/Utils.groovy | 47 -- lib/WorkflowCircrna.groovy | 122 ----- lib/WorkflowMain.groovy | 77 --- main.nf | 100 ++-- modules.json | 28 +- modules/local/samplesheet_check.nf | 31 -- .../dumpsoftwareversions/environment.yml | 7 - .../custom/dumpsoftwareversions/main.nf | 24 - .../custom/dumpsoftwareversions/meta.yml | 37 -- .../templates/dumpsoftwareversions.py | 102 ---- .../dumpsoftwareversions/tests/main.nf.test | 43 -- .../tests/main.nf.test.snap | 33 -- .../dumpsoftwareversions/tests/tags.yml | 2 - modules/nf-core/fastqc/tests/main.nf.test | 14 +- .../nf-core/fastqc/tests/main.nf.test.snap | 76 ++- modules/nf-core/multiqc/environment.yml | 2 +- modules/nf-core/multiqc/main.nf | 4 +- modules/nf-core/multiqc/tests/main.nf.test | 13 +- .../nf-core/multiqc/tests/main.nf.test.snap | 32 +- nextflow.config | 5 +- nextflow_schema.json | 1 + pyproject.toml | 8 +- subworkflows/local/input_check.nf | 44 -- .../utils_nfcore_circrna_pipeline/main.nf | 247 ++++++++++ .../nf-core/utils_nextflow_pipeline/main.nf | 126 +++++ .../nf-core/utils_nextflow_pipeline/meta.yml | 38 ++ .../tests/main.function.nf.test | 54 +++ .../tests/main.function.nf.test.snap | 12 + .../tests/main.workflow.nf.test | 123 +++++ .../tests/nextflow.config | 9 + .../utils_nextflow_pipeline/tests/tags.yml | 2 + .../nf-core/utils_nfcore_pipeline/main.nf | 440 ++++++++++++++++++ .../nf-core/utils_nfcore_pipeline/meta.yml | 24 + .../tests/main.function.nf.test | 134 ++++++ .../tests/main.function.nf.test.snap | 138 ++++++ .../tests/main.workflow.nf.test | 29 ++ .../tests/main.workflow.nf.test.snap | 15 + .../tests/nextflow.config | 9 + .../utils_nfcore_pipeline/tests/tags.yml | 2 + .../nf-core/utils_nfvalidation_plugin/main.nf | 62 +++ .../utils_nfvalidation_plugin/meta.yml | 44 ++ .../tests/main.nf.test | 200 ++++++++ .../tests/nextflow_schema.json | 96 ++++ .../utils_nfvalidation_plugin/tests/tags.yml | 2 + workflows/circrna.nf | 133 ++---- 61 files changed, 2108 insertions(+), 1406 deletions(-) delete mode 100755 bin/check_samplesheet.py delete mode 100755 lib/NfcoreTemplate.groovy delete mode 100644 lib/Utils.groovy delete mode 100755 lib/WorkflowCircrna.groovy delete mode 100755 lib/WorkflowMain.groovy delete mode 100644 modules/local/samplesheet_check.nf delete mode 100644 modules/nf-core/custom/dumpsoftwareversions/environment.yml delete mode 100644 modules/nf-core/custom/dumpsoftwareversions/main.nf delete mode 100644 modules/nf-core/custom/dumpsoftwareversions/meta.yml delete mode 100755 modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py delete mode 100644 modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test delete mode 100644 modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap delete mode 100644 modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml delete mode 100644 subworkflows/local/input_check.nf create mode 100644 subworkflows/local/utils_nfcore_circrna_pipeline/main.nf create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/main.nf create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/meta.yml create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/main.nf create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/meta.yml create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml create mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/main.nf create mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/meta.yml create mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test create mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json create mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml diff --git a/.editorconfig b/.editorconfig index 9b990088..dd9ffa53 100644 --- a/.editorconfig +++ b/.editorconfig @@ -18,7 +18,12 @@ end_of_line = unset insert_final_newline = unset trim_trailing_whitespace = unset indent_style = unset -indent_size = unset +[/subworkflows/nf-core/**] +charset = unset +end_of_line = unset +insert_final_newline = unset +trim_trailing_whitespace = unset +indent_style = unset [/assets/email*] indent_size = unset @@ -28,5 +33,5 @@ indent_size = unset indent_style = unset # ignore python -[*.{py}] +[*.{py,md}] indent_style = unset diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 7b6bd16d..94521ebc 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Launch workflow via tower - uses: seqeralabs/action-tower-launch@v2 + uses: seqeralabs/action-tower-launch@922e5c8d5ac4e918107ec311d2ebbd65e5982b3d # v2 # TODO nf-core: You can customise AWS full pipeline tests as required # Add full size test data (but still relatively small datasets for few samples) # on the `test_full.config` test runs with only one set of parameters @@ -31,7 +31,7 @@ jobs: } profiles: test_full - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4 with: name: Tower debug log file path: | diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index 9590dcae..5307e9aa 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -12,7 +12,7 @@ jobs: steps: # Launch workflow using Tower CLI tool action - name: Launch workflow via tower - uses: seqeralabs/action-tower-launch@v2 + uses: seqeralabs/action-tower-launch@922e5c8d5ac4e918107ec311d2ebbd65e5982b3d # v2 with: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} @@ -25,7 +25,7 @@ jobs: } profiles: test - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4 with: name: Tower debug log file path: | diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index a9339b73..777845e7 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -19,7 +19,7 @@ jobs: # NOTE - this doesn't currently work if the PR is coming from a fork, due to limitations in GitHub actions secrets - name: Post PR comment if: failure() - uses: mshick/add-pr-comment@v2 + uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 with: message: | ## This PR is against the `master` branch :x: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0ac13e2..4e5754df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,13 +28,16 @@ jobs: - "latest-everything" steps: - name: Check out pipeline code - uses: actions/checkout@v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - name: Install Nextflow - uses: nf-core/setup-nextflow@v1 + uses: nf-core/setup-nextflow@b9f764e8ba5c76b712ace14ecbfcef0e40ae2dd8 # v1 with: version: "${{ matrix.NXF_VER }}" + - name: Disk space cleanup + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + - name: Run pipeline with test data # TODO nf-core: You can customise CI pipeline run tests as required # For example: adding multiple test runs with different parameters diff --git a/.github/workflows/clean-up.yml b/.github/workflows/clean-up.yml index e37cfda5..0b6b1f27 100644 --- a/.github/workflows/clean-up.yml +++ b/.github/workflows/clean-up.yml @@ -10,7 +10,7 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/stale@v9 + - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9 with: stale-issue-message: "This issue has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor. Remove stale label or add a comment otherwise this issue will be closed in 20 days." stale-pr-message: "This PR has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor. Remove stale label or add a comment if it is still useful." diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml index 8611458a..f823210d 100644 --- a/.github/workflows/download_pipeline.yml +++ b/.github/workflows/download_pipeline.yml @@ -6,6 +6,11 @@ name: Test successful pipeline download with 'nf-core download' # - the head branch of the pull request is updated, i.e. if fixes for a release are pushed last minute to dev. on: workflow_dispatch: + inputs: + testbranch: + description: "The specific branch you wish to utilize for the test execution of nf-core download." + required: true + default: "dev" pull_request: types: - opened @@ -23,13 +28,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Nextflow - uses: nf-core/setup-nextflow@v1 + uses: nf-core/setup-nextflow@b9f764e8ba5c76b712ace14ecbfcef0e40ae2dd8 # v1 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 with: python-version: "3.11" architecture: "x64" - - uses: eWaterCycle/setup-singularity@v7 + - uses: eWaterCycle/setup-singularity@931d4e31109e875b13309ae1d07c70ca8fbc8537 # v7 with: singularity-version: 3.8.3 @@ -42,13 +47,13 @@ jobs: run: | echo "REPO_LOWERCASE=${GITHUB_REPOSITORY,,}" >> ${GITHUB_ENV} echo "REPOTITLE_LOWERCASE=$(basename ${GITHUB_REPOSITORY,,})" >> ${GITHUB_ENV} - echo "REPO_BRANCH=${GITHUB_REF#refs/heads/}" >> ${GITHUB_ENV} + echo "REPO_BRANCH=${{ github.event.inputs.testbranch || 'dev' }}" >> ${GITHUB_ENV} - name: Download the pipeline env: NXF_SINGULARITY_CACHEDIR: ./ run: | - nf-core download ${{ env.REPO_LOWERCASE }} \ + nf-core download ${{ env.REPO_LOWERCASE }} \ --revision ${{ env.REPO_BRANCH }} \ --outdir ./${{ env.REPOTITLE_LOWERCASE }} \ --compress "none" \ @@ -64,4 +69,4 @@ jobs: env: NXF_SINGULARITY_CACHEDIR: ./ NXF_SINGULARITY_HOME_MOUNT: true - run: nextflow run ./${{ env.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ env.REPO_BRANCH }}) -stub -profile test,singularity --outdir ./results + run: nextflow run ./${{ env.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ env.REPO_BRANCH }}) -stub -profile test,singularity --outdir ./results diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 81cd098e..748b4311 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -14,10 +14,10 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - name: Set up Python 3.11 - uses: actions/setup-python@v5 + uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 with: python-version: 3.11 cache: "pip" @@ -32,12 +32,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out pipeline code - uses: actions/checkout@v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - name: Install Nextflow - uses: nf-core/setup-nextflow@v1 + uses: nf-core/setup-nextflow@b9f764e8ba5c76b712ace14ecbfcef0e40ae2dd8 # v1 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 with: python-version: "3.11" architecture: "x64" @@ -60,7 +60,7 @@ jobs: - name: Upload linting log file artifact if: ${{ always() }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4 with: name: linting-logs path: | diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index 147bcd10..b706875f 100644 --- a/.github/workflows/linting_comment.yml +++ b/.github/workflows/linting_comment.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download lint results - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@f6b0bace624032e30a85a8fd9c1a7f8f611f5737 # v3 with: workflow: linting.yml workflow_conclusion: completed @@ -21,7 +21,7 @@ jobs: run: echo "pr_number=$(cat linting-logs/PR_number.txt)" >> $GITHUB_OUTPUT - name: Post PR comment - uses: marocchino/sticky-pull-request-comment@v2 + uses: marocchino/sticky-pull-request-comment@331f8f5b4215f0445d3c07b4967662a32a2d3e31 # v2 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} number: ${{ steps.pr_number.outputs.pr_number }} diff --git a/.github/workflows/release-announcements.yml b/.github/workflows/release-announcements.yml index 21ac3f06..c3674af2 100644 --- a/.github/workflows/release-announcements.yml +++ b/.github/workflows/release-announcements.yml @@ -9,6 +9,11 @@ jobs: toot: runs-on: ubuntu-latest steps: + - name: get topics and convert to hashtags + id: get_topics + run: | + curl -s https://nf-co.re/pipelines.json | jq -r '.remote_workflows[] | select(.name == "${{ github.repository }}") | .topics[]' | awk '{print "#"$0}' | tr '\n' ' ' > $GITHUB_OUTPUT + - uses: rzr/fediverse-action@master with: access-token: ${{ secrets.MASTODON_ACCESS_TOKEN }} @@ -20,11 +25,13 @@ jobs: Please see the changelog: ${{ github.event.release.html_url }} + ${{ steps.get_topics.outputs.GITHUB_OUTPUT }} #nfcore #openscience #nextflow #bioinformatics + send-tweet: runs-on: ubuntu-latest steps: - - uses: actions/setup-python@v5 + - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 with: python-version: "3.10" - name: Install dependencies @@ -56,7 +63,7 @@ jobs: bsky-post: runs-on: ubuntu-latest steps: - - uses: zentered/bluesky-post-action@v0.1.0 + - uses: zentered/bluesky-post-action@80dbe0a7697de18c15ad22f4619919ceb5ccf597 # v0.1.0 with: post: | Pipeline release! ${{ github.repository }} v${{ github.event.release.tag_name }} - ${{ github.event.release.name }}! diff --git a/README.md b/README.md index 496a65ac..18919fd1 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,9 @@ nf-core/circrna -[![GitHub Actions CI Status](https://github.com/nf-core/circrna/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/circrna/actions?query=workflow%3A%22nf-core+CI%22) -[![GitHub Actions Linting Status](https://github.com/nf-core/circrna/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/circrna/actions?query=workflow%3A%22nf-core+linting%22)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/circrna/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) + +[![GitHub Actions CI Status](https://github.com/nf-core/circrna/actions/workflows/ci.yml/badge.svg)](https://github.com/nf-core/circrna/actions/workflows/ci.yml) +[![GitHub Actions Linting Status](https://github.com/nf-core/circrna/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/circrna/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/circrna/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) [![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A523.04.0-23aa62.svg)](https://www.nextflow.io/) [![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index 9a1b5bda..570f6c0d 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -11,3 +11,5 @@ report_section_order: order: -1002 export_plots: true + +disable_version_detection: true diff --git a/assets/schema_input.json b/assets/schema_input.json index 41716366..fe551cb8 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -10,25 +10,22 @@ "sample": { "type": "string", "pattern": "^\\S+$", - "errorMessage": "Sample name must be provided and cannot contain spaces" + "errorMessage": "Sample name must be provided and cannot contain spaces", + "meta": ["id"] }, "fastq_1": { "type": "string", + "format": "file-path", + "exists": true, "pattern": "^\\S+\\.f(ast)?q\\.gz$", "errorMessage": "FastQ file for reads 1 must be provided, cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz'" }, "fastq_2": { - "errorMessage": "FastQ file for reads 2 cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz'", - "anyOf": [ - { - "type": "string", - "pattern": "^\\S+\\.f(ast)?q\\.gz$" - }, - { - "type": "string", - "maxLength": 0 - } - ] + "type": "string", + "format": "file-path", + "exists": true, + "pattern": "^\\S+\\.f(ast)?q\\.gz$", + "errorMessage": "FastQ file for reads 2 cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz'" } }, "required": ["sample", "fastq_1"] diff --git a/bin/check_samplesheet.py b/bin/check_samplesheet.py deleted file mode 100755 index 4a758fe0..00000000 --- a/bin/check_samplesheet.py +++ /dev/null @@ -1,259 +0,0 @@ -#!/usr/bin/env python - - -"""Provide a command line tool to validate and transform tabular samplesheets.""" - - -import argparse -import csv -import logging -import sys -from collections import Counter -from pathlib import Path - -logger = logging.getLogger() - - -class RowChecker: - """ - Define a service that can validate and transform each given row. - - Attributes: - modified (list): A list of dicts, where each dict corresponds to a previously - validated and transformed row. The order of rows is maintained. - - """ - - VALID_FORMATS = ( - ".fq.gz", - ".fastq.gz", - ) - - def __init__( - self, - sample_col="sample", - first_col="fastq_1", - second_col="fastq_2", - single_col="single_end", - **kwargs, - ): - """ - Initialize the row checker with the expected column names. - - Args: - sample_col (str): The name of the column that contains the sample name - (default "sample"). - first_col (str): The name of the column that contains the first (or only) - FASTQ file path (default "fastq_1"). - second_col (str): The name of the column that contains the second (if any) - FASTQ file path (default "fastq_2"). - single_col (str): The name of the new column that will be inserted and - records whether the sample contains single- or paired-end sequencing - reads (default "single_end"). - - """ - super().__init__(**kwargs) - self._sample_col = sample_col - self._first_col = first_col - self._second_col = second_col - self._single_col = single_col - self._seen = set() - self.modified = [] - - def validate_and_transform(self, row): - """ - Perform all validations on the given row and insert the read pairing status. - - Args: - row (dict): A mapping from column headers (keys) to elements of that row - (values). - - """ - self._validate_sample(row) - self._validate_first(row) - self._validate_second(row) - self._validate_pair(row) - self._seen.add((row[self._sample_col], row[self._first_col])) - self.modified.append(row) - - def _validate_sample(self, row): - """Assert that the sample name exists and convert spaces to underscores.""" - if len(row[self._sample_col]) <= 0: - raise AssertionError("Sample input is required.") - # Sanitize samples slightly. - row[self._sample_col] = row[self._sample_col].replace(" ", "_") - - def _validate_first(self, row): - """Assert that the first FASTQ entry is non-empty and has the right format.""" - if len(row[self._first_col]) <= 0: - raise AssertionError("At least the first FASTQ file is required.") - self._validate_fastq_format(row[self._first_col]) - - def _validate_second(self, row): - """Assert that the second FASTQ entry has the right format if it exists.""" - if len(row[self._second_col]) > 0: - self._validate_fastq_format(row[self._second_col]) - - def _validate_pair(self, row): - """Assert that read pairs have the same file extension. Report pair status.""" - if row[self._first_col] and row[self._second_col]: - row[self._single_col] = False - first_col_suffix = Path(row[self._first_col]).suffixes[-2:] - second_col_suffix = Path(row[self._second_col]).suffixes[-2:] - if first_col_suffix != second_col_suffix: - raise AssertionError("FASTQ pairs must have the same file extensions.") - else: - row[self._single_col] = True - - def _validate_fastq_format(self, filename): - """Assert that a given filename has one of the expected FASTQ extensions.""" - if not any(filename.endswith(extension) for extension in self.VALID_FORMATS): - raise AssertionError( - f"The FASTQ file has an unrecognized extension: {filename}\n" - f"It should be one of: {', '.join(self.VALID_FORMATS)}" - ) - - def validate_unique_samples(self): - """ - Assert that the combination of sample name and FASTQ filename is unique. - - In addition to the validation, also rename all samples to have a suffix of _T{n}, where n is the - number of times the same sample exist, but with different FASTQ files, e.g., multiple runs per experiment. - - """ - if len(self._seen) != len(self.modified): - raise AssertionError("The pair of sample name and FASTQ must be unique.") - seen = Counter() - for row in self.modified: - sample = row[self._sample_col] - seen[sample] += 1 - row[self._sample_col] = f"{sample}_T{seen[sample]}" - - -def read_head(handle, num_lines=10): - """Read the specified number of lines from the current position in the file.""" - lines = [] - for idx, line in enumerate(handle): - if idx == num_lines: - break - lines.append(line) - return "".join(lines) - - -def sniff_format(handle): - """ - Detect the tabular format. - - Args: - handle (text file): A handle to a `text file`_ object. The read position is - expected to be at the beginning (index 0). - - Returns: - csv.Dialect: The detected tabular format. - - .. _text file: - https://docs.python.org/3/glossary.html#term-text-file - - """ - peek = read_head(handle) - handle.seek(0) - sniffer = csv.Sniffer() - dialect = sniffer.sniff(peek) - return dialect - - -def check_samplesheet(file_in, file_out): - """ - Check that the tabular samplesheet has the structure expected by nf-core pipelines. - - Validate the general shape of the table, expected columns, and each row. Also add - an additional column which records whether one or two FASTQ reads were found. - - Args: - file_in (pathlib.Path): The given tabular samplesheet. The format can be either - CSV, TSV, or any other format automatically recognized by ``csv.Sniffer``. - file_out (pathlib.Path): Where the validated and transformed samplesheet should - be created; always in CSV format. - - Example: - This function checks that the samplesheet follows the following structure, - see also the `viral recon samplesheet`_:: - - sample,fastq_1,fastq_2 - SAMPLE_PE,SAMPLE_PE_RUN1_1.fastq.gz,SAMPLE_PE_RUN1_2.fastq.gz - SAMPLE_PE,SAMPLE_PE_RUN2_1.fastq.gz,SAMPLE_PE_RUN2_2.fastq.gz - SAMPLE_SE,SAMPLE_SE_RUN1_1.fastq.gz, - - .. _viral recon samplesheet: - https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv - - """ - required_columns = {"sample", "fastq_1", "fastq_2"} - # See https://docs.python.org/3.9/library/csv.html#id3 to read up on `newline=""`. - with file_in.open(newline="") as in_handle: - reader = csv.DictReader(in_handle, dialect=sniff_format(in_handle)) - # Validate the existence of the expected header columns. - if not required_columns.issubset(reader.fieldnames): - req_cols = ", ".join(required_columns) - logger.critical(f"The sample sheet **must** contain these column headers: {req_cols}.") - sys.exit(1) - # Validate each row. - checker = RowChecker() - for i, row in enumerate(reader): - try: - checker.validate_and_transform(row) - except AssertionError as error: - logger.critical(f"{str(error)} On line {i + 2}.") - sys.exit(1) - checker.validate_unique_samples() - header = list(reader.fieldnames) - header.insert(1, "single_end") - # See https://docs.python.org/3.9/library/csv.html#id3 to read up on `newline=""`. - with file_out.open(mode="w", newline="") as out_handle: - writer = csv.DictWriter(out_handle, header, delimiter=",") - writer.writeheader() - for row in checker.modified: - writer.writerow(row) - - -def parse_args(argv=None): - """Define and immediately parse command line arguments.""" - parser = argparse.ArgumentParser( - description="Validate and transform a tabular samplesheet.", - epilog="Example: python check_samplesheet.py samplesheet.csv samplesheet.valid.csv", - ) - parser.add_argument( - "file_in", - metavar="FILE_IN", - type=Path, - help="Tabular input samplesheet in CSV or TSV format.", - ) - parser.add_argument( - "file_out", - metavar="FILE_OUT", - type=Path, - help="Transformed output samplesheet in CSV format.", - ) - parser.add_argument( - "-l", - "--log-level", - help="The desired log level (default WARNING).", - choices=("CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"), - default="WARNING", - ) - return parser.parse_args(argv) - - -def main(argv=None): - """Coordinate argument parsing and program execution.""" - args = parse_args(argv) - logging.basicConfig(level=args.log_level, format="[%(levelname)s] %(message)s") - if not args.file_in.is_file(): - logger.error(f"The given input file {args.file_in} was not found!") - sys.exit(2) - args.file_out.parent.mkdir(parents=True, exist_ok=True) - check_samplesheet(args.file_in, args.file_out) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/conf/modules.config b/conf/modules.config index d91c6aba..e3ea8fa6 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -18,14 +18,6 @@ process { saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] - withName: SAMPLESHEET_CHECK { - publishDir = [ - path: { "${params.outdir}/pipeline_info" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - withName: FASTQC { ext.args = '--quiet' } diff --git a/lib/NfcoreTemplate.groovy b/lib/NfcoreTemplate.groovy deleted file mode 100755 index e248e4c3..00000000 --- a/lib/NfcoreTemplate.groovy +++ /dev/null @@ -1,356 +0,0 @@ -// -// This file holds several functions used within the nf-core pipeline template. -// - -import org.yaml.snakeyaml.Yaml -import groovy.json.JsonOutput -import nextflow.extension.FilesEx - -class NfcoreTemplate { - - // - // Check AWS Batch related parameters have been specified correctly - // - public static void awsBatch(workflow, params) { - if (workflow.profile.contains('awsbatch')) { - // Check params.awsqueue and params.awsregion have been set if running on AWSBatch - assert (params.awsqueue && params.awsregion) : "Specify correct --awsqueue and --awsregion parameters on AWSBatch!" - // Check outdir paths to be S3 buckets if running on AWSBatch - assert params.outdir.startsWith('s3:') : "Outdir not on S3 - specify S3 Bucket to run on AWSBatch!" - } - } - - // - // Warn if a -profile or Nextflow config has not been provided to run the pipeline - // - public static void checkConfigProvided(workflow, log) { - if (workflow.profile == 'standard' && workflow.configFiles.size() <= 1) { - log.warn "[$workflow.manifest.name] You are attempting to run the pipeline without any custom configuration!\n\n" + - "This will be dependent on your local compute environment but can be achieved via one or more of the following:\n" + - " (1) Using an existing pipeline profile e.g. `-profile docker` or `-profile singularity`\n" + - " (2) Using an existing nf-core/configs for your Institution e.g. `-profile crick` or `-profile uppmax`\n" + - " (3) Using your own local custom config e.g. `-c /path/to/your/custom.config`\n\n" + - "Please refer to the quick start section and usage docs for the pipeline.\n " - } - } - - // - // Generate version string - // - public static String version(workflow) { - String version_string = "" - - if (workflow.manifest.version) { - def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : '' - version_string += "${prefix_v}${workflow.manifest.version}" - } - - if (workflow.commitId) { - def git_shortsha = workflow.commitId.substring(0, 7) - version_string += "-g${git_shortsha}" - } - - return version_string - } - - // - // Construct and send completion email - // - public static void email(workflow, params, summary_params, projectDir, log, multiqc_report=[]) { - - // Set up the e-mail variables - def subject = "[$workflow.manifest.name] Successful: $workflow.runName" - if (!workflow.success) { - subject = "[$workflow.manifest.name] FAILED: $workflow.runName" - } - - def summary = [:] - for (group in summary_params.keySet()) { - summary << summary_params[group] - } - - def misc_fields = [:] - misc_fields['Date Started'] = workflow.start - misc_fields['Date Completed'] = workflow.complete - misc_fields['Pipeline script file path'] = workflow.scriptFile - misc_fields['Pipeline script hash ID'] = workflow.scriptId - if (workflow.repository) misc_fields['Pipeline repository Git URL'] = workflow.repository - if (workflow.commitId) misc_fields['Pipeline repository Git Commit'] = workflow.commitId - if (workflow.revision) misc_fields['Pipeline Git branch/tag'] = workflow.revision - misc_fields['Nextflow Version'] = workflow.nextflow.version - misc_fields['Nextflow Build'] = workflow.nextflow.build - misc_fields['Nextflow Compile Timestamp'] = workflow.nextflow.timestamp - - def email_fields = [:] - email_fields['version'] = NfcoreTemplate.version(workflow) - email_fields['runName'] = workflow.runName - email_fields['success'] = workflow.success - email_fields['dateComplete'] = workflow.complete - email_fields['duration'] = workflow.duration - email_fields['exitStatus'] = workflow.exitStatus - email_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - email_fields['errorReport'] = (workflow.errorReport ?: 'None') - email_fields['commandLine'] = workflow.commandLine - email_fields['projectDir'] = workflow.projectDir - email_fields['summary'] = summary << misc_fields - - // On success try attach the multiqc report - def mqc_report = null - try { - if (workflow.success) { - mqc_report = multiqc_report.getVal() - if (mqc_report.getClass() == ArrayList && mqc_report.size() >= 1) { - if (mqc_report.size() > 1) { - log.warn "[$workflow.manifest.name] Found multiple reports from process 'MULTIQC', will use only one" - } - mqc_report = mqc_report[0] - } - } - } catch (all) { - if (multiqc_report) { - log.warn "[$workflow.manifest.name] Could not attach MultiQC report to summary email" - } - } - - // Check if we are only sending emails on failure - def email_address = params.email - if (!params.email && params.email_on_fail && !workflow.success) { - email_address = params.email_on_fail - } - - // Render the TXT template - def engine = new groovy.text.GStringTemplateEngine() - def tf = new File("$projectDir/assets/email_template.txt") - def txt_template = engine.createTemplate(tf).make(email_fields) - def email_txt = txt_template.toString() - - // Render the HTML template - def hf = new File("$projectDir/assets/email_template.html") - def html_template = engine.createTemplate(hf).make(email_fields) - def email_html = html_template.toString() - - // Render the sendmail template - def max_multiqc_email_size = (params.containsKey('max_multiqc_email_size') ? params.max_multiqc_email_size : 0) as nextflow.util.MemoryUnit - def smail_fields = [ email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "$projectDir", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes() ] - def sf = new File("$projectDir/assets/sendmail_template.txt") - def sendmail_template = engine.createTemplate(sf).make(smail_fields) - def sendmail_html = sendmail_template.toString() - - // Send the HTML e-mail - Map colors = logColours(params.monochrome_logs) - if (email_address) { - try { - if (params.plaintext_email) { throw GroovyException('Send plaintext e-mail, not HTML') } - // Try to send HTML e-mail using sendmail - def sendmail_tf = new File(workflow.launchDir.toString(), ".sendmail_tmp.html") - sendmail_tf.withWriter { w -> w << sendmail_html } - [ 'sendmail', '-t' ].execute() << sendmail_html - log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Sent summary e-mail to $email_address (sendmail)-" - } catch (all) { - // Catch failures and try with plaintext - def mail_cmd = [ 'mail', '-s', subject, '--content-type=text/html', email_address ] - if ( mqc_report != null && mqc_report.size() <= max_multiqc_email_size.toBytes() ) { - mail_cmd += [ '-A', mqc_report ] - } - mail_cmd.execute() << email_html - log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Sent summary e-mail to $email_address (mail)-" - } - } - - // Write summary e-mail HTML to a file - def output_hf = new File(workflow.launchDir.toString(), ".pipeline_report.html") - output_hf.withWriter { w -> w << email_html } - FilesEx.copyTo(output_hf.toPath(), "${params.outdir}/pipeline_info/pipeline_report.html"); - output_hf.delete() - - // Write summary e-mail TXT to a file - def output_tf = new File(workflow.launchDir.toString(), ".pipeline_report.txt") - output_tf.withWriter { w -> w << email_txt } - FilesEx.copyTo(output_tf.toPath(), "${params.outdir}/pipeline_info/pipeline_report.txt"); - output_tf.delete() - } - - // - // Construct and send a notification to a web server as JSON - // e.g. Microsoft Teams and Slack - // - public static void IM_notification(workflow, params, summary_params, projectDir, log) { - def hook_url = params.hook_url - - def summary = [:] - for (group in summary_params.keySet()) { - summary << summary_params[group] - } - - def misc_fields = [:] - misc_fields['start'] = workflow.start - misc_fields['complete'] = workflow.complete - misc_fields['scriptfile'] = workflow.scriptFile - misc_fields['scriptid'] = workflow.scriptId - if (workflow.repository) misc_fields['repository'] = workflow.repository - if (workflow.commitId) misc_fields['commitid'] = workflow.commitId - if (workflow.revision) misc_fields['revision'] = workflow.revision - misc_fields['nxf_version'] = workflow.nextflow.version - misc_fields['nxf_build'] = workflow.nextflow.build - misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp - - def msg_fields = [:] - msg_fields['version'] = NfcoreTemplate.version(workflow) - msg_fields['runName'] = workflow.runName - msg_fields['success'] = workflow.success - msg_fields['dateComplete'] = workflow.complete - msg_fields['duration'] = workflow.duration - msg_fields['exitStatus'] = workflow.exitStatus - msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - msg_fields['errorReport'] = (workflow.errorReport ?: 'None') - msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") - msg_fields['projectDir'] = workflow.projectDir - msg_fields['summary'] = summary << misc_fields - - // Render the JSON template - def engine = new groovy.text.GStringTemplateEngine() - // Different JSON depending on the service provider - // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format - def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" - def hf = new File("$projectDir/assets/${json_path}") - def json_template = engine.createTemplate(hf).make(msg_fields) - def json_message = json_template.toString() - - // POST - def post = new URL(hook_url).openConnection(); - post.setRequestMethod("POST") - post.setDoOutput(true) - post.setRequestProperty("Content-Type", "application/json") - post.getOutputStream().write(json_message.getBytes("UTF-8")); - def postRC = post.getResponseCode(); - if (! postRC.equals(200)) { - log.warn(post.getErrorStream().getText()); - } - } - - // - // Dump pipeline parameters in a json file - // - public static void dump_parameters(workflow, params) { - def timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') - def filename = "params_${timestamp}.json" - def temp_pf = new File(workflow.launchDir.toString(), ".${filename}") - def jsonStr = JsonOutput.toJson(params) - temp_pf.text = JsonOutput.prettyPrint(jsonStr) - - FilesEx.copyTo(temp_pf.toPath(), "${params.outdir}/pipeline_info/params_${timestamp}.json") - temp_pf.delete() - } - - // - // Print pipeline summary on completion - // - public static void summary(workflow, params, log) { - Map colors = logColours(params.monochrome_logs) - if (workflow.success) { - if (workflow.stats.ignoredCount == 0) { - log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Pipeline completed successfully${colors.reset}-" - } else { - log.info "-${colors.purple}[$workflow.manifest.name]${colors.yellow} Pipeline completed successfully, but with errored process(es) ${colors.reset}-" - } - } else { - log.info "-${colors.purple}[$workflow.manifest.name]${colors.red} Pipeline completed with errors${colors.reset}-" - } - } - - // - // ANSII Colours used for terminal logging - // - public static Map logColours(Boolean monochrome_logs) { - Map colorcodes = [:] - - // Reset / Meta - colorcodes['reset'] = monochrome_logs ? '' : "\033[0m" - colorcodes['bold'] = monochrome_logs ? '' : "\033[1m" - colorcodes['dim'] = monochrome_logs ? '' : "\033[2m" - colorcodes['underlined'] = monochrome_logs ? '' : "\033[4m" - colorcodes['blink'] = monochrome_logs ? '' : "\033[5m" - colorcodes['reverse'] = monochrome_logs ? '' : "\033[7m" - colorcodes['hidden'] = monochrome_logs ? '' : "\033[8m" - - // Regular Colors - colorcodes['black'] = monochrome_logs ? '' : "\033[0;30m" - colorcodes['red'] = monochrome_logs ? '' : "\033[0;31m" - colorcodes['green'] = monochrome_logs ? '' : "\033[0;32m" - colorcodes['yellow'] = monochrome_logs ? '' : "\033[0;33m" - colorcodes['blue'] = monochrome_logs ? '' : "\033[0;34m" - colorcodes['purple'] = monochrome_logs ? '' : "\033[0;35m" - colorcodes['cyan'] = monochrome_logs ? '' : "\033[0;36m" - colorcodes['white'] = monochrome_logs ? '' : "\033[0;37m" - - // Bold - colorcodes['bblack'] = monochrome_logs ? '' : "\033[1;30m" - colorcodes['bred'] = monochrome_logs ? '' : "\033[1;31m" - colorcodes['bgreen'] = monochrome_logs ? '' : "\033[1;32m" - colorcodes['byellow'] = monochrome_logs ? '' : "\033[1;33m" - colorcodes['bblue'] = monochrome_logs ? '' : "\033[1;34m" - colorcodes['bpurple'] = monochrome_logs ? '' : "\033[1;35m" - colorcodes['bcyan'] = monochrome_logs ? '' : "\033[1;36m" - colorcodes['bwhite'] = monochrome_logs ? '' : "\033[1;37m" - - // Underline - colorcodes['ublack'] = monochrome_logs ? '' : "\033[4;30m" - colorcodes['ured'] = monochrome_logs ? '' : "\033[4;31m" - colorcodes['ugreen'] = monochrome_logs ? '' : "\033[4;32m" - colorcodes['uyellow'] = monochrome_logs ? '' : "\033[4;33m" - colorcodes['ublue'] = monochrome_logs ? '' : "\033[4;34m" - colorcodes['upurple'] = monochrome_logs ? '' : "\033[4;35m" - colorcodes['ucyan'] = monochrome_logs ? '' : "\033[4;36m" - colorcodes['uwhite'] = monochrome_logs ? '' : "\033[4;37m" - - // High Intensity - colorcodes['iblack'] = monochrome_logs ? '' : "\033[0;90m" - colorcodes['ired'] = monochrome_logs ? '' : "\033[0;91m" - colorcodes['igreen'] = monochrome_logs ? '' : "\033[0;92m" - colorcodes['iyellow'] = monochrome_logs ? '' : "\033[0;93m" - colorcodes['iblue'] = monochrome_logs ? '' : "\033[0;94m" - colorcodes['ipurple'] = monochrome_logs ? '' : "\033[0;95m" - colorcodes['icyan'] = monochrome_logs ? '' : "\033[0;96m" - colorcodes['iwhite'] = monochrome_logs ? '' : "\033[0;97m" - - // Bold High Intensity - colorcodes['biblack'] = monochrome_logs ? '' : "\033[1;90m" - colorcodes['bired'] = monochrome_logs ? '' : "\033[1;91m" - colorcodes['bigreen'] = monochrome_logs ? '' : "\033[1;92m" - colorcodes['biyellow'] = monochrome_logs ? '' : "\033[1;93m" - colorcodes['biblue'] = monochrome_logs ? '' : "\033[1;94m" - colorcodes['bipurple'] = monochrome_logs ? '' : "\033[1;95m" - colorcodes['bicyan'] = monochrome_logs ? '' : "\033[1;96m" - colorcodes['biwhite'] = monochrome_logs ? '' : "\033[1;97m" - - return colorcodes - } - - // - // Does what is says on the tin - // - public static String dashedLine(monochrome_logs) { - Map colors = logColours(monochrome_logs) - return "-${colors.dim}----------------------------------------------------${colors.reset}-" - } - - // - // nf-core logo - // - public static String logo(workflow, monochrome_logs) { - Map colors = logColours(monochrome_logs) - String workflow_version = NfcoreTemplate.version(workflow) - String.format( - """\n - ${dashedLine(monochrome_logs)} - ${colors.green},--.${colors.black}/${colors.green},-.${colors.reset} - ${colors.blue} ___ __ __ __ ___ ${colors.green}/,-._.--~\'${colors.reset} - ${colors.blue} |\\ | |__ __ / ` / \\ |__) |__ ${colors.yellow}} {${colors.reset} - ${colors.blue} | \\| | \\__, \\__/ | \\ |___ ${colors.green}\\`-._,-`-,${colors.reset} - ${colors.green}`._,._,\'${colors.reset} - ${colors.purple} ${workflow.manifest.name} ${workflow_version}${colors.reset} - ${dashedLine(monochrome_logs)} - """.stripIndent() - ) - } -} diff --git a/lib/Utils.groovy b/lib/Utils.groovy deleted file mode 100644 index 8d030f4e..00000000 --- a/lib/Utils.groovy +++ /dev/null @@ -1,47 +0,0 @@ -// -// This file holds several Groovy functions that could be useful for any Nextflow pipeline -// - -import org.yaml.snakeyaml.Yaml - -class Utils { - - // - // When running with -profile conda, warn if channels have not been set-up appropriately - // - public static void checkCondaChannels(log) { - Yaml parser = new Yaml() - def channels = [] - try { - def config = parser.load("conda config --show channels".execute().text) - channels = config.channels - } catch(NullPointerException | IOException e) { - log.warn "Could not verify conda channel configuration." - return - } - - // Check that all channels are present - // This channel list is ordered by required channel priority. - def required_channels_in_order = ['conda-forge', 'bioconda', 'defaults'] - def channels_missing = ((required_channels_in_order as Set) - (channels as Set)) as Boolean - - // Check that they are in the right order - def channel_priority_violation = false - def n = required_channels_in_order.size() - for (int i = 0; i < n - 1; i++) { - channel_priority_violation |= !(channels.indexOf(required_channels_in_order[i]) < channels.indexOf(required_channels_in_order[i+1])) - } - - if (channels_missing | channel_priority_violation) { - log.warn "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + - " There is a problem with your Conda configuration!\n\n" + - " You will need to set-up the conda-forge and bioconda channels correctly.\n" + - " Please refer to https://bioconda.github.io/\n" + - " The observed channel order is \n" + - " ${channels}\n" + - " but the following channel order is required:\n" + - " ${required_channels_in_order}\n" + - "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - } - } -} diff --git a/lib/WorkflowCircrna.groovy b/lib/WorkflowCircrna.groovy deleted file mode 100755 index eae29c19..00000000 --- a/lib/WorkflowCircrna.groovy +++ /dev/null @@ -1,122 +0,0 @@ -// -// This file holds several functions specific to the workflow/circrna.nf in the nf-core/circrna pipeline -// - -import nextflow.Nextflow -import groovy.text.SimpleTemplateEngine - -class WorkflowCircrna { - - // - // Check and validate parameters - // - public static void initialise(params, log) { - - genomeExistsError(params, log) - - - if (!params.fasta) { - Nextflow.error "Genome fasta file not specified with e.g. '--fasta genome.fa' or via a detectable config file." - } - } - - // - // Get workflow summary for MultiQC - // - public static String paramsSummaryMultiqc(workflow, summary) { - String summary_section = '' - for (group in summary.keySet()) { - def group_params = summary.get(group) // This gets the parameters of that particular group - if (group_params) { - summary_section += "

    $group

    \n" - summary_section += "
    \n" - for (param in group_params.keySet()) { - summary_section += "
    $param
    ${group_params.get(param) ?: 'N/A'}
    \n" - } - summary_section += "
    \n" - } - } - - String yaml_file_text = "id: '${workflow.manifest.name.replace('/','-')}-summary'\n" - yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n" - yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n" - yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n" - yaml_file_text += "plot_type: 'html'\n" - yaml_file_text += "data: |\n" - yaml_file_text += "${summary_section}" - return yaml_file_text - } - - // - // Generate methods description for MultiQC - // - - public static String toolCitationText(params) { - - // TODO nf-core: Optionally add in-text citation tools to this list. - // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "", - // Uncomment function in methodsDescriptionText to render in MultiQC report - def citation_text = [ - "Tools used in the workflow included:", - "FastQC (Andrews 2010),", - "MultiQC (Ewels et al. 2016)", - "." - ].join(' ').trim() - - return citation_text - } - - public static String toolBibliographyText(params) { - - // TODO Optionally add bibliographic entries to this list. - // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "
  • Author (2023) Pub name, Journal, DOI
  • " : "", - // Uncomment function in methodsDescriptionText to render in MultiQC report - def reference_text = [ - "
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", - "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " - ].join(' ').trim() - - return reference_text - } - - public static String methodsDescriptionText(run_workflow, mqc_methods_yaml, params) { - // Convert to a named map so can be used as with familar NXF ${workflow} variable syntax in the MultiQC YML file - def meta = [:] - meta.workflow = run_workflow.toMap() - meta["manifest_map"] = run_workflow.manifest.toMap() - - // Pipeline DOI - meta["doi_text"] = meta.manifest_map.doi ? "(doi: ${meta.manifest_map.doi})" : "" - meta["nodoi_text"] = meta.manifest_map.doi ? "": "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " - - // Tool references - meta["tool_citations"] = "" - meta["tool_bibliography"] = "" - - // TODO Only uncomment below if logic in toolCitationText/toolBibliographyText has been filled! - //meta["tool_citations"] = toolCitationText(params).replaceAll(", \\.", ".").replaceAll("\\. \\.", ".").replaceAll(", \\.", ".") - //meta["tool_bibliography"] = toolBibliographyText(params) - - - def methods_text = mqc_methods_yaml.text - - def engine = new SimpleTemplateEngine() - def description_html = engine.createTemplate(methods_text).make(meta) - - return description_html - } - - // - // Exit pipeline if incorrect --genome key provided - // - private static void genomeExistsError(params, log) { - if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { - def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + - " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + - " Currently, the available genome keys are:\n" + - " ${params.genomes.keySet().join(", ")}\n" + - "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - Nextflow.error(error_string) - } - } -} diff --git a/lib/WorkflowMain.groovy b/lib/WorkflowMain.groovy deleted file mode 100755 index 79426ea9..00000000 --- a/lib/WorkflowMain.groovy +++ /dev/null @@ -1,77 +0,0 @@ -// -// This file holds several functions specific to the main.nf workflow in the nf-core/circrna pipeline -// - -import nextflow.Nextflow - -class WorkflowMain { - - // - // Citation string for pipeline - // - public static String citation(workflow) { - return "If you use ${workflow.manifest.name} for your analysis please cite:\n\n" + - // TODO nf-core: Add Zenodo DOI for pipeline after first release - //"* The pipeline\n" + - //" https://doi.org/10.5281/zenodo.XXXXXXX\n\n" + - "* The nf-core framework\n" + - " https://doi.org/10.1038/s41587-020-0439-x\n\n" + - "* Software dependencies\n" + - " https://github.com/${workflow.manifest.name}/blob/master/CITATIONS.md" - } - - - // - // Validate parameters and print summary to screen - // - public static void initialise(workflow, params, log, args) { - - // Print workflow version and exit on --version - if (params.version) { - String workflow_version = NfcoreTemplate.version(workflow) - log.info "${workflow.manifest.name} ${workflow_version}" - System.exit(0) - } - - // Check that a -profile or Nextflow config has been provided to run the pipeline - NfcoreTemplate.checkConfigProvided(workflow, log) - // Check that the profile doesn't contain spaces and doesn't end with a trailing comma - checkProfile(workflow.profile, args, log) - - // Check that conda channels are set-up correctly - if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - Utils.checkCondaChannels(log) - } - - // Check AWS batch settings - NfcoreTemplate.awsBatch(workflow, params) - - // Check input has been provided - if (!params.input) { - Nextflow.error("Please provide an input samplesheet to the pipeline e.g. '--input samplesheet.csv'") - } - } - // - // Get attribute from genome config file e.g. fasta - // - public static Object getGenomeAttribute(params, attribute) { - if (params.genomes && params.genome && params.genomes.containsKey(params.genome)) { - if (params.genomes[ params.genome ].containsKey(attribute)) { - return params.genomes[ params.genome ][ attribute ] - } - } - return null - } - - // - // Exit pipeline if --profile contains spaces - // - private static void checkProfile(profile, args, log) { - if (profile.endsWith(',')) { - Nextflow.error "Profile cannot end with a trailing comma. Please remove the comma from the end of the profile string.\nHint: A common mistake is to provide multiple values to `-profile` separated by spaces. Please use commas to separate profiles instead,e.g., `-profile docker,test`." - } - if (args[0]) { - log.warn "nf-core pipelines do not accept positional arguments. The positional argument `${args[0]}` has been detected.\n Hint: A common mistake is to provide multiple values to `-profile` separated by spaces. Please use commas to separate profiles instead,e.g., `-profile docker,test`." - } - } -} diff --git a/main.nf b/main.nf index 32aabbc7..810b3959 100644 --- a/main.nf +++ b/main.nf @@ -13,66 +13,96 @@ nextflow.enable.dsl = 2 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - GENOME PARAMETER VALUES + IMPORT FUNCTIONS / MODULES / SUBWORKFLOWS / WORKFLOWS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -// TODO nf-core: Remove this line if you don't need a FASTA file -// This is an example of how to use getGenomeAttribute() to fetch parameters -// from igenomes.config using `--genome` -params.fasta = WorkflowMain.getGenomeAttribute(params, 'fasta') +include { CIRCRNA } from './workflows/circrna' +include { PIPELINE_INITIALISATION } from './subworkflows/local/utils_nfcore_circrna_pipeline' +include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_circrna_pipeline' + +include { getGenomeAttribute } from './subworkflows/local/utils_nfcore_circrna_pipeline' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - VALIDATE & PRINT PARAMETER SUMMARY + GENOME PARAMETER VALUES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { validateParameters; paramsHelp } from 'plugin/nf-validation' - -// Print help message if needed -if (params.help) { - def logo = NfcoreTemplate.logo(workflow, params.monochrome_logs) - def citation = '\n' + WorkflowMain.citation(workflow) + '\n' - def String command = "nextflow run ${workflow.manifest.name} --input samplesheet.csv --genome GRCh37 -profile docker" - log.info logo + paramsHelp(command) + citation + NfcoreTemplate.dashedLine(params.monochrome_logs) - System.exit(0) -} - -// Validate input parameters -if (params.validate_params) { - validateParameters() -} - -WorkflowMain.initialise(workflow, params, log, args) +// TODO nf-core: Remove this line if you don't need a FASTA file +// This is an example of how to use getGenomeAttribute() to fetch parameters +// from igenomes.config using `--genome` +params.fasta = getGenomeAttribute('fasta') /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - NAMED WORKFLOW FOR PIPELINE + NAMED WORKFLOWS FOR PIPELINE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { CIRCRNA } from './workflows/circrna' - // -// WORKFLOW: Run main nf-core/circrna analysis pipeline +// WORKFLOW: Run main analysis pipeline depending on type of input // workflow NFCORE_CIRCRNA { - CIRCRNA () -} + take: + samplesheet // channel: samplesheet read in from --input + + main: + + // + // WORKFLOW: Run pipeline + // + CIRCRNA ( + samplesheet + ) + + emit: + multiqc_report = CIRCRNA.out.multiqc_report // channel: /path/to/multiqc_report.html + +} /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - RUN ALL WORKFLOWS + RUN MAIN WORKFLOW ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -// -// WORKFLOW: Execute a single named workflow for the pipeline -// See: https://github.com/nf-core/rnaseq/issues/619 -// workflow { - NFCORE_CIRCRNA () + + main: + + // + // SUBWORKFLOW: Run initialisation tasks + // + PIPELINE_INITIALISATION ( + params.version, + params.help, + params.validate_params, + params.monochrome_logs, + args, + params.outdir, + params.input + ) + + // + // WORKFLOW: Run main workflow + // + NFCORE_CIRCRNA ( + PIPELINE_INITIALISATION.out.samplesheet + ) + + // + // SUBWORKFLOW: Run completion tasks + // + PIPELINE_COMPLETION ( + params.email, + params.email_on_fail, + params.plaintext_email, + params.outdir, + params.monochrome_logs, + params.hook_url, + NFCORE_CIRCRNA.out.multiqc_report + ) } /* diff --git a/modules.json b/modules.json index 67813eca..8cca7fba 100644 --- a/modules.json +++ b/modules.json @@ -5,22 +5,36 @@ "https://github.com/nf-core/modules.git": { "modules": { "nf-core": { - "custom/dumpsoftwareversions": { - "branch": "master", - "git_sha": "8ec825f465b9c17f9d83000022995b4f7de6fe93", - "installed_by": ["modules"] - }, "fastqc": { "branch": "master", - "git_sha": "c9488585ce7bd35ccd2a30faa2371454c8112fb9", + "git_sha": "f4ae1d942bd50c5c0b9bd2de1393ce38315ba57c", "installed_by": ["modules"] }, "multiqc": { "branch": "master", - "git_sha": "8ec825f465b9c17f9d83000022995b4f7de6fe93", + "git_sha": "ccacf6f5de6df3bc6d73b665c1fd2933d8bbc290", "installed_by": ["modules"] } } + }, + "subworkflows": { + "nf-core": { + "utils_nextflow_pipeline": { + "branch": "master", + "git_sha": "cd08c91373cd00a73255081340e4914485846ba1", + "installed_by": ["subworkflows"] + }, + "utils_nfcore_pipeline": { + "branch": "master", + "git_sha": "262b17ed2aad591039f914951659177e6c39a8d8", + "installed_by": ["subworkflows"] + }, + "utils_nfvalidation_plugin": { + "branch": "master", + "git_sha": "cd08c91373cd00a73255081340e4914485846ba1", + "installed_by": ["subworkflows"] + } + } } } } diff --git a/modules/local/samplesheet_check.nf b/modules/local/samplesheet_check.nf deleted file mode 100644 index e102f46d..00000000 --- a/modules/local/samplesheet_check.nf +++ /dev/null @@ -1,31 +0,0 @@ -process SAMPLESHEET_CHECK { - tag "$samplesheet" - label 'process_single' - - conda "conda-forge::python=3.8.3" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/python:3.8.3' : - 'biocontainers/python:3.8.3' }" - - input: - path samplesheet - - output: - path '*.csv' , emit: csv - path "versions.yml", emit: versions - - when: - task.ext.when == null || task.ext.when - - script: // This script is bundled with the pipeline, in nf-core/circrna/bin/ - """ - check_samplesheet.py \\ - $samplesheet \\ - samplesheet.valid.csv - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - python: \$(python --version | sed 's/Python //g') - END_VERSIONS - """ -} diff --git a/modules/nf-core/custom/dumpsoftwareversions/environment.yml b/modules/nf-core/custom/dumpsoftwareversions/environment.yml deleted file mode 100644 index 9b3272bc..00000000 --- a/modules/nf-core/custom/dumpsoftwareversions/environment.yml +++ /dev/null @@ -1,7 +0,0 @@ -name: custom_dumpsoftwareversions -channels: - - conda-forge - - bioconda - - defaults -dependencies: - - bioconda::multiqc=1.19 diff --git a/modules/nf-core/custom/dumpsoftwareversions/main.nf b/modules/nf-core/custom/dumpsoftwareversions/main.nf deleted file mode 100644 index f2187611..00000000 --- a/modules/nf-core/custom/dumpsoftwareversions/main.nf +++ /dev/null @@ -1,24 +0,0 @@ -process CUSTOM_DUMPSOFTWAREVERSIONS { - label 'process_single' - - // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.19--pyhdfd78af_0' : - 'biocontainers/multiqc:1.19--pyhdfd78af_0' }" - - input: - path versions - - output: - path "software_versions.yml" , emit: yml - path "software_versions_mqc.yml", emit: mqc_yml - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - template 'dumpsoftwareversions.py' -} diff --git a/modules/nf-core/custom/dumpsoftwareversions/meta.yml b/modules/nf-core/custom/dumpsoftwareversions/meta.yml deleted file mode 100644 index 5f15a5fd..00000000 --- a/modules/nf-core/custom/dumpsoftwareversions/meta.yml +++ /dev/null @@ -1,37 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json -name: custom_dumpsoftwareversions -description: Custom module used to dump software versions within the nf-core pipeline template -keywords: - - custom - - dump - - version -tools: - - custom: - description: Custom module used to dump software versions within the nf-core pipeline template - homepage: https://github.com/nf-core/tools - documentation: https://github.com/nf-core/tools - licence: ["MIT"] -input: - - versions: - type: file - description: YML file containing software versions - pattern: "*.yml" -output: - - yml: - type: file - description: Standard YML file containing software versions - pattern: "software_versions.yml" - - mqc_yml: - type: file - description: MultiQC custom content YML file containing software versions - pattern: "software_versions_mqc.yml" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" -authors: - - "@drpatelh" - - "@grst" -maintainers: - - "@drpatelh" - - "@grst" diff --git a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py deleted file mode 100755 index e55b8d43..00000000 --- a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python - - -"""Provide functions to merge multiple versions.yml files.""" - - -import platform -from textwrap import dedent - -import yaml - - -def _make_versions_html(versions): - """Generate a tabular HTML output of all versions for MultiQC.""" - html = [ - dedent( - """\\ - -
    Process Name \\", + " \\ Software Version
    CUSTOM_DUMPSOFTWAREVERSIONSpython3.11.7
    yaml5.4.1
    TOOL1tool10.11.9
    TOOL2tool21.9
    WorkflowNextflow
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    - - - - - - - - """ - ) - ] - for process, tmp_versions in sorted(versions.items()): - html.append("") - for i, (tool, version) in enumerate(sorted(tmp_versions.items())): - html.append( - dedent( - f"""\\ - - - - - - """ - ) - ) - html.append("") - html.append("
    Process Name Software Version
    {process if (i == 0) else ''}{tool}{version}
    ") - return "\\n".join(html) - - -def main(): - """Load all version files and generate merged output.""" - versions_this_module = {} - versions_this_module["${task.process}"] = { - "python": platform.python_version(), - "yaml": yaml.__version__, - } - - with open("$versions") as f: - versions_by_process = yaml.load(f, Loader=yaml.BaseLoader) | versions_this_module - - # aggregate versions by the module name (derived from fully-qualified process name) - versions_by_module = {} - for process, process_versions in versions_by_process.items(): - module = process.split(":")[-1] - try: - if versions_by_module[module] != process_versions: - raise AssertionError( - "We assume that software versions are the same between all modules. " - "If you see this error-message it means you discovered an edge-case " - "and should open an issue in nf-core/tools. " - ) - except KeyError: - versions_by_module[module] = process_versions - - versions_by_module["Workflow"] = { - "Nextflow": "$workflow.nextflow.version", - "$workflow.manifest.name": "$workflow.manifest.version", - } - - versions_mqc = { - "id": "software_versions", - "section_name": "${workflow.manifest.name} Software Versions", - "section_href": "https://github.com/${workflow.manifest.name}", - "plot_type": "html", - "description": "are collected at run time from the software output.", - "data": _make_versions_html(versions_by_module), - } - - with open("software_versions.yml", "w") as f: - yaml.dump(versions_by_module, f, default_flow_style=False) - with open("software_versions_mqc.yml", "w") as f: - yaml.dump(versions_mqc, f, default_flow_style=False) - - with open("versions.yml", "w") as f: - yaml.dump(versions_this_module, f, default_flow_style=False) - - -if __name__ == "__main__": - main() diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test deleted file mode 100644 index b1e1630b..00000000 --- a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test +++ /dev/null @@ -1,43 +0,0 @@ -nextflow_process { - - name "Test Process CUSTOM_DUMPSOFTWAREVERSIONS" - script "../main.nf" - process "CUSTOM_DUMPSOFTWAREVERSIONS" - tag "modules" - tag "modules_nfcore" - tag "custom" - tag "dumpsoftwareversions" - tag "custom/dumpsoftwareversions" - - test("Should run without failures") { - when { - process { - """ - def tool1_version = ''' - TOOL1: - tool1: 0.11.9 - '''.stripIndent() - - def tool2_version = ''' - TOOL2: - tool2: 1.9 - '''.stripIndent() - - input[0] = Channel.of(tool1_version, tool2_version).collectFile() - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot( - process.out.versions, - file(process.out.mqc_yml[0]).readLines()[0..10], - file(process.out.yml[0]).readLines()[0..7] - ).match() - } - ) - } - } -} diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap deleted file mode 100644 index 5f59a936..00000000 --- a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap +++ /dev/null @@ -1,33 +0,0 @@ -{ - "Should run without failures": { - "content": [ - [ - "versions.yml:md5,76d454d92244589d32455833f7c1ba6d" - ], - [ - "data: \"\\n\\n \\n \\n \\n \\n \\n \\n \\n\\", - " \\n\\n\\n \\n \\n\\", - " \\ \\n\\n\\n\\n \\n \\", - " \\ \\n \\n\\n\\n\\n\\", - " \\n\\n \\n \\n\\", - " \\ \\n\\n\\n\\n\\n\\n \\n\\", - " \\ \\n \\n\\n\\n\\n\\", - " \\n\\n \\n \\n\\" - ], - [ - "CUSTOM_DUMPSOFTWAREVERSIONS:", - " python: 3.11.7", - " yaml: 5.4.1", - "TOOL1:", - " tool1: 0.11.9", - "TOOL2:", - " tool2: '1.9'", - "Workflow:" - ] - ], - "timestamp": "2024-01-09T23:01:18.710682" - } -} \ No newline at end of file diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml b/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml deleted file mode 100644 index 405aa24a..00000000 --- a/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -custom/dumpsoftwareversions: - - modules/nf-core/custom/dumpsoftwareversions/** diff --git a/modules/nf-core/fastqc/tests/main.nf.test b/modules/nf-core/fastqc/tests/main.nf.test index 1f21c664..70edae4d 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test +++ b/modules/nf-core/fastqc/tests/main.nf.test @@ -33,7 +33,7 @@ nextflow_process { { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, { assert path(process.out.html[0][1]).text.contains("") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("fastqc_versions_single") } ) } } @@ -63,7 +63,7 @@ nextflow_process { { assert path(process.out.html[0][1][0]).text.contains("") }, { assert path(process.out.html[0][1][1]).text.contains("") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("fastqc_versions_paired") } ) } } @@ -89,7 +89,7 @@ nextflow_process { { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, { assert path(process.out.html[0][1]).text.contains("") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("fastqc_versions_interleaved") } ) } } @@ -115,7 +115,7 @@ nextflow_process { { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, { assert path(process.out.html[0][1]).text.contains("") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("fastqc_versions_bam") } ) } } @@ -153,7 +153,7 @@ nextflow_process { { assert path(process.out.html[0][1][2]).text.contains("") }, { assert path(process.out.html[0][1][3]).text.contains("") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("fastqc_versions_multiple") } ) } } @@ -179,7 +179,7 @@ nextflow_process { { assert process.out.zip[0][1] ==~ ".*/mysample_fastqc.zip" }, { assert path(process.out.html[0][1]).text.contains("") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("fastqc_versions_custom_prefix") } ) } } @@ -204,7 +204,7 @@ nextflow_process { { assert process.success }, { assert snapshot(process.out.html.collect { file(it[1]).getName() } + process.out.zip.collect { file(it[1]).getName() } + - process.out.versions ).match() } + process.out.versions ).match("fastqc_stub") } ) } } diff --git a/modules/nf-core/fastqc/tests/main.nf.test.snap b/modules/nf-core/fastqc/tests/main.nf.test.snap index 5d624bb8..86f7c311 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test.snap +++ b/modules/nf-core/fastqc/tests/main.nf.test.snap @@ -1,5 +1,17 @@ { - "sarscov2 single-end [fastq] - stub": { + "fastqc_versions_interleaved": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-01-31T17:40:07.293713" + }, + "fastqc_stub": { "content": [ [ "test.html", @@ -7,14 +19,70 @@ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], - "timestamp": "2024-01-17T18:40:57.254299" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-01-31T17:31:01.425198" + }, + "fastqc_versions_multiple": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-01-31T17:40:55.797907" + }, + "fastqc_versions_bam": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-01-31T17:40:26.795862" + }, + "fastqc_versions_single": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-01-31T17:39:27.043675" + }, + "fastqc_versions_paired": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-01-31T17:39:47.584191" }, - "versions": { + "fastqc_versions_custom_prefix": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], - "timestamp": "2024-01-17T18:36:50.033627" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-01-31T17:41:14.576531" } } \ No newline at end of file diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index 7625b752..2212096a 100644 --- a/modules/nf-core/multiqc/environment.yml +++ b/modules/nf-core/multiqc/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - bioconda::multiqc=1.19 + - bioconda::multiqc=1.20 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 1b9f7c43..354f4430 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -3,8 +3,8 @@ process MULTIQC { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.19--pyhdfd78af_0' : - 'biocontainers/multiqc:1.19--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.20--pyhdfd78af_0' : + 'biocontainers/multiqc:1.20--pyhdfd78af_0' }" input: path multiqc_files, stageAs: "?/*" diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test index d0438eda..f1c4242e 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -3,6 +3,7 @@ nextflow_process { name "Test Process MULTIQC" script "../main.nf" process "MULTIQC" + tag "modules" tag "modules_nfcore" tag "multiqc" @@ -12,7 +13,7 @@ nextflow_process { when { process { """ - input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)]) + input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) input[1] = [] input[2] = [] input[3] = [] @@ -25,7 +26,7 @@ nextflow_process { { assert process.success }, { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("multiqc_versions_single") } ) } @@ -36,7 +37,7 @@ nextflow_process { when { process { """ - input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)]) + input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) input[1] = Channel.of(file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true)) input[2] = [] input[3] = [] @@ -49,7 +50,7 @@ nextflow_process { { assert process.success }, { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("multiqc_versions_config") } ) } } @@ -61,7 +62,7 @@ nextflow_process { when { process { """ - input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)]) + input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) input[1] = [] input[2] = [] input[3] = [] @@ -75,7 +76,7 @@ nextflow_process { { assert snapshot(process.out.report.collect { file(it).getName() } + process.out.data.collect { file(it).getName() } + process.out.plots.collect { file(it).getName() } + - process.out.versions ).match() } + process.out.versions ).match("multiqc_stub") } ) } diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap index d37e7304..c204b488 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -1,21 +1,41 @@ { - "versions": { + "multiqc_versions_single": { "content": [ [ - "versions.yml:md5,14e9a2661241abd828f4f06a7b5c222d" + "versions.yml:md5,d320d4c37e349c5588e07e7a31cd4186" ] ], - "timestamp": "2024-01-09T23:02:49.911994" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-14T09:28:51.744211298" }, - "sarscov2 single-end [fastqc] - stub": { + "multiqc_stub": { "content": [ [ "multiqc_report.html", "multiqc_data", "multiqc_plots", - "versions.yml:md5,14e9a2661241abd828f4f06a7b5c222d" + "versions.yml:md5,d320d4c37e349c5588e07e7a31cd4186" ] ], - "timestamp": "2024-01-09T23:03:14.524346" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-14T09:29:28.847433492" + }, + "multiqc_versions_config": { + "content": [ + [ + "versions.yml:md5,d320d4c37e349c5588e07e7a31cd4186" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-14T09:29:13.223621555" } } \ No newline at end of file diff --git a/nextflow.config b/nextflow.config index 4d098309..564acf64 100644 --- a/nextflow.config +++ b/nextflow.config @@ -16,9 +16,7 @@ params { genome = null igenomes_base = 's3://ngi-igenomes/igenomes/' igenomes_ignore = false - - - // MultiQC options + fasta = null// MultiQC options multiqc_config = null multiqc_title = null multiqc_logo = null @@ -43,7 +41,6 @@ params { custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" config_profile_contact = null config_profile_url = null - // Max resource options // Defaults only, expecting to be overwritten diff --git a/nextflow_schema.json b/nextflow_schema.json index 075e8b33..01ffcd21 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -16,6 +16,7 @@ "type": "string", "format": "file-path", "exists": true, + "schema": "assets/schema_input.json", "mimetype": "text/csv", "pattern": "^\\S+\\.csv$", "description": "Path to comma-separated file containing information about the samples in the experiment.", diff --git a/pyproject.toml b/pyproject.toml index 7d08e1c8..56110621 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,11 +3,13 @@ [tool.ruff] line-length = 120 target-version = "py38" -select = ["I", "E1", "E4", "E7", "E9", "F", "UP", "N"] cache-dir = "~/.cache/ruff" -[tool.ruff.isort] +[tool.ruff.lint] +select = ["I", "E1", "E4", "E7", "E9", "F", "UP", "N"] + +[tool.ruff.lint.isort] known-first-party = ["nf_core"] -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "__init__.py" = ["E402", "F401"] diff --git a/subworkflows/local/input_check.nf b/subworkflows/local/input_check.nf deleted file mode 100644 index 0aecf87f..00000000 --- a/subworkflows/local/input_check.nf +++ /dev/null @@ -1,44 +0,0 @@ -// -// Check input samplesheet and get read channels -// - -include { SAMPLESHEET_CHECK } from '../../modules/local/samplesheet_check' - -workflow INPUT_CHECK { - take: - samplesheet // file: /path/to/samplesheet.csv - - main: - SAMPLESHEET_CHECK ( samplesheet ) - .csv - .splitCsv ( header:true, sep:',' ) - .map { create_fastq_channel(it) } - .set { reads } - - emit: - reads // channel: [ val(meta), [ reads ] ] - versions = SAMPLESHEET_CHECK.out.versions // channel: [ versions.yml ] -} - -// Function to get list of [ meta, [ fastq_1, fastq_2 ] ] -def create_fastq_channel(LinkedHashMap row) { - // create meta map - def meta = [:] - meta.id = row.sample - meta.single_end = row.single_end.toBoolean() - - // add path(s) of the fastq file(s) to the meta map - def fastq_meta = [] - if (!file(row.fastq_1).exists()) { - exit 1, "ERROR: Please check input samplesheet -> Read 1 FastQ file does not exist!\n${row.fastq_1}" - } - if (meta.single_end) { - fastq_meta = [ meta, [ file(row.fastq_1) ] ] - } else { - if (!file(row.fastq_2).exists()) { - exit 1, "ERROR: Please check input samplesheet -> Read 2 FastQ file does not exist!\n${row.fastq_2}" - } - fastq_meta = [ meta, [ file(row.fastq_1), file(row.fastq_2) ] ] - } - return fastq_meta -} diff --git a/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf b/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf new file mode 100644 index 00000000..dc90ad90 --- /dev/null +++ b/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf @@ -0,0 +1,247 @@ +// +// Subworkflow with functionality specific to the nf-core/pipeline pipeline +// + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + IMPORT FUNCTIONS / MODULES / SUBWORKFLOWS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +include { UTILS_NFVALIDATION_PLUGIN } from '../../nf-core/utils_nfvalidation_plugin' +include { paramsSummaryMap } from 'plugin/nf-validation' +include { fromSamplesheet } from 'plugin/nf-validation' +include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' +include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' +include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' +include { dashedLine } from '../../nf-core/utils_nfcore_pipeline' +include { nfCoreLogo } from '../../nf-core/utils_nfcore_pipeline' +include { imNotification } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' +include { workflowCitation } from '../../nf-core/utils_nfcore_pipeline' + +/* +======================================================================================== + SUBWORKFLOW TO INITIALISE PIPELINE +======================================================================================== +*/ + +workflow PIPELINE_INITIALISATION { + + take: + version // boolean: Display version and exit + help // boolean: Display help text + validate_params // boolean: Boolean whether to validate parameters against the schema at runtime + monochrome_logs // boolean: Do not use coloured log outputs + nextflow_cli_args // array: List of positional nextflow CLI args + outdir // string: The output directory where the results will be saved + input // string: Path to input samplesheet + + main: + + ch_versions = Channel.empty() + + // + // Print version and exit if required and dump pipeline parameters to JSON file + // + UTILS_NEXTFLOW_PIPELINE ( + version, + true, + outdir, + workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1 + ) + + // + // Validate parameters and generate parameter summary to stdout + // + pre_help_text = nfCoreLogo(monochrome_logs) + post_help_text = '\n' + workflowCitation() + '\n' + dashedLine(monochrome_logs) + def String workflow_command = "nextflow run ${workflow.manifest.name} -profile --input samplesheet.csv --outdir " + UTILS_NFVALIDATION_PLUGIN ( + help, + workflow_command, + pre_help_text, + post_help_text, + validate_params, + "nextflow_schema.json" + ) + + // + // Check config provided to the pipeline + // + UTILS_NFCORE_PIPELINE ( + nextflow_cli_args + ) + // + // Custom validation for pipeline parameters + // + validateInputParameters() + + // + // Create channel from input file provided through params.input + // + Channel + .fromSamplesheet("input") + .map { + meta, fastq_1, fastq_2 -> + if (!fastq_2) { + return [ meta.id, meta + [ single_end:true ], [ fastq_1 ] ] + } else { + return [ meta.id, meta + [ single_end:false ], [ fastq_1, fastq_2 ] ] + } + } + .groupTuple() + .map { + validateInputSamplesheet(it) + } + .map { + meta, fastqs -> + return [ meta, fastqs.flatten() ] + } + .set { ch_samplesheet } + + emit: + samplesheet = ch_samplesheet + versions = ch_versions +} + +/* +======================================================================================== + SUBWORKFLOW FOR PIPELINE COMPLETION +======================================================================================== +*/ + +workflow PIPELINE_COMPLETION { + + take: + email // string: email address + email_on_fail // string: email address sent on pipeline failure + plaintext_email // boolean: Send plain-text email instead of HTML + outdir // path: Path to output directory where results will be published + monochrome_logs // boolean: Disable ANSI colour codes in log output + hook_url // string: hook URL for notifications + multiqc_report // string: Path to MultiQC report + + main: + + summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") + + // + // Completion email and summary + // + workflow.onComplete { + if (email || email_on_fail) { + completionEmail(summary_params, email, email_on_fail, plaintext_email, outdir, monochrome_logs, multiqc_report.toList()) + } + + completionSummary(monochrome_logs) + + if (hook_url) { + imNotification(summary_params, hook_url) + } + } +} + +/* +======================================================================================== + FUNCTIONS +======================================================================================== +*/ +// +// Check and validate pipeline parameters +// +def validateInputParameters() { + genomeExistsError() +}// +// Validate channels from input samplesheet +// +def validateInputSamplesheet(input) { + def (metas, fastqs) = input[1..2] + + // Check that multiple runs of the same sample are of the same datatype i.e. single-end / paired-end + def endedness_ok = metas.collect{ it.single_end }.unique().size == 1 + if (!endedness_ok) { + error("Please check input samplesheet -> Multiple runs of a sample must be of the same datatype i.e. single-end or paired-end: ${metas[0].id}") + } + + return [ metas[0], fastqs ] +} +// +// Get attribute from genome config file e.g. fasta +// +def getGenomeAttribute(attribute) { + if (params.genomes && params.genome && params.genomes.containsKey(params.genome)) { + if (params.genomes[ params.genome ].containsKey(attribute)) { + return params.genomes[ params.genome ][ attribute ] + } + } + return null +} + +// +// Exit pipeline if incorrect --genome key provided +// +def genomeExistsError() { + if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { + def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + + " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + + " Currently, the available genome keys are:\n" + + " ${params.genomes.keySet().join(", ")}\n" + + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + error(error_string) + } +}// +// Generate methods description for MultiQC +// +def toolCitationText() { + // TODO nf-core: Optionally add in-text citation tools to this list. + // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "", + // Uncomment function in methodsDescriptionText to render in MultiQC report + def citation_text = [ + "Tools used in the workflow included:", + "FastQC (Andrews 2010),", + "MultiQC (Ewels et al. 2016)", + "." + ].join(' ').trim() + + return citation_text +} + +def toolBibliographyText() { + // TODO nf-core: Optionally add bibliographic entries to this list. + // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "
  • Author (2023) Pub name, Journal, DOI
  • " : "", + // Uncomment function in methodsDescriptionText to render in MultiQC report + def reference_text = [ + "
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", + "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " + ].join(' ').trim() + + return reference_text +} + +def methodsDescriptionText(mqc_methods_yaml) { + // Convert to a named map so can be used as with familar NXF ${workflow} variable syntax in the MultiQC YML file + def meta = [:] + meta.workflow = workflow.toMap() + meta["manifest_map"] = workflow.manifest.toMap() + + // Pipeline DOI + meta["doi_text"] = meta.manifest_map.doi ? "(doi: ${meta.manifest_map.doi})" : "" + meta["nodoi_text"] = meta.manifest_map.doi ? "": "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " + + // Tool references + meta["tool_citations"] = "" + meta["tool_bibliography"] = "" + + // TODO nf-core: Only uncomment below if logic in toolCitationText/toolBibliographyText has been filled! + // meta["tool_citations"] = toolCitationText().replaceAll(", \\.", ".").replaceAll("\\. \\.", ".").replaceAll(", \\.", ".") + // meta["tool_bibliography"] = toolBibliographyText() + + + def methods_text = mqc_methods_yaml.text + + def engine = new groovy.text.SimpleTemplateEngine() + def description_html = engine.createTemplate(methods_text).make(meta) + + return description_html.toString() +} diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf new file mode 100644 index 00000000..ac31f28f --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf @@ -0,0 +1,126 @@ +// +// Subworkflow with functionality that may be useful for any Nextflow pipeline +// + +import org.yaml.snakeyaml.Yaml +import groovy.json.JsonOutput +import nextflow.extension.FilesEx + +/* +======================================================================================== + SUBWORKFLOW DEFINITION +======================================================================================== +*/ + +workflow UTILS_NEXTFLOW_PIPELINE { + + take: + print_version // boolean: print version + dump_parameters // boolean: dump parameters + outdir // path: base directory used to publish pipeline results + check_conda_channels // boolean: check conda channels + + main: + + // + // Print workflow version and exit on --version + // + if (print_version) { + log.info "${workflow.manifest.name} ${getWorkflowVersion()}" + System.exit(0) + } + + // + // Dump pipeline parameters to a JSON file + // + if (dump_parameters && outdir) { + dumpParametersToJSON(outdir) + } + + // + // When running with Conda, warn if channels have not been set-up appropriately + // + if (check_conda_channels) { + checkCondaChannels() + } + + emit: + dummy_emit = true +} + +/* +======================================================================================== + FUNCTIONS +======================================================================================== +*/ + +// +// Generate version string +// +def getWorkflowVersion() { + String version_string = "" + if (workflow.manifest.version) { + def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : '' + version_string += "${prefix_v}${workflow.manifest.version}" + } + + if (workflow.commitId) { + def git_shortsha = workflow.commitId.substring(0, 7) + version_string += "-g${git_shortsha}" + } + + return version_string +} + +// +// Dump pipeline parameters to a JSON file +// +def dumpParametersToJSON(outdir) { + def timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') + def filename = "params_${timestamp}.json" + def temp_pf = new File(workflow.launchDir.toString(), ".${filename}") + def jsonStr = JsonOutput.toJson(params) + temp_pf.text = JsonOutput.prettyPrint(jsonStr) + + FilesEx.copyTo(temp_pf.toPath(), "${outdir}/pipeline_info/params_${timestamp}.json") + temp_pf.delete() +} + +// +// When running with -profile conda, warn if channels have not been set-up appropriately +// +def checkCondaChannels() { + Yaml parser = new Yaml() + def channels = [] + try { + def config = parser.load("conda config --show channels".execute().text) + channels = config.channels + } catch(NullPointerException | IOException e) { + log.warn "Could not verify conda channel configuration." + return + } + + // Check that all channels are present + // This channel list is ordered by required channel priority. + def required_channels_in_order = ['conda-forge', 'bioconda', 'defaults'] + def channels_missing = ((required_channels_in_order as Set) - (channels as Set)) as Boolean + + // Check that they are in the right order + def channel_priority_violation = false + def n = required_channels_in_order.size() + for (int i = 0; i < n - 1; i++) { + channel_priority_violation |= !(channels.indexOf(required_channels_in_order[i]) < channels.indexOf(required_channels_in_order[i+1])) + } + + if (channels_missing | channel_priority_violation) { + log.warn "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + + " There is a problem with your Conda configuration!\n\n" + + " You will need to set-up the conda-forge and bioconda channels correctly.\n" + + " Please refer to https://bioconda.github.io/\n" + + " The observed channel order is \n" + + " ${channels}\n" + + " but the following channel order is required:\n" + + " ${required_channels_in_order}\n" + + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + } +} diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/meta.yml b/subworkflows/nf-core/utils_nextflow_pipeline/meta.yml new file mode 100644 index 00000000..e5c3a0a8 --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/meta.yml @@ -0,0 +1,38 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "UTILS_NEXTFLOW_PIPELINE" +description: Subworkflow with functionality that may be useful for any Nextflow pipeline +keywords: + - utility + - pipeline + - initialise + - version +components: [] +input: + - print_version: + type: boolean + description: | + Print the version of the pipeline and exit + - dump_parameters: + type: boolean + description: | + Dump the parameters of the pipeline to a JSON file + - output_directory: + type: directory + description: Path to output dir to write JSON file to. + pattern: "results/" + - check_conda_channel: + type: boolean + description: | + Check if the conda channel priority is correct. +output: + - dummy_emit: + type: boolean + description: | + Dummy emit to make nf-core subworkflows lint happy +authors: + - "@adamrtalbot" + - "@drpatelh" +maintainers: + - "@adamrtalbot" + - "@drpatelh" + - "@maxulysse" diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test new file mode 100644 index 00000000..8ed4310c --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test @@ -0,0 +1,54 @@ + +nextflow_function { + + name "Test Functions" + script "subworkflows/nf-core/utils_nextflow_pipeline/main.nf" + config "subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config" + tag 'subworkflows' + tag 'utils_nextflow_pipeline' + tag 'subworkflows/utils_nextflow_pipeline' + + test("Test Function getWorkflowVersion") { + + function "getWorkflowVersion" + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function dumpParametersToJSON") { + + function "dumpParametersToJSON" + + when { + function { + """ + // define inputs of the function here. Example: + input[0] = "$outputDir" + """.stripIndent() + } + } + + then { + assertAll( + { assert function.success } + ) + } + } + + test("Test Function checkCondaChannels") { + + function "checkCondaChannels" + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap new file mode 100644 index 00000000..db2030f8 --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap @@ -0,0 +1,12 @@ +{ + "Test Function getWorkflowVersion": { + "content": [ + "v9.9.9" + ], + "timestamp": "2024-01-19T11:32:36.031083" + }, + "Test Function checkCondaChannels": { + "content": null, + "timestamp": "2024-01-19T11:32:50.456" + } +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test new file mode 100644 index 00000000..f7c54bc6 --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test @@ -0,0 +1,123 @@ +nextflow_workflow { + + name "Test Workflow UTILS_NEXTFLOW_PIPELINE" + script "../main.nf" + config "subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config" + workflow "UTILS_NEXTFLOW_PIPELINE" + tag 'subworkflows' + tag 'utils_nextflow_pipeline' + tag 'subworkflows/utils_nextflow_pipeline' + + test("Should run no inputs") { + + when { + params { + outdir = "tests/results" + } + workflow { + """ + print_version = false + dump_parameters = false + outdir = null + check_conda_channels = false + + input[0] = print_version + input[1] = dump_parameters + input[2] = outdir + input[3] = check_conda_channels + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } + + test("Should print version") { + + when { + params { + outdir = "tests/results" + } + workflow { + """ + print_version = true + dump_parameters = false + outdir = null + check_conda_channels = false + + input[0] = print_version + input[1] = dump_parameters + input[2] = outdir + input[3] = check_conda_channels + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert workflow.stdout.contains("nextflow_workflow v9.9.9") } + ) + } + } + + test("Should dump params") { + + when { + params { + outdir = "$outputDir" + } + workflow { + """ + print_version = false + dump_parameters = true + outdir = params.outdir + check_conda_channels = false + + input[0] = false + input[1] = true + input[2] = params.outdir + input[3] = false + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } + + test("Should not create params JSON if no output directory") { + + when { + params { + outdir = "$outputDir" + } + workflow { + """ + print_version = false + dump_parameters = true + outdir = params.outdir + check_conda_channels = false + + input[0] = false + input[1] = true + input[2] = null + input[3] = false + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } +} diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config b/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config new file mode 100644 index 00000000..53574ffe --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config @@ -0,0 +1,9 @@ +manifest { + name = 'nextflow_workflow' + author = """nf-core""" + homePage = 'https://127.0.0.1' + description = """Dummy pipeline""" + nextflowVersion = '!>=23.04.0' + version = '9.9.9' + doi = 'https://doi.org/10.5281/zenodo.5070524' +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml b/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml new file mode 100644 index 00000000..f8476112 --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml @@ -0,0 +1,2 @@ +subworkflows/utils_nextflow_pipeline: + - subworkflows/nf-core/utils_nextflow_pipeline/** diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf new file mode 100644 index 00000000..a8b55d6f --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -0,0 +1,440 @@ +// +// Subworkflow with utility functions specific to the nf-core pipeline template +// + +import org.yaml.snakeyaml.Yaml +import nextflow.extension.FilesEx + +/* +======================================================================================== + SUBWORKFLOW DEFINITION +======================================================================================== +*/ + +workflow UTILS_NFCORE_PIPELINE { + + take: + nextflow_cli_args + + main: + valid_config = checkConfigProvided() + checkProfileProvided(nextflow_cli_args) + + emit: + valid_config +} + +/* +======================================================================================== + FUNCTIONS +======================================================================================== +*/ + +// +// Warn if a -profile or Nextflow config has not been provided to run the pipeline +// +def checkConfigProvided() { + valid_config = true + if (workflow.profile == 'standard' && workflow.configFiles.size() <= 1) { + log.warn "[$workflow.manifest.name] You are attempting to run the pipeline without any custom configuration!\n\n" + + "This will be dependent on your local compute environment but can be achieved via one or more of the following:\n" + + " (1) Using an existing pipeline profile e.g. `-profile docker` or `-profile singularity`\n" + + " (2) Using an existing nf-core/configs for your Institution e.g. `-profile crick` or `-profile uppmax`\n" + + " (3) Using your own local custom config e.g. `-c /path/to/your/custom.config`\n\n" + + "Please refer to the quick start section and usage docs for the pipeline.\n " + valid_config = false + } + return valid_config +} + +// +// Exit pipeline if --profile contains spaces +// +def checkProfileProvided(nextflow_cli_args) { + if (workflow.profile.endsWith(',')) { + error "The `-profile` option cannot end with a trailing comma, please remove it and re-run the pipeline!\n" + + "HINT: A common mistake is to provide multiple values separated by spaces e.g. `-profile test, docker`.\n" + } + if (nextflow_cli_args[0]) { + log.warn "nf-core pipelines do not accept positional arguments. The positional argument `${nextflow_cli_args[0]}` has been detected.\n" + + "HINT: A common mistake is to provide multiple values separated by spaces e.g. `-profile test, docker`.\n" + } +} + +// +// Citation string for pipeline +// +def workflowCitation() { + return "If you use ${workflow.manifest.name} for your analysis please cite:\n\n" + + "* The pipeline\n" + + " ${workflow.manifest.doi}\n\n" + + "* The nf-core framework\n" + + " https://doi.org/10.1038/s41587-020-0439-x\n\n" + + "* Software dependencies\n" + + " https://github.com/${workflow.manifest.name}/blob/master/CITATIONS.md" +} + +// +// Generate workflow version string +// +def getWorkflowVersion() { + String version_string = "" + if (workflow.manifest.version) { + def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : '' + version_string += "${prefix_v}${workflow.manifest.version}" + } + + if (workflow.commitId) { + def git_shortsha = workflow.commitId.substring(0, 7) + version_string += "-g${git_shortsha}" + } + + return version_string +} + +// +// Get software versions for pipeline +// +def processVersionsFromYAML(yaml_file) { + Yaml yaml = new Yaml() + versions = yaml.load(yaml_file).collectEntries { k, v -> [ k.tokenize(':')[-1], v ] } + return yaml.dumpAsMap(versions).trim() +} + +// +// Get workflow version for pipeline +// +def workflowVersionToYAML() { + return """ + Workflow: + $workflow.manifest.name: ${getWorkflowVersion()} + Nextflow: $workflow.nextflow.version + """.stripIndent().trim() +} + +// +// Get channel of software versions used in pipeline in YAML format +// +def softwareVersionsToYAML(ch_versions) { + return ch_versions + .unique() + .map { processVersionsFromYAML(it) } + .unique() + .mix(Channel.of(workflowVersionToYAML())) +} + +// +// Get workflow summary for MultiQC +// +def paramsSummaryMultiqc(summary_params) { + def summary_section = '' + for (group in summary_params.keySet()) { + def group_params = summary_params.get(group) // This gets the parameters of that particular group + if (group_params) { + summary_section += "

    $group

    \n" + summary_section += "
    \n" + for (param in group_params.keySet()) { + summary_section += "
    $param
    ${group_params.get(param) ?: 'N/A'}
    \n" + } + summary_section += "
    \n" + } + } + + String yaml_file_text = "id: '${workflow.manifest.name.replace('/','-')}-summary'\n" + yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n" + yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n" + yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n" + yaml_file_text += "plot_type: 'html'\n" + yaml_file_text += "data: |\n" + yaml_file_text += "${summary_section}" + + return yaml_file_text +} + +// +// nf-core logo +// +def nfCoreLogo(monochrome_logs=true) { + Map colors = logColours(monochrome_logs) + String.format( + """\n + ${dashedLine(monochrome_logs)} + ${colors.green},--.${colors.black}/${colors.green},-.${colors.reset} + ${colors.blue} ___ __ __ __ ___ ${colors.green}/,-._.--~\'${colors.reset} + ${colors.blue} |\\ | |__ __ / ` / \\ |__) |__ ${colors.yellow}} {${colors.reset} + ${colors.blue} | \\| | \\__, \\__/ | \\ |___ ${colors.green}\\`-._,-`-,${colors.reset} + ${colors.green}`._,._,\'${colors.reset} + ${colors.purple} ${workflow.manifest.name} ${getWorkflowVersion()}${colors.reset} + ${dashedLine(monochrome_logs)} + """.stripIndent() + ) +} + +// +// Return dashed line +// +def dashedLine(monochrome_logs=true) { + Map colors = logColours(monochrome_logs) + return "-${colors.dim}----------------------------------------------------${colors.reset}-" +} + +// +// ANSII colours used for terminal logging +// +def logColours(monochrome_logs=true) { + Map colorcodes = [:] + + // Reset / Meta + colorcodes['reset'] = monochrome_logs ? '' : "\033[0m" + colorcodes['bold'] = monochrome_logs ? '' : "\033[1m" + colorcodes['dim'] = monochrome_logs ? '' : "\033[2m" + colorcodes['underlined'] = monochrome_logs ? '' : "\033[4m" + colorcodes['blink'] = monochrome_logs ? '' : "\033[5m" + colorcodes['reverse'] = monochrome_logs ? '' : "\033[7m" + colorcodes['hidden'] = monochrome_logs ? '' : "\033[8m" + + // Regular Colors + colorcodes['black'] = monochrome_logs ? '' : "\033[0;30m" + colorcodes['red'] = monochrome_logs ? '' : "\033[0;31m" + colorcodes['green'] = monochrome_logs ? '' : "\033[0;32m" + colorcodes['yellow'] = monochrome_logs ? '' : "\033[0;33m" + colorcodes['blue'] = monochrome_logs ? '' : "\033[0;34m" + colorcodes['purple'] = monochrome_logs ? '' : "\033[0;35m" + colorcodes['cyan'] = monochrome_logs ? '' : "\033[0;36m" + colorcodes['white'] = monochrome_logs ? '' : "\033[0;37m" + + // Bold + colorcodes['bblack'] = monochrome_logs ? '' : "\033[1;30m" + colorcodes['bred'] = monochrome_logs ? '' : "\033[1;31m" + colorcodes['bgreen'] = monochrome_logs ? '' : "\033[1;32m" + colorcodes['byellow'] = monochrome_logs ? '' : "\033[1;33m" + colorcodes['bblue'] = monochrome_logs ? '' : "\033[1;34m" + colorcodes['bpurple'] = monochrome_logs ? '' : "\033[1;35m" + colorcodes['bcyan'] = monochrome_logs ? '' : "\033[1;36m" + colorcodes['bwhite'] = monochrome_logs ? '' : "\033[1;37m" + + // Underline + colorcodes['ublack'] = monochrome_logs ? '' : "\033[4;30m" + colorcodes['ured'] = monochrome_logs ? '' : "\033[4;31m" + colorcodes['ugreen'] = monochrome_logs ? '' : "\033[4;32m" + colorcodes['uyellow'] = monochrome_logs ? '' : "\033[4;33m" + colorcodes['ublue'] = monochrome_logs ? '' : "\033[4;34m" + colorcodes['upurple'] = monochrome_logs ? '' : "\033[4;35m" + colorcodes['ucyan'] = monochrome_logs ? '' : "\033[4;36m" + colorcodes['uwhite'] = monochrome_logs ? '' : "\033[4;37m" + + // High Intensity + colorcodes['iblack'] = monochrome_logs ? '' : "\033[0;90m" + colorcodes['ired'] = monochrome_logs ? '' : "\033[0;91m" + colorcodes['igreen'] = monochrome_logs ? '' : "\033[0;92m" + colorcodes['iyellow'] = monochrome_logs ? '' : "\033[0;93m" + colorcodes['iblue'] = monochrome_logs ? '' : "\033[0;94m" + colorcodes['ipurple'] = monochrome_logs ? '' : "\033[0;95m" + colorcodes['icyan'] = monochrome_logs ? '' : "\033[0;96m" + colorcodes['iwhite'] = monochrome_logs ? '' : "\033[0;97m" + + // Bold High Intensity + colorcodes['biblack'] = monochrome_logs ? '' : "\033[1;90m" + colorcodes['bired'] = monochrome_logs ? '' : "\033[1;91m" + colorcodes['bigreen'] = monochrome_logs ? '' : "\033[1;92m" + colorcodes['biyellow'] = monochrome_logs ? '' : "\033[1;93m" + colorcodes['biblue'] = monochrome_logs ? '' : "\033[1;94m" + colorcodes['bipurple'] = monochrome_logs ? '' : "\033[1;95m" + colorcodes['bicyan'] = monochrome_logs ? '' : "\033[1;96m" + colorcodes['biwhite'] = monochrome_logs ? '' : "\033[1;97m" + + return colorcodes +} + +// +// Attach the multiqc report to email +// +def attachMultiqcReport(multiqc_report) { + def mqc_report = null + try { + if (workflow.success) { + mqc_report = multiqc_report.getVal() + if (mqc_report.getClass() == ArrayList && mqc_report.size() >= 1) { + if (mqc_report.size() > 1) { + log.warn "[$workflow.manifest.name] Found multiple reports from process 'MULTIQC', will use only one" + } + mqc_report = mqc_report[0] + } + } + } catch (all) { + if (multiqc_report) { + log.warn "[$workflow.manifest.name] Could not attach MultiQC report to summary email" + } + } + return mqc_report +} + +// +// Construct and send completion email +// +def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdir, monochrome_logs=true, multiqc_report=null) { + + // Set up the e-mail variables + def subject = "[$workflow.manifest.name] Successful: $workflow.runName" + if (!workflow.success) { + subject = "[$workflow.manifest.name] FAILED: $workflow.runName" + } + + def summary = [:] + for (group in summary_params.keySet()) { + summary << summary_params[group] + } + + def misc_fields = [:] + misc_fields['Date Started'] = workflow.start + misc_fields['Date Completed'] = workflow.complete + misc_fields['Pipeline script file path'] = workflow.scriptFile + misc_fields['Pipeline script hash ID'] = workflow.scriptId + if (workflow.repository) misc_fields['Pipeline repository Git URL'] = workflow.repository + if (workflow.commitId) misc_fields['Pipeline repository Git Commit'] = workflow.commitId + if (workflow.revision) misc_fields['Pipeline Git branch/tag'] = workflow.revision + misc_fields['Nextflow Version'] = workflow.nextflow.version + misc_fields['Nextflow Build'] = workflow.nextflow.build + misc_fields['Nextflow Compile Timestamp'] = workflow.nextflow.timestamp + + def email_fields = [:] + email_fields['version'] = getWorkflowVersion() + email_fields['runName'] = workflow.runName + email_fields['success'] = workflow.success + email_fields['dateComplete'] = workflow.complete + email_fields['duration'] = workflow.duration + email_fields['exitStatus'] = workflow.exitStatus + email_fields['errorMessage'] = (workflow.errorMessage ?: 'None') + email_fields['errorReport'] = (workflow.errorReport ?: 'None') + email_fields['commandLine'] = workflow.commandLine + email_fields['projectDir'] = workflow.projectDir + email_fields['summary'] = summary << misc_fields + + // On success try attach the multiqc report + def mqc_report = attachMultiqcReport(multiqc_report) + + // Check if we are only sending emails on failure + def email_address = email + if (!email && email_on_fail && !workflow.success) { + email_address = email_on_fail + } + + // Render the TXT template + def engine = new groovy.text.GStringTemplateEngine() + def tf = new File("${workflow.projectDir}/assets/email_template.txt") + def txt_template = engine.createTemplate(tf).make(email_fields) + def email_txt = txt_template.toString() + + // Render the HTML template + def hf = new File("${workflow.projectDir}/assets/email_template.html") + def html_template = engine.createTemplate(hf).make(email_fields) + def email_html = html_template.toString() + + // Render the sendmail template + def max_multiqc_email_size = (params.containsKey('max_multiqc_email_size') ? params.max_multiqc_email_size : 0) as nextflow.util.MemoryUnit + def smail_fields = [ email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "${workflow.projectDir}", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes() ] + def sf = new File("${workflow.projectDir}/assets/sendmail_template.txt") + def sendmail_template = engine.createTemplate(sf).make(smail_fields) + def sendmail_html = sendmail_template.toString() + + // Send the HTML e-mail + Map colors = logColours(monochrome_logs) + if (email_address) { + try { + if (plaintext_email) { throw GroovyException('Send plaintext e-mail, not HTML') } + // Try to send HTML e-mail using sendmail + def sendmail_tf = new File(workflow.launchDir.toString(), ".sendmail_tmp.html") + sendmail_tf.withWriter { w -> w << sendmail_html } + [ 'sendmail', '-t' ].execute() << sendmail_html + log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Sent summary e-mail to $email_address (sendmail)-" + } catch (all) { + // Catch failures and try with plaintext + def mail_cmd = [ 'mail', '-s', subject, '--content-type=text/html', email_address ] + mail_cmd.execute() << email_html + log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Sent summary e-mail to $email_address (mail)-" + } + } + + // Write summary e-mail HTML to a file + def output_hf = new File(workflow.launchDir.toString(), ".pipeline_report.html") + output_hf.withWriter { w -> w << email_html } + FilesEx.copyTo(output_hf.toPath(), "${outdir}/pipeline_info/pipeline_report.html"); + output_hf.delete() + + // Write summary e-mail TXT to a file + def output_tf = new File(workflow.launchDir.toString(), ".pipeline_report.txt") + output_tf.withWriter { w -> w << email_txt } + FilesEx.copyTo(output_tf.toPath(), "${outdir}/pipeline_info/pipeline_report.txt"); + output_tf.delete() +} + +// +// Print pipeline summary on completion +// +def completionSummary(monochrome_logs=true) { + Map colors = logColours(monochrome_logs) + if (workflow.success) { + if (workflow.stats.ignoredCount == 0) { + log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Pipeline completed successfully${colors.reset}-" + } else { + log.info "-${colors.purple}[$workflow.manifest.name]${colors.yellow} Pipeline completed successfully, but with errored process(es) ${colors.reset}-" + } + } else { + log.info "-${colors.purple}[$workflow.manifest.name]${colors.red} Pipeline completed with errors${colors.reset}-" + } +} + +// +// Construct and send a notification to a web server as JSON e.g. Microsoft Teams and Slack +// +def imNotification(summary_params, hook_url) { + def summary = [:] + for (group in summary_params.keySet()) { + summary << summary_params[group] + } + + def misc_fields = [:] + misc_fields['start'] = workflow.start + misc_fields['complete'] = workflow.complete + misc_fields['scriptfile'] = workflow.scriptFile + misc_fields['scriptid'] = workflow.scriptId + if (workflow.repository) misc_fields['repository'] = workflow.repository + if (workflow.commitId) misc_fields['commitid'] = workflow.commitId + if (workflow.revision) misc_fields['revision'] = workflow.revision + misc_fields['nxf_version'] = workflow.nextflow.version + misc_fields['nxf_build'] = workflow.nextflow.build + misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp + + def msg_fields = [:] + msg_fields['version'] = getWorkflowVersion() + msg_fields['runName'] = workflow.runName + msg_fields['success'] = workflow.success + msg_fields['dateComplete'] = workflow.complete + msg_fields['duration'] = workflow.duration + msg_fields['exitStatus'] = workflow.exitStatus + msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') + msg_fields['errorReport'] = (workflow.errorReport ?: 'None') + msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") + msg_fields['projectDir'] = workflow.projectDir + msg_fields['summary'] = summary << misc_fields + + // Render the JSON template + def engine = new groovy.text.GStringTemplateEngine() + // Different JSON depending on the service provider + // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format + def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" + def hf = new File("${workflow.projectDir}/assets/${json_path}") + def json_template = engine.createTemplate(hf).make(msg_fields) + def json_message = json_template.toString() + + // POST + def post = new URL(hook_url).openConnection(); + post.setRequestMethod("POST") + post.setDoOutput(true) + post.setRequestProperty("Content-Type", "application/json") + post.getOutputStream().write(json_message.getBytes("UTF-8")); + def postRC = post.getResponseCode(); + if (! postRC.equals(200)) { + log.warn(post.getErrorStream().getText()); + } +} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/meta.yml b/subworkflows/nf-core/utils_nfcore_pipeline/meta.yml new file mode 100644 index 00000000..d08d2434 --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/meta.yml @@ -0,0 +1,24 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "UTILS_NFCORE_PIPELINE" +description: Subworkflow with utility functions specific to the nf-core pipeline template +keywords: + - utility + - pipeline + - initialise + - version +components: [] +input: + - nextflow_cli_args: + type: list + description: | + Nextflow CLI positional arguments +output: + - success: + type: boolean + description: | + Dummy output to indicate success +authors: + - "@adamrtalbot" +maintainers: + - "@adamrtalbot" + - "@maxulysse" diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test new file mode 100644 index 00000000..1dc317f8 --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test @@ -0,0 +1,134 @@ + +nextflow_function { + + name "Test Functions" + script "../main.nf" + config "subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config" + tag "subworkflows" + tag "subworkflows_nfcore" + tag "utils_nfcore_pipeline" + tag "subworkflows/utils_nfcore_pipeline" + + test("Test Function checkConfigProvided") { + + function "checkConfigProvided" + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function checkProfileProvided") { + + function "checkProfileProvided" + + when { + function { + """ + input[0] = [] + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function workflowCitation") { + + function "workflowCitation" + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function nfCoreLogo") { + + function "nfCoreLogo" + + when { + function { + """ + input[0] = false + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function dashedLine") { + + function "dashedLine" + + when { + function { + """ + input[0] = false + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function without logColours") { + + function "logColours" + + when { + function { + """ + input[0] = true + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function with logColours") { + function "logColours" + + when { + function { + """ + input[0] = false + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } +} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap new file mode 100644 index 00000000..10f948e6 --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap @@ -0,0 +1,138 @@ +{ + "Test Function checkProfileProvided": { + "content": null, + "timestamp": "2024-02-09T15:43:55.145717" + }, + "Test Function checkConfigProvided": { + "content": [ + true + ], + "timestamp": "2024-01-19T11:34:13.548431224" + }, + "Test Function nfCoreLogo": { + "content": [ + "\n\n-\u001b[2m----------------------------------------------------\u001b[0m-\n \u001b[0;32m,--.\u001b[0;30m/\u001b[0;32m,-.\u001b[0m\n\u001b[0;34m ___ __ __ __ ___ \u001b[0;32m/,-._.--~'\u001b[0m\n\u001b[0;34m |\\ | |__ __ / ` / \\ |__) |__ \u001b[0;33m} {\u001b[0m\n\u001b[0;34m | \\| | \\__, \\__/ | \\ |___ \u001b[0;32m\\`-._,-`-,\u001b[0m\n \u001b[0;32m`._,._,'\u001b[0m\n\u001b[0;35m nextflow_workflow v9.9.9\u001b[0m\n-\u001b[2m----------------------------------------------------\u001b[0m-\n" + ], + "timestamp": "2024-01-19T11:34:38.840454873" + }, + "Test Function workflowCitation": { + "content": [ + "If you use nextflow_workflow for your analysis please cite:\n\n* The pipeline\n https://doi.org/10.5281/zenodo.5070524\n\n* The nf-core framework\n https://doi.org/10.1038/s41587-020-0439-x\n\n* Software dependencies\n https://github.com/nextflow_workflow/blob/master/CITATIONS.md" + ], + "timestamp": "2024-01-19T11:34:22.24352016" + }, + "Test Function without logColours": { + "content": [ + { + "reset": "", + "bold": "", + "dim": "", + "underlined": "", + "blink": "", + "reverse": "", + "hidden": "", + "black": "", + "red": "", + "green": "", + "yellow": "", + "blue": "", + "purple": "", + "cyan": "", + "white": "", + "bblack": "", + "bred": "", + "bgreen": "", + "byellow": "", + "bblue": "", + "bpurple": "", + "bcyan": "", + "bwhite": "", + "ublack": "", + "ured": "", + "ugreen": "", + "uyellow": "", + "ublue": "", + "upurple": "", + "ucyan": "", + "uwhite": "", + "iblack": "", + "ired": "", + "igreen": "", + "iyellow": "", + "iblue": "", + "ipurple": "", + "icyan": "", + "iwhite": "", + "biblack": "", + "bired": "", + "bigreen": "", + "biyellow": "", + "biblue": "", + "bipurple": "", + "bicyan": "", + "biwhite": "" + } + ], + "timestamp": "2024-01-19T11:35:04.418416984" + }, + "Test Function dashedLine": { + "content": [ + "-\u001b[2m----------------------------------------------------\u001b[0m-" + ], + "timestamp": "2024-01-19T11:34:55.420000755" + }, + "Test Function with logColours": { + "content": [ + { + "reset": "\u001b[0m", + "bold": "\u001b[1m", + "dim": "\u001b[2m", + "underlined": "\u001b[4m", + "blink": "\u001b[5m", + "reverse": "\u001b[7m", + "hidden": "\u001b[8m", + "black": "\u001b[0;30m", + "red": "\u001b[0;31m", + "green": "\u001b[0;32m", + "yellow": "\u001b[0;33m", + "blue": "\u001b[0;34m", + "purple": "\u001b[0;35m", + "cyan": "\u001b[0;36m", + "white": "\u001b[0;37m", + "bblack": "\u001b[1;30m", + "bred": "\u001b[1;31m", + "bgreen": "\u001b[1;32m", + "byellow": "\u001b[1;33m", + "bblue": "\u001b[1;34m", + "bpurple": "\u001b[1;35m", + "bcyan": "\u001b[1;36m", + "bwhite": "\u001b[1;37m", + "ublack": "\u001b[4;30m", + "ured": "\u001b[4;31m", + "ugreen": "\u001b[4;32m", + "uyellow": "\u001b[4;33m", + "ublue": "\u001b[4;34m", + "upurple": "\u001b[4;35m", + "ucyan": "\u001b[4;36m", + "uwhite": "\u001b[4;37m", + "iblack": "\u001b[0;90m", + "ired": "\u001b[0;91m", + "igreen": "\u001b[0;92m", + "iyellow": "\u001b[0;93m", + "iblue": "\u001b[0;94m", + "ipurple": "\u001b[0;95m", + "icyan": "\u001b[0;96m", + "iwhite": "\u001b[0;97m", + "biblack": "\u001b[1;90m", + "bired": "\u001b[1;91m", + "bigreen": "\u001b[1;92m", + "biyellow": "\u001b[1;93m", + "biblue": "\u001b[1;94m", + "bipurple": "\u001b[1;95m", + "bicyan": "\u001b[1;96m", + "biwhite": "\u001b[1;97m" + } + ], + "timestamp": "2024-01-19T11:35:13.436366565" + } +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test new file mode 100644 index 00000000..8940d32d --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test @@ -0,0 +1,29 @@ +nextflow_workflow { + + name "Test Workflow UTILS_NFCORE_PIPELINE" + script "../main.nf" + config "subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config" + workflow "UTILS_NFCORE_PIPELINE" + tag "subworkflows" + tag "subworkflows_nfcore" + tag "utils_nfcore_pipeline" + tag "subworkflows/utils_nfcore_pipeline" + + test("Should run without failures") { + + when { + workflow { + """ + input[0] = [] + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert snapshot(workflow.out).match() } + ) + } + } +} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap new file mode 100644 index 00000000..d07ce54c --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap @@ -0,0 +1,15 @@ +{ + "Should run without failures": { + "content": [ + { + "0": [ + true + ], + "valid_config": [ + true + ] + } + ], + "timestamp": "2024-01-19T11:35:22.538940073" + } +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config b/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config new file mode 100644 index 00000000..d0a926bf --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config @@ -0,0 +1,9 @@ +manifest { + name = 'nextflow_workflow' + author = """nf-core""" + homePage = 'https://127.0.0.1' + description = """Dummy pipeline""" + nextflowVersion = '!>=23.04.0' + version = '9.9.9' + doi = 'https://doi.org/10.5281/zenodo.5070524' +} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml b/subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml new file mode 100644 index 00000000..ac8523c9 --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml @@ -0,0 +1,2 @@ +subworkflows/utils_nfcore_pipeline: + - subworkflows/nf-core/utils_nfcore_pipeline/** diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/main.nf b/subworkflows/nf-core/utils_nfvalidation_plugin/main.nf new file mode 100644 index 00000000..2585b65d --- /dev/null +++ b/subworkflows/nf-core/utils_nfvalidation_plugin/main.nf @@ -0,0 +1,62 @@ +// +// Subworkflow that uses the nf-validation plugin to render help text and parameter summary +// + +/* +======================================================================================== + IMPORT NF-VALIDATION PLUGIN +======================================================================================== +*/ + +include { paramsHelp } from 'plugin/nf-validation' +include { paramsSummaryLog } from 'plugin/nf-validation' +include { validateParameters } from 'plugin/nf-validation' + +/* +======================================================================================== + SUBWORKFLOW DEFINITION +======================================================================================== +*/ + +workflow UTILS_NFVALIDATION_PLUGIN { + + take: + print_help // boolean: print help + workflow_command // string: default commmand used to run pipeline + pre_help_text // string: string to be printed before help text and summary log + post_help_text // string: string to be printed after help text and summary log + validate_params // boolean: validate parameters + schema_filename // path: JSON schema file, null to use default value + + main: + + log.debug "Using schema file: ${schema_filename}" + + // Default values for strings + pre_help_text = pre_help_text ?: '' + post_help_text = post_help_text ?: '' + workflow_command = workflow_command ?: '' + + // + // Print help message if needed + // + if (print_help) { + log.info pre_help_text + paramsHelp(workflow_command, parameters_schema: schema_filename) + post_help_text + System.exit(0) + } + + // + // Print parameter summary to stdout + // + log.info pre_help_text + paramsSummaryLog(workflow, parameters_schema: schema_filename) + post_help_text + + // + // Validate parameters relative to the parameter JSON schema + // + if (validate_params){ + validateParameters(parameters_schema: schema_filename) + } + + emit: + dummy_emit = true +} diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/meta.yml b/subworkflows/nf-core/utils_nfvalidation_plugin/meta.yml new file mode 100644 index 00000000..3d4a6b04 --- /dev/null +++ b/subworkflows/nf-core/utils_nfvalidation_plugin/meta.yml @@ -0,0 +1,44 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "UTILS_NFVALIDATION_PLUGIN" +description: Use nf-validation to initiate and validate a pipeline +keywords: + - utility + - pipeline + - initialise + - validation +components: [] +input: + - print_help: + type: boolean + description: | + Print help message and exit + - workflow_command: + type: string + description: | + The command to run the workflow e.g. "nextflow run main.nf" + - pre_help_text: + type: string + description: | + Text to print before the help message + - post_help_text: + type: string + description: | + Text to print after the help message + - validate_params: + type: boolean + description: | + Validate the parameters and error if invalid. + - schema_filename: + type: string + description: | + The filename of the schema to validate against. +output: + - dummy_emit: + type: boolean + description: | + Dummy emit to make nf-core subworkflows lint happy +authors: + - "@adamrtalbot" +maintainers: + - "@adamrtalbot" + - "@maxulysse" diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test new file mode 100644 index 00000000..517ee54e --- /dev/null +++ b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test @@ -0,0 +1,200 @@ +nextflow_workflow { + + name "Test Workflow UTILS_NFVALIDATION_PLUGIN" + script "../main.nf" + workflow "UTILS_NFVALIDATION_PLUGIN" + tag "subworkflows" + tag "subworkflows_nfcore" + tag "plugin/nf-validation" + tag "'plugin/nf-validation'" + tag "utils_nfvalidation_plugin" + tag "subworkflows/utils_nfvalidation_plugin" + + test("Should run nothing") { + + when { + + params { + monochrome_logs = true + test_data = '' + } + + workflow { + """ + help = false + workflow_command = null + pre_help_text = null + post_help_text = null + validate_params = false + schema_filename = "$moduleTestDir/nextflow_schema.json" + + input[0] = help + input[1] = workflow_command + input[2] = pre_help_text + input[3] = post_help_text + input[4] = validate_params + input[5] = schema_filename + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } + + test("Should run help") { + + + when { + + params { + monochrome_logs = true + test_data = '' + } + workflow { + """ + help = true + workflow_command = null + pre_help_text = null + post_help_text = null + validate_params = false + schema_filename = "$moduleTestDir/nextflow_schema.json" + + input[0] = help + input[1] = workflow_command + input[2] = pre_help_text + input[3] = post_help_text + input[4] = validate_params + input[5] = schema_filename + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert workflow.exitStatus == 0 }, + { assert workflow.stdout.any { it.contains('Input/output options') } }, + { assert workflow.stdout.any { it.contains('--outdir') } } + ) + } + } + + test("Should run help with command") { + + when { + + params { + monochrome_logs = true + test_data = '' + } + workflow { + """ + help = true + workflow_command = "nextflow run noorg/doesntexist" + pre_help_text = null + post_help_text = null + validate_params = false + schema_filename = "$moduleTestDir/nextflow_schema.json" + + input[0] = help + input[1] = workflow_command + input[2] = pre_help_text + input[3] = post_help_text + input[4] = validate_params + input[5] = schema_filename + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert workflow.exitStatus == 0 }, + { assert workflow.stdout.any { it.contains('nextflow run noorg/doesntexist') } }, + { assert workflow.stdout.any { it.contains('Input/output options') } }, + { assert workflow.stdout.any { it.contains('--outdir') } } + ) + } + } + + test("Should run help with extra text") { + + + when { + + params { + monochrome_logs = true + test_data = '' + } + workflow { + """ + help = true + workflow_command = "nextflow run noorg/doesntexist" + pre_help_text = "pre-help-text" + post_help_text = "post-help-text" + validate_params = false + schema_filename = "$moduleTestDir/nextflow_schema.json" + + input[0] = help + input[1] = workflow_command + input[2] = pre_help_text + input[3] = post_help_text + input[4] = validate_params + input[5] = schema_filename + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert workflow.exitStatus == 0 }, + { assert workflow.stdout.any { it.contains('pre-help-text') } }, + { assert workflow.stdout.any { it.contains('nextflow run noorg/doesntexist') } }, + { assert workflow.stdout.any { it.contains('Input/output options') } }, + { assert workflow.stdout.any { it.contains('--outdir') } }, + { assert workflow.stdout.any { it.contains('post-help-text') } } + ) + } + } + + test("Should validate params") { + + when { + + params { + monochrome_logs = true + test_data = '' + outdir = 1 + } + workflow { + """ + help = false + workflow_command = null + pre_help_text = null + post_help_text = null + validate_params = true + schema_filename = "$moduleTestDir/nextflow_schema.json" + + input[0] = help + input[1] = workflow_command + input[2] = pre_help_text + input[3] = post_help_text + input[4] = validate_params + input[5] = schema_filename + """ + } + } + + then { + assertAll( + { assert workflow.failed }, + { assert workflow.stdout.any { it.contains('ERROR ~ ERROR: Validation of pipeline parameters failed!') } } + ) + } + } +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json new file mode 100644 index 00000000..7626c1c9 --- /dev/null +++ b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json @@ -0,0 +1,96 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://raw.githubusercontent.com/./master/nextflow_schema.json", + "title": ". pipeline parameters", + "description": "", + "type": "object", + "definitions": { + "input_output_options": { + "title": "Input/output options", + "type": "object", + "fa_icon": "fas fa-terminal", + "description": "Define where the pipeline should find input data and save output data.", + "required": ["outdir"], + "properties": { + "validate_params": { + "type": "boolean", + "description": "Validate parameters?", + "default": true, + "hidden": true + }, + "outdir": { + "type": "string", + "format": "directory-path", + "description": "The output directory where the results will be saved. You have to use absolute paths to storage on Cloud infrastructure.", + "fa_icon": "fas fa-folder-open" + }, + "test_data_base": { + "type": "string", + "default": "https://raw.githubusercontent.com/nf-core/test-datasets/modules", + "description": "Base for test data directory", + "hidden": true + }, + "test_data": { + "type": "string", + "description": "Fake test data param", + "hidden": true + } + } + }, + "generic_options": { + "title": "Generic options", + "type": "object", + "fa_icon": "fas fa-file-import", + "description": "Less common options for the pipeline, typically set in a config file.", + "help_text": "These options are common to all nf-core pipelines and allow you to customise some of the core preferences for how the pipeline runs.\n\nTypically these options would be set in a Nextflow config file loaded for all pipeline runs, such as `~/.nextflow/config`.", + "properties": { + "help": { + "type": "boolean", + "description": "Display help text.", + "fa_icon": "fas fa-question-circle", + "hidden": true + }, + "version": { + "type": "boolean", + "description": "Display version and exit.", + "fa_icon": "fas fa-question-circle", + "hidden": true + }, + "logo": { + "type": "boolean", + "default": true, + "description": "Display nf-core logo in console output.", + "fa_icon": "fas fa-image", + "hidden": true + }, + "singularity_pull_docker_container": { + "type": "boolean", + "description": "Pull Singularity container from Docker?", + "hidden": true + }, + "publish_dir_mode": { + "type": "string", + "default": "copy", + "description": "Method used to save pipeline results to output directory.", + "help_text": "The Nextflow `publishDir` option specifies which intermediate files should be saved to the output directory. This option tells the pipeline what method should be used to move these files. See [Nextflow docs](https://www.nextflow.io/docs/latest/process.html#publishdir) for details.", + "fa_icon": "fas fa-copy", + "enum": ["symlink", "rellink", "link", "copy", "copyNoFollow", "move"], + "hidden": true + }, + "monochrome_logs": { + "type": "boolean", + "description": "Use monochrome_logs", + "hidden": true + } + } + } + }, + "allOf": [ + { + "$ref": "#/definitions/input_output_options" + }, + { + "$ref": "#/definitions/generic_options" + } + ] +} diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml new file mode 100644 index 00000000..60b1cfff --- /dev/null +++ b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml @@ -0,0 +1,2 @@ +subworkflows/utils_nfvalidation_plugin: + - subworkflows/nf-core/utils_nfvalidation_plugin/** diff --git a/workflows/circrna.nf b/workflows/circrna.nf index 10ecc0ac..5e577f9b 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -1,54 +1,15 @@ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - PRINT PARAMS SUMMARY + IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { paramsSummaryLog; paramsSummaryMap } from 'plugin/nf-validation' - -def logo = NfcoreTemplate.logo(workflow, params.monochrome_logs) -def citation = '\n' + WorkflowMain.citation(workflow) + '\n' -def summary_params = paramsSummaryMap(workflow) - -// Print parameter summary log to screen -log.info logo + paramsSummaryLog(workflow) + citation - -WorkflowCircrna.initialise(params, log) - -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - CONFIG FILES -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - -ch_multiqc_config = Channel.fromPath("$projectDir/assets/multiqc_config.yml", checkIfExists: true) -ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath( params.multiqc_config, checkIfExists: true ) : Channel.empty() -ch_multiqc_logo = params.multiqc_logo ? Channel.fromPath( params.multiqc_logo, checkIfExists: true ) : Channel.empty() -ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("$projectDir/assets/methods_description_template.yml", checkIfExists: true) - -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - IMPORT LOCAL MODULES/SUBWORKFLOWS -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - -// -// SUBWORKFLOW: Consisting of a mix of local and nf-core/modules -// -include { INPUT_CHECK } from '../subworkflows/local/input_check' - -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - IMPORT NF-CORE MODULES/SUBWORKFLOWS -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - -// -// MODULE: Installed directly from nf-core/modules -// -include { FASTQC } from '../modules/nf-core/fastqc/main' -include { MULTIQC } from '../modules/nf-core/multiqc/main' -include { CUSTOM_DUMPSOFTWAREVERSIONS } from '../modules/nf-core/custom/dumpsoftwareversions/main' +include { FASTQC } from '../modules/nf-core/fastqc/main' +include { MULTIQC } from '../modules/nf-core/multiqc/main' +include { paramsSummaryMap } from 'plugin/nf-validation' +include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' +include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' +include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_circrna_pipeline' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -56,50 +17,45 @@ include { CUSTOM_DUMPSOFTWAREVERSIONS } from '../modules/nf-core/custom/dumpsoft ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -// Info required for completion email and summary -def multiqc_report = [] - workflow CIRCRNA { - ch_versions = Channel.empty() + take: + ch_samplesheet // channel: samplesheet read in from --input - // - // SUBWORKFLOW: Read in samplesheet, validate and stage input files - // - INPUT_CHECK ( - file(params.input) - ) - ch_versions = ch_versions.mix(INPUT_CHECK.out.versions) - // TODO: OPTIONAL, you can use nf-validation plugin to create an input channel from the samplesheet with Channel.fromSamplesheet("input") - // See the documentation https://nextflow-io.github.io/nf-validation/samplesheets/fromSamplesheet/ - // ! There is currently no tooling to help you write a sample sheet schema + main: + + ch_versions = Channel.empty() + ch_multiqc_files = Channel.empty() // // MODULE: Run FastQC // FASTQC ( - INPUT_CHECK.out.reads + ch_samplesheet ) + ch_multiqc_files = ch_multiqc_files.mix(FASTQC.out.zip.collect{it[1]}) ch_versions = ch_versions.mix(FASTQC.out.versions.first()) - CUSTOM_DUMPSOFTWAREVERSIONS ( - ch_versions.unique().collectFile(name: 'collated_versions.yml') - ) + // + // Collate and save software versions + // + softwareVersionsToYAML(ch_versions) + .collectFile(storeDir: "${params.outdir}/pipeline_info", name: 'nf_core_pipeline_software_mqc_versions.yml', sort: true, newLine: true) + .set { ch_collated_versions } // // MODULE: MultiQC // - workflow_summary = WorkflowCircrna.paramsSummaryMultiqc(workflow, summary_params) - ch_workflow_summary = Channel.value(workflow_summary) - - methods_description = WorkflowCircrna.methodsDescriptionText(workflow, ch_multiqc_custom_methods_description, params) - ch_methods_description = Channel.value(methods_description) - - ch_multiqc_files = Channel.empty() - ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) - ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml')) - ch_multiqc_files = ch_multiqc_files.mix(CUSTOM_DUMPSOFTWAREVERSIONS.out.mqc_yml.collect()) - ch_multiqc_files = ch_multiqc_files.mix(FASTQC.out.zip.collect{it[1]}.ifEmpty([])) + ch_multiqc_config = Channel.fromPath("$projectDir/assets/multiqc_config.yml", checkIfExists: true) + ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath(params.multiqc_config, checkIfExists: true) : Channel.empty() + ch_multiqc_logo = params.multiqc_logo ? Channel.fromPath(params.multiqc_logo, checkIfExists: true) : Channel.empty() + summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") + ch_workflow_summary = Channel.value(paramsSummaryMultiqc(summary_params)) + ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("$projectDir/assets/methods_description_template.yml", checkIfExists: true) + ch_methods_description = Channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) + ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) + ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) + ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: false)) MULTIQC ( ch_multiqc_files.collect(), @@ -107,31 +63,10 @@ workflow CIRCRNA { ch_multiqc_custom_config.toList(), ch_multiqc_logo.toList() ) - multiqc_report = MULTIQC.out.report.toList() -} - -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - COMPLETION EMAIL AND SUMMARY -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - -workflow.onComplete { - if (params.email || params.email_on_fail) { - NfcoreTemplate.email(workflow, params, summary_params, projectDir, log, multiqc_report) - } - NfcoreTemplate.dump_parameters(workflow, params) - NfcoreTemplate.summary(workflow, params, log) - if (params.hook_url) { - NfcoreTemplate.IM_notification(workflow, params, summary_params, projectDir, log) - } -} -workflow.onError { - if (workflow.errorReport.contains("Process requirement exceeds available memory")) { - println("🛑 Default resources exceed availability 🛑 ") - println("💡 See here on how to configure pipeline: https://nf-co.re/docs/usage/configuration#tuning-workflow-resources 💡") - } + emit: + multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html + versions = ch_versions // channel: [ path(versions.yml) ] } /* From 195e3da0a4a4cee0c816a408a7a590aa3e21d010 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 22 Feb 2024 11:52:02 +0100 Subject: [PATCH 122/491] try to fix disapearing folder --- subworkflows/local/prepare_genome.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index d35b6b5b..672fb794 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -25,7 +25,7 @@ workflow PREPARE_GENOME { // this removes all additional fields in the headers of the input fasta file if( params.tool.contains('mapsplice') && params.module.contains('circrna_discovery') ) { - CLEAN_FASTA(Channel.value([[id: "${fasta.baseName}" + "_clean" ], fasta]), []) + CLEAN_FASTA(Channel.value([[id: "${fasta_tuple.map{ it.last() }.baseName}" + "_clean" ], fasta]), []) ch_fasta = CLEAN_FASTA.out.output.map{ it.last() } } From b30d0b380e348056603a1b168961ac7dc5839596 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 22 Feb 2024 11:59:22 +0100 Subject: [PATCH 123/491] try to fix naming --- subworkflows/local/prepare_genome.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 672fb794..0dc71884 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -25,7 +25,7 @@ workflow PREPARE_GENOME { // this removes all additional fields in the headers of the input fasta file if( params.tool.contains('mapsplice') && params.module.contains('circrna_discovery') ) { - CLEAN_FASTA(Channel.value([[id: "${fasta_tuple.map{ it.last() }.baseName}" + "_clean" ], fasta]), []) + CLEAN_FASTA(Channel.value([[id: fasta_tuple.map{ it.last() }.baseName + "_clean" ], fasta]), []) ch_fasta = CLEAN_FASTA.out.output.map{ it.last() } } From e4bf00fc0fea2e7c2e211734403aae09685371a6 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 22 Feb 2024 12:04:24 +0100 Subject: [PATCH 124/491] try to fix basename --- subworkflows/local/prepare_genome.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 0dc71884..6360fcb2 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -25,7 +25,7 @@ workflow PREPARE_GENOME { // this removes all additional fields in the headers of the input fasta file if( params.tool.contains('mapsplice') && params.module.contains('circrna_discovery') ) { - CLEAN_FASTA(Channel.value([[id: fasta_tuple.map{ it.last() }.baseName + "_clean" ], fasta]), []) + CLEAN_FASTA(Channel.value([[id: fasta_tuple.map{ it.last() }.getBaseName() + "_clean" ], fasta]), []) ch_fasta = CLEAN_FASTA.out.output.map{ it.last() } } From a541cc44f75842b2b29485d518f0b57a37355b65 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 22 Feb 2024 12:09:07 +0100 Subject: [PATCH 125/491] change order --- subworkflows/local/prepare_genome.nf | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 6360fcb2..2e46b826 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -17,15 +17,11 @@ workflow PREPARE_GENOME { main: ch_versions = Channel.empty() - ch_gtf = Channel.fromPath(gtf) - fasta_tuple = Channel.value([[id: "fasta"], fasta]) - gtf_tuple = Channel.value([[id: "gtf"], gtf]) - // MapSplice cannot deal with extra field in the fasta headers // this removes all additional fields in the headers of the input fasta file if( params.tool.contains('mapsplice') && params.module.contains('circrna_discovery') ) { - CLEAN_FASTA(Channel.value([[id: fasta_tuple.map{ it.last() }.getBaseName() + "_clean" ], fasta]), []) + CLEAN_FASTA(Channel.value([[id: "${fasta.baseName}" + "_clean" ], fasta]), []) ch_fasta = CLEAN_FASTA.out.output.map{ it.last() } } @@ -36,6 +32,11 @@ workflow PREPARE_GENOME { } + + ch_gtf = Channel.fromPath(gtf) + fasta_tuple = Channel.value([[id: "fasta"], fasta]) + gtf_tuple = Channel.value([[id: "gtf"], gtf]) + // MapSplice & find_circ requires reference genome to be split per chromosome: if( ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) && params.module.contains('circrna_discovery') ){ directory = file("${params.outdir}/references/chromosomes") From 38df3d1466e5920a3762164c807f2cafbd7dd171 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 22 Feb 2024 16:20:29 +0100 Subject: [PATCH 126/491] update naming new fasta file --- subworkflows/local/prepare_genome.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 2e46b826..96045cfc 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -21,7 +21,7 @@ workflow PREPARE_GENOME { // this removes all additional fields in the headers of the input fasta file if( params.tool.contains('mapsplice') && params.module.contains('circrna_discovery') ) { - CLEAN_FASTA(Channel.value([[id: "${fasta.baseName}" + "_clean" ], fasta]), []) + CLEAN_FASTA(Channel.value([[id: "${fasta.baseName}" + ".clean_headers" ], fasta]), []) ch_fasta = CLEAN_FASTA.out.output.map{ it.last() } } From 12ad8f44be9e57d5ea619c0c1af7a8f01053d277 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Fri, 23 Feb 2024 09:07:32 +0100 Subject: [PATCH 127/491] update gawk module --- modules.json | 2 +- modules/nf-core/gawk/environment.yml | 1 + modules/nf-core/gawk/meta.yml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules.json b/modules.json index e1a5c225..6413c338 100644 --- a/modules.json +++ b/modules.json @@ -77,7 +77,7 @@ }, "gawk": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "dc3527855e7358c6d8400828754c0caa5f11698f", "installed_by": ["modules"] }, "hisat2/align": { diff --git a/modules/nf-core/gawk/environment.yml b/modules/nf-core/gawk/environment.yml index 710fbfd1..34513c7f 100644 --- a/modules/nf-core/gawk/environment.yml +++ b/modules/nf-core/gawk/environment.yml @@ -1,3 +1,4 @@ +name: gawk channels: - conda-forge - bioconda diff --git a/modules/nf-core/gawk/meta.yml b/modules/nf-core/gawk/meta.yml index 1bc978e1..2b6033b0 100644 --- a/modules/nf-core/gawk/meta.yml +++ b/modules/nf-core/gawk/meta.yml @@ -15,7 +15,7 @@ tools: homepage: "https://www.gnu.org/software/gawk/" documentation: "https://www.gnu.org/software/gawk/manual/" tool_dev_url: "https://www.gnu.org/prep/ftp.html" - licence: "['GPL v3']" + licence: ["GPL v3"] input: - meta: type: map From 0a31971808db0df25dc22562296c1bde6af18d0b Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Tue, 20 Feb 2024 15:28:12 +0000 Subject: [PATCH 128/491] Template update for nf-core/tools version 2.13 --- .editorconfig | 9 +- .github/workflows/awsfulltest.yml | 4 +- .github/workflows/awstest.yml | 4 +- .github/workflows/branch.yml | 2 +- .github/workflows/ci.yml | 13 +- .github/workflows/clean-up.yml | 2 +- .github/workflows/download_pipeline.yml | 15 +- .github/workflows/linting.yml | 12 +- .github/workflows/linting_comment.yml | 4 +- .github/workflows/release-announcements.yml | 11 +- README.md | 5 +- assets/multiqc_config.yml | 2 + assets/schema_input.json | 21 +- bin/check_samplesheet.py | 166 ------- lib/NfcoreTemplate.groovy | 356 -------------- lib/Utils.groovy | 47 -- lib/WorkflowCircrna.groovy | 122 ----- lib/WorkflowMain.groovy | 81 ---- main.nf | 98 ++-- modules.json | 21 +- modules/local/samplesheet_check.nf | 31 -- .../dumpsoftwareversions/environment.yml | 7 - .../custom/dumpsoftwareversions/main.nf | 24 - .../custom/dumpsoftwareversions/meta.yml | 37 -- .../templates/dumpsoftwareversions.py | 101 ---- .../dumpsoftwareversions/tests/main.nf.test | 43 -- .../tests/main.nf.test.snap | 33 -- .../dumpsoftwareversions/tests/tags.yml | 2 - modules/nf-core/fastqc/tests/main.nf.test | 14 +- .../nf-core/fastqc/tests/main.nf.test.snap | 76 ++- modules/nf-core/multiqc/environment.yml | 2 +- modules/nf-core/multiqc/main.nf | 4 +- modules/nf-core/multiqc/tests/main.nf.test | 13 +- .../nf-core/multiqc/tests/main.nf.test.snap | 32 +- nextflow.config | 1 - nextflow_schema.json | 1 + pyproject.toml | 8 +- subworkflows/local/input_check.nf | 77 --- .../utils_nfcore_circrna_pipeline/main.nf | 247 ++++++++++ .../nf-core/utils_nextflow_pipeline/main.nf | 126 +++++ .../nf-core/utils_nextflow_pipeline/meta.yml | 38 ++ .../tests/main.function.nf.test | 54 +++ .../tests/main.function.nf.test.snap | 12 + .../tests/main.workflow.nf.test | 123 +++++ .../tests/nextflow.config | 9 + .../utils_nextflow_pipeline/tests/tags.yml | 2 + .../nf-core/utils_nfcore_pipeline/main.nf | 440 ++++++++++++++++++ .../nf-core/utils_nfcore_pipeline/meta.yml | 24 + .../tests/main.function.nf.test | 134 ++++++ .../tests/main.function.nf.test.snap | 138 ++++++ .../tests/main.workflow.nf.test | 29 ++ .../tests/main.workflow.nf.test.snap | 15 + .../tests/nextflow.config | 9 + .../utils_nfcore_pipeline/tests/tags.yml | 2 + .../nf-core/utils_nfvalidation_plugin/main.nf | 62 +++ .../utils_nfvalidation_plugin/meta.yml | 44 ++ .../tests/main.nf.test | 200 ++++++++ .../tests/nextflow_schema.json | 96 ++++ .../utils_nfvalidation_plugin/tests/tags.yml | 2 + workflows/circrna.nf | 41 +- 60 files changed, 2084 insertions(+), 1264 deletions(-) delete mode 100755 bin/check_samplesheet.py delete mode 100755 lib/NfcoreTemplate.groovy delete mode 100644 lib/Utils.groovy delete mode 100755 lib/WorkflowCircrna.groovy delete mode 100755 lib/WorkflowMain.groovy delete mode 100644 modules/local/samplesheet_check.nf delete mode 100644 modules/nf-core/custom/dumpsoftwareversions/environment.yml delete mode 100644 modules/nf-core/custom/dumpsoftwareversions/main.nf delete mode 100644 modules/nf-core/custom/dumpsoftwareversions/meta.yml delete mode 100755 modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py delete mode 100644 modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test delete mode 100644 modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap delete mode 100644 modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml delete mode 100644 subworkflows/local/input_check.nf create mode 100644 subworkflows/local/utils_nfcore_circrna_pipeline/main.nf create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/main.nf create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/meta.yml create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/main.nf create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/meta.yml create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml create mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/main.nf create mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/meta.yml create mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test create mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json create mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml diff --git a/.editorconfig b/.editorconfig index 9b990088..dd9ffa53 100644 --- a/.editorconfig +++ b/.editorconfig @@ -18,7 +18,12 @@ end_of_line = unset insert_final_newline = unset trim_trailing_whitespace = unset indent_style = unset -indent_size = unset +[/subworkflows/nf-core/**] +charset = unset +end_of_line = unset +insert_final_newline = unset +trim_trailing_whitespace = unset +indent_style = unset [/assets/email*] indent_size = unset @@ -28,5 +33,5 @@ indent_size = unset indent_style = unset # ignore python -[*.{py}] +[*.{py,md}] indent_style = unset diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 7b6bd16d..94521ebc 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Launch workflow via tower - uses: seqeralabs/action-tower-launch@v2 + uses: seqeralabs/action-tower-launch@922e5c8d5ac4e918107ec311d2ebbd65e5982b3d # v2 # TODO nf-core: You can customise AWS full pipeline tests as required # Add full size test data (but still relatively small datasets for few samples) # on the `test_full.config` test runs with only one set of parameters @@ -31,7 +31,7 @@ jobs: } profiles: test_full - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4 with: name: Tower debug log file path: | diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index 9590dcae..5307e9aa 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -12,7 +12,7 @@ jobs: steps: # Launch workflow using Tower CLI tool action - name: Launch workflow via tower - uses: seqeralabs/action-tower-launch@v2 + uses: seqeralabs/action-tower-launch@922e5c8d5ac4e918107ec311d2ebbd65e5982b3d # v2 with: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} @@ -25,7 +25,7 @@ jobs: } profiles: test - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4 with: name: Tower debug log file path: | diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index a9339b73..777845e7 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -19,7 +19,7 @@ jobs: # NOTE - this doesn't currently work if the PR is coming from a fork, due to limitations in GitHub actions secrets - name: Post PR comment if: failure() - uses: mshick/add-pr-comment@v2 + uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 with: message: | ## This PR is against the `master` branch :x: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79f1ee44..790f3b8d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,15 +29,20 @@ jobs: steps: - name: Check out pipeline code - uses: actions/checkout@v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - name: Install Nextflow - uses: nf-core/setup-nextflow@v1 + uses: nf-core/setup-nextflow@b9f764e8ba5c76b712ace14ecbfcef0e40ae2dd8 # v1 with: version: "${{ matrix.NXF_VER }}" - - name: Hash Github Workspace - id: hash_workspace + - name: Disk space cleanup + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + + - name: Run pipeline with test data + # TODO nf-core: You can customise CI pipeline run tests as required + # For example: adding multiple test runs with different parameters + # Remember that you can parallelise this by using strategy.matrix run: | echo "digest=$(echo RNA_3.10.1_${{ github.workspace }} | md5sum | cut -c 1-25)" >> $GITHUB_OUTPUT diff --git a/.github/workflows/clean-up.yml b/.github/workflows/clean-up.yml index e37cfda5..0b6b1f27 100644 --- a/.github/workflows/clean-up.yml +++ b/.github/workflows/clean-up.yml @@ -10,7 +10,7 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/stale@v9 + - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9 with: stale-issue-message: "This issue has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor. Remove stale label or add a comment otherwise this issue will be closed in 20 days." stale-pr-message: "This PR has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor. Remove stale label or add a comment if it is still useful." diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml index 8a330045..f823210d 100644 --- a/.github/workflows/download_pipeline.yml +++ b/.github/workflows/download_pipeline.yml @@ -6,6 +6,11 @@ name: Test successful pipeline download with 'nf-core download' # - the head branch of the pull request is updated, i.e. if fixes for a release are pushed last minute to dev. on: workflow_dispatch: + inputs: + testbranch: + description: "The specific branch you wish to utilize for the test execution of nf-core download." + required: true + default: "dev" pull_request: types: - opened @@ -23,13 +28,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Nextflow - uses: nf-core/setup-nextflow@v1 + uses: nf-core/setup-nextflow@b9f764e8ba5c76b712ace14ecbfcef0e40ae2dd8 # v1 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 with: python-version: "3.11" architecture: "x64" - - uses: eWaterCycle/setup-singularity@v7 + - uses: eWaterCycle/setup-singularity@931d4e31109e875b13309ae1d07c70ca8fbc8537 # v7 with: singularity-version: 3.8.3 @@ -42,13 +47,13 @@ jobs: run: | echo "REPO_LOWERCASE=${GITHUB_REPOSITORY,,}" >> ${GITHUB_ENV} echo "REPOTITLE_LOWERCASE=$(basename ${GITHUB_REPOSITORY,,})" >> ${GITHUB_ENV} - echo "REPO_BRANCH=${GITHUB_REF#refs/heads/}" >> ${GITHUB_ENV} + echo "REPO_BRANCH=${{ github.event.inputs.testbranch || 'dev' }}" >> ${GITHUB_ENV} - name: Download the pipeline env: NXF_SINGULARITY_CACHEDIR: ./ run: | - nf-core download ${{ env.REPO_LOWERCASE }} \ + nf-core download ${{ env.REPO_LOWERCASE }} \ --revision ${{ env.REPO_BRANCH }} \ --outdir ./${{ env.REPOTITLE_LOWERCASE }} \ --compress "none" \ diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 81cd098e..748b4311 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -14,10 +14,10 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - name: Set up Python 3.11 - uses: actions/setup-python@v5 + uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 with: python-version: 3.11 cache: "pip" @@ -32,12 +32,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out pipeline code - uses: actions/checkout@v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - name: Install Nextflow - uses: nf-core/setup-nextflow@v1 + uses: nf-core/setup-nextflow@b9f764e8ba5c76b712ace14ecbfcef0e40ae2dd8 # v1 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 with: python-version: "3.11" architecture: "x64" @@ -60,7 +60,7 @@ jobs: - name: Upload linting log file artifact if: ${{ always() }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4 with: name: linting-logs path: | diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index 147bcd10..b706875f 100644 --- a/.github/workflows/linting_comment.yml +++ b/.github/workflows/linting_comment.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download lint results - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@f6b0bace624032e30a85a8fd9c1a7f8f611f5737 # v3 with: workflow: linting.yml workflow_conclusion: completed @@ -21,7 +21,7 @@ jobs: run: echo "pr_number=$(cat linting-logs/PR_number.txt)" >> $GITHUB_OUTPUT - name: Post PR comment - uses: marocchino/sticky-pull-request-comment@v2 + uses: marocchino/sticky-pull-request-comment@331f8f5b4215f0445d3c07b4967662a32a2d3e31 # v2 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} number: ${{ steps.pr_number.outputs.pr_number }} diff --git a/.github/workflows/release-announcements.yml b/.github/workflows/release-announcements.yml index 21ac3f06..c3674af2 100644 --- a/.github/workflows/release-announcements.yml +++ b/.github/workflows/release-announcements.yml @@ -9,6 +9,11 @@ jobs: toot: runs-on: ubuntu-latest steps: + - name: get topics and convert to hashtags + id: get_topics + run: | + curl -s https://nf-co.re/pipelines.json | jq -r '.remote_workflows[] | select(.name == "${{ github.repository }}") | .topics[]' | awk '{print "#"$0}' | tr '\n' ' ' > $GITHUB_OUTPUT + - uses: rzr/fediverse-action@master with: access-token: ${{ secrets.MASTODON_ACCESS_TOKEN }} @@ -20,11 +25,13 @@ jobs: Please see the changelog: ${{ github.event.release.html_url }} + ${{ steps.get_topics.outputs.GITHUB_OUTPUT }} #nfcore #openscience #nextflow #bioinformatics + send-tweet: runs-on: ubuntu-latest steps: - - uses: actions/setup-python@v5 + - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 with: python-version: "3.10" - name: Install dependencies @@ -56,7 +63,7 @@ jobs: bsky-post: runs-on: ubuntu-latest steps: - - uses: zentered/bluesky-post-action@v0.1.0 + - uses: zentered/bluesky-post-action@80dbe0a7697de18c15ad22f4619919ceb5ccf597 # v0.1.0 with: post: | Pipeline release! ${{ github.repository }} v${{ github.event.release.tag_name }} - ${{ github.event.release.name }}! diff --git a/README.md b/README.md index e13dcc3d..83a0804b 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,9 @@ nf-core/circrna -[![GitHub Actions CI Status](https://github.com/nf-core/circrna/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/circrna/actions?query=workflow%3A%22nf-core+CI%22) -[![GitHub Actions Linting Status](https://github.com/nf-core/circrna/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/circrna/actions?query=workflow%3A%22nf-core+linting%22)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/circrna/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) + +[![GitHub Actions CI Status](https://github.com/nf-core/circrna/actions/workflows/ci.yml/badge.svg)](https://github.com/nf-core/circrna/actions/workflows/ci.yml) +[![GitHub Actions Linting Status](https://github.com/nf-core/circrna/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/circrna/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/circrna/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) [![GitHub Actions CI Status](https://github.com/nf-core/circrna/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/circrna/actions?query=workflow%3A%22nf-core+CI%22) [![GitHub Actions Linting Status](https://github.com/nf-core/circrna/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/circrna/actions?query=workflow%3A%22nf-core+linting%22)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/circrna/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index 9a1b5bda..570f6c0d 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -11,3 +11,5 @@ report_section_order: order: -1002 export_plots: true + +disable_version_detection: true diff --git a/assets/schema_input.json b/assets/schema_input.json index 41716366..fe551cb8 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -10,25 +10,22 @@ "sample": { "type": "string", "pattern": "^\\S+$", - "errorMessage": "Sample name must be provided and cannot contain spaces" + "errorMessage": "Sample name must be provided and cannot contain spaces", + "meta": ["id"] }, "fastq_1": { "type": "string", + "format": "file-path", + "exists": true, "pattern": "^\\S+\\.f(ast)?q\\.gz$", "errorMessage": "FastQ file for reads 1 must be provided, cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz'" }, "fastq_2": { - "errorMessage": "FastQ file for reads 2 cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz'", - "anyOf": [ - { - "type": "string", - "pattern": "^\\S+\\.f(ast)?q\\.gz$" - }, - { - "type": "string", - "maxLength": 0 - } - ] + "type": "string", + "format": "file-path", + "exists": true, + "pattern": "^\\S+\\.f(ast)?q\\.gz$", + "errorMessage": "FastQ file for reads 2 cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz'" } }, "required": ["sample", "fastq_1"] diff --git a/bin/check_samplesheet.py b/bin/check_samplesheet.py deleted file mode 100755 index 95346faf..00000000 --- a/bin/check_samplesheet.py +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env python3 - -""" - Borrowed from nf-core/rnaseq, the original from template 2.6 kept breaking at: - "[CRITICAL] The given sample sheet does not appear to contain a header." - Even though the input samplesheet looked to be perfectly fine using vim :set list. - - Strandedness commented out should you wish to include this in future releases. -""" - - -import os -import sys -import errno -import argparse - - -def parse_args(args=None): - Description = "Reformat nf-core/rnaseq samplesheet file and check its contents." - Epilog = "Example usage: python check_samplesheet.py " - - parser = argparse.ArgumentParser(description=Description, epilog=Epilog) - parser.add_argument("FILE_IN", help="Input samplesheet file.") - parser.add_argument("FILE_OUT", help="Output file.") - return parser.parse_args(args) - - -def make_dir(path): - if len(path) > 0: - try: - os.makedirs(path) - except OSError as exception: - if exception.errno != errno.EEXIST: - raise exception - - -def sniff_format(handle): - """ - Detect the tabular format. - - Args: - handle (text file): A handle to a `text file`_ object. The read position is - expected to be at the beginning (index 0). - - Returns: - csv.Dialect: The detected tabular format. - - .. _text file: - https://docs.python.org/3/glossary.html#term-text-file - - """ - peek = read_head(handle) - handle.seek(0) - sniffer = csv.Sniffer() - dialect = sniffer.sniff(peek) - return dialect - - -def check_samplesheet(file_in, file_out): - """ - This function checks that the samplesheet follows the following structure: - sample,fastq_1,fastq_2,strandedness - SAMPLE_PE,SAMPLE_PE_RUN1_1.fastq.gz,SAMPLE_PE_RUN1_2.fastq.gz,forward - SAMPLE_PE,SAMPLE_PE_RUN2_1.fastq.gz,SAMPLE_PE_RUN2_2.fastq.gz,forward - SAMPLE_SE,SAMPLE_SE_RUN1_1.fastq.gz,,forward - For an example see: - https://github.com/nf-core/test-datasets/blob/rnaseq/samplesheet/v3.1/samplesheet_test.csv - """ - - sample_mapping_dict = {} - with open(file_in, "r", encoding="utf-8-sig") as fin: - ## Check header - MIN_COLS = 2 ## edit by BDigby as not using strandedness yet. - HEADER = ["sample", "fastq_1", "fastq_2"] - header = [x.strip('"') for x in fin.readline().strip().split(",")] - if header[: len(HEADER)] != HEADER: - print(f"ERROR: Please check samplesheet header -> {','.join(header)} != {','.join(HEADER)}") - sys.exit(1) - - ## Check sample entries - for line in fin: - if line.strip(): - lspl = [x.strip().strip('"') for x in line.strip().split(",")] - - ## Check valid number of columns per row - if len(lspl) < len(HEADER): - print_error( - f"Invalid number of columns (minimum = {len(HEADER)})!", - "Line", - line, - ) - - num_cols = len([x for x in lspl if x]) - if num_cols < MIN_COLS: - print_error( - f"Invalid number of populated columns (minimum = {MIN_COLS})!", - "Line", - line, - ) - - ## Check sample name entries - sample, fastq_1, fastq_2 = lspl[: len(HEADER)] - if sample.find(" ") != -1: - print(f"WARNING: Spaces have been replaced by underscores for sample: {sample}") - sample = sample.replace(" ", "_") - if not sample: - print_error("Sample entry has not been specified!", "Line", line) - - ## Check FastQ file extension - for fastq in [fastq_1, fastq_2]: - if fastq: - if fastq.find(" ") != -1: - print_error("FastQ file contains spaces!", "Line", line) - if not fastq.endswith(".fastq.gz") and not fastq.endswith(".fq.gz"): - print_error( - "FastQ file does not have extension '.fastq.gz' or '.fq.gz'!", - "Line", - line, - ) - - ## Auto-detect paired-end/single-end - sample_info = [] ## [single_end, fastq_1, fastq_2, strandedness] - if sample and fastq_1 and fastq_2: ## Paired-end short reads - sample_info = ["0", fastq_1, fastq_2] - elif sample and fastq_1 and not fastq_2: ## Single-end short reads - sample_info = ["1", fastq_1, fastq_2] - else: - print_error("Invalid combination of columns provided!", "Line", line) - - ## Create sample mapping dictionary = {sample: [[ single_end, fastq_1, fastq_2, strandedness ]]} - if sample not in sample_mapping_dict: - sample_mapping_dict[sample] = [sample_info] - else: - if sample_info in sample_mapping_dict[sample]: - print_error("Samplesheet contains duplicate rows!", "Line", line) - else: - sample_mapping_dict[sample].append(sample_info) - - ## Write validated samplesheet with appropriate columns - if len(sample_mapping_dict) > 0: - out_dir = os.path.dirname(file_out) - make_dir(out_dir) - with open(file_out, "w") as fout: - fout.write(",".join(["sample", "single_end", "fastq_1", "fastq_2"]) + "\n") - for sample in sorted(sample_mapping_dict.keys()): - ## Check that multiple runs of the same sample are of the same datatype i.e. single-end / paired-end - if not all(x[0] == sample_mapping_dict[sample][0][0] for x in sample_mapping_dict[sample]): - print_error( - f"Multiple runs of a sample must be of the same datatype i.e. single-end or paired-end!", - "Sample", - sample, - ) - - for idx, val in enumerate(sample_mapping_dict[sample]): - fout.write(",".join([f"{sample}_T{idx+1}"] + val) + "\n") - else: - print_error(f"No entries to process!", "Samplesheet: {file_in}") - - -def main(args=None): - args = parse_args(args) - check_samplesheet(args.FILE_IN, args.FILE_OUT) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/lib/NfcoreTemplate.groovy b/lib/NfcoreTemplate.groovy deleted file mode 100755 index e248e4c3..00000000 --- a/lib/NfcoreTemplate.groovy +++ /dev/null @@ -1,356 +0,0 @@ -// -// This file holds several functions used within the nf-core pipeline template. -// - -import org.yaml.snakeyaml.Yaml -import groovy.json.JsonOutput -import nextflow.extension.FilesEx - -class NfcoreTemplate { - - // - // Check AWS Batch related parameters have been specified correctly - // - public static void awsBatch(workflow, params) { - if (workflow.profile.contains('awsbatch')) { - // Check params.awsqueue and params.awsregion have been set if running on AWSBatch - assert (params.awsqueue && params.awsregion) : "Specify correct --awsqueue and --awsregion parameters on AWSBatch!" - // Check outdir paths to be S3 buckets if running on AWSBatch - assert params.outdir.startsWith('s3:') : "Outdir not on S3 - specify S3 Bucket to run on AWSBatch!" - } - } - - // - // Warn if a -profile or Nextflow config has not been provided to run the pipeline - // - public static void checkConfigProvided(workflow, log) { - if (workflow.profile == 'standard' && workflow.configFiles.size() <= 1) { - log.warn "[$workflow.manifest.name] You are attempting to run the pipeline without any custom configuration!\n\n" + - "This will be dependent on your local compute environment but can be achieved via one or more of the following:\n" + - " (1) Using an existing pipeline profile e.g. `-profile docker` or `-profile singularity`\n" + - " (2) Using an existing nf-core/configs for your Institution e.g. `-profile crick` or `-profile uppmax`\n" + - " (3) Using your own local custom config e.g. `-c /path/to/your/custom.config`\n\n" + - "Please refer to the quick start section and usage docs for the pipeline.\n " - } - } - - // - // Generate version string - // - public static String version(workflow) { - String version_string = "" - - if (workflow.manifest.version) { - def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : '' - version_string += "${prefix_v}${workflow.manifest.version}" - } - - if (workflow.commitId) { - def git_shortsha = workflow.commitId.substring(0, 7) - version_string += "-g${git_shortsha}" - } - - return version_string - } - - // - // Construct and send completion email - // - public static void email(workflow, params, summary_params, projectDir, log, multiqc_report=[]) { - - // Set up the e-mail variables - def subject = "[$workflow.manifest.name] Successful: $workflow.runName" - if (!workflow.success) { - subject = "[$workflow.manifest.name] FAILED: $workflow.runName" - } - - def summary = [:] - for (group in summary_params.keySet()) { - summary << summary_params[group] - } - - def misc_fields = [:] - misc_fields['Date Started'] = workflow.start - misc_fields['Date Completed'] = workflow.complete - misc_fields['Pipeline script file path'] = workflow.scriptFile - misc_fields['Pipeline script hash ID'] = workflow.scriptId - if (workflow.repository) misc_fields['Pipeline repository Git URL'] = workflow.repository - if (workflow.commitId) misc_fields['Pipeline repository Git Commit'] = workflow.commitId - if (workflow.revision) misc_fields['Pipeline Git branch/tag'] = workflow.revision - misc_fields['Nextflow Version'] = workflow.nextflow.version - misc_fields['Nextflow Build'] = workflow.nextflow.build - misc_fields['Nextflow Compile Timestamp'] = workflow.nextflow.timestamp - - def email_fields = [:] - email_fields['version'] = NfcoreTemplate.version(workflow) - email_fields['runName'] = workflow.runName - email_fields['success'] = workflow.success - email_fields['dateComplete'] = workflow.complete - email_fields['duration'] = workflow.duration - email_fields['exitStatus'] = workflow.exitStatus - email_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - email_fields['errorReport'] = (workflow.errorReport ?: 'None') - email_fields['commandLine'] = workflow.commandLine - email_fields['projectDir'] = workflow.projectDir - email_fields['summary'] = summary << misc_fields - - // On success try attach the multiqc report - def mqc_report = null - try { - if (workflow.success) { - mqc_report = multiqc_report.getVal() - if (mqc_report.getClass() == ArrayList && mqc_report.size() >= 1) { - if (mqc_report.size() > 1) { - log.warn "[$workflow.manifest.name] Found multiple reports from process 'MULTIQC', will use only one" - } - mqc_report = mqc_report[0] - } - } - } catch (all) { - if (multiqc_report) { - log.warn "[$workflow.manifest.name] Could not attach MultiQC report to summary email" - } - } - - // Check if we are only sending emails on failure - def email_address = params.email - if (!params.email && params.email_on_fail && !workflow.success) { - email_address = params.email_on_fail - } - - // Render the TXT template - def engine = new groovy.text.GStringTemplateEngine() - def tf = new File("$projectDir/assets/email_template.txt") - def txt_template = engine.createTemplate(tf).make(email_fields) - def email_txt = txt_template.toString() - - // Render the HTML template - def hf = new File("$projectDir/assets/email_template.html") - def html_template = engine.createTemplate(hf).make(email_fields) - def email_html = html_template.toString() - - // Render the sendmail template - def max_multiqc_email_size = (params.containsKey('max_multiqc_email_size') ? params.max_multiqc_email_size : 0) as nextflow.util.MemoryUnit - def smail_fields = [ email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "$projectDir", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes() ] - def sf = new File("$projectDir/assets/sendmail_template.txt") - def sendmail_template = engine.createTemplate(sf).make(smail_fields) - def sendmail_html = sendmail_template.toString() - - // Send the HTML e-mail - Map colors = logColours(params.monochrome_logs) - if (email_address) { - try { - if (params.plaintext_email) { throw GroovyException('Send plaintext e-mail, not HTML') } - // Try to send HTML e-mail using sendmail - def sendmail_tf = new File(workflow.launchDir.toString(), ".sendmail_tmp.html") - sendmail_tf.withWriter { w -> w << sendmail_html } - [ 'sendmail', '-t' ].execute() << sendmail_html - log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Sent summary e-mail to $email_address (sendmail)-" - } catch (all) { - // Catch failures and try with plaintext - def mail_cmd = [ 'mail', '-s', subject, '--content-type=text/html', email_address ] - if ( mqc_report != null && mqc_report.size() <= max_multiqc_email_size.toBytes() ) { - mail_cmd += [ '-A', mqc_report ] - } - mail_cmd.execute() << email_html - log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Sent summary e-mail to $email_address (mail)-" - } - } - - // Write summary e-mail HTML to a file - def output_hf = new File(workflow.launchDir.toString(), ".pipeline_report.html") - output_hf.withWriter { w -> w << email_html } - FilesEx.copyTo(output_hf.toPath(), "${params.outdir}/pipeline_info/pipeline_report.html"); - output_hf.delete() - - // Write summary e-mail TXT to a file - def output_tf = new File(workflow.launchDir.toString(), ".pipeline_report.txt") - output_tf.withWriter { w -> w << email_txt } - FilesEx.copyTo(output_tf.toPath(), "${params.outdir}/pipeline_info/pipeline_report.txt"); - output_tf.delete() - } - - // - // Construct and send a notification to a web server as JSON - // e.g. Microsoft Teams and Slack - // - public static void IM_notification(workflow, params, summary_params, projectDir, log) { - def hook_url = params.hook_url - - def summary = [:] - for (group in summary_params.keySet()) { - summary << summary_params[group] - } - - def misc_fields = [:] - misc_fields['start'] = workflow.start - misc_fields['complete'] = workflow.complete - misc_fields['scriptfile'] = workflow.scriptFile - misc_fields['scriptid'] = workflow.scriptId - if (workflow.repository) misc_fields['repository'] = workflow.repository - if (workflow.commitId) misc_fields['commitid'] = workflow.commitId - if (workflow.revision) misc_fields['revision'] = workflow.revision - misc_fields['nxf_version'] = workflow.nextflow.version - misc_fields['nxf_build'] = workflow.nextflow.build - misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp - - def msg_fields = [:] - msg_fields['version'] = NfcoreTemplate.version(workflow) - msg_fields['runName'] = workflow.runName - msg_fields['success'] = workflow.success - msg_fields['dateComplete'] = workflow.complete - msg_fields['duration'] = workflow.duration - msg_fields['exitStatus'] = workflow.exitStatus - msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - msg_fields['errorReport'] = (workflow.errorReport ?: 'None') - msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") - msg_fields['projectDir'] = workflow.projectDir - msg_fields['summary'] = summary << misc_fields - - // Render the JSON template - def engine = new groovy.text.GStringTemplateEngine() - // Different JSON depending on the service provider - // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format - def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" - def hf = new File("$projectDir/assets/${json_path}") - def json_template = engine.createTemplate(hf).make(msg_fields) - def json_message = json_template.toString() - - // POST - def post = new URL(hook_url).openConnection(); - post.setRequestMethod("POST") - post.setDoOutput(true) - post.setRequestProperty("Content-Type", "application/json") - post.getOutputStream().write(json_message.getBytes("UTF-8")); - def postRC = post.getResponseCode(); - if (! postRC.equals(200)) { - log.warn(post.getErrorStream().getText()); - } - } - - // - // Dump pipeline parameters in a json file - // - public static void dump_parameters(workflow, params) { - def timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') - def filename = "params_${timestamp}.json" - def temp_pf = new File(workflow.launchDir.toString(), ".${filename}") - def jsonStr = JsonOutput.toJson(params) - temp_pf.text = JsonOutput.prettyPrint(jsonStr) - - FilesEx.copyTo(temp_pf.toPath(), "${params.outdir}/pipeline_info/params_${timestamp}.json") - temp_pf.delete() - } - - // - // Print pipeline summary on completion - // - public static void summary(workflow, params, log) { - Map colors = logColours(params.monochrome_logs) - if (workflow.success) { - if (workflow.stats.ignoredCount == 0) { - log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Pipeline completed successfully${colors.reset}-" - } else { - log.info "-${colors.purple}[$workflow.manifest.name]${colors.yellow} Pipeline completed successfully, but with errored process(es) ${colors.reset}-" - } - } else { - log.info "-${colors.purple}[$workflow.manifest.name]${colors.red} Pipeline completed with errors${colors.reset}-" - } - } - - // - // ANSII Colours used for terminal logging - // - public static Map logColours(Boolean monochrome_logs) { - Map colorcodes = [:] - - // Reset / Meta - colorcodes['reset'] = monochrome_logs ? '' : "\033[0m" - colorcodes['bold'] = monochrome_logs ? '' : "\033[1m" - colorcodes['dim'] = monochrome_logs ? '' : "\033[2m" - colorcodes['underlined'] = monochrome_logs ? '' : "\033[4m" - colorcodes['blink'] = monochrome_logs ? '' : "\033[5m" - colorcodes['reverse'] = monochrome_logs ? '' : "\033[7m" - colorcodes['hidden'] = monochrome_logs ? '' : "\033[8m" - - // Regular Colors - colorcodes['black'] = monochrome_logs ? '' : "\033[0;30m" - colorcodes['red'] = monochrome_logs ? '' : "\033[0;31m" - colorcodes['green'] = monochrome_logs ? '' : "\033[0;32m" - colorcodes['yellow'] = monochrome_logs ? '' : "\033[0;33m" - colorcodes['blue'] = monochrome_logs ? '' : "\033[0;34m" - colorcodes['purple'] = monochrome_logs ? '' : "\033[0;35m" - colorcodes['cyan'] = monochrome_logs ? '' : "\033[0;36m" - colorcodes['white'] = monochrome_logs ? '' : "\033[0;37m" - - // Bold - colorcodes['bblack'] = monochrome_logs ? '' : "\033[1;30m" - colorcodes['bred'] = monochrome_logs ? '' : "\033[1;31m" - colorcodes['bgreen'] = monochrome_logs ? '' : "\033[1;32m" - colorcodes['byellow'] = monochrome_logs ? '' : "\033[1;33m" - colorcodes['bblue'] = monochrome_logs ? '' : "\033[1;34m" - colorcodes['bpurple'] = monochrome_logs ? '' : "\033[1;35m" - colorcodes['bcyan'] = monochrome_logs ? '' : "\033[1;36m" - colorcodes['bwhite'] = monochrome_logs ? '' : "\033[1;37m" - - // Underline - colorcodes['ublack'] = monochrome_logs ? '' : "\033[4;30m" - colorcodes['ured'] = monochrome_logs ? '' : "\033[4;31m" - colorcodes['ugreen'] = monochrome_logs ? '' : "\033[4;32m" - colorcodes['uyellow'] = monochrome_logs ? '' : "\033[4;33m" - colorcodes['ublue'] = monochrome_logs ? '' : "\033[4;34m" - colorcodes['upurple'] = monochrome_logs ? '' : "\033[4;35m" - colorcodes['ucyan'] = monochrome_logs ? '' : "\033[4;36m" - colorcodes['uwhite'] = monochrome_logs ? '' : "\033[4;37m" - - // High Intensity - colorcodes['iblack'] = monochrome_logs ? '' : "\033[0;90m" - colorcodes['ired'] = monochrome_logs ? '' : "\033[0;91m" - colorcodes['igreen'] = monochrome_logs ? '' : "\033[0;92m" - colorcodes['iyellow'] = monochrome_logs ? '' : "\033[0;93m" - colorcodes['iblue'] = monochrome_logs ? '' : "\033[0;94m" - colorcodes['ipurple'] = monochrome_logs ? '' : "\033[0;95m" - colorcodes['icyan'] = monochrome_logs ? '' : "\033[0;96m" - colorcodes['iwhite'] = monochrome_logs ? '' : "\033[0;97m" - - // Bold High Intensity - colorcodes['biblack'] = monochrome_logs ? '' : "\033[1;90m" - colorcodes['bired'] = monochrome_logs ? '' : "\033[1;91m" - colorcodes['bigreen'] = monochrome_logs ? '' : "\033[1;92m" - colorcodes['biyellow'] = monochrome_logs ? '' : "\033[1;93m" - colorcodes['biblue'] = monochrome_logs ? '' : "\033[1;94m" - colorcodes['bipurple'] = monochrome_logs ? '' : "\033[1;95m" - colorcodes['bicyan'] = monochrome_logs ? '' : "\033[1;96m" - colorcodes['biwhite'] = monochrome_logs ? '' : "\033[1;97m" - - return colorcodes - } - - // - // Does what is says on the tin - // - public static String dashedLine(monochrome_logs) { - Map colors = logColours(monochrome_logs) - return "-${colors.dim}----------------------------------------------------${colors.reset}-" - } - - // - // nf-core logo - // - public static String logo(workflow, monochrome_logs) { - Map colors = logColours(monochrome_logs) - String workflow_version = NfcoreTemplate.version(workflow) - String.format( - """\n - ${dashedLine(monochrome_logs)} - ${colors.green},--.${colors.black}/${colors.green},-.${colors.reset} - ${colors.blue} ___ __ __ __ ___ ${colors.green}/,-._.--~\'${colors.reset} - ${colors.blue} |\\ | |__ __ / ` / \\ |__) |__ ${colors.yellow}} {${colors.reset} - ${colors.blue} | \\| | \\__, \\__/ | \\ |___ ${colors.green}\\`-._,-`-,${colors.reset} - ${colors.green}`._,._,\'${colors.reset} - ${colors.purple} ${workflow.manifest.name} ${workflow_version}${colors.reset} - ${dashedLine(monochrome_logs)} - """.stripIndent() - ) - } -} diff --git a/lib/Utils.groovy b/lib/Utils.groovy deleted file mode 100644 index 8d030f4e..00000000 --- a/lib/Utils.groovy +++ /dev/null @@ -1,47 +0,0 @@ -// -// This file holds several Groovy functions that could be useful for any Nextflow pipeline -// - -import org.yaml.snakeyaml.Yaml - -class Utils { - - // - // When running with -profile conda, warn if channels have not been set-up appropriately - // - public static void checkCondaChannels(log) { - Yaml parser = new Yaml() - def channels = [] - try { - def config = parser.load("conda config --show channels".execute().text) - channels = config.channels - } catch(NullPointerException | IOException e) { - log.warn "Could not verify conda channel configuration." - return - } - - // Check that all channels are present - // This channel list is ordered by required channel priority. - def required_channels_in_order = ['conda-forge', 'bioconda', 'defaults'] - def channels_missing = ((required_channels_in_order as Set) - (channels as Set)) as Boolean - - // Check that they are in the right order - def channel_priority_violation = false - def n = required_channels_in_order.size() - for (int i = 0; i < n - 1; i++) { - channel_priority_violation |= !(channels.indexOf(required_channels_in_order[i]) < channels.indexOf(required_channels_in_order[i+1])) - } - - if (channels_missing | channel_priority_violation) { - log.warn "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + - " There is a problem with your Conda configuration!\n\n" + - " You will need to set-up the conda-forge and bioconda channels correctly.\n" + - " Please refer to https://bioconda.github.io/\n" + - " The observed channel order is \n" + - " ${channels}\n" + - " but the following channel order is required:\n" + - " ${required_channels_in_order}\n" + - "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - } - } -} diff --git a/lib/WorkflowCircrna.groovy b/lib/WorkflowCircrna.groovy deleted file mode 100755 index eae29c19..00000000 --- a/lib/WorkflowCircrna.groovy +++ /dev/null @@ -1,122 +0,0 @@ -// -// This file holds several functions specific to the workflow/circrna.nf in the nf-core/circrna pipeline -// - -import nextflow.Nextflow -import groovy.text.SimpleTemplateEngine - -class WorkflowCircrna { - - // - // Check and validate parameters - // - public static void initialise(params, log) { - - genomeExistsError(params, log) - - - if (!params.fasta) { - Nextflow.error "Genome fasta file not specified with e.g. '--fasta genome.fa' or via a detectable config file." - } - } - - // - // Get workflow summary for MultiQC - // - public static String paramsSummaryMultiqc(workflow, summary) { - String summary_section = '' - for (group in summary.keySet()) { - def group_params = summary.get(group) // This gets the parameters of that particular group - if (group_params) { - summary_section += "

    $group

    \n" - summary_section += "
    \n" - for (param in group_params.keySet()) { - summary_section += "
    $param
    ${group_params.get(param) ?: 'N/A'}
    \n" - } - summary_section += "
    \n" - } - } - - String yaml_file_text = "id: '${workflow.manifest.name.replace('/','-')}-summary'\n" - yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n" - yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n" - yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n" - yaml_file_text += "plot_type: 'html'\n" - yaml_file_text += "data: |\n" - yaml_file_text += "${summary_section}" - return yaml_file_text - } - - // - // Generate methods description for MultiQC - // - - public static String toolCitationText(params) { - - // TODO nf-core: Optionally add in-text citation tools to this list. - // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "", - // Uncomment function in methodsDescriptionText to render in MultiQC report - def citation_text = [ - "Tools used in the workflow included:", - "FastQC (Andrews 2010),", - "MultiQC (Ewels et al. 2016)", - "." - ].join(' ').trim() - - return citation_text - } - - public static String toolBibliographyText(params) { - - // TODO Optionally add bibliographic entries to this list. - // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "
  • Author (2023) Pub name, Journal, DOI
  • " : "", - // Uncomment function in methodsDescriptionText to render in MultiQC report - def reference_text = [ - "
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", - "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " - ].join(' ').trim() - - return reference_text - } - - public static String methodsDescriptionText(run_workflow, mqc_methods_yaml, params) { - // Convert to a named map so can be used as with familar NXF ${workflow} variable syntax in the MultiQC YML file - def meta = [:] - meta.workflow = run_workflow.toMap() - meta["manifest_map"] = run_workflow.manifest.toMap() - - // Pipeline DOI - meta["doi_text"] = meta.manifest_map.doi ? "(doi: ${meta.manifest_map.doi})" : "" - meta["nodoi_text"] = meta.manifest_map.doi ? "": "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " - - // Tool references - meta["tool_citations"] = "" - meta["tool_bibliography"] = "" - - // TODO Only uncomment below if logic in toolCitationText/toolBibliographyText has been filled! - //meta["tool_citations"] = toolCitationText(params).replaceAll(", \\.", ".").replaceAll("\\. \\.", ".").replaceAll(", \\.", ".") - //meta["tool_bibliography"] = toolBibliographyText(params) - - - def methods_text = mqc_methods_yaml.text - - def engine = new SimpleTemplateEngine() - def description_html = engine.createTemplate(methods_text).make(meta) - - return description_html - } - - // - // Exit pipeline if incorrect --genome key provided - // - private static void genomeExistsError(params, log) { - if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { - def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + - " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + - " Currently, the available genome keys are:\n" + - " ${params.genomes.keySet().join(", ")}\n" + - "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - Nextflow.error(error_string) - } - } -} diff --git a/lib/WorkflowMain.groovy b/lib/WorkflowMain.groovy deleted file mode 100755 index 03790911..00000000 --- a/lib/WorkflowMain.groovy +++ /dev/null @@ -1,81 +0,0 @@ -// -// This file holds several functions specific to the main.nf workflow in the nf-core/circrna pipeline -// - -import nextflow.Nextflow - -class WorkflowMain { - - // - // Citation string for pipeline - // - public static String citation(workflow) { - return "If you use ${workflow.manifest.name} for your analysis please cite:\n\n" + - // TODO nf-core: Add Zenodo DOI for pipeline after first release - //"* The pipeline\n" + - //" https://doi.org/10.5281/zenodo.XXXXXXX\n\n" + - "* The nf-core framework\n" + - " https://doi.org/10.1038/s41587-020-0439-x\n\n" + - "* Software dependencies\n" + - " https://github.com/${workflow.manifest.name}/blob/master/CITATIONS.md" - } - - - // - // Validate parameters and print summary to screen - // - public static void initialise(workflow, params, log, args) { - - // Print workflow version and exit on --version - if (params.version) { - String workflow_version = NfcoreTemplate.version(workflow) - log.info "${workflow.manifest.name} ${workflow_version}" - System.exit(0) - } - - // Check that a -profile or Nextflow config has been provided to run the pipeline - NfcoreTemplate.checkConfigProvided(workflow, log) - // Check that the profile doesn't contain spaces and doesn't end with a trailing comma - checkProfile(workflow.profile, args, log) - - // Check that conda channels are set-up correctly - if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - Utils.checkCondaChannels(log) - } - - // Check AWS batch settings - NfcoreTemplate.awsBatch(workflow, params) - - // Check input has been provided - if (!params.input) { - Nextflow.error("Please provide an input samplesheet to the pipeline e.g. '--input samplesheet.csv'") - } - - if (!params.species) { - Nextflow.error("Please provide a species to the pipeline e.g. '--species hsa'") - } - } - // - // Get attribute from genome config file e.g. fasta - // - public static Object getGenomeAttribute(params, attribute) { - if (params.genomes && params.genome && params.genomes.containsKey(params.genome)) { - if (params.genomes[ params.genome ].containsKey(attribute)) { - return params.genomes[ params.genome ][ attribute ] - } - } - return null - } - - // - // Exit pipeline if --profile contains spaces - // - private static void checkProfile(profile, args, log) { - if (profile.endsWith(',')) { - Nextflow.error "Profile cannot end with a trailing comma. Please remove the comma from the end of the profile string.\nHint: A common mistake is to provide multiple values to `-profile` separated by spaces. Please use commas to separate profiles instead,e.g., `-profile docker,test`." - } - if (args[0]) { - log.warn "nf-core pipelines do not accept positional arguments. The positional argument `${args[0]}` has been detected.\n Hint: A common mistake is to provide multiple values to `-profile` separated by spaces. Please use commas to separate profiles instead,e.g., `-profile docker,test`." - } - } -} diff --git a/main.nf b/main.nf index 61a893e9..66917a46 100644 --- a/main.nf +++ b/main.nf @@ -11,6 +11,18 @@ nextflow.enable.dsl = 2 +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + IMPORT FUNCTIONS / MODULES / SUBWORKFLOWS / WORKFLOWS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +include { CIRCRNA } from './workflows/circrna' +include { PIPELINE_INITIALISATION } from './subworkflows/local/utils_nfcore_circrna_pipeline' +include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_circrna_pipeline' + +include { getGenomeAttribute } from './subworkflows/local/utils_nfcore_circrna_pipeline' + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GENOME PARAMETER VALUES @@ -28,55 +40,73 @@ params.species = WorkflowMain.getGenomeAttribute(params, 'species_id') /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - VALIDATE & PRINT PARAMETER SUMMARY + NAMED WORKFLOWS FOR PIPELINE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { validateParameters; paramsHelp } from 'plugin/nf-validation' +// +// WORKFLOW: Run main analysis pipeline depending on type of input +// +workflow NFCORE_CIRCRNA { -// Print help message if needed -if (params.help) { - def logo = NfcoreTemplate.logo(workflow, params.monochrome_logs) - def citation = '\n' + WorkflowMain.citation(workflow) + '\n' - def String command = "nextflow run ${workflow.manifest.name} --input samplesheet.csv --genome GRCh37 -profile docker" - log.info logo + paramsHelp(command) + citation + NfcoreTemplate.dashedLine(params.monochrome_logs) - System.exit(0) -} + take: + samplesheet // channel: samplesheet read in from --input -// Validate input parameters -if (params.validate_params) { - validateParameters() -} + main: -WorkflowMain.initialise(workflow, params, log, args) + // + // WORKFLOW: Run pipeline + // + CIRCRNA ( + samplesheet + ) -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - NAMED WORKFLOW FOR PIPELINE -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ + emit: + multiqc_report = CIRCRNA.out.multiqc_report // channel: /path/to/multiqc_report.html -include { CIRCRNA } from './workflows/circrna' - -// -// WORKFLOW: Run main nf-core/circrna analysis pipeline -// -workflow NFCORE_CIRCRNA { - CIRCRNA () } - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - RUN ALL WORKFLOWS + RUN MAIN WORKFLOW ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -// -// WORKFLOW: Execute a single named workflow for the pipeline -// See: https://github.com/nf-core/rnaseq/issues/619 -// workflow { - NFCORE_CIRCRNA () + + main: + + // + // SUBWORKFLOW: Run initialisation tasks + // + PIPELINE_INITIALISATION ( + params.version, + params.help, + params.validate_params, + params.monochrome_logs, + args, + params.outdir, + params.input + ) + + // + // WORKFLOW: Run main workflow + // + NFCORE_CIRCRNA ( + PIPELINE_INITIALISATION.out.samplesheet + ) + + // + // SUBWORKFLOW: Run completion tasks + // + PIPELINE_COMPLETION ( + params.email, + params.email_on_fail, + params.plaintext_email, + params.outdir, + params.monochrome_logs, + params.hook_url, + NFCORE_CIRCRNA.out.multiqc_report + ) } /* diff --git a/modules.json b/modules.json index e1a5c225..59be5c70 100644 --- a/modules.json +++ b/modules.json @@ -102,7 +102,7 @@ }, "multiqc": { "branch": "master", - "git_sha": "8ec825f465b9c17f9d83000022995b4f7de6fe93", + "git_sha": "ccacf6f5de6df3bc6d73b665c1fd2933d8bbc290", "installed_by": ["modules"] }, "samtools/flagstat": { @@ -180,6 +180,25 @@ "installed_by": ["bam_sort_stats_samtools"] } } + }, + "subworkflows": { + "nf-core": { + "utils_nextflow_pipeline": { + "branch": "master", + "git_sha": "cd08c91373cd00a73255081340e4914485846ba1", + "installed_by": ["subworkflows"] + }, + "utils_nfcore_pipeline": { + "branch": "master", + "git_sha": "262b17ed2aad591039f914951659177e6c39a8d8", + "installed_by": ["subworkflows"] + }, + "utils_nfvalidation_plugin": { + "branch": "master", + "git_sha": "cd08c91373cd00a73255081340e4914485846ba1", + "installed_by": ["subworkflows"] + } + } } } } diff --git a/modules/local/samplesheet_check.nf b/modules/local/samplesheet_check.nf deleted file mode 100644 index e102f46d..00000000 --- a/modules/local/samplesheet_check.nf +++ /dev/null @@ -1,31 +0,0 @@ -process SAMPLESHEET_CHECK { - tag "$samplesheet" - label 'process_single' - - conda "conda-forge::python=3.8.3" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/python:3.8.3' : - 'biocontainers/python:3.8.3' }" - - input: - path samplesheet - - output: - path '*.csv' , emit: csv - path "versions.yml", emit: versions - - when: - task.ext.when == null || task.ext.when - - script: // This script is bundled with the pipeline, in nf-core/circrna/bin/ - """ - check_samplesheet.py \\ - $samplesheet \\ - samplesheet.valid.csv - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - python: \$(python --version | sed 's/Python //g') - END_VERSIONS - """ -} diff --git a/modules/nf-core/custom/dumpsoftwareversions/environment.yml b/modules/nf-core/custom/dumpsoftwareversions/environment.yml deleted file mode 100644 index 9b3272bc..00000000 --- a/modules/nf-core/custom/dumpsoftwareversions/environment.yml +++ /dev/null @@ -1,7 +0,0 @@ -name: custom_dumpsoftwareversions -channels: - - conda-forge - - bioconda - - defaults -dependencies: - - bioconda::multiqc=1.19 diff --git a/modules/nf-core/custom/dumpsoftwareversions/main.nf b/modules/nf-core/custom/dumpsoftwareversions/main.nf deleted file mode 100644 index f2187611..00000000 --- a/modules/nf-core/custom/dumpsoftwareversions/main.nf +++ /dev/null @@ -1,24 +0,0 @@ -process CUSTOM_DUMPSOFTWAREVERSIONS { - label 'process_single' - - // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.19--pyhdfd78af_0' : - 'biocontainers/multiqc:1.19--pyhdfd78af_0' }" - - input: - path versions - - output: - path "software_versions.yml" , emit: yml - path "software_versions_mqc.yml", emit: mqc_yml - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - template 'dumpsoftwareversions.py' -} diff --git a/modules/nf-core/custom/dumpsoftwareversions/meta.yml b/modules/nf-core/custom/dumpsoftwareversions/meta.yml deleted file mode 100644 index 5f15a5fd..00000000 --- a/modules/nf-core/custom/dumpsoftwareversions/meta.yml +++ /dev/null @@ -1,37 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json -name: custom_dumpsoftwareversions -description: Custom module used to dump software versions within the nf-core pipeline template -keywords: - - custom - - dump - - version -tools: - - custom: - description: Custom module used to dump software versions within the nf-core pipeline template - homepage: https://github.com/nf-core/tools - documentation: https://github.com/nf-core/tools - licence: ["MIT"] -input: - - versions: - type: file - description: YML file containing software versions - pattern: "*.yml" -output: - - yml: - type: file - description: Standard YML file containing software versions - pattern: "software_versions.yml" - - mqc_yml: - type: file - description: MultiQC custom content YML file containing software versions - pattern: "software_versions_mqc.yml" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" -authors: - - "@drpatelh" - - "@grst" -maintainers: - - "@drpatelh" - - "@grst" diff --git a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py deleted file mode 100755 index da033408..00000000 --- a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python - - -"""Provide functions to merge multiple versions.yml files.""" - - -import yaml -import platform -from textwrap import dedent - - -def _make_versions_html(versions): - """Generate a tabular HTML output of all versions for MultiQC.""" - html = [ - dedent( - """\\ - -
    Process Name \\", - " \\ Software Version
    CUSTOM_DUMPSOFTWAREVERSIONSpython3.11.7
    yaml5.4.1
    TOOL1tool10.11.9
    TOOL2tool21.9
    WorkflowNextflow
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    - - - - - - - - """ - ) - ] - for process, tmp_versions in sorted(versions.items()): - html.append("") - for i, (tool, version) in enumerate(sorted(tmp_versions.items())): - html.append( - dedent( - f"""\\ - - - - - - """ - ) - ) - html.append("") - html.append("
    Process Name Software Version
    {process if (i == 0) else ''}{tool}{version}
    ") - return "\\n".join(html) - - -def main(): - """Load all version files and generate merged output.""" - versions_this_module = {} - versions_this_module["${task.process}"] = { - "python": platform.python_version(), - "yaml": yaml.__version__, - } - - with open("$versions") as f: - versions_by_process = yaml.load(f, Loader=yaml.BaseLoader) | versions_this_module - - # aggregate versions by the module name (derived from fully-qualified process name) - versions_by_module = {} - for process, process_versions in versions_by_process.items(): - module = process.split(":")[-1] - try: - if versions_by_module[module] != process_versions: - raise AssertionError( - "We assume that software versions are the same between all modules. " - "If you see this error-message it means you discovered an edge-case " - "and should open an issue in nf-core/tools. " - ) - except KeyError: - versions_by_module[module] = process_versions - - versions_by_module["Workflow"] = { - "Nextflow": "$workflow.nextflow.version", - "$workflow.manifest.name": "$workflow.manifest.version", - } - - versions_mqc = { - "id": "software_versions", - "section_name": "${workflow.manifest.name} Software Versions", - "section_href": "https://github.com/${workflow.manifest.name}", - "plot_type": "html", - "description": "are collected at run time from the software output.", - "data": _make_versions_html(versions_by_module), - } - - with open("software_versions.yml", "w") as f: - yaml.dump(versions_by_module, f, default_flow_style=False) - with open("software_versions_mqc.yml", "w") as f: - yaml.dump(versions_mqc, f, default_flow_style=False) - - with open("versions.yml", "w") as f: - yaml.dump(versions_this_module, f, default_flow_style=False) - - -if __name__ == "__main__": - main() diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test deleted file mode 100644 index b1e1630b..00000000 --- a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test +++ /dev/null @@ -1,43 +0,0 @@ -nextflow_process { - - name "Test Process CUSTOM_DUMPSOFTWAREVERSIONS" - script "../main.nf" - process "CUSTOM_DUMPSOFTWAREVERSIONS" - tag "modules" - tag "modules_nfcore" - tag "custom" - tag "dumpsoftwareversions" - tag "custom/dumpsoftwareversions" - - test("Should run without failures") { - when { - process { - """ - def tool1_version = ''' - TOOL1: - tool1: 0.11.9 - '''.stripIndent() - - def tool2_version = ''' - TOOL2: - tool2: 1.9 - '''.stripIndent() - - input[0] = Channel.of(tool1_version, tool2_version).collectFile() - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot( - process.out.versions, - file(process.out.mqc_yml[0]).readLines()[0..10], - file(process.out.yml[0]).readLines()[0..7] - ).match() - } - ) - } - } -} diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap deleted file mode 100644 index 5f59a936..00000000 --- a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap +++ /dev/null @@ -1,33 +0,0 @@ -{ - "Should run without failures": { - "content": [ - [ - "versions.yml:md5,76d454d92244589d32455833f7c1ba6d" - ], - [ - "data: \"\\n\\n \\n \\n \\n \\n \\n \\n \\n\\", - " \\n\\n\\n \\n \\n\\", - " \\ \\n\\n\\n\\n \\n \\", - " \\ \\n \\n\\n\\n\\n\\", - " \\n\\n \\n \\n\\", - " \\ \\n\\n\\n\\n\\n\\n \\n\\", - " \\ \\n \\n\\n\\n\\n\\", - " \\n\\n \\n \\n\\" - ], - [ - "CUSTOM_DUMPSOFTWAREVERSIONS:", - " python: 3.11.7", - " yaml: 5.4.1", - "TOOL1:", - " tool1: 0.11.9", - "TOOL2:", - " tool2: '1.9'", - "Workflow:" - ] - ], - "timestamp": "2024-01-09T23:01:18.710682" - } -} \ No newline at end of file diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml b/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml deleted file mode 100644 index 405aa24a..00000000 --- a/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -custom/dumpsoftwareversions: - - modules/nf-core/custom/dumpsoftwareversions/** diff --git a/modules/nf-core/fastqc/tests/main.nf.test b/modules/nf-core/fastqc/tests/main.nf.test index 1f21c664..70edae4d 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test +++ b/modules/nf-core/fastqc/tests/main.nf.test @@ -33,7 +33,7 @@ nextflow_process { { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, { assert path(process.out.html[0][1]).text.contains("") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("fastqc_versions_single") } ) } } @@ -63,7 +63,7 @@ nextflow_process { { assert path(process.out.html[0][1][0]).text.contains("") }, { assert path(process.out.html[0][1][1]).text.contains("") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("fastqc_versions_paired") } ) } } @@ -89,7 +89,7 @@ nextflow_process { { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, { assert path(process.out.html[0][1]).text.contains("") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("fastqc_versions_interleaved") } ) } } @@ -115,7 +115,7 @@ nextflow_process { { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, { assert path(process.out.html[0][1]).text.contains("") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("fastqc_versions_bam") } ) } } @@ -153,7 +153,7 @@ nextflow_process { { assert path(process.out.html[0][1][2]).text.contains("") }, { assert path(process.out.html[0][1][3]).text.contains("") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("fastqc_versions_multiple") } ) } } @@ -179,7 +179,7 @@ nextflow_process { { assert process.out.zip[0][1] ==~ ".*/mysample_fastqc.zip" }, { assert path(process.out.html[0][1]).text.contains("") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("fastqc_versions_custom_prefix") } ) } } @@ -204,7 +204,7 @@ nextflow_process { { assert process.success }, { assert snapshot(process.out.html.collect { file(it[1]).getName() } + process.out.zip.collect { file(it[1]).getName() } + - process.out.versions ).match() } + process.out.versions ).match("fastqc_stub") } ) } } diff --git a/modules/nf-core/fastqc/tests/main.nf.test.snap b/modules/nf-core/fastqc/tests/main.nf.test.snap index 5d624bb8..86f7c311 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test.snap +++ b/modules/nf-core/fastqc/tests/main.nf.test.snap @@ -1,5 +1,17 @@ { - "sarscov2 single-end [fastq] - stub": { + "fastqc_versions_interleaved": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-01-31T17:40:07.293713" + }, + "fastqc_stub": { "content": [ [ "test.html", @@ -7,14 +19,70 @@ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], - "timestamp": "2024-01-17T18:40:57.254299" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-01-31T17:31:01.425198" + }, + "fastqc_versions_multiple": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-01-31T17:40:55.797907" + }, + "fastqc_versions_bam": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-01-31T17:40:26.795862" + }, + "fastqc_versions_single": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-01-31T17:39:27.043675" + }, + "fastqc_versions_paired": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-01-31T17:39:47.584191" }, - "versions": { + "fastqc_versions_custom_prefix": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], - "timestamp": "2024-01-17T18:36:50.033627" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-01-31T17:41:14.576531" } } \ No newline at end of file diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index 7625b752..2212096a 100644 --- a/modules/nf-core/multiqc/environment.yml +++ b/modules/nf-core/multiqc/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - bioconda::multiqc=1.19 + - bioconda::multiqc=1.20 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 1b9f7c43..354f4430 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -3,8 +3,8 @@ process MULTIQC { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.19--pyhdfd78af_0' : - 'biocontainers/multiqc:1.19--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.20--pyhdfd78af_0' : + 'biocontainers/multiqc:1.20--pyhdfd78af_0' }" input: path multiqc_files, stageAs: "?/*" diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test index d0438eda..f1c4242e 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -3,6 +3,7 @@ nextflow_process { name "Test Process MULTIQC" script "../main.nf" process "MULTIQC" + tag "modules" tag "modules_nfcore" tag "multiqc" @@ -12,7 +13,7 @@ nextflow_process { when { process { """ - input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)]) + input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) input[1] = [] input[2] = [] input[3] = [] @@ -25,7 +26,7 @@ nextflow_process { { assert process.success }, { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("multiqc_versions_single") } ) } @@ -36,7 +37,7 @@ nextflow_process { when { process { """ - input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)]) + input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) input[1] = Channel.of(file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true)) input[2] = [] input[3] = [] @@ -49,7 +50,7 @@ nextflow_process { { assert process.success }, { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out.versions).match("multiqc_versions_config") } ) } } @@ -61,7 +62,7 @@ nextflow_process { when { process { """ - input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)]) + input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) input[1] = [] input[2] = [] input[3] = [] @@ -75,7 +76,7 @@ nextflow_process { { assert snapshot(process.out.report.collect { file(it).getName() } + process.out.data.collect { file(it).getName() } + process.out.plots.collect { file(it).getName() } + - process.out.versions ).match() } + process.out.versions ).match("multiqc_stub") } ) } diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap index d37e7304..c204b488 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -1,21 +1,41 @@ { - "versions": { + "multiqc_versions_single": { "content": [ [ - "versions.yml:md5,14e9a2661241abd828f4f06a7b5c222d" + "versions.yml:md5,d320d4c37e349c5588e07e7a31cd4186" ] ], - "timestamp": "2024-01-09T23:02:49.911994" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-14T09:28:51.744211298" }, - "sarscov2 single-end [fastqc] - stub": { + "multiqc_stub": { "content": [ [ "multiqc_report.html", "multiqc_data", "multiqc_plots", - "versions.yml:md5,14e9a2661241abd828f4f06a7b5c222d" + "versions.yml:md5,d320d4c37e349c5588e07e7a31cd4186" ] ], - "timestamp": "2024-01-09T23:03:14.524346" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-14T09:29:28.847433492" + }, + "multiqc_versions_config": { + "content": [ + [ + "versions.yml:md5,d320d4c37e349c5588e07e7a31cd4186" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-14T09:29:13.223621555" } } \ No newline at end of file diff --git a/nextflow.config b/nextflow.config index 458e66e5..ffa9b39e 100644 --- a/nextflow.config +++ b/nextflow.config @@ -88,7 +88,6 @@ params { config_profile_contact = null config_profile_url = null - // Max resource options max_memory = '300.GB' max_cpus = 50 diff --git a/nextflow_schema.json b/nextflow_schema.json index 98c9bc80..5bdc6753 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -16,6 +16,7 @@ "type": "string", "format": "file-path", "exists": true, + "schema": "assets/schema_input.json", "mimetype": "text/csv", "pattern": "^\\S+\\.csv$", "description": "Path to comma-separated file containing information about the samples in the experiment.", diff --git a/pyproject.toml b/pyproject.toml index 7d08e1c8..56110621 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,11 +3,13 @@ [tool.ruff] line-length = 120 target-version = "py38" -select = ["I", "E1", "E4", "E7", "E9", "F", "UP", "N"] cache-dir = "~/.cache/ruff" -[tool.ruff.isort] +[tool.ruff.lint] +select = ["I", "E1", "E4", "E7", "E9", "F", "UP", "N"] + +[tool.ruff.lint.isort] known-first-party = ["nf_core"] -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "__init__.py" = ["E402", "F401"] diff --git a/subworkflows/local/input_check.nf b/subworkflows/local/input_check.nf deleted file mode 100644 index faf7c5b2..00000000 --- a/subworkflows/local/input_check.nf +++ /dev/null @@ -1,77 +0,0 @@ -// -// Check input files -// - -include { SAMPLESHEET_CHECK } from '../../modules/local/samplesheet_check' - -workflow INPUT_CHECK { - take: - samplesheet - ch_phenotype - - main: - phenotype = params.phenotype && params.module.contains('differential_expression') ? examine_phenotype(ch_phenotype) : Channel.empty() - - SAMPLESHEET_CHECK ( samplesheet ) - .csv - .splitCsv ( header:true, sep:',' ) - .map { create_fastq_channel(it) } - .set { reads } - - emit: - phenotype // Channel: [ pheno ] - reads // channel: [ val(meta), [ reads ] ] - versions = SAMPLESHEET_CHECK.out.versions // channel: [ versions.yml ] -} - -// Function to get list of [ meta, [ fastq_1, fastq_2 ] ] -def create_fastq_channel(LinkedHashMap row) { - // create meta map - def meta = [:] - meta.id = row.sample - meta.single_end = row.single_end.toBoolean() - - // add path(s) of the fastq file(s) to the meta map - def fastq_meta = [] - if (!file(row.fastq_1).exists()) { - exit 1, "ERROR: Please check input samplesheet -> Read 1 FastQ file does not exist!\n${row.fastq_1}" - } - if (meta.single_end) { - fastq_meta = [ meta, [ file(row.fastq_1) ] ] - - // Conduct check here, cannot figure out how to outside of this scope i.e accessing meta.single end for an if else from channel. - if(params.tool.split(',').contains('ciriquant')){ - exit 1, "ERROR: Unfortunately CIRIquant does not support single-end reads. Please select one of the other 6 quantification tools." - } - - } else { - if (!file(row.fastq_2).exists()) { - exit 1, "ERROR: Please check input samplesheet -> Read 2 FastQ file does not exist!\n${row.fastq_2}" - } - fastq_meta = [ meta, [ file(row.fastq_1), file(row.fastq_2) ] ] - } - return fastq_meta -} - - -def examine_phenotype(pheno){ - - Channel - .fromPath(pheno) - .splitCsv(header: true, sep: ',') - .map{ row -> - - def expected_cols = ['condition'] - - if (!row.keySet().containsAll(expected_cols)) exit 1, "[nf-core/circrna] error: 'condition' is not a column name in the phenotype file.\n\nThe primary response variable must be named 'condition', please refer to the usage documentation online" - - def condition = row.condition.matches('NA') ? 'NA' : row.condition - - if(condition == '') exit 1, "[nf-core/circrna] error: Invalid phenotype file, condition column contains empty cells." - if(condition.matches('NA')) exit 1, "[nf-core/circrna] error: NA value in phenotype condition column." - - } - .toList() - - return Channel.value(file(pheno)) -} diff --git a/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf b/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf new file mode 100644 index 00000000..dc90ad90 --- /dev/null +++ b/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf @@ -0,0 +1,247 @@ +// +// Subworkflow with functionality specific to the nf-core/pipeline pipeline +// + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + IMPORT FUNCTIONS / MODULES / SUBWORKFLOWS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +include { UTILS_NFVALIDATION_PLUGIN } from '../../nf-core/utils_nfvalidation_plugin' +include { paramsSummaryMap } from 'plugin/nf-validation' +include { fromSamplesheet } from 'plugin/nf-validation' +include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' +include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' +include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' +include { dashedLine } from '../../nf-core/utils_nfcore_pipeline' +include { nfCoreLogo } from '../../nf-core/utils_nfcore_pipeline' +include { imNotification } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' +include { workflowCitation } from '../../nf-core/utils_nfcore_pipeline' + +/* +======================================================================================== + SUBWORKFLOW TO INITIALISE PIPELINE +======================================================================================== +*/ + +workflow PIPELINE_INITIALISATION { + + take: + version // boolean: Display version and exit + help // boolean: Display help text + validate_params // boolean: Boolean whether to validate parameters against the schema at runtime + monochrome_logs // boolean: Do not use coloured log outputs + nextflow_cli_args // array: List of positional nextflow CLI args + outdir // string: The output directory where the results will be saved + input // string: Path to input samplesheet + + main: + + ch_versions = Channel.empty() + + // + // Print version and exit if required and dump pipeline parameters to JSON file + // + UTILS_NEXTFLOW_PIPELINE ( + version, + true, + outdir, + workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1 + ) + + // + // Validate parameters and generate parameter summary to stdout + // + pre_help_text = nfCoreLogo(monochrome_logs) + post_help_text = '\n' + workflowCitation() + '\n' + dashedLine(monochrome_logs) + def String workflow_command = "nextflow run ${workflow.manifest.name} -profile --input samplesheet.csv --outdir " + UTILS_NFVALIDATION_PLUGIN ( + help, + workflow_command, + pre_help_text, + post_help_text, + validate_params, + "nextflow_schema.json" + ) + + // + // Check config provided to the pipeline + // + UTILS_NFCORE_PIPELINE ( + nextflow_cli_args + ) + // + // Custom validation for pipeline parameters + // + validateInputParameters() + + // + // Create channel from input file provided through params.input + // + Channel + .fromSamplesheet("input") + .map { + meta, fastq_1, fastq_2 -> + if (!fastq_2) { + return [ meta.id, meta + [ single_end:true ], [ fastq_1 ] ] + } else { + return [ meta.id, meta + [ single_end:false ], [ fastq_1, fastq_2 ] ] + } + } + .groupTuple() + .map { + validateInputSamplesheet(it) + } + .map { + meta, fastqs -> + return [ meta, fastqs.flatten() ] + } + .set { ch_samplesheet } + + emit: + samplesheet = ch_samplesheet + versions = ch_versions +} + +/* +======================================================================================== + SUBWORKFLOW FOR PIPELINE COMPLETION +======================================================================================== +*/ + +workflow PIPELINE_COMPLETION { + + take: + email // string: email address + email_on_fail // string: email address sent on pipeline failure + plaintext_email // boolean: Send plain-text email instead of HTML + outdir // path: Path to output directory where results will be published + monochrome_logs // boolean: Disable ANSI colour codes in log output + hook_url // string: hook URL for notifications + multiqc_report // string: Path to MultiQC report + + main: + + summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") + + // + // Completion email and summary + // + workflow.onComplete { + if (email || email_on_fail) { + completionEmail(summary_params, email, email_on_fail, plaintext_email, outdir, monochrome_logs, multiqc_report.toList()) + } + + completionSummary(monochrome_logs) + + if (hook_url) { + imNotification(summary_params, hook_url) + } + } +} + +/* +======================================================================================== + FUNCTIONS +======================================================================================== +*/ +// +// Check and validate pipeline parameters +// +def validateInputParameters() { + genomeExistsError() +}// +// Validate channels from input samplesheet +// +def validateInputSamplesheet(input) { + def (metas, fastqs) = input[1..2] + + // Check that multiple runs of the same sample are of the same datatype i.e. single-end / paired-end + def endedness_ok = metas.collect{ it.single_end }.unique().size == 1 + if (!endedness_ok) { + error("Please check input samplesheet -> Multiple runs of a sample must be of the same datatype i.e. single-end or paired-end: ${metas[0].id}") + } + + return [ metas[0], fastqs ] +} +// +// Get attribute from genome config file e.g. fasta +// +def getGenomeAttribute(attribute) { + if (params.genomes && params.genome && params.genomes.containsKey(params.genome)) { + if (params.genomes[ params.genome ].containsKey(attribute)) { + return params.genomes[ params.genome ][ attribute ] + } + } + return null +} + +// +// Exit pipeline if incorrect --genome key provided +// +def genomeExistsError() { + if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { + def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + + " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + + " Currently, the available genome keys are:\n" + + " ${params.genomes.keySet().join(", ")}\n" + + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + error(error_string) + } +}// +// Generate methods description for MultiQC +// +def toolCitationText() { + // TODO nf-core: Optionally add in-text citation tools to this list. + // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "", + // Uncomment function in methodsDescriptionText to render in MultiQC report + def citation_text = [ + "Tools used in the workflow included:", + "FastQC (Andrews 2010),", + "MultiQC (Ewels et al. 2016)", + "." + ].join(' ').trim() + + return citation_text +} + +def toolBibliographyText() { + // TODO nf-core: Optionally add bibliographic entries to this list. + // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "
  • Author (2023) Pub name, Journal, DOI
  • " : "", + // Uncomment function in methodsDescriptionText to render in MultiQC report + def reference_text = [ + "
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", + "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " + ].join(' ').trim() + + return reference_text +} + +def methodsDescriptionText(mqc_methods_yaml) { + // Convert to a named map so can be used as with familar NXF ${workflow} variable syntax in the MultiQC YML file + def meta = [:] + meta.workflow = workflow.toMap() + meta["manifest_map"] = workflow.manifest.toMap() + + // Pipeline DOI + meta["doi_text"] = meta.manifest_map.doi ? "(doi: ${meta.manifest_map.doi})" : "" + meta["nodoi_text"] = meta.manifest_map.doi ? "": "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " + + // Tool references + meta["tool_citations"] = "" + meta["tool_bibliography"] = "" + + // TODO nf-core: Only uncomment below if logic in toolCitationText/toolBibliographyText has been filled! + // meta["tool_citations"] = toolCitationText().replaceAll(", \\.", ".").replaceAll("\\. \\.", ".").replaceAll(", \\.", ".") + // meta["tool_bibliography"] = toolBibliographyText() + + + def methods_text = mqc_methods_yaml.text + + def engine = new groovy.text.SimpleTemplateEngine() + def description_html = engine.createTemplate(methods_text).make(meta) + + return description_html.toString() +} diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf new file mode 100644 index 00000000..ac31f28f --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf @@ -0,0 +1,126 @@ +// +// Subworkflow with functionality that may be useful for any Nextflow pipeline +// + +import org.yaml.snakeyaml.Yaml +import groovy.json.JsonOutput +import nextflow.extension.FilesEx + +/* +======================================================================================== + SUBWORKFLOW DEFINITION +======================================================================================== +*/ + +workflow UTILS_NEXTFLOW_PIPELINE { + + take: + print_version // boolean: print version + dump_parameters // boolean: dump parameters + outdir // path: base directory used to publish pipeline results + check_conda_channels // boolean: check conda channels + + main: + + // + // Print workflow version and exit on --version + // + if (print_version) { + log.info "${workflow.manifest.name} ${getWorkflowVersion()}" + System.exit(0) + } + + // + // Dump pipeline parameters to a JSON file + // + if (dump_parameters && outdir) { + dumpParametersToJSON(outdir) + } + + // + // When running with Conda, warn if channels have not been set-up appropriately + // + if (check_conda_channels) { + checkCondaChannels() + } + + emit: + dummy_emit = true +} + +/* +======================================================================================== + FUNCTIONS +======================================================================================== +*/ + +// +// Generate version string +// +def getWorkflowVersion() { + String version_string = "" + if (workflow.manifest.version) { + def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : '' + version_string += "${prefix_v}${workflow.manifest.version}" + } + + if (workflow.commitId) { + def git_shortsha = workflow.commitId.substring(0, 7) + version_string += "-g${git_shortsha}" + } + + return version_string +} + +// +// Dump pipeline parameters to a JSON file +// +def dumpParametersToJSON(outdir) { + def timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') + def filename = "params_${timestamp}.json" + def temp_pf = new File(workflow.launchDir.toString(), ".${filename}") + def jsonStr = JsonOutput.toJson(params) + temp_pf.text = JsonOutput.prettyPrint(jsonStr) + + FilesEx.copyTo(temp_pf.toPath(), "${outdir}/pipeline_info/params_${timestamp}.json") + temp_pf.delete() +} + +// +// When running with -profile conda, warn if channels have not been set-up appropriately +// +def checkCondaChannels() { + Yaml parser = new Yaml() + def channels = [] + try { + def config = parser.load("conda config --show channels".execute().text) + channels = config.channels + } catch(NullPointerException | IOException e) { + log.warn "Could not verify conda channel configuration." + return + } + + // Check that all channels are present + // This channel list is ordered by required channel priority. + def required_channels_in_order = ['conda-forge', 'bioconda', 'defaults'] + def channels_missing = ((required_channels_in_order as Set) - (channels as Set)) as Boolean + + // Check that they are in the right order + def channel_priority_violation = false + def n = required_channels_in_order.size() + for (int i = 0; i < n - 1; i++) { + channel_priority_violation |= !(channels.indexOf(required_channels_in_order[i]) < channels.indexOf(required_channels_in_order[i+1])) + } + + if (channels_missing | channel_priority_violation) { + log.warn "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + + " There is a problem with your Conda configuration!\n\n" + + " You will need to set-up the conda-forge and bioconda channels correctly.\n" + + " Please refer to https://bioconda.github.io/\n" + + " The observed channel order is \n" + + " ${channels}\n" + + " but the following channel order is required:\n" + + " ${required_channels_in_order}\n" + + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + } +} diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/meta.yml b/subworkflows/nf-core/utils_nextflow_pipeline/meta.yml new file mode 100644 index 00000000..e5c3a0a8 --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/meta.yml @@ -0,0 +1,38 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "UTILS_NEXTFLOW_PIPELINE" +description: Subworkflow with functionality that may be useful for any Nextflow pipeline +keywords: + - utility + - pipeline + - initialise + - version +components: [] +input: + - print_version: + type: boolean + description: | + Print the version of the pipeline and exit + - dump_parameters: + type: boolean + description: | + Dump the parameters of the pipeline to a JSON file + - output_directory: + type: directory + description: Path to output dir to write JSON file to. + pattern: "results/" + - check_conda_channel: + type: boolean + description: | + Check if the conda channel priority is correct. +output: + - dummy_emit: + type: boolean + description: | + Dummy emit to make nf-core subworkflows lint happy +authors: + - "@adamrtalbot" + - "@drpatelh" +maintainers: + - "@adamrtalbot" + - "@drpatelh" + - "@maxulysse" diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test new file mode 100644 index 00000000..8ed4310c --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test @@ -0,0 +1,54 @@ + +nextflow_function { + + name "Test Functions" + script "subworkflows/nf-core/utils_nextflow_pipeline/main.nf" + config "subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config" + tag 'subworkflows' + tag 'utils_nextflow_pipeline' + tag 'subworkflows/utils_nextflow_pipeline' + + test("Test Function getWorkflowVersion") { + + function "getWorkflowVersion" + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function dumpParametersToJSON") { + + function "dumpParametersToJSON" + + when { + function { + """ + // define inputs of the function here. Example: + input[0] = "$outputDir" + """.stripIndent() + } + } + + then { + assertAll( + { assert function.success } + ) + } + } + + test("Test Function checkCondaChannels") { + + function "checkCondaChannels" + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap new file mode 100644 index 00000000..db2030f8 --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap @@ -0,0 +1,12 @@ +{ + "Test Function getWorkflowVersion": { + "content": [ + "v9.9.9" + ], + "timestamp": "2024-01-19T11:32:36.031083" + }, + "Test Function checkCondaChannels": { + "content": null, + "timestamp": "2024-01-19T11:32:50.456" + } +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test new file mode 100644 index 00000000..f7c54bc6 --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test @@ -0,0 +1,123 @@ +nextflow_workflow { + + name "Test Workflow UTILS_NEXTFLOW_PIPELINE" + script "../main.nf" + config "subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config" + workflow "UTILS_NEXTFLOW_PIPELINE" + tag 'subworkflows' + tag 'utils_nextflow_pipeline' + tag 'subworkflows/utils_nextflow_pipeline' + + test("Should run no inputs") { + + when { + params { + outdir = "tests/results" + } + workflow { + """ + print_version = false + dump_parameters = false + outdir = null + check_conda_channels = false + + input[0] = print_version + input[1] = dump_parameters + input[2] = outdir + input[3] = check_conda_channels + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } + + test("Should print version") { + + when { + params { + outdir = "tests/results" + } + workflow { + """ + print_version = true + dump_parameters = false + outdir = null + check_conda_channels = false + + input[0] = print_version + input[1] = dump_parameters + input[2] = outdir + input[3] = check_conda_channels + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert workflow.stdout.contains("nextflow_workflow v9.9.9") } + ) + } + } + + test("Should dump params") { + + when { + params { + outdir = "$outputDir" + } + workflow { + """ + print_version = false + dump_parameters = true + outdir = params.outdir + check_conda_channels = false + + input[0] = false + input[1] = true + input[2] = params.outdir + input[3] = false + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } + + test("Should not create params JSON if no output directory") { + + when { + params { + outdir = "$outputDir" + } + workflow { + """ + print_version = false + dump_parameters = true + outdir = params.outdir + check_conda_channels = false + + input[0] = false + input[1] = true + input[2] = null + input[3] = false + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } +} diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config b/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config new file mode 100644 index 00000000..53574ffe --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config @@ -0,0 +1,9 @@ +manifest { + name = 'nextflow_workflow' + author = """nf-core""" + homePage = 'https://127.0.0.1' + description = """Dummy pipeline""" + nextflowVersion = '!>=23.04.0' + version = '9.9.9' + doi = 'https://doi.org/10.5281/zenodo.5070524' +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml b/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml new file mode 100644 index 00000000..f8476112 --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml @@ -0,0 +1,2 @@ +subworkflows/utils_nextflow_pipeline: + - subworkflows/nf-core/utils_nextflow_pipeline/** diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf new file mode 100644 index 00000000..a8b55d6f --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -0,0 +1,440 @@ +// +// Subworkflow with utility functions specific to the nf-core pipeline template +// + +import org.yaml.snakeyaml.Yaml +import nextflow.extension.FilesEx + +/* +======================================================================================== + SUBWORKFLOW DEFINITION +======================================================================================== +*/ + +workflow UTILS_NFCORE_PIPELINE { + + take: + nextflow_cli_args + + main: + valid_config = checkConfigProvided() + checkProfileProvided(nextflow_cli_args) + + emit: + valid_config +} + +/* +======================================================================================== + FUNCTIONS +======================================================================================== +*/ + +// +// Warn if a -profile or Nextflow config has not been provided to run the pipeline +// +def checkConfigProvided() { + valid_config = true + if (workflow.profile == 'standard' && workflow.configFiles.size() <= 1) { + log.warn "[$workflow.manifest.name] You are attempting to run the pipeline without any custom configuration!\n\n" + + "This will be dependent on your local compute environment but can be achieved via one or more of the following:\n" + + " (1) Using an existing pipeline profile e.g. `-profile docker` or `-profile singularity`\n" + + " (2) Using an existing nf-core/configs for your Institution e.g. `-profile crick` or `-profile uppmax`\n" + + " (3) Using your own local custom config e.g. `-c /path/to/your/custom.config`\n\n" + + "Please refer to the quick start section and usage docs for the pipeline.\n " + valid_config = false + } + return valid_config +} + +// +// Exit pipeline if --profile contains spaces +// +def checkProfileProvided(nextflow_cli_args) { + if (workflow.profile.endsWith(',')) { + error "The `-profile` option cannot end with a trailing comma, please remove it and re-run the pipeline!\n" + + "HINT: A common mistake is to provide multiple values separated by spaces e.g. `-profile test, docker`.\n" + } + if (nextflow_cli_args[0]) { + log.warn "nf-core pipelines do not accept positional arguments. The positional argument `${nextflow_cli_args[0]}` has been detected.\n" + + "HINT: A common mistake is to provide multiple values separated by spaces e.g. `-profile test, docker`.\n" + } +} + +// +// Citation string for pipeline +// +def workflowCitation() { + return "If you use ${workflow.manifest.name} for your analysis please cite:\n\n" + + "* The pipeline\n" + + " ${workflow.manifest.doi}\n\n" + + "* The nf-core framework\n" + + " https://doi.org/10.1038/s41587-020-0439-x\n\n" + + "* Software dependencies\n" + + " https://github.com/${workflow.manifest.name}/blob/master/CITATIONS.md" +} + +// +// Generate workflow version string +// +def getWorkflowVersion() { + String version_string = "" + if (workflow.manifest.version) { + def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : '' + version_string += "${prefix_v}${workflow.manifest.version}" + } + + if (workflow.commitId) { + def git_shortsha = workflow.commitId.substring(0, 7) + version_string += "-g${git_shortsha}" + } + + return version_string +} + +// +// Get software versions for pipeline +// +def processVersionsFromYAML(yaml_file) { + Yaml yaml = new Yaml() + versions = yaml.load(yaml_file).collectEntries { k, v -> [ k.tokenize(':')[-1], v ] } + return yaml.dumpAsMap(versions).trim() +} + +// +// Get workflow version for pipeline +// +def workflowVersionToYAML() { + return """ + Workflow: + $workflow.manifest.name: ${getWorkflowVersion()} + Nextflow: $workflow.nextflow.version + """.stripIndent().trim() +} + +// +// Get channel of software versions used in pipeline in YAML format +// +def softwareVersionsToYAML(ch_versions) { + return ch_versions + .unique() + .map { processVersionsFromYAML(it) } + .unique() + .mix(Channel.of(workflowVersionToYAML())) +} + +// +// Get workflow summary for MultiQC +// +def paramsSummaryMultiqc(summary_params) { + def summary_section = '' + for (group in summary_params.keySet()) { + def group_params = summary_params.get(group) // This gets the parameters of that particular group + if (group_params) { + summary_section += "

    $group

    \n" + summary_section += "
    \n" + for (param in group_params.keySet()) { + summary_section += "
    $param
    ${group_params.get(param) ?: 'N/A'}
    \n" + } + summary_section += "
    \n" + } + } + + String yaml_file_text = "id: '${workflow.manifest.name.replace('/','-')}-summary'\n" + yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n" + yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n" + yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n" + yaml_file_text += "plot_type: 'html'\n" + yaml_file_text += "data: |\n" + yaml_file_text += "${summary_section}" + + return yaml_file_text +} + +// +// nf-core logo +// +def nfCoreLogo(monochrome_logs=true) { + Map colors = logColours(monochrome_logs) + String.format( + """\n + ${dashedLine(monochrome_logs)} + ${colors.green},--.${colors.black}/${colors.green},-.${colors.reset} + ${colors.blue} ___ __ __ __ ___ ${colors.green}/,-._.--~\'${colors.reset} + ${colors.blue} |\\ | |__ __ / ` / \\ |__) |__ ${colors.yellow}} {${colors.reset} + ${colors.blue} | \\| | \\__, \\__/ | \\ |___ ${colors.green}\\`-._,-`-,${colors.reset} + ${colors.green}`._,._,\'${colors.reset} + ${colors.purple} ${workflow.manifest.name} ${getWorkflowVersion()}${colors.reset} + ${dashedLine(monochrome_logs)} + """.stripIndent() + ) +} + +// +// Return dashed line +// +def dashedLine(monochrome_logs=true) { + Map colors = logColours(monochrome_logs) + return "-${colors.dim}----------------------------------------------------${colors.reset}-" +} + +// +// ANSII colours used for terminal logging +// +def logColours(monochrome_logs=true) { + Map colorcodes = [:] + + // Reset / Meta + colorcodes['reset'] = monochrome_logs ? '' : "\033[0m" + colorcodes['bold'] = monochrome_logs ? '' : "\033[1m" + colorcodes['dim'] = monochrome_logs ? '' : "\033[2m" + colorcodes['underlined'] = monochrome_logs ? '' : "\033[4m" + colorcodes['blink'] = monochrome_logs ? '' : "\033[5m" + colorcodes['reverse'] = monochrome_logs ? '' : "\033[7m" + colorcodes['hidden'] = monochrome_logs ? '' : "\033[8m" + + // Regular Colors + colorcodes['black'] = monochrome_logs ? '' : "\033[0;30m" + colorcodes['red'] = monochrome_logs ? '' : "\033[0;31m" + colorcodes['green'] = monochrome_logs ? '' : "\033[0;32m" + colorcodes['yellow'] = monochrome_logs ? '' : "\033[0;33m" + colorcodes['blue'] = monochrome_logs ? '' : "\033[0;34m" + colorcodes['purple'] = monochrome_logs ? '' : "\033[0;35m" + colorcodes['cyan'] = monochrome_logs ? '' : "\033[0;36m" + colorcodes['white'] = monochrome_logs ? '' : "\033[0;37m" + + // Bold + colorcodes['bblack'] = monochrome_logs ? '' : "\033[1;30m" + colorcodes['bred'] = monochrome_logs ? '' : "\033[1;31m" + colorcodes['bgreen'] = monochrome_logs ? '' : "\033[1;32m" + colorcodes['byellow'] = monochrome_logs ? '' : "\033[1;33m" + colorcodes['bblue'] = monochrome_logs ? '' : "\033[1;34m" + colorcodes['bpurple'] = monochrome_logs ? '' : "\033[1;35m" + colorcodes['bcyan'] = monochrome_logs ? '' : "\033[1;36m" + colorcodes['bwhite'] = monochrome_logs ? '' : "\033[1;37m" + + // Underline + colorcodes['ublack'] = monochrome_logs ? '' : "\033[4;30m" + colorcodes['ured'] = monochrome_logs ? '' : "\033[4;31m" + colorcodes['ugreen'] = monochrome_logs ? '' : "\033[4;32m" + colorcodes['uyellow'] = monochrome_logs ? '' : "\033[4;33m" + colorcodes['ublue'] = monochrome_logs ? '' : "\033[4;34m" + colorcodes['upurple'] = monochrome_logs ? '' : "\033[4;35m" + colorcodes['ucyan'] = monochrome_logs ? '' : "\033[4;36m" + colorcodes['uwhite'] = monochrome_logs ? '' : "\033[4;37m" + + // High Intensity + colorcodes['iblack'] = monochrome_logs ? '' : "\033[0;90m" + colorcodes['ired'] = monochrome_logs ? '' : "\033[0;91m" + colorcodes['igreen'] = monochrome_logs ? '' : "\033[0;92m" + colorcodes['iyellow'] = monochrome_logs ? '' : "\033[0;93m" + colorcodes['iblue'] = monochrome_logs ? '' : "\033[0;94m" + colorcodes['ipurple'] = monochrome_logs ? '' : "\033[0;95m" + colorcodes['icyan'] = monochrome_logs ? '' : "\033[0;96m" + colorcodes['iwhite'] = monochrome_logs ? '' : "\033[0;97m" + + // Bold High Intensity + colorcodes['biblack'] = monochrome_logs ? '' : "\033[1;90m" + colorcodes['bired'] = monochrome_logs ? '' : "\033[1;91m" + colorcodes['bigreen'] = monochrome_logs ? '' : "\033[1;92m" + colorcodes['biyellow'] = monochrome_logs ? '' : "\033[1;93m" + colorcodes['biblue'] = monochrome_logs ? '' : "\033[1;94m" + colorcodes['bipurple'] = monochrome_logs ? '' : "\033[1;95m" + colorcodes['bicyan'] = monochrome_logs ? '' : "\033[1;96m" + colorcodes['biwhite'] = monochrome_logs ? '' : "\033[1;97m" + + return colorcodes +} + +// +// Attach the multiqc report to email +// +def attachMultiqcReport(multiqc_report) { + def mqc_report = null + try { + if (workflow.success) { + mqc_report = multiqc_report.getVal() + if (mqc_report.getClass() == ArrayList && mqc_report.size() >= 1) { + if (mqc_report.size() > 1) { + log.warn "[$workflow.manifest.name] Found multiple reports from process 'MULTIQC', will use only one" + } + mqc_report = mqc_report[0] + } + } + } catch (all) { + if (multiqc_report) { + log.warn "[$workflow.manifest.name] Could not attach MultiQC report to summary email" + } + } + return mqc_report +} + +// +// Construct and send completion email +// +def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdir, monochrome_logs=true, multiqc_report=null) { + + // Set up the e-mail variables + def subject = "[$workflow.manifest.name] Successful: $workflow.runName" + if (!workflow.success) { + subject = "[$workflow.manifest.name] FAILED: $workflow.runName" + } + + def summary = [:] + for (group in summary_params.keySet()) { + summary << summary_params[group] + } + + def misc_fields = [:] + misc_fields['Date Started'] = workflow.start + misc_fields['Date Completed'] = workflow.complete + misc_fields['Pipeline script file path'] = workflow.scriptFile + misc_fields['Pipeline script hash ID'] = workflow.scriptId + if (workflow.repository) misc_fields['Pipeline repository Git URL'] = workflow.repository + if (workflow.commitId) misc_fields['Pipeline repository Git Commit'] = workflow.commitId + if (workflow.revision) misc_fields['Pipeline Git branch/tag'] = workflow.revision + misc_fields['Nextflow Version'] = workflow.nextflow.version + misc_fields['Nextflow Build'] = workflow.nextflow.build + misc_fields['Nextflow Compile Timestamp'] = workflow.nextflow.timestamp + + def email_fields = [:] + email_fields['version'] = getWorkflowVersion() + email_fields['runName'] = workflow.runName + email_fields['success'] = workflow.success + email_fields['dateComplete'] = workflow.complete + email_fields['duration'] = workflow.duration + email_fields['exitStatus'] = workflow.exitStatus + email_fields['errorMessage'] = (workflow.errorMessage ?: 'None') + email_fields['errorReport'] = (workflow.errorReport ?: 'None') + email_fields['commandLine'] = workflow.commandLine + email_fields['projectDir'] = workflow.projectDir + email_fields['summary'] = summary << misc_fields + + // On success try attach the multiqc report + def mqc_report = attachMultiqcReport(multiqc_report) + + // Check if we are only sending emails on failure + def email_address = email + if (!email && email_on_fail && !workflow.success) { + email_address = email_on_fail + } + + // Render the TXT template + def engine = new groovy.text.GStringTemplateEngine() + def tf = new File("${workflow.projectDir}/assets/email_template.txt") + def txt_template = engine.createTemplate(tf).make(email_fields) + def email_txt = txt_template.toString() + + // Render the HTML template + def hf = new File("${workflow.projectDir}/assets/email_template.html") + def html_template = engine.createTemplate(hf).make(email_fields) + def email_html = html_template.toString() + + // Render the sendmail template + def max_multiqc_email_size = (params.containsKey('max_multiqc_email_size') ? params.max_multiqc_email_size : 0) as nextflow.util.MemoryUnit + def smail_fields = [ email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "${workflow.projectDir}", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes() ] + def sf = new File("${workflow.projectDir}/assets/sendmail_template.txt") + def sendmail_template = engine.createTemplate(sf).make(smail_fields) + def sendmail_html = sendmail_template.toString() + + // Send the HTML e-mail + Map colors = logColours(monochrome_logs) + if (email_address) { + try { + if (plaintext_email) { throw GroovyException('Send plaintext e-mail, not HTML') } + // Try to send HTML e-mail using sendmail + def sendmail_tf = new File(workflow.launchDir.toString(), ".sendmail_tmp.html") + sendmail_tf.withWriter { w -> w << sendmail_html } + [ 'sendmail', '-t' ].execute() << sendmail_html + log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Sent summary e-mail to $email_address (sendmail)-" + } catch (all) { + // Catch failures and try with plaintext + def mail_cmd = [ 'mail', '-s', subject, '--content-type=text/html', email_address ] + mail_cmd.execute() << email_html + log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Sent summary e-mail to $email_address (mail)-" + } + } + + // Write summary e-mail HTML to a file + def output_hf = new File(workflow.launchDir.toString(), ".pipeline_report.html") + output_hf.withWriter { w -> w << email_html } + FilesEx.copyTo(output_hf.toPath(), "${outdir}/pipeline_info/pipeline_report.html"); + output_hf.delete() + + // Write summary e-mail TXT to a file + def output_tf = new File(workflow.launchDir.toString(), ".pipeline_report.txt") + output_tf.withWriter { w -> w << email_txt } + FilesEx.copyTo(output_tf.toPath(), "${outdir}/pipeline_info/pipeline_report.txt"); + output_tf.delete() +} + +// +// Print pipeline summary on completion +// +def completionSummary(monochrome_logs=true) { + Map colors = logColours(monochrome_logs) + if (workflow.success) { + if (workflow.stats.ignoredCount == 0) { + log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Pipeline completed successfully${colors.reset}-" + } else { + log.info "-${colors.purple}[$workflow.manifest.name]${colors.yellow} Pipeline completed successfully, but with errored process(es) ${colors.reset}-" + } + } else { + log.info "-${colors.purple}[$workflow.manifest.name]${colors.red} Pipeline completed with errors${colors.reset}-" + } +} + +// +// Construct and send a notification to a web server as JSON e.g. Microsoft Teams and Slack +// +def imNotification(summary_params, hook_url) { + def summary = [:] + for (group in summary_params.keySet()) { + summary << summary_params[group] + } + + def misc_fields = [:] + misc_fields['start'] = workflow.start + misc_fields['complete'] = workflow.complete + misc_fields['scriptfile'] = workflow.scriptFile + misc_fields['scriptid'] = workflow.scriptId + if (workflow.repository) misc_fields['repository'] = workflow.repository + if (workflow.commitId) misc_fields['commitid'] = workflow.commitId + if (workflow.revision) misc_fields['revision'] = workflow.revision + misc_fields['nxf_version'] = workflow.nextflow.version + misc_fields['nxf_build'] = workflow.nextflow.build + misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp + + def msg_fields = [:] + msg_fields['version'] = getWorkflowVersion() + msg_fields['runName'] = workflow.runName + msg_fields['success'] = workflow.success + msg_fields['dateComplete'] = workflow.complete + msg_fields['duration'] = workflow.duration + msg_fields['exitStatus'] = workflow.exitStatus + msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') + msg_fields['errorReport'] = (workflow.errorReport ?: 'None') + msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") + msg_fields['projectDir'] = workflow.projectDir + msg_fields['summary'] = summary << misc_fields + + // Render the JSON template + def engine = new groovy.text.GStringTemplateEngine() + // Different JSON depending on the service provider + // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format + def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" + def hf = new File("${workflow.projectDir}/assets/${json_path}") + def json_template = engine.createTemplate(hf).make(msg_fields) + def json_message = json_template.toString() + + // POST + def post = new URL(hook_url).openConnection(); + post.setRequestMethod("POST") + post.setDoOutput(true) + post.setRequestProperty("Content-Type", "application/json") + post.getOutputStream().write(json_message.getBytes("UTF-8")); + def postRC = post.getResponseCode(); + if (! postRC.equals(200)) { + log.warn(post.getErrorStream().getText()); + } +} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/meta.yml b/subworkflows/nf-core/utils_nfcore_pipeline/meta.yml new file mode 100644 index 00000000..d08d2434 --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/meta.yml @@ -0,0 +1,24 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "UTILS_NFCORE_PIPELINE" +description: Subworkflow with utility functions specific to the nf-core pipeline template +keywords: + - utility + - pipeline + - initialise + - version +components: [] +input: + - nextflow_cli_args: + type: list + description: | + Nextflow CLI positional arguments +output: + - success: + type: boolean + description: | + Dummy output to indicate success +authors: + - "@adamrtalbot" +maintainers: + - "@adamrtalbot" + - "@maxulysse" diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test new file mode 100644 index 00000000..1dc317f8 --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test @@ -0,0 +1,134 @@ + +nextflow_function { + + name "Test Functions" + script "../main.nf" + config "subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config" + tag "subworkflows" + tag "subworkflows_nfcore" + tag "utils_nfcore_pipeline" + tag "subworkflows/utils_nfcore_pipeline" + + test("Test Function checkConfigProvided") { + + function "checkConfigProvided" + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function checkProfileProvided") { + + function "checkProfileProvided" + + when { + function { + """ + input[0] = [] + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function workflowCitation") { + + function "workflowCitation" + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function nfCoreLogo") { + + function "nfCoreLogo" + + when { + function { + """ + input[0] = false + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function dashedLine") { + + function "dashedLine" + + when { + function { + """ + input[0] = false + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function without logColours") { + + function "logColours" + + when { + function { + """ + input[0] = true + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function with logColours") { + function "logColours" + + when { + function { + """ + input[0] = false + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } +} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap new file mode 100644 index 00000000..10f948e6 --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap @@ -0,0 +1,138 @@ +{ + "Test Function checkProfileProvided": { + "content": null, + "timestamp": "2024-02-09T15:43:55.145717" + }, + "Test Function checkConfigProvided": { + "content": [ + true + ], + "timestamp": "2024-01-19T11:34:13.548431224" + }, + "Test Function nfCoreLogo": { + "content": [ + "\n\n-\u001b[2m----------------------------------------------------\u001b[0m-\n \u001b[0;32m,--.\u001b[0;30m/\u001b[0;32m,-.\u001b[0m\n\u001b[0;34m ___ __ __ __ ___ \u001b[0;32m/,-._.--~'\u001b[0m\n\u001b[0;34m |\\ | |__ __ / ` / \\ |__) |__ \u001b[0;33m} {\u001b[0m\n\u001b[0;34m | \\| | \\__, \\__/ | \\ |___ \u001b[0;32m\\`-._,-`-,\u001b[0m\n \u001b[0;32m`._,._,'\u001b[0m\n\u001b[0;35m nextflow_workflow v9.9.9\u001b[0m\n-\u001b[2m----------------------------------------------------\u001b[0m-\n" + ], + "timestamp": "2024-01-19T11:34:38.840454873" + }, + "Test Function workflowCitation": { + "content": [ + "If you use nextflow_workflow for your analysis please cite:\n\n* The pipeline\n https://doi.org/10.5281/zenodo.5070524\n\n* The nf-core framework\n https://doi.org/10.1038/s41587-020-0439-x\n\n* Software dependencies\n https://github.com/nextflow_workflow/blob/master/CITATIONS.md" + ], + "timestamp": "2024-01-19T11:34:22.24352016" + }, + "Test Function without logColours": { + "content": [ + { + "reset": "", + "bold": "", + "dim": "", + "underlined": "", + "blink": "", + "reverse": "", + "hidden": "", + "black": "", + "red": "", + "green": "", + "yellow": "", + "blue": "", + "purple": "", + "cyan": "", + "white": "", + "bblack": "", + "bred": "", + "bgreen": "", + "byellow": "", + "bblue": "", + "bpurple": "", + "bcyan": "", + "bwhite": "", + "ublack": "", + "ured": "", + "ugreen": "", + "uyellow": "", + "ublue": "", + "upurple": "", + "ucyan": "", + "uwhite": "", + "iblack": "", + "ired": "", + "igreen": "", + "iyellow": "", + "iblue": "", + "ipurple": "", + "icyan": "", + "iwhite": "", + "biblack": "", + "bired": "", + "bigreen": "", + "biyellow": "", + "biblue": "", + "bipurple": "", + "bicyan": "", + "biwhite": "" + } + ], + "timestamp": "2024-01-19T11:35:04.418416984" + }, + "Test Function dashedLine": { + "content": [ + "-\u001b[2m----------------------------------------------------\u001b[0m-" + ], + "timestamp": "2024-01-19T11:34:55.420000755" + }, + "Test Function with logColours": { + "content": [ + { + "reset": "\u001b[0m", + "bold": "\u001b[1m", + "dim": "\u001b[2m", + "underlined": "\u001b[4m", + "blink": "\u001b[5m", + "reverse": "\u001b[7m", + "hidden": "\u001b[8m", + "black": "\u001b[0;30m", + "red": "\u001b[0;31m", + "green": "\u001b[0;32m", + "yellow": "\u001b[0;33m", + "blue": "\u001b[0;34m", + "purple": "\u001b[0;35m", + "cyan": "\u001b[0;36m", + "white": "\u001b[0;37m", + "bblack": "\u001b[1;30m", + "bred": "\u001b[1;31m", + "bgreen": "\u001b[1;32m", + "byellow": "\u001b[1;33m", + "bblue": "\u001b[1;34m", + "bpurple": "\u001b[1;35m", + "bcyan": "\u001b[1;36m", + "bwhite": "\u001b[1;37m", + "ublack": "\u001b[4;30m", + "ured": "\u001b[4;31m", + "ugreen": "\u001b[4;32m", + "uyellow": "\u001b[4;33m", + "ublue": "\u001b[4;34m", + "upurple": "\u001b[4;35m", + "ucyan": "\u001b[4;36m", + "uwhite": "\u001b[4;37m", + "iblack": "\u001b[0;90m", + "ired": "\u001b[0;91m", + "igreen": "\u001b[0;92m", + "iyellow": "\u001b[0;93m", + "iblue": "\u001b[0;94m", + "ipurple": "\u001b[0;95m", + "icyan": "\u001b[0;96m", + "iwhite": "\u001b[0;97m", + "biblack": "\u001b[1;90m", + "bired": "\u001b[1;91m", + "bigreen": "\u001b[1;92m", + "biyellow": "\u001b[1;93m", + "biblue": "\u001b[1;94m", + "bipurple": "\u001b[1;95m", + "bicyan": "\u001b[1;96m", + "biwhite": "\u001b[1;97m" + } + ], + "timestamp": "2024-01-19T11:35:13.436366565" + } +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test new file mode 100644 index 00000000..8940d32d --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test @@ -0,0 +1,29 @@ +nextflow_workflow { + + name "Test Workflow UTILS_NFCORE_PIPELINE" + script "../main.nf" + config "subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config" + workflow "UTILS_NFCORE_PIPELINE" + tag "subworkflows" + tag "subworkflows_nfcore" + tag "utils_nfcore_pipeline" + tag "subworkflows/utils_nfcore_pipeline" + + test("Should run without failures") { + + when { + workflow { + """ + input[0] = [] + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert snapshot(workflow.out).match() } + ) + } + } +} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap new file mode 100644 index 00000000..d07ce54c --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap @@ -0,0 +1,15 @@ +{ + "Should run without failures": { + "content": [ + { + "0": [ + true + ], + "valid_config": [ + true + ] + } + ], + "timestamp": "2024-01-19T11:35:22.538940073" + } +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config b/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config new file mode 100644 index 00000000..d0a926bf --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config @@ -0,0 +1,9 @@ +manifest { + name = 'nextflow_workflow' + author = """nf-core""" + homePage = 'https://127.0.0.1' + description = """Dummy pipeline""" + nextflowVersion = '!>=23.04.0' + version = '9.9.9' + doi = 'https://doi.org/10.5281/zenodo.5070524' +} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml b/subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml new file mode 100644 index 00000000..ac8523c9 --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml @@ -0,0 +1,2 @@ +subworkflows/utils_nfcore_pipeline: + - subworkflows/nf-core/utils_nfcore_pipeline/** diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/main.nf b/subworkflows/nf-core/utils_nfvalidation_plugin/main.nf new file mode 100644 index 00000000..2585b65d --- /dev/null +++ b/subworkflows/nf-core/utils_nfvalidation_plugin/main.nf @@ -0,0 +1,62 @@ +// +// Subworkflow that uses the nf-validation plugin to render help text and parameter summary +// + +/* +======================================================================================== + IMPORT NF-VALIDATION PLUGIN +======================================================================================== +*/ + +include { paramsHelp } from 'plugin/nf-validation' +include { paramsSummaryLog } from 'plugin/nf-validation' +include { validateParameters } from 'plugin/nf-validation' + +/* +======================================================================================== + SUBWORKFLOW DEFINITION +======================================================================================== +*/ + +workflow UTILS_NFVALIDATION_PLUGIN { + + take: + print_help // boolean: print help + workflow_command // string: default commmand used to run pipeline + pre_help_text // string: string to be printed before help text and summary log + post_help_text // string: string to be printed after help text and summary log + validate_params // boolean: validate parameters + schema_filename // path: JSON schema file, null to use default value + + main: + + log.debug "Using schema file: ${schema_filename}" + + // Default values for strings + pre_help_text = pre_help_text ?: '' + post_help_text = post_help_text ?: '' + workflow_command = workflow_command ?: '' + + // + // Print help message if needed + // + if (print_help) { + log.info pre_help_text + paramsHelp(workflow_command, parameters_schema: schema_filename) + post_help_text + System.exit(0) + } + + // + // Print parameter summary to stdout + // + log.info pre_help_text + paramsSummaryLog(workflow, parameters_schema: schema_filename) + post_help_text + + // + // Validate parameters relative to the parameter JSON schema + // + if (validate_params){ + validateParameters(parameters_schema: schema_filename) + } + + emit: + dummy_emit = true +} diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/meta.yml b/subworkflows/nf-core/utils_nfvalidation_plugin/meta.yml new file mode 100644 index 00000000..3d4a6b04 --- /dev/null +++ b/subworkflows/nf-core/utils_nfvalidation_plugin/meta.yml @@ -0,0 +1,44 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "UTILS_NFVALIDATION_PLUGIN" +description: Use nf-validation to initiate and validate a pipeline +keywords: + - utility + - pipeline + - initialise + - validation +components: [] +input: + - print_help: + type: boolean + description: | + Print help message and exit + - workflow_command: + type: string + description: | + The command to run the workflow e.g. "nextflow run main.nf" + - pre_help_text: + type: string + description: | + Text to print before the help message + - post_help_text: + type: string + description: | + Text to print after the help message + - validate_params: + type: boolean + description: | + Validate the parameters and error if invalid. + - schema_filename: + type: string + description: | + The filename of the schema to validate against. +output: + - dummy_emit: + type: boolean + description: | + Dummy emit to make nf-core subworkflows lint happy +authors: + - "@adamrtalbot" +maintainers: + - "@adamrtalbot" + - "@maxulysse" diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test new file mode 100644 index 00000000..517ee54e --- /dev/null +++ b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test @@ -0,0 +1,200 @@ +nextflow_workflow { + + name "Test Workflow UTILS_NFVALIDATION_PLUGIN" + script "../main.nf" + workflow "UTILS_NFVALIDATION_PLUGIN" + tag "subworkflows" + tag "subworkflows_nfcore" + tag "plugin/nf-validation" + tag "'plugin/nf-validation'" + tag "utils_nfvalidation_plugin" + tag "subworkflows/utils_nfvalidation_plugin" + + test("Should run nothing") { + + when { + + params { + monochrome_logs = true + test_data = '' + } + + workflow { + """ + help = false + workflow_command = null + pre_help_text = null + post_help_text = null + validate_params = false + schema_filename = "$moduleTestDir/nextflow_schema.json" + + input[0] = help + input[1] = workflow_command + input[2] = pre_help_text + input[3] = post_help_text + input[4] = validate_params + input[5] = schema_filename + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } + + test("Should run help") { + + + when { + + params { + monochrome_logs = true + test_data = '' + } + workflow { + """ + help = true + workflow_command = null + pre_help_text = null + post_help_text = null + validate_params = false + schema_filename = "$moduleTestDir/nextflow_schema.json" + + input[0] = help + input[1] = workflow_command + input[2] = pre_help_text + input[3] = post_help_text + input[4] = validate_params + input[5] = schema_filename + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert workflow.exitStatus == 0 }, + { assert workflow.stdout.any { it.contains('Input/output options') } }, + { assert workflow.stdout.any { it.contains('--outdir') } } + ) + } + } + + test("Should run help with command") { + + when { + + params { + monochrome_logs = true + test_data = '' + } + workflow { + """ + help = true + workflow_command = "nextflow run noorg/doesntexist" + pre_help_text = null + post_help_text = null + validate_params = false + schema_filename = "$moduleTestDir/nextflow_schema.json" + + input[0] = help + input[1] = workflow_command + input[2] = pre_help_text + input[3] = post_help_text + input[4] = validate_params + input[5] = schema_filename + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert workflow.exitStatus == 0 }, + { assert workflow.stdout.any { it.contains('nextflow run noorg/doesntexist') } }, + { assert workflow.stdout.any { it.contains('Input/output options') } }, + { assert workflow.stdout.any { it.contains('--outdir') } } + ) + } + } + + test("Should run help with extra text") { + + + when { + + params { + monochrome_logs = true + test_data = '' + } + workflow { + """ + help = true + workflow_command = "nextflow run noorg/doesntexist" + pre_help_text = "pre-help-text" + post_help_text = "post-help-text" + validate_params = false + schema_filename = "$moduleTestDir/nextflow_schema.json" + + input[0] = help + input[1] = workflow_command + input[2] = pre_help_text + input[3] = post_help_text + input[4] = validate_params + input[5] = schema_filename + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert workflow.exitStatus == 0 }, + { assert workflow.stdout.any { it.contains('pre-help-text') } }, + { assert workflow.stdout.any { it.contains('nextflow run noorg/doesntexist') } }, + { assert workflow.stdout.any { it.contains('Input/output options') } }, + { assert workflow.stdout.any { it.contains('--outdir') } }, + { assert workflow.stdout.any { it.contains('post-help-text') } } + ) + } + } + + test("Should validate params") { + + when { + + params { + monochrome_logs = true + test_data = '' + outdir = 1 + } + workflow { + """ + help = false + workflow_command = null + pre_help_text = null + post_help_text = null + validate_params = true + schema_filename = "$moduleTestDir/nextflow_schema.json" + + input[0] = help + input[1] = workflow_command + input[2] = pre_help_text + input[3] = post_help_text + input[4] = validate_params + input[5] = schema_filename + """ + } + } + + then { + assertAll( + { assert workflow.failed }, + { assert workflow.stdout.any { it.contains('ERROR ~ ERROR: Validation of pipeline parameters failed!') } } + ) + } + } +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json new file mode 100644 index 00000000..7626c1c9 --- /dev/null +++ b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json @@ -0,0 +1,96 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://raw.githubusercontent.com/./master/nextflow_schema.json", + "title": ". pipeline parameters", + "description": "", + "type": "object", + "definitions": { + "input_output_options": { + "title": "Input/output options", + "type": "object", + "fa_icon": "fas fa-terminal", + "description": "Define where the pipeline should find input data and save output data.", + "required": ["outdir"], + "properties": { + "validate_params": { + "type": "boolean", + "description": "Validate parameters?", + "default": true, + "hidden": true + }, + "outdir": { + "type": "string", + "format": "directory-path", + "description": "The output directory where the results will be saved. You have to use absolute paths to storage on Cloud infrastructure.", + "fa_icon": "fas fa-folder-open" + }, + "test_data_base": { + "type": "string", + "default": "https://raw.githubusercontent.com/nf-core/test-datasets/modules", + "description": "Base for test data directory", + "hidden": true + }, + "test_data": { + "type": "string", + "description": "Fake test data param", + "hidden": true + } + } + }, + "generic_options": { + "title": "Generic options", + "type": "object", + "fa_icon": "fas fa-file-import", + "description": "Less common options for the pipeline, typically set in a config file.", + "help_text": "These options are common to all nf-core pipelines and allow you to customise some of the core preferences for how the pipeline runs.\n\nTypically these options would be set in a Nextflow config file loaded for all pipeline runs, such as `~/.nextflow/config`.", + "properties": { + "help": { + "type": "boolean", + "description": "Display help text.", + "fa_icon": "fas fa-question-circle", + "hidden": true + }, + "version": { + "type": "boolean", + "description": "Display version and exit.", + "fa_icon": "fas fa-question-circle", + "hidden": true + }, + "logo": { + "type": "boolean", + "default": true, + "description": "Display nf-core logo in console output.", + "fa_icon": "fas fa-image", + "hidden": true + }, + "singularity_pull_docker_container": { + "type": "boolean", + "description": "Pull Singularity container from Docker?", + "hidden": true + }, + "publish_dir_mode": { + "type": "string", + "default": "copy", + "description": "Method used to save pipeline results to output directory.", + "help_text": "The Nextflow `publishDir` option specifies which intermediate files should be saved to the output directory. This option tells the pipeline what method should be used to move these files. See [Nextflow docs](https://www.nextflow.io/docs/latest/process.html#publishdir) for details.", + "fa_icon": "fas fa-copy", + "enum": ["symlink", "rellink", "link", "copy", "copyNoFollow", "move"], + "hidden": true + }, + "monochrome_logs": { + "type": "boolean", + "description": "Use monochrome_logs", + "hidden": true + } + } + } + }, + "allOf": [ + { + "$ref": "#/definitions/input_output_options" + }, + { + "$ref": "#/definitions/generic_options" + } + ] +} diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml new file mode 100644 index 00000000..60b1cfff --- /dev/null +++ b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml @@ -0,0 +1,2 @@ +subworkflows/utils_nfvalidation_plugin: + - subworkflows/nf-core/utils_nfvalidation_plugin/** diff --git a/workflows/circrna.nf b/workflows/circrna.nf index f540065b..af4880bd 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -1,6 +1,6 @@ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - PRINT PARAMS SUMMARY + IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -98,9 +98,6 @@ include { FASTQC_TRIMGALORE } from '../subworkflows/nf-core/fastqc_trimgalore' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -// Info required for completion email and summary -def multiqc_report = [] - workflow CIRCRNA { ch_reports = Channel.empty() @@ -230,9 +227,12 @@ workflow CIRCRNA { ch_versions = ch_versions.mix(DIFFERENTIAL_EXPRESSION.out.versions) ch_reports = ch_reports.mix(DIFFERENTIAL_EXPRESSION.out.reports) - CUSTOM_DUMPSOFTWAREVERSIONS ( - ch_versions.unique().collectFile(name: 'collated_versions.yml') - ) + // + // Collate and save software versions + // + softwareVersionsToYAML(ch_versions) + .collectFile(storeDir: "${params.outdir}/pipeline_info", name: 'nf_core_pipeline_software_mqc_versions.yml', sort: true, newLine: true) + .set { ch_collated_versions } // MODULE: MultiQC workflow_summary = WorkflowCircrna.paramsSummaryMultiqc(workflow, summary_params) @@ -254,31 +254,10 @@ workflow CIRCRNA { ch_multiqc_custom_config.toList(), ch_multiqc_logo.toList() ) - multiqc_report = MULTIQC.out.report.toList() -} -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - COMPLETION EMAIL AND SUMMARY -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - -workflow.onComplete { - if (params.email || params.email_on_fail) { - NfcoreTemplate.email(workflow, params, summary_params, projectDir, log, multiqc_report) - } - NfcoreTemplate.dump_parameters(workflow, params) - NfcoreTemplate.summary(workflow, params, log) - if (params.hook_url) { - NfcoreTemplate.IM_notification(workflow, params, summary_params, projectDir, log) - } -} - -workflow.onError { - if (workflow.errorReport.contains("Process requirement exceeds available memory")) { - println("🛑 Default resources exceed availability 🛑 ") - println("💡 See here on how to configure pipeline: https://nf-co.re/docs/usage/configuration#tuning-workflow-resources 💡") - } + emit: + multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html + versions = ch_versions // channel: [ path(versions.yml) ] } /* From 499eef1746f1e1f769f34b2ec786e3435512e013 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 29 Feb 2024 09:58:27 +0100 Subject: [PATCH 129/491] Implement pipeline changes necessary for the 2.13 tools update --- main.nf | 16 +-- .../utils_nfcore_circrna_pipeline/main.nf | 35 +++++- workflows/{circrna.nf => circrna/main.nf} | 102 ++++-------------- 3 files changed, 64 insertions(+), 89 deletions(-) rename workflows/{circrna.nf => circrna/main.nf} (69%) diff --git a/main.nf b/main.nf index 66917a46..f3e91b43 100644 --- a/main.nf +++ b/main.nf @@ -29,14 +29,14 @@ include { getGenomeAttribute } from './subworkflows/local/utils_nfcore_circ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -params.fasta = WorkflowMain.getGenomeAttribute(params, 'fasta') -params.gtf = WorkflowMain.getGenomeAttribute(params, 'gtf') -params.bwa = WorkflowMain.getGenomeAttribute(params, 'bwa') -params.star = WorkflowMain.getGenomeAttribute(params, 'star') -params.bowtie = WorkflowMain.getGenomeAttribute(params, 'bowtie') -params.bowtie2 = WorkflowMain.getGenomeAttribute(params, 'bowtie2') -params.mature = WorkflowMain.getGenomeAttribute(params, 'mature') -params.species = WorkflowMain.getGenomeAttribute(params, 'species_id') +params.fasta = getGenomeAttribute('fasta') +params.gtf = getGenomeAttribute('gtf') +params.bwa = getGenomeAttribute('bwa') +params.star = getGenomeAttribute('star') +params.bowtie = getGenomeAttribute('bowtie') +params.bowtie2 = getGenomeAttribute('bowtie2') +params.mature = getGenomeAttribute('mature') +params.species = getGenomeAttribute('species_id') /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf b/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf index dc90ad90..f67b0a4e 100644 --- a/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf @@ -190,7 +190,20 @@ def genomeExistsError() { "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" error(error_string) } -}// +} + +def moduleExistsError() { + if (params.module && !checkParameterList(params.module, defineModuleList())) { + def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + + " Module '${params.modules.join(", ")}' not found in the pipeline.\n" + + " Currently, the available modules are:\n" + + " ${defineModuleList().join(", ")}\n" + + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + error(error_string) + } +} + +// // Generate methods description for MultiQC // def toolCitationText() { @@ -245,3 +258,23 @@ def methodsDescriptionText(mqc_methods_yaml) { return description_html.toString() } + +def defineModuleList() { + return [ + 'circrna_discovery', + 'mirna_prediction', + 'differential_expression' + ] +} + +def checkParameterExistence(it, list) { + if (!list.contains(it)) { + log.warn "Unknown parameter: ${it}" + return false + } + return true +} + +def checkParameterList(list, realList) { + return list.every{ checkParameterExistence(it, realList) } +} \ No newline at end of file diff --git a/workflows/circrna.nf b/workflows/circrna/main.nf similarity index 69% rename from workflows/circrna.nf rename to workflows/circrna/main.nf index af4880bd..f1c0b592 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna/main.nf @@ -4,52 +4,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { paramsSummaryLog; paramsSummaryMap } from 'plugin/nf-validation' - -def logo = NfcoreTemplate.logo(workflow, params.monochrome_logs) -def citation = '\n' + WorkflowMain.citation(workflow) + '\n' -def summary_params = paramsSummaryMap(workflow) - -// Print parameter summary log to screen -log.info logo + paramsSummaryLog(workflow) + citation - -WorkflowCircrna.initialise(params, log) - -// Check modules paramater -def checkParameterExistence(it, list) { - if (!list.contains(it)) { - log.warn "Unknown parameter: ${it}" - return false - } - return true -} - -def checkParameterList(list, realList) { - return list.every{ checkParameterExistence(it, realList) } -} - -def defineModuleList() { - return [ - 'circrna_discovery', - 'mirna_prediction', - 'differential_expression' - ] -} - -moduleList = defineModuleList() -module = params.module ? params.module.split(',').collect{it.trim().toLowerCase()} : [] -if(!checkParameterList(module, moduleList)) { - log.error "error: Unknown module selected, please choose one of the following:\n\n circrna_discovery\n\n mirna_prediction\n\n differential_expression\n\nPlease refer to the help documentation for a description of each module." - System.exit(1) -} - -// Check input path parameters to see if they exist -def checkPathParamList = [ params.input, params.multiqc_config ] -for (param in checkPathParamList) { if (param) { file(param, checkIfExists: true) } } - -// Check mandatory parameters -if (params.input) { ch_input = file(params.input) } else { exit 1, 'Input samplesheet not specified!' } - ch_phenotype = params.phenotype && params.module.contains('differential_expression') ? file(params.phenotype, checkIfExists:true) : Channel.empty() ch_fasta = params.fasta ? file(params.fasta) : 'null' ch_gtf = params.gtf ? file(params.gtf) : 'null' @@ -73,11 +27,12 @@ ch_multiqc_custom_methods_description = params.multiqc_methods_description ? fil */ // SUBWORKFLOWS: -include { INPUT_CHECK } from '../subworkflows/local/input_check' -include { PREPARE_GENOME } from '../subworkflows/local/prepare_genome' -include { CIRCRNA_DISCOVERY } from '../subworkflows/local/circrna_discovery' -include { MIRNA_PREDICTION } from '../subworkflows/local/mirna_prediction' -include { DIFFERENTIAL_EXPRESSION } from '../subworkflows/local/differential_expression' +include { paramsSummaryMultiqc } from '../../subworkflows/nf-core/utils_nfcore_pipeline' +include { softwareVersionsToYAML } from '../../subworkflows/nf-core/utils_nfcore_pipeline' +include { PREPARE_GENOME } from '../../subworkflows/local/prepare_genome' +include { CIRCRNA_DISCOVERY } from '../../subworkflows/local/circrna_discovery' +include { MIRNA_PREDICTION } from '../../subworkflows/local/mirna_prediction' +include { DIFFERENTIAL_EXPRESSION } from '../../subworkflows/local/differential_expression' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -86,12 +41,11 @@ include { DIFFERENTIAL_EXPRESSION } from '../subworkflows/local/differential_exp */ // MODULES: -include { MULTIQC } from '../modules/nf-core/multiqc/main' -include { CUSTOM_DUMPSOFTWAREVERSIONS } from '../modules/nf-core/custom/dumpsoftwareversions/main' -include { CAT_FASTQ } from '../modules/nf-core/cat/fastq/main' +include { MULTIQC } from '../../modules/nf-core/multiqc/main' +include { CAT_FASTQ } from '../../modules/nf-core/cat/fastq/main' // SUBWORKFLOWS: -include { FASTQC_TRIMGALORE } from '../subworkflows/nf-core/fastqc_trimgalore' +include { FASTQC_TRIMGALORE } from '../../subworkflows/nf-core/fastqc_trimgalore' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RUN MAIN WORKFLOW @@ -99,38 +53,26 @@ include { FASTQC_TRIMGALORE } from '../subworkflows/nf-core/fastqc_trimgalore' */ workflow CIRCRNA { + take: + ch_samplesheet + ch_versions - ch_reports = Channel.empty() - ch_versions = Channel.empty() + main: // // 1. Pre-processing // // SUBWORKFLOW: - // Validate input samplesheet & phenotype file - INPUT_CHECK ( - ch_input, - ch_phenotype - ) - .reads - .map { - meta, fastq -> - meta.id = meta.id.split('_')[0..-2].join('_') - [ meta, fastq ] } - .groupTuple(by: [0]) - .branch { - meta, fastq -> - single : fastq.size() == 1 - return [ meta, fastq.flatten() ] - multiple: fastq.size() > 1 - return [ meta, fastq.flatten() ] - } - .set { ch_fastq } - ch_versions = ch_versions.mix(INPUT_CHECK.out.versions) - // TODO: OPTIONAL, you can use nf-validation plugin to create an input channel from the samplesheet with Channel.fromSamplesheet("input") - // See the documentation https://nextflow-io.github.io/nf-validation/samplesheets/fromSamplesheet/ - // ! There is currently no tooling to help you write a sample sheet schema + ch_samplesheet + .branch { + meta, fastq -> + single : fastq.size() == 1 + return [ meta, fastq.flatten() ] + multiple: fastq.size() > 1 + return [ meta, fastq.flatten() ] + } + .set { ch_fastq } // MODULE: // Concatenate FastQ files from same sample if required From 6184a4971e28e27bf0540946c4ee9048d8f0f03c Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 29 Feb 2024 10:34:06 +0100 Subject: [PATCH 130/491] Fix some more problems with template update --- main.nf | 16 +++++------ workflows/circrna/main.nf | 56 +++++++++++++++++++++++++-------------- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/main.nf b/main.nf index f3e91b43..9cf725ef 100644 --- a/main.nf +++ b/main.nf @@ -48,17 +48,17 @@ params.species = getGenomeAttribute('species_id') // WORKFLOW: Run main analysis pipeline depending on type of input // workflow NFCORE_CIRCRNA { - - take: - samplesheet // channel: samplesheet read in from --input - main: + ch_versions = Channel.empty() + // - // WORKFLOW: Run pipeline + // WORKFLOW: Run nf-core/circrna workflow // + ch_samplesheet = Channel.value(file(params.input, checkIfExists: true)) CIRCRNA ( - samplesheet + ch_samplesheet, + ch_versions ) emit: @@ -91,9 +91,7 @@ workflow { // // WORKFLOW: Run main workflow // - NFCORE_CIRCRNA ( - PIPELINE_INITIALISATION.out.samplesheet - ) + NFCORE_CIRCRNA () // // SUBWORKFLOW: Run completion tasks diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index f1c0b592..84f5723c 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -27,7 +27,10 @@ ch_multiqc_custom_methods_description = params.multiqc_methods_description ? fil */ // SUBWORKFLOWS: +include { paramsSummaryMap } from 'plugin/nf-validation' include { paramsSummaryMultiqc } from '../../subworkflows/nf-core/utils_nfcore_pipeline' +include { validateInputSamplesheet } from '../../subworkflows/local/utils_nfcore_circrna_pipeline' + include { softwareVersionsToYAML } from '../../subworkflows/nf-core/utils_nfcore_pipeline' include { PREPARE_GENOME } from '../../subworkflows/local/prepare_genome' include { CIRCRNA_DISCOVERY } from '../../subworkflows/local/circrna_discovery' @@ -59,18 +62,37 @@ workflow CIRCRNA { main: + ch_multiqc_files = Channel.empty() + // // 1. Pre-processing // // SUBWORKFLOW: - ch_samplesheet + Channel + .fromSamplesheet("input") + .map { + meta, fastq_1, fastq_2 -> + if (!fastq_2) { + return [ meta.id, meta + [ single_end:true ], [ fastq_1 ] ] + } else { + return [ meta.id, meta + [ single_end:false ], [ fastq_1, fastq_2 ] ] + } + } + .groupTuple() + .map { + validateInputSamplesheet(it) + } + .map { + meta, fastqs -> + return [ meta, fastqs.flatten() ] + } .branch { - meta, fastq -> - single : fastq.size() == 1 - return [ meta, fastq.flatten() ] - multiple: fastq.size() > 1 - return [ meta, fastq.flatten() ] + meta, fastqs -> + single : fastqs.size() == 1 + return [ meta, fastqs ] + multiple: fastqs.size() > 1 + return [ meta, fastqs ] } .set { ch_fastq } @@ -108,8 +130,8 @@ workflow CIRCRNA { params.skip_trimming ) ch_versions = ch_versions.mix(FASTQC_TRIMGALORE.out.versions) - ch_reports = ch_reports.mix(FASTQC_TRIMGALORE.out.trim_zip.collect{it[1]}.ifEmpty([])) - ch_reports = ch_reports.mix(FASTQC_TRIMGALORE.out.trim_log.collect{it[1]}.ifEmpty([])) + ch_multiqc_files = ch_multiqc_files.mix(FASTQC_TRIMGALORE.out.trim_zip.collect{it[1]}.ifEmpty([])) + ch_multiqc_files = ch_multiqc_files.mix(FASTQC_TRIMGALORE.out.trim_log.collect{it[1]}.ifEmpty([])) // // 2. circRNA Discovery @@ -167,7 +189,7 @@ workflow CIRCRNA { ) ch_versions = ch_versions.mix(DIFFERENTIAL_EXPRESSION.out.versions) - ch_reports = ch_reports.mix(DIFFERENTIAL_EXPRESSION.out.reports) + ch_multiqc_files = ch_multiqc_files.mix(DIFFERENTIAL_EXPRESSION.out.reports) // // Collate and save software versions @@ -177,18 +199,12 @@ workflow CIRCRNA { .set { ch_collated_versions } // MODULE: MultiQC - workflow_summary = WorkflowCircrna.paramsSummaryMultiqc(workflow, summary_params) - ch_workflow_summary = Channel.value(workflow_summary) - - methods_description = WorkflowCircrna.methodsDescriptionText(workflow, ch_multiqc_custom_methods_description, params) - ch_methods_description = Channel.value(methods_description) - - ch_multiqc_files = Channel.empty() + ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath(params.multiqc_config) : Channel.empty() + ch_multiqc_logo = params.multiqc_logo ? Channel.fromPath(params.multiqc_logo) : Channel.empty() + summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") + ch_workflow_summary = Channel.value(paramsSummaryMultiqc(summary_params)) ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) - ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml')) - ch_multiqc_files = ch_multiqc_files.mix(CUSTOM_DUMPSOFTWAREVERSIONS.out.mqc_yml.collect()) - ch_multiqc_files = ch_multiqc_files.mix(FASTQC_TRIMGALORE.out.fastqc_zip.collect{it[1]}.ifEmpty([])) - ch_multiqc_files = ch_multiqc_files.mix(ch_reports.collect().ifEmpty([])) + ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) MULTIQC ( ch_multiqc_files.collect(), From 0d5b03264b96f4e0175c6145f79ee0a0fb688f39 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 29 Feb 2024 10:51:48 +0100 Subject: [PATCH 131/491] Fix linting problems --- subworkflows/local/utils_nfcore_circrna_pipeline/main.nf | 2 +- workflows/circrna/main.nf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf b/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf index f67b0a4e..690b335d 100644 --- a/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf @@ -277,4 +277,4 @@ def checkParameterExistence(it, list) { def checkParameterList(list, realList) { return list.every{ checkParameterExistence(it, realList) } -} \ No newline at end of file +} diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 84f5723c..3e95f4ca 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -83,7 +83,7 @@ workflow CIRCRNA { .map { validateInputSamplesheet(it) } - .map { + .map { meta, fastqs -> return [ meta, fastqs.flatten() ] } From 09a630e8dee7c18d16904bcac228b1037d311d79 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Thu, 29 Feb 2024 16:09:40 +0000 Subject: [PATCH 132/491] Template update for nf-core/tools version 2.13.1 --- .devcontainer/devcontainer.json | 10 +---- .github/CONTRIBUTING.md | 14 ++++--- .github/PULL_REQUEST_TEMPLATE.md | 2 +- .github/workflows/awsfulltest.yml | 4 +- .github/workflows/awstest.yml | 4 +- .github/workflows/ci.yml | 2 +- .github/workflows/download_pipeline.yml | 2 +- .github/workflows/linting.yml | 2 +- .github/workflows/release-announcements.yml | 2 +- .gitpod.yml | 6 +-- README.md | 3 +- modules.json | 8 ++-- modules/nf-core/multiqc/environment.yml | 2 +- modules/nf-core/multiqc/main.nf | 4 +- .../nf-core/multiqc/tests/main.nf.test.snap | 12 +++--- .../utils_nfcore_circrna_pipeline/main.nf | 10 +++-- .../tests/main.function.nf.test | 2 +- .../tests/main.function.nf.test.snap | 12 +++++- .../tests/main.workflow.nf.test | 20 ++------- .../tests/nextflow.config | 2 +- .../tests/main.function.nf.test.snap | 42 +++++++++++++++---- .../tests/main.workflow.nf.test.snap | 6 ++- .../tests/main.nf.test | 2 +- 23 files changed, 99 insertions(+), 74 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 4ecfbfe3..b290e090 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -10,15 +10,7 @@ "vscode": { // Set *default* container specific settings.json values on container create. "settings": { - "python.defaultInterpreterPath": "/opt/conda/bin/python", - "python.linting.enabled": true, - "python.linting.pylintEnabled": true, - "python.formatting.autopep8Path": "/opt/conda/bin/autopep8", - "python.formatting.yapfPath": "/opt/conda/bin/yapf", - "python.linting.flake8Path": "/opt/conda/bin/flake8", - "python.linting.pycodestylePath": "/opt/conda/bin/pycodestyle", - "python.linting.pydocstylePath": "/opt/conda/bin/pydocstyle", - "python.linting.pylintPath": "/opt/conda/bin/pylint" + "python.defaultInterpreterPath": "/opt/conda/bin/python" }, // Add the IDs of extensions you want installed when the container is created. diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 479ec155..d8a9ab91 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -9,9 +9,8 @@ Please use the pre-filled template to save time. However, don't be put off by this template - other more general issues and suggestions are welcome! Contributions to the code are even more welcome ;) -:::info -If you need help using or modifying nf-core/circrna then the best place to ask is on the nf-core Slack [#circrna](https://nfcore.slack.com/channels/circrna) channel ([join our Slack here](https://nf-co.re/join/slack)). -::: +> [!NOTE] +> If you need help using or modifying nf-core/circrna then the best place to ask is on the nf-core Slack [#circrna](https://nfcore.slack.com/channels/circrna) channel ([join our Slack here](https://nf-co.re/join/slack)). ## Contribution workflow @@ -27,8 +26,11 @@ If you're not used to this workflow with git, you can start with some [docs from ## Tests -You can optionally test your changes by running the pipeline locally. Then it is recommended to use the `debug` profile to -receive warnings about process selectors and other debug info. Example: `nextflow run . -profile debug,test,docker --outdir `. +You have the option to test your changes locally by running the pipeline. For receiving warnings about process selectors and other `debug` information, it is recommended to use the debug profile. Execute all the tests with the following command: + +```bash +nf-test test --profile debug,test,docker --verbose +``` When you create a pull request with changes, [GitHub Actions](https://github.com/features/actions) will run automatic tests. Typically, pull-requests are only fully reviewed when these tests are passing, though of course we can help out before then. @@ -90,7 +92,7 @@ Once there, use `nf-core schema build` to add to `nextflow_schema.json`. Sensible defaults for process resource requirements (CPUs / memory / time) for a process should be defined in `conf/base.config`. These should generally be specified generic with `withLabel:` selectors so they can be shared across multiple processes/steps of the pipeline. A nf-core standard set of labels that should be followed where possible can be seen in the [nf-core pipeline template](https://github.com/nf-core/tools/blob/master/nf_core/pipeline-template/conf/base.config), which has the default process as a single core-process, and then different levels of multi-core configurations for increasingly large memory requirements defined with standardised labels. -The process resources can be passed on to the tool dynamically within the process with the `${task.cpu}` and `${task.memory}` variables in the `script:` block. +The process resources can be passed on to the tool dynamically within the process with the `${task.cpus}` and `${task.memory}` variables in the `script:` block. ### Naming schemes diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9d44ed38..364dd9b5 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -18,7 +18,7 @@ Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/circ - [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/nf-core/circrna/tree/master/.github/CONTRIBUTING.md) - [ ] If necessary, also make a PR on the nf-core/circrna _branch_ on the [nf-core/test-datasets](https://github.com/nf-core/test-datasets) repository. - [ ] Make sure your code lints (`nf-core lint`). -- [ ] Ensure the test suite passes (`nextflow run . -profile test,docker --outdir `). +- [ ] Ensure the test suite passes (`nf-test test main.nf.test -profile test,docker`). - [ ] Check for unexpected warnings in debug mode (`nextflow run . -profile debug,test,docker --outdir `). - [ ] Usage Documentation in `docs/usage.md` is updated. - [ ] Output Documentation in `docs/output.md` is updated. diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 94521ebc..7b6bd16d 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Launch workflow via tower - uses: seqeralabs/action-tower-launch@922e5c8d5ac4e918107ec311d2ebbd65e5982b3d # v2 + uses: seqeralabs/action-tower-launch@v2 # TODO nf-core: You can customise AWS full pipeline tests as required # Add full size test data (but still relatively small datasets for few samples) # on the `test_full.config` test runs with only one set of parameters @@ -31,7 +31,7 @@ jobs: } profiles: test_full - - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4 + - uses: actions/upload-artifact@v4 with: name: Tower debug log file path: | diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index 5307e9aa..9590dcae 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -12,7 +12,7 @@ jobs: steps: # Launch workflow using Tower CLI tool action - name: Launch workflow via tower - uses: seqeralabs/action-tower-launch@922e5c8d5ac4e918107ec311d2ebbd65e5982b3d # v2 + uses: seqeralabs/action-tower-launch@v2 with: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} @@ -25,7 +25,7 @@ jobs: } profiles: test - - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4 + - uses: actions/upload-artifact@v4 with: name: Tower debug log file path: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e5754df..916fd86a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - name: Install Nextflow - uses: nf-core/setup-nextflow@b9f764e8ba5c76b712ace14ecbfcef0e40ae2dd8 # v1 + uses: nf-core/setup-nextflow@v1 with: version: "${{ matrix.NXF_VER }}" diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml index f823210d..08622fd5 100644 --- a/.github/workflows/download_pipeline.yml +++ b/.github/workflows/download_pipeline.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Nextflow - uses: nf-core/setup-nextflow@b9f764e8ba5c76b712ace14ecbfcef0e40ae2dd8 # v1 + uses: nf-core/setup-nextflow@v1 - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 with: diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 748b4311..073e1876 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -35,7 +35,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - name: Install Nextflow - uses: nf-core/setup-nextflow@b9f764e8ba5c76b712ace14ecbfcef0e40ae2dd8 # v1 + uses: nf-core/setup-nextflow@v1 - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 with: diff --git a/.github/workflows/release-announcements.yml b/.github/workflows/release-announcements.yml index c3674af2..d468aeaa 100644 --- a/.github/workflows/release-announcements.yml +++ b/.github/workflows/release-announcements.yml @@ -12,7 +12,7 @@ jobs: - name: get topics and convert to hashtags id: get_topics run: | - curl -s https://nf-co.re/pipelines.json | jq -r '.remote_workflows[] | select(.name == "${{ github.repository }}") | .topics[]' | awk '{print "#"$0}' | tr '\n' ' ' > $GITHUB_OUTPUT + curl -s https://nf-co.re/pipelines.json | jq -r '.remote_workflows[] | select(.full_name == "${{ github.repository }}") | .topics[]' | awk '{print "#"$0}' | tr '\n' ' ' >> $GITHUB_OUTPUT - uses: rzr/fediverse-action@master with: diff --git a/.gitpod.yml b/.gitpod.yml index 363d5b1d..105a1821 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -10,13 +10,11 @@ tasks: vscode: extensions: # based on nf-core.nf-core-extensionpack - - codezombiech.gitignore # Language support for .gitignore files - # - cssho.vscode-svgviewer # SVG viewer - esbenp.prettier-vscode # Markdown/CommonMark linting and style checking for Visual Studio Code - - eamodio.gitlens # Quickly glimpse into whom, why, and when a line or code block was changed - EditorConfig.EditorConfig # override user/workspace settings with settings found in .editorconfig files - Gruntfuggly.todo-tree # Display TODO and FIXME in a tree view in the activity bar - mechatroner.rainbow-csv # Highlight columns in csv files in different colors - # - nextflow.nextflow # Nextflow syntax highlighting + # - nextflow.nextflow # Nextflow syntax highlighting - oderwat.indent-rainbow # Highlight indentation level - streetsidesoftware.code-spell-checker # Spelling checker for source code + - charliermarsh.ruff # Code linter Ruff diff --git a/README.md b/README.md index 18919fd1..ab055f20 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,13 @@ [![GitHub Actions CI Status](https://github.com/nf-core/circrna/actions/workflows/ci.yml/badge.svg)](https://github.com/nf-core/circrna/actions/workflows/ci.yml) [![GitHub Actions Linting Status](https://github.com/nf-core/circrna/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/circrna/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/circrna/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) +[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com) [![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A523.04.0-23aa62.svg)](https://www.nextflow.io/) [![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) [![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) [![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) -[![Launch on Nextflow Tower](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Nextflow%20Tower-%234256e7)](https://tower.nf/launch?pipeline=https://github.com/nf-core/circrna) +[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://tower.nf/launch?pipeline=https://github.com/nf-core/circrna) [![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23circrna-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/circrna)[![Follow on Twitter](http://img.shields.io/badge/twitter-%40nf__core-1DA1F2?labelColor=000000&logo=twitter)](https://twitter.com/nf_core)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core) diff --git a/modules.json b/modules.json index 8cca7fba..c0226feb 100644 --- a/modules.json +++ b/modules.json @@ -12,7 +12,7 @@ }, "multiqc": { "branch": "master", - "git_sha": "ccacf6f5de6df3bc6d73b665c1fd2933d8bbc290", + "git_sha": "b7ebe95761cd389603f9cc0e0dc384c0f663815a", "installed_by": ["modules"] } } @@ -21,17 +21,17 @@ "nf-core": { "utils_nextflow_pipeline": { "branch": "master", - "git_sha": "cd08c91373cd00a73255081340e4914485846ba1", + "git_sha": "5caf7640a9ef1d18d765d55339be751bb0969dfa", "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "262b17ed2aad591039f914951659177e6c39a8d8", + "git_sha": "5caf7640a9ef1d18d765d55339be751bb0969dfa", "installed_by": ["subworkflows"] }, "utils_nfvalidation_plugin": { "branch": "master", - "git_sha": "cd08c91373cd00a73255081340e4914485846ba1", + "git_sha": "5caf7640a9ef1d18d765d55339be751bb0969dfa", "installed_by": ["subworkflows"] } } diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index 2212096a..ca39fb67 100644 --- a/modules/nf-core/multiqc/environment.yml +++ b/modules/nf-core/multiqc/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - bioconda::multiqc=1.20 + - bioconda::multiqc=1.21 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 354f4430..47ac352f 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -3,8 +3,8 @@ process MULTIQC { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.20--pyhdfd78af_0' : - 'biocontainers/multiqc:1.20--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.21--pyhdfd78af_0' : + 'biocontainers/multiqc:1.21--pyhdfd78af_0' }" input: path multiqc_files, stageAs: "?/*" diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap index c204b488..bfebd802 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -2,14 +2,14 @@ "multiqc_versions_single": { "content": [ [ - "versions.yml:md5,d320d4c37e349c5588e07e7a31cd4186" + "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" ] ], "meta": { "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-02-14T09:28:51.744211298" + "timestamp": "2024-02-29T08:48:55.657331" }, "multiqc_stub": { "content": [ @@ -17,25 +17,25 @@ "multiqc_report.html", "multiqc_data", "multiqc_plots", - "versions.yml:md5,d320d4c37e349c5588e07e7a31cd4186" + "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" ] ], "meta": { "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-02-14T09:29:28.847433492" + "timestamp": "2024-02-29T08:49:49.071937" }, "multiqc_versions_config": { "content": [ [ - "versions.yml:md5,d320d4c37e349c5588e07e7a31cd4186" + "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" ] ], "meta": { "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-02-14T09:29:13.223621555" + "timestamp": "2024-02-29T08:49:25.457567" } } \ No newline at end of file diff --git a/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf b/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf index dc90ad90..69918616 100644 --- a/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf @@ -1,5 +1,5 @@ // -// Subworkflow with functionality specific to the nf-core/pipeline pipeline +// Subworkflow with functionality specific to the nf-core/circrna pipeline // /* @@ -152,7 +152,9 @@ workflow PIPELINE_COMPLETION { // def validateInputParameters() { genomeExistsError() -}// +} + +// // Validate channels from input samplesheet // def validateInputSamplesheet(input) { @@ -190,7 +192,9 @@ def genomeExistsError() { "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" error(error_string) } -}// +} + +// // Generate methods description for MultiQC // def toolCitationText() { diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test index 8ed4310c..68718e4f 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test @@ -51,4 +51,4 @@ nextflow_function { ) } } -} \ No newline at end of file +} diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap index db2030f8..e3f0baf4 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap @@ -3,10 +3,18 @@ "content": [ "v9.9.9" ], - "timestamp": "2024-01-19T11:32:36.031083" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:02:05.308243" }, "Test Function checkCondaChannels": { "content": null, - "timestamp": "2024-01-19T11:32:50.456" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:02:12.425833" } } \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test index f7c54bc6..ca964ce8 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test @@ -11,9 +11,6 @@ nextflow_workflow { test("Should run no inputs") { when { - params { - outdir = "tests/results" - } workflow { """ print_version = false @@ -39,9 +36,6 @@ nextflow_workflow { test("Should print version") { when { - params { - outdir = "tests/results" - } workflow { """ print_version = true @@ -68,19 +62,16 @@ nextflow_workflow { test("Should dump params") { when { - params { - outdir = "$outputDir" - } workflow { """ print_version = false dump_parameters = true - outdir = params.outdir + outdir = 'results' check_conda_channels = false input[0] = false input[1] = true - input[2] = params.outdir + input[2] = outdir input[3] = false """ } @@ -96,19 +87,16 @@ nextflow_workflow { test("Should not create params JSON if no output directory") { when { - params { - outdir = "$outputDir" - } workflow { """ print_version = false dump_parameters = true - outdir = params.outdir + outdir = null check_conda_channels = false input[0] = false input[1] = true - input[2] = null + input[2] = outdir input[3] = false """ } diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config b/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config index 53574ffe..d0a926bf 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config @@ -6,4 +6,4 @@ manifest { nextflowVersion = '!>=23.04.0' version = '9.9.9' doi = 'https://doi.org/10.5281/zenodo.5070524' -} \ No newline at end of file +} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap index 10f948e6..1037232c 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap @@ -1,25 +1,41 @@ { "Test Function checkProfileProvided": { "content": null, - "timestamp": "2024-02-09T15:43:55.145717" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:03.360873" }, "Test Function checkConfigProvided": { "content": [ true ], - "timestamp": "2024-01-19T11:34:13.548431224" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:02:59.729647" }, "Test Function nfCoreLogo": { "content": [ "\n\n-\u001b[2m----------------------------------------------------\u001b[0m-\n \u001b[0;32m,--.\u001b[0;30m/\u001b[0;32m,-.\u001b[0m\n\u001b[0;34m ___ __ __ __ ___ \u001b[0;32m/,-._.--~'\u001b[0m\n\u001b[0;34m |\\ | |__ __ / ` / \\ |__) |__ \u001b[0;33m} {\u001b[0m\n\u001b[0;34m | \\| | \\__, \\__/ | \\ |___ \u001b[0;32m\\`-._,-`-,\u001b[0m\n \u001b[0;32m`._,._,'\u001b[0m\n\u001b[0;35m nextflow_workflow v9.9.9\u001b[0m\n-\u001b[2m----------------------------------------------------\u001b[0m-\n" ], - "timestamp": "2024-01-19T11:34:38.840454873" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:10.562934" }, "Test Function workflowCitation": { "content": [ "If you use nextflow_workflow for your analysis please cite:\n\n* The pipeline\n https://doi.org/10.5281/zenodo.5070524\n\n* The nf-core framework\n https://doi.org/10.1038/s41587-020-0439-x\n\n* Software dependencies\n https://github.com/nextflow_workflow/blob/master/CITATIONS.md" ], - "timestamp": "2024-01-19T11:34:22.24352016" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:07.019761" }, "Test Function without logColours": { "content": [ @@ -73,13 +89,21 @@ "biwhite": "" } ], - "timestamp": "2024-01-19T11:35:04.418416984" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:17.969323" }, "Test Function dashedLine": { "content": [ "-\u001b[2m----------------------------------------------------\u001b[0m-" ], - "timestamp": "2024-01-19T11:34:55.420000755" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:14.366181" }, "Test Function with logColours": { "content": [ @@ -133,6 +157,10 @@ "biwhite": "\u001b[1;97m" } ], - "timestamp": "2024-01-19T11:35:13.436366565" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:21.714424" } } \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap index d07ce54c..859d1030 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap @@ -10,6 +10,10 @@ ] } ], - "timestamp": "2024-01-19T11:35:22.538940073" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:25.726491" } } \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test index 517ee54e..5784a33f 100644 --- a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test +++ b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test @@ -197,4 +197,4 @@ nextflow_workflow { ) } } -} \ No newline at end of file +} From 93c2881dc80963376e7c131ee8596600a8b8ed5c Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 1 Feb 2024 10:58:58 +0100 Subject: [PATCH 133/491] Implement pandas-based annotation --- conf/modules.config | 5 + .../local/annotation/full_annotation/main.nf | 103 ++++++++++++------ subworkflows/local/circrna_discovery.nf | 84 +++++++------- 3 files changed, 117 insertions(+), 75 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 52b47439..0b64d0de 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -604,6 +604,11 @@ if (!params.skip_trimming) { ] } + withName: INTERSECT_ANNOTATION { + ext.args = "-loj" + ext.suffix = "intersect.bed" + } + withName: FASTA { ext.when = { params.module.split(',').contains('circrna_discovery') } publishDir = [ diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/full_annotation/main.nf index 789c884f..da50da22 100644 --- a/modules/local/annotation/full_annotation/main.nf +++ b/modules/local/annotation/full_annotation/main.nf @@ -1,48 +1,83 @@ process ANNOTATION { - tag "${meta.id}:${meta.tool}" - label 'process_high' + tag "$meta.id" + label 'process_single' - conda "bioconda::ucsc-gtftogenepred=377 bioconda::ucsc-genepredtobed=377 bioconda::bedtools=2.27.0" + conda "bioconda::pandas=1.5.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' : - 'quay.io/biocontainers/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' }" + 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : + 'quay.io/biocontainers/pandas:1.5.2' }" input: - tuple val(meta), path(bed) - path gtf - path biotypes - val exon_boundary + tuple val(meta), path(intersection) + val(exon_boundary) + + output: + tuple val(meta), path("${meta.id}.annotation.bed"), emit: bed + + script: + """ + #!/usr/bin/env python + import pandas as pd + import os - output: - tuple val(meta), path("${prefix}.bed"), emit: bed - path("*.log") , emit: log - path "versions.yml" , emit: versions + columns = { + 0: 'chr', + 1: 'start', + 2: 'end', + 3: 'name', + 4: 'score', + 5: 'strand', + 9: 'tx_start', + 10: 'tx_end', + 14: 'attributes' + } - when: - task.ext.when == null || task.ext.when + attributes = ['gene_id', 'transcript_id'] - script: - def args = task.ext.args ?: '' - prefix = task.ext.prefix ?: "${meta.id}" - def VERSION = '377' - """ - grep -vf $biotypes $gtf > filt.gtf - mv $bed circs.bed + exon_boundary = ${exon_boundary} + + df = pd.read_csv("${intersection}", sep="\\t", header=None, usecols=columns.keys()) + df = df.rename(columns=columns) + # Convert attributes to a dictionary + df['attributes'] = df['attributes'].apply(lambda row: dict([[value.strip(r'\\"') for value in entry.strip().split(' ')] for entry in row.split(';') if entry])) + # Keep only the attributes we want + df['attributes'] = df['attributes'].apply(lambda row: {key: row[key] for key in attributes}) + # Convert attributes to columns + df = pd.concat([df.drop(['attributes'], axis=1), df['attributes'].apply(pd.Series)], axis=1) + + df['any_outside'] = (df['start'] < df['tx_start'] - exon_boundary) | (df['end'] > df['tx_end'] + exon_boundary) + # Perfect is inverse of any_outside + df['perfect'] = ~df['any_outside'] + # Drop any_outside + df = df.drop(['any_outside', 'tx_start', 'tx_end'], axis=1) + + df = df.groupby(['chr', 'start', 'end', 'strand']).aggregate({ + 'name': lambda x: x.iloc[0], + 'score': lambda x: x.iloc[0], + 'gene_id': lambda x: list(x), + 'transcript_id': lambda x: list(x), + 'perfect': lambda x: list(x) + }) - annotate_outputs.sh $exon_boundary &> ${prefix}.log - mv master_bed12.bed ${prefix}.bed.tmp + def filter_perfect(row, col): + if any(row['perfect']): + matching_values = [value for value, perfectness in zip(row[col], row['perfect']) if perfectness] + else: + matching_values = row[col] + return ",".join(set(matching_values)) - awk -v FS="\\t" '{print \$11}' ${prefix}.bed.tmp > mature_len.tmp - awk -v FS="," '{for(i=t=0;i mature_length + df['type'] = df['perfect'].apply(lambda x: 'circRNA' if any(x) else 'EI-circRNA') + df['gene_id'] = df.apply(lambda row: filter_perfect(row, 'gene_id'), axis=1) + df['transcript_id'] = df.apply(lambda row: filter_perfect(row, 'transcript_id'), axis=1) + # Drop perfect + df = df.drop(['perfect'], axis=1) - paste ${prefix}.bed.tmp mature_length > ${prefix}.bed + df = df.sort_index() + df = df.reset_index() + bed_order = ['chr', 'start', 'end', 'name', 'score', 'strand', 'type', 'gene_id', 'transcript_id'] + df = df[bed_order] - cat <<-END_VERSIONS > versions.yml - "${task.process}": - awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) - bedtools: \$(bedtools --version | sed -e "s/bedtools v//g") - ucsc: $VERSION - END_VERSIONS + df.to_csv('${meta.id}.annotation.bed', sep='\\t', index=False, header=False) """ -} +} \ No newline at end of file diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 80ba9a19..1fef8419 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -1,44 +1,45 @@ -include { ANNOTATION } from '../../modules/local/annotation/full_annotation/main' -include { BOWTIE2_ALIGN as FIND_CIRC_ALIGN } from '../../modules/nf-core/bowtie2/align/main' -include { SAMTOOLS_VIEW } from '../../modules/nf-core/samtools/view/main' -include { SAMTOOLS_INDEX } from '../../modules/nf-core/samtools/index/main' -include { FIND_CIRC_ANCHORS } from '../../modules/local/find_circ/anchors/main' -include { FIND_CIRC } from '../../modules/local/find_circ/find_circ/main' -include { FIND_CIRC_FILTER } from '../../modules/local/find_circ/filter/main' -include { CIRIQUANT_YML } from '../../modules/local/ciriquant/yml/main' -include { CIRIQUANT } from '../../modules/local/ciriquant/ciriquant/main' -include { CIRIQUANT_FILTER } from '../../modules/local/ciriquant/filter/main' -include { CIRCRNA_FINDER_FILTER } from '../../modules/local/circrna_finder/filter/main' -include { SEGEMEHL_ALIGN } from '../../modules/nf-core/segemehl/align/main' -include { SEGEMEHL_FILTER } from '../../modules/local/segemehl/filter/main' -include { STAR_ALIGN as STAR_1ST_PASS } from '../../modules/nf-core/star/align/main' -include { STAR_ALIGN as STAR_2ND_PASS } from '../../modules/nf-core/star/align/main' -include { SJDB as STAR_SJDB } from '../../modules/local/star/sjdb/main' -include { STAR_ALIGN as DCC_1ST_PASS } from '../../modules/nf-core/star/align/main' -include { STAR_ALIGN as DCC_2ND_PASS } from '../../modules/nf-core/star/align/main' -include { SJDB as DCC_SJDB } from '../../modules/local/star/sjdb/main' -include { STAR_ALIGN as DCC_MATE1_1ST_PASS } from '../../modules/nf-core/star/align/main' -include { STAR_ALIGN as DCC_MATE1_2ND_PASS } from '../../modules/nf-core/star/align/main' -include { SJDB as DCC_MATE1_SJDB } from '../../modules/local/star/sjdb/main' -include { STAR_ALIGN as DCC_MATE2_1ST_PASS } from '../../modules/nf-core/star/align/main' -include { STAR_ALIGN as DCC_MATE2_2ND_PASS } from '../../modules/nf-core/star/align/main' -include { SJDB as DCC_MATE2_SJDB } from '../../modules/local/star/sjdb/main' -include { DCC } from '../../modules/local/dcc/dcc/main' -include { DCC_FILTER } from '../../modules/local/dcc/filter/main' -include { MAPSPLICE_ALIGN } from '../../modules/local/mapsplice/align/main' -include { FASTA } from '../../modules/local/fasta/main' -include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools/main' -include { COUNTS_COMBINED } from '../../modules/local/count_matrix/combined/main' -include { COUNTS_SINGLE } from '../../modules/local/count_matrix/single/main' -include { CIRCEXPLORER2_REFERENCE as CIRCEXPLORER2_REF } from '../../modules/local/circexplorer2/reference/main' -include { CIRCEXPLORER2_PARSE as CIRCEXPLORER2_PAR } from '../../modules/nf-core/circexplorer2/parse/main' -include { CIRCEXPLORER2_ANNOTATE as CIRCEXPLORER2_ANN } from '../../modules/nf-core/circexplorer2/annotate/main' -include { CIRCEXPLORER2_FILTER as CIRCEXPLORER2_FLT } from '../../modules/local/circexplorer2/filter/main' +include { ANNOTATION } from '../../modules/local/annotation/full_annotation/main' +include { BEDTOOLS_INTERSECT as INTERSECT_ANNOTATION } from '../../modules/nf-core/bedtools/intersect/main' +include { BOWTIE2_ALIGN as FIND_CIRC_ALIGN } from '../../modules/nf-core/bowtie2/align/main' +include { SAMTOOLS_VIEW } from '../../modules/nf-core/samtools/view/main' +include { SAMTOOLS_INDEX } from '../../modules/nf-core/samtools/index/main' +include { FIND_CIRC_ANCHORS } from '../../modules/local/find_circ/anchors/main' +include { FIND_CIRC } from '../../modules/local/find_circ/find_circ/main' +include { FIND_CIRC_FILTER } from '../../modules/local/find_circ/filter/main' +include { CIRIQUANT_YML } from '../../modules/local/ciriquant/yml/main' +include { CIRIQUANT } from '../../modules/local/ciriquant/ciriquant/main' +include { CIRIQUANT_FILTER } from '../../modules/local/ciriquant/filter/main' +include { CIRCRNA_FINDER_FILTER } from '../../modules/local/circrna_finder/filter/main' +include { SEGEMEHL_ALIGN } from '../../modules/nf-core/segemehl/align/main' +include { SEGEMEHL_FILTER } from '../../modules/local/segemehl/filter/main' +include { STAR_ALIGN as STAR_1ST_PASS } from '../../modules/nf-core/star/align/main' +include { STAR_ALIGN as STAR_2ND_PASS } from '../../modules/nf-core/star/align/main' +include { SJDB as STAR_SJDB } from '../../modules/local/star/sjdb/main' +include { STAR_ALIGN as DCC_1ST_PASS } from '../../modules/nf-core/star/align/main' +include { STAR_ALIGN as DCC_2ND_PASS } from '../../modules/nf-core/star/align/main' +include { SJDB as DCC_SJDB } from '../../modules/local/star/sjdb/main' +include { STAR_ALIGN as DCC_MATE1_1ST_PASS } from '../../modules/nf-core/star/align/main' +include { STAR_ALIGN as DCC_MATE1_2ND_PASS } from '../../modules/nf-core/star/align/main' +include { SJDB as DCC_MATE1_SJDB } from '../../modules/local/star/sjdb/main' +include { STAR_ALIGN as DCC_MATE2_1ST_PASS } from '../../modules/nf-core/star/align/main' +include { STAR_ALIGN as DCC_MATE2_2ND_PASS } from '../../modules/nf-core/star/align/main' +include { SJDB as DCC_MATE2_SJDB } from '../../modules/local/star/sjdb/main' +include { DCC } from '../../modules/local/dcc/dcc/main' +include { DCC_FILTER } from '../../modules/local/dcc/filter/main' +include { MAPSPLICE_ALIGN } from '../../modules/local/mapsplice/align/main' +include { FASTA } from '../../modules/local/fasta/main' +include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools/main' +include { COUNTS_COMBINED } from '../../modules/local/count_matrix/combined/main' +include { COUNTS_SINGLE } from '../../modules/local/count_matrix/single/main' +include { CIRCEXPLORER2_REFERENCE as CIRCEXPLORER2_REF } from '../../modules/local/circexplorer2/reference/main' +include { CIRCEXPLORER2_PARSE as CIRCEXPLORER2_PAR } from '../../modules/nf-core/circexplorer2/parse/main' +include { CIRCEXPLORER2_ANNOTATE as CIRCEXPLORER2_ANN } from '../../modules/nf-core/circexplorer2/annotate/main' +include { CIRCEXPLORER2_FILTER as CIRCEXPLORER2_FLT } from '../../modules/local/circexplorer2/filter/main' include { CIRCEXPLORER2_REFERENCE as MAPSPLICE_REFERENCE } from '../../modules/local/circexplorer2/reference/main' -include { CIRCEXPLORER2_PARSE as MAPSPLICE_PARSE } from '../../modules/nf-core/circexplorer2/parse/main' -include { CIRCEXPLORER2_ANNOTATE as MAPSPLICE_ANNOTATE } from '../../modules/nf-core/circexplorer2/annotate/main' -include { CIRCEXPLORER2_FILTER as MAPSPLICE_FILTER } from '../../modules/local/circexplorer2/filter/main' +include { CIRCEXPLORER2_PARSE as MAPSPLICE_PARSE } from '../../modules/nf-core/circexplorer2/parse/main' +include { CIRCEXPLORER2_ANNOTATE as MAPSPLICE_ANNOTATE } from '../../modules/nf-core/circexplorer2/annotate/main' +include { CIRCEXPLORER2_FILTER as MAPSPLICE_FILTER } from '../../modules/local/circexplorer2/filter/main' workflow CIRCRNA_DISCOVERY { @@ -217,9 +218,10 @@ workflow CIRCRNA_DISCOVERY { DCC_FILTER.out.results, MAPSPLICE_FILTER.out.results) - ANNOTATION( circrna_filtered, gtf, ch_biotypes.collect(), exon_boundary ) + INTERSECT_ANNOTATION( circrna_filtered.combine(ch_gtf), [[], []]) + ANNOTATION( INTERSECT_ANNOTATION.out.intersect, exon_boundary ) - ch_versions = ch_versions.mix(ANNOTATION.out.versions) + ch_versions = ch_versions.mix(INTERSECT_ANNOTATION.out.versions) // // FASTA WORKFLOW: From cfee6c77ba1195203f5e8749f71a6151820c0ca2 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 1 Feb 2024 12:42:23 +0100 Subject: [PATCH 134/491] Implement handling of intergenic circRNAs --- .../local/annotation/full_annotation/main.nf | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/full_annotation/main.nf index da50da22..22c16b21 100644 --- a/modules/local/annotation/full_annotation/main.nf +++ b/modules/local/annotation/full_annotation/main.nf @@ -39,8 +39,17 @@ process ANNOTATION { df = pd.read_csv("${intersection}", sep="\\t", header=None, usecols=columns.keys()) df = df.rename(columns=columns) + + # Extract circRNAs without match + mask = df['tx_start'] == -1 + df_nomatch = df[mask] + df = df[~mask] + df_nomatch['type'] = 'intergenic-circRNA' + df_nomatch['gene_id'] = 'NaN' + df_nomatch['transcript_id'] = 'NaN' + # Convert attributes to a dictionary - df['attributes'] = df['attributes'].apply(lambda row: dict([[value.strip(r'\\"') for value in entry.strip().split(' ')] for entry in row.split(';') if entry])) + df['attributes'] = df['attributes'].apply(lambda row: dict([[value.strip(r'"') for value in entry.strip().split(' ')] for entry in row.split(';') if entry])) # Keep only the attributes we want df['attributes'] = df['attributes'].apply(lambda row: {key: row[key] for key in attributes}) # Convert attributes to columns @@ -73,10 +82,16 @@ process ANNOTATION { # Drop perfect df = df.drop(['perfect'], axis=1) - df = df.sort_index() df = df.reset_index() + df_nomatch = df_nomatch.reset_index() bed_order = ['chr', 'start', 'end', 'name', 'score', 'strand', 'type', 'gene_id', 'transcript_id'] df = df[bed_order] + df_nomatch = df_nomatch[bed_order] + + df = pd.concat([df, df_nomatch], axis=0) + + # Sort by chr, start, end + df = df.sort_values(['chr', 'start', 'end']) df.to_csv('${meta.id}.annotation.bed', sep='\\t', index=False, header=False) """ From 3e5f72a726c4de3ffea5ad495c6c1d3dbc8196b2 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 1 Feb 2024 13:06:21 +0100 Subject: [PATCH 135/491] Fix linting problems --- modules/local/annotation/full_annotation/main.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/full_annotation/main.nf index 22c16b21..8cde37dd 100644 --- a/modules/local/annotation/full_annotation/main.nf +++ b/modules/local/annotation/full_annotation/main.nf @@ -10,10 +10,10 @@ process ANNOTATION { input: tuple val(meta), path(intersection) val(exon_boundary) - + output: tuple val(meta), path("${meta.id}.annotation.bed"), emit: bed - + script: """ #!/usr/bin/env python @@ -95,4 +95,4 @@ process ANNOTATION { df.to_csv('${meta.id}.annotation.bed', sep='\\t', index=False, header=False) """ -} \ No newline at end of file +} From 740d17aa3d0bd990a3a9cfc0106d06e7bf564a25 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Feb 2024 19:18:47 +0100 Subject: [PATCH 136/491] Implement handling of "gene" rows in annotation --- .../local/annotation/full_annotation/main.nf | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/full_annotation/main.nf index 8cde37dd..e44af433 100644 --- a/modules/local/annotation/full_annotation/main.nf +++ b/modules/local/annotation/full_annotation/main.nf @@ -19,7 +19,7 @@ process ANNOTATION { #!/usr/bin/env python import pandas as pd - import os + import numpy as np columns = { 0: 'chr', @@ -42,16 +42,16 @@ process ANNOTATION { # Extract circRNAs without match mask = df['tx_start'] == -1 - df_nomatch = df[mask] + df_intergenic = df[mask] df = df[~mask] - df_nomatch['type'] = 'intergenic-circRNA' - df_nomatch['gene_id'] = 'NaN' - df_nomatch['transcript_id'] = 'NaN' + df_intergenic['type'] = 'intergenic-circRNA' + df_intergenic['gene_id'] = 'NaN' + df_intergenic['transcript_id'] = 'NaN' # Convert attributes to a dictionary df['attributes'] = df['attributes'].apply(lambda row: dict([[value.strip(r'"') for value in entry.strip().split(' ')] for entry in row.split(';') if entry])) # Keep only the attributes we want - df['attributes'] = df['attributes'].apply(lambda row: {key: row[key] for key in attributes}) + df['attributes'] = df['attributes'].apply(lambda row: {key: row[key] for key in attributes if key in row}) # Convert attributes to columns df = pd.concat([df.drop(['attributes'], axis=1), df['attributes'].apply(pd.Series)], axis=1) @@ -74,21 +74,31 @@ process ANNOTATION { matching_values = [value for value, perfectness in zip(row[col], row['perfect']) if perfectness] else: matching_values = row[col] - return ",".join(set(matching_values)) + valid_values = set([value for value in matching_values if type(value) == str]) + return ",".join(valid_values) if valid_values else "NaN" - df['type'] = df['perfect'].apply(lambda x: 'circRNA' if any(x) else 'EI-circRNA') + def determine_type(row): + if row["no_transcript"]: + return "ciRNA" + if any(row['perfect']): + return "circRNA" + else: + return 'EI-circRNA' + + df['no_transcript'] = df['transcript_id'].apply(lambda x: all([type(value) != str and np.isnan(value) for value in x])) + df['type'] = df.apply(lambda row: determine_type(row), axis=1) df['gene_id'] = df.apply(lambda row: filter_perfect(row, 'gene_id'), axis=1) df['transcript_id'] = df.apply(lambda row: filter_perfect(row, 'transcript_id'), axis=1) # Drop perfect df = df.drop(['perfect'], axis=1) df = df.reset_index() - df_nomatch = df_nomatch.reset_index() + df_intergenic = df_intergenic.reset_index() bed_order = ['chr', 'start', 'end', 'name', 'score', 'strand', 'type', 'gene_id', 'transcript_id'] df = df[bed_order] - df_nomatch = df_nomatch[bed_order] + df_intergenic = df_intergenic[bed_order] - df = pd.concat([df, df_nomatch], axis=0) + df = pd.concat([df, df_intergenic], axis=0) # Sort by chr, start, end df = df.sort_values(['chr', 'start', 'end']) From 686e40fabeea6ba005029ac1d1bff7a6e26fef46 Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Wed, 28 Feb 2024 19:47:31 +0100 Subject: [PATCH 137/491] Remove quay.io prefix from container definition Co-authored-by: Maxime U Garcia --- modules/local/annotation/full_annotation/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/full_annotation/main.nf index e44af433..bfa58786 100644 --- a/modules/local/annotation/full_annotation/main.nf +++ b/modules/local/annotation/full_annotation/main.nf @@ -5,7 +5,7 @@ process ANNOTATION { conda "bioconda::pandas=1.5.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : - 'quay.io/biocontainers/pandas:1.5.2' }" + 'biocontainers/pandas:1.5.2' }" input: tuple val(meta), path(intersection) From 49f47ca2f9369a921a7961248d087682ed04491d Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Wed, 28 Feb 2024 20:19:54 +0100 Subject: [PATCH 138/491] Implement capture of versions in annotation --- bin/annotation.py | 97 +++++++++++++++++++ .../local/annotation/full_annotation/main.nf | 97 ++----------------- subworkflows/local/circrna_discovery.nf | 1 + 3 files changed, 107 insertions(+), 88 deletions(-) create mode 100755 bin/annotation.py diff --git a/bin/annotation.py b/bin/annotation.py new file mode 100755 index 00000000..2d5992ff --- /dev/null +++ b/bin/annotation.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python + +import pandas as pd +import numpy as np +import argparse + +parser = argparse.ArgumentParser(description='Annotate circRNAs') +parser.add_argument('--input', type=str, help='Path to the input file') +parser.add_argument('--exon_boundary', type=int, help='Exon boundary') +parser.add_argument('--output', type=str, help='Path to the output file') + +args = parser.parse_args() + + +columns = { + 0: 'chr', + 1: 'start', + 2: 'end', + 3: 'name', + 4: 'score', + 5: 'strand', + 9: 'tx_start', + 10: 'tx_end', + 14: 'attributes' +} + +attributes = ['gene_id', 'transcript_id'] + +exon_boundary = args.exon_boundary + +df = pd.read_csv(args.input, sep="\\t", header=None, usecols=columns.keys()) +df = df.rename(columns=columns) + +# Extract circRNAs without match +mask = df['tx_start'] == -1 +df_intergenic = df[mask] +df = df[~mask] +df_intergenic['type'] = 'intergenic-circRNA' +df_intergenic['gene_id'] = 'NaN' +df_intergenic['transcript_id'] = 'NaN' + +# Convert attributes to a dictionary +df['attributes'] = df['attributes'].apply(lambda row: dict([[value.strip(r'"') for value in entry.strip().split(' ')] for entry in row.split(';') if entry])) +# Keep only the attributes we want +df['attributes'] = df['attributes'].apply(lambda row: {key: row[key] for key in attributes if key in row}) +# Convert attributes to columns +df = pd.concat([df.drop(['attributes'], axis=1), df['attributes'].apply(pd.Series)], axis=1) + +df['any_outside'] = (df['start'] < df['tx_start'] - exon_boundary) | (df['end'] > df['tx_end'] + exon_boundary) +# Perfect is inverse of any_outside +df['perfect'] = ~df['any_outside'] +# Drop any_outside +df = df.drop(['any_outside', 'tx_start', 'tx_end'], axis=1) + +df = df.groupby(['chr', 'start', 'end', 'strand']).aggregate({ + 'name': lambda x: x.iloc[0], + 'score': lambda x: x.iloc[0], + 'gene_id': lambda x: list(x), + 'transcript_id': lambda x: list(x), + 'perfect': lambda x: list(x) +}) + +def filter_perfect(row, col): + if any(row['perfect']): + matching_values = [value for value, perfectness in zip(row[col], row['perfect']) if perfectness] + else: + matching_values = row[col] + valid_values = set([value for value in matching_values if type(value) == str]) + return ",".join(valid_values) if valid_values else "NaN" + +def determine_type(row): + if row["no_transcript"]: + return "ciRNA" + if any(row['perfect']): + return "circRNA" + else: + return 'EI-circRNA' + +df['no_transcript'] = df['transcript_id'].apply(lambda x: all([type(value) != str and np.isnan(value) for value in x])) +df['type'] = df.apply(lambda row: determine_type(row), axis=1) +df['gene_id'] = df.apply(lambda row: filter_perfect(row, 'gene_id'), axis=1) +df['transcript_id'] = df.apply(lambda row: filter_perfect(row, 'transcript_id'), axis=1) +# Drop perfect +df = df.drop(['perfect'], axis=1) + +df = df.reset_index() +df_intergenic = df_intergenic.reset_index() +bed_order = ['chr', 'start', 'end', 'name', 'score', 'strand', 'type', 'gene_id', 'transcript_id'] +df = df[bed_order] +df_intergenic = df_intergenic[bed_order] + +df = pd.concat([df, df_intergenic], axis=0) + +# Sort by chr, start, end +df = df.sort_values(['chr', 'start', 'end']) + +df.to_csv(args.output, sep='\\t', index=False, header=False) \ No newline at end of file diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/full_annotation/main.nf index bfa58786..1df42646 100644 --- a/modules/local/annotation/full_annotation/main.nf +++ b/modules/local/annotation/full_annotation/main.nf @@ -13,96 +13,17 @@ process ANNOTATION { output: tuple val(meta), path("${meta.id}.annotation.bed"), emit: bed + path "versions.yml", emit: versions script: """ - #!/usr/bin/env python - - import pandas as pd - import numpy as np - - columns = { - 0: 'chr', - 1: 'start', - 2: 'end', - 3: 'name', - 4: 'score', - 5: 'strand', - 9: 'tx_start', - 10: 'tx_end', - 14: 'attributes' - } - - attributes = ['gene_id', 'transcript_id'] - - exon_boundary = ${exon_boundary} - - df = pd.read_csv("${intersection}", sep="\\t", header=None, usecols=columns.keys()) - df = df.rename(columns=columns) - - # Extract circRNAs without match - mask = df['tx_start'] == -1 - df_intergenic = df[mask] - df = df[~mask] - df_intergenic['type'] = 'intergenic-circRNA' - df_intergenic['gene_id'] = 'NaN' - df_intergenic['transcript_id'] = 'NaN' - - # Convert attributes to a dictionary - df['attributes'] = df['attributes'].apply(lambda row: dict([[value.strip(r'"') for value in entry.strip().split(' ')] for entry in row.split(';') if entry])) - # Keep only the attributes we want - df['attributes'] = df['attributes'].apply(lambda row: {key: row[key] for key in attributes if key in row}) - # Convert attributes to columns - df = pd.concat([df.drop(['attributes'], axis=1), df['attributes'].apply(pd.Series)], axis=1) - - df['any_outside'] = (df['start'] < df['tx_start'] - exon_boundary) | (df['end'] > df['tx_end'] + exon_boundary) - # Perfect is inverse of any_outside - df['perfect'] = ~df['any_outside'] - # Drop any_outside - df = df.drop(['any_outside', 'tx_start', 'tx_end'], axis=1) - - df = df.groupby(['chr', 'start', 'end', 'strand']).aggregate({ - 'name': lambda x: x.iloc[0], - 'score': lambda x: x.iloc[0], - 'gene_id': lambda x: list(x), - 'transcript_id': lambda x: list(x), - 'perfect': lambda x: list(x) - }) - - def filter_perfect(row, col): - if any(row['perfect']): - matching_values = [value for value, perfectness in zip(row[col], row['perfect']) if perfectness] - else: - matching_values = row[col] - valid_values = set([value for value in matching_values if type(value) == str]) - return ",".join(valid_values) if valid_values else "NaN" - - def determine_type(row): - if row["no_transcript"]: - return "ciRNA" - if any(row['perfect']): - return "circRNA" - else: - return 'EI-circRNA' - - df['no_transcript'] = df['transcript_id'].apply(lambda x: all([type(value) != str and np.isnan(value) for value in x])) - df['type'] = df.apply(lambda row: determine_type(row), axis=1) - df['gene_id'] = df.apply(lambda row: filter_perfect(row, 'gene_id'), axis=1) - df['transcript_id'] = df.apply(lambda row: filter_perfect(row, 'transcript_id'), axis=1) - # Drop perfect - df = df.drop(['perfect'], axis=1) - - df = df.reset_index() - df_intergenic = df_intergenic.reset_index() - bed_order = ['chr', 'start', 'end', 'name', 'score', 'strand', 'type', 'gene_id', 'transcript_id'] - df = df[bed_order] - df_intergenic = df_intergenic[bed_order] - - df = pd.concat([df, df_intergenic], axis=0) - - # Sort by chr, start, end - df = df.sort_values(['chr', 'start', 'end']) - - df.to_csv('${meta.id}.annotation.bed', sep='\\t', index=False, header=False) + ./annotation.py --input ${intersection} --exon_boundary ${exon_boundary} --output ${meta.id}.annotation.bed + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + python: \$(python --version | sed 's/Python //g') + pandas: \$(python -c "import pandas; print(pandas.__version__)") + numpy: \$(python -c "import numpy; print(numpy.__version__)") + END_VERSIONS """ } diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 1fef8419..90b60726 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -222,6 +222,7 @@ workflow CIRCRNA_DISCOVERY { ANNOTATION( INTERSECT_ANNOTATION.out.intersect, exon_boundary ) ch_versions = ch_versions.mix(INTERSECT_ANNOTATION.out.versions) + ch_versions = ch_versions.mix(ANNOTATION.out.versions) // // FASTA WORKFLOW: From fb6a1d95ef92624ef80f45066f2c3f0e34de90db Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 1 Mar 2024 12:31:05 +0100 Subject: [PATCH 139/491] Fix linting --- bin/annotation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/annotation.py b/bin/annotation.py index 2d5992ff..e88bda5c 100755 --- a/bin/annotation.py +++ b/bin/annotation.py @@ -94,4 +94,4 @@ def determine_type(row): # Sort by chr, start, end df = df.sort_values(['chr', 'start', 'end']) -df.to_csv(args.output, sep='\\t', index=False, header=False) \ No newline at end of file +df.to_csv(args.output, sep='\\t', index=False, header=False) From cf46f11bee9150c760dedd4823a4dc079dad48fd Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 1 Mar 2024 12:59:51 +0100 Subject: [PATCH 140/491] Fix problem with annotation.py script calling --- modules/local/annotation/full_annotation/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/full_annotation/main.nf index 1df42646..f06546ac 100644 --- a/modules/local/annotation/full_annotation/main.nf +++ b/modules/local/annotation/full_annotation/main.nf @@ -17,7 +17,7 @@ process ANNOTATION { script: """ - ./annotation.py --input ${intersection} --exon_boundary ${exon_boundary} --output ${meta.id}.annotation.bed + annotation.py --input ${intersection} --exon_boundary ${exon_boundary} --output ${meta.id}.annotation.bed cat <<-END_VERSIONS > versions.yml "${task.process}": From 2de5b60ee5f8c6bab7f3ef7d8aa313ba5b66b3cc Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 1 Mar 2024 13:18:10 +0100 Subject: [PATCH 141/491] Fix problem with escape characters in dedicated python script --- bin/annotation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/annotation.py b/bin/annotation.py index e88bda5c..ab9dc01d 100755 --- a/bin/annotation.py +++ b/bin/annotation.py @@ -28,7 +28,7 @@ exon_boundary = args.exon_boundary -df = pd.read_csv(args.input, sep="\\t", header=None, usecols=columns.keys()) +df = pd.read_csv(args.input, sep="\t", header=None, usecols=columns.keys()) df = df.rename(columns=columns) # Extract circRNAs without match @@ -94,4 +94,4 @@ def determine_type(row): # Sort by chr, start, end df = df.sort_values(['chr', 'start', 'end']) -df.to_csv(args.output, sep='\\t', index=False, header=False) +df.to_csv(args.output, sep='\t', index=False, header=False) From 82e1b2849346df5e67b06c4a94b6e6f367eeb455 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Fri, 1 Mar 2024 17:48:01 +0100 Subject: [PATCH 142/491] add dumpsoftwareversions --- modules.json | 33 ------ .../dumpsoftwareversions/environment.yml | 7 ++ .../custom/dumpsoftwareversions/main.nf | 24 +++++ .../custom/dumpsoftwareversions/meta.yml | 37 +++++++ .../templates/dumpsoftwareversions.py | 101 ++++++++++++++++++ .../dumpsoftwareversions/tests/main.nf.test | 43 ++++++++ .../tests/main.nf.test.snap | 33 ++++++ .../dumpsoftwareversions/tests/tags.yml | 2 + 8 files changed, 247 insertions(+), 33 deletions(-) create mode 100644 modules/nf-core/custom/dumpsoftwareversions/environment.yml create mode 100644 modules/nf-core/custom/dumpsoftwareversions/main.nf create mode 100644 modules/nf-core/custom/dumpsoftwareversions/meta.yml create mode 100755 modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py create mode 100644 modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test create mode 100644 modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap create mode 100644 modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml diff --git a/modules.json b/modules.json index d82ffc55..9cfb49d2 100644 --- a/modules.json +++ b/modules.json @@ -167,39 +167,6 @@ } } }, - "subworkflows": { - "nf-core": { - "bam_sort_stats_samtools": { - "branch": "master", - "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", - "installed_by": ["subworkflows"] - }, - "bam_stats_samtools": { - "branch": "master", - "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", - "installed_by": ["bam_sort_stats_samtools"] - } - } - }, - "subworkflows": { - "nf-core": { - "utils_nextflow_pipeline": { - "branch": "master", - "git_sha": "cd08c91373cd00a73255081340e4914485846ba1", - "installed_by": ["subworkflows"] - }, - "utils_nfcore_pipeline": { - "branch": "master", - "git_sha": "262b17ed2aad591039f914951659177e6c39a8d8", - "installed_by": ["subworkflows"] - }, - "utils_nfvalidation_plugin": { - "branch": "master", - "git_sha": "cd08c91373cd00a73255081340e4914485846ba1", - "installed_by": ["subworkflows"] - } - } - }, "subworkflows": { "nf-core": { "utils_nextflow_pipeline": { diff --git a/modules/nf-core/custom/dumpsoftwareversions/environment.yml b/modules/nf-core/custom/dumpsoftwareversions/environment.yml new file mode 100644 index 00000000..9b3272bc --- /dev/null +++ b/modules/nf-core/custom/dumpsoftwareversions/environment.yml @@ -0,0 +1,7 @@ +name: custom_dumpsoftwareversions +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::multiqc=1.19 diff --git a/modules/nf-core/custom/dumpsoftwareversions/main.nf b/modules/nf-core/custom/dumpsoftwareversions/main.nf new file mode 100644 index 00000000..f2187611 --- /dev/null +++ b/modules/nf-core/custom/dumpsoftwareversions/main.nf @@ -0,0 +1,24 @@ +process CUSTOM_DUMPSOFTWAREVERSIONS { + label 'process_single' + + // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/multiqc:1.19--pyhdfd78af_0' : + 'biocontainers/multiqc:1.19--pyhdfd78af_0' }" + + input: + path versions + + output: + path "software_versions.yml" , emit: yml + path "software_versions_mqc.yml", emit: mqc_yml + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + template 'dumpsoftwareversions.py' +} diff --git a/modules/nf-core/custom/dumpsoftwareversions/meta.yml b/modules/nf-core/custom/dumpsoftwareversions/meta.yml new file mode 100644 index 00000000..5f15a5fd --- /dev/null +++ b/modules/nf-core/custom/dumpsoftwareversions/meta.yml @@ -0,0 +1,37 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json +name: custom_dumpsoftwareversions +description: Custom module used to dump software versions within the nf-core pipeline template +keywords: + - custom + - dump + - version +tools: + - custom: + description: Custom module used to dump software versions within the nf-core pipeline template + homepage: https://github.com/nf-core/tools + documentation: https://github.com/nf-core/tools + licence: ["MIT"] +input: + - versions: + type: file + description: YML file containing software versions + pattern: "*.yml" +output: + - yml: + type: file + description: Standard YML file containing software versions + pattern: "software_versions.yml" + - mqc_yml: + type: file + description: MultiQC custom content YML file containing software versions + pattern: "software_versions_mqc.yml" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@drpatelh" + - "@grst" +maintainers: + - "@drpatelh" + - "@grst" diff --git a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py new file mode 100755 index 00000000..da033408 --- /dev/null +++ b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python + + +"""Provide functions to merge multiple versions.yml files.""" + + +import yaml +import platform +from textwrap import dedent + + +def _make_versions_html(versions): + """Generate a tabular HTML output of all versions for MultiQC.""" + html = [ + dedent( + """\\ + +
    Process Name \\", - " \\ Software Version
    CUSTOM_DUMPSOFTWAREVERSIONSpython3.11.7
    yaml5.4.1
    TOOL1tool10.11.9
    TOOL2tool21.9
    WorkflowNextflow
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    + + + + + + + + """ + ) + ] + for process, tmp_versions in sorted(versions.items()): + html.append("") + for i, (tool, version) in enumerate(sorted(tmp_versions.items())): + html.append( + dedent( + f"""\\ + + + + + + """ + ) + ) + html.append("") + html.append("
    Process Name Software Version
    {process if (i == 0) else ''}{tool}{version}
    ") + return "\\n".join(html) + + +def main(): + """Load all version files and generate merged output.""" + versions_this_module = {} + versions_this_module["${task.process}"] = { + "python": platform.python_version(), + "yaml": yaml.__version__, + } + + with open("$versions") as f: + versions_by_process = yaml.load(f, Loader=yaml.BaseLoader) | versions_this_module + + # aggregate versions by the module name (derived from fully-qualified process name) + versions_by_module = {} + for process, process_versions in versions_by_process.items(): + module = process.split(":")[-1] + try: + if versions_by_module[module] != process_versions: + raise AssertionError( + "We assume that software versions are the same between all modules. " + "If you see this error-message it means you discovered an edge-case " + "and should open an issue in nf-core/tools. " + ) + except KeyError: + versions_by_module[module] = process_versions + + versions_by_module["Workflow"] = { + "Nextflow": "$workflow.nextflow.version", + "$workflow.manifest.name": "$workflow.manifest.version", + } + + versions_mqc = { + "id": "software_versions", + "section_name": "${workflow.manifest.name} Software Versions", + "section_href": "https://github.com/${workflow.manifest.name}", + "plot_type": "html", + "description": "are collected at run time from the software output.", + "data": _make_versions_html(versions_by_module), + } + + with open("software_versions.yml", "w") as f: + yaml.dump(versions_by_module, f, default_flow_style=False) + with open("software_versions_mqc.yml", "w") as f: + yaml.dump(versions_mqc, f, default_flow_style=False) + + with open("versions.yml", "w") as f: + yaml.dump(versions_this_module, f, default_flow_style=False) + + +if __name__ == "__main__": + main() diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test new file mode 100644 index 00000000..b1e1630b --- /dev/null +++ b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test @@ -0,0 +1,43 @@ +nextflow_process { + + name "Test Process CUSTOM_DUMPSOFTWAREVERSIONS" + script "../main.nf" + process "CUSTOM_DUMPSOFTWAREVERSIONS" + tag "modules" + tag "modules_nfcore" + tag "custom" + tag "dumpsoftwareversions" + tag "custom/dumpsoftwareversions" + + test("Should run without failures") { + when { + process { + """ + def tool1_version = ''' + TOOL1: + tool1: 0.11.9 + '''.stripIndent() + + def tool2_version = ''' + TOOL2: + tool2: 1.9 + '''.stripIndent() + + input[0] = Channel.of(tool1_version, tool2_version).collectFile() + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.versions, + file(process.out.mqc_yml[0]).readLines()[0..10], + file(process.out.yml[0]).readLines()[0..7] + ).match() + } + ) + } + } +} diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap new file mode 100644 index 00000000..5f59a936 --- /dev/null +++ b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap @@ -0,0 +1,33 @@ +{ + "Should run without failures": { + "content": [ + [ + "versions.yml:md5,76d454d92244589d32455833f7c1ba6d" + ], + [ + "data: \"\\n\\n \\n \\n \\n \\n \\n \\n \\n\\", + " \\n\\n\\n \\n \\n\\", + " \\ \\n\\n\\n\\n \\n \\", + " \\ \\n \\n\\n\\n\\n\\", + " \\n\\n \\n \\n\\", + " \\ \\n\\n\\n\\n\\n\\n \\n\\", + " \\ \\n \\n\\n\\n\\n\\", + " \\n\\n \\n \\n\\" + ], + [ + "CUSTOM_DUMPSOFTWAREVERSIONS:", + " python: 3.11.7", + " yaml: 5.4.1", + "TOOL1:", + " tool1: 0.11.9", + "TOOL2:", + " tool2: '1.9'", + "Workflow:" + ] + ], + "timestamp": "2024-01-09T23:01:18.710682" + } +} \ No newline at end of file diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml b/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml new file mode 100644 index 00000000..405aa24a --- /dev/null +++ b/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml @@ -0,0 +1,2 @@ +custom/dumpsoftwareversions: + - modules/nf-core/custom/dumpsoftwareversions/** From abd9aa7fc8005a412e3c16733a21fef64382b233 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sun, 3 Mar 2024 08:30:51 +0100 Subject: [PATCH 143/491] Fix script references --- modules/local/count_matrix/single/main.nf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/local/count_matrix/single/main.nf b/modules/local/count_matrix/single/main.nf index 856ffa7e..20e1b975 100644 --- a/modules/local/count_matrix/single/main.nf +++ b/modules/local/count_matrix/single/main.nf @@ -29,12 +29,12 @@ process COUNTS_SINGLE { mv \$b \${sample_name}.bed done - python ${workflow.projectDir}/bin/circRNA_counts_matrix.py > matrix.txt + circRNA_counts_matrix.py > matrix.txt ## handle non-canon chromosomes here (https://stackoverflow.com/questions/71479919/joining-columns-based-on-number-of-fields) n_samps=\$(ls *.bed | wc -l) canon=\$(awk -v a="\$n_samps" 'BEGIN {print a + 4}') awk -v n="\$canon" '{ for (i = 2; i <= NF - n + 1; ++i) { \$1 = \$1"-"\$i; \$i=""; } } 1' matrix.txt | awk -v OFS="\\t" '\$1=\$1' > circRNA_matrix.txt - Rscript ${workflow.projectDir}/bin/reformat_count_matrix.R + reformat_count_matrix.R cat <<-END_VERSIONS > versions.yml "${task.process}": From 5a68987e2ae64d226963d0a6faf14c81d70efeba Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 18 Mar 2024 08:58:54 +0100 Subject: [PATCH 144/491] Improve channel structure --- main.nf | 11 +++++- modules/local/targetscan/database/main.nf | 6 +-- modules/local/targetscan/predict/main.nf | 2 +- subworkflows/local/circrna_discovery.nf | 29 +++++++------- subworkflows/local/differential_expression.nf | 17 +++----- subworkflows/local/prepare_genome.nf | 39 +++++++------------ workflows/circrna/main.nf | 24 +++++------- 7 files changed, 56 insertions(+), 72 deletions(-) diff --git a/main.nf b/main.nf index 9cf725ef..1e202b27 100644 --- a/main.nf +++ b/main.nf @@ -55,9 +55,18 @@ workflow NFCORE_CIRCRNA { // // WORKFLOW: Run nf-core/circrna workflow // - ch_samplesheet = Channel.value(file(params.input, checkIfExists: true)) + ch_samplesheet = Channel.fromSamplesheet("input") + ch_phenotype = Channel.value([[id: "phenotype"], file(params.phenotype, checkIfExists:true)]) + ch_fasta = Channel.value([[id: "fasta"], file(params.fasta, checkIfExists:true)]) + ch_gtf = Channel.value([[id: "gtf"], file(params.gtf, checkIfExists:true)]) + ch_mature = Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) + CIRCRNA ( ch_samplesheet, + ch_phenotype, + ch_fasta, + ch_gtf, + ch_mature, ch_versions ) diff --git a/modules/local/targetscan/database/main.nf b/modules/local/targetscan/database/main.nf index 44e54e40..8ba3ef71 100644 --- a/modules/local/targetscan/database/main.nf +++ b/modules/local/targetscan/database/main.nf @@ -1,5 +1,5 @@ process TARGETSCAN_DATABASE { - tag "$mature" + tag "$meta.id" label 'process_low' conda "conda-forge::sed=4.7" @@ -8,10 +8,10 @@ process TARGETSCAN_DATABASE { 'nf-core/ubuntu:20.04' }" input: - path(mature) + tuple val(meta), path(mature) output: - path("mature.txt") , emit: mature_txt + tuple val(meta), path("mature.txt") , emit: mature_txt path "versions.yml" , emit: versions when: diff --git a/modules/local/targetscan/predict/main.nf b/modules/local/targetscan/predict/main.nf index e8e5567f..12d3511e 100644 --- a/modules/local/targetscan/predict/main.nf +++ b/modules/local/targetscan/predict/main.nf @@ -9,7 +9,7 @@ process TARGETSCAN { input: tuple val(meta), path(fasta) - path(mature_txt) + tuple val(meta2), path(mature_txt) output: tuple val(meta), path("${prefix}.txt"), emit: txt diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 90b60726..a0a20433 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -45,8 +45,8 @@ workflow CIRCRNA_DISCOVERY { take: reads - fasta - gtf + ch_fasta + ch_gtf bowtie_index bowtie2_index bwa_index @@ -61,11 +61,8 @@ workflow CIRCRNA_DISCOVERY { main: ch_versions = Channel.empty() - ch_fasta = Channel.value(fasta) - ch_gtf = Channel.value(gtf) - fasta_tuple = Channel.value([[id: "fasta"], fasta]) - gtf_tuple = Channel.value([[id: "gtf"], gtf]) - + fasta = ch_fasta.map{meta, fasta -> fasta} + gtf = ch_gtf.map{meta, gtf -> gtf} // // SEGEMEHL WORKFLOW: @@ -86,10 +83,10 @@ workflow CIRCRNA_DISCOVERY { seq_center = params.seq_center ?: '' seq_platform = '' - STAR_1ST_PASS( reads, star_index.first(), gtf_tuple, star_ignore_sjdbgtf, seq_platform, seq_center) + STAR_1ST_PASS( reads, star_index, ch_gtf, star_ignore_sjdbgtf, seq_platform, seq_center) sjdb = STAR_1ST_PASS.out.tab.map{ meta, tab -> return tab }.collect().map{[[id: "star_sjdb"], it]} STAR_SJDB( sjdb, bsj_reads ) - STAR_2ND_PASS( reads, star_index.first(), STAR_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) + STAR_2ND_PASS( reads, star_index, STAR_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) ch_versions = ch_versions.mix(STAR_1ST_PASS.out.versions) ch_versions = ch_versions.mix(STAR_2ND_PASS.out.versions) @@ -125,7 +122,7 @@ workflow CIRCRNA_DISCOVERY { FIND_CIRC_ALIGN( reads, bowtie2_index.collect(), false, true ) SAMTOOLS_INDEX( FIND_CIRC_ALIGN.out.aligned ) - SAMTOOLS_VIEW( FIND_CIRC_ALIGN.out.aligned.join( SAMTOOLS_INDEX.out.bai ), fasta_tuple, [] ) + SAMTOOLS_VIEW( FIND_CIRC_ALIGN.out.aligned.join( SAMTOOLS_INDEX.out.bai ), ch_fasta, [] ) FIND_CIRC_ANCHORS( SAMTOOLS_VIEW.out.bam ) FIND_CIRC( FIND_CIRC_ANCHORS.out.anchors, bowtie2_index.collect(), fasta ) find_circ_filter = FIND_CIRC.out.bed.map{ meta, bed -> [ meta + [tool: "find_circ"], bed ] } @@ -156,14 +153,14 @@ workflow CIRCRNA_DISCOVERY { // mate1 = reads.filter{ meta, reads -> !meta.single_end }.map{ meta, reads -> return [ [id: meta.id, single_end: true], reads[0] ] } - DCC_MATE1_1ST_PASS( mate1, star_index.first(), gtf_tuple, star_ignore_sjdbgtf, seq_platform, seq_center ) + DCC_MATE1_1ST_PASS( mate1, star_index, ch_gtf, star_ignore_sjdbgtf, seq_platform, seq_center ) DCC_MATE1_SJDB( DCC_MATE1_1ST_PASS.out.tab.map{ meta, tab -> return tab }.collect().map{[[id: "mate1_sjdb"], it]}, bsj_reads ) - DCC_MATE1_2ND_PASS( mate1, star_index.first(), DCC_MATE1_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) + DCC_MATE1_2ND_PASS( mate1, star_index, DCC_MATE1_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) mate2 = reads.filter{ meta, reads -> !meta.single_end }.map{ meta, reads -> return [ [id: meta.id, single_end: true], reads[1] ] } - DCC_MATE2_1ST_PASS( mate2, star_index.first(), gtf_tuple, star_ignore_sjdbgtf, seq_platform, seq_center ) + DCC_MATE2_1ST_PASS( mate2, star_index, ch_gtf, star_ignore_sjdbgtf, seq_platform, seq_center ) DCC_MATE2_SJDB( DCC_MATE2_1ST_PASS.out.tab.map{ meta, tab -> return tab }.collect().map{[[id: "mate2_sjdb"], it]}, bsj_reads ) - DCC_MATE2_2ND_PASS( mate2, star_index.first(), DCC_MATE2_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) + DCC_MATE2_2ND_PASS( mate2, star_index, DCC_MATE2_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) dcc_stage = STAR_2ND_PASS.out.junction.map{ meta, junction -> return [ meta.id, meta, junction]} .join( @@ -194,7 +191,7 @@ workflow CIRCRNA_DISCOVERY { // MAPSPLICE_REFERENCE( gtf ) - MAPSPLICE_ALIGN( reads, bowtie_index.collect(), chromosomes, ch_gtf ) + MAPSPLICE_ALIGN( reads, bowtie_index.collect(), chromosomes, gtf ) MAPSPLICE_PARSE( MAPSPLICE_ALIGN.out.raw_fusions ) MAPSPLICE_ANNOTATE( MAPSPLICE_PARSE.out.junction, fasta, MAPSPLICE_REFERENCE.out.txt ) mapsplice_filter = MAPSPLICE_ANNOTATE.out.txt.map{ meta, txt -> [ meta + [tool: "mapsplice"], txt ] } @@ -218,7 +215,7 @@ workflow CIRCRNA_DISCOVERY { DCC_FILTER.out.results, MAPSPLICE_FILTER.out.results) - INTERSECT_ANNOTATION( circrna_filtered.combine(ch_gtf), [[], []]) + INTERSECT_ANNOTATION( circrna_filtered.combine(gtf), [[], []]) ANNOTATION( INTERSECT_ANNOTATION.out.intersect, exon_boundary ) ch_versions = ch_versions.mix(INTERSECT_ANNOTATION.out.versions) diff --git a/subworkflows/local/differential_expression.nf b/subworkflows/local/differential_expression.nf index 2964c3fb..f341fd3f 100644 --- a/subworkflows/local/differential_expression.nf +++ b/subworkflows/local/differential_expression.nf @@ -12,8 +12,8 @@ workflow DIFFERENTIAL_EXPRESSION { take: reads - gtf - fasta + ch_gtf + ch_fasta hisat2_index splice_sites phenotype @@ -25,22 +25,17 @@ workflow DIFFERENTIAL_EXPRESSION { main: ch_versions = Channel.empty() - qc_reports = Channel.empty() - ch_fasta = Channel.fromPath(fasta) - ch_gtf = Channel.fromPath(gtf) + qc_reports = Channel.empty() - ch_fasta.map{ it -> [ [id: it.simpleName], [it] ] - }.set{ fasta_tuple } - - ch_gtf.map{ it -> [ [id: it.simpleName], [it] ] - }.set{ gtf_tuple } + fasta = ch_fasta.map{ meta, fasta -> fasta } + gtf = ch_gtf.map{ meta, gtf -> gtf } // // LINEAR RNA ALIGNEMT WORKFLOW: // HISAT2_ALIGN( reads, hisat2_index, splice_sites ) - BAM_SORT_STATS_SAMTOOLS( HISAT2_ALIGN.out.bam, fasta_tuple ) + BAM_SORT_STATS_SAMTOOLS( HISAT2_ALIGN.out.bam, ch_fasta ) STRINGTIE_STRINGTIE( BAM_SORT_STATS_SAMTOOLS.out.bam, gtf ) STRINGTIE_PREPDE( STRINGTIE_STRINGTIE.out.transcript_gtf.map{ meta, gtf -> return [ gtf ] }.collect() ) diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 96045cfc..5d82d65d 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -11,8 +11,8 @@ include { GAWK as CLEAN_FASTA } from '../../modules/nf-core/gawk/main' workflow PREPARE_GENOME { take: - fasta - gtf + ch_fasta + ch_gtf main: ch_versions = Channel.empty() @@ -20,53 +20,40 @@ workflow PREPARE_GENOME { // MapSplice cannot deal with extra field in the fasta headers // this removes all additional fields in the headers of the input fasta file if( params.tool.contains('mapsplice') && params.module.contains('circrna_discovery') ) { - - CLEAN_FASTA(Channel.value([[id: "${fasta.baseName}" + ".clean_headers" ], fasta]), []) - - ch_fasta = CLEAN_FASTA.out.output.map{ it.last() } - } - - else { - - ch_fasta = Channel.fromPath(fasta) - + CLEAN_FASTA(ch_fasta, []) + ch_fasta = CLEAN_FASTA.out.output } - - ch_gtf = Channel.fromPath(gtf) - fasta_tuple = Channel.value([[id: "fasta"], fasta]) - gtf_tuple = Channel.value([[id: "gtf"], gtf]) - // MapSplice & find_circ requires reference genome to be split per chromosome: if( ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) && params.module.contains('circrna_discovery') ){ directory = file("${params.outdir}/references/chromosomes") if ( !directory.exists() ) { directory.mkdirs() - ch_fasta.splitFasta( record: [id:true] ) + ch_fasta.map{meta, fasta -> fasta}.splitFasta( record: [id:true] ) .map{ record -> record.id.toString() } .set{ ID } - ch_fasta.splitFasta( file: true ) + ch_fasta.map{meta, fasta -> fasta}.splitFasta( file: true ) .merge( ID ).map{ file, id -> file.copyTo(directory + "/${id}.fa") } } stage_chromosomes = Channel.value(directory) } - BOWTIE_BUILD(ch_fasta) + BOWTIE_BUILD(ch_fasta.map{ meta, fasta -> fasta }) - BOWTIE2_BUILD(fasta_tuple) + BOWTIE2_BUILD(ch_fasta) - BWA_INDEX (fasta_tuple) + BWA_INDEX (ch_fasta) - HISAT2_EXTRACTSPLICESITES(gtf_tuple) + HISAT2_EXTRACTSPLICESITES(ch_gtf) - HISAT2_BUILD(fasta_tuple, gtf_tuple, HISAT2_EXTRACTSPLICESITES.out.txt) + HISAT2_BUILD(ch_fasta, ch_gtf, HISAT2_EXTRACTSPLICESITES.out.txt) - STAR_GENOMEGENERATE(fasta_tuple, gtf_tuple) + STAR_GENOMEGENERATE(ch_fasta, ch_gtf) - SEGEMEHL_INDEX(fasta) + SEGEMEHL_INDEX(ch_fasta.map{ meta, fasta -> fasta}) // TODO: Add support for meta // Collect versions ch_versions = ch_versions.mix(BOWTIE_BUILD.out.versions) diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 3e95f4ca..e51d850e 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -4,11 +4,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -ch_phenotype = params.phenotype && params.module.contains('differential_expression') ? file(params.phenotype, checkIfExists:true) : Channel.empty() -ch_fasta = params.fasta ? file(params.fasta) : 'null' -ch_gtf = params.gtf ? file(params.gtf) : 'null' -ch_mature = params.mature && params.module.contains('mirna_prediction') ? file(params.mature) : Channel.empty() - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CONFIG FILES @@ -58,6 +53,10 @@ include { FASTQC_TRIMGALORE } from '../../subworkflows/nf-core/fastqc_trimgalore workflow CIRCRNA { take: ch_samplesheet + ch_phenotype + ch_fasta + ch_gtf + ch_mature ch_versions main: @@ -69,8 +68,7 @@ workflow CIRCRNA { // // SUBWORKFLOW: - Channel - .fromSamplesheet("input") + ch_samplesheet .map { meta, fastq_1, fastq_2 -> if (!fastq_2) { @@ -98,13 +96,11 @@ workflow CIRCRNA { // MODULE: // Concatenate FastQ files from same sample if required - CAT_FASTQ ( - ch_fastq.multiple - ) - .reads - .mix(ch_fastq.single) - .set { ch_cat_fastq } - ch_versions = ch_versions.mix(CAT_FASTQ.out.versions.first().ifEmpty(null)) + CAT_FASTQ (ch_fastq.multiple) + .reads + .mix(ch_fastq.single) + .set { ch_cat_fastq } + ch_versions = ch_versions.mix(CAT_FASTQ.out.versions) // SUBORKFLOW: // Prepare index files &/or use iGenomes if chosen. From 0a782bea722662ecfced07254c1e82eeb37e8d7e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 18 Mar 2024 09:23:14 +0100 Subject: [PATCH 145/491] Implement seqkit_split --- conf/modules.config | 10 ++++++ modules/local/seqkit/split/environment.yml | 7 +++++ modules/local/seqkit/split/main.nf | 36 ++++++++++++++++++++++ subworkflows/local/prepare_genome.nf | 21 ++----------- 4 files changed, 56 insertions(+), 18 deletions(-) create mode 100644 modules/local/seqkit/split/environment.yml create mode 100644 modules/local/seqkit/split/main.nf diff --git a/conf/modules.config b/conf/modules.config index 65671920..8c1f48bd 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -78,6 +78,16 @@ if (!params.skip_trimming) { ] } + withName: SEQKIT_SPLIT { + ext.args = "-i" + publishDir = [ + path: { "${params.outdir}/references/chromosomes" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + enabled: params.save_reference + ] + } + withName: BOWTIE_BUILD { ext.when = { params.fasta && !params.bowtie && params.tool.split(',').contains('mapsplice') && params.module.split(',').contains('circrna_discovery') } publishDir = [ diff --git a/modules/local/seqkit/split/environment.yml b/modules/local/seqkit/split/environment.yml new file mode 100644 index 00000000..6eaa568f --- /dev/null +++ b/modules/local/seqkit/split/environment.yml @@ -0,0 +1,7 @@ +name: seqkit_split +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::seqkit=2.1.0 \ No newline at end of file diff --git a/modules/local/seqkit/split/main.nf b/modules/local/seqkit/split/main.nf new file mode 100644 index 00000000..c1be1899 --- /dev/null +++ b/modules/local/seqkit/split/main.nf @@ -0,0 +1,36 @@ +process SEQKIT_SPLIT { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/seqkit:2.1.0--h9ee0642_0' : + 'biocontainers/seqkit:2.1.0--h9ee0642_0' }" + + input: + tuple val(meta), path(fasta) + + output: + tuple val(meta), path("${prefix}/*"), emit: split + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${meta.id}" + """ + seqkit \\ + split \\ + $args \\ + --threads $task.cpus \\ + $fasta \\ + --out-dir ${prefix} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + seqkit: \$(echo \$(seqkit 2>&1) | sed 's/^.*Version: //; s/ .*\$//') + END_VERSIONS + """ +} \ No newline at end of file diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 5d82d65d..b27e226d 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -1,4 +1,4 @@ - +include { SEQKIT_SPLIT } from '../../modules/local/seqkit/split/main' include { BOWTIE_BUILD } from '../../modules/nf-core/bowtie/build/main' include { BOWTIE2_BUILD } from '../../modules/nf-core/bowtie2/build/main' include { BWA_INDEX } from '../../modules/nf-core/bwa/index/main' @@ -24,22 +24,7 @@ workflow PREPARE_GENOME { ch_fasta = CLEAN_FASTA.out.output } - // MapSplice & find_circ requires reference genome to be split per chromosome: - if( ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) && params.module.contains('circrna_discovery') ){ - directory = file("${params.outdir}/references/chromosomes") - - if ( !directory.exists() ) { - directory.mkdirs() - ch_fasta.map{meta, fasta -> fasta}.splitFasta( record: [id:true] ) - .map{ record -> record.id.toString() } - .set{ ID } - - ch_fasta.map{meta, fasta -> fasta}.splitFasta( file: true ) - .merge( ID ).map{ file, id -> file.copyTo(directory + "/${id}.fa") } - } - - stage_chromosomes = Channel.value(directory) - } + SEQKIT_SPLIT(ch_fasta) BOWTIE_BUILD(ch_fasta.map{ meta, fasta -> fasta }) @@ -68,7 +53,7 @@ workflow PREPARE_GENOME { bowtie = BOWTIE_BUILD.out.index bowtie2 = BOWTIE2_BUILD.out.index bwa = BWA_INDEX.out.index - chromosomes = ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) ? stage_chromosomes : 'null' + chromosomes = SEQKIT_SPLIT.out.split hisat2 = HISAT2_BUILD.out.index.collect() star = STAR_GENOMEGENERATE.out.index.collect() segemehl = SEGEMEHL_INDEX.out.index From 09642064ad1520eb0ba4885faaefb39278f7c78f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 18 Mar 2024 09:41:52 +0100 Subject: [PATCH 146/491] Update seqkit version --- conf/modules.config | 2 +- modules/local/mapsplice/align/main.nf | 8 ++++---- modules/local/seqkit/split/environment.yml | 2 +- modules/local/seqkit/split/main.nf | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 8c1f48bd..a6ccdf5c 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -79,7 +79,7 @@ if (!params.skip_trimming) { } withName: SEQKIT_SPLIT { - ext.args = "-i" + ext.args = "-i --by-id-prefix \"\"" publishDir = [ path: { "${params.outdir}/references/chromosomes" }, mode: params.publish_dir_mode, diff --git a/modules/local/mapsplice/align/main.nf b/modules/local/mapsplice/align/main.nf index b62e4db2..7dcbbbd3 100644 --- a/modules/local/mapsplice/align/main.nf +++ b/modules/local/mapsplice/align/main.nf @@ -10,7 +10,7 @@ process MAPSPLICE_ALIGN { input: tuple val(meta), path(reads) path bowtie_index - path chromosomes + tuple val(meta2), path(chromosomes, stageAs: 'chromosomes/*') path gtf output: @@ -32,7 +32,7 @@ process MAPSPLICE_ALIGN { $handleGzip_R1 mapsplice.py \\ - -c $chromosomes \\ + -c chromosomes \\ -x $gtf_prefix \\ -1 ${read1} \\ -p ${task.cpus} \\ @@ -46,7 +46,7 @@ process MAPSPLICE_ALIGN { mapsplice: $VERSION END_VERSIONS """ - }else{ + } else { def handleGzip_R1 = reads[0].getExtension() == 'gz' ? "gzip -d -f ${reads[0]}" : '' def handleGzip_R2 = reads[1].getExtension() == 'gz' ? "gzip -d -f ${reads[1]}" : '' def read1 = reads[0].getExtension() == 'gz' ? reads[0].toString() - ~/.gz/ : reads[0] @@ -56,7 +56,7 @@ process MAPSPLICE_ALIGN { $handleGzip_R2 mapsplice.py \\ - -c $chromosomes \\ + -c chromosomes \\ -x $gtf_prefix \\ -1 ${read1} \\ -2 ${read2} \\ diff --git a/modules/local/seqkit/split/environment.yml b/modules/local/seqkit/split/environment.yml index 6eaa568f..fb5b8b63 100644 --- a/modules/local/seqkit/split/environment.yml +++ b/modules/local/seqkit/split/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - bioconda::seqkit=2.1.0 \ No newline at end of file + - bioconda::seqkit=2.8.0 \ No newline at end of file diff --git a/modules/local/seqkit/split/main.nf b/modules/local/seqkit/split/main.nf index c1be1899..5d70f47b 100644 --- a/modules/local/seqkit/split/main.nf +++ b/modules/local/seqkit/split/main.nf @@ -4,8 +4,8 @@ process SEQKIT_SPLIT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/seqkit:2.1.0--h9ee0642_0' : - 'biocontainers/seqkit:2.1.0--h9ee0642_0' }" + 'https://depot.galaxyproject.org/singularity/seqkit:2.8.0--h9ee0642_0' : + 'biocontainers/seqkit:2.8.0--h9ee0642_0' }" input: tuple val(meta), path(fasta) From c4a3e8e62224c236f73da02c6e836867e0bd1fc7 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 18 Mar 2024 10:04:22 +0100 Subject: [PATCH 147/491] Update modules --- modules.json | 52 +- modules/nf-core/bedtools/intersect/meta.yml | 4 +- modules/nf-core/bedtools/sort/meta.yml | 4 +- modules/nf-core/bwa/index/tests/main.nf.test | 4 +- modules/nf-core/cat/cat/main.nf | 11 +- modules/nf-core/cat/cat/tests/main.nf.test | 23 +- modules/nf-core/cat/fastq/environment.yml | 2 +- modules/nf-core/cat/fastq/main.nf | 1 - modules/nf-core/cat/fastq/tests/main.nf.test | 63 ++- .../nf-core/cat/fastq/tests/main.nf.test.snap | 185 +++++-- .../dumpsoftwareversions/environment.yml | 2 +- .../custom/dumpsoftwareversions/main.nf | 4 +- .../nf-core/hisat2/align/tests/main.nf.test | 144 +++--- .../nf-core/hisat2/build/tests/main.nf.test | 29 +- .../extractsplicesites/tests/main.nf.test | 14 +- .../tests/main.nf.test.snap | 29 +- .../nf-core/samtools/flagstat/environment.yml | 3 +- modules/nf-core/samtools/flagstat/main.nf | 4 +- .../samtools/flagstat/tests/main.nf.test | 12 +- .../samtools/flagstat/tests/main.nf.test.snap | 20 +- .../nf-core/samtools/idxstats/environment.yml | 3 +- modules/nf-core/samtools/idxstats/main.nf | 4 +- .../samtools/idxstats/tests/main.nf.test | 14 +- .../samtools/idxstats/tests/main.nf.test.snap | 20 +- .../nf-core/samtools/index/environment.yml | 3 +- modules/nf-core/samtools/index/main.nf | 4 +- .../nf-core/samtools/index/tests/main.nf.test | 36 +- .../samtools/index/tests/main.nf.test.snap | 54 +- modules/nf-core/samtools/sort/environment.yml | 3 +- modules/nf-core/samtools/sort/main.nf | 32 +- modules/nf-core/samtools/sort/meta.yml | 32 +- .../nf-core/samtools/sort/tests/main.nf.test | 71 ++- .../samtools/sort/tests/main.nf.test.snap | 128 ++++- .../samtools/sort/tests/nextflow.config | 3 +- .../nf-core/samtools/stats/environment.yml | 3 +- modules/nf-core/samtools/stats/main.nf | 4 +- .../nf-core/samtools/stats/tests/main.nf.test | 53 +- .../samtools/stats/tests/main.nf.test.snap | 32 +- modules/nf-core/samtools/view/environment.yml | 3 +- modules/nf-core/samtools/view/main.nf | 4 +- .../nf-core/samtools/view/tests/main.nf.test | 193 ++++---- .../samtools/view/tests/main.nf.test.snap | 466 +++++++++++++++--- modules/nf-core/star/align/environment.yml | 1 + modules/nf-core/star/align/tests/main.nf.test | 141 ++---- .../star/genomegenerate/environment.yml | 3 +- .../star/genomegenerate/tests/main.nf.test | 40 +- .../genomegenerate/tests/main.nf.test.snap | 80 ++- .../stringtie/stringtie/tests/main.nf.test | 64 +-- .../stringtie/stringtie/tests/nextflow.config | 5 + modules/nf-core/trimgalore/environment.yml | 3 + modules/nf-core/trimgalore/tests/main.nf.test | 20 +- .../trimgalore/tests/main.nf.test.snap | 154 +----- .../nf-core/bam_sort_stats_samtools/main.nf | 2 +- .../tests/main.nf.test | 28 +- .../tests/main.nf.test.snap | 36 +- 55 files changed, 1461 insertions(+), 891 deletions(-) create mode 100644 modules/nf-core/stringtie/stringtie/tests/nextflow.config diff --git a/modules.json b/modules.json index 9cfb49d2..c7beb988 100644 --- a/modules.json +++ b/modules.json @@ -7,12 +7,12 @@ "nf-core": { "bedtools/intersect": { "branch": "master", - "git_sha": "3b248b84694d1939ac4bb33df84bf6233a34d668", + "git_sha": "575e1bc54b083fb15e7dd8b5fcc40bea60e8ce83", "installed_by": ["modules"] }, "bedtools/sort": { "branch": "master", - "git_sha": "3b248b84694d1939ac4bb33df84bf6233a34d668", + "git_sha": "575e1bc54b083fb15e7dd8b5fcc40bea60e8ce83", "installed_by": ["modules"] }, "bowtie/align": { @@ -37,17 +37,17 @@ }, "bwa/index": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "6278bf9afd4a4b2d00fa6052250e73da3d91546f", "installed_by": ["modules"] }, "cat/cat": { "branch": "master", - "git_sha": "d593e8f6b7d1bbbb2acf43a4b9efeeac8d6720f2", + "git_sha": "9437e6053dccf4aafa022bfd6e7e9de67e625af8", "installed_by": ["modules"] }, "cat/fastq": { "branch": "master", - "git_sha": "e8940f18cfbbdcdcde38f4b3633df5ed4e48da10", + "git_sha": "0997b47c93c06b49aa7b3fefda87e728312cf2ca", "installed_by": ["modules"] }, "circexplorer2/annotate": { @@ -67,12 +67,12 @@ }, "custom/dumpsoftwareversions": { "branch": "master", - "git_sha": "8ec825f465b9c17f9d83000022995b4f7de6fe93", + "git_sha": "de45447d060b8c8b98575bc637a4a575fd0638e1", "installed_by": ["modules"] }, "fastqc": { "branch": "master", - "git_sha": "617777a807a1770f73deb38c80004bac06807eef", + "git_sha": "f4ae1d942bd50c5c0b9bd2de1393ce38315ba57c", "installed_by": ["modules"] }, "gawk": { @@ -82,22 +82,22 @@ }, "hisat2/align": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", "installed_by": ["modules"] }, "hisat2/build": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", "installed_by": ["modules"] }, "hisat2/extractsplicesites": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", "installed_by": ["modules"] }, "miranda": { "branch": "master", - "git_sha": "c9488585ce7bd35ccd2a30faa2371454c8112fb9", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": ["modules"] }, "multiqc": { @@ -107,32 +107,32 @@ }, "samtools/flagstat": { "branch": "master", - "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", "installed_by": ["bam_stats_samtools"] }, "samtools/idxstats": { "branch": "master", - "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", "installed_by": ["bam_stats_samtools"] }, "samtools/index": { "branch": "master", - "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", "installed_by": ["bam_sort_stats_samtools", "modules"] }, "samtools/sort": { "branch": "master", - "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", + "git_sha": "4352dbdb09ec40db71e9b172b97a01dcf5622c26", "installed_by": ["bam_sort_stats_samtools", "modules"] }, "samtools/stats": { "branch": "master", - "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", "installed_by": ["bam_stats_samtools"] }, "samtools/view": { "branch": "master", - "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", + "git_sha": "0bd7d2333a88483aa0476acea172e9f5f6dd83bb", "installed_by": ["modules"] }, "segemehl/align": { @@ -147,28 +147,38 @@ }, "star/align": { "branch": "master", - "git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c", + "git_sha": "a21faa6a3481af92a343a10926f59c189a2c16c9", "installed_by": ["modules"] }, "star/genomegenerate": { "branch": "master", - "git_sha": "d87a6e2156c2099c09280fa70776eaf0a824817a", + "git_sha": "a21faa6a3481af92a343a10926f59c189a2c16c9", "installed_by": ["modules"] }, "stringtie/stringtie": { "branch": "master", - "git_sha": "b0dcb44b018d9b2bcb35b1abb7bcd34061bc5a6d", + "git_sha": "b1b959609bda44341120aed1766329909f54b8d0", "installed_by": ["modules"] }, "trimgalore": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "a98418419ae6c9df3cf6cf108d1e1aba71037d5a", "installed_by": ["modules"] } } }, "subworkflows": { "nf-core": { + "bam_sort_stats_samtools": { + "branch": "master", + "git_sha": "4352dbdb09ec40db71e9b172b97a01dcf5622c26", + "installed_by": ["subworkflows"] + }, + "bam_stats_samtools": { + "branch": "master", + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "installed_by": ["bam_sort_stats_samtools", "subworkflows"] + }, "utils_nextflow_pipeline": { "branch": "master", "git_sha": "5caf7640a9ef1d18d765d55339be751bb0969dfa", diff --git a/modules/nf-core/bedtools/intersect/meta.yml b/modules/nf-core/bedtools/intersect/meta.yml index 8d9a08aa..0939cb54 100644 --- a/modules/nf-core/bedtools/intersect/meta.yml +++ b/modules/nf-core/bedtools/intersect/meta.yml @@ -48,12 +48,12 @@ output: description: File containing software versions pattern: "versions.yml" authors: - - "@Emiller88" + - "@edmundmiller" - "@sruthipsuresh" - "@drpatelh" - "@sidorov-si" maintainers: - - "@Emiller88" + - "@edmundmiller" - "@sruthipsuresh" - "@drpatelh" - "@sidorov-si" diff --git a/modules/nf-core/bedtools/sort/meta.yml b/modules/nf-core/bedtools/sort/meta.yml index 9ad70b11..7c915f5f 100644 --- a/modules/nf-core/bedtools/sort/meta.yml +++ b/modules/nf-core/bedtools/sort/meta.yml @@ -41,13 +41,13 @@ output: description: File containing software versions pattern: "versions.yml" authors: - - "@Emiller88" + - "@edmundmiller" - "@sruthipsuresh" - "@drpatelh" - "@chris-cheshire" - "@adamrtalbot" maintainers: - - "@Emiller88" + - "@edmundmiller" - "@sruthipsuresh" - "@drpatelh" - "@chris-cheshire" diff --git a/modules/nf-core/bwa/index/tests/main.nf.test b/modules/nf-core/bwa/index/tests/main.nf.test index 5fc8d496..af33e73c 100644 --- a/modules/nf-core/bwa/index/tests/main.nf.test +++ b/modules/nf-core/bwa/index/tests/main.nf.test @@ -15,7 +15,7 @@ nextflow_process { """ input[0] = [ [id: 'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -29,5 +29,5 @@ nextflow_process { } } - + } diff --git a/modules/nf-core/cat/cat/main.nf b/modules/nf-core/cat/cat/main.nf index 970ab760..adbdbd7b 100644 --- a/modules/nf-core/cat/cat/main.nf +++ b/modules/nf-core/cat/cat/main.nf @@ -22,6 +22,8 @@ process CAT_CAT { def args2 = task.ext.args2 ?: '' def file_list = files_in.collect { it.toString() } + // choose appropriate concatenation tool depending on input and output format + // | input | output | command1 | command2 | // |-----------|------------|----------|----------| // | gzipped | gzipped | cat | | @@ -30,7 +32,7 @@ process CAT_CAT { // | ungzipped | gzipped | cat | pigz | // Use input file ending as default - prefix = task.ext.prefix ?: "${meta.id}${file_list[0].substring(file_list[0].lastIndexOf('.'))}" + prefix = task.ext.prefix ?: "${meta.id}${getFileSuffix(file_list[0])}" out_zip = prefix.endsWith('.gz') in_zip = file_list[0].endsWith('.gz') command1 = (in_zip && !out_zip) ? 'zcat' : 'cat' @@ -68,3 +70,10 @@ process CAT_CAT { END_VERSIONS """ } + +// for .gz files also include the second to last extension if it is present. E.g., .fasta.gz +def getFileSuffix(filename) { + def match = filename =~ /^.*?((\.\w{1,5})?(\.\w{1,5}\.gz$))/ + return match ? match[0][1] : filename.substring(filename.lastIndexOf('.')) +} + diff --git a/modules/nf-core/cat/cat/tests/main.nf.test b/modules/nf-core/cat/cat/tests/main.nf.test index ed5a4f12..fcee2d19 100644 --- a/modules/nf-core/cat/cat/tests/main.nf.test +++ b/modules/nf-core/cat/cat/tests/main.nf.test @@ -19,8 +19,8 @@ nextflow_process { [ [ id:'genome', single_end:true ], [ - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true), - file(params.test_data['sarscov2']['genome']['genome_sizes'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.sizes', checkIfExists: true) ] ] """ @@ -45,8 +45,8 @@ nextflow_process { [ [ id:'test', single_end:true ], [ - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true), - file(params.test_data['sarscov2']['genome']['genome_sizes'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.sizes', checkIfExists: true) ] ] """ @@ -72,8 +72,8 @@ nextflow_process { [ [ id:'test', single_end:true ], [ - file(params.test_data['sarscov2']['genome']['genome_gff3_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['genome']['contigs_genome_maf_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gff3.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/alignment/last/contigs.genome.maf.gz', checkIfExists: true) ] ] """ @@ -102,8 +102,8 @@ nextflow_process { [ [ id:'test', single_end:true ], [ - file(params.test_data['sarscov2']['genome']['genome_gff3_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['genome']['contigs_genome_maf_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gff3.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/alignment/last/contigs.genome.maf.gz', checkIfExists: true) ] ] """ @@ -131,8 +131,8 @@ nextflow_process { [ [ id:'test', single_end:true ], [ - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true), - file(params.test_data['sarscov2']['genome']['genome_sizes'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.sizes', checkIfExists: true) ] ] """ @@ -160,7 +160,7 @@ nextflow_process { [ [ id:'test', single_end:true ], [ - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] ] """ @@ -176,4 +176,3 @@ nextflow_process { } } } - diff --git a/modules/nf-core/cat/fastq/environment.yml b/modules/nf-core/cat/fastq/environment.yml index bff93add..8c69b121 100644 --- a/modules/nf-core/cat/fastq/environment.yml +++ b/modules/nf-core/cat/fastq/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - conda-forge::sed=4.7 + - conda-forge::coreutils=8.30 diff --git a/modules/nf-core/cat/fastq/main.nf b/modules/nf-core/cat/fastq/main.nf index 3d963784..f132b2ad 100644 --- a/modules/nf-core/cat/fastq/main.nf +++ b/modules/nf-core/cat/fastq/main.nf @@ -76,5 +76,4 @@ process CAT_FASTQ { """ } } - } diff --git a/modules/nf-core/cat/fastq/tests/main.nf.test b/modules/nf-core/cat/fastq/tests/main.nf.test index f5f94182..dab2e14c 100644 --- a/modules/nf-core/cat/fastq/tests/main.nf.test +++ b/modules/nf-core/cat/fastq/tests/main.nf.test @@ -16,11 +16,11 @@ nextflow_process { } process { """ - input[0] = [ - [ id:'test', single_end:true ], // meta map - [ file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test2_1_fastq_gz'], checkIfExists: true) ] - ] + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)] + ]) """ } } @@ -28,8 +28,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.reads).match() }, - { assert path(process.out.versions.get(0)).getText().contains("cat") } + { assert snapshot(process.out).match() } ) } } @@ -42,13 +41,13 @@ nextflow_process { } process { """ - input[0] = [ + input[0] = Channel.of([ [ id:'test', single_end:false ], // meta map - [ file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test2_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test2_2_fastq_gz'], checkIfExists: true) ] - ] + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true)] + ]) """ } } @@ -56,8 +55,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.reads).match() }, - { assert path(process.out.versions.get(0)).getText().contains("cat") } + { assert snapshot(process.out).match() } ) } } @@ -70,11 +68,11 @@ nextflow_process { } process { """ - input[0] = [ + input[0] = Channel.of([ [ id:'test', single_end:true ], // meta map - [ file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] - ] + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)] + ]) """ } } @@ -82,8 +80,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.reads).match() }, - { assert path(process.out.versions.get(0)).getText().contains("cat") } + { assert snapshot(process.out).match() } ) } } @@ -96,13 +93,13 @@ nextflow_process { } process { """ - input[0] = [ + input[0] = Channel.of([ [ id:'test', single_end:false ], // meta map - [ file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) ] - ] + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)] + ]) """ } } @@ -110,8 +107,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.reads).match() }, - { assert path(process.out.versions.get(0)).getText().contains("cat") } + { assert snapshot(process.out).match() } ) } } @@ -124,10 +120,10 @@ nextflow_process { } process { """ - input[0] = [ + input[0] = Channel.of([ [ id:'test', single_end:true ], // meta map - [ file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true)] - ] + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)] + ]) """ } } @@ -135,8 +131,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.reads).match() }, - { assert path(process.out.versions.get(0)).getText().contains("cat") } + { assert snapshot(process.out).match() } ) } } diff --git a/modules/nf-core/cat/fastq/tests/main.nf.test.snap b/modules/nf-core/cat/fastq/tests/main.nf.test.snap index 7f44e3e0..43dfe28f 100644 --- a/modules/nf-core/cat/fastq/tests/main.nf.test.snap +++ b/modules/nf-core/cat/fastq/tests/main.nf.test.snap @@ -1,78 +1,169 @@ { "test_cat_fastq_single_end": { "content": [ - [ - [ - { - "id": "test", - "single_end": true - }, - "test.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22" + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,ee314a9bd568d06617171b0c85f508da" + ] + ], + "1": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,ee314a9bd568d06617171b0c85f508da" + ] + ], + "versions": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" ] - ] + } ], - "timestamp": "2024-01-12T14:02:54.278243" + "timestamp": "2024-01-17T17:30:39.816981" }, "test_cat_fastq_single_end_same_name": { "content": [ - [ - [ - { - "id": "test", - "single_end": true - }, - "test.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22" + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22" + ] + ], + "1": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22" + ] + ], + "versions": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" ] - ] + } ], - "timestamp": "2024-01-12T14:03:01.765432" + "timestamp": "2024-01-17T17:32:35.229332" }, "test_cat_fastq_single_end_single_file": { "content": [ - [ - [ - { - "id": "test", - "single_end": true - }, - "test.merged.fastq.gz:md5,4161df271f9bfcd25d5845a1e220dbec" + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "1": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "versions": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" ] - ] + } ], - "timestamp": "2024-01-12T14:03:08.858654" + "timestamp": "2024-01-17T17:34:00.058829" }, "test_cat_fastq_paired_end_same_name": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, + { + "0": [ [ - "test_1.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22", - "test_2.merged.fastq.gz:md5,a52cab0b840c7178b0ea83df1fdbe8d5" + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22", + "test_2.merged.fastq.gz:md5,a52cab0b840c7178b0ea83df1fdbe8d5" + ] ] + ], + "1": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ], + "reads": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22", + "test_2.merged.fastq.gz:md5,a52cab0b840c7178b0ea83df1fdbe8d5" + ] + ] + ], + "versions": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" ] - ] + } ], - "timestamp": "2024-01-12T14:03:05.494631" + "timestamp": "2024-01-17T17:33:33.031555" }, "test_cat_fastq_paired_end": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22", + "test_2.merged.fastq.gz:md5,a52cab0b840c7178b0ea83df1fdbe8d5" + ] + ] + ], + "1": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ], + "reads": [ [ - "test_1.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22", - "test_2.merged.fastq.gz:md5,a52cab0b840c7178b0ea83df1fdbe8d5" + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22", + "test_2.merged.fastq.gz:md5,a52cab0b840c7178b0ea83df1fdbe8d5" + ] ] + ], + "versions": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" ] - ] + } ], - "timestamp": "2024-01-12T14:02:58.35062" + "timestamp": "2024-01-17T17:32:02.270935" } } \ No newline at end of file diff --git a/modules/nf-core/custom/dumpsoftwareversions/environment.yml b/modules/nf-core/custom/dumpsoftwareversions/environment.yml index 9b3272bc..b48ced26 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/environment.yml +++ b/modules/nf-core/custom/dumpsoftwareversions/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - bioconda::multiqc=1.19 + - bioconda::multiqc=1.20 diff --git a/modules/nf-core/custom/dumpsoftwareversions/main.nf b/modules/nf-core/custom/dumpsoftwareversions/main.nf index f2187611..105f9265 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/main.nf +++ b/modules/nf-core/custom/dumpsoftwareversions/main.nf @@ -4,8 +4,8 @@ process CUSTOM_DUMPSOFTWAREVERSIONS { // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.19--pyhdfd78af_0' : - 'biocontainers/multiqc:1.19--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.20--pyhdfd78af_0' : + 'biocontainers/multiqc:1.20--pyhdfd78af_0' }" input: path versions diff --git a/modules/nf-core/hisat2/align/tests/main.nf.test b/modules/nf-core/hisat2/align/tests/main.nf.test index 79e137c9..3a520e9a 100644 --- a/modules/nf-core/hisat2/align/tests/main.nf.test +++ b/modules/nf-core/hisat2/align/tests/main.nf.test @@ -7,6 +7,8 @@ nextflow_process { tag "modules_nfcore" tag "hisat2" tag "hisat2/align" + tag "hisat2/build" + tag "hisat2/extractsplicesites" test("Single-End") { @@ -15,26 +17,28 @@ nextflow_process { script "../../extractsplicesites/main.nf" process { """ - input[0] = [ [id:'genome'], - file(params.test_data['sarscov2']['genome']['genome_gtf'], checkIfExists: true) - ] + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ]) """ - } + } } run("HISAT2_BUILD") { script "../../build/main.nf" process { """ - input[0] = [ [id:'genome'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) - ] - input[1] = [ [id:'genome'], - file(params.test_data['sarscov2']['genome']['genome_gtf'], checkIfExists: true) - ] + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + input[1] = Channel.of([ [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ]) input[2] = HISAT2_EXTRACTSPLICESITES.out.txt """ - } + } } } @@ -44,12 +48,10 @@ nextflow_process { } process { """ - input[0] = [ - [ id:'test', single_end:true ], // meta map - [ - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) - ] - ] + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)] + ]) input[1] = HISAT2_BUILD.out.index input[2] = HISAT2_EXTRACTSPLICESITES.out.txt """ @@ -58,10 +60,10 @@ nextflow_process { then { assertAll( - { assert process.success }, - { assert snapshot(process.out.summary).match("se_summary") }, - { assert snapshot(process.out.fastq).match("se_fastq") }, - { assert snapshot(process.out.versions).match("se_versions") } + { assert process.success }, + { assert snapshot(process.out.summary).match("se_summary") }, + { assert snapshot(process.out.fastq).match("se_fastq") }, + { assert snapshot(process.out.versions).match("se_versions") } ) } } @@ -73,26 +75,28 @@ nextflow_process { script "../../extractsplicesites/main.nf" process { """ - input[0] = [ [id:'genome'], - file(params.test_data['sarscov2']['genome']['genome_gtf'], checkIfExists: true) - ] + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ]) """ - } + } } run("HISAT2_BUILD") { script "../../build/main.nf" process { """ - input[0] = [ [id:'genome'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) - ] - input[1] = [ [id:'genome'], - file(params.test_data['sarscov2']['genome']['genome_gtf'], checkIfExists: true) - ] + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + input[1] = Channel.of([ [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ]) input[2] = HISAT2_EXTRACTSPLICESITES.out.txt """ - } + } } } @@ -102,13 +106,11 @@ nextflow_process { } process { """ - input[0] = [ - [ id:'test', single_end:false ], // meta map - [ - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) - ] - ] + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] + ]) input[1] = HISAT2_BUILD.out.index input[2] = HISAT2_EXTRACTSPLICESITES.out.txt """ @@ -117,10 +119,10 @@ nextflow_process { then { assertAll( - { assert process.success }, - { assert snapshot(process.out.summary).match("pe_summary") }, - { assert snapshot(process.out.fastq).match("pe_fastq") }, - { assert snapshot(process.out.versions).match("pe_versions") } + { assert process.success }, + { assert snapshot(process.out.summary).match("pe_summary") }, + { assert snapshot(process.out.fastq).match("pe_fastq") }, + { assert snapshot(process.out.versions).match("pe_versions") } ) } } @@ -132,13 +134,14 @@ nextflow_process { script "../../build/main.nf" process { """ - input[0] = [ [id:'genome'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) - ] + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) input[1] = [[:],[]] input[2] = [[:],[]] """ - } + } } } @@ -148,12 +151,10 @@ nextflow_process { } process { """ - input[0] = [ - [ id:'test', single_end:true ], // meta map - [ - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) - ] - ] + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] + ]) input[1] = HISAT2_BUILD.out.index input[2] = [[:],[]] """ @@ -162,10 +163,10 @@ nextflow_process { then { assertAll( - { assert process.success }, - { assert snapshot(process.out.summary).match("se_no_ss_summary") }, - { assert snapshot(process.out.fastq).match("se_no_ss_fastq") }, - { assert snapshot(process.out.versions).match("se_no_ss_versions") } + { assert process.success }, + { assert snapshot(process.out.summary).match("se_no_ss_summary") }, + { assert snapshot(process.out.fastq).match("se_no_ss_fastq") }, + { assert snapshot(process.out.versions).match("se_no_ss_versions") } ) } } @@ -177,13 +178,14 @@ nextflow_process { script "../../build/main.nf" process { """ - input[0] = [ [id:'genome'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) - ] + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) input[1] = [[:],[]] input[2] = [[:],[]] """ - } + } } } @@ -193,13 +195,11 @@ nextflow_process { } process { """ - input[0] = [ - [ id:'test', single_end:false ], // meta map - [ - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) - ] - ] + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] + ]) input[1] = HISAT2_BUILD.out.index input[2] = [[:],[]] """ @@ -208,10 +208,10 @@ nextflow_process { then { assertAll( - { assert process.success }, - { assert snapshot(process.out.summary).match("pe_no_ss_summary") }, - { assert snapshot(process.out.fastq).match("pe_no_ss_fastq") }, - { assert snapshot(process.out.versions).match("pe_no_ss_versions") } + { assert process.success }, + { assert snapshot(process.out.summary).match("pe_no_ss_summary") }, + { assert snapshot(process.out.fastq).match("pe_no_ss_fastq") }, + { assert snapshot(process.out.versions).match("pe_no_ss_versions") } ) } } diff --git a/modules/nf-core/hisat2/build/tests/main.nf.test b/modules/nf-core/hisat2/build/tests/main.nf.test index c5fc1763..5b31debc 100644 --- a/modules/nf-core/hisat2/build/tests/main.nf.test +++ b/modules/nf-core/hisat2/build/tests/main.nf.test @@ -7,6 +7,7 @@ nextflow_process { tag "modules_nfcore" tag "hisat2" tag "hisat2/build" + tag "hisat2/extractsplicesites" test("Should run without failures") { @@ -15,11 +16,12 @@ nextflow_process { script "../../extractsplicesites/main.nf" process { """ - input[0] = [ [id:'genome'], - file(params.test_data['sarscov2']['genome']['genome_gtf'], checkIfExists: true) - ] + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ]) """ - } + } } } @@ -29,12 +31,13 @@ nextflow_process { } process { """ - input[0] = [ [id:'genome'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) - ] - input[1] = [ [id:'genome'], - file(params.test_data['sarscov2']['genome']['genome_gtf'], checkIfExists: true) - ] + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + input[1] = Channel.of([ [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ]) input[2] = HISAT2_EXTRACTSPLICESITES.out.txt """ } @@ -42,11 +45,9 @@ nextflow_process { then { assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert process.success }, + { assert snapshot(process.out).match() } ) } - } - } diff --git a/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test b/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test index a7a22e9b..72eb6d53 100644 --- a/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test +++ b/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test @@ -16,20 +16,20 @@ nextflow_process { } process { """ - input[0] = [ [id:'test'], - file(params.test_data['sarscov2']['genome']['genome_gtf'], checkIfExists: true) - ] + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ]) """ } } then { assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert process.success }, + { assert path("${process.out.txt[0][1]}").exists() }, + { assert snapshot(process.out.versions).match() } ) } - } - } diff --git a/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test.snap b/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test.snap index 3cef6905..17f1c8eb 100644 --- a/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test.snap +++ b/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test.snap @@ -1,31 +1,10 @@ { "Should run without failures": { "content": [ - { - "0": [ - [ - { - "id": "test" - }, - "genome.splice_sites.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - "versions.yml:md5,eeea7231fe197810659b8bad4133aff2" - ], - "txt": [ - [ - { - "id": "test" - }, - "genome.splice_sites.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,eeea7231fe197810659b8bad4133aff2" - ] - } + [ + "versions.yml:md5,eeea7231fe197810659b8bad4133aff2" + ] ], - "timestamp": "2023-10-16T14:25:01.248332036" + "timestamp": "2024-01-18T20:56:30.71763" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/flagstat/environment.yml b/modules/nf-core/samtools/flagstat/environment.yml index 5efae053..bd57cb54 100644 --- a/modules/nf-core/samtools/flagstat/environment.yml +++ b/modules/nf-core/samtools/flagstat/environment.yml @@ -4,4 +4,5 @@ channels: - bioconda - defaults dependencies: - - bioconda::samtools=1.18 + - bioconda::samtools=1.19.2 + - bioconda::htslib=1.19.1 diff --git a/modules/nf-core/samtools/flagstat/main.nf b/modules/nf-core/samtools/flagstat/main.nf index f1893d7c..eb5f5252 100644 --- a/modules/nf-core/samtools/flagstat/main.nf +++ b/modules/nf-core/samtools/flagstat/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_FLAGSTAT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.18--h50ea8bc_1' : - 'biocontainers/samtools:1.18--h50ea8bc_1' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.19.2--h50ea8bc_0' : + 'biocontainers/samtools:1.19.2--h50ea8bc_0' }" input: tuple val(meta), path(bam), path(bai) diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test b/modules/nf-core/samtools/flagstat/tests/main.nf.test index c8dd8dc9..24c3c04b 100644 --- a/modules/nf-core/samtools/flagstat/tests/main.nf.test +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test @@ -16,11 +16,11 @@ nextflow_process { } process { """ - input[0] = [ + input[0] = Channel.of([ [ id:'test', single_end:false ], // meta map - file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam_bai'], checkIfExists: true) - ] + 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) + ]) """ } } @@ -28,8 +28,8 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out.flagstat).match() }, - { assert path(process.out.versions.get(0)).getText().contains("samtools") } + { assert snapshot(process.out.flagstat).match("flagstat") }, + { assert snapshot(process.out.versions).match("versions") } ) } } diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap index 880019f2..a76fc27e 100644 --- a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap @@ -1,5 +1,5 @@ { - "BAM": { + "flagstat": { "content": [ [ [ @@ -11,6 +11,22 @@ ] ] ], - "timestamp": "2023-11-14T15:49:22.577133" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T18:31:37.783927" + }, + "versions": { + "content": [ + [ + "versions.yml:md5,fd0030ce49ab3a92091ad80260226452" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:11:44.299617452" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/idxstats/environment.yml b/modules/nf-core/samtools/idxstats/environment.yml index 2401db0f..174973b8 100644 --- a/modules/nf-core/samtools/idxstats/environment.yml +++ b/modules/nf-core/samtools/idxstats/environment.yml @@ -4,4 +4,5 @@ channels: - bioconda - defaults dependencies: - - bioconda::samtools=1.18 + - bioconda::samtools=1.19.2 + - bioconda::htslib=1.19.1 diff --git a/modules/nf-core/samtools/idxstats/main.nf b/modules/nf-core/samtools/idxstats/main.nf index 00d916bb..a544026f 100644 --- a/modules/nf-core/samtools/idxstats/main.nf +++ b/modules/nf-core/samtools/idxstats/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_IDXSTATS { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.18--h50ea8bc_1' : - 'biocontainers/samtools:1.18--h50ea8bc_1' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.19.2--h50ea8bc_0' : + 'biocontainers/samtools:1.19.2--h50ea8bc_0' }" input: tuple val(meta), path(bam), path(bai) diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test b/modules/nf-core/samtools/idxstats/tests/main.nf.test index f6c92150..a2dcb27c 100644 --- a/modules/nf-core/samtools/idxstats/tests/main.nf.test +++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test @@ -8,7 +8,7 @@ nextflow_process { tag "samtools" tag "samtools/idxstats" - test("BAM") { + test("bam") { when { params { @@ -16,11 +16,11 @@ nextflow_process { } process { """ - input[0] = [ + input[0] = Channel.of([ [ id:'test', single_end:false ], // meta map - file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam_bai'], checkIfExists: true) - ] + 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) + ]) """ } } @@ -28,8 +28,8 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out.idxstats).match() }, - { assert path(process.out.versions.get(0)).getText().contains("samtools") } + { assert snapshot(process.out.idxstats).match("idxstats") }, + { assert snapshot(process.out.versions).match("versions") } ) } } diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap index 4c6c12bd..a7050bdc 100644 --- a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap @@ -1,5 +1,17 @@ { - "BAM": { + "versions": { + "content": [ + [ + "versions.yml:md5,613dde56f108418039ffcdeeddba397a" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:16:50.147462763" + }, + "idxstats": { "content": [ [ [ @@ -11,6 +23,10 @@ ] ] ], - "timestamp": "2023-11-14T15:52:19.875194" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T18:36:41.561026" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/index/environment.yml b/modules/nf-core/samtools/index/environment.yml index 296ed99e..a5e50649 100644 --- a/modules/nf-core/samtools/index/environment.yml +++ b/modules/nf-core/samtools/index/environment.yml @@ -4,4 +4,5 @@ channels: - bioconda - defaults dependencies: - - bioconda::samtools=1.18 + - bioconda::samtools=1.19.2 + - bioconda::htslib=1.19.1 diff --git a/modules/nf-core/samtools/index/main.nf b/modules/nf-core/samtools/index/main.nf index 8ad18fdc..dc14f98d 100644 --- a/modules/nf-core/samtools/index/main.nf +++ b/modules/nf-core/samtools/index/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_INDEX { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.18--h50ea8bc_1' : - 'biocontainers/samtools:1.18--h50ea8bc_1' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.19.2--h50ea8bc_0' : + 'biocontainers/samtools:1.19.2--h50ea8bc_0' }" input: tuple val(meta), path(input) diff --git a/modules/nf-core/samtools/index/tests/main.nf.test b/modules/nf-core/samtools/index/tests/main.nf.test index c76a9169..bb7756d1 100644 --- a/modules/nf-core/samtools/index/tests/main.nf.test +++ b/modules/nf-core/samtools/index/tests/main.nf.test @@ -8,7 +8,7 @@ nextflow_process { tag "samtools" tag "samtools/index" - test("sarscov2 [BAI]") { + test("bai") { when { params { @@ -16,10 +16,10 @@ nextflow_process { } process { """ - input[0] = [ - [ id:'test' ], // meta map - file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) - ] + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) + ]) """ } } @@ -28,12 +28,12 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot(process.out.bai).match("bai") }, - { assert path(process.out.versions.get(0)).getText().contains("samtools") } + { assert snapshot(process.out.versions).match("bai_versions") } ) } } - test("homo_sapiens [CRAI]") { + test("crai") { when { params { @@ -41,10 +41,10 @@ nextflow_process { } process { """ - input[0] = [ - [ id:'test' ], // meta map - file(params.test_data['homo_sapiens']['illumina']['test_paired_end_recalibrated_sorted_cram'], checkIfExists: true) - ] + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram', checkIfExists: true) + ]) """ } } @@ -53,12 +53,12 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot(process.out.crai).match("crai") }, - { assert path(process.out.versions.get(0)).getText().contains("samtools") } + { assert snapshot(process.out.versions).match("crai_versions") } ) } } - test("homo_sapiens [CSI]") { + test("csi") { config "./csi.nextflow.config" @@ -68,10 +68,10 @@ nextflow_process { } process { """ - input[0] = [ - [ id:'test' ], // meta map - file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) - ] + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) + ]) """ } } @@ -80,7 +80,7 @@ nextflow_process { assertAll ( { assert process.success }, { assert path(process.out.csi.get(0).get(1)).exists() }, - { assert path(process.out.versions.get(0)).getText().contains("samtools") } + { assert snapshot(process.out.versions).match("csi_versions") } ) } } diff --git a/modules/nf-core/samtools/index/tests/main.nf.test.snap b/modules/nf-core/samtools/index/tests/main.nf.test.snap index b3baee7f..3dc8e7de 100644 --- a/modules/nf-core/samtools/index/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/index/tests/main.nf.test.snap @@ -1,28 +1,74 @@ { + "crai_versions": { + "content": [ + [ + "versions.yml:md5,cc4370091670b64bba7c7206403ffb3e" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:12:00.324667957" + }, + "csi_versions": { + "content": [ + [ + "versions.yml:md5,cc4370091670b64bba7c7206403ffb3e" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:12:07.885103162" + }, "crai": { "content": [ [ [ { - "id": "test" + "id": "test", + "single_end": false }, "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" ] ] ], - "timestamp": "2023-11-15T15:17:37.30801" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T18:41:38.446424" }, "bai": { "content": [ [ [ { - "id": "test" + "id": "test", + "single_end": false }, "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" ] ] ], - "timestamp": "2023-11-15T15:17:30.869234" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T18:40:46.579747" + }, + "bai_versions": { + "content": [ + [ + "versions.yml:md5,cc4370091670b64bba7c7206403ffb3e" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:11:51.641425452" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/sort/environment.yml b/modules/nf-core/samtools/sort/environment.yml index cd50868c..4d898e48 100644 --- a/modules/nf-core/samtools/sort/environment.yml +++ b/modules/nf-core/samtools/sort/environment.yml @@ -4,4 +4,5 @@ channels: - bioconda - defaults dependencies: - - bioconda::samtools=1.18 + - bioconda::samtools=1.19.2 + - bioconda::htslib=1.19.1 diff --git a/modules/nf-core/samtools/sort/main.nf b/modules/nf-core/samtools/sort/main.nf index 4a666d42..fc374f98 100644 --- a/modules/nf-core/samtools/sort/main.nf +++ b/modules/nf-core/samtools/sort/main.nf @@ -4,15 +4,18 @@ process SAMTOOLS_SORT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.18--h50ea8bc_1' : - 'biocontainers/samtools:1.18--h50ea8bc_1' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.19.2--h50ea8bc_0' : + 'biocontainers/samtools:1.19.2--h50ea8bc_0' }" input: - tuple val(meta), path(bam) + tuple val(meta) , path(bam) + tuple val(meta2), path(fasta) output: - tuple val(meta), path("*.bam"), emit: bam - tuple val(meta), path("*.csi"), emit: csi, optional: true + tuple val(meta), path("*.bam"), emit: bam, optional: true + tuple val(meta), path("*.cram"), emit: cram, optional: true + tuple val(meta), path("*.crai"), emit: crai, optional: true + tuple val(meta), path("*.csi"), emit: csi, optional: true path "versions.yml" , emit: versions when: @@ -21,14 +24,24 @@ process SAMTOOLS_SORT { script: def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" + def extension = args.contains("--output-fmt sam") ? "sam" : + args.contains("--output-fmt cram") ? "cram" : + "bam" + def reference = fasta ? "--reference ${fasta}" : "" if ("$bam" == "${prefix}.bam") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" + """ + samtools cat \\ + --threads $task.cpus \\ + ${bam} \\ + | \\ samtools sort \\ $args \\ - -@ $task.cpus \\ - -o ${prefix}.bam \\ - -T $prefix \\ - $bam + -T ${prefix} \\ + --threads $task.cpus \\ + ${reference} \\ + -o ${prefix}.${extension} \\ + - cat <<-END_VERSIONS > versions.yml "${task.process}": @@ -40,6 +53,7 @@ process SAMTOOLS_SORT { def prefix = task.ext.prefix ?: "${meta.id}" """ touch ${prefix}.bam + touch ${prefix}.bam.csi cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/samtools/sort/meta.yml b/modules/nf-core/samtools/sort/meta.yml index 2200de72..341a7d0e 100644 --- a/modules/nf-core/samtools/sort/meta.yml +++ b/modules/nf-core/samtools/sort/meta.yml @@ -23,8 +23,18 @@ input: e.g. [ id:'test', single_end:false ] - bam: type: file - description: BAM/CRAM/SAM file + description: BAM/CRAM/SAM file(s) pattern: "*.{bam,cram,sam}" + - meta2: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'genome' ] + - fasta: + type: file + description: Reference genome FASTA file + pattern: "*.{fa,fasta,fna}" + optional: true output: - meta: type: map @@ -33,19 +43,29 @@ output: e.g. [ id:'test', single_end:false ] - bam: type: file - description: Sorted BAM/CRAM/SAM file - pattern: "*.{bam,cram,sam}" - - versions: + description: Sorted BAM file + pattern: "*.{bam}" + - cram: type: file - description: File containing software versions - pattern: "versions.yml" + description: Sorted CRAM file + pattern: "*.{cram}" + - crai: + type: file + description: CRAM index file (optional) + pattern: "*.crai" - csi: type: file description: BAM index file (optional) pattern: "*.csi" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" authors: - "@drpatelh" - "@ewels" + - "@matthdsm" maintainers: - "@drpatelh" - "@ewels" + - "@matthdsm" diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test b/modules/nf-core/samtools/sort/tests/main.nf.test index abb80978..8360e2b1 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test +++ b/modules/nf-core/samtools/sort/tests/main.nf.test @@ -8,22 +8,21 @@ nextflow_process { tag "samtools" tag "samtools/sort" - test("test_samtools_sort") { + test("bam") { config "./nextflow.config" when { - params { - outdir = "$outputDir" - } process { """ - input[0] = [ - [ id:'test', single_end:false ], - [ - file(params.test_data['sarscov2']['illumina']['test_paired_end_bam'], checkIfExists: true) - ] - ] + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true) + ]) + input[1] = Channel.of([ + [ id:'fasta' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) """ } } @@ -34,13 +33,39 @@ nextflow_process { { assert snapshot(process.out).match() } ) } + } + + test("cram") { + + config "./nextflow.config" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true) + ]) + input[1] = Channel.of([ + [ id:'fasta' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + """ + } + } + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } } - test("test_samtools_sort_stub") { + test("bam_stub") { config "./nextflow.config" - options "-stub-run" + options "-stub" when { params { @@ -48,12 +73,14 @@ nextflow_process { } process { """ - input[0] = [ - [ id:'test', single_end:false ], - [ - file(params.test_data['sarscov2']['illumina']['test_paired_end_bam'], checkIfExists: true) - ] - ] + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true) + ]) + input[1] = Channel.of([ + [ id:'fasta' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) """ } } @@ -61,13 +88,9 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot( - file(process.out.bam[0][1]).name, - process.out.versions - ).match() } + { assert snapshot(file(process.out.bam[0][1]).name).match("bam_stub_bam") }, + { assert snapshot(process.out.versions).match("bam_stub_versions") } ) } - } - } diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test.snap b/modules/nf-core/samtools/sort/tests/main.nf.test.snap index ff722259..38477656 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/sort/tests/main.nf.test.snap @@ -1,5 +1,5 @@ { - "test_samtools_sort": { + "cram": { "content": [ { "0": [ @@ -8,14 +8,26 @@ "id": "test", "single_end": false }, - "test.sorted.bam:md5,ea6a0fef94eb534e901f107a05a33a06" + "test.sorted.bam:md5,bc0b7c25da26384a006ed84cc9e4da23" ] ], "1": [ ], "2": [ - "versions.yml:md5,33b6a403dc19a0d28e4219ccab0a1d80" + + ], + "3": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.csi:md5,8d4e836c2fed6c0bf874d5e8cdba5831" + ] + ], + "4": [ + "versions.yml:md5,e6d43fefc9a8bff91c2ce6e3a1716eca" ], "bam": [ [ @@ -23,26 +35,120 @@ "id": "test", "single_end": false }, - "test.sorted.bam:md5,ea6a0fef94eb534e901f107a05a33a06" + "test.sorted.bam:md5,bc0b7c25da26384a006ed84cc9e4da23" ] ], - "csi": [ + "crai": [ + + ], + "cram": [ + ], + "csi": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.csi:md5,8d4e836c2fed6c0bf874d5e8cdba5831" + ] ], "versions": [ - "versions.yml:md5,33b6a403dc19a0d28e4219ccab0a1d80" + "versions.yml:md5,e6d43fefc9a8bff91c2ce6e3a1716eca" ] } ], - "timestamp": "2023-12-04T11:11:22.005628301" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-04T15:08:00.830294" + }, + "bam_stub_bam": { + "content": [ + "test.sorted.bam" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:21:04.364044" }, - "test_samtools_sort_stub": { + "bam_stub_versions": { "content": [ - "test.sorted.bam", [ - "versions.yml:md5,33b6a403dc19a0d28e4219ccab0a1d80" + "versions.yml:md5,e6d43fefc9a8bff91c2ce6e3a1716eca" ] ], - "timestamp": "2023-12-04T17:47:22.314445935" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:15:00.20800281" + }, + "bam": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,bc0b7c25da26384a006ed84cc9e4da23" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.csi:md5,8d4e836c2fed6c0bf874d5e8cdba5831" + ] + ], + "4": [ + "versions.yml:md5,e6d43fefc9a8bff91c2ce6e3a1716eca" + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,bc0b7c25da26384a006ed84cc9e4da23" + ] + ], + "crai": [ + + ], + "cram": [ + + ], + "csi": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.csi:md5,8d4e836c2fed6c0bf874d5e8cdba5831" + ] + ], + "versions": [ + "versions.yml:md5,e6d43fefc9a8bff91c2ce6e3a1716eca" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-04T15:07:48.773803" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/sort/tests/nextflow.config b/modules/nf-core/samtools/sort/tests/nextflow.config index d0f35086..f642771f 100644 --- a/modules/nf-core/samtools/sort/tests/nextflow.config +++ b/modules/nf-core/samtools/sort/tests/nextflow.config @@ -1,7 +1,8 @@ process { withName: SAMTOOLS_SORT { - ext.prefix = { "${meta.id}.sorted" } + ext.prefix = { "${meta.id}.sorted" } + ext.args = "--write-index" } } diff --git a/modules/nf-core/samtools/stats/environment.yml b/modules/nf-core/samtools/stats/environment.yml index b89ce647..67bb0ca4 100644 --- a/modules/nf-core/samtools/stats/environment.yml +++ b/modules/nf-core/samtools/stats/environment.yml @@ -4,4 +4,5 @@ channels: - bioconda - defaults dependencies: - - bioconda::samtools=1.18 + - bioconda::samtools=1.19.2 + - bioconda::htslib=1.19.1 diff --git a/modules/nf-core/samtools/stats/main.nf b/modules/nf-core/samtools/stats/main.nf index 7539140a..52b00f4b 100644 --- a/modules/nf-core/samtools/stats/main.nf +++ b/modules/nf-core/samtools/stats/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_STATS { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.18--h50ea8bc_1' : - 'biocontainers/samtools:1.18--h50ea8bc_1' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.19.2--h50ea8bc_0' : + 'biocontainers/samtools:1.19.2--h50ea8bc_0' }" input: tuple val(meta), path(input), path(input_index) diff --git a/modules/nf-core/samtools/stats/tests/main.nf.test b/modules/nf-core/samtools/stats/tests/main.nf.test index 20c3efe1..e3d5cb14 100644 --- a/modules/nf-core/samtools/stats/tests/main.nf.test +++ b/modules/nf-core/samtools/stats/tests/main.nf.test @@ -8,71 +8,58 @@ nextflow_process { tag "samtools" tag "samtools/stats" - test("SAMTOOLS STATS Should run without failures") { + test("bam") { when { params { - outdir = "$outputDir" } process { """ - // define inputs of the process here. - input[0] = [ - [ id:'test', single_end:false ], // meta map - file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam_bai'], checkIfExists: true) - - ] + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + 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] = [[],[]] """ - } } then { assertAll( - {assert process.success}, - {assert snapshot(process.out).match()} + {assert process.success}, + {assert snapshot(process.out).match()} ) } - } - test("SAMTOOLS CRAM Should run without failures") { + test("cram") { when { params { - outdir = "$outputDir" } process { """ - // define inputs of the process here - input[0] = [ - [ id:'test', single_end:false ], // meta map - file(params.test_data['homo_sapiens']['illumina']['test_paired_end_recalibrated_sorted_cram'], checkIfExists: true), - file(params.test_data['homo_sapiens']['illumina']['test_paired_end_recalibrated_sorted_cram_crai'], checkIfExists: true) - - ] - input[1] = [ - [ id:'genome' ], - file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true) - ] + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram.crai', checkIfExists: true) + ]) + input[1] = Channel.of([ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) """ } - - } then { assertAll( - {assert process.success}, - {assert snapshot(process.out).match()} + {assert process.success}, + {assert snapshot(process.out).match()} ) } - } - - } diff --git a/modules/nf-core/samtools/stats/tests/main.nf.test.snap b/modules/nf-core/samtools/stats/tests/main.nf.test.snap index 025c83a5..1b7c9ba4 100644 --- a/modules/nf-core/samtools/stats/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/stats/tests/main.nf.test.snap @@ -1,5 +1,5 @@ { - "SAMTOOLS STATS Should run without failures": { + "cram": { "content": [ { "0": [ @@ -8,11 +8,11 @@ "id": "test", "single_end": false }, - "test.stats:md5,045a48208b1c6f5b8af4347fe31f4def" + "test.stats:md5,01812900aa4027532906c5d431114233" ] ], "1": [ - "versions.yml:md5,650a365c6635001436008350ae83337c" + "versions.yml:md5,0514ceb1769b2a88843e08c1f82624a9" ], "stats": [ [ @@ -20,17 +20,21 @@ "id": "test", "single_end": false }, - "test.stats:md5,045a48208b1c6f5b8af4347fe31f4def" + "test.stats:md5,01812900aa4027532906c5d431114233" ] ], "versions": [ - "versions.yml:md5,650a365c6635001436008350ae83337c" + "versions.yml:md5,0514ceb1769b2a88843e08c1f82624a9" ] } ], - "timestamp": "2023-12-04T11:07:28.26821485" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:15:25.562429714" }, - "SAMTOOLS CRAM Should run without failures": { + "bam": { "content": [ { "0": [ @@ -39,11 +43,11 @@ "id": "test", "single_end": false }, - "test.stats:md5,dfbfa130d4a6925ddd1931dcd8354a43" + "test.stats:md5,5d8681bf541199898c042bf400391d59" ] ], "1": [ - "versions.yml:md5,650a365c6635001436008350ae83337c" + "versions.yml:md5,0514ceb1769b2a88843e08c1f82624a9" ], "stats": [ [ @@ -51,14 +55,18 @@ "id": "test", "single_end": false }, - "test.stats:md5,dfbfa130d4a6925ddd1931dcd8354a43" + "test.stats:md5,5d8681bf541199898c042bf400391d59" ] ], "versions": [ - "versions.yml:md5,650a365c6635001436008350ae83337c" + "versions.yml:md5,0514ceb1769b2a88843e08c1f82624a9" ] } ], - "timestamp": "2023-12-04T11:07:50.356233402" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:15:07.857611509" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/view/environment.yml b/modules/nf-core/samtools/view/environment.yml index 99aa69d0..b0676f33 100644 --- a/modules/nf-core/samtools/view/environment.yml +++ b/modules/nf-core/samtools/view/environment.yml @@ -4,4 +4,5 @@ channels: - bioconda - defaults dependencies: - - bioconda::samtools=1.18 + - bioconda::samtools=1.19.2 + - bioconda::htslib=1.19.1 diff --git a/modules/nf-core/samtools/view/main.nf b/modules/nf-core/samtools/view/main.nf index 0b5a2912..5a8989d6 100644 --- a/modules/nf-core/samtools/view/main.nf +++ b/modules/nf-core/samtools/view/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_VIEW { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.18--h50ea8bc_1' : - 'biocontainers/samtools:1.18--h50ea8bc_1' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.19.2--h50ea8bc_0' : + 'biocontainers/samtools:1.19.2--h50ea8bc_0' }" input: tuple val(meta), path(input), path(index) diff --git a/modules/nf-core/samtools/view/tests/main.nf.test b/modules/nf-core/samtools/view/tests/main.nf.test index 89ed3555..45a0defb 100644 --- a/modules/nf-core/samtools/view/tests/main.nf.test +++ b/modules/nf-core/samtools/view/tests/main.nf.test @@ -9,16 +9,16 @@ nextflow_process { tag "samtools" tag "samtools/view" - test("sarscov2 - [bam, []], [], []") { + test("bam") { when { process { """ - input[0] = [ + input[0] = Channel.of([ [ id:'test', single_end:false ], // meta map - file(params.test_data['sarscov2']['illumina']['test_paired_end_bam'], checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true), [] - ] + ]) input[1] = [[],[]] input[2] = [] """ @@ -28,34 +28,31 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - file(process.out.bam[0][1]).name, - process.out.cram, - process.out.sam, - process.out.bai, - process.out.crai, - process.out.csi, - process.out.versions - ).match() } + { assert snapshot(file(process.out.bam[0][1]).name).match("bam_bam") }, + { assert snapshot(process.out.bai).match("bam_bai") }, + { assert snapshot(process.out.crai).match("bam_crai") }, + { assert snapshot(process.out.cram).match("bam_cram") }, + { assert snapshot(process.out.csi).match("bam_csi") }, + { assert snapshot(process.out.sam).match("bam_sam") }, + { assert snapshot(process.out.versions).match("bam_versions") } ) } - } - test("homo_sapiens - [cram, crai], fasta, []") { + test("cram") { when { process { """ - input[0] = [ - [ id: 'test' ], // meta map - file(params.test_data['homo_sapiens']['illumina']['test_paired_end_sorted_cram'], checkIfExists: true), - file(params.test_data['homo_sapiens']['illumina']['test_paired_end_sorted_cram_crai'], checkIfExists: true) - ] - input[1] = [ - [ id:'genome' ], - file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true) - ] + input[0] = Channel.of([ + [ id:'test', single_end:false ], // 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] = Channel.of([ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) input[2] = [] """ } @@ -64,36 +61,33 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - file(process.out.cram[0][1]).name, - process.out.bam, - process.out.sam, - process.out.bai, - process.out.crai, - process.out.csi, - process.out.versions - ).match() } + { assert snapshot(file(process.out.cram[0][1]).name).match("cram_cram") }, + { assert snapshot(process.out.bai).match("cram_bai") }, + { assert snapshot(process.out.bam).match("cram_bam") }, + { assert snapshot(process.out.crai).match("cram_crai") }, + { assert snapshot(process.out.csi).match("cram_csi") }, + { assert snapshot(process.out.sam).match("cram_sam") }, + { assert snapshot(process.out.versions).match("cram_versions") } ) } - } - test("homo_sapiens - [cram, []], fasta, [] - bam output") { + test("cram_to_bam") { config "./bam.config" when { process { """ - input[0] = [ - [ id: 'test' ], // meta map - file(params.test_data['homo_sapiens']['illumina']['test_paired_end_sorted_cram'], checkIfExists: true), + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true), [] - ] - input[1] = [ - [ id:'genome' ], - file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true) - ] + ]) + input[1] = Channel.of([ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) input[2] = [] """ } @@ -102,36 +96,33 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - file(process.out.bam[0][1]).name, - process.out.cram, - process.out.sam, - process.out.bai, - process.out.crai, - process.out.csi, - process.out.versions - ).match() } + { assert snapshot(file(process.out.bam[0][1]).name).match("cram_to_bam_bam") }, + { assert snapshot(process.out.bai).match("cram_to_bam_bai") }, + { assert snapshot(process.out.crai).match("cram_to_bam_crai") }, + { assert snapshot(process.out.cram).match("cram_to_bam_cram") }, + { assert snapshot(process.out.csi).match("cram_to_bam_csi") }, + { assert snapshot(process.out.sam).match("cram_to_bam_sam") }, + { assert snapshot(process.out.versions).match("cram_to_bam_versions") } ) } - } - test("homo_sapiens - [cram, []], fasta, [] - bam & index output") { + test("cram_to_bam_index") { config "./bam_index.config" when { process { """ - input[0] = [ - [ id: 'test' ], // meta map - file(params.test_data['homo_sapiens']['illumina']['test_paired_end_sorted_cram'], checkIfExists: true), + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true), [] - ] - input[1] = [ - [ id:'genome' ], - file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true) - ] + ]) + input[1] = Channel.of([ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) input[2] = [] """ } @@ -140,36 +131,33 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - file(process.out.bam[0][1]).name, - process.out.cram, - process.out.sam, - file(process.out.csi[0][1]).name, - process.out.crai, - process.out.bai, - process.out.versions - ).match() } + { assert snapshot(file(process.out.bam[0][1]).name).match("cram_to_bam_index_bam") }, + { assert snapshot(file(process.out.csi[0][1]).name).match("cram_to_bam_index_csi") }, + { assert snapshot(process.out.bai).match("cram_to_bam_index_bai") }, + { assert snapshot(process.out.crai).match("cram_to_bam_index_crai") }, + { assert snapshot(process.out.cram).match("cram_to_bam_index_cram") }, + { assert snapshot(process.out.sam).match("cram_to_bam_index_sam") }, + { assert snapshot(process.out.versions).match("cram_to_bam_index_versions") } ) } - } - test("homo_sapiens - [cram, []], fasta, qname - bam & index output") { + test("cram_to_bam_index_qname") { config "./bam_index.config" when { process { """ - input[0] = [ - [ id: 'test' ], // meta map - file(params.test_data['homo_sapiens']['illumina']['test_paired_end_sorted_cram'], checkIfExists: true), + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true), [] - ] - input[1] = [ - [ id:'genome' ], - file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true) - ] + ]) + input[1] = Channel.of([ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) input[2] = Channel.of("testN:2817", "testN:2814").collectFile(name: "readnames.list", newLine: true) """ } @@ -178,21 +166,18 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - file(process.out.bam[0][1]).name, - process.out.cram, - process.out.sam, - file(process.out.csi[0][1]).name, - process.out.crai, - process.out.bai, - process.out.versions - ).match() } + { assert snapshot(file(process.out.bam[0][1]).name).match("cram_to_bam_index_qname_bam") }, + { assert snapshot(file(process.out.csi[0][1]).name).match("cram_to_bam_index_qname_csi") }, + { assert snapshot(process.out.bai).match("cram_to_bam_index_qname_bai") }, + { assert snapshot(process.out.crai).match("cram_to_bam_index_qname_crai") }, + { assert snapshot(process.out.cram).match("cram_to_bam_index_qname_cram") }, + { assert snapshot(process.out.sam).match("cram_to_bam_index_qname_sam") }, + { assert snapshot(process.out.versions).match("cram_to_bam_index_qname_versions") } ) } - } - test("sarscov2 - [bam, []], [], [] - stub") { + test("bam_stub") { options "-stub" config "./bam_index.config" @@ -200,11 +185,11 @@ nextflow_process { when { process { """ - input[0] = [ + input[0] = Channel.of([ [ id:'test', single_end:false ], // meta map - file(params.test_data['sarscov2']['illumina']['test_paired_end_bam'], checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true), [] - ] + ]) input[1] = [[],[]] input[2] = [] """ @@ -214,18 +199,14 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - file(process.out.bam[0][1]).name, - process.out.cram, - process.out.sam, - file(process.out.csi[0][1]).name, - process.out.crai, - process.out.bai, - process.out.versions - ).match() } + { assert snapshot(file(process.out.bam[0][1]).name).match("bam_stub_bam") }, + { assert snapshot(file(process.out.csi[0][1]).name).match("bam_stub_csi") }, + { assert snapshot(process.out.bai).match("bam_stub_bai") }, + { assert snapshot(process.out.crai).match("bam_stub_crai") }, + { assert snapshot(process.out.cram).match("bam_stub_cram") }, + { assert snapshot(process.out.sam).match("bam_stub_sam") }, + { assert snapshot(process.out.versions).match("bam_stub_versions") } ) } - } - } diff --git a/modules/nf-core/samtools/view/tests/main.nf.test.snap b/modules/nf-core/samtools/view/tests/main.nf.test.snap index 83427491..f55943a7 100644 --- a/modules/nf-core/samtools/view/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/view/tests/main.nf.test.snap @@ -1,140 +1,488 @@ { - "homo_sapiens - [cram, []], fasta, [] - bam output": { + "bam_bam": { + "content": [ + "test.bam" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:37:51.256068" + }, + "cram_to_bam_index_csi": { + "content": [ + "test.bam.csi" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:12.958617" + }, + "bam_stub_bam": { + "content": [ + "test.bam" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:32.065301" + }, + "bam_bai": { "content": [ - "test.bam", [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:37:51.258578" + }, + "bam_stub_bai": { + "content": [ [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:32.071284" + }, + "bam_stub_versions": { + "content": [ [ - - ], + "versions.yml:md5,4ea32c57d546102a1b32d9693ada7cf1" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:13:09.713353823" + }, + "cram_to_bam_index_cram": { + "content": [ [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:12.972288" + }, + "cram_to_bam_sam": { + "content": [ [ - ], - [ - "versions.yml:md5,06b9049228b111e7bed5c52fe8a98d9b" ] ], - "timestamp": "2023-12-04T17:41:17.563069206" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:04.999247" }, - "sarscov2 - [bam, []], [], []": { + "cram_to_bam_index_sam": { "content": [ - "test.bam", [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:12.976457" + }, + "cram_crai": { + "content": [ [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:37:56.497581" + }, + "cram_csi": { + "content": [ [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:37:56.50038" + }, + "cram_to_bam_cram": { + "content": [ [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:04.992239" + }, + "cram_to_bam_index_qname_csi": { + "content": [ + "test.bam.csi" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:23.325496" + }, + "bam_stub_sam": { + "content": [ [ - ], - [ - "versions.yml:md5,06b9049228b111e7bed5c52fe8a98d9b" ] ], - "timestamp": "2023-12-04T17:41:03.206994564" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:32.079529" }, - "homo_sapiens - [cram, []], fasta, qname - bam & index output": { + "cram_cram": { + "content": [ + "test.cram" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:37:56.490286" + }, + "bam_csi": { "content": [ - "test.bam", [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:37:51.262882" + }, + "cram_to_bam_crai": { + "content": [ [ - ], - "test.bam.csi", + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:04.989247" + }, + "cram_to_bam_index_crai": { + "content": [ [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:12.967681" + }, + "cram_to_bam_index_qname_versions": { + "content": [ [ - - ], + "versions.yml:md5,4ea32c57d546102a1b32d9693ada7cf1" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:13:03.935041046" + }, + "cram_to_bam_bam": { + "content": [ + "test.bam" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:04.982361" + }, + "cram_to_bam_index_bam": { + "content": [ + "test.bam" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:12.95456" + }, + "cram_to_bam_index_versions": { + "content": [ [ - "versions.yml:md5,06b9049228b111e7bed5c52fe8a98d9b" + "versions.yml:md5,4ea32c57d546102a1b32d9693ada7cf1" ] ], - "timestamp": "2023-12-04T17:44:39.165289759" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:12:55.910685496" }, - "homo_sapiens - [cram, []], fasta, [] - bam & index output": { + "cram_to_bam_bai": { "content": [ - "test.bam", [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:04.98601" + }, + "cram_to_bam_versions": { + "content": [ [ - - ], - "test.bam.csi", + "versions.yml:md5,4ea32c57d546102a1b32d9693ada7cf1" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:12:47.715221169" + }, + "cram_bam": { + "content": [ [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:37:56.495512" + }, + "bam_stub_cram": { + "content": [ [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:32.076908" + }, + "cram_to_bam_index_qname_bai": { + "content": [ [ - "versions.yml:md5,06b9049228b111e7bed5c52fe8a98d9b" + ] ], - "timestamp": "2023-12-04T17:44:32.25731224" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:23.328458" }, - "sarscov2 - [bam, []], [], [] - stub": { + "cram_to_bam_index_qname_crai": { "content": [ - "test.bam", [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:23.330789" + }, + "cram_bai": { + "content": [ [ - ], - "test.csi", + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:37:56.493129" + }, + "bam_stub_crai": { + "content": [ [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:32.074313" + }, + "cram_to_bam_index_qname_bam": { + "content": [ + "test.bam" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:23.322874" + }, + "bam_versions": { + "content": [ + [ + "versions.yml:md5,4ea32c57d546102a1b32d9693ada7cf1" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:12:31.692607421" + }, + "cram_to_bam_index_qname_cram": { + "content": [ [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:23.333248" + }, + "bam_crai": { + "content": [ [ - "versions.yml:md5,06b9049228b111e7bed5c52fe8a98d9b" + ] ], - "timestamp": "2023-12-04T17:44:45.81037195" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:37:51.259774" }, - "homo_sapiens - [cram, crai], fasta, []": { + "bam_cram": { "content": [ - "test.cram", [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:37:51.261287" + }, + "cram_to_bam_csi": { + "content": [ [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:04.995454" + }, + "cram_sam": { + "content": [ [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:37:56.502625" + }, + "cram_versions": { + "content": [ + [ + "versions.yml:md5,4ea32c57d546102a1b32d9693ada7cf1" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:12:39.913411036" + }, + "bam_sam": { + "content": [ [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:37:51.264651" + }, + "cram_to_bam_index_bai": { + "content": [ [ - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:12.962863" + }, + "cram_to_bam_index_qname_sam": { + "content": [ [ - "versions.yml:md5,06b9049228b111e7bed5c52fe8a98d9b" + ] ], - "timestamp": "2023-12-04T17:41:10.730011823" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:23.337634" + }, + "bam_stub_csi": { + "content": [ + "test.csi" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:32.068596" } } \ No newline at end of file diff --git a/modules/nf-core/star/align/environment.yml b/modules/nf-core/star/align/environment.yml index 36fcd022..8bd58cff 100644 --- a/modules/nf-core/star/align/environment.yml +++ b/modules/nf-core/star/align/environment.yml @@ -6,4 +6,5 @@ channels: dependencies: - bioconda::star=2.7.10a - bioconda::samtools=1.18 + - bioconda::htslib=1.18 - conda-forge::gawk=5.1.0 diff --git a/modules/nf-core/star/align/tests/main.nf.test b/modules/nf-core/star/align/tests/main.nf.test index 4c878474..6ecd7786 100644 --- a/modules/nf-core/star/align/tests/main.nf.test +++ b/modules/nf-core/star/align/tests/main.nf.test @@ -7,39 +7,40 @@ nextflow_process { tag "modules_nfcore" tag "star" tag "star/align" + tag "star/genomegenerate" - test("homo_sapiens - single_end") { - config "./nextflow.config" - - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] - ]) - """ - } + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + """ } } + } + + test("homo_sapiens - single_end") { + config "./nextflow.config" when { process { """ input[0] = Channel.of([ [ id:'test', single_end:true ], // meta map - [ file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_1_fastq_gz'], checkIfExists: true) ] + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true) ] ]) input[1] = STAR_GENOMEGENERATE.out.index input[2] = Channel.of([ [ id:'test_gtf' ], - [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false input[4] = 'illumina' @@ -74,38 +75,20 @@ nextflow_process { test("homo_sapiens - paired_end") { config "./nextflow.config" - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] - ]) - """ - } - } - } - when { process { """ input[0] = Channel.of([ [ id:'test', single_end:false ], // meta map [ - file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_1_fastq_gz'], checkIfExists: true), - file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_2_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true) ] ]) input[1] = STAR_GENOMEGENERATE.out.index input[2] = Channel.of([ [ id:'test_gtf' ], - [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false input[4] = 'illumina' @@ -140,38 +123,20 @@ nextflow_process { test("homo_sapiens - paired_end - arriba") { config "./nextflow.arriba.config" - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] - ]) - """ - } - } - } - when { process { """ input[0] = Channel.of([ [ id:'test', single_end:false ], // meta map [ - file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_1_fastq_gz'], checkIfExists: true), - file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_2_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true) ] ]) input[1] = STAR_GENOMEGENERATE.out.index input[2] = Channel.of([ [ id:'test_gtf' ], - [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false input[4] = 'illumina' @@ -206,38 +171,20 @@ nextflow_process { test("homo_sapiens - paired_end - starfusion") { config "./nextflow.starfusion.config" - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] - ]) - """ - } - } - } - when { process { """ input[0] = Channel.of([ [ id:'test', single_end:false ], // meta map [ - file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_1_fastq_gz'], checkIfExists: true), - file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_2_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true) ] ]) input[1] = STAR_GENOMEGENERATE.out.index input[2] = Channel.of([ [ id:'test_gtf' ], - [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false input[4] = 'illumina' @@ -272,40 +219,22 @@ nextflow_process { test("homo_sapiens - paired_end - multiple") { config "./nextflow.config" - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] - ]) - """ - } - } - } - when { process { """ input[0] = Channel.of([ [ id:'test', single_end:false ], // meta map [ - file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_1_fastq_gz'], checkIfExists: true), - file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_2_fastq_gz'], checkIfExists: true), - file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_1_fastq_gz'], checkIfExists: true), - file(params.test_data['homo_sapiens']['illumina']['test_rnaseq_2_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true) ] ]) input[1] = STAR_GENOMEGENERATE.out.index input[2] = Channel.of([ [ id:'test_gtf' ], - [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false input[4] = 'illumina' diff --git a/modules/nf-core/star/genomegenerate/environment.yml b/modules/nf-core/star/genomegenerate/environment.yml index 93e4476a..791f255e 100644 --- a/modules/nf-core/star/genomegenerate/environment.yml +++ b/modules/nf-core/star/genomegenerate/environment.yml @@ -1,11 +1,10 @@ name: star_genomegenerate - channels: - conda-forge - bioconda - defaults - dependencies: - bioconda::samtools=1.18 + - bioconda::htslib=1.18 - bioconda::star=2.7.10a - conda-forge::gawk=5.1.0 diff --git a/modules/nf-core/star/genomegenerate/tests/main.nf.test b/modules/nf-core/star/genomegenerate/tests/main.nf.test index af0c9421..c17c8ba4 100644 --- a/modules/nf-core/star/genomegenerate/tests/main.nf.test +++ b/modules/nf-core/star/genomegenerate/tests/main.nf.test @@ -8,18 +8,18 @@ nextflow_process { tag "star" tag "star/genomegenerate" - test("homo_sapiens") { + test("fasta_gtf") { when { process { """ input[0] = Channel.of([ [ id:'test_fasta' ], - [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] ]) input[1] = Channel.of([ [ id:'test_gtf' ], - [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) """ } @@ -28,14 +28,13 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("index_with_gtf") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("fasta_gtf_index") }, + { assert snapshot(process.out.versions).match("fasta_gtf_versions") } ) } - } - test("homo_sapiens-stub") { + test("fasta_gtf_stub") { options '-stub' @@ -44,11 +43,11 @@ nextflow_process { """ input[0] = Channel.of([ [ id:'test_fasta' ], - [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] ]) input[1] = Channel.of([ [ id:'test_gtf' ], - [file(params.test_data['homo_sapiens']['genome']['genome_gtf'], checkIfExists: true)] + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) """ } @@ -57,21 +56,20 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("index_with_gtf") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("fasta_gtf_stub_index") }, + { assert snapshot(process.out.versions).match("fasta_gtf_stub_versions") } ) } - } - test("homo_sapiens-without_gtf") { + test("fasta") { when { process { """ input[0] = Channel.of([ [ id:'test_fasta' ], - [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] ]) input[1] = Channel.of([ [], [] ]) """ @@ -81,14 +79,14 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("index_without_gtf") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("fasta_index") }, + { assert snapshot(process.out.versions).match("fasta_versions") } ) } } - test("homo_sapiens-without_gtf-stub") { + test("fasta_stub") { options '-stub' @@ -97,7 +95,7 @@ nextflow_process { """ input[0] = Channel.of([ [ id:'test_fasta' ], - [file(params.test_data['homo_sapiens']['genome']['genome_fasta'], checkIfExists: true)] + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] ]) input[1] = Channel.of([ [], [] ]) """ @@ -107,11 +105,11 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("index_without_gtf") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("fasta_stub_index") }, + { assert snapshot(process.out.versions).match("fasta_stub_versions") } ) } } -} \ No newline at end of file +} diff --git a/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap b/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap index 9de08c74..5653d6e6 100644 --- a/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap +++ b/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap @@ -1,22 +1,90 @@ { - "versions": { + "fasta_gtf_versions": { "content": [ [ "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" ] ], - "timestamp": "2023-12-19T11:05:51.741109" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-01T15:54:31.798555" }, - "index_with_gtf": { + "fasta_stub_versions": { + "content": [ + [ + "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-01T15:55:07.521209" + }, + "fasta_gtf_stub_index": { + "content": [ + "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, exonGeTrInfo.tab, exonInfo.tab, geneInfo.tab, genomeParameters.txt, sjdbInfo.txt, sjdbList.fromGTF.out.tab, sjdbList.out.tab, transcriptInfo.tab]" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-01T15:54:46.478098" + }, + "fasta_gtf_stub_versions": { + "content": [ + [ + "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-01T15:54:46.491657" + }, + "fasta_index": { + "content": [ + "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, genomeParameters.txt]" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-01T15:54:57.552329" + }, + "fasta_versions": { + "content": [ + [ + "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-01T15:54:57.560541" + }, + "fasta_gtf_index": { "content": [ "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, exonGeTrInfo.tab, exonInfo.tab, geneInfo.tab, genomeParameters.txt, sjdbInfo.txt, sjdbList.fromGTF.out.tab, sjdbList.out.tab, transcriptInfo.tab]" ], - "timestamp": "2023-12-19T11:38:14.551548" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-01T15:54:31.786814" }, - "index_without_gtf": { + "fasta_stub_index": { "content": [ "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, genomeParameters.txt]" ], - "timestamp": "2023-12-19T11:38:22.382905" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-01T15:55:07.517472" } } \ No newline at end of file diff --git a/modules/nf-core/stringtie/stringtie/tests/main.nf.test b/modules/nf-core/stringtie/stringtie/tests/main.nf.test index 68786b74..00efe8f1 100644 --- a/modules/nf-core/stringtie/stringtie/tests/main.nf.test +++ b/modules/nf-core/stringtie/stringtie/tests/main.nf.test @@ -10,13 +10,15 @@ nextflow_process { test("sarscov2 [bam] - forward strandedness") { + config "./nextflow.config" + when { process { """ input[0] = [ [ id:'test', strandedness:'forward' ], // meta map - [ file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) ] - ] + [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam", checkIfExists: true) ] + ] input[1] = [] """ } @@ -24,24 +26,26 @@ nextflow_process { then { assertAll( - { assert process.success }, - { assert snapshot(process.out.transcript_gtf).match("fs_transcript_gtf") }, - { assert snapshot(process.out.abundance).match("fs_abundance") }, - { assert snapshot(process.out.versions).match("fs_versions") } + { assert process.success }, + { assert snapshot(process.out.transcript_gtf).match("fs_transcript_gtf") }, + { assert snapshot(process.out.abundance).match("fs_abundance") }, + { assert snapshot(process.out.versions).match("fs_versions") } ) } } test("sarscov2 [bam] - forward strandedness + reference annotation") { + config "./nextflow.config" + when { process { """ input[0] = [ - [ id:'test', strandedness:'forward' ], // meta map - [ file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) ] - ] - input[1] = file(params.test_data['sarscov2']['genome']['genome_gtf'], checkIfExists: true) + [ id:'test', strandedness:'forward' ], // meta map + [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam", checkIfExists: true) ] + ] + input[1] = file(params.modules_testdata_base_path + "genomics/sarscov2/genome/genome.gtf", checkIfExists: true) """ } } @@ -49,23 +53,25 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.transcript_gtf).match("fs_gtf_transcript_gtf") }, - { assert snapshot(process.out.abundance).match("fs_gtf_abundance") }, - { assert snapshot(process.out.ballgown).match("fs_gtf_ballgown") }, - { assert snapshot(process.out.versions).match("fs_gtf_versions") } + { assert snapshot(process.out.transcript_gtf).match("fs_gtf_transcript_gtf") }, + { assert snapshot(process.out.abundance).match("fs_gtf_abundance") }, + { assert snapshot(process.out.ballgown).match("fs_gtf_ballgown") }, + { assert snapshot(process.out.versions).match("fs_gtf_versions") } ) } } test("sarscov2 [bam] - reverse strandedness") { + config "./nextflow.config" + when { process { """ input[0] = [ [ id:'test', strandedness:'reverse' ], // meta map - [ file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) ] - ] + [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam", checkIfExists: true) ] + ] input[1] = [] """ } @@ -73,35 +79,37 @@ nextflow_process { then { assertAll( - { assert process.success }, - { assert snapshot(process.out.transcript_gtf).match("rs_transcript_gtf") }, - { assert snapshot(process.out.abundance).match("rs_abundance") }, - { assert snapshot(process.out.versions).match("rs_versions") } + { assert process.success }, + { assert snapshot(process.out.transcript_gtf).match("rs_transcript_gtf") }, + { assert snapshot(process.out.abundance).match("rs_abundance") }, + { assert snapshot(process.out.versions).match("rs_versions") } ) } } test("sarscov2 [bam] - reverse strandedness + reference annotation") { + config "./nextflow.config" + when { process { """ input[0] = [ [ id:'test', strandedness:'reverse' ], // meta map - [ file(params.test_data['sarscov2']['illumina']['test_paired_end_sorted_bam'], checkIfExists: true) ] - ] - input[1] = file(params.test_data['sarscov2']['genome']['genome_gtf'], checkIfExists: true) + [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam", checkIfExists: true) ] + ] + input[1] = file(params.modules_testdata_base_path + "genomics/sarscov2/genome/genome.gtf", checkIfExists: true) """ } } then { assertAll( - { assert process.success }, - { assert snapshot(process.out.transcript_gtf).match("rs_gtf_transcript_gtf") }, - { assert snapshot(process.out.abundance).match("rs_gtf_abundance") }, - { assert snapshot(process.out.ballgown).match("rs_gtf_ballgown") }, - { assert snapshot(process.out.versions).match("rs_gtf_versions") } + { assert process.success }, + { assert snapshot(process.out.transcript_gtf).match("rs_gtf_transcript_gtf") }, + { assert snapshot(process.out.abundance).match("rs_gtf_abundance") }, + { assert snapshot(process.out.ballgown).match("rs_gtf_ballgown") }, + { assert snapshot(process.out.versions).match("rs_gtf_versions") } ) } } diff --git a/modules/nf-core/stringtie/stringtie/tests/nextflow.config b/modules/nf-core/stringtie/stringtie/tests/nextflow.config new file mode 100644 index 00000000..e3aaa099 --- /dev/null +++ b/modules/nf-core/stringtie/stringtie/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: 'STRINGTIE_STRINGTIE' { + ext.args = '' + } +} diff --git a/modules/nf-core/trimgalore/environment.yml b/modules/nf-core/trimgalore/environment.yml index 6cd0f51b..0981320c 100644 --- a/modules/nf-core/trimgalore/environment.yml +++ b/modules/nf-core/trimgalore/environment.yml @@ -1,7 +1,10 @@ name: trimgalore + channels: - conda-forge - bioconda - defaults + dependencies: + - bioconda::cutadapt=3.4 - bioconda::trim-galore=0.6.7 diff --git a/modules/nf-core/trimgalore/tests/main.nf.test b/modules/nf-core/trimgalore/tests/main.nf.test index bc6812cc..43904ac3 100644 --- a/modules/nf-core/trimgalore/tests/main.nf.test +++ b/modules/nf-core/trimgalore/tests/main.nf.test @@ -10,13 +10,10 @@ nextflow_process { test("test_trimgalore_single_end") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - [ file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] + [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/fastq/test_1.fastq.gz", checkIfExists: true) ] ] """ } @@ -41,7 +38,8 @@ nextflow_process { { report1_lines.each { report1_line -> { assert path(process.out.log.get(0).get(1)).getText().contains(report1_line) } } - } + }, + { assert snapshot(process.out.versions).match() } ) } } @@ -49,15 +47,14 @@ nextflow_process { test("test_trimgalore_paired_end") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = [ [ id:'test', single_end:false ], // meta map - [ file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) ] + [ + file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/fastq/test_1.fastq.gz", checkIfExists: true), + file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/fastq/test_2.fastq.gz", checkIfExists: true) ] + ] """ } } @@ -98,7 +95,8 @@ nextflow_process { { report2_lines.each { report2_line -> { assert path(process.out.log.get(0).get(1).get(1)).getText().contains(report2_line) } } - } + }, + { assert snapshot(process.out.versions).match() } ) } } diff --git a/modules/nf-core/trimgalore/tests/main.nf.test.snap b/modules/nf-core/trimgalore/tests/main.nf.test.snap index 84feacca..082c5500 100644 --- a/modules/nf-core/trimgalore/tests/main.nf.test.snap +++ b/modules/nf-core/trimgalore/tests/main.nf.test.snap @@ -1,148 +1,26 @@ { "test_trimgalore_single_end": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test_trimmed.fq.gz:md5,e0a7516b8ea8d6467d6306acb2cd13c4" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": true - }, - "test.fastq.gz_trimming_report.txt:md5,a1ab3958205f1ddf48af623242b5b429" - ] - ], - "2": [ - - ], - "3": [ - - ], - "4": [ - - ], - "5": [ - "versions.yml:md5,47d966cbb31c80eb8f7fe860d55659b7" - ], - "html": [ - - ], - "log": [ - [ - { - "id": "test", - "single_end": true - }, - "test.fastq.gz_trimming_report.txt:md5,a1ab3958205f1ddf48af623242b5b429" - ] - ], - "reads": [ - [ - { - "id": "test", - "single_end": true - }, - "test_trimmed.fq.gz:md5,e0a7516b8ea8d6467d6306acb2cd13c4" - ] - ], - "unpaired": [ - - ], - "versions": [ - "versions.yml:md5,47d966cbb31c80eb8f7fe860d55659b7" - ], - "zip": [ - - ] - } + [ + "versions.yml:md5,47d966cbb31c80eb8f7fe860d55659b7" + ] ], - "timestamp": "2023-10-17T15:24:57.782141441" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-29T16:33:20.401347" }, "test_trimgalore_paired_end": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test_1_val_1.fq.gz:md5,e0a7516b8ea8d6467d6306acb2cd13c4", - "test_2_val_2.fq.gz:md5,f3d61189e6d10202da7b8686f1dbb71b" - ] - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test_1.fastq.gz_trimming_report.txt:md5,315d40465412f9909bbaabf52269274d", - "test_2.fastq.gz_trimming_report.txt:md5,34436303da1c78811103427a2fb57f7b" - ] - ] - ], - "2": [ - - ], - "3": [ - - ], - "4": [ - - ], - "5": [ - "versions.yml:md5,47d966cbb31c80eb8f7fe860d55659b7" - ], - "html": [ - - ], - "log": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test_1.fastq.gz_trimming_report.txt:md5,315d40465412f9909bbaabf52269274d", - "test_2.fastq.gz_trimming_report.txt:md5,34436303da1c78811103427a2fb57f7b" - ] - ] - ], - "reads": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test_1_val_1.fq.gz:md5,e0a7516b8ea8d6467d6306acb2cd13c4", - "test_2_val_2.fq.gz:md5,f3d61189e6d10202da7b8686f1dbb71b" - ] - ] - ], - "unpaired": [ - - ], - "versions": [ - "versions.yml:md5,47d966cbb31c80eb8f7fe860d55659b7" - ], - "zip": [ - - ] - } + [ + "versions.yml:md5,47d966cbb31c80eb8f7fe860d55659b7" + ] ], - "timestamp": "2023-10-17T15:25:08.513589909" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-29T16:33:28.960497" } } \ No newline at end of file diff --git a/subworkflows/nf-core/bam_sort_stats_samtools/main.nf b/subworkflows/nf-core/bam_sort_stats_samtools/main.nf index fc1c652b..b716375b 100644 --- a/subworkflows/nf-core/bam_sort_stats_samtools/main.nf +++ b/subworkflows/nf-core/bam_sort_stats_samtools/main.nf @@ -15,7 +15,7 @@ workflow BAM_SORT_STATS_SAMTOOLS { ch_versions = Channel.empty() - SAMTOOLS_SORT ( ch_bam ) + SAMTOOLS_SORT ( ch_bam, ch_fasta ) ch_versions = ch_versions.mix(SAMTOOLS_SORT.out.versions.first()) SAMTOOLS_INDEX ( SAMTOOLS_SORT.out.bam ) diff --git a/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test b/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test index 59b749d8..75b5b934 100644 --- a/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test +++ b/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test @@ -24,12 +24,14 @@ nextflow_workflow { } workflow { """ - input[0] = [ [ id:'test', single_end:false ], // meta map - file(params.test_data['sarscov2']['illumina']['test_single_end_bam'], checkIfExists: true) - ] - input[1] = [ [ id:'genome' ], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) - ] + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.single_end.bam', checkIfExists: true) + ]) + input[1] = Channel.of([ + [ id:'genome' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) """ } } @@ -54,12 +56,14 @@ nextflow_workflow { } workflow { """ - input[0] = [ [ id:'test', single_end:false ], // meta map - file(params.test_data['sarscov2']['illumina']['test_paired_end_bam'], checkIfExists: true) - ] - input[1] = [ [ id:'genome' ], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) - ] + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true) + ]) + input[1] = Channel.of([ + [ id:'genome' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) """ } } diff --git a/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap b/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap index 77afbf17..6645a092 100644 --- a/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap +++ b/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap @@ -11,6 +11,10 @@ ] ] ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, "timestamp": "2023-10-22T20:25:03.687121177" }, "test_bam_sort_stats_samtools_paired_end_idxstats": { @@ -25,6 +29,10 @@ ] ] ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, "timestamp": "2023-10-22T20:25:03.709648916" }, "test_bam_sort_stats_samtools_single_end_stats": { @@ -35,11 +43,15 @@ "id": "test", "single_end": false }, - "test.stats:md5,f281507081517414eb1a04b2d9c855b2" + "test.stats:md5,cb0bf2b79de52fdf0c61e80efcdb0bb4" ] ] ], - "timestamp": "2023-12-04T11:06:50.951881479" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:44:38.553256801" }, "test_bam_sort_stats_samtools_paired_end_stats": { "content": [ @@ -49,11 +61,15 @@ "id": "test", "single_end": false }, - "test.stats:md5,e32e7e49dce1fbe327a89e0fb7bc01b1" + "test.stats:md5,d7796222a087b9bb97f631f1c21b9c95" ] ] ], - "timestamp": "2023-12-04T11:06:59.253905951" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-13T16:44:48.355870518" }, "test_bam_sort_stats_samtools_single_end_idxstats": { "content": [ @@ -67,7 +83,11 @@ ] ] ], - "timestamp": "2023-10-22T20:25:58.451364604" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-01-18T17:10:02.84631" }, "test_bam_sort_stats_samtools_single_end_flagstats": { "content": [ @@ -81,6 +101,10 @@ ] ] ], - "timestamp": "2023-10-22T20:25:58.416859285" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-01-18T17:10:02.829756" } } \ No newline at end of file From 72dd514cc90d19797bf3869b9427d879677582f6 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 18 Mar 2024 11:39:50 +0100 Subject: [PATCH 148/491] Fix some common problems in CIRIquant and HISAT2_ALIGN --- modules/local/ciriquant/yml/main.nf | 6 +++--- nextflow.config | 1 + subworkflows/local/circrna_discovery.nf | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/local/ciriquant/yml/main.nf b/modules/local/ciriquant/yml/main.nf index 25bc0b01..4eb2d06f 100644 --- a/modules/local/ciriquant/yml/main.nf +++ b/modules/local/ciriquant/yml/main.nf @@ -7,8 +7,8 @@ process CIRIQUANT_YML { 'quay.io/biocontainers/ciriquant:1.1.2--pyhdfd78af_2' }" input: - path gtf - path fasta + tuple val(meta), path(gtf) + tuple val(meta2), path(fasta) path bwa path hisat2 @@ -19,7 +19,7 @@ process CIRIQUANT_YML { task.ext.when == null || task.ext.when script: - hisat2_prefix = fasta.toString() - ~/.(fa|fasta)$/ + hisat2_prefix = meta2.id fasta_path = fasta.toRealPath() gtf_path = gtf.toRealPath() bwa_path = bwa.toRealPath() diff --git a/nextflow.config b/nextflow.config index ffa9b39e..018a60da 100644 --- a/nextflow.config +++ b/nextflow.config @@ -206,6 +206,7 @@ profiles { podman.enabled = false shifter.enabled = false charliecloud.enabled = false + apptainer.runOptions = '--no-mount tmp --writable-tmpfs' } gitpod { executor.name = 'local' diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index a0a20433..73ac5e62 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -141,7 +141,7 @@ workflow CIRCRNA_DISCOVERY { // only need path to bwa, only need path to hisat2. // do not want to upset the collect declr for all indices just for this. - CIRIQUANT_YML( gtf, fasta, bwa_index.map{ meta, index -> return index }, hisat2_index.map{ meta, index -> return index } ) + CIRIQUANT_YML( ch_gtf, ch_fasta, bwa_index.map{ meta, index -> return index }, hisat2_index.map{ meta, index -> return index } ) CIRIQUANT( reads, CIRIQUANT_YML.out.yml.collect() ) CIRIQUANT_FILTER( CIRIQUANT.out.gtf.map{ meta, gtf -> [ meta + [tool: "ciriquant"], gtf ] }, bsj_reads ) From 6fc9ae8c4db439c07b544a7c5e8880ca6ddb8f58 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 18 Mar 2024 11:42:08 +0100 Subject: [PATCH 149/491] Fix miranda channel structure --- subworkflows/local/mirna_prediction.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index b9a4cfc7..cdd6f86d 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -8,7 +8,7 @@ workflow MIRNA_PREDICTION{ take: circrna_fasta circrna_bed12 - mature + ch_mature main: ch_versions = Channel.empty() @@ -17,7 +17,7 @@ workflow MIRNA_PREDICTION{ // TARGETSCAN WORKFLOW: // - TARGETSCAN_DATABASE( mature ) + TARGETSCAN_DATABASE( ch_mature ) TARGETSCAN( circrna_fasta, TARGETSCAN_DATABASE.out.mature_txt ) ch_versions = ch_versions.mix(TARGETSCAN_DATABASE.out.versions) @@ -27,7 +27,7 @@ workflow MIRNA_PREDICTION{ // MIRANDA WORKFLOW: // - MIRANDA( circrna_fasta, mature ) + MIRANDA( circrna_fasta, ch_mature.map{meta, mature -> mature} ) ch_versions = ch_versions.mix(MIRANDA.out.versions) From 4e50b0b67262f7e01ebc61e7dfb92218fe37ae4e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 18 Mar 2024 11:54:17 +0100 Subject: [PATCH 150/491] Fix linting --- modules/local/seqkit/split/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/seqkit/split/main.nf b/modules/local/seqkit/split/main.nf index 5d70f47b..1fbc0c8d 100644 --- a/modules/local/seqkit/split/main.nf +++ b/modules/local/seqkit/split/main.nf @@ -33,4 +33,4 @@ process SEQKIT_SPLIT { seqkit: \$(echo \$(seqkit 2>&1) | sed 's/^.*Version: //; s/ .*\$//') END_VERSIONS """ -} \ No newline at end of file +} From 919f5fa92d4f49568e01516437947ac7eebdec40 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 18 Mar 2024 12:11:31 +0100 Subject: [PATCH 151/491] Add some meta inputs --- modules/local/circtest/test/main.nf | 2 +- modules/local/deseq2/differential_expression/main.nf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/local/circtest/test/main.nf b/modules/local/circtest/test/main.nf index 1d1e4df3..643f2c56 100644 --- a/modules/local/circtest/test/main.nf +++ b/modules/local/circtest/test/main.nf @@ -9,7 +9,7 @@ process CIRCTEST { input: path(circ_csv) path(linear_csv) - path(phenotype) + tuple val(meta), path(phenotype) output: path "*" , emit: results diff --git a/modules/local/deseq2/differential_expression/main.nf b/modules/local/deseq2/differential_expression/main.nf index 67631ed5..86ee474c 100644 --- a/modules/local/deseq2/differential_expression/main.nf +++ b/modules/local/deseq2/differential_expression/main.nf @@ -8,7 +8,7 @@ process DESEQ2_DIFFERENTIAL_EXPRESSION { input: path(gene_matrix) - path(phenotype) + tuple val(meta), path(phenotype) path(circrna_matrix) val(species) path(biomart_keys) From 50a6ca2d2a1913e43e6e4e65fe53707c89d2dd52 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 18 Mar 2024 12:16:45 +0100 Subject: [PATCH 152/491] Prettier --- modules/local/seqkit/split/environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/seqkit/split/environment.yml b/modules/local/seqkit/split/environment.yml index fb5b8b63..d557b8b3 100644 --- a/modules/local/seqkit/split/environment.yml +++ b/modules/local/seqkit/split/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - bioconda::seqkit=2.8.0 \ No newline at end of file + - bioconda::seqkit=2.8.0 From 30552fa2dec7d0a6a3edcb6530582edce59507cb Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 07:59:24 +0100 Subject: [PATCH 153/491] Unify species_id parameter --- conf/test.config | 2 +- main.nf | 18 ++++++++++-------- nextflow.config | 1 + nextflow_schema.json | 2 +- workflows/circrna/main.nf | 3 ++- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/conf/test.config b/conf/test.config index c0444832..0c75023b 100644 --- a/conf/test.config +++ b/conf/test.config @@ -30,5 +30,5 @@ params { module = "circrna_discovery,mirna_prediction,differential_expression" outdir = "results/" bsj_reads = 2 - species = "cel" + species_id = "cel" } diff --git a/main.nf b/main.nf index 1e202b27..544e9738 100644 --- a/main.nf +++ b/main.nf @@ -29,14 +29,14 @@ include { getGenomeAttribute } from './subworkflows/local/utils_nfcore_circ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -params.fasta = getGenomeAttribute('fasta') -params.gtf = getGenomeAttribute('gtf') -params.bwa = getGenomeAttribute('bwa') -params.star = getGenomeAttribute('star') -params.bowtie = getGenomeAttribute('bowtie') -params.bowtie2 = getGenomeAttribute('bowtie2') -params.mature = getGenomeAttribute('mature') -params.species = getGenomeAttribute('species_id') +params.fasta = getGenomeAttribute('fasta') +params.gtf = getGenomeAttribute('gtf') +params.bwa = getGenomeAttribute('bwa') +params.star = getGenomeAttribute('star') +params.bowtie = getGenomeAttribute('bowtie') +params.bowtie2 = getGenomeAttribute('bowtie2') +params.mature = getGenomeAttribute('mature') +params.species_id = getGenomeAttribute('species_id') /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -60,6 +60,7 @@ workflow NFCORE_CIRCRNA { ch_fasta = Channel.value([[id: "fasta"], file(params.fasta, checkIfExists:true)]) ch_gtf = Channel.value([[id: "gtf"], file(params.gtf, checkIfExists:true)]) ch_mature = Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) + ch_species = Channel.value(params.species_id) CIRCRNA ( ch_samplesheet, @@ -67,6 +68,7 @@ workflow NFCORE_CIRCRNA { ch_fasta, ch_gtf, ch_mature, + ch_species, ch_versions ) diff --git a/nextflow.config b/nextflow.config index 018a60da..4c3bfcd5 100644 --- a/nextflow.config +++ b/nextflow.config @@ -31,6 +31,7 @@ params { hisat2_build_memory = '200.GB' segemehl = null save_reference = true + species_id = null // Trimming min_trimmed_reads = 10000 diff --git a/nextflow_schema.json b/nextflow_schema.json index 5bdc6753..912bd12b 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -212,7 +212,7 @@ "fa_icon": "fas fa-wheelchair", "default": null }, - "species": { + "species_id": { "type": "string", "fa_icon": "fas fa-dog", "description": "String identifying species.", diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index e51d850e..f090f857 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -57,6 +57,7 @@ workflow CIRCRNA { ch_fasta ch_gtf ch_mature + ch_species ch_versions main: @@ -179,7 +180,7 @@ workflow CIRCRNA { ch_phenotype, CIRCRNA_DISCOVERY.out.dea_matrix, CIRCRNA_DISCOVERY.out.clr_matrix, - params.species, + ch_species, ch_ensembl_database_map, params.exon_boundary ) From b4929ee2373d97322a75f2bda4e7381d7968fc72 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 08:14:49 +0100 Subject: [PATCH 154/491] Simplify handling of tool indices --- conf/modules.config | 16 +++++++------- subworkflows/local/circrna_discovery.nf | 6 ++--- subworkflows/local/prepare_genome.nf | 29 +++++++++++++------------ workflows/circrna/main.nf | 15 ++++++------- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index a6ccdf5c..875f83ee 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -89,7 +89,7 @@ if (!params.skip_trimming) { } withName: BOWTIE_BUILD { - ext.when = { params.fasta && !params.bowtie && params.tool.split(',').contains('mapsplice') && params.module.split(',').contains('circrna_discovery') } + ext.when = { !params.bowtie && params.tool.split(',').contains('mapsplice') && params.module.split(',').contains('circrna_discovery') } publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, @@ -99,7 +99,7 @@ if (!params.skip_trimming) { } withName: BOWTIE2_BUILD { - ext.when = { params.fasta && !params.bowtie2 && params.tool.split(',').contains('find_circ') && params.module.split(',').contains('circrna_discovery') } + ext.when = { !params.bowtie2 && params.tool.split(',').contains('find_circ') && params.module.split(',').contains('circrna_discovery') } publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, @@ -109,7 +109,7 @@ if (!params.skip_trimming) { } withName: BWA_INDEX { - ext.when = { params.fasta && !params.bwa && params.tool.split(',').contains('ciriquant') && params.module.split(',').contains('circrna_discovery') } + ext.when = { !params.bwa && params.tool.split(',').contains('ciriquant') && params.module.split(',').contains('circrna_discovery') } publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, @@ -119,7 +119,7 @@ if (!params.skip_trimming) { } withName: HISAT2_EXTRACTSPLICESITES { - ext.when = { params.fasta && params.gtf && ( params.module.split(',').contains('differential_expression') || params.tool.split(',').contains('ciriquant') ) } + ext.when = { params.module.split(',').contains('differential_expression') || params.tool.split(',').contains('ciriquant') } publishDir = [ path: { "${params.outdir}/references/index/hisat2" }, mode: params.publish_dir_mode, @@ -129,7 +129,7 @@ if (!params.skip_trimming) { } withName: HISAT2_BUILD { - ext.when = { params.fasta && params.gtf && ( params.module.split(',').contains('differential_expression') || params.tool.split(',').contains('ciriquant') ) } + ext.when = { params.module.split(',').contains('differential_expression') || params.tool.split(',').contains('ciriquant') } publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, @@ -139,7 +139,7 @@ if (!params.skip_trimming) { } withName: STAR_GENOMEGENERATE { - ext.when = { params.fasta && params.gtf && !params.star && params.module.split(',').contains('circrna_discovery') && ( params.tool.split(',').contains('circexplorer2') || params.tool.split(',').contains('dcc') || params.tool.split(',').contains('circrna_finder') ) } + ext.when = { !params.star && params.module.split(',').contains('circrna_discovery') && ( params.tool.split(',').contains('circexplorer2') || params.tool.split(',').contains('dcc') || params.tool.split(',').contains('circrna_finder') ) } ext.args = [ "", params.sjdboverhang ? "--sjdbOverhang ${params.sjdboverhang}" : '', ].join(' ').trim() @@ -152,7 +152,7 @@ if (!params.skip_trimming) { } withName: SEGEMEHL_INDEX { - ext.when = { params.fasta && !params.segemehl && params.tool.split(',').contains('segemehl') && params.module.split(',').contains('circrna_discovery') } + ext.when = { !params.segemehl && params.tool.split(',').contains('segemehl') && params.module.split(',').contains('circrna_discovery') } publishDir = [ path: { "${params.outdir}/references/index/segemehl" }, mode: params.publish_dir_mode, @@ -164,7 +164,7 @@ if (!params.skip_trimming) { // circRNA withName: SEGEMEHL_ALIGN { - ext.when = { params.fasta && params.tool.split(',').contains('segemehl') && params.module.split(',').contains('circrna_discovery') } + ext.when = { params.tool.split(',').contains('segemehl') && params.module.split(',').contains('circrna_discovery') } ext.args = [ "", "-b", "-S" diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 73ac5e62..b51c821f 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -120,11 +120,11 @@ workflow CIRCRNA_DISCOVERY { // FIND_CIRC WORKFLOW: // - FIND_CIRC_ALIGN( reads, bowtie2_index.collect(), false, true ) + FIND_CIRC_ALIGN( reads, bowtie2_index, false, true ) SAMTOOLS_INDEX( FIND_CIRC_ALIGN.out.aligned ) SAMTOOLS_VIEW( FIND_CIRC_ALIGN.out.aligned.join( SAMTOOLS_INDEX.out.bai ), ch_fasta, [] ) FIND_CIRC_ANCHORS( SAMTOOLS_VIEW.out.bam ) - FIND_CIRC( FIND_CIRC_ANCHORS.out.anchors, bowtie2_index.collect(), fasta ) + FIND_CIRC( FIND_CIRC_ANCHORS.out.anchors, bowtie2_index, fasta ) find_circ_filter = FIND_CIRC.out.bed.map{ meta, bed -> [ meta + [tool: "find_circ"], bed ] } FIND_CIRC_FILTER( find_circ_filter, bsj_reads ) @@ -191,7 +191,7 @@ workflow CIRCRNA_DISCOVERY { // MAPSPLICE_REFERENCE( gtf ) - MAPSPLICE_ALIGN( reads, bowtie_index.collect(), chromosomes, gtf ) + MAPSPLICE_ALIGN( reads, bowtie_index, chromosomes, gtf ) MAPSPLICE_PARSE( MAPSPLICE_ALIGN.out.raw_fusions ) MAPSPLICE_ANNOTATE( MAPSPLICE_PARSE.out.junction, fasta, MAPSPLICE_REFERENCE.out.txt ) mapsplice_filter = MAPSPLICE_ANNOTATE.out.txt.map{ meta, txt -> [ meta + [tool: "mapsplice"], txt ] } diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index b27e226d..8c7a5994 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -19,7 +19,7 @@ workflow PREPARE_GENOME { // MapSplice cannot deal with extra field in the fasta headers // this removes all additional fields in the headers of the input fasta file - if( params.tool.contains('mapsplice') && params.module.contains('circrna_discovery') ) { + if( params.module.contains('circrna_discovery') && params.tool.contains('mapsplice') ) { CLEAN_FASTA(ch_fasta, []) ch_fasta = CLEAN_FASTA.out.output } @@ -41,22 +41,23 @@ workflow PREPARE_GENOME { SEGEMEHL_INDEX(ch_fasta.map{ meta, fasta -> fasta}) // TODO: Add support for meta // Collect versions - ch_versions = ch_versions.mix(BOWTIE_BUILD.out.versions) - ch_versions = ch_versions.mix(BOWTIE2_BUILD.out.versions) - ch_versions = ch_versions.mix(BWA_INDEX.out.versions) - ch_versions = ch_versions.mix(HISAT2_EXTRACTSPLICESITES.out.versions) - ch_versions = ch_versions.mix(HISAT2_BUILD.out.versions) - ch_versions = ch_versions.mix(SEGEMEHL_INDEX.out.versions) - ch_versions = ch_versions.mix(STAR_GENOMEGENERATE.out.versions) + ch_versions = ch_versions.mix(BOWTIE_BUILD.out.versions, + BOWTIE2_BUILD.out.versions, + BWA_INDEX.out.versions, + HISAT2_EXTRACTSPLICESITES.out.versions, + HISAT2_BUILD.out.versions, + SEGEMEHL_INDEX.out.versions, + STAR_GENOMEGENERATE.out.versions) emit: - bowtie = BOWTIE_BUILD.out.index - bowtie2 = BOWTIE2_BUILD.out.index - bwa = BWA_INDEX.out.index + bowtie = params.bowtie ?: BOWTIE_BUILD.out.index + segemehl = params.segemehl ?: SEGEMEHL_INDEX.out.index + bowtie2 = params.bowtie2 ? Channel.value([[id: "bowtie2"], file(params.bowtie2, checkIfExists: true)]) : BOWTIE2_BUILD.out.index.collect() + bwa = params.bwa ? Channel.value([[id: "bwa"], file(params.bwa, checkIfExists: true)]) : BWA_INDEX.out.index.collect() + hisat2 = params.hisat2 ? Channel.value([[id: "hisat2"], file(params.hisat2, checkIfExists: true)]) : HISAT2_BUILD.out.index.collect() + star = params.star ? Channel.value([[id: "star"], file(params.star, checkIfExists: true)]) : STAR_GENOMEGENERATE.out.index.collect() chromosomes = SEQKIT_SPLIT.out.split - hisat2 = HISAT2_BUILD.out.index.collect() - star = STAR_GENOMEGENERATE.out.index.collect() - segemehl = SEGEMEHL_INDEX.out.index splice_sites = HISAT2_EXTRACTSPLICESITES.out.txt.collect() + versions = ch_versions } diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index f090f857..4a614505 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -110,14 +110,13 @@ workflow CIRCRNA { ch_gtf ) - // Stage the indices via newly created indices, iGenomes or empty list if tool not selected. - bowtie_index = params.fasta ? params.bowtie ? Channel.fromPath(params.bowtie) : PREPARE_GENOME.out.bowtie : [] - bowtie2_index = params.fasta ? params.bowtie2 ? Channel.fromPath(params.bowtie2).map{ it -> [[id:'bowtie2'], it] } : PREPARE_GENOME.out.bowtie2 : [] - bwa_index = params.fasta ? params.bwa ? Channel.fromPath(params.bwa).map{ it -> [[id:'bwa'], it] } : PREPARE_GENOME.out.bwa : [] - chromosomes = params.fasta && ( params.tool.contains('mapsplice') || params.tool.contains('find_circ') ) ? PREPARE_GENOME.out.chromosomes : [] - hisat2_index = params.fasta ? params.hisat2 && ( params.tool.contains('ciriquant') || params.module.contains('differential_expression') ) ? Channel.fromPath(params.hisat2).map{ [[id:"hisat2"], it]} : PREPARE_GENOME.out.hisat2 : [] - star_index = params.fasta ? params.star ? Channel.fromPath(params.star).map{[[id:'star'], it]}: PREPARE_GENOME.out.star : [] - segemehl_index = params.fasta ? params.segemehl ? Channel.fromPath(params.segemehl) : PREPARE_GENOME.out.segemehl : [] + bowtie_index = PREPARE_GENOME.out.bowtie + bowtie2_index = PREPARE_GENOME.out.bowtie2 + bwa_index = PREPARE_GENOME.out.bwa + chromosomes = PREPARE_GENOME.out.chromosomes + hisat2_index = PREPARE_GENOME.out.hisat2 + star_index = PREPARE_GENOME.out.star + segemehl_index = PREPARE_GENOME.out.segemehl ch_versions = ch_versions.mix(PREPARE_GENOME.out.versions) // MODULE: Run FastQC, trimgalore! From f741c75c47a2c64e07e1e16d3ea302f6f6b074f1 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 08:27:50 +0100 Subject: [PATCH 155/491] Add defaults for previously undefined parameters --- nextflow.config | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nextflow.config b/nextflow.config index 4c3bfcd5..628468c4 100644 --- a/nextflow.config +++ b/nextflow.config @@ -27,6 +27,10 @@ params { genome = null igenomes_base = 's3://ngi-igenomes/igenomes/' igenomes_ignore = false + bowtie = null + bowtie2 = null + bwa = null + star = null hisat2 = null hisat2_build_memory = '200.GB' segemehl = null From c2089ca697f581c5d313faef959aa62458aac34d Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 08:39:45 +0100 Subject: [PATCH 156/491] Linting --- subworkflows/local/prepare_genome.nf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 8c7a5994..0118cf2d 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -42,12 +42,12 @@ workflow PREPARE_GENOME { // Collect versions ch_versions = ch_versions.mix(BOWTIE_BUILD.out.versions, - BOWTIE2_BUILD.out.versions, - BWA_INDEX.out.versions, - HISAT2_EXTRACTSPLICESITES.out.versions, - HISAT2_BUILD.out.versions, - SEGEMEHL_INDEX.out.versions, - STAR_GENOMEGENERATE.out.versions) + BOWTIE2_BUILD.out.versions, + BWA_INDEX.out.versions, + HISAT2_EXTRACTSPLICESITES.out.versions, + HISAT2_BUILD.out.versions, + SEGEMEHL_INDEX.out.versions, + STAR_GENOMEGENERATE.out.versions) emit: bowtie = params.bowtie ?: BOWTIE_BUILD.out.index From e691f5c800cf3ea934717df4156bb7f82be94563 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 17:11:41 +0100 Subject: [PATCH 157/491] Fix indent --- conf/test.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/test.config b/conf/test.config index 0c75023b..af8b601e 100644 --- a/conf/test.config +++ b/conf/test.config @@ -30,5 +30,5 @@ params { module = "circrna_discovery,mirna_prediction,differential_expression" outdir = "results/" bsj_reads = 2 - species_id = "cel" + species_id = "cel" } From 0ee988b0ba81a5201485d5b1eb1879690893f45b Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 30 Mar 2024 08:01:36 +0100 Subject: [PATCH 158/491] Make some parameters non-required when according modules are disabled --- main.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main.nf b/main.nf index 544e9738..a360b046 100644 --- a/main.nf +++ b/main.nf @@ -56,11 +56,11 @@ workflow NFCORE_CIRCRNA { // WORKFLOW: Run nf-core/circrna workflow // ch_samplesheet = Channel.fromSamplesheet("input") - ch_phenotype = Channel.value([[id: "phenotype"], file(params.phenotype, checkIfExists:true)]) ch_fasta = Channel.value([[id: "fasta"], file(params.fasta, checkIfExists:true)]) ch_gtf = Channel.value([[id: "gtf"], file(params.gtf, checkIfExists:true)]) - ch_mature = Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) - ch_species = Channel.value(params.species_id) + ch_mature = params.module.split(',').contains('mirna_prediction') ? Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) : Channel.empty() + ch_phenotype = params.module.split(',').contains('differential_expression') ? Channel.value([[id: "phenotype"], file(params.phenotype, checkIfExists:true)]) : Channel.empty() + ch_species = params.module.split(',').contains('differential_expression') ? Channel.value(params.species_id) : Channel.empty() CIRCRNA ( ch_samplesheet, From 30af2097d27ebad532dbc1264d5e607f70596ef0 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:06:18 +0200 Subject: [PATCH 159/491] fix hisast2 index bug in yml file --- modules/local/ciriquant/yml/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/ciriquant/yml/main.nf b/modules/local/ciriquant/yml/main.nf index 4eb2d06f..42de10dc 100644 --- a/modules/local/ciriquant/yml/main.nf +++ b/modules/local/ciriquant/yml/main.nf @@ -19,7 +19,7 @@ process CIRIQUANT_YML { task.ext.when == null || task.ext.when script: - hisat2_prefix = meta2.id + hisat2_prefix = fasta.toString() - ~/.(fa|fasta)$/ fasta_path = fasta.toRealPath() gtf_path = gtf.toRealPath() bwa_path = bwa.toRealPath() From a860bf8d8e96a63443d9314fade2524cf6c2af8a Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:07:01 +0200 Subject: [PATCH 160/491] fix bug to make dir --- modules/local/ciriquant/ciriquant/main.nf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/local/ciriquant/ciriquant/main.nf b/modules/local/ciriquant/ciriquant/main.nf index 3ad0c34a..31d80e3a 100644 --- a/modules/local/ciriquant/ciriquant/main.nf +++ b/modules/local/ciriquant/ciriquant/main.nf @@ -24,6 +24,9 @@ process CIRIQUANT { prefix = task.ext.prefix ?: "${meta.id}" def VERSION = '2.1.0' """ + mkdir -p ${prefix} + mkdir -p ${prefix}/circ + touch ${prefix}/circ/${prefix}.ciri CIRIquant \\ -t ${task.cpus} \\ -1 ${reads[0]} \\ From 63cfd78d1ca4c1d61cb81aaafaefecc3662f1aed Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:55:51 +0200 Subject: [PATCH 161/491] cleaner way to set hisat2_prefix --- modules/local/ciriquant/yml/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/ciriquant/yml/main.nf b/modules/local/ciriquant/yml/main.nf index 42de10dc..89c7048f 100644 --- a/modules/local/ciriquant/yml/main.nf +++ b/modules/local/ciriquant/yml/main.nf @@ -19,7 +19,7 @@ process CIRIQUANT_YML { task.ext.when == null || task.ext.when script: - hisat2_prefix = fasta.toString() - ~/.(fa|fasta)$/ + hisat2_prefix = fasta.baseName fasta_path = fasta.toRealPath() gtf_path = gtf.toRealPath() bwa_path = bwa.toRealPath() From cf0a05519a95a40994d6037644e2ef87c6cf4d31 Mon Sep 17 00:00:00 2001 From: MariekeVromman <74721287+MariekeVromman@users.noreply.github.com> Date: Thu, 11 Apr 2024 16:03:41 +0200 Subject: [PATCH 162/491] revert back changes for testing --- modules/local/ciriquant/ciriquant/main.nf | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/local/ciriquant/ciriquant/main.nf b/modules/local/ciriquant/ciriquant/main.nf index 31d80e3a..3ad0c34a 100644 --- a/modules/local/ciriquant/ciriquant/main.nf +++ b/modules/local/ciriquant/ciriquant/main.nf @@ -24,9 +24,6 @@ process CIRIQUANT { prefix = task.ext.prefix ?: "${meta.id}" def VERSION = '2.1.0' """ - mkdir -p ${prefix} - mkdir -p ${prefix}/circ - touch ${prefix}/circ/${prefix}.ciri CIRIquant \\ -t ${task.cpus} \\ -1 ${reads[0]} \\ From 1c9d74e396c2e27cf5021b89577f1370858a81a7 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 15 Apr 2024 13:51:13 +0200 Subject: [PATCH 163/491] Add parameter for setting STAR limitSjdbInsertNsj --- conf/modules.config | 8 ++++++++ nextflow.config | 1 + nextflow_schema.json | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/conf/modules.config b/conf/modules.config index 875f83ee..bf2cf087 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -197,6 +197,7 @@ if (!params.skip_trimming) { "--outReadsUnmapped None", "--readFilesCommand zcat", "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--limitSjdbInsertNsj ${params.limitSjdbInsertNsj}", "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() @@ -228,6 +229,7 @@ if (!params.skip_trimming) { "--readFilesCommand zcat", "--sjdbFileChrStartEnd dataset.SJ.out.tab", "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--limitSjdbInsertNsj ${params.limitSjdbInsertNsj}", "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() @@ -395,6 +397,7 @@ if (!params.skip_trimming) { "--outReadsUnmapped None", "--readFilesCommand zcat", "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--limitSjdbInsertNsj ${params.limitSjdbInsertNsj}", "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() @@ -426,6 +429,7 @@ if (!params.skip_trimming) { "--readFilesCommand zcat", "--sjdbFileChrStartEnd dataset.SJ.out.tab", "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--limitSjdbInsertNsj ${params.limitSjdbInsertNsj}", "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() @@ -447,6 +451,7 @@ if (!params.skip_trimming) { "--outReadsUnmapped None", "--readFilesCommand zcat", "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--limitSjdbInsertNsj ${params.limitSjdbInsertNsj}", "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() @@ -479,6 +484,7 @@ if (!params.skip_trimming) { "--readFilesCommand zcat", "--sjdbFileChrStartEnd dataset.SJ.out.tab", "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--limitSjdbInsertNsj ${params.limitSjdbInsertNsj}", "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() @@ -500,6 +506,7 @@ if (!params.skip_trimming) { "--outReadsUnmapped None", "--readFilesCommand zcat", "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--limitSjdbInsertNsj ${params.limitSjdbInsertNsj}", "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() @@ -532,6 +539,7 @@ if (!params.skip_trimming) { "--readFilesCommand zcat", "--sjdbFileChrStartEnd dataset.SJ.out.tab", "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", + "--limitSjdbInsertNsj ${params.limitSjdbInsertNsj}", "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() diff --git a/nextflow.config b/nextflow.config index 628468c4..257145b9 100644 --- a/nextflow.config +++ b/nextflow.config @@ -54,6 +54,7 @@ params { alignSJDBoverhangMin = 10 chimSegmentMin = 10 sjdboverhang = 100 + limitSjdbInsertNsj = 1000000 //> MAPSPLICE seglen = 25 diff --git a/nextflow_schema.json b/nextflow_schema.json index 912bd12b..3cf5fd34 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -125,6 +125,11 @@ "description": "Minimum overhang for annotated junctions", "default": 10 }, + "limitSjdbInsertNsj": { + "type": "integer", + "description": "Maximum number of junction to be inserted to the genome on the fly at the mapping stage, including those from annotations and those detected in the 1st step of the 2-pass run", + "default": 1000000 + }, "chimSegmentMin": { "type": "integer", "description": "Minimum length of chimeric segment length. Must be set to a positive value to detect circular junctions.", From e14ceae239324ca5b5fe4b9c5ab4c1612b6ec1b7 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 19 Apr 2024 10:23:12 +0200 Subject: [PATCH 164/491] Remove problematic ciriquant-yml process --- modules/local/ciriquant/ciriquant/main.nf | 20 ++++++++++-- modules/local/ciriquant/yml/main.nf | 40 ----------------------- subworkflows/local/circrna_discovery.nf | 4 +-- 3 files changed, 19 insertions(+), 45 deletions(-) delete mode 100644 modules/local/ciriquant/yml/main.nf diff --git a/modules/local/ciriquant/ciriquant/main.nf b/modules/local/ciriquant/ciriquant/main.nf index 3ad0c34a..acf435a6 100644 --- a/modules/local/ciriquant/ciriquant/main.nf +++ b/modules/local/ciriquant/ciriquant/main.nf @@ -9,7 +9,10 @@ process CIRIQUANT { input: tuple val(meta), path(reads) - path yml + tuple val(meta2), path(gtf) + tuple val(meta3), path(fasta) + tuple val(meta4), path(bwa) + tuple val(meta5), path(hisat2) output: tuple val(meta), path("${prefix}/${prefix}.gtf"), emit: gtf @@ -24,11 +27,24 @@ process CIRIQUANT { prefix = task.ext.prefix ?: "${meta.id}" def VERSION = '2.1.0' """ + BWA=`which bwa` + HISAT2=`which hisat2` + STRINGTIE=`which stringtie` + SAMTOOLS=`which samtools` + + BWA_FILE=`ls ${bwa}/*.bwt` + BWA_PREFIX=`basename \$BWA_FILE .bwt` + + HISAT2_FILE=`ls ${hisat2}/*.1.ht2` + HISAT2_PREFIX=`basename \$HISAT2_FILE .1.ht2` + + printf "name: ciriquant\\ntools:\\n bwa: \$BWA\\n hisat2: \$HISAT2\\n stringtie: \$STRINGTIE\\n samtools: \$SAMTOOLS\\n\\nreference:\\n fasta: ${fasta}\\n gtf: ${gtf}\\n bwa_index: ${bwa}/\$BWA_PREFIX\\n hisat_index: ${hisat2}/\$HISAT2_PREFIX" > config.yml + CIRIquant \\ -t ${task.cpus} \\ -1 ${reads[0]} \\ -2 ${reads[1]} \\ - --config $yml \\ + --config config.yml \\ --no-gene \\ -o ${prefix} \\ -p ${prefix} diff --git a/modules/local/ciriquant/yml/main.nf b/modules/local/ciriquant/yml/main.nf deleted file mode 100644 index 89c7048f..00000000 --- a/modules/local/ciriquant/yml/main.nf +++ /dev/null @@ -1,40 +0,0 @@ -process CIRIQUANT_YML { - label 'process_single' - - conda "bioconda::ciriquant=1.1.2" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/ciriquant:1.1.2--pyhdfd78af_2' : - 'quay.io/biocontainers/ciriquant:1.1.2--pyhdfd78af_2' }" - - input: - tuple val(meta), path(gtf) - tuple val(meta2), path(fasta) - path bwa - path hisat2 - - output: - path "travis.yml" , emit: yml - - when: - task.ext.when == null || task.ext.when - - script: - hisat2_prefix = fasta.baseName - fasta_path = fasta.toRealPath() - gtf_path = gtf.toRealPath() - bwa_path = bwa.toRealPath() - hisat2_path = hisat2.toRealPath() - """ - BWA=`which bwa` - HISAT2=`which hisat2` - STRINGTIE=`which stringtie` - SAMTOOLS=`which samtools` - - # Get first file in bwa index directory - BWA_FILE=`ls ${bwa_path}/*.bwt` - BWA_FILE=`basename \$BWA_FILE .bwt` - - touch travis.yml - printf "name: ciriquant\ntools:\n bwa: \$BWA\n hisat2: \$HISAT2\n stringtie: \$STRINGTIE\n samtools: \$SAMTOOLS\n\nreference:\n fasta: ${fasta_path}\n gtf: ${gtf_path}\n bwa_index: ${bwa_path}/\$BWA_FILE\n hisat_index: ${hisat2_path}/${hisat2_prefix}" >> travis.yml - """ -} diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index b51c821f..0708ee37 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -7,7 +7,6 @@ include { SAMTOOLS_INDEX } from '../../modules/n include { FIND_CIRC_ANCHORS } from '../../modules/local/find_circ/anchors/main' include { FIND_CIRC } from '../../modules/local/find_circ/find_circ/main' include { FIND_CIRC_FILTER } from '../../modules/local/find_circ/filter/main' -include { CIRIQUANT_YML } from '../../modules/local/ciriquant/yml/main' include { CIRIQUANT } from '../../modules/local/ciriquant/ciriquant/main' include { CIRIQUANT_FILTER } from '../../modules/local/ciriquant/filter/main' include { CIRCRNA_FINDER_FILTER } from '../../modules/local/circrna_finder/filter/main' @@ -141,8 +140,7 @@ workflow CIRCRNA_DISCOVERY { // only need path to bwa, only need path to hisat2. // do not want to upset the collect declr for all indices just for this. - CIRIQUANT_YML( ch_gtf, ch_fasta, bwa_index.map{ meta, index -> return index }, hisat2_index.map{ meta, index -> return index } ) - CIRIQUANT( reads, CIRIQUANT_YML.out.yml.collect() ) + CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index ) CIRIQUANT_FILTER( CIRIQUANT.out.gtf.map{ meta, gtf -> [ meta + [tool: "ciriquant"], gtf ] }, bsj_reads ) ch_versions = ch_versions.mix(CIRIQUANT.out.versions) From ff100b332a75525d56cb0a7b343525bc2044dc03 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Wed, 28 Feb 2024 19:56:01 +0100 Subject: [PATCH 165/491] Implement common quantification --- conf/modules.config | 9 ++++ modules.json | 5 +++ modules/local/psirc/combine/main.nf | 39 +++++++++++++++++ modules/local/psirc/index/main.nf | 17 ++++++++ modules/local/psirc/quant/main.nf | 23 ++++++++++ .../quantification/transcriptome/main.nf | 42 +++++++++++++++++++ .../nf-core/bedtools/getfasta/environment.yml | 7 ++++ modules/nf-core/bedtools/getfasta/main.nf | 37 ++++++++++++++++ modules/nf-core/bedtools/getfasta/meta.yml | 36 ++++++++++++++++ subworkflows/local/quantification.nf | 34 +++++++++++++++ workflows/circrna/main.nf | 8 ++++ 11 files changed, 257 insertions(+) create mode 100644 modules/local/psirc/combine/main.nf create mode 100644 modules/local/psirc/index/main.nf create mode 100644 modules/local/psirc/quant/main.nf create mode 100644 modules/local/quantification/transcriptome/main.nf create mode 100644 modules/nf-core/bedtools/getfasta/environment.yml create mode 100644 modules/nf-core/bedtools/getfasta/main.nf create mode 100644 modules/nf-core/bedtools/getfasta/meta.yml create mode 100644 subworkflows/local/quantification.nf diff --git a/conf/modules.config b/conf/modules.config index bf2cf087..d0d87018 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -667,6 +667,15 @@ if (!params.skip_trimming) { ] } + withName: COUNTS_TO_BED { + ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$4, \".\", \$4 }'" + ext.suffix = "bed" + } + + withName: TRANSCRIPTOME_FASTA { + ext.args = "-nameOnly" + } + withName: TARGETSCAN_DATABASE { ext.when = { params.module.split(',').contains('mirna_prediction') } publishDir = [ diff --git a/modules.json b/modules.json index c7beb988..8aec025c 100644 --- a/modules.json +++ b/modules.json @@ -5,6 +5,11 @@ "https://github.com/nf-core/modules.git": { "modules": { "nf-core": { + "bedtools/getfasta": { + "branch": "master", + "git_sha": "3b248b84694d1939ac4bb33df84bf6233a34d668", + "installed_by": ["modules"] + }, "bedtools/intersect": { "branch": "master", "git_sha": "575e1bc54b083fb15e7dd8b5fcc40bea60e8ce83", diff --git a/modules/local/psirc/combine/main.nf b/modules/local/psirc/combine/main.nf new file mode 100644 index 00000000..30481139 --- /dev/null +++ b/modules/local/psirc/combine/main.nf @@ -0,0 +1,39 @@ +process PSIRC_COMBINE { + label 'process_single' + + conda "conda-forge::mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6==fccb0c41a243c639e11dd1be7b74f563e624fcca-0" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0': + 'biocontainers/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0' }" + + input: + path(files) + + output: + path("counts.tsv"), emit: est_counts + path("tpm.tsv"), emit: tpm + + + script: + """ + #!/usr/bin/env python + + import os + import pandas as pd + + files = "${files}".split(" ") + + counts_df = pd.DataFrame() + tpm_df = pd.DataFrame() + + for f in files: + sample_name = os.path.basename(f)[:-len(".tsv")] + df = pd.read_csv(f, sep="\\t", index_col=0) + + counts_df[sample_name] = df["est_counts"] + tpm_df[sample_name] = df["tpm"] + + counts_df.to_csv("counts.tsv", sep="\\t") + tpm_df.to_csv("tpm.tsv", sep="\\t") + """ +} diff --git a/modules/local/psirc/index/main.nf b/modules/local/psirc/index/main.nf new file mode 100644 index 00000000..bda903d1 --- /dev/null +++ b/modules/local/psirc/index/main.nf @@ -0,0 +1,17 @@ +process PSIRC_INDEX { + tag "${meta.id}" + label 'process_single' + + container "registry.hub.docker.com/bigdatainbiomedicine/psirc" + + input: + tuple val(meta), path(fasta) + + output: + tuple val(meta), path("psirc.index") + + script: + """ + psirc-quant index -i psirc.index --make-unique $fasta + """ +} diff --git a/modules/local/psirc/quant/main.nf b/modules/local/psirc/quant/main.nf new file mode 100644 index 00000000..87ddbb36 --- /dev/null +++ b/modules/local/psirc/quant/main.nf @@ -0,0 +1,23 @@ +process PSIRC_QUANT { + tag "${meta.id}" + label 'process_medium' + + container "registry.hub.docker.com/bigdatainbiomedicine/psirc" + + input: + tuple val(meta), path(reads) + tuple val(meta2), path(index) + + output: + tuple val(meta), path("output/${meta.id}.tsv"), emit: abundance_tsv + tuple val(meta), path("output/${meta.id}.h5"), emit: abundance_h5 + + script: + def single_end = meta.single_end ? "--single -l 76 -s 20" : "" + """ + psirc-quant quant -t $task.cpus -i $index -o output $single_end $reads + + mv output/abundance.tsv output/${meta.id}.tsv + mv output/abundance.h5 output/${meta.id}.h5 + """ +} diff --git a/modules/local/quantification/transcriptome/main.nf b/modules/local/quantification/transcriptome/main.nf new file mode 100644 index 00000000..a21d1429 --- /dev/null +++ b/modules/local/quantification/transcriptome/main.nf @@ -0,0 +1,42 @@ +process EXTRACT_TRANSCRIPTOME { + tag "$meta.id" + label 'process_single' + + conda "bioconda::pandas=1.5.2" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : + 'quay.io/biocontainers/pandas:1.5.2' }" + + input: + tuple val(meta), path(gtf) + + output: + tuple val(meta), path("${meta.id}.transcriptome.bed"), emit: bed + + script: + """ + #!/usr/bin/env python + + import pandas as pd + + columns = ["seqname", "source", "feature", "start", "end", "score", "strand", "frame", "attributes"] + + df = pd.read_csv("${gtf}", sep="\\t", comment="#", names=columns, header=None) + + # Keep only transcript features + df = df[df['feature'] == 'transcript'] + + # Convert attributes to a dictionary + df['attributes'] = df['attributes'].apply(lambda row: dict([[value.strip(r'"') for value in entry.strip().split(' ')] for entry in row.split(';') if entry])) + + # Extract gene_id and transcript_id + df['gene_id'] = df['attributes'].apply(lambda row: row['gene_id']) + df['transcript_id'] = df['attributes'].apply(lambda row: row['transcript_id']) + df['name'] = df['gene_id'] + ":" + df['transcript_id'] + + # Format as bed + df = df[['seqname', 'start', 'end', 'name', 'score', 'strand']] + + df.to_csv("${meta.id}.transcriptome.bed", sep="\\t", index=False, header=False) + """ +} diff --git a/modules/nf-core/bedtools/getfasta/environment.yml b/modules/nf-core/bedtools/getfasta/environment.yml new file mode 100644 index 00000000..a89401f2 --- /dev/null +++ b/modules/nf-core/bedtools/getfasta/environment.yml @@ -0,0 +1,7 @@ +name: bedtools_getfasta +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::bedtools=2.31.1 diff --git a/modules/nf-core/bedtools/getfasta/main.nf b/modules/nf-core/bedtools/getfasta/main.nf new file mode 100644 index 00000000..50549c7d --- /dev/null +++ b/modules/nf-core/bedtools/getfasta/main.nf @@ -0,0 +1,37 @@ +process BEDTOOLS_GETFASTA { + tag "$bed" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/bedtools:2.31.1--hf5e1c6e_0' : + 'biocontainers/bedtools:2.31.1--hf5e1c6e_0' }" + + input: + path bed + path fasta + + output: + path "*.fa" , emit: fasta + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${bed.baseName}" + """ + bedtools \\ + getfasta \\ + $args \\ + -fi $fasta \\ + -bed $bed \\ + -fo ${prefix}.fa + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + bedtools: \$(bedtools --version | sed -e "s/bedtools v//g") + END_VERSIONS + """ +} diff --git a/modules/nf-core/bedtools/getfasta/meta.yml b/modules/nf-core/bedtools/getfasta/meta.yml new file mode 100644 index 00000000..25fb19a1 --- /dev/null +++ b/modules/nf-core/bedtools/getfasta/meta.yml @@ -0,0 +1,36 @@ +name: bedtools_getfasta +description: extract sequences in a FASTA file based on intervals defined in a feature file. +keywords: + - bed + - fasta + - getfasta +tools: + - bedtools: + description: | + A set of tools for genomic analysis tasks, specifically enabling genome arithmetic (merge, count, complement) on various file types. + documentation: https://bedtools.readthedocs.io/en/latest/content/tools/intersect.html + licence: ["MIT"] +input: + - bed: + type: file + description: Bed feature file + pattern: "*.{bed}" + - fasta: + type: file + description: Input fasta file + pattern: "*.{fa,fasta}" +output: + - fasta: + type: file + description: Output fasta file with extracted sequences + pattern: "*.{fa}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@joseespinosa" + - "@drpatelh" +maintainers: + - "@joseespinosa" + - "@drpatelh" diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf new file mode 100644 index 00000000..e7502fec --- /dev/null +++ b/subworkflows/local/quantification.nf @@ -0,0 +1,34 @@ +include { EXTRACT_TRANSCRIPTOME } from '../../modules/local/quantification/transcriptome/main' +include { BEDTOOLS_GETFASTA as TRANSCRIPTOME_FASTA } from '../../modules/nf-core/bedtools/getfasta/main' +include { GAWK as COUNTS_TO_BED } from '../../modules/nf-core/gawk/main' +include { CAT_CAT as CAT_TRANSCRIPTOME } from '../../modules/nf-core/cat/cat/main' +include { PSIRC_INDEX } from '../../modules/local/psirc/index/main' +include { PSIRC_QUANT } from '../../modules/local/psirc/quant/main' +include { PSIRC_COMBINE } from '../../modules/local/psirc/combine/main' + +workflow QUANTIFICATION { + take: + ch_gtf + ch_fasta + counts + reads + + main: + EXTRACT_TRANSCRIPTOME(ch_gtf) + COUNTS_TO_BED(counts.map{counts -> [[id: "counts"], counts]}, []) + + CAT_TRANSCRIPTOME( + EXTRACT_TRANSCRIPTOME.out.bed.map{meta, bed -> bed}.mix( + COUNTS_TO_BED.out.output.map{meta, bed -> bed} + ).collect().map(beds -> [[id: "transcriptome"], beds]) + ) + + TRANSCRIPTOME_FASTA( + CAT_TRANSCRIPTOME.out.file_out.map{meta, bed -> bed}, + ch_fasta.map{meta, fasta -> fasta} + ) + + PSIRC_INDEX(TRANSCRIPTOME_FASTA.out.fasta.map{fasta -> [[id: "transcriptome"], fasta]}) + PSIRC_QUANT(reads, PSIRC_INDEX.out.collect()) + PSIRC_COMBINE( PSIRC_QUANT.out.abundance_tsv.map{ meta, data -> data }.collect() ) +} diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 4a614505..0fa1446c 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -29,6 +29,7 @@ include { validateInputSamplesheet } from '../../subworkflows/local/util include { softwareVersionsToYAML } from '../../subworkflows/nf-core/utils_nfcore_pipeline' include { PREPARE_GENOME } from '../../subworkflows/local/prepare_genome' include { CIRCRNA_DISCOVERY } from '../../subworkflows/local/circrna_discovery' +include { QUANTIFICATION } from '../../subworkflows/local/quantification' include { MIRNA_PREDICTION } from '../../subworkflows/local/mirna_prediction' include { DIFFERENTIAL_EXPRESSION } from '../../subworkflows/local/differential_expression' @@ -152,6 +153,13 @@ workflow CIRCRNA { ch_versions = ch_versions.mix(CIRCRNA_DISCOVERY.out.versions) + QUANTIFICATION( + ch_gtf, + ch_fasta, + CIRCRNA_DISCOVERY.out.dea_matrix, + FASTQC_TRIMGALORE.out.reads + ) + // // 3. miRNA prediction // From 27b17a2708ff87df2df6b94d43a760006af8f944 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 07:36:20 +0100 Subject: [PATCH 166/491] Add marking of circRNAs in quantification --- conf/modules.config | 8 ++++++++ subworkflows/local/quantification.nf | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index d0d87018..cfc67d5a 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -676,6 +676,14 @@ if (!params.skip_trimming) { ext.args = "-nameOnly" } + withName: MARK_CIRCULAR { + // GAWK process that marks FASTA headers. + // Leaves headers starting with "ENS" and non-header lines as is. + // Adds "\tC" to the end of the header for all other headers + ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (!/^>/ || /^>ENS/) { print } else { print \$1 \"\\tC\" } }'" + ext.suffix = "marked.fasta" + } + withName: TARGETSCAN_DATABASE { ext.when = { params.module.split(',').contains('mirna_prediction') } publishDir = [ diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index e7502fec..33b32cca 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -2,6 +2,7 @@ include { EXTRACT_TRANSCRIPTOME } from '../../modules/local/q include { BEDTOOLS_GETFASTA as TRANSCRIPTOME_FASTA } from '../../modules/nf-core/bedtools/getfasta/main' include { GAWK as COUNTS_TO_BED } from '../../modules/nf-core/gawk/main' include { CAT_CAT as CAT_TRANSCRIPTOME } from '../../modules/nf-core/cat/cat/main' +include { GAWK as MARK_CIRCULAR } from '../../modules/nf-core/gawk/main' include { PSIRC_INDEX } from '../../modules/local/psirc/index/main' include { PSIRC_QUANT } from '../../modules/local/psirc/quant/main' include { PSIRC_COMBINE } from '../../modules/local/psirc/combine/main' @@ -27,8 +28,11 @@ workflow QUANTIFICATION { CAT_TRANSCRIPTOME.out.file_out.map{meta, bed -> bed}, ch_fasta.map{meta, fasta -> fasta} ) + ch_transcriptome_fasta = TRANSCRIPTOME_FASTA.out.fasta.map{fasta -> [[id: "transcriptome"], fasta]} - PSIRC_INDEX(TRANSCRIPTOME_FASTA.out.fasta.map{fasta -> [[id: "transcriptome"], fasta]}) + MARK_CIRCULAR(ch_transcriptome_fasta, []) + + PSIRC_INDEX(MARK_CIRCULAR.out.output) PSIRC_QUANT(reads, PSIRC_INDEX.out.collect()) PSIRC_COMBINE( PSIRC_QUANT.out.abundance_tsv.map{ meta, data -> data }.collect() ) } From 1d81d4b99c8f427cbb37c1b3e331b8bdf2b87907 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 08:29:23 +0100 Subject: [PATCH 167/491] Increase resources for PSIRC --- modules/local/psirc/index/main.nf | 2 +- modules/local/psirc/quant/main.nf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/local/psirc/index/main.nf b/modules/local/psirc/index/main.nf index bda903d1..daca0402 100644 --- a/modules/local/psirc/index/main.nf +++ b/modules/local/psirc/index/main.nf @@ -1,6 +1,6 @@ process PSIRC_INDEX { tag "${meta.id}" - label 'process_single' + label 'process_high' container "registry.hub.docker.com/bigdatainbiomedicine/psirc" diff --git a/modules/local/psirc/quant/main.nf b/modules/local/psirc/quant/main.nf index 87ddbb36..88ecef04 100644 --- a/modules/local/psirc/quant/main.nf +++ b/modules/local/psirc/quant/main.nf @@ -1,6 +1,6 @@ process PSIRC_QUANT { tag "${meta.id}" - label 'process_medium' + label 'process_high' container "registry.hub.docker.com/bigdatainbiomedicine/psirc" From eb3b3669d8d289aad63483a65a3ba0db838a8446 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 11:01:11 +0100 Subject: [PATCH 168/491] Implement separation of circular and linear counts --- modules/local/psirc/combine/main.nf | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/modules/local/psirc/combine/main.nf b/modules/local/psirc/combine/main.nf index 30481139..4aa23e6a 100644 --- a/modules/local/psirc/combine/main.nf +++ b/modules/local/psirc/combine/main.nf @@ -10,8 +10,13 @@ process PSIRC_COMBINE { path(files) output: - path("counts.tsv"), emit: est_counts - path("tpm.tsv"), emit: tpm + path("linear_counts.tsv"), emit: linear_counts + path("circular_counts.tsv"), emit: circular_counts + path("counts.tsv"), emit: counts + + path("linear_tpm.tsv"), emit: linear_tpm + path("circular_tpm.tsv"), emit: circular_tpm + path("tpm.tsv"), emit: tpm script: @@ -33,7 +38,13 @@ process PSIRC_COMBINE { counts_df[sample_name] = df["est_counts"] tpm_df[sample_name] = df["tpm"] - counts_df.to_csv("counts.tsv", sep="\\t") - tpm_df.to_csv("tpm.tsv", sep="\\t") + for name, df in [("counts", counts_df), ("tpm", tpm_df)]: + is_linear = df.index.str.startswith("ENS") + linear_df = df[is_linear] + circular_df = df[~is_linear] + + linear_df.to_csv(f"linear_{name}.tsv", sep="\\t") + circular_df.to_csv(f"circular_{name}.tsv", sep="\\t") + df.to_csv(f"{name}.tsv", sep="\\t") """ } From 7176cceafe580e1a49e6dab6e8cfc6229bc40f88 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 12:33:38 +0100 Subject: [PATCH 169/491] Implement aggregation of annotations --- conf/modules.config | 13 ++ modules.json | 5 + .../local/annotation/full_annotation/main.nf | 7 +- modules/nf-core/gnu/sort/environment.yml | 7 + modules/nf-core/gnu/sort/main.nf | 51 +++++++ modules/nf-core/gnu/sort/meta.yml | 41 ++++++ modules/nf-core/gnu/sort/tests/main.nf.test | 120 ++++++++++++++++ .../nf-core/gnu/sort/tests/main.nf.test.snap | 136 ++++++++++++++++++ .../gnu/sort/tests/sort_complex.config | 6 + .../gnu/sort/tests/sort_simple_bed.config | 6 + .../gnu/sort/tests/sort_simple_genome.config | 6 + modules/nf-core/gnu/sort/tests/tags.yml | 2 + subworkflows/local/circrna_discovery.nf | 4 + 13 files changed, 402 insertions(+), 2 deletions(-) create mode 100644 modules/nf-core/gnu/sort/environment.yml create mode 100644 modules/nf-core/gnu/sort/main.nf create mode 100644 modules/nf-core/gnu/sort/meta.yml create mode 100644 modules/nf-core/gnu/sort/tests/main.nf.test create mode 100644 modules/nf-core/gnu/sort/tests/main.nf.test.snap create mode 100644 modules/nf-core/gnu/sort/tests/sort_complex.config create mode 100644 modules/nf-core/gnu/sort/tests/sort_simple_bed.config create mode 100644 modules/nf-core/gnu/sort/tests/sort_simple_genome.config create mode 100644 modules/nf-core/gnu/sort/tests/tags.yml diff --git a/conf/modules.config b/conf/modules.config index cfc67d5a..5504f876 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -625,6 +625,7 @@ if (!params.skip_trimming) { } withName: ANNOTATION { + ext.prefix = { "${meta.id}.${meta.tool}.annotated" } publishDir = [ path: { "${params.outdir}/circrna_discovery/${meta.tool}/${meta.id}" }, mode: params.publish_dir_mode, @@ -637,6 +638,18 @@ if (!params.skip_trimming) { ext.suffix = "intersect.bed" } + withName: COMBINE_ANNOTATIONS { + ext.args = "-k 1,1 -k2,2n -k3,3n -u" + ext.suffix = "combined.bed" + } + + withName: REMOVE_SCORE { + // AWK command to replace the 5th column with a dot + // input and output are both BED files + ext.args = "-v FS='\\t' -v OFS='\\t' '{ \$5=\".\"; print }'" + ext.suffix = "noscore.bed" + } + withName: FASTA { ext.when = { params.module.split(',').contains('circrna_discovery') } publishDir = [ diff --git a/modules.json b/modules.json index 8aec025c..ed44f1c4 100644 --- a/modules.json +++ b/modules.json @@ -85,6 +85,11 @@ "git_sha": "dc3527855e7358c6d8400828754c0caa5f11698f", "installed_by": ["modules"] }, + "gnu/sort": { + "branch": "master", + "git_sha": "ca199cfe5aa4f1ea3c41302158f0af2cfaa58957", + "installed_by": ["modules"] + }, "hisat2/align": { "branch": "master", "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/full_annotation/main.nf index f06546ac..bf17b2cc 100644 --- a/modules/local/annotation/full_annotation/main.nf +++ b/modules/local/annotation/full_annotation/main.nf @@ -12,12 +12,15 @@ process ANNOTATION { val(exon_boundary) output: - tuple val(meta), path("${meta.id}.annotation.bed"), emit: bed + tuple val(meta), path("${outfile}"), emit: bed path "versions.yml", emit: versions script: + prefix = task.ext.prefix ?: "${meta.id}.annotation" + suffix = task.ext.suffix ?: "bed" + outfile = "${prefix}.${suffix}" """ - annotation.py --input ${intersection} --exon_boundary ${exon_boundary} --output ${meta.id}.annotation.bed + annotation.py --input ${intersection} --exon_boundary ${exon_boundary} --output ${outfile} cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/gnu/sort/environment.yml b/modules/nf-core/gnu/sort/environment.yml new file mode 100644 index 00000000..5c4eb9d1 --- /dev/null +++ b/modules/nf-core/gnu/sort/environment.yml @@ -0,0 +1,7 @@ +name: gnu_sort +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::coreutils=8.25 diff --git a/modules/nf-core/gnu/sort/main.nf b/modules/nf-core/gnu/sort/main.nf new file mode 100644 index 00000000..d0560ee2 --- /dev/null +++ b/modules/nf-core/gnu/sort/main.nf @@ -0,0 +1,51 @@ +process GNU_SORT { + tag "${meta.id}" + label "process_low" + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/coreutils:8.25--1' : + 'biocontainers/coreutils:8.25--1' }" + + input: + tuple val(meta), path(input) + + output: + tuple val(meta), file( "${output_file}" ) , emit: sorted + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + suffix = task.ext.suffix ?: "${input.extension}" + output_file = "${prefix}.${suffix}" + def VERSION = "9.1" // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. + if ("$input" == "$output_file") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" + """ + sort ${args} ${input} > ${output_file} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + coreutils: $VERSION + END_VERSIONS + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + suffix = task.ext.suffix ?: "${input.extension}" + output_file = "${prefix}.${suffix}" + def VERSION = "9.1" + + if ("$input" == "$output_file") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" + """ + touch ${output_file} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + coreutils: $VERSION + END_VERSIONS + """ +} diff --git a/modules/nf-core/gnu/sort/meta.yml b/modules/nf-core/gnu/sort/meta.yml new file mode 100644 index 00000000..9d961750 --- /dev/null +++ b/modules/nf-core/gnu/sort/meta.yml @@ -0,0 +1,41 @@ +name: "gnu_sort" +description: | + Writes a sorted concatenation of file/s +keywords: + - GNU + - sort + - merge compare +tools: + - sort: + description: "Writes a sorted concatenation of file/s" + homepage: "https://github.com/vgl-hub/gfastats" + documentation: "https://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html" + licence: ["GPL"] +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - input: + type: file + description: Draft assembly file + pattern: "*.{txt,bed,interval,genome,bins}" +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - sorted: + type: file + description: The sorted txt file generated by sort + pattern: "*.{txt,bed,interval,genome,bins}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@DLBPointon" +maintainers: + - "@DLBPointon" diff --git a/modules/nf-core/gnu/sort/tests/main.nf.test b/modules/nf-core/gnu/sort/tests/main.nf.test new file mode 100644 index 00000000..e4030187 --- /dev/null +++ b/modules/nf-core/gnu/sort/tests/main.nf.test @@ -0,0 +1,120 @@ +nextflow_process { + + name "Test Process GNU_SORT" + script "modules/nf-core/gnu/sort/main.nf" + process "GNU_SORT" + + tag "modules" + tag "modules_nfcore" + tag "gnu" + tag "gnu/sort" + + test("unsorted_genome_sort") { + config "./sort_simple_bed.config" + + when { + process { + """ + input[0] = [ + [id:'genome_test'], + file(params.test_data['generic']['unsorted_data']['unsorted_text']['genome_file'], + checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() }, + { assert snapshot( + file(process.out.sorted[0][1]).name + ).match("genome_sort") + } + ) + } + + } + + test("unsorted_intervals_sort") { + config "./sort_simple_bed.config" + when { + process { + """ + input[0] = [ + [id:'test'], + file(params.test_data['generic']['unsorted_data']['unsorted_text']['intervals'], + checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() }, + { assert snapshot( + file(process.out.sorted[0][1]).name + ).match("interval_sort") + } + ) + } + + } + + test("unsorted_csv_sort") { + config "./sort_complex.config" + + when { + process { + """ + input[0] = [ + [id:'test'], + file(params.test_data['generic']['unsorted_data']['unsorted_text']['numbers_csv'], + checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() }, + { assert snapshot( + file(process.out.sorted[0][1]).name + ).match("csv_sort") + } + ) + } + + } + + test("unsorted_csv_sort_stub") { + config "./sort_complex.config" + options "-stub" + + when { + process { + """ + input[0] = [ + [id:'test'], + file(params.test_data['generic']['unsorted_data']['unsorted_text']['numbers_csv'], + checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() }, + ) + } + + } + +} diff --git a/modules/nf-core/gnu/sort/tests/main.nf.test.snap b/modules/nf-core/gnu/sort/tests/main.nf.test.snap new file mode 100644 index 00000000..fc20d872 --- /dev/null +++ b/modules/nf-core/gnu/sort/tests/main.nf.test.snap @@ -0,0 +1,136 @@ +{ + "unsorted_csv_sort": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.csv.sorted:md5,0b52d1b4c4a0c6e972c6f94aafd75a1d" + ] + ], + "1": [ + "versions.yml:md5,8ebec31a85721157399cb4faab6e0d26" + ], + "sorted": [ + [ + { + "id": "test" + }, + "test.csv.sorted:md5,0b52d1b4c4a0c6e972c6f94aafd75a1d" + ] + ], + "versions": [ + "versions.yml:md5,8ebec31a85721157399cb4faab6e0d26" + ] + } + ], + "timestamp": "2024-02-22T13:57:33.598003" + }, + "interval_sort": { + "content": [ + "test.bed.sorted" + ], + "timestamp": "2024-02-22T13:57:25.5442" + }, + "unsorted_csv_sort_stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.csv.sorted:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,8ebec31a85721157399cb4faab6e0d26" + ], + "sorted": [ + [ + { + "id": "test" + }, + "test.csv.sorted:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,8ebec31a85721157399cb4faab6e0d26" + ] + } + ], + "timestamp": "2024-02-22T13:57:41.490986" + }, + "csv_sort": { + "content": [ + "test.csv.sorted" + ], + "timestamp": "2024-02-22T13:57:33.62444" + }, + "unsorted_genome_sort": { + "content": [ + { + "0": [ + [ + { + "id": "genome_test" + }, + "genome_test.bed.sorted:md5,fd97f7efafdbbfa71d9b560f10b4b048" + ] + ], + "1": [ + "versions.yml:md5,8ebec31a85721157399cb4faab6e0d26" + ], + "sorted": [ + [ + { + "id": "genome_test" + }, + "genome_test.bed.sorted:md5,fd97f7efafdbbfa71d9b560f10b4b048" + ] + ], + "versions": [ + "versions.yml:md5,8ebec31a85721157399cb4faab6e0d26" + ] + } + ], + "timestamp": "2024-02-22T13:57:17.281092" + }, + "genome_sort": { + "content": [ + "genome_test.bed.sorted" + ], + "timestamp": "2024-02-22T13:57:17.340463" + }, + "unsorted_intervals_sort": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.bed.sorted:md5,abbce903ef263d38b2f71856387799ab" + ] + ], + "1": [ + "versions.yml:md5,8ebec31a85721157399cb4faab6e0d26" + ], + "sorted": [ + [ + { + "id": "test" + }, + "test.bed.sorted:md5,abbce903ef263d38b2f71856387799ab" + ] + ], + "versions": [ + "versions.yml:md5,8ebec31a85721157399cb4faab6e0d26" + ] + } + ], + "timestamp": "2024-02-22T13:57:25.514206" + } +} \ No newline at end of file diff --git a/modules/nf-core/gnu/sort/tests/sort_complex.config b/modules/nf-core/gnu/sort/tests/sort_complex.config new file mode 100644 index 00000000..103eaaf6 --- /dev/null +++ b/modules/nf-core/gnu/sort/tests/sort_complex.config @@ -0,0 +1,6 @@ +process { + withName: GNU_SORT { + ext.args = { "-t ';' -g -k 1,1 -k 2,2" } + ext.suffix = { "csv.sorted" } + } +} \ No newline at end of file diff --git a/modules/nf-core/gnu/sort/tests/sort_simple_bed.config b/modules/nf-core/gnu/sort/tests/sort_simple_bed.config new file mode 100644 index 00000000..d7d52e0f --- /dev/null +++ b/modules/nf-core/gnu/sort/tests/sort_simple_bed.config @@ -0,0 +1,6 @@ +process { + withName: GNU_SORT { + ext.args = { "-k1,1 -k2,2n" } + ext.suffix = { "bed.sorted" } + } +} \ No newline at end of file diff --git a/modules/nf-core/gnu/sort/tests/sort_simple_genome.config b/modules/nf-core/gnu/sort/tests/sort_simple_genome.config new file mode 100644 index 00000000..4dcec385 --- /dev/null +++ b/modules/nf-core/gnu/sort/tests/sort_simple_genome.config @@ -0,0 +1,6 @@ +process { + withName: GNU_SORT { + ext.args = { "-k1,1 -k2,2n" } + ext.suffix = { "genome.sorted" } + } +} \ No newline at end of file diff --git a/modules/nf-core/gnu/sort/tests/tags.yml b/modules/nf-core/gnu/sort/tests/tags.yml new file mode 100644 index 00000000..ac40e376 --- /dev/null +++ b/modules/nf-core/gnu/sort/tests/tags.yml @@ -0,0 +1,2 @@ +gnu/sort: + - "modules/nf-core/gnu/sort/**" diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 0708ee37..c45ac4ff 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -1,5 +1,7 @@ include { ANNOTATION } from '../../modules/local/annotation/full_annotation/main' +include { GNU_SORT as COMBINE_ANNOTATIONS } from '../../modules/nf-core/gnu/sort/main' +include { GAWK as REMOVE_SCORE } from '../../modules/nf-core/gawk/main' include { BEDTOOLS_INTERSECT as INTERSECT_ANNOTATION } from '../../modules/nf-core/bedtools/intersect/main' include { BOWTIE2_ALIGN as FIND_CIRC_ALIGN } from '../../modules/nf-core/bowtie2/align/main' include { SAMTOOLS_VIEW } from '../../modules/nf-core/samtools/view/main' @@ -215,6 +217,8 @@ workflow CIRCRNA_DISCOVERY { INTERSECT_ANNOTATION( circrna_filtered.combine(gtf), [[], []]) ANNOTATION( INTERSECT_ANNOTATION.out.intersect, exon_boundary ) + COMBINE_ANNOTATIONS(ANNOTATION.out.bed.map{ meta, bed -> bed}.collect().map{[[id: "annotation"], it]}) + REMOVE_SCORE( COMBINE_ANNOTATIONS.out.sorted, []) ch_versions = ch_versions.mix(INTERSECT_ANNOTATION.out.versions) ch_versions = ch_versions.mix(ANNOTATION.out.versions) From b7d63010b623ddb8b7ee5306d67142e38ba2f050 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 13:57:15 +0100 Subject: [PATCH 170/491] Update quantification subworkflow --- modules.json | 10 + modules/local/psirc/quant/main.nf | 10 +- .../quantification/transcriptome/main.nf | 58 +- .../nf-core/custom/tx2gene/environment.yml | 9 + modules/nf-core/custom/tx2gene/main.nf | 36 ++ modules/nf-core/custom/tx2gene/meta.yml | 65 ++ .../custom/tx2gene/templates/tx2gene.py | 187 ++++++ .../nf-core/custom/tx2gene/tests/main.nf.test | 81 +++ .../custom/tx2gene/tests/main.nf.test.snap | 60 ++ modules/nf-core/custom/tx2gene/tests/tags.yml | 2 + .../nf-core/tximeta/tximport/environment.yml | 9 + modules/nf-core/tximeta/tximport/main.nf | 47 ++ modules/nf-core/tximeta/tximport/meta.yml | 120 ++++ .../tximeta/tximport/templates/tximport.r | 220 +++++++ .../tximeta/tximport/tests/main.nf.test | 193 ++++++ .../tximeta/tximport/tests/main.nf.test.snap | 594 ++++++++++++++++++ .../nf-core/tximeta/tximport/tests/tags.yml | 2 + subworkflows/local/quantification.nf | 35 +- 18 files changed, 1688 insertions(+), 50 deletions(-) create mode 100644 modules/nf-core/custom/tx2gene/environment.yml create mode 100644 modules/nf-core/custom/tx2gene/main.nf create mode 100644 modules/nf-core/custom/tx2gene/meta.yml create mode 100755 modules/nf-core/custom/tx2gene/templates/tx2gene.py create mode 100644 modules/nf-core/custom/tx2gene/tests/main.nf.test create mode 100644 modules/nf-core/custom/tx2gene/tests/main.nf.test.snap create mode 100644 modules/nf-core/custom/tx2gene/tests/tags.yml create mode 100644 modules/nf-core/tximeta/tximport/environment.yml create mode 100644 modules/nf-core/tximeta/tximport/main.nf create mode 100644 modules/nf-core/tximeta/tximport/meta.yml create mode 100755 modules/nf-core/tximeta/tximport/templates/tximport.r create mode 100644 modules/nf-core/tximeta/tximport/tests/main.nf.test create mode 100644 modules/nf-core/tximeta/tximport/tests/main.nf.test.snap create mode 100644 modules/nf-core/tximeta/tximport/tests/tags.yml diff --git a/modules.json b/modules.json index ed44f1c4..439ea7a3 100644 --- a/modules.json +++ b/modules.json @@ -75,6 +75,11 @@ "git_sha": "de45447d060b8c8b98575bc637a4a575fd0638e1", "installed_by": ["modules"] }, + "custom/tx2gene": { + "branch": "master", + "git_sha": "ec155021a9104441bf6a9bae3b55d1b5b0bfdb3a", + "installed_by": ["modules"] + }, "fastqc": { "branch": "master", "git_sha": "f4ae1d942bd50c5c0b9bd2de1393ce38315ba57c", @@ -174,6 +179,11 @@ "branch": "master", "git_sha": "a98418419ae6c9df3cf6cf108d1e1aba71037d5a", "installed_by": ["modules"] + }, + "tximeta/tximport": { + "branch": "master", + "git_sha": "c275c3baac6df8f0c7c500760a0cf014ce7b525d", + "installed_by": ["modules"] } } }, diff --git a/modules/local/psirc/quant/main.nf b/modules/local/psirc/quant/main.nf index 88ecef04..df4e8b54 100644 --- a/modules/local/psirc/quant/main.nf +++ b/modules/local/psirc/quant/main.nf @@ -9,15 +9,13 @@ process PSIRC_QUANT { tuple val(meta2), path(index) output: - tuple val(meta), path("output/${meta.id}.tsv"), emit: abundance_tsv - tuple val(meta), path("output/${meta.id}.h5"), emit: abundance_h5 + tuple val(meta), path("${meta.id}/abundance.tsv"), emit: abundance_tsv + tuple val(meta), path("${meta.id}/abundance.h5"), emit: abundance_h5 + tuple val(meta), path("${meta.id}"), emit: directory script: def single_end = meta.single_end ? "--single -l 76 -s 20" : "" """ - psirc-quant quant -t $task.cpus -i $index -o output $single_end $reads - - mv output/abundance.tsv output/${meta.id}.tsv - mv output/abundance.h5 output/${meta.id}.h5 + psirc-quant quant -t $task.cpus -i $index -o $meta.id $single_end $reads """ } diff --git a/modules/local/quantification/transcriptome/main.nf b/modules/local/quantification/transcriptome/main.nf index a21d1429..4d4d3028 100644 --- a/modules/local/quantification/transcriptome/main.nf +++ b/modules/local/quantification/transcriptome/main.nf @@ -1,42 +1,38 @@ -process EXTRACT_TRANSCRIPTOME { +process TRANSCRIPTOME { tag "$meta.id" - label 'process_single' + label 'process_low' - conda "bioconda::pandas=1.5.2" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : - 'quay.io/biocontainers/pandas:1.5.2' }" + 'https://depot.galaxyproject.org/singularity/gffread:0.12.1--h8b12597_0' : + 'biocontainers/gffread:0.12.1--h8b12597_0' }" input: - tuple val(meta), path(gtf) + tuple val(meta), path(gff) + tuple val(meta2), path(genome) output: - tuple val(meta), path("${meta.id}.transcriptome.bed"), emit: bed + tuple val(meta), path("$outfile"), emit: transcriptome + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def extension = task.ext.extension ?: "fasta" + outfile = "${prefix}.${extension}" """ - #!/usr/bin/env python - - import pandas as pd - - columns = ["seqname", "source", "feature", "start", "end", "score", "strand", "frame", "attributes"] - - df = pd.read_csv("${gtf}", sep="\\t", comment="#", names=columns, header=None) - - # Keep only transcript features - df = df[df['feature'] == 'transcript'] - - # Convert attributes to a dictionary - df['attributes'] = df['attributes'].apply(lambda row: dict([[value.strip(r'"') for value in entry.strip().split(' ')] for entry in row.split(';') if entry])) - - # Extract gene_id and transcript_id - df['gene_id'] = df['attributes'].apply(lambda row: row['gene_id']) - df['transcript_id'] = df['attributes'].apply(lambda row: row['transcript_id']) - df['name'] = df['gene_id'] + ":" + df['transcript_id'] - - # Format as bed - df = df[['seqname', 'start', 'end', 'name', 'score', 'strand']] - - df.to_csv("${meta.id}.transcriptome.bed", sep="\\t", index=False, header=False) + gffread \\ + -g $genome \\ + -w $outfile \\ + $args \\ + $gff + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + gffread: \$(gffread --version 2>&1) + END_VERSIONS """ -} +} \ No newline at end of file diff --git a/modules/nf-core/custom/tx2gene/environment.yml b/modules/nf-core/custom/tx2gene/environment.yml new file mode 100644 index 00000000..a859dc88 --- /dev/null +++ b/modules/nf-core/custom/tx2gene/environment.yml @@ -0,0 +1,9 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +name: "custom_tx2gene" +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - python=3.9.5 diff --git a/modules/nf-core/custom/tx2gene/main.nf b/modules/nf-core/custom/tx2gene/main.nf new file mode 100644 index 00000000..99c00aa0 --- /dev/null +++ b/modules/nf-core/custom/tx2gene/main.nf @@ -0,0 +1,36 @@ +process CUSTOM_TX2GENE { + tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/python:3.9--1' : + 'biocontainers/python:3.9--1' }" + + input: + tuple val(meta), path(gtf) + tuple val(meta2), path ("quants/*") + val quant_type + val id + val extra + + output: + tuple val(meta), path("*tx2gene.tsv"), emit: tx2gene + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + template 'tx2gene.py' + + stub: + """ + touch ${meta.id}.tx2gene.tsv + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + python: \$(python --version | sed 's/Python //g') + END_VERSIONS + """ +} diff --git a/modules/nf-core/custom/tx2gene/meta.yml b/modules/nf-core/custom/tx2gene/meta.yml new file mode 100644 index 00000000..d991bf1b --- /dev/null +++ b/modules/nf-core/custom/tx2gene/meta.yml @@ -0,0 +1,65 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json +name: "custom_tx2gene" +description: Make a transcript/gene mapping from a GTF and cross-reference with transcript quantifications. +keywords: + - gene + - gtf + - pseudoalignment + - transcript +tools: + - "custom": + description: | + "Custom module to create a transcript to gene mapping from a GTF and + check it against transcript quantifications" + tool_dev_url: "https://github.com/nf-core/modules/blob/master/modules/nf-core/custom/tx2gene/main.nf" + licence: ["MIT"] + +input: + - meta: + type: map + description: | + Groovy Map containing reference information related to the GTF file + e.g. `[ id:'yeast' ]` + - gtf: + type: file + description: An annotation file of the reference genome in GTF format + pattern: "*.gtf" + - meta2: + type: map + description: | + Groovy Map containing information related to the experiment as a whole + e.g. `[ id:'SRP123456' ]` + - quants: + type: directory + description: Paths to subdirectories corresponding to + sample-wise runs of Salmon or Kallisto + - quant_type: + type: string + description: Quantification type, 'kallisto' or 'salmon' + - id: + type: string + description: Gene ID attribute in the GTF file (default= gene_id) + - extra: + type: string + description: Extra gene attribute in the GTF file (default= gene_name) + +output: + - meta: + type: map + description: | + Groovy Map containing reference information related to the GTF file + e.g. `[ id:'yeast' ]` + - tx2gene: + type: file + description: A transcript/ gene mapping table in TSV format + pattern: "*.tx2gene.tsv" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + +authors: + - "@pinin4fjords" +maintainers: + - "@pinin4fjords" diff --git a/modules/nf-core/custom/tx2gene/templates/tx2gene.py b/modules/nf-core/custom/tx2gene/templates/tx2gene.py new file mode 100755 index 00000000..7fd0de64 --- /dev/null +++ b/modules/nf-core/custom/tx2gene/templates/tx2gene.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python3 + +# Written by Lorena Pantano with subsequent reworking by Jonathan Manning. Released under the MIT license. + +import logging +import argparse +import glob +import os +import platform +import re +from collections import Counter, defaultdict, OrderedDict +from collections.abc import Set +from typing import Dict + +# Configure logging +logging.basicConfig(format="%(name)s - %(asctime)s %(levelname)s: %(message)s") +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) + +def format_yaml_like(data: dict, indent: int = 0) -> str: + """Formats a dictionary to a YAML-like string. + + Args: + data (dict): The dictionary to format. + indent (int): The current indentation level. + + Returns: + str: A string formatted as YAML. + """ + yaml_str = "" + for key, value in data.items(): + spaces = " " * indent + if isinstance(value, dict): + yaml_str += f"{spaces}{key}:\\n{format_yaml_like(value, indent + 1)}" + else: + yaml_str += f"{spaces}{key}: {value}\\n" + return yaml_str + +def read_top_transcripts(quant_dir: str, file_pattern: str) -> Set[str]: + """ + Read the top 100 transcripts from the quantification file. + + Parameters: + quant_dir (str): Directory where quantification files are located. + file_pattern (str): Pattern to match quantification files. + + Returns: + set: A set containing the top 100 transcripts. + """ + try: + # Find the quantification file within the directory + quant_file_path = glob.glob(os.path.join(quant_dir, "*", file_pattern))[0] + with open(quant_file_path, "r") as file_handle: + # Read the file and extract the top 100 transcripts + return {line.split()[0] for i, line in enumerate(file_handle) if i > 0 and i <= 100} + except IndexError: + # Log an error and raise a FileNotFoundError if the quant file does not exist + logger.error("No quantification files found.") + raise FileNotFoundError("Quantification file not found.") + + +def discover_transcript_attribute(gtf_file: str, transcripts: Set[str]) -> str: + """ + Discover the attribute in the GTF that corresponds to transcripts, prioritizing 'transcript_id'. + + Parameters: + gtf_file (str): Path to the GTF file. + transcripts (Set[str]): A set of transcripts to match in the GTF file. + + Returns: + str: The attribute name that corresponds to transcripts in the GTF file. + """ + + votes = Counter() + with open(gtf_file) as inh: + # Read GTF file, skipping header lines + for line in filter(lambda x: not x.startswith("#"), inh): + cols = line.split("\\t") + + # Use regular expression to correctly split the attributes string + attributes_str = cols[8] + attributes = dict(re.findall(r'(\\S+) "(.*?)(? Dict[str, str]: + """ + Parse the attributes column of a GTF file. + + :param attributes_text: The attributes column as a string. + :return: A dictionary of the attributes. + """ + # Split the attributes string by semicolon and strip whitespace + attributes = attributes_text.strip().split(";") + attr_dict = OrderedDict() + + # Iterate over each attribute pair + for attribute in attributes: + # Split the attribute into key and value, ensuring there are two parts + parts = attribute.strip().split(" ", 1) + if len(parts) == 2: + key, value = parts + # Remove any double quotes from the value + value = value.replace('"', "") + attr_dict[key] = value + + return attr_dict + + +def map_transcripts_to_gene( + quant_type: str, gtf_file: str, quant_dir: str, gene_id: str, extra_id_field: str, output_file: str +) -> bool: + """ + Map transcripts to gene names and write the output to a file. + + Parameters: + quant_type (str): The quantification method used (e.g., 'salmon'). + gtf_file (str): Path to the GTF file. + quant_dir (str): Directory where quantification files are located. + gene_id (str): The gene ID attribute in the GTF file. + extra_id_field (str): Additional ID field in the GTF file. + output_file (str): The output file path. + + Returns: + bool: True if the operation was successful, False otherwise. + """ + # Read the top transcripts based on quantification type + transcripts = read_top_transcripts(quant_dir, "quant.sf" if quant_type == "salmon" else "abundance.tsv") + # Discover the attribute that corresponds to transcripts in the GTF + transcript_attribute = discover_transcript_attribute(gtf_file, transcripts) + + # Open GTF and output file to write the mappings + # Initialize the set to track seen combinations + seen = set() + + with open(gtf_file) as inh, open(output_file, "w") as output_handle: + output_handle.write(f"{transcript_attribute}\\t{gene_id}\\t{extra_id_field}\\n") + # Parse each line of the GTF, mapping transcripts to genes + for line in filter(lambda x: not x.startswith("#"), inh): + cols = line.split("\\t") + attr_dict = parse_attributes(cols[8]) + if gene_id in attr_dict and transcript_attribute in attr_dict: + # Create a unique identifier for the transcript-gene combination + transcript_gene_pair = (attr_dict[transcript_attribute], attr_dict[gene_id]) + + # Check if the combination has already been seen + if transcript_gene_pair not in seen: + # If it's a new combination, write it to the output and add to the seen set + extra_id = attr_dict.get(extra_id_field, attr_dict[gene_id]) + output_handle.write(f"{attr_dict[transcript_attribute]}\\t{attr_dict[gene_id]}\\t{extra_id}\\n") + seen.add(transcript_gene_pair) + + return True + + +# Main function to parse arguments and call the mapping function +if __name__ == "__main__": + if '${task.ext.prefix}' != "null": + prefix = "${task.ext.prefix}." + elif '$meta.id' != "null": + prefix = '${meta.id}.' + else: + prefix = '' + + if not map_transcripts_to_gene('$quant_type', '$gtf', 'quants', '$id', '$extra', f"{prefix}tx2gene.tsv"): + logger.error("Failed to map transcripts to genes.") + + # Write the versions + versions_this_module = {} + versions_this_module["${task.process}"] = {"python": platform.python_version()} + with open("versions.yml", "w") as f: + f.write(format_yaml_like(versions_this_module)) diff --git a/modules/nf-core/custom/tx2gene/tests/main.nf.test b/modules/nf-core/custom/tx2gene/tests/main.nf.test new file mode 100644 index 00000000..b1559279 --- /dev/null +++ b/modules/nf-core/custom/tx2gene/tests/main.nf.test @@ -0,0 +1,81 @@ +nextflow_process { + + name "Test Process CUSTOM_TX2GENE" + script "../main.nf" + process "CUSTOM_TX2GENE" + + tag "modules" + tag "modules_nfcore" + tag "custom" + tag "custom/tx2gene" + tag "untar" + + setup { + + run("UNTAR") { + script "../../../untar/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test'], // meta map + file(params.modules_testdata_base_path + 'genomics/eukaryotes/saccharomyces_cerevisiae/kallisto_results.tar.gz', checkIfExists: true) + ]) + """ + } + } + } + + test("saccharomyces_cerevisiae - gtf") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test'], // meta map + file(params.modules_testdata_base_path + 'genomics/eukaryotes/saccharomyces_cerevisiae/genome_gfp.gtf', checkIfExists: true) + ]) + input[1] = UNTAR.out.untar.map { meta, dir -> [ meta, dir.listFiles().collect() ] } + input[2] = 'kallisto' + input[3] = 'gene_id' + input[4] = 'gene_name' + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.tx2gene).match('tx2gene') }, + { assert snapshot(process.out.versions).match('versions') } + ) + } + } + + test("saccharomyces_cerevisiae - gtf - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test'], // meta map + file(params.modules_testdata_base_path + 'genomics/eukaryotes/saccharomyces_cerevisiae/genome_gfp.gtf', checkIfExists: true) + ]) + input[1] = UNTAR.out.untar.map { meta, dir -> [ meta, dir.listFiles().collect() ] } + input[2] = 'kallisto' + input[3] = 'gene_id' + input[4] = 'gene_name' + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.tx2gene).match('tx2gene - stub') }, + { assert snapshot(process.out.versions).match('versions - stub') } + ) + } + } +} \ No newline at end of file diff --git a/modules/nf-core/custom/tx2gene/tests/main.nf.test.snap b/modules/nf-core/custom/tx2gene/tests/main.nf.test.snap new file mode 100644 index 00000000..1e76e10d --- /dev/null +++ b/modules/nf-core/custom/tx2gene/tests/main.nf.test.snap @@ -0,0 +1,60 @@ +{ + "versions": { + "content": [ + [ + "versions.yml:md5,fb8145d7fbc6043ba031249b23ecda50" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-26T13:14:18.218251" + }, + "tx2gene": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.tx2gene.tsv:md5,0e2418a69d2eba45097ebffc2f700bfe" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-26T13:14:18.21054" + }, + "tx2gene - stub": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.tx2gene.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-26T13:14:25.915434" + }, + "versions - stub": { + "content": [ + [ + "versions.yml:md5,5613eefbca41377128f1d8dc09b9fb60" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-26T13:14:25.919243" + } +} \ No newline at end of file diff --git a/modules/nf-core/custom/tx2gene/tests/tags.yml b/modules/nf-core/custom/tx2gene/tests/tags.yml new file mode 100644 index 00000000..493fbc3b --- /dev/null +++ b/modules/nf-core/custom/tx2gene/tests/tags.yml @@ -0,0 +1,2 @@ +custom/tx2gene: + - "modules/nf-core/custom/tx2gene/**" diff --git a/modules/nf-core/tximeta/tximport/environment.yml b/modules/nf-core/tximeta/tximport/environment.yml new file mode 100644 index 00000000..24b20222 --- /dev/null +++ b/modules/nf-core/tximeta/tximport/environment.yml @@ -0,0 +1,9 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +name: "tximeta_tximport" +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - "bioconda::bioconductor-tximeta=1.20.1" diff --git a/modules/nf-core/tximeta/tximport/main.nf b/modules/nf-core/tximeta/tximport/main.nf new file mode 100644 index 00000000..b0cce853 --- /dev/null +++ b/modules/nf-core/tximeta/tximport/main.nf @@ -0,0 +1,47 @@ +process TXIMETA_TXIMPORT { + label "process_medium" + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/bioconductor-tximeta%3A1.20.1--r43hdfd78af_0' : + 'biocontainers/bioconductor-tximeta:1.20.1--r43hdfd78af_0' }" + + input: + tuple val(meta), path("quants/*") + tuple val(meta2), path(tx2gene) + val quant_type + + output: + tuple val(meta), path("*gene_tpm.tsv") , emit: tpm_gene + tuple val(meta), path("*gene_counts.tsv") , emit: counts_gene + tuple val(meta), path("*gene_counts_length_scaled.tsv"), emit: counts_gene_length_scaled + tuple val(meta), path("*gene_counts_scaled.tsv") , emit: counts_gene_scaled + tuple val(meta), path("*gene_lengths.tsv") , emit: lengths_gene + tuple val(meta), path("*transcript_tpm.tsv") , emit: tpm_transcript + tuple val(meta), path("*transcript_counts.tsv") , emit: counts_transcript + tuple val(meta), path("*transcript_lengths.tsv") , emit: lengths_transcript + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + template 'tximport.r' + + stub: + """ + touch ${meta.id}.gene_tpm.tsv + touch ${meta.id}.gene_counts.tsv + touch ${meta.id}.gene_counts_length_scaled.tsv + touch ${meta.id}.gene_counts_scaled.tsv + touch ${meta.id}.gene_lengths.tsv + touch ${meta.id}.transcript_tpm.tsv + touch ${meta.id}.transcript_counts.tsv + touch ${meta.id}.transcript_lengths.tsv + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + bioconductor-tximeta: \$(Rscript -e "library(tximeta); cat(as.character(packageVersion('tximeta')))") + END_VERSIONS + """ +} diff --git a/modules/nf-core/tximeta/tximport/meta.yml b/modules/nf-core/tximeta/tximport/meta.yml new file mode 100644 index 00000000..9ee5fd36 --- /dev/null +++ b/modules/nf-core/tximeta/tximport/meta.yml @@ -0,0 +1,120 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json +name: "tximeta_tximport" +description: | + Import transcript-level abundances and estimated counts for gene-level + analysis packages +keywords: + - gene + - kallisto + - pseudoalignment + - salmon + - transcript +tools: + - "tximeta": + description: "Transcript Quantification Import with Automatic Metadata" + homepage: "https://bioconductor.org/packages/release/bioc/html/tximeta.html" + documentation: "https://bioconductor.org/packages/release/bioc/vignettes/tximeta/inst/doc/tximeta.html" + tool_dev_url: "https://github.com/thelovelab/tximeta" + doi: "10.1371/journal.pcbi.1007664" + licence: ["GPL-2"] + +input: + - meta: + type: map + description: | + Groovy Map containing information related to the experiment as a whole + e.g. `[ id:'SRP123456' ]` + - quants: + type: directory + description: Paths to subdirectories corresponding to + sample-wise runs of Salmon or Kallisto + - meta2: + type: map + description: | + Groovy Map containing reference information related to the species + reference e.g. `[ id:'yeast' ]` + - tx2gene: + type: file + description: A transcript to gene mapping table such as those generated + by custom/tx2gene + pattern: "*.{csv,tsv}" + - meta3: + type: map + description: | + Groovy Map containing information related to the experiment as a whole + e.g. `[ id:'SRP123456' ]` + - coldata: + type: file + description: | + Optional 'coldata' file equivalent to a sample sheet where the first + column corresponds to the sample names (directory names in the input + salmon/ kallisto results) + pattern: "*.{csv,tsv}" + - quant_type: + type: string + description: Quantification type, 'kallisto' or 'salmon' + +output: + - meta: + type: map + description: | + Groovy Map containing information related to the experiment as a whole + e.g. `[ id:'SRP123456' ]` + - tpm_gene: + type: file + description: | + Abundance (TPM) values derived from tximport output after + summarizeToGene(), without a 'countsFromAbundance' specification + pattern: "*gene_tpm.tsv" + - counts_gene: + type: file + description: | + Count values derived from tximport output after + summarizeToGene(), without a 'countsFromAbundance' specification + pattern: "*gene_counts.tsv" + - counts_gene_length_scaled: + type: file + description: | + Count values derived from tximport output after summarizeToGene(), with + a 'countsFromAbundance' specification of 'lengthScaledTPM' + pattern: "*gene_counts_length_scaled.tsv" + - counts_gene_scaled: + type: file + description: | + Count values derived from tximport output after summarizeToGene(), with + a 'countsFromAbundance' specification of 'scaledTPM' + pattern: "*gene_counts_scaled.tsv" + - lengths_gene: + type: file + description: | + Length values derived from tximport output after summarizeToGene(), + without a 'countsFromAbundance' specification + pattern: "*gene_lengths.tsv" + - tpm_transcript: + type: file + description: | + Abundance (TPM) values derived from tximport output without + summarizeToGene(), without a 'countsFromAbundance' specification + pattern: "*transcript_tpm.tsv" + - counts_transcript: + type: file + description: | + Count values derived from tximport output without + summarizeToGene(), without a 'countsFromAbundance' specification + pattern: "*transcript_counts.tsv" + - lengths_transcript: + type: file + description: | + Length values derived from tximport output without summarizeToGene(), + without a 'countsFromAbundance' specification + pattern: "*gene_lengths.tsv" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + +authors: + - "@pinin4fjords" +maintainers: + - "@pinin4fjords" diff --git a/modules/nf-core/tximeta/tximport/templates/tximport.r b/modules/nf-core/tximeta/tximport/templates/tximport.r new file mode 100755 index 00000000..92f1a9e8 --- /dev/null +++ b/modules/nf-core/tximeta/tximport/templates/tximport.r @@ -0,0 +1,220 @@ +#!/usr/bin/env Rscript --vanilla + +# Script for importing and processing transcript-level quantifications. +# Written by Lorena Pantano, later modified by Jonathan Manning, and released +# under the MIT license. + +# Loading required libraries +library(SummarizedExperiment) +library(tximport) + +################################################ +################################################ +## Functions ## +################################################ +################################################ + +#' Build a table from a SummarizedExperiment object +#' +#' This function takes a SummarizedExperiment object and a specific slot name to extract +#' assay data. It then combines the first two columns of the rowData with the specified +#' assay data slot into a new data table. +#' +#' @param se.obj A SummarizedExperiment object from which to build the table. +#' @param slot The name of the slot in the assays list from which to extract data. +#' +#' @return A data frame combining the first two columns of the rowData with the assay data from the specified slot. + +build_table <- function(se.obj, slot) { + cbind(rowData(se.obj)[,1:2], assays(se.obj)[[slot]]) +} + +#' Write a table to a file from a SummarizedExperiment object with given parameters +#' +#' This function generates a table from a SummarizedExperiment object using specified parameters +#' and writes the resulting table to a file. The file name is constructed using a prefix and a +#' suffix from the parameters, and the table is written with tab separation, without quoting text, +#' and without row names. +#' +#' @param params A list containing the parameters needed for file generation and table writing. +#' The list should include: +#' - `obj`: A SummarizedExperiment object from which to build the table. +#' - `slot`: The name of the slot in the assays list from which to extract data. +#' - `suffix`: Suffix to use for generating the file name. +#' +#' @return NULL The function is called for its side effect of writing a file and does not return anything. + +write_se_table <- function(params, prefix) { + file_name <- paste0(prefix, ".", params\$suffix) + write.table(build_table(params\$obj, params\$slot), file_name, + sep="\t", quote=FALSE, row.names = FALSE) +} + +#' Read Transcript Metadata from a Given Path +#' +#' This function reads transcript metadata from a specified file path. The file is expected to +#' be a tab-separated values file without headers, containing transcript information. The function +#' checks if the file is empty and stops execution with an error message if so. It reads the file +#' into a data frame, expecting columns for transcript IDs, gene IDs, and gene names. Additional +#' processing is done to ensure compatibility with a predefined data structure (e.g., `txi[[1]]`), +#' including adding missing entries and reordering based on the transcript IDs found in `txi[[1]]`. +#' +#' @param tinfo_path The file path to the transcript information file. +#' +#' @return A list containing three elements: +#' - `transcript`: A data frame with transcript IDs, gene IDs, and gene names, indexed by transcript IDs. +#' - `gene`: A data frame with unique gene IDs and gene names. +#' - `tx2gene`: A data frame mapping transcript IDs to gene IDs. + +read_transcript_info <- function(tinfo_path){ + info <- file.info(tinfo_path) + if (info\$size == 0) { + stop("tx2gene file is empty") + } + + transcript_info <- read.csv(tinfo_path, sep="\t", header = TRUE, + col.names = c("tx", "gene_id", "gene_name")) + + extra <- setdiff(rownames(txi[[1]]), as.character(transcript_info[["tx"]])) + transcript_info <- rbind(transcript_info, data.frame(tx=extra, gene_id=extra, gene_name=extra)) + transcript_info <- transcript_info[match(rownames(txi[[1]]), transcript_info[["tx"]]), ] + rownames(transcript_info) <- transcript_info[["tx"]] + + list(transcript = transcript_info, + gene = unique(transcript_info[,2:3]), + tx2gene = transcript_info[,1:2]) +} + +#' Create a SummarizedExperiment Object +#' +#' Constructs a SummarizedExperiment object using provided matrices for counts, abundance, and length, +#' along with metadata for columns and rows. This function facilitates the organization of experimental +#' data (e.g., RNA-seq or other high-throughput data) in a structured format that is convenient for +#' further analyses and visualization. +#' +#' @param counts A matrix or DataFrame containing counts data, with rows as features (e.g., genes) and +#' columns as samples. +#' @param abundance A matrix or DataFrame containing abundance data (e.g., TPM or FPKM) with the same +#' dimensions and row/column names as the counts data. +#' @param length A matrix or DataFrame containing feature lengths, matching the dimensions and row/column +#' names of the counts data. +#' @param col_data A DataFrame containing sample-level metadata, with rows corresponding to columns in the +#' counts, abundance, and length matrices. +#' @param row_data A DataFrame containing feature-level metadata, with rows corresponding to features in +#' the counts, abundance, and length matrices. +#' +#' @return A SummarizedExperiment object containing the supplied data and metadata. + +create_summarized_experiment <- function(counts, abundance, length, col_data, row_data) { + SummarizedExperiment(assays = list(counts = counts, abundance = abundance, length = length), + colData = col_data, + rowData = row_data) +} + +################################################ +################################################ +## Main script starts here ## +################################################ +################################################ + +# Define pattern for file names based on quantification type +pattern <- ifelse('$quant_type' == "kallisto", "abundance.tsv", "quant.sf") +fns <- list.files('quants', pattern = pattern, recursive = T, full.names = T) +names <- basename(dirname(fns)) +names(fns) <- names +dropInfReps <- '$quant_type' == "kallisto" + +# Import transcript-level quantifications +txi <- tximport(fns, type = '$quant_type', txOut = TRUE, dropInfReps = dropInfReps) + +# Read transcript and sample data +transcript_info <- read_transcript_info('$tx2gene') + +# Make coldata just to appease the summarizedexperiment +coldata <- data.frame(files = fns, names = names) +rownames(coldata) <- coldata[["names"]] + +# Create initial SummarizedExperiment object +se <- create_summarized_experiment(txi[["counts"]], txi[["abundance"]], txi[["length"]], + DataFrame(coldata), transcript_info\$transcript) + +# Setting parameters for writing tables +params <- list( + list(obj = se, slot = "abundance", suffix = "transcript_tpm.tsv"), + list(obj = se, slot = "counts", suffix = "transcript_counts.tsv"), + list(obj = se, slot = "length", suffix = "transcript_lengths.tsv") +) + +# Process gene-level data if tx2gene mapping is available +if ("tx2gene" %in% names(transcript_info) && !is.null(transcript_info\$tx2gene)) { + tx2gene <- transcript_info\$tx2gene + gi <- summarizeToGene(txi, tx2gene = tx2gene) + gi.ls <- summarizeToGene(txi, tx2gene = tx2gene, countsFromAbundance = "lengthScaledTPM") + gi.s <- summarizeToGene(txi, tx2gene = tx2gene, countsFromAbundance = "scaledTPM") + + gene_info <- transcript_info\$gene[match(rownames(gi[[1]]), transcript_info\$gene[["gene_id"]]),] + rownames(gene_info) <- gene_info[["tx"]] + + col_data_frame <- DataFrame(coldata) + + # Create gene-level SummarizedExperiment objects + gse <- create_summarized_experiment(gi[["counts"]], gi[["abundance"]], gi[["length"]], + col_data_frame, gene_info) + gse.ls <- create_summarized_experiment(gi.ls[["counts"]], gi.ls[["abundance"]], gi.ls[["length"]], + col_data_frame, gene_info) + gse.s <- create_summarized_experiment(gi.s[["counts"]], gi.s[["abundance"]], gi.s[["length"]], + col_data_frame, gene_info) + + params <- c(params, list( + list(obj = gse, slot = "length", suffix = "gene_lengths.tsv"), + list(obj = gse, slot = "abundance", suffix = "gene_tpm.tsv"), + list(obj = gse, slot = "counts", suffix = "gene_counts.tsv"), + list(obj = gse.ls, slot = "abundance", suffix = "gene_tpm_length_scaled.tsv"), + list(obj = gse.ls, slot = "counts", suffix = "gene_counts_length_scaled.tsv"), + list(obj = gse.s, slot = "abundance", suffix = "gene_tpm_scaled.tsv"), + list(obj = gse.s, slot = "counts", suffix = "gene_counts_scaled.tsv") + )) +} + +# Writing tables for each set of parameters + +prefix <- '' +if ('$task.ext.prefix' != 'null'){ + prefix = '$task.ext.prefix' +} else if ('$meta.id' != 'null'){ + prefix = '$meta.id' +} + +done <- lapply(params, write_se_table, prefix) + +################################################ +################################################ +## R SESSION INFO ## +################################################ +################################################ + +sink(paste(prefix, "R_sessionInfo.log", sep = '.')) +citation("tximeta") +print(sessionInfo()) +sink() + +################################################ +################################################ +## VERSIONS FILE ## +################################################ +################################################ + +r.version <- strsplit(version[['version.string']], ' ')[[1]][3] +tximeta.version <- as.character(packageVersion('tximeta')) + +writeLines( + c( + '"${task.process}":', + paste(' bioconductor-tximeta:', tximeta.version) + ), +'versions.yml') + +################################################ +################################################ +################################################ +################################################ diff --git a/modules/nf-core/tximeta/tximport/tests/main.nf.test b/modules/nf-core/tximeta/tximport/tests/main.nf.test new file mode 100644 index 00000000..5cf6af83 --- /dev/null +++ b/modules/nf-core/tximeta/tximport/tests/main.nf.test @@ -0,0 +1,193 @@ +nextflow_process { + + name "Test Process TXIMETA_TXIMPORT" + script "../main.nf" + process "TXIMETA_TXIMPORT" + + tag "modules" + tag "modules_nfcore" + tag "custom/tx2gene" + tag "tximeta" + tag "tximeta/tximport" + tag "untar" + + test("saccharomyces_cerevisiae - kallisto - gtf") { + + setup { + + run("UNTAR") { + script "../../../untar/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test'], // meta map + file(params.modules_testdata_base_path + 'genomics/eukaryotes/saccharomyces_cerevisiae/kallisto_results.tar.gz', checkIfExists: true) + ]) + """ + } + } + run("CUSTOM_TX2GENE") { + script "../../../custom/tx2gene/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test'], // meta map + file(params.modules_testdata_base_path + 'genomics/eukaryotes/saccharomyces_cerevisiae/genome_gfp.gtf', checkIfExists: true) + ]) + input[1] = UNTAR.out.untar.map { meta, dir -> [ meta, dir.listFiles().collect() ] } + input[2] = 'kallisto' + input[3] = 'gene_id' + input[4] = 'gene_name' + """ + } + } + } + + when { + process { + """ + input[0] = UNTAR.out.untar.map { meta, dir -> [ meta, dir.listFiles().collect() ] } + input[1] = CUSTOM_TX2GENE.out.tx2gene + input[2] = 'kallisto' + """ + } + } + + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.counts_gene).match('counts_gene_kallisto') }, + { assert snapshot(process.out.counts_gene_length_scaled).match('counts_gene_length_scaled_kallisto') }, + { assert snapshot(process.out.counts_gene_scaled).match('counts_gene_scaled_kallisto') }, + { assert snapshot(process.out.counts_transcript).match('counts_transcript_kallisto') }, + { assert snapshot(process.out.lengths_gene).match('lengths_gene_kallisto') }, + { assert snapshot(process.out.lengths_transcript).match('lengths_transcript_kallisto') }, + { assert snapshot(process.out.tpm_gene).match('tpm_gene_kallisto') }, + { assert snapshot(process.out.tpm_transcript).match('tpm_transcript_kallisto') }, + { assert snapshot(process.out.versions).match('versions_kallisto') } + ) + } + } + + test("saccharomyces_cerevisiae - kallisto - gtf - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ [], [] ]) + input[1] = Channel.of([ [], [] ]) + input[2] = 'kallisto' + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.counts_gene).match('counts_gene_kallisto - stub') }, + { assert snapshot(process.out.counts_gene_length_scaled).match('counts_gene_length_scaled_kallisto - stub') }, + { assert snapshot(process.out.counts_gene_scaled).match('counts_gene_scaled_kallisto - stub') }, + { assert snapshot(process.out.counts_transcript).match('counts_transcript_kallisto - stub') }, + { assert snapshot(process.out.lengths_gene).match('lengths_gene_kallisto - stub') }, + { assert snapshot(process.out.lengths_transcript).match('lengths_transcript_kallisto - stub') }, + { assert snapshot(process.out.tpm_gene).match('tpm_gene_kallisto - stub') }, + { assert snapshot(process.out.tpm_transcript).match('tpm_transcript_kallisto - stub') }, + { assert snapshot(process.out.versions).match('versions_kallisto - stub') } + ) + } + + } + test("saccharomyces_cerevisiae - salmon - gtf") { + + setup { + + run("UNTAR") { + script "../../../untar/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test'], // meta map + file(params.modules_testdata_base_path + 'genomics/eukaryotes/saccharomyces_cerevisiae/salmon_results.tar.gz', checkIfExists: true) + ]) + """ + } + } + run("CUSTOM_TX2GENE") { + script "../../../custom/tx2gene/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test'], // meta map + file(params.modules_testdata_base_path + 'genomics/eukaryotes/saccharomyces_cerevisiae/genome_gfp.gtf', checkIfExists: true) + ]) + input[1] = UNTAR.out.untar.map { meta, dir -> [ meta, dir.listFiles().collect() ] } + input[2] = 'salmon' + input[3] = 'gene_id' + input[4] = 'gene_name' + """ + } + } + } + + when { + process { + """ + input[0] = UNTAR.out.untar.map { meta, dir -> [ meta, dir.listFiles().collect() ] } + input[1] = CUSTOM_TX2GENE.out.tx2gene + input[2] = 'salmon' + """ + } + } + + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.counts_gene).match('counts_gene_salmon') }, + { assert snapshot(process.out.counts_gene_length_scaled).match('counts_gene_length_scaled_salmon') }, + { assert snapshot(process.out.counts_gene_scaled).match('counts_gene_scaled_salmon') }, + { assert snapshot(process.out.counts_transcript).match('counts_transcript_salmon') }, + { assert snapshot(process.out.lengths_gene).match('lengths_gene_salmon') }, + { assert snapshot(process.out.lengths_transcript).match('lengths_transcript_salmon') }, + { assert snapshot(process.out.tpm_gene).match('tpm_gene_salmon') }, + { assert snapshot(process.out.tpm_transcript).match('tpm_transcript_salmon') }, + { assert snapshot(process.out.versions).match('versions_salmon') } + ) + } + + } + + test("saccharomyces_cerevisiae - salmon - gtf - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ [], [] ]) + input[1] = Channel.of([ [], [] ]) + input[2] = 'salmon' + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.counts_gene).match('counts_gene_salmon - stub') }, + { assert snapshot(process.out.counts_gene_length_scaled).match('counts_gene_length_scaled_salmon - stub') }, + { assert snapshot(process.out.counts_gene_scaled).match('counts_gene_scaled_salmon - stub') }, + { assert snapshot(process.out.counts_transcript).match('counts_transcript_salmon - stub') }, + { assert snapshot(process.out.lengths_gene).match('lengths_gene_salmon - stub') }, + { assert snapshot(process.out.lengths_transcript).match('lengths_transcript_salmon - stub') }, + { assert snapshot(process.out.tpm_gene).match('tpm_gene_salmon - stub') }, + { assert snapshot(process.out.tpm_transcript).match('tpm_transcript_salmon - stub') }, + { assert snapshot(process.out.versions).match('versions_salmon - stub') } + ) + } + } +} + diff --git a/modules/nf-core/tximeta/tximport/tests/main.nf.test.snap b/modules/nf-core/tximeta/tximport/tests/main.nf.test.snap new file mode 100644 index 00000000..fe972d09 --- /dev/null +++ b/modules/nf-core/tximeta/tximport/tests/main.nf.test.snap @@ -0,0 +1,594 @@ +{ + "tpm_transcript_salmon - stub": { + "content": [ + [ + [ + [ + + ], + "[].transcript_tpm.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:54.169267" + }, + "lengths_gene_kallisto - stub": { + "content": [ + [ + [ + [ + + ], + "[].gene_lengths.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:20.838048" + }, + "counts_gene_scaled_salmon - stub": { + "content": [ + [ + [ + [ + + ], + "[].gene_counts_scaled.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:54.139493" + }, + "counts_gene_kallisto - stub": { + "content": [ + [ + [ + [ + + ], + "[].gene_counts.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:20.823542" + }, + "lengths_transcript_salmon - stub": { + "content": [ + [ + [ + [ + + ], + "[].transcript_lengths.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:54.157265" + }, + "versions_salmon - stub": { + "content": [ + [ + "versions.yml:md5,6ff317cceddc686f84d79cb976e1e28b" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:54.175019" + }, + "counts_gene_length_scaled_kallisto": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.gene_counts_length_scaled.tsv:md5,4944841ac711124d29673b6b6ed16ef3" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:04.116135" + }, + "lengths_transcript_salmon": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.transcript_lengths.tsv:md5,db6d8ab9f8e1123d5984fd534b4347dc" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:37.664041" + }, + "counts_transcript_kallisto": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.transcript_counts.tsv:md5,42e0106e75fa97c1c684c6d9060f1724" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:04.162273" + }, + "counts_transcript_kallisto - stub": { + "content": [ + [ + [ + [ + + ], + "[].transcript_counts.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:20.834743" + }, + "counts_transcript_salmon": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.transcript_counts.tsv:md5,ff0f5be09ca7a322672c0074ba35da17" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:37.652813" + }, + "lengths_gene_salmon - stub": { + "content": [ + [ + [ + [ + + ], + "[].gene_lengths.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:54.151603" + }, + "tpm_gene_salmon": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.gene_tpm.tsv:md5,6076364cc78741a4f8bc8935a045d13d" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:37.669821" + }, + "tpm_transcript_salmon": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.transcript_tpm.tsv:md5,7a334b565e1e865efb1caf615f194ef7" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:37.674895" + }, + "tpm_gene_salmon - stub": { + "content": [ + [ + [ + [ + + ], + "[].gene_tpm.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:54.163303" + }, + "lengths_transcript_kallisto": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.transcript_lengths.tsv:md5,f974b52840431a5dae57bcb615badbf1" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:04.1686" + }, + "counts_gene_length_scaled_kallisto - stub": { + "content": [ + [ + [ + [ + + ], + "[].gene_counts_length_scaled.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:20.827742" + }, + "tpm_gene_kallisto - stub": { + "content": [ + [ + [ + [ + + ], + "[].gene_tpm.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:20.846428" + }, + "counts_transcript_salmon - stub": { + "content": [ + [ + [ + [ + + ], + "[].transcript_counts.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:54.145564" + }, + "counts_gene_scaled_kallisto": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.gene_counts_scaled.tsv:md5,39d14e361434978b3cadae901a26a028" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:04.159638" + }, + "counts_gene_salmon": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.gene_counts.tsv:md5,c14cab7e15cfac73ec0602dc2c404551" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:37.636972" + }, + "versions_salmon": { + "content": [ + [ + "versions.yml:md5,6ff317cceddc686f84d79cb976e1e28b" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:37.680246" + }, + "counts_gene_length_scaled_salmon": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.gene_counts_length_scaled.tsv:md5,5f92a6784f6edc5e3b336c71c3ee7daf" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:37.642848" + }, + "tpm_gene_kallisto": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.gene_tpm.tsv:md5,85d108269769ae0d841247b9b9ed922d" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:04.172531" + }, + "lengths_transcript_kallisto - stub": { + "content": [ + [ + [ + [ + + ], + "[].transcript_lengths.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:20.842475" + }, + "lengths_gene_kallisto": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.gene_lengths.tsv:md5,db6becdf807fd164a9c63dd1dd916d9c" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:04.16551" + }, + "counts_gene_scaled_kallisto - stub": { + "content": [ + [ + [ + [ + + ], + "[].gene_counts_scaled.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:20.831518" + }, + "tpm_transcript_kallisto": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.transcript_tpm.tsv:md5,65862ed9d4a05abfab952e680dc0e49d" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:04.177955" + }, + "lengths_gene_salmon": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.gene_lengths.tsv:md5,1691ea2677612805cd699265c83024d7" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:37.658624" + }, + "counts_gene_length_scaled_salmon - stub": { + "content": [ + [ + [ + [ + + ], + "[].gene_counts_length_scaled.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:54.13369" + }, + "counts_gene_kallisto": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.gene_counts.tsv:md5,e89c28692ea214396b2d4cb702a804c3" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:04.113216" + }, + "versions_kallisto": { + "content": [ + [ + "versions.yml:md5,6ff317cceddc686f84d79cb976e1e28b" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:04.181904" + }, + "counts_gene_salmon - stub": { + "content": [ + [ + [ + [ + + ], + "[].gene_counts.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:54.127272" + }, + "versions_kallisto - stub": { + "content": [ + [ + "versions.yml:md5,6ff317cceddc686f84d79cb976e1e28b" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:20.86053" + }, + "tpm_transcript_kallisto - stub": { + "content": [ + [ + [ + [ + + ], + "[].transcript_tpm.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:20.856075" + }, + "counts_gene_scaled_salmon": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.gene_counts_scaled.tsv:md5,fdfb3d23aaf5d4316d81247ec4664ca0" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-11T11:35:37.647691" + } +} \ No newline at end of file diff --git a/modules/nf-core/tximeta/tximport/tests/tags.yml b/modules/nf-core/tximeta/tximport/tests/tags.yml new file mode 100644 index 00000000..fc96a89e --- /dev/null +++ b/modules/nf-core/tximeta/tximport/tests/tags.yml @@ -0,0 +1,2 @@ +tximeta/tximport: + - "modules/nf-core/tximeta/tximport/**" diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index 33b32cca..2757838d 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -1,11 +1,13 @@ -include { EXTRACT_TRANSCRIPTOME } from '../../modules/local/quantification/transcriptome/main' -include { BEDTOOLS_GETFASTA as TRANSCRIPTOME_FASTA } from '../../modules/nf-core/bedtools/getfasta/main' +include { TRANSCRIPTOME as LINEAR_TRANSCRIPTOME } from '../../modules/local/quantification/transcriptome/main' +include { BEDTOOLS_GETFASTA as CIRCULAR_TRANSCRIPTOME } from '../../modules/nf-core/bedtools/getfasta/main' include { GAWK as COUNTS_TO_BED } from '../../modules/nf-core/gawk/main' include { CAT_CAT as CAT_TRANSCRIPTOME } from '../../modules/nf-core/cat/cat/main' include { GAWK as MARK_CIRCULAR } from '../../modules/nf-core/gawk/main' include { PSIRC_INDEX } from '../../modules/local/psirc/index/main' include { PSIRC_QUANT } from '../../modules/local/psirc/quant/main' include { PSIRC_COMBINE } from '../../modules/local/psirc/combine/main' +include { CUSTOM_TX2GENE } from '../../modules/nf-core/custom/tx2gene/main' +include { TXIMETA_TXIMPORT } from '../../modules/nf-core/tximeta/tximport/main' workflow QUANTIFICATION { take: @@ -15,24 +17,31 @@ workflow QUANTIFICATION { reads main: - EXTRACT_TRANSCRIPTOME(ch_gtf) + LINEAR_TRANSCRIPTOME(ch_gtf, ch_fasta) COUNTS_TO_BED(counts.map{counts -> [[id: "counts"], counts]}, []) - CAT_TRANSCRIPTOME( - EXTRACT_TRANSCRIPTOME.out.bed.map{meta, bed -> bed}.mix( - COUNTS_TO_BED.out.output.map{meta, bed -> bed} - ).collect().map(beds -> [[id: "transcriptome"], beds]) + CIRCULAR_TRANSCRIPTOME( + COUNTS_TO_BED.out.output.map{meta, bed -> bed}, + ch_fasta.map{meta, fasta -> fasta} ) - TRANSCRIPTOME_FASTA( - CAT_TRANSCRIPTOME.out.file_out.map{meta, bed -> bed}, - ch_fasta.map{meta, fasta -> fasta} + CAT_TRANSCRIPTOME( + LINEAR_TRANSCRIPTOME.out.transcriptome.map{meta, fasta -> fasta}.mix( + CIRCULAR_TRANSCRIPTOME.out.fasta + ).collect().map(fastas -> [[id: "transcriptome"], fastas]) ) - ch_transcriptome_fasta = TRANSCRIPTOME_FASTA.out.fasta.map{fasta -> [[id: "transcriptome"], fasta]} - MARK_CIRCULAR(ch_transcriptome_fasta, []) + MARK_CIRCULAR(CAT_TRANSCRIPTOME.out.file_out, []) PSIRC_INDEX(MARK_CIRCULAR.out.output) PSIRC_QUANT(reads, PSIRC_INDEX.out.collect()) - PSIRC_COMBINE( PSIRC_QUANT.out.abundance_tsv.map{ meta, data -> data }.collect() ) + // PSIRC_COMBINE( PSIRC_QUANT.out.abundance_tsv.map{ meta, data -> data }.collect() ) + + CUSTOM_TX2GENE( + ch_gtf, + PSIRC_QUANT.out.directory, + "kallisto", + "gene_id", + "gene_name" + ) } From be0453a89e8f787230509b9769a764835c950728 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 14:50:29 +0100 Subject: [PATCH 171/491] Simplify count merging processes --- bin/circRNA_counts_matrix.py | 50 ------- bin/consolidate_algorithms_intersection.R | 134 ------------------ bin/counts_combined.py | 30 ++++ bin/merge_tools.py | 24 ++++ modules/local/count_matrix/combined/main.nf | 31 ++-- .../local/count_matrix/merge_tools/main.nf | 36 ++--- modules/local/count_matrix/single/main.nf | 4 +- subworkflows/local/circrna_discovery.nf | 29 ++-- subworkflows/local/differential_expression.nf | 10 +- workflows/circrna/main.nf | 6 +- 10 files changed, 95 insertions(+), 259 deletions(-) delete mode 100755 bin/circRNA_counts_matrix.py delete mode 100755 bin/consolidate_algorithms_intersection.R create mode 100755 bin/counts_combined.py create mode 100755 bin/merge_tools.py diff --git a/bin/circRNA_counts_matrix.py b/bin/circRNA_counts_matrix.py deleted file mode 100755 index 3f6e24f6..00000000 --- a/bin/circRNA_counts_matrix.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python - -import sys, glob -from collections import defaultdict - -""" -Script to parse circRNA quantification bed files, creating a count matrix suitable for statistical analyses -requires python 2.7 -Author: Declan Bennett @declan93 -License: MIT -""" - - -par = sys.argv -hld = defaultdict(list) -samps = defaultdict(list) - -path = "./" -files = [f for f in glob.glob("*.bed")] - -for fi in files: - name = fi.strip("./").split(".bed")[0] - with open(fi) as IN: - for li in IN: - fds = li.strip().split() - k = "_".join(fds[0:4]) - if k in samps: - samps[k].append((name, fds[4])) - else: - samps[k] = [(name, fds[4])] - - -def Diff(list1, list2): - return list(list(set(list1) - set(list2)) + list(set(list2) - set(list1))) - - -tmp = [x.replace(".bed", "") for x in files] -print("Chr\tStart\tStop\tStrand\t" + "\t".join([x for x in tmp])) - -for k, v in samps.items(): - disj = Diff(tmp, [a_tuple[0] for a_tuple in v]) - for val in disj: - v.append((val, "0")) - li = [] - for h in tmp: - for x in v: - if x[0] == h: - li.append(x[1]) - print("\t".join(k.split("_")) + "\t" + "\t".join(li)) -sys.exit() diff --git a/bin/consolidate_algorithms_intersection.R b/bin/consolidate_algorithms_intersection.R deleted file mode 100755 index 1fbd27b4..00000000 --- a/bin/consolidate_algorithms_intersection.R +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env Rscript - -## Script to consolidate circRNAs across multiple tools. Allow user -## to apply 'max' or 'mean' aggregate function to those called by multiple -## tools. -## Author: Barry Digby -## License: MIT - -get_args <- function(){ - - argp <- arg_parser( - description="Script to take tool outputs and bring forward circRNAs called by at least n tools", - hide.opts=TRUE) - - argp <- add_argument( - parser=argp, - arg="samples", - short="s", - help="csv file listing tool output files that are not empty", - default="samples.csv") - - argp <- add_argument( - parser=argp, - arg="n_tools", - short="n", - help="number of tools circrna must be called by") - - argp <- add_argument( - parser=argp, - arg="duplicates_fun", - short="d", - help="how to handle counts for duplicate circRNAs [mean, max]") - - argv <- parse_args( - parser=argp, - argv=commandArgs(trailingOnly=TRUE)) - - return(argv) -} - -giveError <- function(message){ - cat(paste("\n", message, sep="")) - quit() -} - -usage <- function(){giveError("Usage: consolidate_algorithms.R samples.csv ${params.n_tools}")} - -## script body - -stage_data <- function(samples, n_tools, duplicates_fun){ - - inputdata <- list() - - samples <- read.csv(samples, sep="\t", header=F, stringsAsFactors=FALSE) - inputdata$samples <- samples - inputdata$n_tools <- n_tools - inputdata$duplicates_fun <- duplicates_fun - - return(inputdata) -} - - -## read in files and make circRNA IDs. - -main <- function(inputdata){ - - samples <- inputdata$samples - n_tools <- inputdata$n_tools - duplicates_fun <- inputdata$duplicates_fun - - ## intit lists - dflist <- list() - idlist <- list() - - # loop over samples, append to counts mat and IDs to respective lists - for(i in 1:nrow(samples)){ - file_handle <- file.path(paste("./", samples$V1[i], sep="")) - df <- read.table(file_handle, sep="\t", header=F, stringsAsFactors=FALSE) - dflist[[i]] <- read.table(file_handle, sep="\t", header=F, stringsAsFactors=FALSE) - idlist[[i]] <- with(df, paste0(V1, sep="-", V2, sep=":", V3, sep="-", V4)) - } - - # place all ids in a vector - vec <- unlist(idlist) - - # make table to get ID ocurrence count - tab <- table(vec) - - # now filter by ocurrence i.e must have been in "n" tools - filt_id <- names(tab)[tab >= n_tools] - - # make matser df, append ID - mat <- do.call("rbind", dflist) - mat$ID <- with(mat, paste0(V1, sep="-", V2, sep=":", V3, sep="-", V4)) - - # extract circrnas called by n tools - mat <- subset(mat, mat$ID %in% filt_id) - print(head(mat)) - # handle duplicate circRNA counts: - if(duplicates_fun == "max"){ - - # Take the max value for duplicate circRNAs - mat <- mat[order(mat$ID, -abs(mat$V5)),] - mat <- mat[!duplicated(mat$ID),] - mat <- subset(mat, select=-c(ID)) - }else{ - - # Remove duplicates like above to generate row indices - tmp <- mat[order(mat$ID, -abs(mat$V5)),] - tmp <- tmp[!duplicated(tmp$ID),] - # Now Take average values, append back to tmp. - mat <- setNames(aggregate(mat$V5, list(mat$ID), FUN=mean), c("ID", "V5")) - stopifnot(nrow(tmp)==nrow(mat)) - tmp <- subset(tmp, select=c(V1,V2,V3,V4)) - mat <- cbind(tmp,mat) - # round up to nearest integer - mat$V5 <- ceiling(mat$V5) - mat <- subset(mat, select=-c(ID)) - } - - write.table(mat, "combined_counts.bed", sep="\t", row.names = F, col.names = F, quote = F) - -} - -## error messages, library load -options(error=function()traceback(2)) -suppressPackageStartupMessages(library("argparser")) - -## initiate script -arg <- get_args() - -inputdata <- stage_data(arg$samples, arg$n_tools, arg$duplicates_fun) - -x <- main(inputdata) diff --git a/bin/counts_combined.py b/bin/counts_combined.py new file mode 100755 index 00000000..cb40c588 --- /dev/null +++ b/bin/counts_combined.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +import argparse +import pandas as pd +import os + +parser = argparse.ArgumentParser(description='Merge counts across tools for a single sample') +parser.add_argument('--beds', type=str, nargs='+', help='List of bed files to merge') +parser.add_argument('--out_bed', type=str, help='Output bed file') +parser.add_argument('--out_tsv', type=str, help='Output tsv file') + +args = parser.parse_args() + +columns = ['chr', 'start', 'end', 'strand', 'count', 'tools'] +dfs = {os.path.basename(bed).split('.')[0]: pd.read_csv(bed, + sep='\t', + header=None, + names=columns, + index_col=[0, 1, 2, 3]) + .drop('tools', axis=1) for bed in args.beds} + +dfs = [df.rename(columns={'count': sample}) for sample, df in dfs.items()] + +df = pd.concat(dfs, axis=1) +df = df.fillna(0).astype(int) + +df.to_csv(args.out_bed, sep='\t') + +df.index = df.index.map(lambda x: f'{x[0]}:{x[1]}-{x[2]}:{x[3]}') +df.to_csv(args.out_tsv, sep='\t') \ No newline at end of file diff --git a/bin/merge_tools.py b/bin/merge_tools.py new file mode 100755 index 00000000..4246d0fd --- /dev/null +++ b/bin/merge_tools.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +import argparse +import pandas as pd + +parser = argparse.ArgumentParser(description='Merge counts across tools for a single sample') +parser.add_argument('--beds', type=str, nargs='+', help='List of bed files to merge') +parser.add_argument('--tool_filter', type=int, help='Minimum number of tools to keep a circRNA') +parser.add_argument('--duplicates_fun', type=str, help='Function to apply to duplicates', choices=['sum', 'mean', 'max', 'min']) +parser.add_argument('--output', type=str, help='Output file') + +args = parser.parse_args() + +columns = ['chr', 'start', 'end', 'strand', 'count'] +dfs = [pd.read_csv(bed, sep='\t', header=None, names=columns) for bed in args.beds] +df = pd.concat(dfs) + +df['tool_count'] = 1 + +df = df.groupby(['chr', 'start', 'end', 'strand']).agg({'count': args.duplicates_fun, + 'tool_count': 'sum'}).reset_index() +df = df[df['tool_count'] >= args.tool_filter] + +df.to_csv(args.output, sep='\t', index=False, header=False) diff --git a/modules/local/count_matrix/combined/main.nf b/modules/local/count_matrix/combined/main.nf index 0c4719ab..5b3bc28a 100644 --- a/modules/local/count_matrix/combined/main.nf +++ b/modules/local/count_matrix/combined/main.nf @@ -1,37 +1,28 @@ process COUNTS_COMBINED { - label 'process_low' + label "process_single" - conda "conda-forge::r-base=3.6.3 conda-forge::python=2.7.15 conda-forge::r-argparser=0.6 conda-forge::r-dplyr=1.0.5" + conda "conda-forge::mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6==fccb0c41a243c639e11dd1be7b74f563e624fcca-0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' : - 'quay.io/biocontainers/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' }" + 'https://depot.galaxyproject.org/singularity/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0': + 'biocontainers/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0' }" input: - path(bed) + path(beds) output: - path("circRNA_matrix.txt"), emit: dea_matrix - path("count_matrix.txt") , emit: clr_matrix + path("merged_counts.bed") , emit: counts_bed + path("merged_counts.tsv") , emit: counts_tsv path "versions.yml" , emit: versions - when: - task.ext.when == null || task.ext.when - script: - def args = task.ext.args ?: '' """ - circRNA_counts_matrix.py > matrix.txt - ## handle non-canon chromosomes here (https://stackoverflow.com/questions/71479919/joining-columns-based-on-number-of-fields) - n_samps=\$(ls *.bed | wc -l) - canon=\$(awk -v a="\$n_samps" 'BEGIN {print a + 4}') - awk -v n="\$canon" '{ for (i = 2; i <= NF - n + 1; ++i) { \$1 = \$1"-"\$i; \$i=""; } } 1' matrix.txt | awk -v OFS="\\t" '\$1=\$1' > circRNA_matrix.txt - reformat_count_matrix.R + counts_combined.py --beds ${beds} --out_bed merged_counts.bed --out_tsv merged_counts.tsv cat <<-END_VERSIONS > versions.yml "${task.process}": - awk: \$(awk --version | head -n 1 | cut -d' ' -f3 | sed 's/,//g') - r-base: \$(echo \$(R --version 2>&1) | sed 's/^.*R version //; s/ .*\$//') - dplyr: \$(Rscript -e "library(dplyr); cat(as.character(packageVersion('dplyr')))") + python: \$(python --version | sed 's/Python //g') + pandas: \$(python -c "import pandas; print(pandas.__version__)") + numpy: \$(python -c "import numpy; print(numpy.__version__)") END_VERSIONS """ } diff --git a/modules/local/count_matrix/merge_tools/main.nf b/modules/local/count_matrix/merge_tools/main.nf index 106df47b..55bdcde0 100644 --- a/modules/local/count_matrix/merge_tools/main.nf +++ b/modules/local/count_matrix/merge_tools/main.nf @@ -1,45 +1,31 @@ process MERGE_TOOLS { tag "$meta.id" - label 'process_low' + label "process_single" - conda "conda-forge::r-base=3.6.3 conda-forge::python=2.7.15 conda-forge::r-argparser=0.6 conda-forge::r-dplyr=1.0.5" + conda "conda-forge::mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6==fccb0c41a243c639e11dd1be7b74f563e624fcca-0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' : - 'quay.io/biocontainers/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' }" + 'https://depot.galaxyproject.org/singularity/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0': + 'biocontainers/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0' }" input: - tuple val(meta), path(bed) + tuple val(meta), path(beds) val(tool_filter) val(duplicates_fun) output: - tuple val(meta), path("${prefix}.bed"), emit: merged - path "versions.yml" , emit: versions + tuple val(meta), path("${meta.id}.merged.bed"), emit: merged - when: - task.ext.when == null || task.ext.when + path "versions.yml" , emit: versions script: - def args = task.ext.args ?: '' - prefix = task.ext.prefix ?: "${meta.id}" """ - ## make list of files for R to read - ls *.bed > samples.csv - - ## Add catch for empty bed file and delete - check_empty.sh - - ## Use intersection of "n" (params.tool_filter) circRNAs called by tools - ## remove duplicate IDs, keep highest count. - consolidate_algorithms_intersection.R samples.csv $tool_filter $duplicates_fun - mv combined_counts.bed ${prefix}.bed + merge_tools.py --beds ${beds} --tool_filter ${tool_filter} --duplicates_fun ${duplicates_fun} --output ${meta.id}.merged.bed cat <<-END_VERSIONS > versions.yml "${task.process}": - r-base: \$(echo \$(R --version 2>&1) | sed 's/^.*R version //; s/ .*\$//') - argparser: \$(Rscript -e "library(arparser); cat(as.character(packageVersion('argparser')))") - dplyr: \$(Rscript -e "library(dplyr); cat(as.character(packageVersion('dplyr')))") - python: \$(python --version | sed -e 's/Python //g') + python: \$(python --version | sed 's/Python //g') + pandas: \$(python -c "import pandas; print(pandas.__version__)") + numpy: \$(python -c "import numpy; print(numpy.__version__)") END_VERSIONS """ } diff --git a/modules/local/count_matrix/single/main.nf b/modules/local/count_matrix/single/main.nf index 20e1b975..a7c01833 100644 --- a/modules/local/count_matrix/single/main.nf +++ b/modules/local/count_matrix/single/main.nf @@ -11,8 +11,8 @@ process COUNTS_SINGLE { tuple val(meta), path(bed) output: - path("circRNA_matrix.txt"), emit: dea_matrix - path("count_matrix.txt") , emit: clr_matrix + path("circRNA_matrix.txt"), emit: counts_bed + path("count_matrix.txt") , emit: counts_tsv path "versions.yml" , emit: versions when: diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index c45ac4ff..5e88dcaf 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -244,31 +244,20 @@ workflow CIRCRNA_DISCOVERY { tools_selected = params.tool.split(',').collect{it.trim().toLowerCase()} - if( tools_selected.size() > 1){ + MERGE_TOOLS( ch_matrix.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), + tools_selected.size() > 1 ? tool_filter : 1, duplicates_fun ) - MERGE_TOOLS( ch_matrix.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), tool_filter, duplicates_fun ) + COUNTS_COMBINED( MERGE_TOOLS.out.merged.map{ meta, bed -> bed }.collect() ) - COUNTS_COMBINED( MERGE_TOOLS.out.merged.map{ meta, bed -> return [ bed ] }.collect() ) - - dea_matrix = COUNTS_COMBINED.out.dea_matrix - clr_matrix = COUNTS_COMBINED.out.clr_matrix - ch_versions = ch_versions.mix(MERGE_TOOLS.out.versions) - ch_versions = ch_versions.mix(COUNTS_COMBINED.out.versions) - - }else{ - - COUNTS_SINGLE( ch_matrix.map{ meta, bed -> [ [tool: meta.tool], bed ] }.groupTuple() ) - - dea_matrix = COUNTS_SINGLE.out.dea_matrix - clr_matrix = COUNTS_SINGLE.out.clr_matrix - ch_versions = ch_versions.mix(COUNTS_SINGLE.out.versions) - - } + counts_bed = COUNTS_COMBINED.out.counts_bed + counts_tsv = COUNTS_COMBINED.out.counts_tsv + ch_versions = ch_versions.mix(MERGE_TOOLS.out.versions) + ch_versions = ch_versions.mix(COUNTS_COMBINED.out.versions) emit: circrna_bed12 = ANNOTATION.out.bed fasta = FASTA.out.analysis_fasta versions = ch_versions - dea_matrix - clr_matrix + counts_bed + counts_tsv } diff --git a/subworkflows/local/differential_expression.nf b/subworkflows/local/differential_expression.nf index f341fd3f..f4454af6 100644 --- a/subworkflows/local/differential_expression.nf +++ b/subworkflows/local/differential_expression.nf @@ -17,8 +17,8 @@ workflow DIFFERENTIAL_EXPRESSION { hisat2_index splice_sites phenotype - dea_matrix - clr_matrix + counts_bed + counts_tsv species ensembl_map exon_boundary @@ -49,7 +49,7 @@ workflow DIFFERENTIAL_EXPRESSION { // Circular, Linear Differential Expression // - DESEQ2_DIFFERENTIAL_EXPRESSION( STRINGTIE_PREPDE.out.gene_matrix, phenotype, dea_matrix, species, ensembl_map ) + DESEQ2_DIFFERENTIAL_EXPRESSION( STRINGTIE_PREPDE.out.gene_matrix, phenotype, counts_bed, species, ensembl_map ) // // CircRNA - Host Gene Ratio tests @@ -57,8 +57,8 @@ workflow DIFFERENTIAL_EXPRESSION { ch_biotypes = Channel.fromPath("${projectDir}/bin/unwanted_biotypes.txt") - PARENT_GENE( clr_matrix, gtf, ch_biotypes.collect(), exon_boundary ) - PREPARE_CLR_TEST( STRINGTIE_PREPDE.out.gene_matrix, clr_matrix, PARENT_GENE.out.circ_host_map, gtf ) + PARENT_GENE( counts_tsv, gtf, ch_biotypes.collect(), exon_boundary ) + PREPARE_CLR_TEST( STRINGTIE_PREPDE.out.gene_matrix, counts_tsv, PARENT_GENE.out.circ_host_map, gtf ) CIRCTEST( PREPARE_CLR_TEST.out.circular, PREPARE_CLR_TEST.out.linear, phenotype ) ch_versions = ch_versions.mix(HISAT2_ALIGN.out.versions) diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 0fa1446c..ffbb2c51 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -156,7 +156,7 @@ workflow CIRCRNA { QUANTIFICATION( ch_gtf, ch_fasta, - CIRCRNA_DISCOVERY.out.dea_matrix, + CIRCRNA_DISCOVERY.out.counts_bed, FASTQC_TRIMGALORE.out.reads ) @@ -185,8 +185,8 @@ workflow CIRCRNA { hisat2_index, PREPARE_GENOME.out.splice_sites, ch_phenotype, - CIRCRNA_DISCOVERY.out.dea_matrix, - CIRCRNA_DISCOVERY.out.clr_matrix, + CIRCRNA_DISCOVERY.out.counts_bed, + CIRCRNA_DISCOVERY.out.counts_tsv, ch_species, ch_ensembl_database_map, params.exon_boundary From be5f1341a1fa051de40abe6b42865ad4ad376d9f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 15:36:03 +0100 Subject: [PATCH 172/491] Use tximport --- conf/modules.config | 4 ++-- modules/local/psirc/quant/main.nf | 2 -- subworkflows/local/quantification.nf | 6 ++++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 5504f876..47097587 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -685,8 +685,8 @@ if (!params.skip_trimming) { ext.suffix = "bed" } - withName: TRANSCRIPTOME_FASTA { - ext.args = "-nameOnly" + withName: CIRCULAR_TRANSCRIPTOME { + ext.args = "-s" } withName: MARK_CIRCULAR { diff --git a/modules/local/psirc/quant/main.nf b/modules/local/psirc/quant/main.nf index df4e8b54..aa949e3e 100644 --- a/modules/local/psirc/quant/main.nf +++ b/modules/local/psirc/quant/main.nf @@ -9,8 +9,6 @@ process PSIRC_QUANT { tuple val(meta2), path(index) output: - tuple val(meta), path("${meta.id}/abundance.tsv"), emit: abundance_tsv - tuple val(meta), path("${meta.id}/abundance.h5"), emit: abundance_h5 tuple val(meta), path("${meta.id}"), emit: directory script: diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index 2757838d..a1739611 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -44,4 +44,10 @@ workflow QUANTIFICATION { "gene_id", "gene_name" ) + + TXIMETA_TXIMPORT( + PSIRC_QUANT.out.directory, + CUSTOM_TX2GENE.out.tx2gene, + "kallisto" + ) } From 9723eaf2d302f0e33e136be9b8babdf8786a4d4d Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 17:07:22 +0100 Subject: [PATCH 173/491] Finalize quantification --- bin/combine_quantification.py | 51 +++++++++++++++++++ conf/modules.config | 17 ++++--- modules/local/psirc/combine/main.nf | 50 ------------------ .../combine_quantification/main.nf | 35 +++++++++++++ subworkflows/local/circrna_discovery.nf | 5 +- subworkflows/local/quantification.nf | 35 ++++++++----- workflows/circrna/main.nf | 3 +- 7 files changed, 124 insertions(+), 72 deletions(-) create mode 100755 bin/combine_quantification.py delete mode 100644 modules/local/psirc/combine/main.nf create mode 100644 modules/local/quantification/combine_quantification/main.nf diff --git a/bin/combine_quantification.py b/bin/combine_quantification.py new file mode 100755 index 00000000..d26ade6c --- /dev/null +++ b/bin/combine_quantification.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +import argparse +import pandas as pd +import os + +parser = argparse.ArgumentParser(description='Merge quantification files into a single file') +parser.add_argument('--inputs', type=str, nargs='+', help='List input files to merge') +parser.add_argument('--tx2gene', type=str, help='Path to tx2gene file') +parser.add_argument('--circ_annotation', type=str, help='Path to circRNA annotation file') +parser.add_argument('--out_linear', type=str, help='Path to output linear RNA quantification file') +parser.add_argument('--out_circular', type=str, help='Path to output circRNA quantification file') +parser.add_argument('--out_combined', type=str, help='Path to output combined quantification file') + +args = parser.parse_args() + +df_annotation = pd.read_csv(args.circ_annotation, + sep='\t', header=None, + names=['chr', 'start', 'end', 'name', 'score', 'strand', 'type', 'gene', 'transcript'], + index_col=['name']) + +df_tx2gene = pd.read_csv(args.tx2gene, sep='\t') + +dfs = [pd.read_csv(f, sep='\t', index_col=["gene_id", "gene_name"]) for f in args.inputs] +df_combined = pd.concat(dfs, axis=1, sort=True) + +# Split linear and circular +linear_mask = df_combined.index.get_level_values(0) \ + .isin(df_tx2gene["gene_id"]) +df_linear = df_combined[linear_mask].copy() +df_circular = df_combined[~linear_mask].copy() + +df_linear.to_csv(args.out_linear, sep='\t') + +# Perform annotation +df_annotation["annotation"] = df_annotation.apply(lambda row: 'intergenic' if row['type'] == 'intergenic-circRNA' else row['gene'], axis=1) +annotation_dict = df_annotation["annotation"].to_dict() + +df_circular.reset_index(inplace=True) +df_circular["gene_name"] = df_circular['gene_id'].map(annotation_dict) +df_circular.set_index(["gene_id", "gene_name"], inplace=True) + +df_circular.to_csv(args.out_circular, sep='\t') + +# Save combined +df_linear["type"] = "gene" +df_circular["type"] = "circRNA" + +df_combined = pd.concat([df_linear, df_circular], axis=0, sort=True) + +df_combined.to_csv(args.out_combined, sep='\t') \ No newline at end of file diff --git a/conf/modules.config b/conf/modules.config index 47097587..4bfcba71 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -643,11 +643,9 @@ if (!params.skip_trimming) { ext.suffix = "combined.bed" } - withName: REMOVE_SCORE { - // AWK command to replace the 5th column with a dot - // input and output are both BED files - ext.args = "-v FS='\\t' -v OFS='\\t' '{ \$5=\".\"; print }'" - ext.suffix = "noscore.bed" + withName: REMOVE_SCORE_STRAND { + ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3, \".\", \".\", \$7, \$8, \$9 }'" + ext.suffix = "tidy.bed" } withName: FASTA { @@ -681,12 +679,17 @@ if (!params.skip_trimming) { } withName: COUNTS_TO_BED { - ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$4, \".\", \$4 }'" + ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3, \".\", \".\" }'" ext.suffix = "bed" } + withName: UNIQUE_REGIONS { + ext.args = "-k 1,1 -k2,2n -k3,3n -u" + ext.suffix = "unique.bed" + } + withName: CIRCULAR_TRANSCRIPTOME { - ext.args = "-s" + ext.args = "-nameOnly" } withName: MARK_CIRCULAR { diff --git a/modules/local/psirc/combine/main.nf b/modules/local/psirc/combine/main.nf deleted file mode 100644 index 4aa23e6a..00000000 --- a/modules/local/psirc/combine/main.nf +++ /dev/null @@ -1,50 +0,0 @@ -process PSIRC_COMBINE { - label 'process_single' - - conda "conda-forge::mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6==fccb0c41a243c639e11dd1be7b74f563e624fcca-0" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0': - 'biocontainers/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0' }" - - input: - path(files) - - output: - path("linear_counts.tsv"), emit: linear_counts - path("circular_counts.tsv"), emit: circular_counts - path("counts.tsv"), emit: counts - - path("linear_tpm.tsv"), emit: linear_tpm - path("circular_tpm.tsv"), emit: circular_tpm - path("tpm.tsv"), emit: tpm - - - script: - """ - #!/usr/bin/env python - - import os - import pandas as pd - - files = "${files}".split(" ") - - counts_df = pd.DataFrame() - tpm_df = pd.DataFrame() - - for f in files: - sample_name = os.path.basename(f)[:-len(".tsv")] - df = pd.read_csv(f, sep="\\t", index_col=0) - - counts_df[sample_name] = df["est_counts"] - tpm_df[sample_name] = df["tpm"] - - for name, df in [("counts", counts_df), ("tpm", tpm_df)]: - is_linear = df.index.str.startswith("ENS") - linear_df = df[is_linear] - circular_df = df[~is_linear] - - linear_df.to_csv(f"linear_{name}.tsv", sep="\\t") - circular_df.to_csv(f"circular_{name}.tsv", sep="\\t") - df.to_csv(f"{name}.tsv", sep="\\t") - """ -} diff --git a/modules/local/quantification/combine_quantification/main.nf b/modules/local/quantification/combine_quantification/main.nf new file mode 100644 index 00000000..35193372 --- /dev/null +++ b/modules/local/quantification/combine_quantification/main.nf @@ -0,0 +1,35 @@ +process COMBINE_QUANTIFICATION { + label "process_single" + + conda "conda-forge::mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6==fccb0c41a243c639e11dd1be7b74f563e624fcca-0" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0': + 'biocontainers/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0' }" + + input: + tuple val(meta), path(inputs) + tuple val(meta2), path(tx2gene) + tuple val(meta3), path(circ_annotation) + + output: + path("${meta.id}.linear.tsv") , emit: linear + path("${meta.id}.circular.tsv") , emit: circular + path "versions.yml" , emit: versions + + script: + """ + combine_quantification.py --inputs ${inputs} \\ + --tx2gene ${tx2gene} \\ + --circ_annotation ${circ_annotation} \\ + --out_linear ${meta.id}.linear.tsv \\ + --out_circular ${meta.id}.circular.tsv \\ + --out_combined ${meta.id}.combined.tsv + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + python: \$(python --version | sed 's/Python //g') + pandas: \$(python -c "import pandas; print(pandas.__version__)") + numpy: \$(python -c "import numpy; print(numpy.__version__)") + END_VERSIONS + """ +} diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 5e88dcaf..62275d50 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -1,7 +1,7 @@ include { ANNOTATION } from '../../modules/local/annotation/full_annotation/main' include { GNU_SORT as COMBINE_ANNOTATIONS } from '../../modules/nf-core/gnu/sort/main' -include { GAWK as REMOVE_SCORE } from '../../modules/nf-core/gawk/main' +include { GAWK as REMOVE_SCORE_STRAND } from '../../modules/nf-core/gawk/main' include { BEDTOOLS_INTERSECT as INTERSECT_ANNOTATION } from '../../modules/nf-core/bedtools/intersect/main' include { BOWTIE2_ALIGN as FIND_CIRC_ALIGN } from '../../modules/nf-core/bowtie2/align/main' include { SAMTOOLS_VIEW } from '../../modules/nf-core/samtools/view/main' @@ -218,7 +218,7 @@ workflow CIRCRNA_DISCOVERY { INTERSECT_ANNOTATION( circrna_filtered.combine(gtf), [[], []]) ANNOTATION( INTERSECT_ANNOTATION.out.intersect, exon_boundary ) COMBINE_ANNOTATIONS(ANNOTATION.out.bed.map{ meta, bed -> bed}.collect().map{[[id: "annotation"], it]}) - REMOVE_SCORE( COMBINE_ANNOTATIONS.out.sorted, []) + REMOVE_SCORE_STRAND( COMBINE_ANNOTATIONS.out.sorted, []) ch_versions = ch_versions.mix(INTERSECT_ANNOTATION.out.versions) ch_versions = ch_versions.mix(ANNOTATION.out.versions) @@ -257,6 +257,7 @@ workflow CIRCRNA_DISCOVERY { emit: circrna_bed12 = ANNOTATION.out.bed fasta = FASTA.out.analysis_fasta + annotation = REMOVE_SCORE_STRAND.out.output versions = ch_versions counts_bed counts_tsv diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index a1739611..25e66c5a 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -1,13 +1,14 @@ -include { TRANSCRIPTOME as LINEAR_TRANSCRIPTOME } from '../../modules/local/quantification/transcriptome/main' +include { TRANSCRIPTOME as LINEAR_TRANSCRIPTOME } from '../../modules/local/quantification/transcriptome/main' include { BEDTOOLS_GETFASTA as CIRCULAR_TRANSCRIPTOME } from '../../modules/nf-core/bedtools/getfasta/main' -include { GAWK as COUNTS_TO_BED } from '../../modules/nf-core/gawk/main' -include { CAT_CAT as CAT_TRANSCRIPTOME } from '../../modules/nf-core/cat/cat/main' -include { GAWK as MARK_CIRCULAR } from '../../modules/nf-core/gawk/main' -include { PSIRC_INDEX } from '../../modules/local/psirc/index/main' -include { PSIRC_QUANT } from '../../modules/local/psirc/quant/main' -include { PSIRC_COMBINE } from '../../modules/local/psirc/combine/main' -include { CUSTOM_TX2GENE } from '../../modules/nf-core/custom/tx2gene/main' -include { TXIMETA_TXIMPORT } from '../../modules/nf-core/tximeta/tximport/main' +include { GAWK as COUNTS_TO_BED } from '../../modules/nf-core/gawk/main' +include { GNU_SORT as UNIQUE_REGIONS } from '../../modules/nf-core/gnu/sort/main' +include { CAT_CAT as CAT_TRANSCRIPTOME } from '../../modules/nf-core/cat/cat/main' +include { GAWK as MARK_CIRCULAR } from '../../modules/nf-core/gawk/main' +include { PSIRC_INDEX } from '../../modules/local/psirc/index/main' +include { PSIRC_QUANT } from '../../modules/local/psirc/quant/main' +include { CUSTOM_TX2GENE } from '../../modules/nf-core/custom/tx2gene/main' +include { TXIMETA_TXIMPORT } from '../../modules/nf-core/tximeta/tximport/main' +include { COMBINE_QUANTIFICATION } from '../../modules/local/quantification/combine_quantification/main' workflow QUANTIFICATION { take: @@ -15,13 +16,15 @@ workflow QUANTIFICATION { ch_fasta counts reads + circ_annotation main: LINEAR_TRANSCRIPTOME(ch_gtf, ch_fasta) COUNTS_TO_BED(counts.map{counts -> [[id: "counts"], counts]}, []) + UNIQUE_REGIONS(COUNTS_TO_BED.out.output) CIRCULAR_TRANSCRIPTOME( - COUNTS_TO_BED.out.output.map{meta, bed -> bed}, + UNIQUE_REGIONS.out.sorted.map{meta, bed -> bed}, ch_fasta.map{meta, fasta -> fasta} ) @@ -35,11 +38,10 @@ workflow QUANTIFICATION { PSIRC_INDEX(MARK_CIRCULAR.out.output) PSIRC_QUANT(reads, PSIRC_INDEX.out.collect()) - // PSIRC_COMBINE( PSIRC_QUANT.out.abundance_tsv.map{ meta, data -> data }.collect() ) CUSTOM_TX2GENE( ch_gtf, - PSIRC_QUANT.out.directory, + PSIRC_QUANT.out.directory.map{meta, quant -> quant}.collect().map{[[id: "quant"], it]}, "kallisto", "gene_id", "gene_name" @@ -50,4 +52,13 @@ workflow QUANTIFICATION { CUSTOM_TX2GENE.out.tx2gene, "kallisto" ) + + ch_counts = TXIMETA_TXIMPORT.out.counts_gene + ch_tpm = TXIMETA_TXIMPORT.out.tpm_gene + + COMBINE_QUANTIFICATION( + ch_counts.map{meta, counts -> counts}.collect().map{[[id: "counts"], it]}, + CUSTOM_TX2GENE.out.tx2gene, + circ_annotation + ) } diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index ffbb2c51..3db9ee32 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -157,7 +157,8 @@ workflow CIRCRNA { ch_gtf, ch_fasta, CIRCRNA_DISCOVERY.out.counts_bed, - FASTQC_TRIMGALORE.out.reads + FASTQC_TRIMGALORE.out.reads, + CIRCRNA_DISCOVERY.out.annotation ) // From 9c1ef11da2e3b04ae02520945654143e8314d7fc Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 17:09:49 +0100 Subject: [PATCH 174/491] Implement quantification aggregation for TPMs --- .../quantification/combine_quantification/main.nf | 1 + subworkflows/local/quantification.nf | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/local/quantification/combine_quantification/main.nf b/modules/local/quantification/combine_quantification/main.nf index 35193372..975ae48f 100644 --- a/modules/local/quantification/combine_quantification/main.nf +++ b/modules/local/quantification/combine_quantification/main.nf @@ -14,6 +14,7 @@ process COMBINE_QUANTIFICATION { output: path("${meta.id}.linear.tsv") , emit: linear path("${meta.id}.circular.tsv") , emit: circular + path("${meta.id}.combined.tsv") , emit: combined path "versions.yml" , emit: versions script: diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index 25e66c5a..a06c1360 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -8,7 +8,8 @@ include { PSIRC_INDEX } from '../../modules/loca include { PSIRC_QUANT } from '../../modules/local/psirc/quant/main' include { CUSTOM_TX2GENE } from '../../modules/nf-core/custom/tx2gene/main' include { TXIMETA_TXIMPORT } from '../../modules/nf-core/tximeta/tximport/main' -include { COMBINE_QUANTIFICATION } from '../../modules/local/quantification/combine_quantification/main' +include { COMBINE_QUANTIFICATION as COMBINE_COUNTS } from '../../modules/local/quantification/combine_quantification/main' +include { COMBINE_QUANTIFICATION as COMBINE_TPM } from '../../modules/local/quantification/combine_quantification/main' workflow QUANTIFICATION { take: @@ -56,9 +57,15 @@ workflow QUANTIFICATION { ch_counts = TXIMETA_TXIMPORT.out.counts_gene ch_tpm = TXIMETA_TXIMPORT.out.tpm_gene - COMBINE_QUANTIFICATION( + COMBINE_COUNTS( ch_counts.map{meta, counts -> counts}.collect().map{[[id: "counts"], it]}, CUSTOM_TX2GENE.out.tx2gene, circ_annotation ) + + COMBINE_TPM( + ch_tpm.map{meta, tpm -> tpm}.collect().map{[[id: "tpm"], it]}, + CUSTOM_TX2GENE.out.tx2gene, + circ_annotation + ) } From d384c65614ddb18b9ce6121babc28a243d54ca6f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 17:18:39 +0100 Subject: [PATCH 175/491] Override publishdir of quantification results --- conf/modules.config | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/conf/modules.config b/conf/modules.config index 4bfcba71..e070d457 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -700,6 +700,22 @@ if (!params.skip_trimming) { ext.suffix = "marked.fasta" } + withName: COMBINE_COUNTS { + publishDir = [ + path: { "${params.outdir}/quantification/" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + + withName: COMBINE_TPM { + publishDir = [ + path: { "${params.outdir}/quantification/" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + withName: TARGETSCAN_DATABASE { ext.when = { params.module.split(',').contains('mirna_prediction') } publishDir = [ From 4ef2321313939df1ff3c11a721cc089cac33a0c4 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 17:19:53 +0100 Subject: [PATCH 176/491] Emit Quantification results --- subworkflows/local/quantification.nf | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index a06c1360..edf44ea1 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -68,4 +68,13 @@ workflow QUANTIFICATION { CUSTOM_TX2GENE.out.tx2gene, circ_annotation ) + + emit: + counts_linear = COMBINE_COUNTS.out.linear + counts_circular = COMBINE_COUNTS.out.circular + counts_combined = COMBINE_COUNTS.out.combined + + tpm_linear = COMBINE_TPM.out.linear + tpm_circular = COMBINE_TPM.out.circular + tpm_combined = COMBINE_TPM.out.combined } From 047421af5e8a90cd6e68178b068809eebc5ca255 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 17:21:25 +0100 Subject: [PATCH 177/491] Align indentation --- subworkflows/local/quantification.nf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index edf44ea1..d6256a6e 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -70,11 +70,11 @@ workflow QUANTIFICATION { ) emit: - counts_linear = COMBINE_COUNTS.out.linear + counts_linear = COMBINE_COUNTS.out.linear counts_circular = COMBINE_COUNTS.out.circular counts_combined = COMBINE_COUNTS.out.combined - tpm_linear = COMBINE_TPM.out.linear - tpm_circular = COMBINE_TPM.out.circular - tpm_combined = COMBINE_TPM.out.combined + tpm_linear = COMBINE_TPM.out.linear + tpm_circular = COMBINE_TPM.out.circular + tpm_combined = COMBINE_TPM.out.combined } From 9261572a615f9beb7fb4df9da2ce195402f67d71 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 17:40:35 +0100 Subject: [PATCH 178/491] Remove traces of old count combination --- bin/DEA.R | 4 +- bin/prepare_circ_test.R | 2 +- bin/reformat_count_matrix.R | 16 ------- conf/modules.config | 16 ------- modules/local/count_matrix/single/main.nf | 48 ------------------- .../deseq2/differential_expression/main.nf | 2 +- subworkflows/local/circrna_discovery.nf | 1 - 7 files changed, 4 insertions(+), 85 deletions(-) delete mode 100755 bin/reformat_count_matrix.R delete mode 100644 modules/local/count_matrix/single/main.nf diff --git a/bin/DEA.R b/bin/DEA.R index 83f3cccf..bd10c931 100755 --- a/bin/DEA.R +++ b/bin/DEA.R @@ -28,7 +28,7 @@ get_args <- function(){ arg="circRNA", short="c", help="circRNA counts matrix", - default="circRNA_matrix.txt") + default="merged_counts.bed") argp <- add_argument( parser=argp, @@ -57,7 +57,7 @@ giveError <- function(message){ quit() } -usage <- function(){giveError("USAGE: DEA.R ")} +usage <- function(){giveError("USAGE: DEA.R ")} stage_data <- function(gene_counts, phenotype, circRNA, species, map){ diff --git a/bin/prepare_circ_test.R b/bin/prepare_circ_test.R index f95b8f9c..95057f19 100755 --- a/bin/prepare_circ_test.R +++ b/bin/prepare_circ_test.R @@ -3,7 +3,7 @@ ## Author: Barry Digby ## License: MIT -circ_mat = read.table("count_matrix.txt", header=T, sep="\t", check.names = FALSE, stringsAsFactors = F, row.names = "ID") +circ_mat = read.table("merged_counts.tsv", header=T, sep="\t", check.names = FALSE, stringsAsFactors = F, row.names = "ID") gene_mat = read.table("gene_count_matrix.csv", sep=",", header=T, row.names="gene_id", stringsAsFactors = F) map = read.table("circrna_host-gene.txt", header = F, sep="\t", stringsAsFactors = F) diff --git a/bin/reformat_count_matrix.R b/bin/reformat_count_matrix.R deleted file mode 100755 index 3c635b29..00000000 --- a/bin/reformat_count_matrix.R +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env Rscript - -## Author: Barry Digby -## License: MIT - -library(dplyr) -mat <- read.table("circRNA_matrix.txt", sep="\t", header=T, stringsAsFactors=F, check.names=F) -mat$ID <- with(mat, paste0(Chr, sep=":", Start, sep="-", Stop, sep=":", Strand)) -mat <- mat[,-c(1:4)] -mat1 <- mat %>% select(ID, everything()) -ID <- as.data.frame(mat1$ID) -mat <- as.data.frame(subset(mat1, select=-c(ID))) -mat <- mat[, order(names(mat))] -mat1 <- cbind(ID, mat) -colnames(mat1)[1] <- "ID" -write.table(mat1, "count_matrix.txt", sep="\t", row.names=F, col.names=T, quote=F) diff --git a/conf/modules.config b/conf/modules.config index e070d457..fc6a6ba9 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -658,24 +658,8 @@ if (!params.skip_trimming) { ] } - withName: COUNTS_SINGLE { - ext.when = { params.module.split(',').contains('circrna_discovery') } - publishDir = [ - path: { "${params.outdir}/circrna_discovery/" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - pattern: "*.txt" - ] - } - withName: COUNTS_COMBINED { ext.when = { params.module.split(',').contains('circrna_discovery') } - publishDir = [ - path: { "${params.outdir}/circrna_discovery/" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - pattern: "count_matrix.txt" - ] } withName: COUNTS_TO_BED { diff --git a/modules/local/count_matrix/single/main.nf b/modules/local/count_matrix/single/main.nf deleted file mode 100644 index a7c01833..00000000 --- a/modules/local/count_matrix/single/main.nf +++ /dev/null @@ -1,48 +0,0 @@ -process COUNTS_SINGLE { - tag "${meta.tool}" - label 'process_low' - - conda "conda-forge::r-base=3.6.3 conda-forge::python=2.7.15 conda-forge::r-argparser=0.6 conda-forge::r-dplyr=1.0.5" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' : - 'quay.io/biocontainers/mulled-v2-5fbffedf7f529cf3c5093b976deb4290f5e1267a:3456f1432b1c9dad42815275abe2d6cb6f26fd94-0' }" - - input: - tuple val(meta), path(bed) - - output: - path("circRNA_matrix.txt"), emit: counts_bed - path("count_matrix.txt") , emit: counts_tsv - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - def tool_name = "${meta.tool}" - """ - # Strip tool name from BED files (no consolidation prior to this step for 1 tool) - for b in *.bed; do - basename=\${b%".bed"}; - sample_name=\${basename%"_${tool_name}"}; - mv \$b \${sample_name}.bed - done - - circRNA_counts_matrix.py > matrix.txt - ## handle non-canon chromosomes here (https://stackoverflow.com/questions/71479919/joining-columns-based-on-number-of-fields) - n_samps=\$(ls *.bed | wc -l) - canon=\$(awk -v a="\$n_samps" 'BEGIN {print a + 4}') - awk -v n="\$canon" '{ for (i = 2; i <= NF - n + 1; ++i) { \$1 = \$1"-"\$i; \$i=""; } } 1' matrix.txt | awk -v OFS="\\t" '\$1=\$1' > circRNA_matrix.txt - reformat_count_matrix.R - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - awk: \$(awk --version | head -n 1 | cut -d' ' -f3 | sed 's/,//g') - r-base: \$(echo \$(R --version 2>&1) | sed 's/^.*R version //; s/ .*\$//') - argparser: \$(Rscript -e "library(arparser); cat(as.character(packageVersion('argparser')))") - dplyr: \$(Rscript -e "library(dplyr); cat(as.character(packageVersion('dplyr')))") - python: \$(python --version | sed -e 's/Python //g') - END_VERSIONS - """ -} diff --git a/modules/local/deseq2/differential_expression/main.nf b/modules/local/deseq2/differential_expression/main.nf index 86ee474c..249bcba4 100644 --- a/modules/local/deseq2/differential_expression/main.nf +++ b/modules/local/deseq2/differential_expression/main.nf @@ -30,7 +30,7 @@ process DESEQ2_DIFFERENTIAL_EXPRESSION { tail -n +2 $phenotype | LC_COLLATE=C sort > sorted_pheno cat header sorted_pheno > tmp && rm phenotype.csv && mv tmp phenotype.csv - DEA.R $gene_matrix $phenotype $circrna_matrix $species ensembl_database_map.txt + DEA.R -g $gene_matrix -p $phenotype -c $circrna_matrix -s $species -m ensembl_database_map.txt mv boxplots/ circRNA/ mv *.RData DESeq2_QC/ diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 62275d50..49733e7f 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -32,7 +32,6 @@ include { MAPSPLICE_ALIGN } from '../../modules/l include { FASTA } from '../../modules/local/fasta/main' include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools/main' include { COUNTS_COMBINED } from '../../modules/local/count_matrix/combined/main' -include { COUNTS_SINGLE } from '../../modules/local/count_matrix/single/main' include { CIRCEXPLORER2_REFERENCE as CIRCEXPLORER2_REF } from '../../modules/local/circexplorer2/reference/main' include { CIRCEXPLORER2_PARSE as CIRCEXPLORER2_PAR } from '../../modules/nf-core/circexplorer2/parse/main' include { CIRCEXPLORER2_ANNOTATE as CIRCEXPLORER2_ANN } from '../../modules/nf-core/circexplorer2/annotate/main' From 8a8efa7f1ab41f53bb3d110ae6de44d52ae9c29e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 17:57:09 +0100 Subject: [PATCH 179/491] Fix compatibility issues with DGEA --- bin/DEA.R | 4 ++-- bin/counts_combined.py | 1 + modules/local/deseq2/differential_expression/main.nf | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/DEA.R b/bin/DEA.R index bd10c931..b40dbfa7 100755 --- a/bin/DEA.R +++ b/bin/DEA.R @@ -69,9 +69,9 @@ stage_data <- function(gene_counts, phenotype, circRNA, species, map){ circ <- read.table(circRNA, sep ="\t", header = T, stringsAsFactors=FALSE) # Merge circRNA genomic loci to ID - circ$circ <- with(circ, paste0(Chr, sep=":", Start, sep="-", Stop, sep=":", Strand)) + circ$circ <- with(circ, paste0(chr, sep=":", start, sep="-", end, sep=":", strand)) rownames(circ) <- circ$circ - circ <- subset(circ, select=-c(Chr, Start, Stop, Strand, circ)) + circ <- subset(circ, select=-c(chr, start, end, strand, circ)) # R converts '-' to '.' in colnames here and results in failures. # If you need to make this 'smarter' check that colnames contains '.', diff --git a/bin/counts_combined.py b/bin/counts_combined.py index cb40c588..7ae67065 100755 --- a/bin/counts_combined.py +++ b/bin/counts_combined.py @@ -27,4 +27,5 @@ df.to_csv(args.out_bed, sep='\t') df.index = df.index.map(lambda x: f'{x[0]}:{x[1]}-{x[2]}:{x[3]}') +df.index.name = 'ID' df.to_csv(args.out_tsv, sep='\t') \ No newline at end of file diff --git a/modules/local/deseq2/differential_expression/main.nf b/modules/local/deseq2/differential_expression/main.nf index 249bcba4..86ee474c 100644 --- a/modules/local/deseq2/differential_expression/main.nf +++ b/modules/local/deseq2/differential_expression/main.nf @@ -30,7 +30,7 @@ process DESEQ2_DIFFERENTIAL_EXPRESSION { tail -n +2 $phenotype | LC_COLLATE=C sort > sorted_pheno cat header sorted_pheno > tmp && rm phenotype.csv && mv tmp phenotype.csv - DEA.R -g $gene_matrix -p $phenotype -c $circrna_matrix -s $species -m ensembl_database_map.txt + DEA.R $gene_matrix $phenotype $circrna_matrix $species ensembl_database_map.txt mv boxplots/ circRNA/ mv *.RData DESeq2_QC/ From f80e0cb5eecd3e902e9d7afd80e9a3158be3b864 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 18:25:36 +0100 Subject: [PATCH 180/491] Add version captures --- subworkflows/local/circrna_discovery.nf | 11 +- subworkflows/local/differential_expression.nf | 1 - subworkflows/local/prepare_genome.nf | 5 +- subworkflows/local/quantification.nf | 131 +++++++++++------- workflows/circrna/main.nf | 10 +- 5 files changed, 97 insertions(+), 61 deletions(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 49733e7f..907cc2c7 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -17,9 +17,6 @@ include { SEGEMEHL_FILTER } from '../../modules/l include { STAR_ALIGN as STAR_1ST_PASS } from '../../modules/nf-core/star/align/main' include { STAR_ALIGN as STAR_2ND_PASS } from '../../modules/nf-core/star/align/main' include { SJDB as STAR_SJDB } from '../../modules/local/star/sjdb/main' -include { STAR_ALIGN as DCC_1ST_PASS } from '../../modules/nf-core/star/align/main' -include { STAR_ALIGN as DCC_2ND_PASS } from '../../modules/nf-core/star/align/main' -include { SJDB as DCC_SJDB } from '../../modules/local/star/sjdb/main' include { STAR_ALIGN as DCC_MATE1_1ST_PASS } from '../../modules/nf-core/star/align/main' include { STAR_ALIGN as DCC_MATE1_2ND_PASS } from '../../modules/nf-core/star/align/main' include { SJDB as DCC_MATE1_SJDB } from '../../modules/local/star/sjdb/main' @@ -89,6 +86,7 @@ workflow CIRCRNA_DISCOVERY { STAR_2ND_PASS( reads, star_index, STAR_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) ch_versions = ch_versions.mix(STAR_1ST_PASS.out.versions) + ch_versions = ch_versions.mix(STAR_SJDB.out.versions) ch_versions = ch_versions.mix(STAR_2ND_PASS.out.versions) // @@ -144,6 +142,7 @@ workflow CIRCRNA_DISCOVERY { CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index ) CIRIQUANT_FILTER( CIRIQUANT.out.gtf.map{ meta, gtf -> [ meta + [tool: "ciriquant"], gtf ] }, bsj_reads ) + ch_versions = ch_versions.mix(CIRIQUANT_YML.out.versions) ch_versions = ch_versions.mix(CIRIQUANT.out.versions) ch_versions = ch_versions.mix(CIRIQUANT_FILTER.out.versions) @@ -200,6 +199,7 @@ workflow CIRCRNA_DISCOVERY { ch_versions = ch_versions.mix(MAPSPLICE_ALIGN.out.versions) ch_versions = ch_versions.mix(MAPSPLICE_PARSE.out.versions) ch_versions = ch_versions.mix(MAPSPLICE_ANNOTATE.out.versions) + ch_versions = ch_versions.mix(MAPSPLICE_FILTER.out.versions) // // ANNOTATION WORKFLOW: @@ -221,6 +221,8 @@ workflow CIRCRNA_DISCOVERY { ch_versions = ch_versions.mix(INTERSECT_ANNOTATION.out.versions) ch_versions = ch_versions.mix(ANNOTATION.out.versions) + ch_versions = ch_versions.mix(COMBINE_ANNOTATIONS.out.versions) + ch_versions = ch_versions.mix(REMOVE_SCORE_STRAND.out.versions) // // FASTA WORKFLOW: @@ -257,7 +259,8 @@ workflow CIRCRNA_DISCOVERY { circrna_bed12 = ANNOTATION.out.bed fasta = FASTA.out.analysis_fasta annotation = REMOVE_SCORE_STRAND.out.output - versions = ch_versions counts_bed counts_tsv + + versions = ch_versions } diff --git a/subworkflows/local/differential_expression.nf b/subworkflows/local/differential_expression.nf index f4454af6..d4199b86 100644 --- a/subworkflows/local/differential_expression.nf +++ b/subworkflows/local/differential_expression.nf @@ -1,5 +1,4 @@ include { HISAT2_ALIGN } from '../../modules/nf-core/hisat2/align/main' -include { SAMTOOLS_SORT } from '../../modules/nf-core/samtools/sort/main' include { STRINGTIE_STRINGTIE } from '../../modules/nf-core/stringtie/stringtie/main' include { STRINGTIE_PREPDE } from '../../modules/local/stringtie/prepde/main' include { PARENT_GENE } from '../../modules/local/annotation/parent_gene/main' diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 0118cf2d..5d3b0755 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -22,6 +22,8 @@ workflow PREPARE_GENOME { if( params.module.contains('circrna_discovery') && params.tool.contains('mapsplice') ) { CLEAN_FASTA(ch_fasta, []) ch_fasta = CLEAN_FASTA.out.output + + ch_versions = ch_versions.mix(CLEAN_FASTA.out.versions) } SEQKIT_SPLIT(ch_fasta) @@ -41,7 +43,8 @@ workflow PREPARE_GENOME { SEGEMEHL_INDEX(ch_fasta.map{ meta, fasta -> fasta}) // TODO: Add support for meta // Collect versions - ch_versions = ch_versions.mix(BOWTIE_BUILD.out.versions, + ch_versions = ch_versions.mix(SEQKIT_SPLIT.out.versions, + BOWTIE_BUILD.out.versions, BOWTIE2_BUILD.out.versions, BWA_INDEX.out.versions, HISAT2_EXTRACTSPLICESITES.out.versions, diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index d6256a6e..e5db420d 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -13,61 +13,84 @@ include { COMBINE_QUANTIFICATION as COMBINE_TPM } from '../../modules/loca workflow QUANTIFICATION { take: - ch_gtf - ch_fasta - counts - reads - circ_annotation + ch_gtf + ch_fasta + counts + reads + circ_annotation main: - LINEAR_TRANSCRIPTOME(ch_gtf, ch_fasta) - COUNTS_TO_BED(counts.map{counts -> [[id: "counts"], counts]}, []) - UNIQUE_REGIONS(COUNTS_TO_BED.out.output) - - CIRCULAR_TRANSCRIPTOME( - UNIQUE_REGIONS.out.sorted.map{meta, bed -> bed}, - ch_fasta.map{meta, fasta -> fasta} - ) - - CAT_TRANSCRIPTOME( - LINEAR_TRANSCRIPTOME.out.transcriptome.map{meta, fasta -> fasta}.mix( - CIRCULAR_TRANSCRIPTOME.out.fasta - ).collect().map(fastas -> [[id: "transcriptome"], fastas]) - ) - - MARK_CIRCULAR(CAT_TRANSCRIPTOME.out.file_out, []) - - PSIRC_INDEX(MARK_CIRCULAR.out.output) - PSIRC_QUANT(reads, PSIRC_INDEX.out.collect()) - - CUSTOM_TX2GENE( - ch_gtf, - PSIRC_QUANT.out.directory.map{meta, quant -> quant}.collect().map{[[id: "quant"], it]}, - "kallisto", - "gene_id", - "gene_name" - ) - - TXIMETA_TXIMPORT( - PSIRC_QUANT.out.directory, - CUSTOM_TX2GENE.out.tx2gene, - "kallisto" - ) - - ch_counts = TXIMETA_TXIMPORT.out.counts_gene - ch_tpm = TXIMETA_TXIMPORT.out.tpm_gene - - COMBINE_COUNTS( - ch_counts.map{meta, counts -> counts}.collect().map{[[id: "counts"], it]}, - CUSTOM_TX2GENE.out.tx2gene, - circ_annotation - ) - - COMBINE_TPM( - ch_tpm.map{meta, tpm -> tpm}.collect().map{[[id: "tpm"], it]}, - CUSTOM_TX2GENE.out.tx2gene, - circ_annotation - ) + ch_versions = Channel.empty() + + LINEAR_TRANSCRIPTOME(ch_gtf, ch_fasta) + COUNTS_TO_BED(counts.map{counts -> [[id: "counts"], counts]}, []) + UNIQUE_REGIONS(COUNTS_TO_BED.out.output) + + CIRCULAR_TRANSCRIPTOME( + UNIQUE_REGIONS.out.sorted.map{meta, bed -> bed}, + ch_fasta.map{meta, fasta -> fasta} + ) + + CAT_TRANSCRIPTOME( + LINEAR_TRANSCRIPTOME.out.transcriptome.map{meta, fasta -> fasta}.mix( + CIRCULAR_TRANSCRIPTOME.out.fasta + ).collect().map(fastas -> [[id: "transcriptome"], fastas]) + ) + + MARK_CIRCULAR(CAT_TRANSCRIPTOME.out.file_out, []) + + ch_versions = ch_versions.mix( + LINEAR_TRANSCRIPTOME.out.versions, + COUNTS_TO_BED.out.versions, + UNIQUE_REGIONS.out.versions, + CIRCULAR_TRANSCRIPTOME.out.versions, + CAT_TRANSCRIPTOME.out.versions, + MARK_CIRCULAR.out.versions + ) + + PSIRC_INDEX(MARK_CIRCULAR.out.output) + PSIRC_QUANT(reads, PSIRC_INDEX.out.collect()) + + CUSTOM_TX2GENE( + ch_gtf, + PSIRC_QUANT.out.directory.map{meta, quant -> quant}.collect().map{[[id: "quant"], it]}, + "kallisto", + "gene_id", + "gene_name" + ) + + TXIMETA_TXIMPORT( + PSIRC_QUANT.out.directory, + CUSTOM_TX2GENE.out.tx2gene, + "kallisto" + ) + + ch_versions = ch_versions.mix( + PSIRC_INDEX.out.versions, + PSIRC_QUANT.out.versions, + CUSTOM_TX2GENE.out.versions, + TXIMETA_TXIMPORT.out.versions + ) + + ch_counts = TXIMETA_TXIMPORT.out.counts_gene + ch_tpm = TXIMETA_TXIMPORT.out.tpm_gene + + COMBINE_COUNTS( + ch_counts.map{meta, counts -> counts}.collect().map{[[id: "counts"], it]}, + CUSTOM_TX2GENE.out.tx2gene, + circ_annotation + ) + + COMBINE_TPM( + ch_tpm.map{meta, tpm -> tpm}.collect().map{[[id: "tpm"], it]}, + CUSTOM_TX2GENE.out.tx2gene, + circ_annotation + ) + + ch_versions = ch_versions.mix( + COMBINE_COUNTS.out.versions, + COMBINE_TPM.out.versions + ) emit: counts_linear = COMBINE_COUNTS.out.linear @@ -77,4 +100,6 @@ workflow QUANTIFICATION { tpm_linear = COMBINE_TPM.out.linear tpm_circular = COMBINE_TPM.out.circular tpm_combined = COMBINE_TPM.out.combined + + versions = ch_versions } diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 3db9ee32..7c7d522f 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -153,6 +153,10 @@ workflow CIRCRNA { ch_versions = ch_versions.mix(CIRCRNA_DISCOVERY.out.versions) + // + // 3. Quantification + // + QUANTIFICATION( ch_gtf, ch_fasta, @@ -161,8 +165,10 @@ workflow CIRCRNA { CIRCRNA_DISCOVERY.out.annotation ) + ch_versions = ch_versions.mix(QUANTIFICATION.out.versions) + // - // 3. miRNA prediction + // 4. miRNA prediction // MIRNA_PREDICTION( @@ -174,7 +180,7 @@ workflow CIRCRNA { ch_versions = ch_versions.mix(MIRNA_PREDICTION.out.versions) // - // 4. Differential expression tests + // 5. Differential expression tests // ch_ensembl_database_map = params.module.contains('differential_expression') ? Channel.fromPath("${projectDir}/bin/ensembl_database_map.txt") : Channel.empty() From b143b302912a14580621bb76f69caf9ada5d84d8 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 18:26:21 +0100 Subject: [PATCH 181/491] Fix unchanged file --- docs/images/nf-core-circrna_logo_dark.png | Bin 25192 -> 25216 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/images/nf-core-circrna_logo_dark.png b/docs/images/nf-core-circrna_logo_dark.png index b48e7b08c6faa330c043d93a106076880d4157c8..869f35cbe9b6efda9efc5db2f2eb063f17c534cc 100644 GIT binary patch delta 24563 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 JZR2zMe*kpKTde>9 delta 24534 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 Date: Tue, 19 Mar 2024 18:26:57 +0100 Subject: [PATCH 182/491] Update modules --- modules.json | 4 +- .../nf-core/bedtools/sort/tests/main.nf.test | 58 +++++ .../bedtools/sort/tests/main.nf.test.snap | 68 ++++++ .../bedtools/sort/tests/nextflow.config | 8 + modules/nf-core/bedtools/sort/tests/tags.yml | 2 + modules/nf-core/bowtie2/align/main.nf | 26 ++- .../bowtie2/align/tests/cram_crai.config | 5 + .../nf-core/bowtie2/align/tests/main.nf.test | 162 +++++++++---- .../bowtie2/align/tests/main.nf.test.snap | 216 +++++++++++------- 9 files changed, 409 insertions(+), 140 deletions(-) create mode 100644 modules/nf-core/bedtools/sort/tests/main.nf.test create mode 100644 modules/nf-core/bedtools/sort/tests/main.nf.test.snap create mode 100644 modules/nf-core/bedtools/sort/tests/nextflow.config create mode 100644 modules/nf-core/bedtools/sort/tests/tags.yml create mode 100644 modules/nf-core/bowtie2/align/tests/cram_crai.config diff --git a/modules.json b/modules.json index 439ea7a3..751a3f5c 100644 --- a/modules.json +++ b/modules.json @@ -17,7 +17,7 @@ }, "bedtools/sort": { "branch": "master", - "git_sha": "575e1bc54b083fb15e7dd8b5fcc40bea60e8ce83", + "git_sha": "571a5feac4c9ce0a8df0bc15b94230e7f3e8db47", "installed_by": ["modules"] }, "bowtie/align": { @@ -32,7 +32,7 @@ }, "bowtie2/align": { "branch": "master", - "git_sha": "3c77ca9aac783e76c3614a06db3bfe4fef619bde", + "git_sha": "0fe30831abbc2ed115e46e92330edf38f56edc3d", "installed_by": ["modules"] }, "bowtie2/build": { diff --git a/modules/nf-core/bedtools/sort/tests/main.nf.test b/modules/nf-core/bedtools/sort/tests/main.nf.test new file mode 100644 index 00000000..b1f36dd9 --- /dev/null +++ b/modules/nf-core/bedtools/sort/tests/main.nf.test @@ -0,0 +1,58 @@ +nextflow_process { + + name "Test Process BEDTOOLS_SORT" + script "../main.nf" + config "./nextflow.config" + process "BEDTOOLS_SORT" + + tag "modules" + tag "modules_nfcore" + tag "bedtools" + tag "bedtools/sort" + + test("test_bedtools_sort") { + + when { + process { + """ + input[0] = [ [ id:'test'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/bed/test.bed', checkIfExists: true) + ] + input[1] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + + test("test_bedtools_sort_with_genome") { + + when { + process { + """ + input[0] = [ [ id:'test'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/bed/test.bed', checkIfExists: true) + ] + input[1] = file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} \ No newline at end of file diff --git a/modules/nf-core/bedtools/sort/tests/main.nf.test.snap b/modules/nf-core/bedtools/sort/tests/main.nf.test.snap new file mode 100644 index 00000000..f10e8b98 --- /dev/null +++ b/modules/nf-core/bedtools/sort/tests/main.nf.test.snap @@ -0,0 +1,68 @@ +{ + "test_bedtools_sort_with_genome": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test_out.testtext:md5,fe4053cf4de3aebbdfc3be2efb125a74" + ] + ], + "1": [ + "versions.yml:md5,cdbae2c7ebc41e534aaf0835779061f8" + ], + "sorted": [ + [ + { + "id": "test" + }, + "test_out.testtext:md5,fe4053cf4de3aebbdfc3be2efb125a74" + ] + ], + "versions": [ + "versions.yml:md5,cdbae2c7ebc41e534aaf0835779061f8" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-19T10:13:11.830452" + }, + "test_bedtools_sort": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test_out.testtext:md5,fe4053cf4de3aebbdfc3be2efb125a74" + ] + ], + "1": [ + "versions.yml:md5,cdbae2c7ebc41e534aaf0835779061f8" + ], + "sorted": [ + [ + { + "id": "test" + }, + "test_out.testtext:md5,fe4053cf4de3aebbdfc3be2efb125a74" + ] + ], + "versions": [ + "versions.yml:md5,cdbae2c7ebc41e534aaf0835779061f8" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-19T10:16:40.535947" + } +} \ No newline at end of file diff --git a/modules/nf-core/bedtools/sort/tests/nextflow.config b/modules/nf-core/bedtools/sort/tests/nextflow.config new file mode 100644 index 00000000..f203c99c --- /dev/null +++ b/modules/nf-core/bedtools/sort/tests/nextflow.config @@ -0,0 +1,8 @@ +process { + + withName: BEDTOOLS_SORT { + ext.prefix = { "${meta.id}_out" } + ext.suffix = "testtext" + } + +} \ No newline at end of file diff --git a/modules/nf-core/bedtools/sort/tests/tags.yml b/modules/nf-core/bedtools/sort/tests/tags.yml new file mode 100644 index 00000000..47c85eea --- /dev/null +++ b/modules/nf-core/bedtools/sort/tests/tags.yml @@ -0,0 +1,2 @@ +bedtools/sort: + - "modules/nf-core/bedtools/sort/**" diff --git a/modules/nf-core/bowtie2/align/main.nf b/modules/nf-core/bowtie2/align/main.nf index 8c405ee3..96a7027d 100644 --- a/modules/nf-core/bowtie2/align/main.nf +++ b/modules/nf-core/bowtie2/align/main.nf @@ -10,13 +10,18 @@ process BOWTIE2_ALIGN { input: tuple val(meta) , path(reads) tuple val(meta2), path(index) + tuple val(meta3), path(fasta) val save_unaligned val sort_bam output: - tuple val(meta), path("*.{bam,sam}"), emit: aligned + tuple val(meta), path("*.sam") , emit: sam , optional:true + tuple val(meta), path("*.bam") , emit: bam , optional:true + tuple val(meta), path("*.cram") , emit: cram , optional:true + tuple val(meta), path("*.csi") , emit: csi , optional:true + tuple val(meta), path("*.crai") , emit: crai , optional:true tuple val(meta), path("*.log") , emit: log - tuple val(meta), path("*fastq.gz") , emit: fastq, optional:true + tuple val(meta), path("*fastq.gz") , emit: fastq , optional:true path "versions.yml" , emit: versions when: @@ -39,7 +44,10 @@ process BOWTIE2_ALIGN { def samtools_command = sort_bam ? 'sort' : 'view' def extension_pattern = /(--output-fmt|-O)+\s+(\S+)/ - def extension = (args2 ==~ extension_pattern) ? (args2 =~ extension_pattern)[0][2].toLowerCase() : "bam" + def extension_matcher = (args2 =~ extension_pattern) + def extension = extension_matcher.getCount() > 0 ? extension_matcher[0][2].toLowerCase() : "bam" + def reference = fasta && extension=="cram" ? "--reference ${fasta}" : "" + if (!fasta && extension=="cram") error "Fasta reference is required for CRAM output" """ INDEX=`find -L ./ -name "*.rev.1.bt2" | sed "s/\\.rev.1.bt2\$//"` @@ -53,7 +61,7 @@ process BOWTIE2_ALIGN { $unaligned \\ $args \\ 2> >(tee ${prefix}.bowtie2.log >&2) \\ - | samtools $samtools_command $args2 --threads $task.cpus -o ${prefix}.${extension} - + | samtools $samtools_command $args2 --threads $task.cpus ${reference} -o ${prefix}.${extension} - if [ -f ${prefix}.unmapped.fastq.1.gz ]; then mv ${prefix}.unmapped.fastq.1.gz ${prefix}.unmapped_1.fastq.gz @@ -82,9 +90,19 @@ process BOWTIE2_ALIGN { } else { create_unmapped = save_unaligned ? "touch ${prefix}.unmapped_1.fastq.gz && touch ${prefix}.unmapped_2.fastq.gz" : "" } + def reference = fasta && extension=="cram" ? "--reference ${fasta}" : "" + if (!fasta && extension=="cram") error "Fasta reference is required for CRAM output" + + def create_index = "" + if (extension == "cram") { + create_index = "touch ${prefix}.crai" + } else if (extension == "bam") { + create_index = "touch ${prefix}.csi" + } """ touch ${prefix}.${extension} + ${create_index} touch ${prefix}.bowtie2.log ${create_unmapped} diff --git a/modules/nf-core/bowtie2/align/tests/cram_crai.config b/modules/nf-core/bowtie2/align/tests/cram_crai.config new file mode 100644 index 00000000..03f1d5e5 --- /dev/null +++ b/modules/nf-core/bowtie2/align/tests/cram_crai.config @@ -0,0 +1,5 @@ +process { + withName: BOWTIE2_ALIGN { + ext.args2 = '--output-fmt cram --write-index' + } +} diff --git a/modules/nf-core/bowtie2/align/tests/main.nf.test b/modules/nf-core/bowtie2/align/tests/main.nf.test index a478d17b..03aeaf9e 100644 --- a/modules/nf-core/bowtie2/align/tests/main.nf.test +++ b/modules/nf-core/bowtie2/align/tests/main.nf.test @@ -6,9 +6,10 @@ nextflow_process { tag "modules" tag "modules_nfcore" tag "bowtie2" + tag "bowtie2/build" tag "bowtie2/align" - test("sarscov2 - fastq, index, false, false - bam") { + test("sarscov2 - fastq, index, fasta, false, false - bam") { setup { run("BOWTIE2_BUILD") { @@ -32,8 +33,9 @@ nextflow_process { file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = false //save_unaligned - input[3] = false //sort + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[3] = false //save_unaligned + input[4] = false //sort """ } } @@ -42,7 +44,7 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - file(process.out.aligned[0][1]).name, + file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, process.out.versions @@ -52,7 +54,7 @@ nextflow_process { } - test("sarscov2 - fastq, index, false, false - sam") { + test("sarscov2 - fastq, index, fasta, false, false - sam") { config "./sam.config" setup { @@ -77,8 +79,9 @@ nextflow_process { file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = false //save_unaligned - input[3] = false //sort + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[3] = false //save_unaligned + input[4] = false //sort """ } } @@ -87,7 +90,7 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - file(process.out.aligned[0][1]).readLines()[0..4], + file(process.out.sam[0][1]).readLines()[0..4], process.out.log, process.out.fastq, process.out.versions @@ -97,7 +100,7 @@ nextflow_process { } - test("sarscov2 - fastq, index, false, false - sam2") { + test("sarscov2 - fastq, index, fasta, false, false - sam2") { config "./sam2.config" setup { @@ -122,8 +125,9 @@ nextflow_process { file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = false //save_unaligned - input[3] = false //sort + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[3] = false //save_unaligned + input[4] = false //sort """ } } @@ -132,7 +136,7 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - file(process.out.aligned[0][1]).readLines()[0..4], + file(process.out.sam[0][1]).readLines()[0..4], process.out.log, process.out.fastq, process.out.versions @@ -142,7 +146,7 @@ nextflow_process { } - test("sarscov2 - fastq, index, false, true - bam") { + test("sarscov2 - fastq, index, fasta, false, true - bam") { setup { run("BOWTIE2_BUILD") { @@ -166,8 +170,9 @@ nextflow_process { file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = false //save_unaligned - input[3] = true //sort + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[3] = false //save_unaligned + input[4] = false //sort """ } } @@ -176,7 +181,7 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - file(process.out.aligned[0][1]).name, + file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, process.out.versions @@ -186,7 +191,7 @@ nextflow_process { } - test("sarscov2 - [fastq1, fastq2], index, false, false - bam") { + test("sarscov2 - [fastq1, fastq2], index, fasta, false, false - bam") { setup { run("BOWTIE2_BUILD") { @@ -213,8 +218,9 @@ nextflow_process { ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = false //save_unaligned - input[3] = false //sort + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[3] = false //save_unaligned + input[4] = false //sort """ } } @@ -223,7 +229,7 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - file(process.out.aligned[0][1]).name, + file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, process.out.versions @@ -233,7 +239,7 @@ nextflow_process { } - test("sarscov2 - [fastq1, fastq2], index, false, true - bam") { + test("sarscov2 - [fastq1, fastq2], index, fasta, false, true - bam") { setup { run("BOWTIE2_BUILD") { @@ -260,8 +266,9 @@ nextflow_process { ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = false //save_unaligned - input[3] = true //sort + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[3] = false //save_unaligned + input[4] = false //sort """ } } @@ -270,7 +277,7 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - file(process.out.aligned[0][1]).name, + file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, process.out.versions @@ -280,7 +287,7 @@ nextflow_process { } - test("sarscov2 - fastq, large_index, false, false - bam") { + test("sarscov2 - fastq, large_index, fasta, false, false - bam") { config "./large_index.config" setup { @@ -305,8 +312,9 @@ nextflow_process { file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = false //save_unaligned - input[3] = false //sort + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[3] = false //save_unaligned + input[4] = false //sort """ } } @@ -315,7 +323,7 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - file(process.out.aligned[0][1]).name, + file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, process.out.versions @@ -325,7 +333,7 @@ nextflow_process { } - test("sarscov2 - [fastq1, fastq2], large_index, false, false - bam") { + test("sarscov2 - [fastq1, fastq2], large_index, fasta, false, false - bam") { config "./large_index.config" setup { @@ -353,8 +361,9 @@ nextflow_process { ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = false //save_unaligned - input[3] = false //sort + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[3] = false //save_unaligned + input[4] = false //sort """ } } @@ -363,7 +372,7 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - file(process.out.aligned[0][1]).name, + file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, process.out.versions @@ -373,7 +382,7 @@ nextflow_process { } - test("sarscov2 - [fastq1, fastq2], index, true, false - bam") { + test("sarscov2 - [fastq1, fastq2], index, fasta, true, false - bam") { setup { run("BOWTIE2_BUILD") { @@ -400,8 +409,9 @@ nextflow_process { ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = true //save_unaligned - input[3] = false //sort + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[3] = false //save_unaligned + input[4] = false //sort """ } } @@ -410,7 +420,7 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - file(process.out.aligned[0][1]).name, + file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, process.out.versions @@ -420,7 +430,7 @@ nextflow_process { } - test("sarscov2 - fastq, index, true, false - bam") { + test("sarscov2 - fastq, index, fasta, true, false - bam") { setup { run("BOWTIE2_BUILD") { @@ -444,8 +454,9 @@ nextflow_process { file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = true //save_unaligned - input[3] = false //sort + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[3] = false //save_unaligned + input[4] = false //sort """ } } @@ -454,7 +465,7 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - file(process.out.aligned[0][1]).name, + file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, process.out.versions @@ -465,7 +476,54 @@ nextflow_process { } - test("sarscov2 - [fastq1, fastq2], index, false, false - stub") { + test("sarscov2 - [fastq1, fastq2], index, fasta, true, true - cram") { + + config "./cram_crai.config" + setup { + run("BOWTIE2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = [ + [ id:'test'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + [ + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) + ] + ] + input[1] = BOWTIE2_BUILD.out.index + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[3] = false //save_unaligned + input[4] = true //sort + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.cram[0][1]).name, + file(process.out.crai[0][1]).name + ).match() } + ) + } + + } + + test("sarscov2 - [fastq1, fastq2], index, fasta, false, false - stub") { options "-stub" setup { @@ -493,8 +551,9 @@ nextflow_process { ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = false //save_unaligned - input[3] = false //sort + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[3] = false //save_unaligned + input[4] = false //sort """ } } @@ -503,7 +562,8 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - file(process.out.aligned[0][1]).name, + file(process.out.bam[0][1]).name, + file(process.out.csi[0][1]).name, file(process.out.log[0][1]).name, process.out.fastq, process.out.versions @@ -513,7 +573,7 @@ nextflow_process { } - test("sarscov2 - fastq, index, true, false - stub") { + test("sarscov2 - fastq, index, fasta, true, false - stub") { options "-stub" setup { @@ -538,8 +598,9 @@ nextflow_process { file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = true //save_unaligned - input[3] = false //sort + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[3] = false //save_unaligned + input[4] = false //sort """ } } @@ -548,14 +609,15 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - file(process.out.aligned[0][1]).name, + file(process.out.bam[0][1]).name, + file(process.out.csi[0][1]).name, file(process.out.log[0][1]).name, - file(process.out.fastq[0][1]).name, + process.out.fastq, process.out.versions ).match() } ) } } - + } diff --git a/modules/nf-core/bowtie2/align/tests/main.nf.test.snap b/modules/nf-core/bowtie2/align/tests/main.nf.test.snap index 883dc7ec..028e7da6 100644 --- a/modules/nf-core/bowtie2/align/tests/main.nf.test.snap +++ b/modules/nf-core/bowtie2/align/tests/main.nf.test.snap @@ -1,34 +1,38 @@ { - "sarscov2 - fastq, index, false, false - sam2": { + "sarscov2 - [fastq1, fastq2], large_index, fasta, false, false - bam": { "content": [ - [ - "ERR5069949.2151832\t16\tMT192765.1\t17453\t42\t150M\t*\t0\t0\tACGCACATTGCTAACTAAGGGCACACTAGAACCAGAATATTTCAATTCAGTGTGTAGACTTATGAAAACTATAGGTCCAGACATGTTCCTCGGAACTTGTCGGCGTTGTCCTGCTGAAATTGTTGACACTGTGAGTGCTTTGGTTTATGA\tAAAA Date: Tue, 19 Mar 2024 18:34:46 +0100 Subject: [PATCH 183/491] Add missing version capture for ciriquant_yml --- subworkflows/local/circrna_discovery.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 907cc2c7..4e081a4a 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -118,9 +118,9 @@ workflow CIRCRNA_DISCOVERY { // FIND_CIRC WORKFLOW: // - FIND_CIRC_ALIGN( reads, bowtie2_index, false, true ) - SAMTOOLS_INDEX( FIND_CIRC_ALIGN.out.aligned ) - SAMTOOLS_VIEW( FIND_CIRC_ALIGN.out.aligned.join( SAMTOOLS_INDEX.out.bai ), ch_fasta, [] ) + FIND_CIRC_ALIGN( reads, bowtie2_index, ch_fasta, false, true ) + SAMTOOLS_INDEX( FIND_CIRC_ALIGN.out.bam ) + SAMTOOLS_VIEW( FIND_CIRC_ALIGN.out.bam.join( SAMTOOLS_INDEX.out.bai ), ch_fasta, [] ) FIND_CIRC_ANCHORS( SAMTOOLS_VIEW.out.bam ) FIND_CIRC( FIND_CIRC_ANCHORS.out.anchors, bowtie2_index, fasta ) find_circ_filter = FIND_CIRC.out.bed.map{ meta, bed -> [ meta + [tool: "find_circ"], bed ] } From 5732485d563198fc545c426b9c37b7252a51144c Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 19:13:25 +0100 Subject: [PATCH 184/491] Fix some version capture problems --- modules/local/ciriquant/ciriquant/main.nf | 2 +- modules/local/psirc/index/main.nf | 9 ++++++++- modules/local/psirc/quant/main.nf | 6 ++++++ subworkflows/local/quantification.nf | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/modules/local/ciriquant/ciriquant/main.nf b/modules/local/ciriquant/ciriquant/main.nf index acf435a6..fab482ba 100644 --- a/modules/local/ciriquant/ciriquant/main.nf +++ b/modules/local/ciriquant/ciriquant/main.nf @@ -52,7 +52,7 @@ process CIRIQUANT { cat <<-END_VERSIONS > versions.yml "${task.process}": bwa: \$(echo \$(bwa 2>&1) | sed 's/^.*Version: //; s/Contact:.*\$//') - ciriquant : \$(echo \$(CIRIquant --version 2>&1) | sed 's/CIRIquant //g' ) + ciriquant: \$(echo \$(CIRIquant --version 2>&1) | sed 's/CIRIquant //g' ) samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') stringtie: \$(stringtie --version 2>&1) hisat2: $VERSION diff --git a/modules/local/psirc/index/main.nf b/modules/local/psirc/index/main.nf index daca0402..7c10a533 100644 --- a/modules/local/psirc/index/main.nf +++ b/modules/local/psirc/index/main.nf @@ -8,10 +8,17 @@ process PSIRC_INDEX { tuple val(meta), path(fasta) output: - tuple val(meta), path("psirc.index") + tuple val(meta), path("psirc.index"), emit: index + path "versions.yml", emit: versions script: + def VERSION = '1.0' """ psirc-quant index -i psirc.index --make-unique $fasta + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + psirc-quant: $VERSION + END_VERSIONS """ } diff --git a/modules/local/psirc/quant/main.nf b/modules/local/psirc/quant/main.nf index aa949e3e..b23895e6 100644 --- a/modules/local/psirc/quant/main.nf +++ b/modules/local/psirc/quant/main.nf @@ -10,10 +10,16 @@ process PSIRC_QUANT { output: tuple val(meta), path("${meta.id}"), emit: directory + path "versions.yml" , emit: versions script: def single_end = meta.single_end ? "--single -l 76 -s 20" : "" """ psirc-quant quant -t $task.cpus -i $index -o $meta.id $single_end $reads + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + psirc-quant: $VERSION + END_VERSIONS """ } diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index e5db420d..af720ce0 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -49,7 +49,7 @@ workflow QUANTIFICATION { ) PSIRC_INDEX(MARK_CIRCULAR.out.output) - PSIRC_QUANT(reads, PSIRC_INDEX.out.collect()) + PSIRC_QUANT(reads, PSIRC_INDEX.out.index.collect()) CUSTOM_TX2GENE( ch_gtf, From d1adb3e4f013a5de29f73b732af7c06d69ae24f4 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 19:23:19 +0100 Subject: [PATCH 185/491] Fix missing version variable in psirc-quant --- modules/local/psirc/quant/main.nf | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/local/psirc/quant/main.nf b/modules/local/psirc/quant/main.nf index b23895e6..9afe8150 100644 --- a/modules/local/psirc/quant/main.nf +++ b/modules/local/psirc/quant/main.nf @@ -14,6 +14,7 @@ process PSIRC_QUANT { script: def single_end = meta.single_end ? "--single -l 76 -s 20" : "" + def VERSION = '1.0' """ psirc-quant quant -t $task.cpus -i $index -o $meta.id $single_end $reads From 48f0dcae9431f9d854273bfb877fdf0d24eb36e7 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 19:24:38 +0100 Subject: [PATCH 186/491] Revert "Fix unchanged file" This reverts commit 18673fcef44b2fd0115fcd67655bac7379825ead. --- docs/images/nf-core-circrna_logo_dark.png | Bin 25216 -> 25192 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/images/nf-core-circrna_logo_dark.png b/docs/images/nf-core-circrna_logo_dark.png index 869f35cbe9b6efda9efc5db2f2eb063f17c534cc..b48e7b08c6faa330c043d93a106076880d4157c8 100644 GIT binary patch delta 24534 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 JZR2zMe*kpKTde>9 From b6f612dc5db3d530e701db1228b717da0b7af959 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 19 Mar 2024 19:27:18 +0100 Subject: [PATCH 187/491] Fix editorconfig checks --- bin/combine_quantification.py | 6 +++--- bin/counts_combined.py | 2 +- bin/merge_tools.py | 2 +- modules/local/quantification/transcriptome/main.nf | 2 +- subworkflows/local/circrna_discovery.nf | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bin/combine_quantification.py b/bin/combine_quantification.py index d26ade6c..88601ebc 100755 --- a/bin/combine_quantification.py +++ b/bin/combine_quantification.py @@ -14,8 +14,8 @@ args = parser.parse_args() -df_annotation = pd.read_csv(args.circ_annotation, - sep='\t', header=None, +df_annotation = pd.read_csv(args.circ_annotation, + sep='\t', header=None, names=['chr', 'start', 'end', 'name', 'score', 'strand', 'type', 'gene', 'transcript'], index_col=['name']) @@ -48,4 +48,4 @@ df_combined = pd.concat([df_linear, df_circular], axis=0, sort=True) -df_combined.to_csv(args.out_combined, sep='\t') \ No newline at end of file +df_combined.to_csv(args.out_combined, sep='\t') diff --git a/bin/counts_combined.py b/bin/counts_combined.py index 7ae67065..99a9304e 100755 --- a/bin/counts_combined.py +++ b/bin/counts_combined.py @@ -28,4 +28,4 @@ df.index = df.index.map(lambda x: f'{x[0]}:{x[1]}-{x[2]}:{x[3]}') df.index.name = 'ID' -df.to_csv(args.out_tsv, sep='\t') \ No newline at end of file +df.to_csv(args.out_tsv, sep='\t') diff --git a/bin/merge_tools.py b/bin/merge_tools.py index 4246d0fd..fe81353d 100755 --- a/bin/merge_tools.py +++ b/bin/merge_tools.py @@ -17,7 +17,7 @@ df['tool_count'] = 1 -df = df.groupby(['chr', 'start', 'end', 'strand']).agg({'count': args.duplicates_fun, +df = df.groupby(['chr', 'start', 'end', 'strand']).agg({'count': args.duplicates_fun, 'tool_count': 'sum'}).reset_index() df = df[df['tool_count'] >= args.tool_filter] diff --git a/modules/local/quantification/transcriptome/main.nf b/modules/local/quantification/transcriptome/main.nf index 4d4d3028..747942c0 100644 --- a/modules/local/quantification/transcriptome/main.nf +++ b/modules/local/quantification/transcriptome/main.nf @@ -35,4 +35,4 @@ process TRANSCRIPTOME { gffread: \$(gffread --version 2>&1) END_VERSIONS """ -} \ No newline at end of file +} diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 4e081a4a..cf3d751b 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -245,7 +245,7 @@ workflow CIRCRNA_DISCOVERY { tools_selected = params.tool.split(',').collect{it.trim().toLowerCase()} - MERGE_TOOLS( ch_matrix.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), + MERGE_TOOLS( ch_matrix.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), tools_selected.size() > 1 ? tool_filter : 1, duplicates_fun ) COUNTS_COMBINED( MERGE_TOOLS.out.merged.map{ meta, bed -> bed }.collect() ) From f658463a4f47a11495ae43b28a896cfa980423ea Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Wed, 20 Mar 2024 09:39:49 +0100 Subject: [PATCH 188/491] Use gene names for annotation instead of ids --- bin/annotation.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/annotation.py b/bin/annotation.py index ab9dc01d..a4d801f5 100755 --- a/bin/annotation.py +++ b/bin/annotation.py @@ -24,7 +24,7 @@ 14: 'attributes' } -attributes = ['gene_id', 'transcript_id'] +attributes = ['gene_name', 'transcript_id'] exon_boundary = args.exon_boundary @@ -36,7 +36,7 @@ df_intergenic = df[mask] df = df[~mask] df_intergenic['type'] = 'intergenic-circRNA' -df_intergenic['gene_id'] = 'NaN' +df_intergenic['gene_name'] = 'NaN' df_intergenic['transcript_id'] = 'NaN' # Convert attributes to a dictionary @@ -55,7 +55,7 @@ df = df.groupby(['chr', 'start', 'end', 'strand']).aggregate({ 'name': lambda x: x.iloc[0], 'score': lambda x: x.iloc[0], - 'gene_id': lambda x: list(x), + 'gene_name': lambda x: list(x), 'transcript_id': lambda x: list(x), 'perfect': lambda x: list(x) }) @@ -78,14 +78,14 @@ def determine_type(row): df['no_transcript'] = df['transcript_id'].apply(lambda x: all([type(value) != str and np.isnan(value) for value in x])) df['type'] = df.apply(lambda row: determine_type(row), axis=1) -df['gene_id'] = df.apply(lambda row: filter_perfect(row, 'gene_id'), axis=1) +df['gene_name'] = df.apply(lambda row: filter_perfect(row, 'gene_name'), axis=1) df['transcript_id'] = df.apply(lambda row: filter_perfect(row, 'transcript_id'), axis=1) # Drop perfect df = df.drop(['perfect'], axis=1) df = df.reset_index() df_intergenic = df_intergenic.reset_index() -bed_order = ['chr', 'start', 'end', 'name', 'score', 'strand', 'type', 'gene_id', 'transcript_id'] +bed_order = ['chr', 'start', 'end', 'name', 'score', 'strand', 'type', 'gene_name', 'transcript_id'] df = df[bed_order] df_intergenic = df_intergenic[bed_order] From 6d863a45bc7b78e24934a7c9e444e8c69fe78d5b Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 22 Mar 2024 08:29:41 +0100 Subject: [PATCH 189/491] Add GTF creation to annotation --- bin/annotation.py | 27 ++++++++++++++----- .../local/annotation/full_annotation/main.nf | 9 ++++--- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/bin/annotation.py b/bin/annotation.py index a4d801f5..b1ca1383 100755 --- a/bin/annotation.py +++ b/bin/annotation.py @@ -3,11 +3,13 @@ import pandas as pd import numpy as np import argparse +import csv parser = argparse.ArgumentParser(description='Annotate circRNAs') parser.add_argument('--input', type=str, help='Path to the input file') parser.add_argument('--exon_boundary', type=int, help='Exon boundary') -parser.add_argument('--output', type=str, help='Path to the output file') +parser.add_argument('--output_bed', type=str, help='Path to the output bed file') +parser.add_argument('--output_gtf', type=str, help='Path to the output gtf') args = parser.parse_args() @@ -24,7 +26,7 @@ 14: 'attributes' } -attributes = ['gene_name', 'transcript_id'] +attributes = ['gene_id', 'gene_name', 'transcript_id'] exon_boundary = args.exon_boundary @@ -36,8 +38,9 @@ df_intergenic = df[mask] df = df[~mask] df_intergenic['type'] = 'intergenic-circRNA' -df_intergenic['gene_name'] = 'NaN' -df_intergenic['transcript_id'] = 'NaN' +df_intergenic['gene_id'] = 'integenic' + df_intergenic['name'] +df_intergenic['gene_name'] = 'integenic' + df_intergenic['name'] +df_intergenic['transcript_id'] = 'integenic' + df_intergenic['name'] # Convert attributes to a dictionary df['attributes'] = df['attributes'].apply(lambda row: dict([[value.strip(r'"') for value in entry.strip().split(' ')] for entry in row.split(';') if entry])) @@ -55,6 +58,7 @@ df = df.groupby(['chr', 'start', 'end', 'strand']).aggregate({ 'name': lambda x: x.iloc[0], 'score': lambda x: x.iloc[0], + 'gene_id': lambda x: list(x), 'gene_name': lambda x: list(x), 'transcript_id': lambda x: list(x), 'perfect': lambda x: list(x) @@ -78,6 +82,7 @@ def determine_type(row): df['no_transcript'] = df['transcript_id'].apply(lambda x: all([type(value) != str and np.isnan(value) for value in x])) df['type'] = df.apply(lambda row: determine_type(row), axis=1) +df['gene_id'] = df.apply(lambda row: filter_perfect(row, 'gene_id'), axis=1) df['gene_name'] = df.apply(lambda row: filter_perfect(row, 'gene_name'), axis=1) df['transcript_id'] = df.apply(lambda row: filter_perfect(row, 'transcript_id'), axis=1) # Drop perfect @@ -85,7 +90,7 @@ def determine_type(row): df = df.reset_index() df_intergenic = df_intergenic.reset_index() -bed_order = ['chr', 'start', 'end', 'name', 'score', 'strand', 'type', 'gene_name', 'transcript_id'] +bed_order = ['chr', 'start', 'end', 'name', 'score', 'strand', 'type', 'gene_id', 'gene_name', 'transcript_id'] df = df[bed_order] df_intergenic = df_intergenic[bed_order] @@ -94,4 +99,14 @@ def determine_type(row): # Sort by chr, start, end df = df.sort_values(['chr', 'start', 'end']) -df.to_csv(args.output, sep='\t', index=False, header=False) +df.to_csv(args.output_bed, sep='\t', index=False, header=False) + +# Convert to GTF +df['source'] = 'circRNA' +df['frame'] = '.' +df['attributes'] = 'gene_id "' + df['gene_id'] + '"; gene_name "' + df['gene_name'] + '"; transcript_id "' + df['name'] + '";' + +gtf_order = ['chr', 'source', 'type', 'start', 'end', 'score', 'strand', 'frame', 'attributes'] +df = df[gtf_order] + +df.to_csv(args.output_gtf, sep='\t', index=False, header=False, quoting=csv.QUOTE_NONE) diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/full_annotation/main.nf index bf17b2cc..43030ca4 100644 --- a/modules/local/annotation/full_annotation/main.nf +++ b/modules/local/annotation/full_annotation/main.nf @@ -12,15 +12,16 @@ process ANNOTATION { val(exon_boundary) output: - tuple val(meta), path("${outfile}"), emit: bed + tuple val(meta), path("${out_bed}"), emit: bed + tuple val(meta), path("${out_gtf}"), emit: gtf path "versions.yml", emit: versions script: prefix = task.ext.prefix ?: "${meta.id}.annotation" - suffix = task.ext.suffix ?: "bed" - outfile = "${prefix}.${suffix}" + out_bed = "${prefix}.bed" + out_gtf = "${prefix}.gtf" """ - annotation.py --input ${intersection} --exon_boundary ${exon_boundary} --output ${outfile} + annotation.py --input ${intersection} --exon_boundary ${exon_boundary} --output_bed ${out_bed} --output_gtf ${out_gtf} cat <<-END_VERSIONS > versions.yml "${task.process}": From db88a4500b4d031a9774df0db452efaaddc586f2 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 22 Mar 2024 09:26:58 +0100 Subject: [PATCH 190/491] Switch to processing circRNAs more like standard transcripts --- bin/annotation.py | 8 +- bin/combine_quantification.py | 41 +--------- conf/modules.config | 16 +++- .../combine_quantification/main.nf | 10 +-- subworkflows/local/circrna_discovery.nf | 14 ++-- subworkflows/local/quantification.nf | 80 ++++++++----------- workflows/circrna/main.nf | 3 +- 7 files changed, 65 insertions(+), 107 deletions(-) diff --git a/bin/annotation.py b/bin/annotation.py index b1ca1383..17001e36 100755 --- a/bin/annotation.py +++ b/bin/annotation.py @@ -38,9 +38,9 @@ df_intergenic = df[mask] df = df[~mask] df_intergenic['type'] = 'intergenic-circRNA' -df_intergenic['gene_id'] = 'integenic' + df_intergenic['name'] -df_intergenic['gene_name'] = 'integenic' + df_intergenic['name'] -df_intergenic['transcript_id'] = 'integenic' + df_intergenic['name'] +df_intergenic['gene_id'] = 'intergenic_' + df_intergenic['name'] +df_intergenic['gene_name'] = 'intergenic_' + df_intergenic['name'] +df_intergenic['transcript_id'] = 'intergenic_' + df_intergenic['name'] # Convert attributes to a dictionary df['attributes'] = df['attributes'].apply(lambda row: dict([[value.strip(r'"') for value in entry.strip().split(' ')] for entry in row.split(';') if entry])) @@ -104,7 +104,7 @@ def determine_type(row): # Convert to GTF df['source'] = 'circRNA' df['frame'] = '.' -df['attributes'] = 'gene_id "' + df['gene_id'] + '"; gene_name "' + df['gene_name'] + '"; transcript_id "' + df['name'] + '";' +df['attributes'] = 'gene_id "' + df['gene_id'] + '"; gene_name "' + df['gene_name'] + '"; transcript_id "circ_' + df['name'] + '";' gtf_order = ['chr', 'source', 'type', 'start', 'end', 'score', 'strand', 'frame', 'attributes'] df = df[gtf_order] diff --git a/bin/combine_quantification.py b/bin/combine_quantification.py index 88601ebc..dd0b1307 100755 --- a/bin/combine_quantification.py +++ b/bin/combine_quantification.py @@ -6,46 +6,11 @@ parser = argparse.ArgumentParser(description='Merge quantification files into a single file') parser.add_argument('--inputs', type=str, nargs='+', help='List input files to merge') -parser.add_argument('--tx2gene', type=str, help='Path to tx2gene file') -parser.add_argument('--circ_annotation', type=str, help='Path to circRNA annotation file') -parser.add_argument('--out_linear', type=str, help='Path to output linear RNA quantification file') -parser.add_argument('--out_circular', type=str, help='Path to output circRNA quantification file') -parser.add_argument('--out_combined', type=str, help='Path to output combined quantification file') +parser.add_argument('--output', type=str, help='Path to output combined quantification file') args = parser.parse_args() -df_annotation = pd.read_csv(args.circ_annotation, - sep='\t', header=None, - names=['chr', 'start', 'end', 'name', 'score', 'strand', 'type', 'gene', 'transcript'], - index_col=['name']) - -df_tx2gene = pd.read_csv(args.tx2gene, sep='\t') - -dfs = [pd.read_csv(f, sep='\t', index_col=["gene_id", "gene_name"]) for f in args.inputs] +dfs = [pd.read_csv(f, sep='\t', index_col=[0, 1]) for f in args.inputs] df_combined = pd.concat(dfs, axis=1, sort=True) -# Split linear and circular -linear_mask = df_combined.index.get_level_values(0) \ - .isin(df_tx2gene["gene_id"]) -df_linear = df_combined[linear_mask].copy() -df_circular = df_combined[~linear_mask].copy() - -df_linear.to_csv(args.out_linear, sep='\t') - -# Perform annotation -df_annotation["annotation"] = df_annotation.apply(lambda row: 'intergenic' if row['type'] == 'intergenic-circRNA' else row['gene'], axis=1) -annotation_dict = df_annotation["annotation"].to_dict() - -df_circular.reset_index(inplace=True) -df_circular["gene_name"] = df_circular['gene_id'].map(annotation_dict) -df_circular.set_index(["gene_id", "gene_name"], inplace=True) - -df_circular.to_csv(args.out_circular, sep='\t') - -# Save combined -df_linear["type"] = "gene" -df_circular["type"] = "circRNA" - -df_combined = pd.concat([df_linear, df_circular], axis=0, sort=True) - -df_combined.to_csv(args.out_combined, sep='\t') +df_combined.to_csv(args.output, sep='\t') diff --git a/conf/modules.config b/conf/modules.config index fc6a6ba9..5ac28733 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -638,13 +638,18 @@ if (!params.skip_trimming) { ext.suffix = "intersect.bed" } - withName: COMBINE_ANNOTATIONS { + withName: COMBINE_ANNOTATION_BEDS { ext.args = "-k 1,1 -k2,2n -k3,3n -u" ext.suffix = "combined.bed" } + withName: COMBINE_ANNOTATION_GTFS { + ext.args = "-k 1,1 -k3,3n -k4,4n -u" + ext.suffix = "combined.gtf" + } + withName: REMOVE_SCORE_STRAND { - ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3, \".\", \".\", \$7, \$8, \$9 }'" + ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3, \".\", \".\", \$7, \$8, \$9, \$10 }'" ext.suffix = "tidy.bed" } @@ -672,6 +677,11 @@ if (!params.skip_trimming) { ext.suffix = "unique.bed" } + withName: COMBINE_TRANSCRIPTOME_GTFS { + ext.args = "-k 1,1 -k3,3n -k4,4n" + ext.suffix = "gtf" + } + withName: CIRCULAR_TRANSCRIPTOME { ext.args = "-nameOnly" } @@ -680,7 +690,7 @@ if (!params.skip_trimming) { // GAWK process that marks FASTA headers. // Leaves headers starting with "ENS" and non-header lines as is. // Adds "\tC" to the end of the header for all other headers - ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (!/^>/ || /^>ENS/) { print } else { print \$1 \"\\tC\" } }'" + ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (!/^>circ_/) { print } else { print \$1 \"\\tC\" } }'" ext.suffix = "marked.fasta" } diff --git a/modules/local/quantification/combine_quantification/main.nf b/modules/local/quantification/combine_quantification/main.nf index 975ae48f..41790d9b 100644 --- a/modules/local/quantification/combine_quantification/main.nf +++ b/modules/local/quantification/combine_quantification/main.nf @@ -8,23 +8,15 @@ process COMBINE_QUANTIFICATION { input: tuple val(meta), path(inputs) - tuple val(meta2), path(tx2gene) - tuple val(meta3), path(circ_annotation) output: - path("${meta.id}.linear.tsv") , emit: linear - path("${meta.id}.circular.tsv") , emit: circular path("${meta.id}.combined.tsv") , emit: combined path "versions.yml" , emit: versions script: """ combine_quantification.py --inputs ${inputs} \\ - --tx2gene ${tx2gene} \\ - --circ_annotation ${circ_annotation} \\ - --out_linear ${meta.id}.linear.tsv \\ - --out_circular ${meta.id}.circular.tsv \\ - --out_combined ${meta.id}.combined.tsv + --output ${meta.id}.combined.tsv cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index cf3d751b..9afb3c12 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -1,6 +1,7 @@ include { ANNOTATION } from '../../modules/local/annotation/full_annotation/main' -include { GNU_SORT as COMBINE_ANNOTATIONS } from '../../modules/nf-core/gnu/sort/main' +include { GNU_SORT as COMBINE_ANNOTATION_BEDS } from '../../modules/nf-core/gnu/sort/main' +include { GNU_SORT as COMBINE_ANNOTATION_GTFS } from '../../modules/nf-core/gnu/sort/main' include { GAWK as REMOVE_SCORE_STRAND } from '../../modules/nf-core/gawk/main' include { BEDTOOLS_INTERSECT as INTERSECT_ANNOTATION } from '../../modules/nf-core/bedtools/intersect/main' include { BOWTIE2_ALIGN as FIND_CIRC_ALIGN } from '../../modules/nf-core/bowtie2/align/main' @@ -216,13 +217,15 @@ workflow CIRCRNA_DISCOVERY { INTERSECT_ANNOTATION( circrna_filtered.combine(gtf), [[], []]) ANNOTATION( INTERSECT_ANNOTATION.out.intersect, exon_boundary ) - COMBINE_ANNOTATIONS(ANNOTATION.out.bed.map{ meta, bed -> bed}.collect().map{[[id: "annotation"], it]}) - REMOVE_SCORE_STRAND( COMBINE_ANNOTATIONS.out.sorted, []) + COMBINE_ANNOTATION_BEDS(ANNOTATION.out.bed.map{ meta, bed -> bed}.collect().map{[[id: "annotation"], it]}) + REMOVE_SCORE_STRAND( COMBINE_ANNOTATION_BEDS.out.sorted, []) + COMBINE_ANNOTATION_GTFS(ANNOTATION.out.gtf.map{ meta, gtf -> gtf}.collect().map{[[id: "annotation"], it]}) ch_versions = ch_versions.mix(INTERSECT_ANNOTATION.out.versions) ch_versions = ch_versions.mix(ANNOTATION.out.versions) - ch_versions = ch_versions.mix(COMBINE_ANNOTATIONS.out.versions) + ch_versions = ch_versions.mix(COMBINE_ANNOTATION_BEDS.out.versions) ch_versions = ch_versions.mix(REMOVE_SCORE_STRAND.out.versions) + ch_versions = ch_versions.mix(COMBINE_ANNOTATION_GTFS.out.versions) // // FASTA WORKFLOW: @@ -258,7 +261,8 @@ workflow CIRCRNA_DISCOVERY { emit: circrna_bed12 = ANNOTATION.out.bed fasta = FASTA.out.analysis_fasta - annotation = REMOVE_SCORE_STRAND.out.output + annotation_bed = REMOVE_SCORE_STRAND.out.output + annotation_gtf = COMBINE_ANNOTATION_GTFS.out.sorted counts_bed counts_tsv diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index af720ce0..6a64d35c 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -1,15 +1,14 @@ -include { TRANSCRIPTOME as LINEAR_TRANSCRIPTOME } from '../../modules/local/quantification/transcriptome/main' -include { BEDTOOLS_GETFASTA as CIRCULAR_TRANSCRIPTOME } from '../../modules/nf-core/bedtools/getfasta/main' -include { GAWK as COUNTS_TO_BED } from '../../modules/nf-core/gawk/main' -include { GNU_SORT as UNIQUE_REGIONS } from '../../modules/nf-core/gnu/sort/main' -include { CAT_CAT as CAT_TRANSCRIPTOME } from '../../modules/nf-core/cat/cat/main' +include { GNU_SORT as COMBINE_TRANSCRIPTOME_GTFS } from '../../modules/nf-core/gnu/sort/main' +include { TRANSCRIPTOME } from '../../modules/local/quantification/transcriptome/main' include { GAWK as MARK_CIRCULAR } from '../../modules/nf-core/gawk/main' include { PSIRC_INDEX } from '../../modules/local/psirc/index/main' include { PSIRC_QUANT } from '../../modules/local/psirc/quant/main' include { CUSTOM_TX2GENE } from '../../modules/nf-core/custom/tx2gene/main' include { TXIMETA_TXIMPORT } from '../../modules/nf-core/tximeta/tximport/main' -include { COMBINE_QUANTIFICATION as COMBINE_COUNTS } from '../../modules/local/quantification/combine_quantification/main' -include { COMBINE_QUANTIFICATION as COMBINE_TPM } from '../../modules/local/quantification/combine_quantification/main' +include { COMBINE_QUANTIFICATION as COMBINE_GENE_COUNTS } from '../../modules/local/quantification/combine_quantification/main' +include { COMBINE_QUANTIFICATION as COMBINE_GENE_TPM } from '../../modules/local/quantification/combine_quantification/main' +include { COMBINE_QUANTIFICATION as COMBINE_TX_COUNTS } from '../../modules/local/quantification/combine_quantification/main' +include { COMBINE_QUANTIFICATION as COMBINE_TX_TPM } from '../../modules/local/quantification/combine_quantification/main' workflow QUANTIFICATION { take: @@ -17,34 +16,22 @@ workflow QUANTIFICATION { ch_fasta counts reads - circ_annotation + circ_annotation_bed + circ_annotation_gtf main: ch_versions = Channel.empty() - LINEAR_TRANSCRIPTOME(ch_gtf, ch_fasta) - COUNTS_TO_BED(counts.map{counts -> [[id: "counts"], counts]}, []) - UNIQUE_REGIONS(COUNTS_TO_BED.out.output) - - CIRCULAR_TRANSCRIPTOME( - UNIQUE_REGIONS.out.sorted.map{meta, bed -> bed}, - ch_fasta.map{meta, fasta -> fasta} - ) - - CAT_TRANSCRIPTOME( - LINEAR_TRANSCRIPTOME.out.transcriptome.map{meta, fasta -> fasta}.mix( - CIRCULAR_TRANSCRIPTOME.out.fasta - ).collect().map(fastas -> [[id: "transcriptome"], fastas]) + COMBINE_TRANSCRIPTOME_GTFS( + ch_gtf.mix(circ_annotation_gtf).map{meta, gtf -> gtf}.collect().map{[[id: "transcriptome"], it]}, ) - MARK_CIRCULAR(CAT_TRANSCRIPTOME.out.file_out, []) + TRANSCRIPTOME(COMBINE_TRANSCRIPTOME_GTFS.out.sorted, ch_fasta) + MARK_CIRCULAR(TRANSCRIPTOME.out.transcriptome, []) ch_versions = ch_versions.mix( - LINEAR_TRANSCRIPTOME.out.versions, - COUNTS_TO_BED.out.versions, - UNIQUE_REGIONS.out.versions, - CIRCULAR_TRANSCRIPTOME.out.versions, - CAT_TRANSCRIPTOME.out.versions, + COMBINE_TRANSCRIPTOME_GTFS.out.versions, + TRANSCRIPTOME.out.versions, MARK_CIRCULAR.out.versions ) @@ -52,7 +39,7 @@ workflow QUANTIFICATION { PSIRC_QUANT(reads, PSIRC_INDEX.out.index.collect()) CUSTOM_TX2GENE( - ch_gtf, + COMBINE_TRANSCRIPTOME_GTFS.out.sorted, PSIRC_QUANT.out.directory.map{meta, quant -> quant}.collect().map{[[id: "quant"], it]}, "kallisto", "gene_id", @@ -72,34 +59,33 @@ workflow QUANTIFICATION { TXIMETA_TXIMPORT.out.versions ) - ch_counts = TXIMETA_TXIMPORT.out.counts_gene - ch_tpm = TXIMETA_TXIMPORT.out.tpm_gene + ch_gene_counts = TXIMETA_TXIMPORT.out.counts_gene + ch_gene_tpm = TXIMETA_TXIMPORT.out.tpm_gene - COMBINE_COUNTS( - ch_counts.map{meta, counts -> counts}.collect().map{[[id: "counts"], it]}, - CUSTOM_TX2GENE.out.tx2gene, - circ_annotation + COMBINE_GENE_COUNTS( + ch_gene_counts.map{meta, counts -> counts}.collect().map{[[id: "gene_counts"], it]} ) - COMBINE_TPM( - ch_tpm.map{meta, tpm -> tpm}.collect().map{[[id: "tpm"], it]}, - CUSTOM_TX2GENE.out.tx2gene, - circ_annotation + COMBINE_GENE_TPM( + ch_gene_tpm.map{meta, tpm -> tpm}.collect().map{[[id: "gene_tpm"], it]} + ) + + COMBINE_TX_COUNTS( + TXIMETA_TXIMPORT.out.counts_transcript.map{meta, counts -> counts}.collect().map{[[id: "tx_counts"], it]} + ) + + COMBINE_TX_TPM( + TXIMETA_TXIMPORT.out.tpm_transcript.map{meta, tpm -> tpm}.collect().map{[[id: "tx_tpm"], it]} ) ch_versions = ch_versions.mix( - COMBINE_COUNTS.out.versions, - COMBINE_TPM.out.versions + COMBINE_GENE_COUNTS.out.versions, + COMBINE_GENE_TPM.out.versions ) emit: - counts_linear = COMBINE_COUNTS.out.linear - counts_circular = COMBINE_COUNTS.out.circular - counts_combined = COMBINE_COUNTS.out.combined - - tpm_linear = COMBINE_TPM.out.linear - tpm_circular = COMBINE_TPM.out.circular - tpm_combined = COMBINE_TPM.out.combined + gene_counts = COMBINE_GENE_COUNTS.out.combined + gene_tpm = COMBINE_GENE_TPM.out.combined versions = ch_versions } diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 7c7d522f..cde056ff 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -162,7 +162,8 @@ workflow CIRCRNA { ch_fasta, CIRCRNA_DISCOVERY.out.counts_bed, FASTQC_TRIMGALORE.out.reads, - CIRCRNA_DISCOVERY.out.annotation + CIRCRNA_DISCOVERY.out.annotation_bed, + CIRCRNA_DISCOVERY.out.annotation_gtf ) ch_versions = ch_versions.mix(QUANTIFICATION.out.versions) From 8b7cf90b32dd5465a0359939a3bbcc45b7c3e02e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 22 Mar 2024 09:55:07 +0100 Subject: [PATCH 191/491] Switch to using CSVTK for joining quantifications --- conf/modules.config | 11 +--- modules.json | 5 ++ .../combine_quantification/main.nf | 28 ----------- modules/nf-core/csvtk/join/environment.yml | 7 +++ modules/nf-core/csvtk/join/main.nf | 50 +++++++++++++++++++ modules/nf-core/csvtk/join/meta.yml | 41 +++++++++++++++ subworkflows/local/quantification.nf | 40 ++++++++------- 7 files changed, 126 insertions(+), 56 deletions(-) delete mode 100644 modules/local/quantification/combine_quantification/main.nf create mode 100644 modules/nf-core/csvtk/join/environment.yml create mode 100644 modules/nf-core/csvtk/join/main.nf create mode 100644 modules/nf-core/csvtk/join/meta.yml diff --git a/conf/modules.config b/conf/modules.config index 5ac28733..9e9cde44 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -694,15 +694,8 @@ if (!params.skip_trimming) { ext.suffix = "marked.fasta" } - withName: COMBINE_COUNTS { - publishDir = [ - path: { "${params.outdir}/quantification/" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - withName: COMBINE_TPM { + withName: ".*:JOIN_(GENE|TX)_(COUNTS|TPM)" { + ext.args = "-f 1,2 -t" publishDir = [ path: { "${params.outdir}/quantification/" }, mode: params.publish_dir_mode, diff --git a/modules.json b/modules.json index 751a3f5c..77b6ee5d 100644 --- a/modules.json +++ b/modules.json @@ -65,6 +65,11 @@ "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": ["modules"] }, + "csvtk/join": { + "branch": "master", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "installed_by": ["modules"] + }, "csvtk/split": { "branch": "master", "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", diff --git a/modules/local/quantification/combine_quantification/main.nf b/modules/local/quantification/combine_quantification/main.nf deleted file mode 100644 index 41790d9b..00000000 --- a/modules/local/quantification/combine_quantification/main.nf +++ /dev/null @@ -1,28 +0,0 @@ -process COMBINE_QUANTIFICATION { - label "process_single" - - conda "conda-forge::mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6==fccb0c41a243c639e11dd1be7b74f563e624fcca-0" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0': - 'biocontainers/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0' }" - - input: - tuple val(meta), path(inputs) - - output: - path("${meta.id}.combined.tsv") , emit: combined - path "versions.yml" , emit: versions - - script: - """ - combine_quantification.py --inputs ${inputs} \\ - --output ${meta.id}.combined.tsv - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - python: \$(python --version | sed 's/Python //g') - pandas: \$(python -c "import pandas; print(pandas.__version__)") - numpy: \$(python -c "import numpy; print(numpy.__version__)") - END_VERSIONS - """ -} diff --git a/modules/nf-core/csvtk/join/environment.yml b/modules/nf-core/csvtk/join/environment.yml new file mode 100644 index 00000000..b488c861 --- /dev/null +++ b/modules/nf-core/csvtk/join/environment.yml @@ -0,0 +1,7 @@ +name: csvtk_join +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::csvtk=0.26.0 diff --git a/modules/nf-core/csvtk/join/main.nf b/modules/nf-core/csvtk/join/main.nf new file mode 100644 index 00000000..bf02e7f5 --- /dev/null +++ b/modules/nf-core/csvtk/join/main.nf @@ -0,0 +1,50 @@ +process CSVTK_JOIN { + tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/csvtk:0.26.0--h9ee0642_0': + 'biocontainers/csvtk:0.26.0--h9ee0642_0' }" + + input: + tuple val(meta), path(csv) + + output: + tuple val(meta), path("${prefix}.${out_extension}"), emit: csv + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${meta.id}" + out_extension = args.contains('--out-delimiter "\t"') || args.contains('-D "\t"') || args.contains("-D \$'\t'") ? "tsv" : "csv" + """ + csvtk \\ + join \\ + $args \\ + --num-cpus $task.cpus \\ + --out-file ${prefix}.${out_extension} \\ + $csv + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + csvtk: \$(echo \$( csvtk version | sed -e "s/csvtk v//g" )) + END_VERSIONS + """ + + stub: + def args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${meta.id}" + out_extension = args.contains('--out-delimiter "\t"') || args.contains('-D "\t"') || args.contains("-D \$'\t'") ? "tsv" : "csv" + """ + touch ${prefix}.${out_extension} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + csvtk: \$(echo \$( csvtk version | sed -e "s/csvtk v//g" )) + END_VERSIONS + """ +} diff --git a/modules/nf-core/csvtk/join/meta.yml b/modules/nf-core/csvtk/join/meta.yml new file mode 100644 index 00000000..a75ec40f --- /dev/null +++ b/modules/nf-core/csvtk/join/meta.yml @@ -0,0 +1,41 @@ +name: csvtk_join +description: Join two or more CSV (or TSV) tables by selected fields into a single table +keywords: + - join + - tsv + - csv +tools: + - csvtk: + description: A cross-platform, efficient, practical CSV/TSV toolkit + homepage: http://bioinf.shenwei.me/csvtk + documentation: http://bioinf.shenwei.me/csvtk + tool_dev_url: https://github.com/shenwei356/csvtk + licence: ["MIT"] +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - csv: + type: file + description: CSV/TSV formatted files + pattern: "*.{csv,tsv}" +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - versions: + type: file + description: File containing software versions + pattern: "version.yml" + - csv: + type: file + description: Joined CSV/TSV file + pattern: "*.{csv,tsv}" +authors: + - "@anoronh4" +maintainers: + - "@anoronh4" diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index 6a64d35c..fccd30a1 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -1,14 +1,14 @@ -include { GNU_SORT as COMBINE_TRANSCRIPTOME_GTFS } from '../../modules/nf-core/gnu/sort/main' -include { TRANSCRIPTOME } from '../../modules/local/quantification/transcriptome/main' -include { GAWK as MARK_CIRCULAR } from '../../modules/nf-core/gawk/main' -include { PSIRC_INDEX } from '../../modules/local/psirc/index/main' -include { PSIRC_QUANT } from '../../modules/local/psirc/quant/main' -include { CUSTOM_TX2GENE } from '../../modules/nf-core/custom/tx2gene/main' -include { TXIMETA_TXIMPORT } from '../../modules/nf-core/tximeta/tximport/main' -include { COMBINE_QUANTIFICATION as COMBINE_GENE_COUNTS } from '../../modules/local/quantification/combine_quantification/main' -include { COMBINE_QUANTIFICATION as COMBINE_GENE_TPM } from '../../modules/local/quantification/combine_quantification/main' -include { COMBINE_QUANTIFICATION as COMBINE_TX_COUNTS } from '../../modules/local/quantification/combine_quantification/main' -include { COMBINE_QUANTIFICATION as COMBINE_TX_TPM } from '../../modules/local/quantification/combine_quantification/main' +include { GNU_SORT as COMBINE_TRANSCRIPTOME_GTFS } from '../../modules/nf-core/gnu/sort/main' +include { TRANSCRIPTOME } from '../../modules/local/quantification/transcriptome/main' +include { GAWK as MARK_CIRCULAR } from '../../modules/nf-core/gawk/main' +include { PSIRC_INDEX } from '../../modules/local/psirc/index/main' +include { PSIRC_QUANT } from '../../modules/local/psirc/quant/main' +include { CUSTOM_TX2GENE } from '../../modules/nf-core/custom/tx2gene/main' +include { TXIMETA_TXIMPORT } from '../../modules/nf-core/tximeta/tximport/main' +include { CSVTK_JOIN as JOIN_GENE_COUNTS } from '../../modules/nf-core/csvtk/join/main' +include { CSVTK_JOIN as JOIN_GENE_TPM } from '../../modules/nf-core/csvtk/join/main' +include { CSVTK_JOIN as JOIN_TX_COUNTS } from '../../modules/nf-core/csvtk/join/main' +include { CSVTK_JOIN as JOIN_TX_TPM } from '../../modules/nf-core/csvtk/join/main' workflow QUANTIFICATION { take: @@ -62,30 +62,32 @@ workflow QUANTIFICATION { ch_gene_counts = TXIMETA_TXIMPORT.out.counts_gene ch_gene_tpm = TXIMETA_TXIMPORT.out.tpm_gene - COMBINE_GENE_COUNTS( + JOIN_GENE_COUNTS( ch_gene_counts.map{meta, counts -> counts}.collect().map{[[id: "gene_counts"], it]} ) - COMBINE_GENE_TPM( + JOIN_GENE_TPM( ch_gene_tpm.map{meta, tpm -> tpm}.collect().map{[[id: "gene_tpm"], it]} ) - COMBINE_TX_COUNTS( + JOIN_TX_COUNTS( TXIMETA_TXIMPORT.out.counts_transcript.map{meta, counts -> counts}.collect().map{[[id: "tx_counts"], it]} ) - COMBINE_TX_TPM( + JOIN_TX_TPM( TXIMETA_TXIMPORT.out.tpm_transcript.map{meta, tpm -> tpm}.collect().map{[[id: "tx_tpm"], it]} ) ch_versions = ch_versions.mix( - COMBINE_GENE_COUNTS.out.versions, - COMBINE_GENE_TPM.out.versions + JOIN_GENE_COUNTS.out.versions, + JOIN_GENE_TPM.out.versions ) emit: - gene_counts = COMBINE_GENE_COUNTS.out.combined - gene_tpm = COMBINE_GENE_TPM.out.combined + gene_counts = JOIN_GENE_COUNTS.out.csv + gene_tpm = JOIN_GENE_TPM.out.csv + tx_counts = JOIN_TX_COUNTS.out.csv + tx_tpm = JOIN_TX_TPM.out.csv versions = ch_versions } From 2581c28a2b57a2cb50f183d1100dc4fa6ec4bbf7 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 22 Mar 2024 10:49:42 +0100 Subject: [PATCH 192/491] Implement splitting of circular and linear transcripts --- .../local/quantification/split_types/main.nf | 43 +++++++++++++++++++ subworkflows/local/quantification.nf | 26 ++++++++--- 2 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 modules/local/quantification/split_types/main.nf diff --git a/modules/local/quantification/split_types/main.nf b/modules/local/quantification/split_types/main.nf new file mode 100644 index 00000000..a95b18af --- /dev/null +++ b/modules/local/quantification/split_types/main.nf @@ -0,0 +1,43 @@ +process SPLIT_TYPES { + tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/gawk:5.1.0' : + 'biocontainers/gawk:5.1.0' }" + + input: + tuple val(meta), path(input) + + output: + tuple val(meta), path("linear.tsv") , emit: linear + tuple val(meta), path("circular.tsv"), emit: circular + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + """ + awk -F'\\t' \\ + 'NR==1 {print > "circular.tsv"; print > "linear.tsv"} \\ + NR>1 {if (\$1 ~ /^circ_/) print > "circular.tsv"; else print > "linear.tsv"}' ${input} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + gawk: \$(awk -Wversion | sed '1!d; s/.*Awk //; s/,.*//') + END_VERSIONS + """ + + stub: + """ + touch linear.tsv + touch circular.tsv + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + gawk: \$(awk -Wversion | sed '1!d; s/.*Awk //; s/,.*//') + END_VERSIONS + """ +} diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index fccd30a1..f2969a5f 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -9,6 +9,8 @@ include { CSVTK_JOIN as JOIN_GENE_COUNTS } from '../../modules/nf-core/c include { CSVTK_JOIN as JOIN_GENE_TPM } from '../../modules/nf-core/csvtk/join/main' include { CSVTK_JOIN as JOIN_TX_COUNTS } from '../../modules/nf-core/csvtk/join/main' include { CSVTK_JOIN as JOIN_TX_TPM } from '../../modules/nf-core/csvtk/join/main' +include { SPLIT_TYPES as SPLIT_TYPES_COUNTS } from '../../modules/local/quantification/split_types/main' +include { SPLIT_TYPES as SPLIT_TYPES_TPM } from '../../modules/local/quantification/split_types/main' workflow QUANTIFICATION { take: @@ -78,16 +80,30 @@ workflow QUANTIFICATION { TXIMETA_TXIMPORT.out.tpm_transcript.map{meta, tpm -> tpm}.collect().map{[[id: "tx_tpm"], it]} ) + SPLIT_TYPES_COUNTS( + JOIN_TX_COUNTS.out.csv + ) + + SPLIT_TYPES_TPM( + JOIN_TX_TPM.out.csv + ) + ch_versions = ch_versions.mix( JOIN_GENE_COUNTS.out.versions, - JOIN_GENE_TPM.out.versions + JOIN_GENE_TPM.out.versions, + JOIN_TX_COUNTS.out.versions, + JOIN_TX_TPM.out.versions ) emit: - gene_counts = JOIN_GENE_COUNTS.out.csv - gene_tpm = JOIN_GENE_TPM.out.csv - tx_counts = JOIN_TX_COUNTS.out.csv - tx_tpm = JOIN_TX_TPM.out.csv + gene_counts = JOIN_GENE_COUNTS.out.csv + gene_tpm = JOIN_GENE_TPM.out.csv + tx_counts = JOIN_TX_COUNTS.out.csv + tx_tpm = JOIN_TX_TPM.out.csv + linear_tx_counts = SPLIT_TYPES_COUNTS.out.linear + linear_tx_tpm = SPLIT_TYPES_TPM.out.linear + circular_tx_counts = SPLIT_TYPES_COUNTS.out.circular + circular_tx_tpm = SPLIT_TYPES_TPM.out.circular versions = ch_versions } From 12a1b380f9e840b58515e22ee17454a445d8ba71 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 22 Mar 2024 10:52:18 +0100 Subject: [PATCH 193/491] Simplify quantification script --- subworkflows/local/quantification.nf | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index f2969a5f..a17805cf 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -61,15 +61,12 @@ workflow QUANTIFICATION { TXIMETA_TXIMPORT.out.versions ) - ch_gene_counts = TXIMETA_TXIMPORT.out.counts_gene - ch_gene_tpm = TXIMETA_TXIMPORT.out.tpm_gene - JOIN_GENE_COUNTS( - ch_gene_counts.map{meta, counts -> counts}.collect().map{[[id: "gene_counts"], it]} + TXIMETA_TXIMPORT.out.counts_gene.map{meta, counts -> counts}.collect().map{[[id: "gene_counts"], it]} ) JOIN_GENE_TPM( - ch_gene_tpm.map{meta, tpm -> tpm}.collect().map{[[id: "gene_tpm"], it]} + TXIMETA_TXIMPORT.out.tpm_gene.map{meta, tpm -> tpm}.collect().map{[[id: "gene_tpm"], it]} ) JOIN_TX_COUNTS( @@ -92,7 +89,9 @@ workflow QUANTIFICATION { JOIN_GENE_COUNTS.out.versions, JOIN_GENE_TPM.out.versions, JOIN_TX_COUNTS.out.versions, - JOIN_TX_TPM.out.versions + JOIN_TX_TPM.out.versions, + SPLIT_TYPES_COUNTS.out.versions, + SPLIT_TYPES_TPM.out.versions ) emit: From 967fb00cb169a07fd05a7001ec14a966ca58eeab Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 22 Mar 2024 12:40:19 +0100 Subject: [PATCH 194/491] Add quantification type splitting to output --- conf/modules.config | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/conf/modules.config b/conf/modules.config index 9e9cde44..fadfbf84 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -703,6 +703,14 @@ if (!params.skip_trimming) { ] } + withName: ".*:SPLIT_TYPES_(COUNTS|TPM)" { + publishDir = [ + path: { "${params.outdir}/quantification/" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + withName: TARGETSCAN_DATABASE { ext.when = { params.module.split(',').contains('mirna_prediction') } publishDir = [ From 6dd7a5a90b4d854d22bfe1935fe8cf6403fc6029 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 22 Mar 2024 15:04:45 +0100 Subject: [PATCH 195/491] Add filter for overlong circRNAs --- bin/annotation.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/annotation.py b/bin/annotation.py index 17001e36..21bd9587 100755 --- a/bin/annotation.py +++ b/bin/annotation.py @@ -33,6 +33,9 @@ df = pd.read_csv(args.input, sep="\t", header=None, usecols=columns.keys()) df = df.rename(columns=columns) +# Remove overlong circRNAs +df = df[df['end'] - df['start'] <= 10_000] + # Extract circRNAs without match mask = df['tx_start'] == -1 df_intergenic = df[mask] From 9c62830dc059ed53dc5ea201239b4f7050a86168 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 19 Apr 2024 10:28:38 +0200 Subject: [PATCH 196/491] Remove ciriquant YML version capture --- subworkflows/local/circrna_discovery.nf | 1 - 1 file changed, 1 deletion(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 9afb3c12..8ac26e69 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -143,7 +143,6 @@ workflow CIRCRNA_DISCOVERY { CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index ) CIRIQUANT_FILTER( CIRIQUANT.out.gtf.map{ meta, gtf -> [ meta + [tool: "ciriquant"], gtf ] }, bsj_reads ) - ch_versions = ch_versions.mix(CIRIQUANT_YML.out.versions) ch_versions = ch_versions.mix(CIRIQUANT.out.versions) ch_versions = ch_versions.mix(CIRIQUANT_FILTER.out.versions) From 65f0f54825c86edd94bfb330bc90f6563e131a32 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 20 Apr 2024 09:51:29 +0200 Subject: [PATCH 197/491] Add draft tximeta support --- modules/local/psirc/quant/main.nf | 3 +- modules/local/tximeta/tximeta/main.nf | 47 ++++ .../local/tximeta/tximeta/templates/tximeta.r | 222 ++++++++++++++++++ nextflow.config | 2 + nextflow_schema.json | 5 + subworkflows/local/quantification.nf | 17 +- workflows/circrna/main.nf | 3 +- 7 files changed, 289 insertions(+), 10 deletions(-) create mode 100644 modules/local/tximeta/tximeta/main.nf create mode 100755 modules/local/tximeta/tximeta/templates/tximeta.r diff --git a/modules/local/psirc/quant/main.nf b/modules/local/psirc/quant/main.nf index 9afe8150..5761aaad 100644 --- a/modules/local/psirc/quant/main.nf +++ b/modules/local/psirc/quant/main.nf @@ -7,6 +7,7 @@ process PSIRC_QUANT { input: tuple val(meta), path(reads) tuple val(meta2), path(index) + val(bootstrap_samples) output: tuple val(meta), path("${meta.id}"), emit: directory @@ -16,7 +17,7 @@ process PSIRC_QUANT { def single_end = meta.single_end ? "--single -l 76 -s 20" : "" def VERSION = '1.0' """ - psirc-quant quant -t $task.cpus -i $index -o $meta.id $single_end $reads + psirc-quant quant -t $task.cpus -i $index -o $meta.id $single_end $reads -b $bootstrap_samples cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/tximeta/tximeta/main.nf b/modules/local/tximeta/tximeta/main.nf new file mode 100644 index 00000000..db263cf9 --- /dev/null +++ b/modules/local/tximeta/tximeta/main.nf @@ -0,0 +1,47 @@ +process TXIMETA_TXIMETA { + label "process_medium" + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/bioconductor-tximeta%3A1.20.1--r43hdfd78af_1' : + 'biocontainers/bioconductor-tximeta:1.20.1--r43hdfd78af_1' }" + + input: + tuple val(meta), path("quants/*") + tuple val(meta2), path(tx2gene) + val quant_type + + output: + tuple val(meta), path("*gene_tpm.tsv") , emit: tpm_gene + tuple val(meta), path("*gene_counts.tsv") , emit: counts_gene + tuple val(meta), path("*gene_counts_length_scaled.tsv"), emit: counts_gene_length_scaled + tuple val(meta), path("*gene_counts_scaled.tsv") , emit: counts_gene_scaled + tuple val(meta), path("*gene_lengths.tsv") , emit: lengths_gene + tuple val(meta), path("*transcript_tpm.tsv") , emit: tpm_transcript + tuple val(meta), path("*transcript_counts.tsv") , emit: counts_transcript + tuple val(meta), path("*transcript_lengths.tsv") , emit: lengths_transcript + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + template 'tximeta.r' + + stub: + """ + touch ${meta.id}.gene_tpm.tsv + touch ${meta.id}.gene_counts.tsv + touch ${meta.id}.gene_counts_length_scaled.tsv + touch ${meta.id}.gene_counts_scaled.tsv + touch ${meta.id}.gene_lengths.tsv + touch ${meta.id}.transcript_tpm.tsv + touch ${meta.id}.transcript_counts.tsv + touch ${meta.id}.transcript_lengths.tsv + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + bioconductor-tximeta: \$(Rscript -e "library(tximeta); cat(as.character(packageVersion('tximeta')))") + END_VERSIONS + """ +} diff --git a/modules/local/tximeta/tximeta/templates/tximeta.r b/modules/local/tximeta/tximeta/templates/tximeta.r new file mode 100755 index 00000000..56a24566 --- /dev/null +++ b/modules/local/tximeta/tximeta/templates/tximeta.r @@ -0,0 +1,222 @@ +#!/usr/bin/env Rscript --vanilla + +# Script for importing and processing transcript-level quantifications. +# Written by Lorena Pantano, later modified by Jonathan Manning, and released +# under the MIT license. + +# Loading required libraries +library(SummarizedExperiment) +library(tximport) + +################################################ +################################################ +## Functions ## +################################################ +################################################ + +#' Build a table from a SummarizedExperiment object +#' +#' This function takes a SummarizedExperiment object and a specific slot name to extract +#' assay data. It then combines the first two columns of the rowData with the specified +#' assay data slot into a new data table. +#' +#' @param se.obj A SummarizedExperiment object from which to build the table. +#' @param slot The name of the slot in the assays list from which to extract data. +#' +#' @return A data frame combining the first two columns of the rowData with the assay data from the specified slot. + +build_table <- function(se.obj, slot) { + cbind(rowData(se.obj)[,1:2], assays(se.obj)[[slot]]) +} + +#' Write a table to a file from a SummarizedExperiment object with given parameters +#' +#' This function generates a table from a SummarizedExperiment object using specified parameters +#' and writes the resulting table to a file. The file name is constructed using a prefix and a +#' suffix from the parameters, and the table is written with tab separation, without quoting text, +#' and without row names. +#' +#' @param params A list containing the parameters needed for file generation and table writing. +#' The list should include: +#' - `obj`: A SummarizedExperiment object from which to build the table. +#' - `slot`: The name of the slot in the assays list from which to extract data. +#' - `suffix`: Suffix to use for generating the file name. +#' +#' @return NULL The function is called for its side effect of writing a file and does not return anything. + +write_se_table <- function(params, prefix) { + file_name <- paste0(prefix, ".", params\$suffix) + write.table(build_table(params\$obj, params\$slot), file_name, + sep="\t", quote=FALSE, row.names = FALSE) +} + +#' Read Transcript Metadata from a Given Path +#' +#' This function reads transcript metadata from a specified file path. The file is expected to +#' be a tab-separated values file without headers, containing transcript information. The function +#' checks if the file is empty and stops execution with an error message if so. It reads the file +#' into a data frame, expecting columns for transcript IDs, gene IDs, and gene names. Additional +#' processing is done to ensure compatibility with a predefined data structure (e.g., `txi[[1]]`), +#' including adding missing entries and reordering based on the transcript IDs found in `txi[[1]]`. +#' +#' @param tinfo_path The file path to the transcript information file. +#' +#' @return A list containing three elements: +#' - `transcript`: A data frame with transcript IDs, gene IDs, and gene names, indexed by transcript IDs. +#' - `gene`: A data frame with unique gene IDs and gene names. +#' - `tx2gene`: A data frame mapping transcript IDs to gene IDs. + +read_transcript_info <- function(tinfo_path){ + info <- file.info(tinfo_path) + if (info\$size == 0) { + stop("tx2gene file is empty") + } + + transcript_info <- read.csv(tinfo_path, sep="\t", header = TRUE, + col.names = c("tx", "gene_id", "gene_name")) + + extra <- setdiff(rownames(txi[[1]]), as.character(transcript_info[["tx"]])) + transcript_info <- rbind(transcript_info, data.frame(tx=extra, gene_id=extra, gene_name=extra)) + transcript_info <- transcript_info[match(rownames(txi[[1]]), transcript_info[["tx"]]), ] + rownames(transcript_info) <- transcript_info[["tx"]] + + list(transcript = transcript_info, + gene = unique(transcript_info[,2:3]), + tx2gene = transcript_info[,1:2]) +} + +#' Create a SummarizedExperiment Object +#' +#' Constructs a SummarizedExperiment object using provided matrices for counts, abundance, and length, +#' along with metadata for columns and rows. This function facilitates the organization of experimental +#' data (e.g., RNA-seq or other high-throughput data) in a structured format that is convenient for +#' further analyses and visualization. +#' +#' @param counts A matrix or DataFrame containing counts data, with rows as features (e.g., genes) and +#' columns as samples. +#' @param abundance A matrix or DataFrame containing abundance data (e.g., TPM or FPKM) with the same +#' dimensions and row/column names as the counts data. +#' @param length A matrix or DataFrame containing feature lengths, matching the dimensions and row/column +#' names of the counts data. +#' @param col_data A DataFrame containing sample-level metadata, with rows corresponding to columns in the +#' counts, abundance, and length matrices. +#' @param row_data A DataFrame containing feature-level metadata, with rows corresponding to features in +#' the counts, abundance, and length matrices. +#' +#' @return A SummarizedExperiment object containing the supplied data and metadata. + +create_summarized_experiment <- function(counts, abundance, length, col_data, row_data) { + SummarizedExperiment(assays = list(counts = counts, abundance = abundance, length = length), + colData = col_data, + rowData = row_data) +} + +################################################ +################################################ +## Main script starts here ## +################################################ +################################################ + +# Define pattern for file names based on quantification type +pattern <- ifelse('$quant_type' == "kallisto", + ifelse(file.exists("quants/abundance.h5"), "abundance.h5", "abundance.tsv"), + "quant.sf") + +fns <- list.files('quants', pattern = pattern, recursive = T, full.names = T) +names <- basename(dirname(fns)) +names(fns) <- names + +# Import transcript-level quantifications +txi <- tximport(fns, type = '$quant_type', txOut = TRUE) + +# Read transcript and sample data +transcript_info <- read_transcript_info('$tx2gene') + +# Make coldata just to appease the summarizedexperiment +coldata <- data.frame(files = fns, names = names) +rownames(coldata) <- coldata[["names"]] + +# Create initial SummarizedExperiment object +se <- create_summarized_experiment(txi[["counts"]], txi[["abundance"]], txi[["length"]], + DataFrame(coldata), transcript_info\$transcript) + +# Setting parameters for writing tables +params <- list( + list(obj = se, slot = "abundance", suffix = "transcript_tpm.tsv"), + list(obj = se, slot = "counts", suffix = "transcript_counts.tsv"), + list(obj = se, slot = "length", suffix = "transcript_lengths.tsv") +) + +# Process gene-level data if tx2gene mapping is available +if ("tx2gene" %in% names(transcript_info) && !is.null(transcript_info\$tx2gene)) { + tx2gene <- transcript_info\$tx2gene + gi <- summarizeToGene(txi, tx2gene = tx2gene) + gi.ls <- summarizeToGene(txi, tx2gene = tx2gene, countsFromAbundance = "lengthScaledTPM") + gi.s <- summarizeToGene(txi, tx2gene = tx2gene, countsFromAbundance = "scaledTPM") + + gene_info <- transcript_info\$gene[match(rownames(gi[[1]]), transcript_info\$gene[["gene_id"]]),] + rownames(gene_info) <- gene_info[["tx"]] + + col_data_frame <- DataFrame(coldata) + + # Create gene-level SummarizedExperiment objects + gse <- create_summarized_experiment(gi[["counts"]], gi[["abundance"]], gi[["length"]], + col_data_frame, gene_info) + gse.ls <- create_summarized_experiment(gi.ls[["counts"]], gi.ls[["abundance"]], gi.ls[["length"]], + col_data_frame, gene_info) + gse.s <- create_summarized_experiment(gi.s[["counts"]], gi.s[["abundance"]], gi.s[["length"]], + col_data_frame, gene_info) + + params <- c(params, list( + list(obj = gse, slot = "length", suffix = "gene_lengths.tsv"), + list(obj = gse, slot = "abundance", suffix = "gene_tpm.tsv"), + list(obj = gse, slot = "counts", suffix = "gene_counts.tsv"), + list(obj = gse.ls, slot = "abundance", suffix = "gene_tpm_length_scaled.tsv"), + list(obj = gse.ls, slot = "counts", suffix = "gene_counts_length_scaled.tsv"), + list(obj = gse.s, slot = "abundance", suffix = "gene_tpm_scaled.tsv"), + list(obj = gse.s, slot = "counts", suffix = "gene_counts_scaled.tsv") + )) +} + +# Writing tables for each set of parameters + +prefix <- '' +if ('$task.ext.prefix' != 'null'){ + prefix = '$task.ext.prefix' +} else if ('$meta.id' != 'null'){ + prefix = '$meta.id' +} + +done <- lapply(params, write_se_table, prefix) + +################################################ +################################################ +## R SESSION INFO ## +################################################ +################################################ + +sink(paste(prefix, "R_sessionInfo.log", sep = '.')) +citation("tximeta") +print(sessionInfo()) +sink() + +################################################ +################################################ +## VERSIONS FILE ## +################################################ +################################################ + +r.version <- strsplit(version[['version.string']], ' ')[[1]][3] +tximeta.version <- as.character(packageVersion('tximeta')) + +writeLines( + c( + '"${task.process}":', + paste(' bioconductor-tximeta:', tximeta.version) + ), +'versions.yml') + +################################################ +################################################ +################################################ +################################################ diff --git a/nextflow.config b/nextflow.config index 257145b9..1c8eaf0b 100644 --- a/nextflow.config +++ b/nextflow.config @@ -63,6 +63,8 @@ params { min_map_len = 40 min_fusion_distance = 200 + //> Quantification + bootstrap_samples = 30 //> MISC save_unaligned = false diff --git a/nextflow_schema.json b/nextflow_schema.json index 3cf5fd34..03fbbf3d 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -165,6 +165,11 @@ "description": "Sequencing center information to be added to read group of BAM files.", "fa_icon": "fas fa-synagogue" }, + "bootstrap_samples":{ + "type": "integer", + "description": "Number of bootstrap samples to generate during quantification.", + "default": 30 + }, "save_unaligned": { "type": "boolean", "fa_icon": "fas fa-save", diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index a17805cf..01d20a9f 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -4,7 +4,7 @@ include { GAWK as MARK_CIRCULAR } from '../../modules/nf-core/g include { PSIRC_INDEX } from '../../modules/local/psirc/index/main' include { PSIRC_QUANT } from '../../modules/local/psirc/quant/main' include { CUSTOM_TX2GENE } from '../../modules/nf-core/custom/tx2gene/main' -include { TXIMETA_TXIMPORT } from '../../modules/nf-core/tximeta/tximport/main' +include { TXIMETA_TXIMETA } from '../../modules/local/tximeta/tximeta/main' include { CSVTK_JOIN as JOIN_GENE_COUNTS } from '../../modules/nf-core/csvtk/join/main' include { CSVTK_JOIN as JOIN_GENE_TPM } from '../../modules/nf-core/csvtk/join/main' include { CSVTK_JOIN as JOIN_TX_COUNTS } from '../../modules/nf-core/csvtk/join/main' @@ -20,6 +20,7 @@ workflow QUANTIFICATION { reads circ_annotation_bed circ_annotation_gtf + bootstrap_samples main: ch_versions = Channel.empty() @@ -38,7 +39,7 @@ workflow QUANTIFICATION { ) PSIRC_INDEX(MARK_CIRCULAR.out.output) - PSIRC_QUANT(reads, PSIRC_INDEX.out.index.collect()) + PSIRC_QUANT(reads, PSIRC_INDEX.out.index.collect(), bootstrap_samples) CUSTOM_TX2GENE( COMBINE_TRANSCRIPTOME_GTFS.out.sorted, @@ -48,7 +49,7 @@ workflow QUANTIFICATION { "gene_name" ) - TXIMETA_TXIMPORT( + TXIMETA_TXIMETA( PSIRC_QUANT.out.directory, CUSTOM_TX2GENE.out.tx2gene, "kallisto" @@ -58,23 +59,23 @@ workflow QUANTIFICATION { PSIRC_INDEX.out.versions, PSIRC_QUANT.out.versions, CUSTOM_TX2GENE.out.versions, - TXIMETA_TXIMPORT.out.versions + TXIMETA_TXIMETA.out.versions ) JOIN_GENE_COUNTS( - TXIMETA_TXIMPORT.out.counts_gene.map{meta, counts -> counts}.collect().map{[[id: "gene_counts"], it]} + TXIMETA_TXIMETA.out.counts_gene.map{meta, counts -> counts}.collect().map{[[id: "gene_counts"], it]} ) JOIN_GENE_TPM( - TXIMETA_TXIMPORT.out.tpm_gene.map{meta, tpm -> tpm}.collect().map{[[id: "gene_tpm"], it]} + TXIMETA_TXIMETA.out.tpm_gene.map{meta, tpm -> tpm}.collect().map{[[id: "gene_tpm"], it]} ) JOIN_TX_COUNTS( - TXIMETA_TXIMPORT.out.counts_transcript.map{meta, counts -> counts}.collect().map{[[id: "tx_counts"], it]} + TXIMETA_TXIMETA.out.counts_transcript.map{meta, counts -> counts}.collect().map{[[id: "tx_counts"], it]} ) JOIN_TX_TPM( - TXIMETA_TXIMPORT.out.tpm_transcript.map{meta, tpm -> tpm}.collect().map{[[id: "tx_tpm"], it]} + TXIMETA_TXIMETA.out.tpm_transcript.map{meta, tpm -> tpm}.collect().map{[[id: "tx_tpm"], it]} ) SPLIT_TYPES_COUNTS( diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index cde056ff..1c6c9872 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -163,7 +163,8 @@ workflow CIRCRNA { CIRCRNA_DISCOVERY.out.counts_bed, FASTQC_TRIMGALORE.out.reads, CIRCRNA_DISCOVERY.out.annotation_bed, - CIRCRNA_DISCOVERY.out.annotation_gtf + CIRCRNA_DISCOVERY.out.annotation_gtf, + params.bootstrap_samples ) ch_versions = ch_versions.mix(QUANTIFICATION.out.versions) From 74c08a3ef605ba2e63bbef725b74df76ed04867d Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 20 Apr 2024 10:01:32 +0200 Subject: [PATCH 198/491] Fix problem with erroneous abundance.h5 detection --- modules/local/tximeta/tximeta/templates/tximeta.r | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/local/tximeta/tximeta/templates/tximeta.r b/modules/local/tximeta/tximeta/templates/tximeta.r index 56a24566..9a74585e 100755 --- a/modules/local/tximeta/tximeta/templates/tximeta.r +++ b/modules/local/tximeta/tximeta/templates/tximeta.r @@ -119,7 +119,9 @@ create_summarized_experiment <- function(counts, abundance, length, col_data, ro # Define pattern for file names based on quantification type pattern <- ifelse('$quant_type' == "kallisto", - ifelse(file.exists("quants/abundance.h5"), "abundance.h5", "abundance.tsv"), + ifelse(length(list.files('quants', pattern = "abundance.h5", recursive = T, full.names = T)) != 0, + "abundance.h5", + "abundance.tsv"), "quant.sf") fns <- list.files('quants', pattern = pattern, recursive = T, full.names = T) From 9bbcc2ec4866c072c676419184060bcd1d744fb1 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 20 Apr 2024 10:56:36 +0200 Subject: [PATCH 199/491] Update tximeta script --- .../local/tximeta/tximeta/templates/tximeta.r | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/modules/local/tximeta/tximeta/templates/tximeta.r b/modules/local/tximeta/tximeta/templates/tximeta.r index 9a74585e..c4ad9e2f 100755 --- a/modules/local/tximeta/tximeta/templates/tximeta.r +++ b/modules/local/tximeta/tximeta/templates/tximeta.r @@ -6,7 +6,7 @@ # Loading required libraries library(SummarizedExperiment) -library(tximport) +library(tximeta) ################################################ ################################################ @@ -75,9 +75,9 @@ read_transcript_info <- function(tinfo_path){ transcript_info <- read.csv(tinfo_path, sep="\t", header = TRUE, col.names = c("tx", "gene_id", "gene_name")) - extra <- setdiff(rownames(txi[[1]]), as.character(transcript_info[["tx"]])) + extra <- setdiff(rownames(se), as.character(transcript_info[["tx"]])) transcript_info <- rbind(transcript_info, data.frame(tx=extra, gene_id=extra, gene_name=extra)) - transcript_info <- transcript_info[match(rownames(txi[[1]]), transcript_info[["tx"]]), ] + transcript_info <- transcript_info[match(rownames(se), transcript_info[["tx"]]), ] rownames(transcript_info) <- transcript_info[["tx"]] list(transcript = transcript_info, @@ -128,20 +128,15 @@ fns <- list.files('quants', pattern = pattern, recursive = T, full.names = T) names <- basename(dirname(fns)) names(fns) <- names +coldata <- data.frame(files = fns, names = names) +rownames(coldata) <- coldata[["names"]] + # Import transcript-level quantifications -txi <- tximport(fns, type = '$quant_type', txOut = TRUE) +se <- tximeta(coldata, type = '$quant_type', txOut = TRUE) # Read transcript and sample data transcript_info <- read_transcript_info('$tx2gene') -# Make coldata just to appease the summarizedexperiment -coldata <- data.frame(files = fns, names = names) -rownames(coldata) <- coldata[["names"]] - -# Create initial SummarizedExperiment object -se <- create_summarized_experiment(txi[["counts"]], txi[["abundance"]], txi[["length"]], - DataFrame(coldata), transcript_info\$transcript) - # Setting parameters for writing tables params <- list( list(obj = se, slot = "abundance", suffix = "transcript_tpm.tsv"), @@ -152,9 +147,9 @@ params <- list( # Process gene-level data if tx2gene mapping is available if ("tx2gene" %in% names(transcript_info) && !is.null(transcript_info\$tx2gene)) { tx2gene <- transcript_info\$tx2gene - gi <- summarizeToGene(txi, tx2gene = tx2gene) - gi.ls <- summarizeToGene(txi, tx2gene = tx2gene, countsFromAbundance = "lengthScaledTPM") - gi.s <- summarizeToGene(txi, tx2gene = tx2gene, countsFromAbundance = "scaledTPM") + gi <- summarizeToGene(se, tx2gene = tx2gene) + gi.ls <- summarizeToGene(se, tx2gene = tx2gene, countsFromAbundance = "lengthScaledTPM") + gi.s <- summarizeToGene(se, tx2gene = tx2gene, countsFromAbundance = "scaledTPM") gene_info <- transcript_info\$gene[match(rownames(gi[[1]]), transcript_info\$gene[["gene_id"]]),] rownames(gene_info) <- gene_info[["tx"]] From a23b898bc1d6509400fca6c76393f9c1a794772a Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 20 Apr 2024 14:39:23 +0200 Subject: [PATCH 200/491] Switch to tximeta pure RDS approach --- modules/local/tximeta/tximeta/main.nf | 22 +-- .../local/tximeta/tximeta/templates/tximeta.r | 159 +----------------- subworkflows/local/quantification.nf | 19 ++- 3 files changed, 20 insertions(+), 180 deletions(-) diff --git a/modules/local/tximeta/tximeta/main.nf b/modules/local/tximeta/tximeta/main.nf index db263cf9..e1d2247b 100644 --- a/modules/local/tximeta/tximeta/main.nf +++ b/modules/local/tximeta/tximeta/main.nf @@ -8,36 +8,22 @@ process TXIMETA_TXIMETA { input: tuple val(meta), path("quants/*") - tuple val(meta2), path(tx2gene) val quant_type output: - tuple val(meta), path("*gene_tpm.tsv") , emit: tpm_gene - tuple val(meta), path("*gene_counts.tsv") , emit: counts_gene - tuple val(meta), path("*gene_counts_length_scaled.tsv"), emit: counts_gene_length_scaled - tuple val(meta), path("*gene_counts_scaled.tsv") , emit: counts_gene_scaled - tuple val(meta), path("*gene_lengths.tsv") , emit: lengths_gene - tuple val(meta), path("*transcript_tpm.tsv") , emit: tpm_transcript - tuple val(meta), path("*transcript_counts.tsv") , emit: counts_transcript - tuple val(meta), path("*transcript_lengths.tsv") , emit: lengths_transcript - path "versions.yml" , emit: versions + tuple val(meta), path("*.rds"), emit: se + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when script: + prefix = task.ext.prefix ?: meta.id template 'tximeta.r' stub: """ - touch ${meta.id}.gene_tpm.tsv - touch ${meta.id}.gene_counts.tsv - touch ${meta.id}.gene_counts_length_scaled.tsv - touch ${meta.id}.gene_counts_scaled.tsv - touch ${meta.id}.gene_lengths.tsv - touch ${meta.id}.transcript_tpm.tsv - touch ${meta.id}.transcript_counts.tsv - touch ${meta.id}.transcript_lengths.tsv + touch ${meta.id}_se.RDS cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/tximeta/tximeta/templates/tximeta.r b/modules/local/tximeta/tximeta/templates/tximeta.r index c4ad9e2f..878ada02 100755 --- a/modules/local/tximeta/tximeta/templates/tximeta.r +++ b/modules/local/tximeta/tximeta/templates/tximeta.r @@ -5,112 +5,8 @@ # under the MIT license. # Loading required libraries -library(SummarizedExperiment) library(tximeta) -################################################ -################################################ -## Functions ## -################################################ -################################################ - -#' Build a table from a SummarizedExperiment object -#' -#' This function takes a SummarizedExperiment object and a specific slot name to extract -#' assay data. It then combines the first two columns of the rowData with the specified -#' assay data slot into a new data table. -#' -#' @param se.obj A SummarizedExperiment object from which to build the table. -#' @param slot The name of the slot in the assays list from which to extract data. -#' -#' @return A data frame combining the first two columns of the rowData with the assay data from the specified slot. - -build_table <- function(se.obj, slot) { - cbind(rowData(se.obj)[,1:2], assays(se.obj)[[slot]]) -} - -#' Write a table to a file from a SummarizedExperiment object with given parameters -#' -#' This function generates a table from a SummarizedExperiment object using specified parameters -#' and writes the resulting table to a file. The file name is constructed using a prefix and a -#' suffix from the parameters, and the table is written with tab separation, without quoting text, -#' and without row names. -#' -#' @param params A list containing the parameters needed for file generation and table writing. -#' The list should include: -#' - `obj`: A SummarizedExperiment object from which to build the table. -#' - `slot`: The name of the slot in the assays list from which to extract data. -#' - `suffix`: Suffix to use for generating the file name. -#' -#' @return NULL The function is called for its side effect of writing a file and does not return anything. - -write_se_table <- function(params, prefix) { - file_name <- paste0(prefix, ".", params\$suffix) - write.table(build_table(params\$obj, params\$slot), file_name, - sep="\t", quote=FALSE, row.names = FALSE) -} - -#' Read Transcript Metadata from a Given Path -#' -#' This function reads transcript metadata from a specified file path. The file is expected to -#' be a tab-separated values file without headers, containing transcript information. The function -#' checks if the file is empty and stops execution with an error message if so. It reads the file -#' into a data frame, expecting columns for transcript IDs, gene IDs, and gene names. Additional -#' processing is done to ensure compatibility with a predefined data structure (e.g., `txi[[1]]`), -#' including adding missing entries and reordering based on the transcript IDs found in `txi[[1]]`. -#' -#' @param tinfo_path The file path to the transcript information file. -#' -#' @return A list containing three elements: -#' - `transcript`: A data frame with transcript IDs, gene IDs, and gene names, indexed by transcript IDs. -#' - `gene`: A data frame with unique gene IDs and gene names. -#' - `tx2gene`: A data frame mapping transcript IDs to gene IDs. - -read_transcript_info <- function(tinfo_path){ - info <- file.info(tinfo_path) - if (info\$size == 0) { - stop("tx2gene file is empty") - } - - transcript_info <- read.csv(tinfo_path, sep="\t", header = TRUE, - col.names = c("tx", "gene_id", "gene_name")) - - extra <- setdiff(rownames(se), as.character(transcript_info[["tx"]])) - transcript_info <- rbind(transcript_info, data.frame(tx=extra, gene_id=extra, gene_name=extra)) - transcript_info <- transcript_info[match(rownames(se), transcript_info[["tx"]]), ] - rownames(transcript_info) <- transcript_info[["tx"]] - - list(transcript = transcript_info, - gene = unique(transcript_info[,2:3]), - tx2gene = transcript_info[,1:2]) -} - -#' Create a SummarizedExperiment Object -#' -#' Constructs a SummarizedExperiment object using provided matrices for counts, abundance, and length, -#' along with metadata for columns and rows. This function facilitates the organization of experimental -#' data (e.g., RNA-seq or other high-throughput data) in a structured format that is convenient for -#' further analyses and visualization. -#' -#' @param counts A matrix or DataFrame containing counts data, with rows as features (e.g., genes) and -#' columns as samples. -#' @param abundance A matrix or DataFrame containing abundance data (e.g., TPM or FPKM) with the same -#' dimensions and row/column names as the counts data. -#' @param length A matrix or DataFrame containing feature lengths, matching the dimensions and row/column -#' names of the counts data. -#' @param col_data A DataFrame containing sample-level metadata, with rows corresponding to columns in the -#' counts, abundance, and length matrices. -#' @param row_data A DataFrame containing feature-level metadata, with rows corresponding to features in -#' the counts, abundance, and length matrices. -#' -#' @return A SummarizedExperiment object containing the supplied data and metadata. - -create_summarized_experiment <- function(counts, abundance, length, col_data, row_data) { - SummarizedExperiment(assays = list(counts = counts, abundance = abundance, length = length), - colData = col_data, - rowData = row_data) -} - ################################################ ################################################ ## Main script starts here ## @@ -134,57 +30,8 @@ rownames(coldata) <- coldata[["names"]] # Import transcript-level quantifications se <- tximeta(coldata, type = '$quant_type', txOut = TRUE) -# Read transcript and sample data -transcript_info <- read_transcript_info('$tx2gene') - -# Setting parameters for writing tables -params <- list( - list(obj = se, slot = "abundance", suffix = "transcript_tpm.tsv"), - list(obj = se, slot = "counts", suffix = "transcript_counts.tsv"), - list(obj = se, slot = "length", suffix = "transcript_lengths.tsv") -) - -# Process gene-level data if tx2gene mapping is available -if ("tx2gene" %in% names(transcript_info) && !is.null(transcript_info\$tx2gene)) { - tx2gene <- transcript_info\$tx2gene - gi <- summarizeToGene(se, tx2gene = tx2gene) - gi.ls <- summarizeToGene(se, tx2gene = tx2gene, countsFromAbundance = "lengthScaledTPM") - gi.s <- summarizeToGene(se, tx2gene = tx2gene, countsFromAbundance = "scaledTPM") - - gene_info <- transcript_info\$gene[match(rownames(gi[[1]]), transcript_info\$gene[["gene_id"]]),] - rownames(gene_info) <- gene_info[["tx"]] - - col_data_frame <- DataFrame(coldata) - - # Create gene-level SummarizedExperiment objects - gse <- create_summarized_experiment(gi[["counts"]], gi[["abundance"]], gi[["length"]], - col_data_frame, gene_info) - gse.ls <- create_summarized_experiment(gi.ls[["counts"]], gi.ls[["abundance"]], gi.ls[["length"]], - col_data_frame, gene_info) - gse.s <- create_summarized_experiment(gi.s[["counts"]], gi.s[["abundance"]], gi.s[["length"]], - col_data_frame, gene_info) - - params <- c(params, list( - list(obj = gse, slot = "length", suffix = "gene_lengths.tsv"), - list(obj = gse, slot = "abundance", suffix = "gene_tpm.tsv"), - list(obj = gse, slot = "counts", suffix = "gene_counts.tsv"), - list(obj = gse.ls, slot = "abundance", suffix = "gene_tpm_length_scaled.tsv"), - list(obj = gse.ls, slot = "counts", suffix = "gene_counts_length_scaled.tsv"), - list(obj = gse.s, slot = "abundance", suffix = "gene_tpm_scaled.tsv"), - list(obj = gse.s, slot = "counts", suffix = "gene_counts_scaled.tsv") - )) -} - -# Writing tables for each set of parameters - -prefix <- '' -if ('$task.ext.prefix' != 'null'){ - prefix = '$task.ext.prefix' -} else if ('$meta.id' != 'null'){ - prefix = '$meta.id' -} - -done <- lapply(params, write_se_table, prefix) +# Save summarized experiment to file +saveRDS(se, file = paste0('$prefix', '.rds')) ################################################ ################################################ @@ -192,7 +39,7 @@ done <- lapply(params, write_se_table, prefix) ################################################ ################################################ -sink(paste(prefix, "R_sessionInfo.log", sep = '.')) +sink(paste("R_sessionInfo.log", sep = '.')) citation("tximeta") print(sessionInfo()) sink() diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index 01d20a9f..92141240 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -4,7 +4,8 @@ include { GAWK as MARK_CIRCULAR } from '../../modules/nf-core/g include { PSIRC_INDEX } from '../../modules/local/psirc/index/main' include { PSIRC_QUANT } from '../../modules/local/psirc/quant/main' include { CUSTOM_TX2GENE } from '../../modules/nf-core/custom/tx2gene/main' -include { TXIMETA_TXIMETA } from '../../modules/local/tximeta/tximeta/main' +include { TXIMETA_TXIMPORT } from '../../modules/nf-core/tximeta/tximport/main' +include { TXIMETA_TXIMETA } from '../../modules/local/tximeta/tximeta/main' include { CSVTK_JOIN as JOIN_GENE_COUNTS } from '../../modules/nf-core/csvtk/join/main' include { CSVTK_JOIN as JOIN_GENE_TPM } from '../../modules/nf-core/csvtk/join/main' include { CSVTK_JOIN as JOIN_TX_COUNTS } from '../../modules/nf-core/csvtk/join/main' @@ -50,6 +51,11 @@ workflow QUANTIFICATION { ) TXIMETA_TXIMETA( + PSIRC_QUANT.out.directory, + "kallisto" + ) + + TXIMETA_TXIMPORT( PSIRC_QUANT.out.directory, CUSTOM_TX2GENE.out.tx2gene, "kallisto" @@ -59,23 +65,24 @@ workflow QUANTIFICATION { PSIRC_INDEX.out.versions, PSIRC_QUANT.out.versions, CUSTOM_TX2GENE.out.versions, - TXIMETA_TXIMETA.out.versions + TXIMETA_TXIMETA.out.versions, + TXIMETA_TXIMPORT.out.versions ) JOIN_GENE_COUNTS( - TXIMETA_TXIMETA.out.counts_gene.map{meta, counts -> counts}.collect().map{[[id: "gene_counts"], it]} + TXIMETA_TXIMPORT.out.counts_gene.map{meta, counts -> counts}.collect().map{[[id: "gene_counts"], it]} ) JOIN_GENE_TPM( - TXIMETA_TXIMETA.out.tpm_gene.map{meta, tpm -> tpm}.collect().map{[[id: "gene_tpm"], it]} + TXIMETA_TXIMPORT.out.tpm_gene.map{meta, tpm -> tpm}.collect().map{[[id: "gene_tpm"], it]} ) JOIN_TX_COUNTS( - TXIMETA_TXIMETA.out.counts_transcript.map{meta, counts -> counts}.collect().map{[[id: "tx_counts"], it]} + TXIMETA_TXIMPORT.out.counts_transcript.map{meta, counts -> counts}.collect().map{[[id: "tx_counts"], it]} ) JOIN_TX_TPM( - TXIMETA_TXIMETA.out.tpm_transcript.map{meta, tpm -> tpm}.collect().map{[[id: "tx_tpm"], it]} + TXIMETA_TXIMPORT.out.tpm_transcript.map{meta, tpm -> tpm}.collect().map{[[id: "tx_tpm"], it]} ) SPLIT_TYPES_COUNTS( From 6b261424a9f77e777a3e6aee29b833bb229234b1 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 20 Apr 2024 18:08:13 +0200 Subject: [PATCH 201/491] Implement basic swish functionality --- modules/local/fishpond/swish/environment.yml | 9 ++++ modules/local/fishpond/swish/main.nf | 30 ++++++++++++ .../local/fishpond/swish/templates/swish.r | 46 +++++++++++++++++++ modules/local/tximeta/tximeta/main.nf | 5 +- subworkflows/local/quantification.nf | 10 +++- workflows/circrna/main.nf | 3 +- 6 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 modules/local/fishpond/swish/environment.yml create mode 100644 modules/local/fishpond/swish/main.nf create mode 100644 modules/local/fishpond/swish/templates/swish.r diff --git a/modules/local/fishpond/swish/environment.yml b/modules/local/fishpond/swish/environment.yml new file mode 100644 index 00000000..9af93313 --- /dev/null +++ b/modules/local/fishpond/swish/environment.yml @@ -0,0 +1,9 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +name: "fishpond_swish" +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - "bioconda::bioconductor-fishpond=2.8.0-0" diff --git a/modules/local/fishpond/swish/main.nf b/modules/local/fishpond/swish/main.nf new file mode 100644 index 00000000..040c8443 --- /dev/null +++ b/modules/local/fishpond/swish/main.nf @@ -0,0 +1,30 @@ +process FISHPOND_SWISH { + tag "$meta.id" + label "process_medium" + + conda "${moduleDir}/environment.yaml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/bioconductor-fishpond:2.8.0--r43hdfd78af_0' : + 'biocontainers/bioconductor-fishpond:2.8.0--r43hdfd78af_0' }" + + input: + tuple val(meta), path(experiments) + tuple val(meta2), path(phenotype) + + output: + tuple val(meta), path("${meta.id}.rds"), emit: swish + path "versions.yml" , emit: versions + + script: + template "swish.r" + + stub: + """ + touch ${meta.id}.RDS + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + bioconductor-fishpond: \$(Rscript -e "library(fishpond); cat(as.character(packageVersion('fishpond')))") + END_VERSIONS + """ +} \ No newline at end of file diff --git a/modules/local/fishpond/swish/templates/swish.r b/modules/local/fishpond/swish/templates/swish.r new file mode 100644 index 00000000..c632508f --- /dev/null +++ b/modules/local/fishpond/swish/templates/swish.r @@ -0,0 +1,46 @@ +#!/usr/bin/env Rscript --vanilla + +library(fishpond) +library(SummarizedExperiment) + +paths <- c('${experiments.join("\', \'")}') +experiments <- lapply(paths, readRDS) + +phenotype <- read.csv('${phenotype}', stringsAsFactors = FALSE) + +se_assays <- list() + +for (se in experiments) { + assays <- assays(se) + # Iterate over named list of assays + for (assay_name in names(assays)) { + assay <- assays[[assay_name]] + + # Add assay to se_assays for its name + if (is.null(se_assays[[assay_name]])) { + se_assays[[assay_name]] <- assay + } else { + se_assays[[assay_name]] <- cbind(se_assays[[assay_name]], assay) + } + } +} + +se_cbind <- do.call(SummarizedExperiment::cbind, experiments) +se <- SummarizedExperiment(assays = se_assays, colData = colData(se_cbind), rowData = rowData(se_cbind)) + +# Join phenotype data +colData(se) <- merge(colData(se), phenotype, by.x="names", by.y="Sample_ID") +colData(se)\$condition <- as.factor(colData(se)\$condition) + +se <- scaleInfReps(se) +se <- labelKeep(se) +se <- swish(se, x="condition") + +saveRDS(se, '${meta.id}.rds') + +writeLines( + c( + '"${task.process}":', + paste(' bioconductor-fishpond:', packageVersion('fishpond')) + ), +'versions.yml') \ No newline at end of file diff --git a/modules/local/tximeta/tximeta/main.nf b/modules/local/tximeta/tximeta/main.nf index e1d2247b..c1be1d37 100644 --- a/modules/local/tximeta/tximeta/main.nf +++ b/modules/local/tximeta/tximeta/main.nf @@ -1,4 +1,5 @@ process TXIMETA_TXIMETA { + tag "$meta.id" label "process_medium" conda "${moduleDir}/environment.yml" @@ -12,7 +13,7 @@ process TXIMETA_TXIMETA { output: tuple val(meta), path("*.rds"), emit: se - path "versions.yml" , emit: versions + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -23,7 +24,7 @@ process TXIMETA_TXIMETA { stub: """ - touch ${meta.id}_se.RDS + touch ${meta.id}.rds cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index 92141240..715cc461 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -6,6 +6,7 @@ include { PSIRC_QUANT } from '../../modules/local/psi include { CUSTOM_TX2GENE } from '../../modules/nf-core/custom/tx2gene/main' include { TXIMETA_TXIMPORT } from '../../modules/nf-core/tximeta/tximport/main' include { TXIMETA_TXIMETA } from '../../modules/local/tximeta/tximeta/main' +include { FISHPOND_SWISH } from '../../modules/local/fishpond/swish/main' include { CSVTK_JOIN as JOIN_GENE_COUNTS } from '../../modules/nf-core/csvtk/join/main' include { CSVTK_JOIN as JOIN_GENE_TPM } from '../../modules/nf-core/csvtk/join/main' include { CSVTK_JOIN as JOIN_TX_COUNTS } from '../../modules/nf-core/csvtk/join/main' @@ -22,6 +23,7 @@ workflow QUANTIFICATION { circ_annotation_bed circ_annotation_gtf bootstrap_samples + ch_phenotype main: ch_versions = Channel.empty() @@ -55,6 +57,11 @@ workflow QUANTIFICATION { "kallisto" ) + FISHPOND_SWISH( + TXIMETA_TXIMETA.out.se.map{meta, se -> se}.collect().map{[[id: "experiments"], it]}, + ch_phenotype + ) + TXIMETA_TXIMPORT( PSIRC_QUANT.out.directory, CUSTOM_TX2GENE.out.tx2gene, @@ -66,7 +73,8 @@ workflow QUANTIFICATION { PSIRC_QUANT.out.versions, CUSTOM_TX2GENE.out.versions, TXIMETA_TXIMETA.out.versions, - TXIMETA_TXIMPORT.out.versions + TXIMETA_TXIMPORT.out.versions, + FISHPOND_SWISH.out.versions ) JOIN_GENE_COUNTS( diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 1c6c9872..5f1e27fb 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -164,7 +164,8 @@ workflow CIRCRNA { FASTQC_TRIMGALORE.out.reads, CIRCRNA_DISCOVERY.out.annotation_bed, CIRCRNA_DISCOVERY.out.annotation_gtf, - params.bootstrap_samples + params.bootstrap_samples, + ch_phenotype ) ch_versions = ch_versions.mix(QUANTIFICATION.out.versions) From 6c254a731441dc29d5dd8ce4953297e99b612b6c Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 20 Apr 2024 18:32:39 +0200 Subject: [PATCH 202/491] Fix linting --- modules/local/fishpond/swish/main.nf | 2 +- .../local/fishpond/swish/templates/swish.r | 24 +++++++++---------- subworkflows/local/quantification.nf | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/modules/local/fishpond/swish/main.nf b/modules/local/fishpond/swish/main.nf index 040c8443..ff1184ec 100644 --- a/modules/local/fishpond/swish/main.nf +++ b/modules/local/fishpond/swish/main.nf @@ -27,4 +27,4 @@ process FISHPOND_SWISH { bioconductor-fishpond: \$(Rscript -e "library(fishpond); cat(as.character(packageVersion('fishpond')))") END_VERSIONS """ -} \ No newline at end of file +} diff --git a/modules/local/fishpond/swish/templates/swish.r b/modules/local/fishpond/swish/templates/swish.r index c632508f..6ead02e7 100644 --- a/modules/local/fishpond/swish/templates/swish.r +++ b/modules/local/fishpond/swish/templates/swish.r @@ -11,18 +11,18 @@ phenotype <- read.csv('${phenotype}', stringsAsFactors = FALSE) se_assays <- list() for (se in experiments) { - assays <- assays(se) - # Iterate over named list of assays - for (assay_name in names(assays)) { - assay <- assays[[assay_name]] - - # Add assay to se_assays for its name - if (is.null(se_assays[[assay_name]])) { - se_assays[[assay_name]] <- assay - } else { - se_assays[[assay_name]] <- cbind(se_assays[[assay_name]], assay) + assays <- assays(se) + # Iterate over named list of assays + for (assay_name in names(assays)) { + assay <- assays[[assay_name]] + + # Add assay to se_assays for its name + if (is.null(se_assays[[assay_name]])) { + se_assays[[assay_name]] <- assay + } else { + se_assays[[assay_name]] <- cbind(se_assays[[assay_name]], assay) + } } - } } se_cbind <- do.call(SummarizedExperiment::cbind, experiments) @@ -43,4 +43,4 @@ writeLines( '"${task.process}":', paste(' bioconductor-fishpond:', packageVersion('fishpond')) ), -'versions.yml') \ No newline at end of file +'versions.yml') diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index 715cc461..c219fcb4 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -120,5 +120,5 @@ workflow QUANTIFICATION { circular_tx_counts = SPLIT_TYPES_COUNTS.out.circular circular_tx_tpm = SPLIT_TYPES_TPM.out.circular - versions = ch_versions + versions = ch_versions } From 48fc366228682d23e4210ae493d05e9cead2b8c2 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 20 Apr 2024 18:42:22 +0200 Subject: [PATCH 203/491] Prettier --- nextflow_schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index 03fbbf3d..2aaea8bb 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -165,7 +165,7 @@ "description": "Sequencing center information to be added to read group of BAM files.", "fa_icon": "fas fa-synagogue" }, - "bootstrap_samples":{ + "bootstrap_samples": { "type": "integer", "description": "Number of bootstrap samples to generate during quantification.", "default": 30 From 6ca97933552dcfa8584361a04737f4caea616695 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sun, 21 Apr 2024 14:19:51 +0200 Subject: [PATCH 204/491] Increase resource usage of quantification joining --- conf/modules.config | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/modules.config b/conf/modules.config index fadfbf84..f928106d 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -696,6 +696,7 @@ if (!params.skip_trimming) { withName: ".*:JOIN_(GENE|TX)_(COUNTS|TPM)" { ext.args = "-f 1,2 -t" + label = "process_medium" publishDir = [ path: { "${params.outdir}/quantification/" }, mode: params.publish_dir_mode, From c88bbf53f31c4d84505a83f2ac903a904bb243e2 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sun, 21 Apr 2024 17:09:35 +0200 Subject: [PATCH 205/491] Implement separate process for merging summarizedexperiment objects --- conf/modules.config | 1 + main.nf | 2 +- modules/local/fishpond/swish/main.nf | 6 +-- .../local/fishpond/swish/templates/swish.r | 32 +------------ .../merge_experiments/environment.yml | 9 ++++ .../quantification/merge_experiments/main.nf | 30 ++++++++++++ .../templates/merge_experiments.r | 47 +++++++++++++++++++ subworkflows/local/quantification.nf | 35 +++++++------- 8 files changed, 111 insertions(+), 51 deletions(-) create mode 100644 modules/local/quantification/merge_experiments/environment.yml create mode 100644 modules/local/quantification/merge_experiments/main.nf create mode 100644 modules/local/quantification/merge_experiments/templates/merge_experiments.r diff --git a/conf/modules.config b/conf/modules.config index f928106d..2e0a6320 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -697,6 +697,7 @@ if (!params.skip_trimming) { withName: ".*:JOIN_(GENE|TX)_(COUNTS|TPM)" { ext.args = "-f 1,2 -t" label = "process_medium" + maxRetries = 3 publishDir = [ path: { "${params.outdir}/quantification/" }, mode: params.publish_dir_mode, diff --git a/main.nf b/main.nf index a360b046..cf0a707b 100644 --- a/main.nf +++ b/main.nf @@ -59,7 +59,7 @@ workflow NFCORE_CIRCRNA { ch_fasta = Channel.value([[id: "fasta"], file(params.fasta, checkIfExists:true)]) ch_gtf = Channel.value([[id: "gtf"], file(params.gtf, checkIfExists:true)]) ch_mature = params.module.split(',').contains('mirna_prediction') ? Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) : Channel.empty() - ch_phenotype = params.module.split(',').contains('differential_expression') ? Channel.value([[id: "phenotype"], file(params.phenotype, checkIfExists:true)]) : Channel.empty() + ch_phenotype = Channel.value([[id: "phenotype"], file(params.phenotype, checkIfExists:true)]) ch_species = params.module.split(',').contains('differential_expression') ? Channel.value(params.species_id) : Channel.empty() CIRCRNA ( diff --git a/modules/local/fishpond/swish/main.nf b/modules/local/fishpond/swish/main.nf index ff1184ec..5ac73202 100644 --- a/modules/local/fishpond/swish/main.nf +++ b/modules/local/fishpond/swish/main.nf @@ -8,11 +8,11 @@ process FISHPOND_SWISH { 'biocontainers/bioconductor-fishpond:2.8.0--r43hdfd78af_0' }" input: - tuple val(meta), path(experiments) - tuple val(meta2), path(phenotype) + tuple val(meta), path(experiment) + val(column) output: - tuple val(meta), path("${meta.id}.rds"), emit: swish + tuple val(meta), path("${meta.id}.swish.rds"), emit: swish path "versions.yml" , emit: versions script: diff --git a/modules/local/fishpond/swish/templates/swish.r b/modules/local/fishpond/swish/templates/swish.r index 6ead02e7..2b95a61a 100644 --- a/modules/local/fishpond/swish/templates/swish.r +++ b/modules/local/fishpond/swish/templates/swish.r @@ -1,40 +1,12 @@ #!/usr/bin/env Rscript --vanilla library(fishpond) -library(SummarizedExperiment) -paths <- c('${experiments.join("\', \'")}') -experiments <- lapply(paths, readRDS) - -phenotype <- read.csv('${phenotype}', stringsAsFactors = FALSE) - -se_assays <- list() - -for (se in experiments) { - assays <- assays(se) - # Iterate over named list of assays - for (assay_name in names(assays)) { - assay <- assays[[assay_name]] - - # Add assay to se_assays for its name - if (is.null(se_assays[[assay_name]])) { - se_assays[[assay_name]] <- assay - } else { - se_assays[[assay_name]] <- cbind(se_assays[[assay_name]], assay) - } - } -} - -se_cbind <- do.call(SummarizedExperiment::cbind, experiments) -se <- SummarizedExperiment(assays = se_assays, colData = colData(se_cbind), rowData = rowData(se_cbind)) - -# Join phenotype data -colData(se) <- merge(colData(se), phenotype, by.x="names", by.y="Sample_ID") -colData(se)\$condition <- as.factor(colData(se)\$condition) +se <- readRDS('$experiment') se <- scaleInfReps(se) se <- labelKeep(se) -se <- swish(se, x="condition") +se <- swish(se, x="$column") saveRDS(se, '${meta.id}.rds') diff --git a/modules/local/quantification/merge_experiments/environment.yml b/modules/local/quantification/merge_experiments/environment.yml new file mode 100644 index 00000000..381dba4d --- /dev/null +++ b/modules/local/quantification/merge_experiments/environment.yml @@ -0,0 +1,9 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +name: "fishpond_swish" +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - "bioconda::bioconductor-summarizedexperiment=1.32.0" diff --git a/modules/local/quantification/merge_experiments/main.nf b/modules/local/quantification/merge_experiments/main.nf new file mode 100644 index 00000000..367a3082 --- /dev/null +++ b/modules/local/quantification/merge_experiments/main.nf @@ -0,0 +1,30 @@ +process MERGE_EXPERIMENTS { + tag "$meta.id" + label "process_medium" + + conda "${moduleDir}/environment.yaml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/bioconductor-summarizedexperiment:1.32.0--r43hdfd78af_0' : + 'biocontainers/bioconductor-summarizedexperiment:1.32.0--r43hdfd78af_0' }" + + input: + tuple val(meta), path(experiments) + tuple val(meta2), path(phenotype) + + output: + tuple val(meta), path("${meta.id}.merged.rds"), emit: merged + path "versions.yml" , emit: versions + + script: + template "merge_experiments.r" + + stub: + """ + touch ${meta.id}.merged.rds + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + bioconductor-summarizedexperiment: \$(Rscript -e "library(SummarizedExperiment); cat(as.character(packageVersion('SummarizedExperiment')))") + END_VERSIONS + """ +} diff --git a/modules/local/quantification/merge_experiments/templates/merge_experiments.r b/modules/local/quantification/merge_experiments/templates/merge_experiments.r new file mode 100644 index 00000000..51b5b666 --- /dev/null +++ b/modules/local/quantification/merge_experiments/templates/merge_experiments.r @@ -0,0 +1,47 @@ +#!/usr/bin/env Rscript --vanilla + +library(SummarizedExperiment) + +paths <- c('${experiments.join("\', \'")}') +experiments <- lapply(paths, readRDS) + +phenotype <- read.csv('${phenotype}', stringsAsFactors = FALSE) + +se_assays <- list() + +for (se in experiments) { + assays <- assays(se) + # Iterate over named list of assays + for (assay_name in names(assays)) { + assay <- assays[[assay_name]] + + # Add assay to se_assays for its name + if (is.null(se_assays[[assay_name]])) { + se_assays[[assay_name]] <- assay + } else { + se_assays[[assay_name]] <- cbind(se_assays[[assay_name]], assay) + } + } +} + +se_cbind <- do.call(SummarizedExperiment::cbind, experiments) +se <- SummarizedExperiment(assays = se_assays, colData = colData(se_cbind), rowData = rowData(se_cbind)) + +# Join phenotype data +colData(se) <- merge(colData(se), phenotype, by.x="names", by.y=colnames(phenotype)[1]) + +# Convert string columns to factors +for (col in colnames(colData(se))) { + if (is.character(colData(se)[[col]]) && !(col == "names")) { + colData(se)[[col]] <- as.factor(colData(se)[[col]]) + } +} + +saveRDS(se, '${meta.id}.merged.rds') + +writeLines( + c( + '"${task.process}":', + paste(' bioconductor-summarizedexperiment:', packageVersion('SummarizedExperiment')) + ), +'versions.yml') diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index c219fcb4..fbf030a5 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -1,18 +1,19 @@ -include { GNU_SORT as COMBINE_TRANSCRIPTOME_GTFS } from '../../modules/nf-core/gnu/sort/main' -include { TRANSCRIPTOME } from '../../modules/local/quantification/transcriptome/main' -include { GAWK as MARK_CIRCULAR } from '../../modules/nf-core/gawk/main' -include { PSIRC_INDEX } from '../../modules/local/psirc/index/main' -include { PSIRC_QUANT } from '../../modules/local/psirc/quant/main' -include { CUSTOM_TX2GENE } from '../../modules/nf-core/custom/tx2gene/main' -include { TXIMETA_TXIMPORT } from '../../modules/nf-core/tximeta/tximport/main' -include { TXIMETA_TXIMETA } from '../../modules/local/tximeta/tximeta/main' -include { FISHPOND_SWISH } from '../../modules/local/fishpond/swish/main' -include { CSVTK_JOIN as JOIN_GENE_COUNTS } from '../../modules/nf-core/csvtk/join/main' -include { CSVTK_JOIN as JOIN_GENE_TPM } from '../../modules/nf-core/csvtk/join/main' -include { CSVTK_JOIN as JOIN_TX_COUNTS } from '../../modules/nf-core/csvtk/join/main' -include { CSVTK_JOIN as JOIN_TX_TPM } from '../../modules/nf-core/csvtk/join/main' -include { SPLIT_TYPES as SPLIT_TYPES_COUNTS } from '../../modules/local/quantification/split_types/main' -include { SPLIT_TYPES as SPLIT_TYPES_TPM } from '../../modules/local/quantification/split_types/main' +include { GNU_SORT as COMBINE_TRANSCRIPTOME_GTFS } from '../../modules/nf-core/gnu/sort' +include { TRANSCRIPTOME } from '../../modules/local/quantification/transcriptome' +include { GAWK as MARK_CIRCULAR } from '../../modules/nf-core/gawk' +include { PSIRC_INDEX } from '../../modules/local/psirc/index' +include { PSIRC_QUANT } from '../../modules/local/psirc/quant' +include { CUSTOM_TX2GENE } from '../../modules/nf-core/custom/tx2gene' +include { TXIMETA_TXIMPORT } from '../../modules/nf-core/tximeta/tximport' +include { TXIMETA_TXIMETA } from '../../modules/local/tximeta/tximeta' +include { MERGE_EXPERIMENTS } from '../../modules/local/quantification/merge_experiments' +include { FISHPOND_SWISH } from '../../modules/local/fishpond/swish' +include { CSVTK_JOIN as JOIN_GENE_COUNTS } from '../../modules/nf-core/csvtk/join' +include { CSVTK_JOIN as JOIN_GENE_TPM } from '../../modules/nf-core/csvtk/join' +include { CSVTK_JOIN as JOIN_TX_COUNTS } from '../../modules/nf-core/csvtk/join' +include { CSVTK_JOIN as JOIN_TX_TPM } from '../../modules/nf-core/csvtk/join' +include { SPLIT_TYPES as SPLIT_TYPES_COUNTS } from '../../modules/local/quantification/split_types' +include { SPLIT_TYPES as SPLIT_TYPES_TPM } from '../../modules/local/quantification/split_types' workflow QUANTIFICATION { take: @@ -57,7 +58,7 @@ workflow QUANTIFICATION { "kallisto" ) - FISHPOND_SWISH( + MERGE_EXPERIMENTS( TXIMETA_TXIMETA.out.se.map{meta, se -> se}.collect().map{[[id: "experiments"], it]}, ch_phenotype ) @@ -74,7 +75,7 @@ workflow QUANTIFICATION { CUSTOM_TX2GENE.out.versions, TXIMETA_TXIMETA.out.versions, TXIMETA_TXIMPORT.out.versions, - FISHPOND_SWISH.out.versions + MERGE_EXPERIMENTS.out.versions ) JOIN_GENE_COUNTS( From 257d4da042c1bd1d9d816f49866fdf22cb2bf823 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Wed, 24 Apr 2024 07:12:21 +0200 Subject: [PATCH 206/491] Fix problematic stub in FISHPOND_SWISH --- modules/local/fishpond/swish/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/fishpond/swish/main.nf b/modules/local/fishpond/swish/main.nf index 5ac73202..cb011ec8 100644 --- a/modules/local/fishpond/swish/main.nf +++ b/modules/local/fishpond/swish/main.nf @@ -20,7 +20,7 @@ process FISHPOND_SWISH { stub: """ - touch ${meta.id}.RDS + touch ${meta.id}.swish.rds cat <<-END_VERSIONS > versions.yml "${task.process}": From aa266a5f7536903d14b94ba90864af2a5f7a4aec Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Wed, 24 Apr 2024 07:29:00 +0200 Subject: [PATCH 207/491] Add bam file output to psirc-quant --- modules.json | 5 + modules/local/psirc/quant/main.nf | 6 +- .../nf-core/samtools/faidx/environment.yml | 10 + modules/nf-core/samtools/faidx/main.nf | 50 ++++ modules/nf-core/samtools/faidx/meta.yml | 65 +++++ .../nf-core/samtools/faidx/tests/main.nf.test | 122 +++++++++ .../samtools/faidx/tests/main.nf.test.snap | 249 ++++++++++++++++++ .../samtools/faidx/tests/nextflow.config | 7 + .../samtools/faidx/tests/nextflow2.config | 6 + modules/nf-core/samtools/faidx/tests/tags.yml | 2 + subworkflows/local/prepare_genome.nf | 22 +- subworkflows/local/quantification.nf | 3 +- workflows/circrna/main.nf | 3 +- 13 files changed, 538 insertions(+), 12 deletions(-) create mode 100644 modules/nf-core/samtools/faidx/environment.yml create mode 100644 modules/nf-core/samtools/faidx/main.nf create mode 100644 modules/nf-core/samtools/faidx/meta.yml create mode 100644 modules/nf-core/samtools/faidx/tests/main.nf.test create mode 100644 modules/nf-core/samtools/faidx/tests/main.nf.test.snap create mode 100644 modules/nf-core/samtools/faidx/tests/nextflow.config create mode 100644 modules/nf-core/samtools/faidx/tests/nextflow2.config create mode 100644 modules/nf-core/samtools/faidx/tests/tags.yml diff --git a/modules.json b/modules.json index 77b6ee5d..3cd8115e 100644 --- a/modules.json +++ b/modules.json @@ -125,6 +125,11 @@ "git_sha": "b7ebe95761cd389603f9cc0e0dc384c0f663815a", "installed_by": ["modules"] }, + "samtools/faidx": { + "branch": "master", + "git_sha": "f153f1f10e1083c49935565844cccb7453021682", + "installed_by": ["modules"] + }, "samtools/flagstat": { "branch": "master", "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", diff --git a/modules/local/psirc/quant/main.nf b/modules/local/psirc/quant/main.nf index 5761aaad..edecc8f9 100644 --- a/modules/local/psirc/quant/main.nf +++ b/modules/local/psirc/quant/main.nf @@ -7,6 +7,8 @@ process PSIRC_QUANT { input: tuple val(meta), path(reads) tuple val(meta2), path(index) + tuple val(meta3), path(gtf) + tuple val(meta4), path(chrom_sizes) val(bootstrap_samples) output: @@ -15,9 +17,11 @@ process PSIRC_QUANT { script: def single_end = meta.single_end ? "--single -l 76 -s 20" : "" + def genomebam = gtf ? "--genomebam -g $gtf" : "" + def chromosomes = chrom_sizes ? "-c $chrom_sizes" : "" def VERSION = '1.0' """ - psirc-quant quant -t $task.cpus -i $index -o $meta.id $single_end $reads -b $bootstrap_samples + psirc-quant quant -t $task.cpus -i $index -o $meta.id $single_end $reads -b $bootstrap_samples $genomebam $chromosomes cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/samtools/faidx/environment.yml b/modules/nf-core/samtools/faidx/environment.yml new file mode 100644 index 00000000..9c24eb0a --- /dev/null +++ b/modules/nf-core/samtools/faidx/environment.yml @@ -0,0 +1,10 @@ +name: samtools_faidx + +channels: + - conda-forge + - bioconda + - defaults + +dependencies: + - bioconda::htslib=1.19.1 + - bioconda::samtools=1.19.2 diff --git a/modules/nf-core/samtools/faidx/main.nf b/modules/nf-core/samtools/faidx/main.nf new file mode 100644 index 00000000..cfe7ad95 --- /dev/null +++ b/modules/nf-core/samtools/faidx/main.nf @@ -0,0 +1,50 @@ +process SAMTOOLS_FAIDX { + tag "$fasta" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/samtools:1.19.2--h50ea8bc_0' : + 'biocontainers/samtools:1.19.2--h50ea8bc_0' }" + + input: + tuple val(meta), path(fasta) + tuple val(meta2), path(fai) + + output: + tuple val(meta), path ("*.{fa,fasta}") , emit: fa , optional: true + tuple val(meta), path ("*.fai") , emit: fai, optional: true + tuple val(meta), path ("*.gzi") , emit: gzi, optional: true + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + """ + samtools \\ + faidx \\ + $fasta \\ + $args + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') + END_VERSIONS + """ + + stub: + def match = (task.ext.args =~ /-o(?:utput)?\s(.*)\s?/).findAll() + def fastacmd = match[0] ? "touch ${match[0][1]}" : '' + """ + ${fastacmd} + touch ${fasta}.fai + + cat <<-END_VERSIONS > versions.yml + + "${task.process}": + samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') + END_VERSIONS + """ +} diff --git a/modules/nf-core/samtools/faidx/meta.yml b/modules/nf-core/samtools/faidx/meta.yml new file mode 100644 index 00000000..f3c25de2 --- /dev/null +++ b/modules/nf-core/samtools/faidx/meta.yml @@ -0,0 +1,65 @@ +name: samtools_faidx +description: Index FASTA file +keywords: + - index + - fasta + - faidx +tools: + - samtools: + description: | + SAMtools is a set of utilities for interacting with and post-processing + short DNA sequence read alignments in the SAM, BAM and CRAM formats, written by Heng Li. + These files are generated as output by short read aligners like BWA. + homepage: http://www.htslib.org/ + documentation: http://www.htslib.org/doc/samtools.html + doi: 10.1093/bioinformatics/btp352 + licence: ["MIT"] +input: + - meta: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'test' ] + - fasta: + type: file + description: FASTA file + pattern: "*.{fa,fasta}" + - meta2: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'test' ] + - fai: + type: file + description: FASTA index file + pattern: "*.{fai}" +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - fa: + type: file + description: FASTA file + pattern: "*.{fa}" + - fai: + type: file + description: FASTA index file + pattern: "*.{fai}" + - gzi: + type: file + description: Optional gzip index file for compressed inputs + pattern: "*.gzi" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@drpatelh" + - "@ewels" + - "@phue" +maintainers: + - "@drpatelh" + - "@ewels" + - "@phue" diff --git a/modules/nf-core/samtools/faidx/tests/main.nf.test b/modules/nf-core/samtools/faidx/tests/main.nf.test new file mode 100644 index 00000000..17244ef2 --- /dev/null +++ b/modules/nf-core/samtools/faidx/tests/main.nf.test @@ -0,0 +1,122 @@ +nextflow_process { + + name "Test Process SAMTOOLS_FAIDX" + script "../main.nf" + process "SAMTOOLS_FAIDX" + + tag "modules" + tag "modules_nfcore" + tag "samtools" + tag "samtools/faidx" + + test("test_samtools_faidx") { + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] + + input[1] = [[],[]] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_samtools_faidx_bgzip") { + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true)] + + input[1] = [[],[]] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_samtools_faidx_fasta") { + + config "./nextflow.config" + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] + + input[1] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_samtools_faidx_stub_fasta") { + + config "./nextflow2.config" + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] + + input[1] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_samtools_faidx_stub_fai") { + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] + + input[1] = [[],[]] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } +} \ No newline at end of file diff --git a/modules/nf-core/samtools/faidx/tests/main.nf.test.snap b/modules/nf-core/samtools/faidx/tests/main.nf.test.snap new file mode 100644 index 00000000..3e651ef6 --- /dev/null +++ b/modules/nf-core/samtools/faidx/tests/main.nf.test.snap @@ -0,0 +1,249 @@ +{ + "test_samtools_faidx": { + "content": [ + { + "0": [ + + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + ], + "fa": [ + + ], + "fai": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "gzi": [ + + ], + "versions": [ + "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-18T16:22:39.412601" + }, + "test_samtools_faidx_bgzip": { + "content": [ + { + "0": [ + + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.gz.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.gz.gzi:md5,7dea362b3fac8e00956a4952a3d4f474" + ] + ], + "3": [ + "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + ], + "fa": [ + + ], + "fai": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.gz.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "gzi": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.gz.gzi:md5,7dea362b3fac8e00956a4952a3d4f474" + ] + ], + "versions": [ + "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-18T16:23:22.427966" + }, + "test_samtools_faidx_fasta": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "extract.fa:md5,6a0774a0ad937ba0bfd2ac7457d90f36" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + ], + "fa": [ + [ + { + "id": "test", + "single_end": false + }, + "extract.fa:md5,6a0774a0ad937ba0bfd2ac7457d90f36" + ] + ], + "fai": [ + + ], + "gzi": [ + + ], + "versions": [ + "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-18T16:24:04.107537" + }, + "test_samtools_faidx_stub_fasta": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "extract.fa:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + ], + "fa": [ + [ + { + "id": "test", + "single_end": false + }, + "extract.fa:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "fai": [ + + ], + "gzi": [ + + ], + "versions": [ + "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-18T16:24:45.868463" + }, + "test_samtools_faidx_stub_fai": { + "content": [ + { + "0": [ + + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + ], + "fa": [ + + ], + "fai": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "gzi": [ + + ], + "versions": [ + "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-18T16:25:27.550554" + } +} \ No newline at end of file diff --git a/modules/nf-core/samtools/faidx/tests/nextflow.config b/modules/nf-core/samtools/faidx/tests/nextflow.config new file mode 100644 index 00000000..f76a3ba0 --- /dev/null +++ b/modules/nf-core/samtools/faidx/tests/nextflow.config @@ -0,0 +1,7 @@ +process { + + withName: SAMTOOLS_FAIDX { + ext.args = 'MT192765.1 -o extract.fa' + } + +} diff --git a/modules/nf-core/samtools/faidx/tests/nextflow2.config b/modules/nf-core/samtools/faidx/tests/nextflow2.config new file mode 100644 index 00000000..33ebbd5d --- /dev/null +++ b/modules/nf-core/samtools/faidx/tests/nextflow2.config @@ -0,0 +1,6 @@ +process { + + withName: SAMTOOLS_FAIDX { + ext.args = '-o extract.fa' + } +} diff --git a/modules/nf-core/samtools/faidx/tests/tags.yml b/modules/nf-core/samtools/faidx/tests/tags.yml new file mode 100644 index 00000000..e4a83948 --- /dev/null +++ b/modules/nf-core/samtools/faidx/tests/tags.yml @@ -0,0 +1,2 @@ +samtools/faidx: + - modules/nf-core/samtools/faidx/** diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 5d3b0755..6c2c0b4b 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -1,12 +1,13 @@ -include { SEQKIT_SPLIT } from '../../modules/local/seqkit/split/main' -include { BOWTIE_BUILD } from '../../modules/nf-core/bowtie/build/main' -include { BOWTIE2_BUILD } from '../../modules/nf-core/bowtie2/build/main' -include { BWA_INDEX } from '../../modules/nf-core/bwa/index/main' -include { HISAT2_EXTRACTSPLICESITES } from '../../modules/nf-core/hisat2/extractsplicesites/main' -include { HISAT2_BUILD } from '../../modules/nf-core/hisat2/build/main' -include { STAR_GENOMEGENERATE } from '../../modules/nf-core/star/genomegenerate/main' -include { SEGEMEHL_INDEX } from '../../modules/nf-core/segemehl/index/main' -include { GAWK as CLEAN_FASTA } from '../../modules/nf-core/gawk/main' +include { SEQKIT_SPLIT } from '../../modules/local/seqkit/split' +include { BOWTIE_BUILD } from '../../modules/nf-core/bowtie/build' +include { BOWTIE2_BUILD } from '../../modules/nf-core/bowtie2/build' +include { BWA_INDEX } from '../../modules/nf-core/bwa/index' +include { HISAT2_EXTRACTSPLICESITES } from '../../modules/nf-core/hisat2/extractsplicesites' +include { HISAT2_BUILD } from '../../modules/nf-core/hisat2/build' +include { STAR_GENOMEGENERATE } from '../../modules/nf-core/star/genomegenerate' +include { SEGEMEHL_INDEX } from '../../modules/nf-core/segemehl/index' +include { GAWK as CLEAN_FASTA } from '../../modules/nf-core/gawk' +include { SAMTOOLS_FAIDX } from '../../modules/nf-core/samtools/faidx' workflow PREPARE_GENOME { @@ -42,6 +43,8 @@ workflow PREPARE_GENOME { SEGEMEHL_INDEX(ch_fasta.map{ meta, fasta -> fasta}) // TODO: Add support for meta + SAMTOOLS_FAIDX(ch_fasta, [[], []]) + // Collect versions ch_versions = ch_versions.mix(SEQKIT_SPLIT.out.versions, BOWTIE_BUILD.out.versions, @@ -53,6 +56,7 @@ workflow PREPARE_GENOME { STAR_GENOMEGENERATE.out.versions) emit: + faidx = SAMTOOLS_FAIDX.out.fai bowtie = params.bowtie ?: BOWTIE_BUILD.out.index segemehl = params.segemehl ?: SEGEMEHL_INDEX.out.index bowtie2 = params.bowtie2 ? Channel.value([[id: "bowtie2"], file(params.bowtie2, checkIfExists: true)]) : BOWTIE2_BUILD.out.index.collect() diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index fbf030a5..9420fd2f 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -25,6 +25,7 @@ workflow QUANTIFICATION { circ_annotation_gtf bootstrap_samples ch_phenotype + ch_faidx main: ch_versions = Channel.empty() @@ -43,7 +44,7 @@ workflow QUANTIFICATION { ) PSIRC_INDEX(MARK_CIRCULAR.out.output) - PSIRC_QUANT(reads, PSIRC_INDEX.out.index.collect(), bootstrap_samples) + PSIRC_QUANT(reads, PSIRC_INDEX.out.index.collect(), MARK_CIRCULAR.out.output, ch_faidx, bootstrap_samples) CUSTOM_TX2GENE( COMBINE_TRANSCRIPTOME_GTFS.out.sorted, diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 5f1e27fb..b8bfa62d 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -165,7 +165,8 @@ workflow CIRCRNA { CIRCRNA_DISCOVERY.out.annotation_bed, CIRCRNA_DISCOVERY.out.annotation_gtf, params.bootstrap_samples, - ch_phenotype + ch_phenotype, + PREPARE_GENOME.out.faidx ) ch_versions = ch_versions.mix(QUANTIFICATION.out.versions) From 86996528ec322f9e03b1ea912b32913d0f886747 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Wed, 24 Apr 2024 16:33:29 +0200 Subject: [PATCH 208/491] Remove swish traces --- modules/local/fishpond/swish/environment.yml | 9 ------ modules/local/fishpond/swish/main.nf | 30 ------------------- .../local/fishpond/swish/templates/swish.r | 18 ----------- subworkflows/local/quantification.nf | 1 - 4 files changed, 58 deletions(-) delete mode 100644 modules/local/fishpond/swish/environment.yml delete mode 100644 modules/local/fishpond/swish/main.nf delete mode 100644 modules/local/fishpond/swish/templates/swish.r diff --git a/modules/local/fishpond/swish/environment.yml b/modules/local/fishpond/swish/environment.yml deleted file mode 100644 index 9af93313..00000000 --- a/modules/local/fishpond/swish/environment.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json -name: "fishpond_swish" -channels: - - conda-forge - - bioconda - - defaults -dependencies: - - "bioconda::bioconductor-fishpond=2.8.0-0" diff --git a/modules/local/fishpond/swish/main.nf b/modules/local/fishpond/swish/main.nf deleted file mode 100644 index cb011ec8..00000000 --- a/modules/local/fishpond/swish/main.nf +++ /dev/null @@ -1,30 +0,0 @@ -process FISHPOND_SWISH { - tag "$meta.id" - label "process_medium" - - conda "${moduleDir}/environment.yaml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/bioconductor-fishpond:2.8.0--r43hdfd78af_0' : - 'biocontainers/bioconductor-fishpond:2.8.0--r43hdfd78af_0' }" - - input: - tuple val(meta), path(experiment) - val(column) - - output: - tuple val(meta), path("${meta.id}.swish.rds"), emit: swish - path "versions.yml" , emit: versions - - script: - template "swish.r" - - stub: - """ - touch ${meta.id}.swish.rds - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bioconductor-fishpond: \$(Rscript -e "library(fishpond); cat(as.character(packageVersion('fishpond')))") - END_VERSIONS - """ -} diff --git a/modules/local/fishpond/swish/templates/swish.r b/modules/local/fishpond/swish/templates/swish.r deleted file mode 100644 index 2b95a61a..00000000 --- a/modules/local/fishpond/swish/templates/swish.r +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env Rscript --vanilla - -library(fishpond) - -se <- readRDS('$experiment') - -se <- scaleInfReps(se) -se <- labelKeep(se) -se <- swish(se, x="$column") - -saveRDS(se, '${meta.id}.rds') - -writeLines( - c( - '"${task.process}":', - paste(' bioconductor-fishpond:', packageVersion('fishpond')) - ), -'versions.yml') diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index 9420fd2f..86cee630 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -7,7 +7,6 @@ include { CUSTOM_TX2GENE } from '../../modules/nf-core/c include { TXIMETA_TXIMPORT } from '../../modules/nf-core/tximeta/tximport' include { TXIMETA_TXIMETA } from '../../modules/local/tximeta/tximeta' include { MERGE_EXPERIMENTS } from '../../modules/local/quantification/merge_experiments' -include { FISHPOND_SWISH } from '../../modules/local/fishpond/swish' include { CSVTK_JOIN as JOIN_GENE_COUNTS } from '../../modules/nf-core/csvtk/join' include { CSVTK_JOIN as JOIN_GENE_TPM } from '../../modules/nf-core/csvtk/join' include { CSVTK_JOIN as JOIN_TX_COUNTS } from '../../modules/nf-core/csvtk/join' From 282ac3293de4efbb4504827fa5fcb56ba52c824a Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Wed, 24 Apr 2024 18:32:16 +0200 Subject: [PATCH 209/491] Remove check for overlong circRNAs --- bin/annotation.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/bin/annotation.py b/bin/annotation.py index 21bd9587..17001e36 100755 --- a/bin/annotation.py +++ b/bin/annotation.py @@ -33,9 +33,6 @@ df = pd.read_csv(args.input, sep="\t", header=None, usecols=columns.keys()) df = df.rename(columns=columns) -# Remove overlong circRNAs -df = df[df['end'] - df['start'] <= 10_000] - # Extract circRNAs without match mask = df['tx_start'] == -1 df_intergenic = df[mask] From 7e367ade97e128af997522ba1d21f02c28ca6cea Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 25 Apr 2024 08:02:26 +0200 Subject: [PATCH 210/491] Fix environment int COUNTS_COMBINED --- modules/local/count_matrix/combined/main.nf | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/local/count_matrix/combined/main.nf b/modules/local/count_matrix/combined/main.nf index 5b3bc28a..7d1e1269 100644 --- a/modules/local/count_matrix/combined/main.nf +++ b/modules/local/count_matrix/combined/main.nf @@ -1,10 +1,10 @@ process COUNTS_COMBINED { label "process_single" - conda "conda-forge::mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6==fccb0c41a243c639e11dd1be7b74f563e624fcca-0" + conda "bioconda::pandas=1.5.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0': - 'biocontainers/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0' }" + 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : + 'biocontainers/pandas:1.5.2' }" input: path(beds) @@ -22,7 +22,6 @@ process COUNTS_COMBINED { "${task.process}": python: \$(python --version | sed 's/Python //g') pandas: \$(python -c "import pandas; print(pandas.__version__)") - numpy: \$(python -c "import numpy; print(numpy.__version__)") END_VERSIONS """ } From 2ae28facc94748a690fd4828daf1a3687e1d842e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 25 Apr 2024 09:28:53 +0200 Subject: [PATCH 211/491] Remove quay.io prefixes --- modules/local/annotation/parent_gene/main.nf | 2 +- modules/local/circexplorer2/reference/main.nf | 2 +- modules/local/circrna_finder/filter/main.nf | 2 +- modules/local/circtest/prepare/main.nf | 2 +- modules/local/circtest/test/main.nf | 2 +- modules/local/ciriquant/ciriquant/main.nf | 2 +- modules/local/dcc/dcc/main.nf | 2 +- modules/local/deseq2/differential_expression/main.nf | 2 +- modules/local/fasta/main.nf | 2 +- modules/local/find_circ/anchors/main.nf | 2 +- modules/local/find_circ/filter/main.nf | 2 +- modules/local/find_circ/find_circ/main.nf | 2 +- modules/local/mapsplice/align/main.nf | 2 +- modules/local/mirna_targets/main.nf | 2 +- modules/local/stringtie/prepde/main.nf | 2 +- modules/local/targetscan/predict/main.nf | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/modules/local/annotation/parent_gene/main.nf b/modules/local/annotation/parent_gene/main.nf index 9566f015..21f0b892 100644 --- a/modules/local/annotation/parent_gene/main.nf +++ b/modules/local/annotation/parent_gene/main.nf @@ -4,7 +4,7 @@ process PARENT_GENE { conda "bioconda::ucsc-gtftogenepred=377 bioconda::ucsc-genepredtobed=377 bioconda::bedtools=2.27.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' : - 'quay.io/biocontainers/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' }" + 'biocontainers/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' }" input: path circrna_matrix diff --git a/modules/local/circexplorer2/reference/main.nf b/modules/local/circexplorer2/reference/main.nf index 07571e4a..f16fa9c0 100644 --- a/modules/local/circexplorer2/reference/main.nf +++ b/modules/local/circexplorer2/reference/main.nf @@ -5,7 +5,7 @@ process CIRCEXPLORER2_REFERENCE { conda "bioconda::ucsc-gtftogenepred=377 bioconda::ucsc-genepredtobed=377 bioconda::bedtools=2.27.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' : - 'quay.io/biocontainers/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' }" + 'biocontainers/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' }" input: path gtf diff --git a/modules/local/circrna_finder/filter/main.nf b/modules/local/circrna_finder/filter/main.nf index 1182442f..1f781a32 100644 --- a/modules/local/circrna_finder/filter/main.nf +++ b/modules/local/circrna_finder/filter/main.nf @@ -5,7 +5,7 @@ process CIRCRNA_FINDER_FILTER { conda "bioconda::circrna_finder=1.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/circrna_finder%3A1.2--pl5321hdfd78af_1' : - 'quay.io/biocontainers/circrna_finder:1.2--pl5321hdfd78af_1' }" + 'biocontainers/circrna_finder:1.2--pl5321hdfd78af_1' }" input: tuple val(meta), path(sam), path(junction), path(tab) diff --git a/modules/local/circtest/prepare/main.nf b/modules/local/circtest/prepare/main.nf index 2fecd7b0..834c6063 100644 --- a/modules/local/circtest/prepare/main.nf +++ b/modules/local/circtest/prepare/main.nf @@ -4,7 +4,7 @@ process PREPARE_CLR_TEST { conda "conda-forge::r-base=4.2.2 conda-forge::r-aod=1.3.2 conda-forge::r-ggplot2=3.4.0 conda-forge::r-plyr=1.8.8" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' : - 'quay.io/biocontainers/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' }" + 'biocontainers/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' }" input: path(gene_matrix) diff --git a/modules/local/circtest/test/main.nf b/modules/local/circtest/test/main.nf index 643f2c56..c7add5e6 100644 --- a/modules/local/circtest/test/main.nf +++ b/modules/local/circtest/test/main.nf @@ -4,7 +4,7 @@ process CIRCTEST { conda "conda-forge::r-base=4.2.2 conda-forge::r-aod=1.3.2 conda-forge::r-ggplot2=3.4.0 conda-forge::r-plyr=1.8.8" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' : - 'quay.io/biocontainers/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' }" + 'biocontainers/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' }" input: path(circ_csv) diff --git a/modules/local/ciriquant/ciriquant/main.nf b/modules/local/ciriquant/ciriquant/main.nf index fab482ba..5c96fe14 100644 --- a/modules/local/ciriquant/ciriquant/main.nf +++ b/modules/local/ciriquant/ciriquant/main.nf @@ -5,7 +5,7 @@ process CIRIQUANT { conda "bioconda::ciriquant=1.1.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/ciriquant:1.1.2--pyhdfd78af_2' : - 'quay.io/biocontainers/ciriquant:1.1.2--pyhdfd78af_2' }" + 'biocontainers/ciriquant:1.1.2--pyhdfd78af_2' }" input: tuple val(meta), path(reads) diff --git a/modules/local/dcc/dcc/main.nf b/modules/local/dcc/dcc/main.nf index 77dc2c55..9baad3ff 100644 --- a/modules/local/dcc/dcc/main.nf +++ b/modules/local/dcc/dcc/main.nf @@ -5,7 +5,7 @@ process DCC { conda "bioconda::circtools=1.2.1" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/circtools:1.2.1--pyh7cba7a3_0' : - 'quay.io/biocontainers/circtools:1.2.1--pyh7cba7a3_0' }" + 'biocontainers/circtools:1.2.1--pyh7cba7a3_0' }" input: tuple val(meta), path(pairs), path(mate1), path(mate2) diff --git a/modules/local/deseq2/differential_expression/main.nf b/modules/local/deseq2/differential_expression/main.nf index 86ee474c..560df2fc 100644 --- a/modules/local/deseq2/differential_expression/main.nf +++ b/modules/local/deseq2/differential_expression/main.nf @@ -4,7 +4,7 @@ process DESEQ2_DIFFERENTIAL_EXPRESSION { conda "r-base=3.6.3 conda-forge::r-argparser=0.6 conda-forge::r-dplyr=1.0.5 conda-forge::r-ggplot2=3.3.3 r-ggpubr=0.4.0 conda-forge::r-gplots=3.1.1 conda-forge::r-pheatmap=1.0.12 r-plyr=1.8.6 r-pvclust=2.2_0 r-rcolorbrewer=1.1_2 conda-forge::r-circlize=0.4.12 bioconductor-biomart=2.42.0 bioconductor-complexheatmap=2.2.0 bioconductor-deseq2=1.26.0 bioconductor-enhancedvolcano=1.4.0 bioconductor-ihw=1.14.0 bioconductor-org.hs.eg.db=3.10.0 bioconductor-pcatools=1.2.0 bioconductor-tximport=1.14.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-04b2ef814c9c6ab8c196c3e372521b88160dc260:e0cb4046baee3fd35fdbf883ba8af34e3e8af2e8-0' : - 'quay.io/biocontainers/mulled-v2-04b2ef814c9c6ab8c196c3e372521b88160dc260:e0cb4046baee3fd35fdbf883ba8af34e3e8af2e8-0' }" + 'biocontainers/mulled-v2-04b2ef814c9c6ab8c196c3e372521b88160dc260:e0cb4046baee3fd35fdbf883ba8af34e3e8af2e8-0' }" input: path(gene_matrix) diff --git a/modules/local/fasta/main.nf b/modules/local/fasta/main.nf index 63381c1b..d17b17d7 100644 --- a/modules/local/fasta/main.nf +++ b/modules/local/fasta/main.nf @@ -5,7 +5,7 @@ process FASTA { conda "bioconda::bedtools=2.30.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/bedtools:2.30.0--h7d7f7ad_2': - 'quay.io/biocontainers/bedtools:2.30.0--h7d7f7ad_2' }" + 'biocontainers/bedtools:2.30.0--h7d7f7ad_2' }" input: tuple val(meta), path(bed) diff --git a/modules/local/find_circ/anchors/main.nf b/modules/local/find_circ/anchors/main.nf index 5359497d..9bccb403 100644 --- a/modules/local/find_circ/anchors/main.nf +++ b/modules/local/find_circ/anchors/main.nf @@ -5,7 +5,7 @@ process FIND_CIRC_ANCHORS { conda "bioconda::find_circ=1.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/find_circ%3A1.2--hdfd78af_0' : - 'quay.io/biocontainers/find_circ:1.2--hdfd78af_0' }" + 'biocontainers/find_circ:1.2--hdfd78af_0' }" input: tuple val(meta), path(bam) diff --git a/modules/local/find_circ/filter/main.nf b/modules/local/find_circ/filter/main.nf index c8e4f3a7..c4313b20 100644 --- a/modules/local/find_circ/filter/main.nf +++ b/modules/local/find_circ/filter/main.nf @@ -5,7 +5,7 @@ process FIND_CIRC_FILTER { conda "bioconda::find_circ=1.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/find_circ%3A1.2--hdfd78af_0' : - 'quay.io/biocontainers/find_circ:1.2--hdfd78af_0' }" + 'biocontainers/find_circ:1.2--hdfd78af_0' }" input: tuple val(meta), path(bed) diff --git a/modules/local/find_circ/find_circ/main.nf b/modules/local/find_circ/find_circ/main.nf index 242e195f..bd1bced2 100644 --- a/modules/local/find_circ/find_circ/main.nf +++ b/modules/local/find_circ/find_circ/main.nf @@ -5,7 +5,7 @@ process FIND_CIRC { conda "bioconda::find_circ=1.2 bioconda::bowtie2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mulled-v2-c27e472038a09e49d9147bc52903e12836302c12:60ffb3b15a2c40c669f8d38382b1e6e4b065f5e4-0' : - 'quay.io/biocontainers/mulled-v2-c27e472038a09e49d9147bc52903e12836302c12:60ffb3b15a2c40c669f8d38382b1e6e4b065f5e4-0' }" + 'biocontainers/mulled-v2-c27e472038a09e49d9147bc52903e12836302c12:60ffb3b15a2c40c669f8d38382b1e6e4b065f5e4-0' }" input: tuple val(meta), path(anchors) diff --git a/modules/local/mapsplice/align/main.nf b/modules/local/mapsplice/align/main.nf index 7dcbbbd3..a90930d6 100644 --- a/modules/local/mapsplice/align/main.nf +++ b/modules/local/mapsplice/align/main.nf @@ -5,7 +5,7 @@ process MAPSPLICE_ALIGN { conda "bioconda::mapsplice=2.2.1" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/mapsplice:2.2.1--py27h07887db_0': - 'quay.io/biocontainers/mapsplice:2.2.1--py27h07887db_0' }" + 'biocontainers/mapsplice:2.2.1--py27h07887db_0' }" input: tuple val(meta), path(reads) diff --git a/modules/local/mirna_targets/main.nf b/modules/local/mirna_targets/main.nf index fdfee556..94b31eeb 100644 --- a/modules/local/mirna_targets/main.nf +++ b/modules/local/mirna_targets/main.nf @@ -5,7 +5,7 @@ process MIRNA_TARGETS { conda "bioconda::bedtools=2.30.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/bedtools:2.30.0--h7d7f7ad_2': - 'quay.io/biocontainers/bedtools:2.30.0--h7d7f7ad_2' }" + 'biocontainers/bedtools:2.30.0--h7d7f7ad_2' }" input: tuple val(meta), path(targetscan), path(miranda), path(bed12) diff --git a/modules/local/stringtie/prepde/main.nf b/modules/local/stringtie/prepde/main.nf index eb72483b..38f27434 100644 --- a/modules/local/stringtie/prepde/main.nf +++ b/modules/local/stringtie/prepde/main.nf @@ -4,7 +4,7 @@ process STRINGTIE_PREPDE { conda "bioconda::stringtie=2.2.1" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/stringtie:2.2.1--hecb563c_2' : - 'quay.io/biocontainers/stringtie:2.2.1--hecb563c_2' }" + 'biocontainers/stringtie:2.2.1--hecb563c_2' }" input: path gtf diff --git a/modules/local/targetscan/predict/main.nf b/modules/local/targetscan/predict/main.nf index 12d3511e..450611c2 100644 --- a/modules/local/targetscan/predict/main.nf +++ b/modules/local/targetscan/predict/main.nf @@ -5,7 +5,7 @@ process TARGETSCAN { conda "bioconda::targetscan=7.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/targetscan:7.0--pl5321hdfd78af_0' : - 'quay.io/biocontainers/targetscan:7.0--pl5321hdfd78af_0' }" + 'biocontainers/targetscan:7.0--pl5321hdfd78af_0' }" input: tuple val(meta), path(fasta) From eceacd7e61d9f58f6a71064e0af7c97ea2b2f172 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 25 Apr 2024 09:33:37 +0200 Subject: [PATCH 212/491] Fix environment definition of MERGE_TOOLS --- modules/local/count_matrix/merge_tools/main.nf | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/local/count_matrix/merge_tools/main.nf b/modules/local/count_matrix/merge_tools/main.nf index 55bdcde0..17f8556f 100644 --- a/modules/local/count_matrix/merge_tools/main.nf +++ b/modules/local/count_matrix/merge_tools/main.nf @@ -2,10 +2,10 @@ process MERGE_TOOLS { tag "$meta.id" label "process_single" - conda "conda-forge::mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6==fccb0c41a243c639e11dd1be7b74f563e624fcca-0" + conda "bioconda::pandas=1.5.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0': - 'biocontainers/mulled-v2-2076f4a3fb468a04063c9e6b7747a630abb457f6:fccb0c41a243c639e11dd1be7b74f563e624fcca-0' }" + 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : + 'biocontainers/pandas:1.5.2' }" input: tuple val(meta), path(beds) @@ -25,7 +25,6 @@ process MERGE_TOOLS { "${task.process}": python: \$(python --version | sed 's/Python //g') pandas: \$(python -c "import pandas; print(pandas.__version__)") - numpy: \$(python -c "import numpy; print(numpy.__version__)") END_VERSIONS """ } From 4cded24939feca3915e0f174e9de49da2cfe450f Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Wed, 8 May 2024 13:58:09 +0000 Subject: [PATCH 213/491] Template update for nf-core/tools version 2.14.0 --- .editorconfig | 6 +- .github/PULL_REQUEST_TEMPLATE.md | 2 +- .github/workflows/awsfulltest.yml | 10 +- .github/workflows/awstest.yml | 12 +- .github/workflows/ci.yml | 4 +- .github/workflows/download_pipeline.yml | 22 ++- .github/workflows/fix-linting.yml | 6 +- .github/workflows/linting.yml | 18 +- .github/workflows/linting_comment.yml | 2 +- .github/workflows/release-announcements.yml | 6 +- .nf-core.yml | 1 + .pre-commit-config.yaml | 3 + README.md | 2 +- conf/base.config | 3 - conf/modules.config | 8 - conf/test.config | 2 +- conf/test_full.config | 2 +- docs/usage.md | 2 + modules.json | 4 +- modules/nf-core/fastqc/main.nf | 6 + nextflow.config | 176 +++++++++--------- nextflow_schema.json | 7 + pyproject.toml | 15 -- .../utils_nfcore_circrna_pipeline/main.nf | 16 +- .../nf-core/utils_nfcore_pipeline/main.nf | 8 +- workflows/circrna.nf | 46 +++-- 26 files changed, 220 insertions(+), 169 deletions(-) delete mode 100644 pyproject.toml diff --git a/.editorconfig b/.editorconfig index dd9ffa53..72dda289 100644 --- a/.editorconfig +++ b/.editorconfig @@ -28,10 +28,6 @@ indent_style = unset [/assets/email*] indent_size = unset -# ignore Readme -[README.md] -indent_style = unset - -# ignore python +# ignore python and markdown [*.{py,md}] indent_style = unset diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 364dd9b5..9d44ed38 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -18,7 +18,7 @@ Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/circ - [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/nf-core/circrna/tree/master/.github/CONTRIBUTING.md) - [ ] If necessary, also make a PR on the nf-core/circrna _branch_ on the [nf-core/test-datasets](https://github.com/nf-core/test-datasets) repository. - [ ] Make sure your code lints (`nf-core lint`). -- [ ] Ensure the test suite passes (`nf-test test main.nf.test -profile test,docker`). +- [ ] Ensure the test suite passes (`nextflow run . -profile test,docker --outdir `). - [ ] Check for unexpected warnings in debug mode (`nextflow run . -profile debug,test,docker --outdir `). - [ ] Usage Documentation in `docs/usage.md` is updated. - [ ] Output Documentation in `docs/output.md` is updated. diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 7b6bd16d..8f7ea0eb 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -8,12 +8,12 @@ on: types: [published] workflow_dispatch: jobs: - run-tower: + run-platform: name: Run AWS full tests if: github.repository == 'nf-core/circrna' runs-on: ubuntu-latest steps: - - name: Launch workflow via tower + - name: Launch workflow via Seqera Platform uses: seqeralabs/action-tower-launch@v2 # TODO nf-core: You can customise AWS full pipeline tests as required # Add full size test data (but still relatively small datasets for few samples) @@ -33,7 +33,7 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: Tower debug log file + name: Seqera Platform debug log file path: | - tower_action_*.log - tower_action_*.json + seqera_platform_action_*.log + seqera_platform_action_*.json diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index 9590dcae..cbea731e 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -5,13 +5,13 @@ name: nf-core AWS test on: workflow_dispatch: jobs: - run-tower: + run-platform: name: Run AWS tests if: github.repository == 'nf-core/circrna' runs-on: ubuntu-latest steps: - # Launch workflow using Tower CLI tool action - - name: Launch workflow via tower + # Launch workflow using Seqera Platform CLI tool action + - name: Launch workflow via Seqera Platform uses: seqeralabs/action-tower-launch@v2 with: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} @@ -27,7 +27,7 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: Tower debug log file + name: Seqera Platform debug log file path: | - tower_action_*.log - tower_action_*.json + seqera_platform_action_*.log + seqera_platform_action_*.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 916fd86a..8bfcd749 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,10 +28,10 @@ jobs: - "latest-everything" steps: - name: Check out pipeline code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 - name: Install Nextflow - uses: nf-core/setup-nextflow@v1 + uses: nf-core/setup-nextflow@v2 with: version: "${{ matrix.NXF_VER }}" diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml index 08622fd5..2d20d644 100644 --- a/.github/workflows/download_pipeline.yml +++ b/.github/workflows/download_pipeline.yml @@ -14,6 +14,8 @@ on: pull_request: types: - opened + - edited + - synchronize branches: - master pull_request_target: @@ -28,11 +30,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Nextflow - uses: nf-core/setup-nextflow@v1 + uses: nf-core/setup-nextflow@v2 - - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 + - name: Disk space cleanup + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 with: - python-version: "3.11" + python-version: "3.12" architecture: "x64" - uses: eWaterCycle/setup-singularity@931d4e31109e875b13309ae1d07c70ca8fbc8537 # v7 with: @@ -65,8 +70,17 @@ jobs: - name: Inspect download run: tree ./${{ env.REPOTITLE_LOWERCASE }} - - name: Run the downloaded pipeline + - name: Run the downloaded pipeline (stub) + id: stub_run_pipeline + continue-on-error: true env: NXF_SINGULARITY_CACHEDIR: ./ NXF_SINGULARITY_HOME_MOUNT: true run: nextflow run ./${{ env.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ env.REPO_BRANCH }}) -stub -profile test,singularity --outdir ./results + - name: Run the downloaded pipeline (stub run not supported) + id: run_pipeline + if: ${{ job.steps.stub_run_pipeline.status == failure() }} + env: + NXF_SINGULARITY_CACHEDIR: ./ + NXF_SINGULARITY_HOME_MOUNT: true + run: nextflow run ./${{ env.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ env.REPO_BRANCH }}) -profile test,singularity --outdir ./results diff --git a/.github/workflows/fix-linting.yml b/.github/workflows/fix-linting.yml index 505d843c..765c84e8 100644 --- a/.github/workflows/fix-linting.yml +++ b/.github/workflows/fix-linting.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: # Use the @nf-core-bot token to check out so we can push later - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 with: token: ${{ secrets.nf_core_bot_auth_token }} @@ -32,9 +32,9 @@ jobs: GITHUB_TOKEN: ${{ secrets.nf_core_bot_auth_token }} # Install and run pre-commit - - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 with: - python-version: 3.11 + python-version: "3.12" - name: Install pre-commit run: pip install pre-commit diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 073e1876..a3fb2541 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -14,12 +14,12 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 - - name: Set up Python 3.11 - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 + - name: Set up Python 3.12 + uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 with: - python-version: 3.11 + python-version: "3.12" cache: "pip" - name: Install pre-commit @@ -32,14 +32,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out pipeline code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 - name: Install Nextflow - uses: nf-core/setup-nextflow@v1 + uses: nf-core/setup-nextflow@v2 - - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 with: - python-version: "3.11" + python-version: "3.12" architecture: "x64" - name: Install dependencies @@ -60,7 +60,7 @@ jobs: - name: Upload linting log file artifact if: ${{ always() }} - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4 with: name: linting-logs path: | diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index b706875f..40acc23f 100644 --- a/.github/workflows/linting_comment.yml +++ b/.github/workflows/linting_comment.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download lint results - uses: dawidd6/action-download-artifact@f6b0bace624032e30a85a8fd9c1a7f8f611f5737 # v3 + uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3 with: workflow: linting.yml workflow_conclusion: completed diff --git a/.github/workflows/release-announcements.yml b/.github/workflows/release-announcements.yml index d468aeaa..03ecfcf7 100644 --- a/.github/workflows/release-announcements.yml +++ b/.github/workflows/release-announcements.yml @@ -12,7 +12,7 @@ jobs: - name: get topics and convert to hashtags id: get_topics run: | - curl -s https://nf-co.re/pipelines.json | jq -r '.remote_workflows[] | select(.full_name == "${{ github.repository }}") | .topics[]' | awk '{print "#"$0}' | tr '\n' ' ' >> $GITHUB_OUTPUT + echo "topics=$(curl -s https://nf-co.re/pipelines.json | jq -r '.remote_workflows[] | select(.full_name == "${{ github.repository }}") | .topics[]' | awk '{print "#"$0}' | tr '\n' ' ')" >> $GITHUB_OUTPUT - uses: rzr/fediverse-action@master with: @@ -25,13 +25,13 @@ jobs: Please see the changelog: ${{ github.event.release.html_url }} - ${{ steps.get_topics.outputs.GITHUB_OUTPUT }} #nfcore #openscience #nextflow #bioinformatics + ${{ steps.get_topics.outputs.topics }} #nfcore #openscience #nextflow #bioinformatics send-tweet: runs-on: ubuntu-latest steps: - - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 with: python-version: "3.10" - name: Install dependencies diff --git a/.nf-core.yml b/.nf-core.yml index 3805dc81..d6daa403 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -1 +1,2 @@ repository_type: pipeline +nf_core_version: "2.14.0" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index af57081f..4dc0f1dc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,6 +3,9 @@ repos: rev: "v3.1.0" hooks: - id: prettier + additional_dependencies: + - prettier@3.2.5 + - repo: https://github.com/editorconfig-checker/editorconfig-checker.python rev: "2.7.3" hooks: diff --git a/README.md b/README.md index ab055f20..558557f1 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ [![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) [![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) [![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) -[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://tower.nf/launch?pipeline=https://github.com/nf-core/circrna) +[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-core/circrna) [![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23circrna-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/circrna)[![Follow on Twitter](http://img.shields.io/badge/twitter-%40nf__core-1DA1F2?labelColor=000000&logo=twitter)](https://twitter.com/nf_core)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core) diff --git a/conf/base.config b/conf/base.config index 307e9381..cdf46e83 100644 --- a/conf/base.config +++ b/conf/base.config @@ -59,7 +59,4 @@ process { errorStrategy = 'retry' maxRetries = 2 } - withName:CUSTOM_DUMPSOFTWAREVERSIONS { - cache = false - } } diff --git a/conf/modules.config b/conf/modules.config index e3ea8fa6..d203d2b6 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -22,14 +22,6 @@ process { ext.args = '--quiet' } - withName: CUSTOM_DUMPSOFTWAREVERSIONS { - publishDir = [ - path: { "${params.outdir}/pipeline_info" }, - mode: params.publish_dir_mode, - pattern: '*_versions.yml' - ] - } - withName: 'MULTIQC' { ext.args = { params.multiqc_title ? "--title \"$params.multiqc_title\"" : '' } publishDir = [ diff --git a/conf/test.config b/conf/test.config index e1f2acda..a7c2516f 100644 --- a/conf/test.config +++ b/conf/test.config @@ -22,7 +22,7 @@ params { // Input data // TODO nf-core: Specify the paths to your test data on nf-core/test-datasets // TODO nf-core: Give any required params for the test so that command line flags are not needed - input = 'https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv' + input = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv' // Genome references genome = 'R64-1-1' diff --git a/conf/test_full.config b/conf/test_full.config index a3b229ad..448193d7 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -17,7 +17,7 @@ params { // Input data for full size test // TODO nf-core: Specify the paths to your full test data ( on nf-core/test-datasets or directly in repositories, e.g. SRA) // TODO nf-core: Give any required params for the test so that command line flags are not needed - input = 'https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_full_illumina_amplicon.csv' + input = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_full_illumina_amplicon.csv' // Genome references genome = 'R64-1-1' diff --git a/docs/usage.md b/docs/usage.md index 8960ea47..98e72a06 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -156,6 +156,8 @@ If `-profile` is not specified, the pipeline will run locally and expect all sof - A generic configuration profile to be used with [Charliecloud](https://hpc.github.io/charliecloud/) - `apptainer` - A generic configuration profile to be used with [Apptainer](https://apptainer.org/) +- `wave` + - A generic configuration profile to enable [Wave](https://seqera.io/wave/) containers. Use together with one of the above (requires Nextflow ` 24.03.0-edge` or later). - `conda` - A generic configuration profile to be used with [Conda](https://conda.io/docs/). Please only use Conda as a last resort i.e. when it's not possible to run the pipeline with Docker, Singularity, Podman, Shifter, Charliecloud, or Apptainer. diff --git a/modules.json b/modules.json index c0226feb..3b1e37ee 100644 --- a/modules.json +++ b/modules.json @@ -7,7 +7,7 @@ "nf-core": { "fastqc": { "branch": "master", - "git_sha": "f4ae1d942bd50c5c0b9bd2de1393ce38315ba57c", + "git_sha": "285a50500f9e02578d90b3ce6382ea3c30216acd", "installed_by": ["modules"] }, "multiqc": { @@ -26,7 +26,7 @@ }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "5caf7640a9ef1d18d765d55339be751bb0969dfa", + "git_sha": "92de218a329bfc9a9033116eb5f65fd270e72ba3", "installed_by": ["subworkflows"] }, "utils_nfvalidation_plugin": { diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf index 9e19a74c..d79f1c86 100644 --- a/modules/nf-core/fastqc/main.nf +++ b/modules/nf-core/fastqc/main.nf @@ -25,6 +25,11 @@ process FASTQC { def old_new_pairs = reads instanceof Path || reads.size() == 1 ? [[ reads, "${prefix}.${reads.extension}" ]] : reads.withIndex().collect { entry, index -> [ entry, "${prefix}_${index + 1}.${entry.extension}" ] } def rename_to = old_new_pairs*.join(' ').join(' ') def renamed_files = old_new_pairs.collect{ old_name, new_name -> new_name }.join(' ') + + def memory_in_mb = MemoryUnit.of("${task.memory}").toUnit('MB') + // FastQC memory value allowed range (100 - 10000) + def fastqc_memory = memory_in_mb > 10000 ? 10000 : (memory_in_mb < 100 ? 100 : memory_in_mb) + """ printf "%s %s\\n" $rename_to | while read old_name new_name; do [ -f "\${new_name}" ] || ln -s \$old_name \$new_name @@ -33,6 +38,7 @@ process FASTQC { fastqc \\ $args \\ --threads $task.cpus \\ + --memory $fastqc_memory \\ $renamed_files cat <<-END_VERSIONS > versions.yml diff --git a/nextflow.config b/nextflow.config index 564acf64..13ad97ff 100644 --- a/nextflow.config +++ b/nextflow.config @@ -16,7 +16,8 @@ params { genome = null igenomes_base = 's3://ngi-igenomes/igenomes/' igenomes_ignore = false - fasta = null// MultiQC options + + // MultiQC options multiqc_config = null multiqc_title = null multiqc_logo = null @@ -24,15 +25,16 @@ params { multiqc_methods_description = null // Boilerplate options - outdir = null - publish_dir_mode = 'copy' - email = null - email_on_fail = null - plaintext_email = false - monochrome_logs = false - hook_url = null - help = false - version = false + outdir = null + publish_dir_mode = 'copy' + email = null + email_on_fail = null + plaintext_email = false + monochrome_logs = false + hook_url = null + help = false + version = false + pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' // Config options config_profile_name = null @@ -68,103 +70,109 @@ try { } // Load nf-core/circrna custom profiles from different institutions. -// Warning: Uncomment only if a pipeline-specific institutional config already exists on nf-core/configs! -// try { -// includeConfig "${params.custom_config_base}/pipeline/circrna.config" -// } catch (Exception e) { -// System.err.println("WARNING: Could not load nf-core/config/circrna profiles: ${params.custom_config_base}/pipeline/circrna.config") -// } +try { + includeConfig "${params.custom_config_base}/pipeline/circrna.config" +} catch (Exception e) { + System.err.println("WARNING: Could not load nf-core/config/circrna profiles: ${params.custom_config_base}/pipeline/circrna.config") +} profiles { debug { - dumpHashes = true - process.beforeScript = 'echo $HOSTNAME' - cleanup = false + dumpHashes = true + process.beforeScript = 'echo $HOSTNAME' + cleanup = false nextflow.enable.configProcessNamesValidation = true } conda { - conda.enabled = true - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - channels = ['conda-forge', 'bioconda', 'defaults'] - apptainer.enabled = false + conda.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + conda.channels = ['conda-forge', 'bioconda', 'defaults'] + apptainer.enabled = false } mamba { - conda.enabled = true - conda.useMamba = true - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + conda.enabled = true + conda.useMamba = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } docker { - docker.enabled = true - conda.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false - docker.runOptions = '-u $(id -u):$(id -g)' + docker.enabled = true + conda.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false + docker.runOptions = '-u $(id -u):$(id -g)' } arm { - docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' + docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' } singularity { - singularity.enabled = true - singularity.autoMounts = true - conda.enabled = false - docker.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + singularity.enabled = true + singularity.autoMounts = true + conda.enabled = false + docker.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } podman { - podman.enabled = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + podman.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } shifter { - shifter.enabled = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - podman.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + shifter.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } charliecloud { - charliecloud.enabled = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - apptainer.enabled = false + charliecloud.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + apptainer.enabled = false } apptainer { - apptainer.enabled = true - apptainer.autoMounts = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false + apptainer.enabled = true + apptainer.autoMounts = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + wave { + apptainer.ociAutoPull = true + singularity.ociAutoPull = true + wave.enabled = true + wave.freeze = true + wave.strategy = 'conda,container' } gitpod { - executor.name = 'local' - executor.cpus = 4 - executor.memory = 8.GB + executor.name = 'local' + executor.cpus = 4 + executor.memory = 8.GB } test { includeConfig 'conf/test.config' } test_full { includeConfig 'conf/test_full.config' } diff --git a/nextflow_schema.json b/nextflow_schema.json index 01ffcd21..82858e99 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -265,6 +265,13 @@ "description": "Validation of parameters in lenient more.", "hidden": true, "help_text": "Allows string values that are parseable as numbers or booleans. For further information see [JSONSchema docs](https://github.com/everit-org/json-schema#lenient-mode)." + }, + "pipelines_testdata_base_path": { + "type": "string", + "fa_icon": "far fa-check-circle", + "description": "Base URL or local path to location of pipeline test dataset files", + "default": "https://raw.githubusercontent.com/nf-core/test-datasets/", + "hidden": true } } } diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 56110621..00000000 --- a/pyproject.toml +++ /dev/null @@ -1,15 +0,0 @@ -# Config file for Python. Mostly used to configure linting of bin/*.py with Ruff. -# Should be kept the same as nf-core/tools to avoid fighting with template synchronisation. -[tool.ruff] -line-length = 120 -target-version = "py38" -cache-dir = "~/.cache/ruff" - -[tool.ruff.lint] -select = ["I", "E1", "E4", "E7", "E9", "F", "UP", "N"] - -[tool.ruff.lint.isort] -known-first-party = ["nf_core"] - -[tool.ruff.lint.per-file-ignores] -"__init__.py" = ["E402", "F401"] diff --git a/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf b/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf index 69918616..5ee14910 100644 --- a/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf @@ -140,6 +140,10 @@ workflow PIPELINE_COMPLETION { imNotification(summary_params, hook_url) } } + + workflow.onError { + log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting" + } } /* @@ -230,8 +234,16 @@ def methodsDescriptionText(mqc_methods_yaml) { meta["manifest_map"] = workflow.manifest.toMap() // Pipeline DOI - meta["doi_text"] = meta.manifest_map.doi ? "(doi: ${meta.manifest_map.doi})" : "" - meta["nodoi_text"] = meta.manifest_map.doi ? "": "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " + if (meta.manifest_map.doi) { + // Using a loop to handle multiple DOIs + // Removing `https://doi.org/` to handle pipelines using DOIs vs DOI resolvers + // Removing ` ` since the manifest.doi is a string and not a proper list + def temp_doi_ref = "" + String[] manifest_doi = meta.manifest_map.doi.tokenize(",") + for (String doi_ref: manifest_doi) temp_doi_ref += "(doi: ${doi_ref.replace("https://doi.org/", "").replace(" ", "")}), " + meta["doi_text"] = temp_doi_ref.substring(0, temp_doi_ref.length() - 2) + } else meta["doi_text"] = "" + meta["nodoi_text"] = meta.manifest_map.doi ? "" : "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " // Tool references meta["tool_citations"] = "" diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index a8b55d6f..14558c39 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -65,9 +65,15 @@ def checkProfileProvided(nextflow_cli_args) { // Citation string for pipeline // def workflowCitation() { + def temp_doi_ref = "" + String[] manifest_doi = workflow.manifest.doi.tokenize(",") + // Using a loop to handle multiple DOIs + // Removing `https://doi.org/` to handle pipelines using DOIs vs DOI resolvers + // Removing ` ` since the manifest.doi is a string and not a proper list + for (String doi_ref: manifest_doi) temp_doi_ref += " https://doi.org/${doi_ref.replace('https://doi.org/', '').replace(' ', '')}\n" return "If you use ${workflow.manifest.name} for your analysis please cite:\n\n" + "* The pipeline\n" + - " ${workflow.manifest.doi}\n\n" + + temp_doi_ref + "\n" + "* The nf-core framework\n" + " https://doi.org/10.1038/s41587-020-0439-x\n\n" + "* Software dependencies\n" + diff --git a/workflows/circrna.nf b/workflows/circrna.nf index 5e577f9b..da558a8e 100644 --- a/workflows/circrna.nf +++ b/workflows/circrna.nf @@ -40,22 +40,44 @@ workflow CIRCRNA { // Collate and save software versions // softwareVersionsToYAML(ch_versions) - .collectFile(storeDir: "${params.outdir}/pipeline_info", name: 'nf_core_pipeline_software_mqc_versions.yml', sort: true, newLine: true) - .set { ch_collated_versions } + .collectFile( + storeDir: "${params.outdir}/pipeline_info", + name: 'nf_core_pipeline_software_mqc_versions.yml', + sort: true, + newLine: true + ).set { ch_collated_versions } // // MODULE: MultiQC // - ch_multiqc_config = Channel.fromPath("$projectDir/assets/multiqc_config.yml", checkIfExists: true) - ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath(params.multiqc_config, checkIfExists: true) : Channel.empty() - ch_multiqc_logo = params.multiqc_logo ? Channel.fromPath(params.multiqc_logo, checkIfExists: true) : Channel.empty() - summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") - ch_workflow_summary = Channel.value(paramsSummaryMultiqc(summary_params)) - ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("$projectDir/assets/methods_description_template.yml", checkIfExists: true) - ch_methods_description = Channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) - ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) - ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) - ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: false)) + ch_multiqc_config = Channel.fromPath( + "$projectDir/assets/multiqc_config.yml", checkIfExists: true) + ch_multiqc_custom_config = params.multiqc_config ? + Channel.fromPath(params.multiqc_config, checkIfExists: true) : + Channel.empty() + ch_multiqc_logo = params.multiqc_logo ? + Channel.fromPath(params.multiqc_logo, checkIfExists: true) : + Channel.empty() + + summary_params = paramsSummaryMap( + workflow, parameters_schema: "nextflow_schema.json") + ch_workflow_summary = Channel.value(paramsSummaryMultiqc(summary_params)) + + ch_multiqc_custom_methods_description = params.multiqc_methods_description ? + file(params.multiqc_methods_description, checkIfExists: true) : + file("$projectDir/assets/methods_description_template.yml", checkIfExists: true) + ch_methods_description = Channel.value( + methodsDescriptionText(ch_multiqc_custom_methods_description)) + + ch_multiqc_files = ch_multiqc_files.mix( + ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) + ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) + ch_multiqc_files = ch_multiqc_files.mix( + ch_methods_description.collectFile( + name: 'methods_description_mqc.yaml', + sort: true + ) + ) MULTIQC ( ch_multiqc_files.collect(), From 80712a4951f6bc40a2e3de182d651ffc52d67f1d Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Thu, 9 May 2024 11:39:08 +0000 Subject: [PATCH 214/491] Template update for nf-core/tools version 2.14.1 --- .github/workflows/linting.yml | 1 - .nf-core.yml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index a3fb2541..1fcafe88 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -20,7 +20,6 @@ jobs: uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 with: python-version: "3.12" - cache: "pip" - name: Install pre-commit run: pip install pre-commit diff --git a/.nf-core.yml b/.nf-core.yml index d6daa403..e0b85a77 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -1,2 +1,2 @@ repository_type: pipeline -nf_core_version: "2.14.0" +nf_core_version: "2.14.1" From 3f8d5d8eb3194667aa33b70005f42f2dfd06766e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 9 May 2024 21:09:45 +0200 Subject: [PATCH 215/491] Remove unnecessary module configs --- conf/modules.config | 85 --------------------------------------------- 1 file changed, 85 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 2e0a6320..1d82c383 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -18,14 +18,6 @@ process { saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] - withName: SAMPLESHEET_CHECK { - publishDir = [ - path: { "${params.outdir}/pipeline_info" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - withName: CUSTOM_DUMPSOFTWAREVERSIONS { publishDir = [ path: { "${params.outdir}/pipeline_info" }, @@ -357,16 +349,6 @@ if (!params.skip_trimming) { ] } - withName: CIRIQUANT_YML { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('ciriquant') } - publishDir = [ - path: { "${params.outdir}/references/ciriquant" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_reference - ] - } - withName: CIRIQUANT { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('ciriquant') } publishDir = [ @@ -388,59 +370,6 @@ if (!params.skip_trimming) { ] } - withName: DCC_1ST_PASS { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } - ext.args = [ "", - "--chimOutType Junctions WithinBAM", - "--outSAMunmapped Within", - "--outFilterType BySJout", - "--outReadsUnmapped None", - "--readFilesCommand zcat", - "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", - "--limitSjdbInsertNsj ${params.limitSjdbInsertNsj}", - "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", - "--chimSegmentMin ${params.chimSegmentMin}" - ].join(' ').trim() - publishDir = [ - path: { "${params.outdir}/circrna_discovery/dcc/intermediates/align/1st_pass" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates - ] - } - - withName: DCC_SJDB { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } - publishDir = [ - path: { "${params.outdir}/circrna_discovery/dcc/intermediates/align/sjdb" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates - ] - } - - withName: DCC_2ND_PASS { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } - ext.args = [ "", - "--chimOutType Junctions WithinBAM", - "--outSAMunmapped Within", - "--outFilterType BySJout", - "--outReadsUnmapped None", - "--readFilesCommand zcat", - "--sjdbFileChrStartEnd dataset.SJ.out.tab", - "--alignSJDBoverhangMin ${params.alignSJDBoverhangMin}", - "--limitSjdbInsertNsj ${params.limitSjdbInsertNsj}", - "--chimJunctionOverhangMin ${params.chimJunctionOverhangMin}", - "--chimSegmentMin ${params.chimSegmentMin}" - ].join(' ').trim() - publishDir = [ - path: { "${params.outdir}/circrna_discovery/dcc/intermediates/align/2nd_pass" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates - ] - } - withName: DCC_MATE1_1ST_PASS { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } ext.prefix = { "${meta.id}_mate1" } @@ -667,25 +596,11 @@ if (!params.skip_trimming) { ext.when = { params.module.split(',').contains('circrna_discovery') } } - withName: COUNTS_TO_BED { - ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3, \".\", \".\" }'" - ext.suffix = "bed" - } - - withName: UNIQUE_REGIONS { - ext.args = "-k 1,1 -k2,2n -k3,3n -u" - ext.suffix = "unique.bed" - } - withName: COMBINE_TRANSCRIPTOME_GTFS { ext.args = "-k 1,1 -k3,3n -k4,4n" ext.suffix = "gtf" } - withName: CIRCULAR_TRANSCRIPTOME { - ext.args = "-nameOnly" - } - withName: MARK_CIRCULAR { // GAWK process that marks FASTA headers. // Leaves headers starting with "ENS" and non-header lines as is. From 70b3a5f96fb08e89b1904ff2221c8f651360b517 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 9 May 2024 21:10:50 +0200 Subject: [PATCH 216/491] Update modules --- modules.json | 4 +- modules/nf-core/bedtools/getfasta/main.nf | 23 ++++-- modules/nf-core/bedtools/getfasta/meta.yml | 12 +++- .../bedtools/getfasta/tests/main.nf.test | 62 ++++++++++++++++ .../bedtools/getfasta/tests/main.nf.test.snap | 72 +++++++++++++++++++ .../nf-core/bedtools/getfasta/tests/tags.yml | 2 + modules/nf-core/gawk/environment.yml | 7 ++ modules/nf-core/gawk/main.nf | 5 +- modules/nf-core/gawk/tests/main.nf.test | 56 +++++++++++++++ modules/nf-core/gawk/tests/main.nf.test.snap | 68 ++++++++++++++++++ modules/nf-core/gawk/tests/nextflow.config | 6 ++ .../tests/nextflow_with_program_file.config | 5 ++ modules/nf-core/gawk/tests/tags.yml | 2 + 13 files changed, 314 insertions(+), 10 deletions(-) create mode 100644 modules/nf-core/bedtools/getfasta/tests/main.nf.test create mode 100644 modules/nf-core/bedtools/getfasta/tests/main.nf.test.snap create mode 100644 modules/nf-core/bedtools/getfasta/tests/tags.yml create mode 100644 modules/nf-core/gawk/environment.yml create mode 100644 modules/nf-core/gawk/tests/main.nf.test create mode 100644 modules/nf-core/gawk/tests/main.nf.test.snap create mode 100644 modules/nf-core/gawk/tests/nextflow.config create mode 100644 modules/nf-core/gawk/tests/nextflow_with_program_file.config create mode 100644 modules/nf-core/gawk/tests/tags.yml diff --git a/modules.json b/modules.json index ef0f06e4..acc410f5 100644 --- a/modules.json +++ b/modules.json @@ -7,7 +7,7 @@ "nf-core": { "bedtools/getfasta": { "branch": "master", - "git_sha": "3b248b84694d1939ac4bb33df84bf6233a34d668", + "git_sha": "cdcdd5e3d806f0ff3983c40c69e0b07bb44ec299", "installed_by": ["modules"] }, "bedtools/intersect": { @@ -92,7 +92,7 @@ }, "gawk": { "branch": "master", - "git_sha": "dc3527855e7358c6d8400828754c0caa5f11698f", + "git_sha": "b42fec6f7c6e5d0716685cabb825ef6bf6e386b5", "installed_by": ["modules"] }, "gnu/sort": { diff --git a/modules/nf-core/bedtools/getfasta/main.nf b/modules/nf-core/bedtools/getfasta/main.nf index 50549c7d..b316117d 100644 --- a/modules/nf-core/bedtools/getfasta/main.nf +++ b/modules/nf-core/bedtools/getfasta/main.nf @@ -1,5 +1,5 @@ process BEDTOOLS_GETFASTA { - tag "$bed" + tag "$meta.id" label 'process_single' conda "${moduleDir}/environment.yml" @@ -8,19 +8,20 @@ process BEDTOOLS_GETFASTA { 'biocontainers/bedtools:2.31.1--hf5e1c6e_0' }" input: - path bed + tuple val(meta), path(bed) path fasta output: - path "*.fa" , emit: fasta - path "versions.yml" , emit: versions + tuple val(meta), path("*.fa"), emit: fasta + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when script: def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${bed.baseName}" + def prefix = task.ext.prefix ?: "${meta.id}" + if ("$fasta" == "${prefix}.fa") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" """ bedtools \\ getfasta \\ @@ -34,4 +35,16 @@ process BEDTOOLS_GETFASTA { bedtools: \$(bedtools --version | sed -e "s/bedtools v//g") END_VERSIONS """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + if ("$fasta" == "${prefix}.fa") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" + """ + touch ${prefix}.fa + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + bedtools: \$(bedtools --version | sed -e "s/bedtools v//g") + END_VERSIONS + """ } diff --git a/modules/nf-core/bedtools/getfasta/meta.yml b/modules/nf-core/bedtools/getfasta/meta.yml index 25fb19a1..41917fe3 100644 --- a/modules/nf-core/bedtools/getfasta/meta.yml +++ b/modules/nf-core/bedtools/getfasta/meta.yml @@ -8,9 +8,14 @@ tools: - bedtools: description: | A set of tools for genomic analysis tasks, specifically enabling genome arithmetic (merge, count, complement) on various file types. - documentation: https://bedtools.readthedocs.io/en/latest/content/tools/intersect.html + documentation: https://bedtools.readthedocs.io/en/latest/content/tools/getfasta.html licence: ["MIT"] input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] - bed: type: file description: Bed feature file @@ -20,6 +25,11 @@ input: description: Input fasta file pattern: "*.{fa,fasta}" output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] - fasta: type: file description: Output fasta file with extracted sequences diff --git a/modules/nf-core/bedtools/getfasta/tests/main.nf.test b/modules/nf-core/bedtools/getfasta/tests/main.nf.test new file mode 100644 index 00000000..4da7552c --- /dev/null +++ b/modules/nf-core/bedtools/getfasta/tests/main.nf.test @@ -0,0 +1,62 @@ +nextflow_process { + + name "Test Process BEDTOOLS_GETFASTA" + script "../main.nf" + process "BEDTOOLS_GETFASTA" + + tag "modules" + tag "modules_nfcore" + tag "bedtools" + tag "bedtools/getfasta" + + test("sarscov2 - bed - fasta") { + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false], + file(params.test_data['sarscov2']['genome']['test_bed'], checkIfExists: true), + ] + + input[1] = file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("sarscov2 - bed - fasta - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false], + file(params.test_data['sarscov2']['genome']['test_bed'], checkIfExists: true), + ] + + input[1] = file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/nf-core/bedtools/getfasta/tests/main.nf.test.snap b/modules/nf-core/bedtools/getfasta/tests/main.nf.test.snap new file mode 100644 index 00000000..69bf33f7 --- /dev/null +++ b/modules/nf-core/bedtools/getfasta/tests/main.nf.test.snap @@ -0,0 +1,72 @@ +{ + "sarscov2 - bed - fasta": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fa:md5,41c3a45a57a16c04f828d8f8bb52df70" + ] + ], + "1": [ + "versions.yml:md5,427b4f64b2f05f28f0beef96c9f0d310" + ], + "fasta": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fa:md5,41c3a45a57a16c04f828d8f8bb52df70" + ] + ], + "versions": [ + "versions.yml:md5,427b4f64b2f05f28f0beef96c9f0d310" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-05-03T14:16:19.383758985" + }, + "sarscov2 - bed - fasta - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fa:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,427b4f64b2f05f28f0beef96c9f0d310" + ], + "fasta": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fa:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,427b4f64b2f05f28f0beef96c9f0d310" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-05-03T14:16:47.47010536" + } +} \ No newline at end of file diff --git a/modules/nf-core/bedtools/getfasta/tests/tags.yml b/modules/nf-core/bedtools/getfasta/tests/tags.yml new file mode 100644 index 00000000..42ec3026 --- /dev/null +++ b/modules/nf-core/bedtools/getfasta/tests/tags.yml @@ -0,0 +1,2 @@ +bedtools/getfasta: + - "modules/nf-core/bedtools/getfasta/**" diff --git a/modules/nf-core/gawk/environment.yml b/modules/nf-core/gawk/environment.yml new file mode 100644 index 00000000..34513c7f --- /dev/null +++ b/modules/nf-core/gawk/environment.yml @@ -0,0 +1,7 @@ +name: gawk +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - anaconda::gawk=5.1.0 diff --git a/modules/nf-core/gawk/main.nf b/modules/nf-core/gawk/main.nf index f856a1f8..578b448c 100644 --- a/modules/nf-core/gawk/main.nf +++ b/modules/nf-core/gawk/main.nf @@ -41,10 +41,11 @@ process GAWK { stub: prefix = task.ext.prefix ?: "${meta.id}" - suffix = task.ext.suffix ?: "${input.getExtension}" + suffix = task.ext.suffix ?: "${input.getExtension()}" + def create_cmd = suffix.endsWith("gz") ? "echo '' | gzip >" : "touch" """ - touch ${prefix}.${suffix} + ${create_cmd} ${prefix}.${suffix} cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/gawk/tests/main.nf.test b/modules/nf-core/gawk/tests/main.nf.test new file mode 100644 index 00000000..fce82ca9 --- /dev/null +++ b/modules/nf-core/gawk/tests/main.nf.test @@ -0,0 +1,56 @@ +nextflow_process { + + name "Test Process GAWK" + script "../main.nf" + process "GAWK" + + tag "modules" + tag "modules_nfcore" + tag "gawk" + + test("convert fasta to bed") { + config "./nextflow.config" + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) + ] + input[1] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("convert fasta to bed with program file") { + config "./nextflow_with_program_file.config" + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) + ] + input[1] = Channel.of('BEGIN {FS="\t"}; {print \$1 FS "0" FS \$2}').collectFile(name:"program.txt") + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } +} \ No newline at end of file diff --git a/modules/nf-core/gawk/tests/main.nf.test.snap b/modules/nf-core/gawk/tests/main.nf.test.snap new file mode 100644 index 00000000..ce207478 --- /dev/null +++ b/modules/nf-core/gawk/tests/main.nf.test.snap @@ -0,0 +1,68 @@ +{ + "convert fasta to bed with program file": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.bed:md5,87a15eb9c2ff20ccd5cd8735a28708f7" + ] + ], + "1": [ + "versions.yml:md5,4c320d8c98ca80690afd7651da1ba520" + ], + "output": [ + [ + { + "id": "test" + }, + "test.bed:md5,87a15eb9c2ff20ccd5cd8735a28708f7" + ] + ], + "versions": [ + "versions.yml:md5,4c320d8c98ca80690afd7651da1ba520" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.02.0" + }, + "timestamp": "2024-04-05T11:00:28.097563" + }, + "convert fasta to bed": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.bed:md5,87a15eb9c2ff20ccd5cd8735a28708f7" + ] + ], + "1": [ + "versions.yml:md5,4c320d8c98ca80690afd7651da1ba520" + ], + "output": [ + [ + { + "id": "test" + }, + "test.bed:md5,87a15eb9c2ff20ccd5cd8735a28708f7" + ] + ], + "versions": [ + "versions.yml:md5,4c320d8c98ca80690afd7651da1ba520" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.02.0" + }, + "timestamp": "2024-04-05T10:28:15.625869" + } +} \ No newline at end of file diff --git a/modules/nf-core/gawk/tests/nextflow.config b/modules/nf-core/gawk/tests/nextflow.config new file mode 100644 index 00000000..6e5d43a3 --- /dev/null +++ b/modules/nf-core/gawk/tests/nextflow.config @@ -0,0 +1,6 @@ +process { + withName: GAWK { + ext.suffix = "bed" + ext.args2 = '\'BEGIN {FS="\t"}; {print \$1 FS "0" FS \$2}\'' + } +} diff --git a/modules/nf-core/gawk/tests/nextflow_with_program_file.config b/modules/nf-core/gawk/tests/nextflow_with_program_file.config new file mode 100644 index 00000000..693ad419 --- /dev/null +++ b/modules/nf-core/gawk/tests/nextflow_with_program_file.config @@ -0,0 +1,5 @@ +process { + withName: GAWK { + ext.suffix = "bed" + } +} diff --git a/modules/nf-core/gawk/tests/tags.yml b/modules/nf-core/gawk/tests/tags.yml new file mode 100644 index 00000000..72e4531d --- /dev/null +++ b/modules/nf-core/gawk/tests/tags.yml @@ -0,0 +1,2 @@ +gawk: + - "modules/nf-core/gawk/**" From 6dde17b13924604e1e6d4b2bdd1cbd71e2f46533 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 9 May 2024 21:11:43 +0200 Subject: [PATCH 217/491] Add samtools faidx version capture --- subworkflows/local/prepare_genome.nf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 6c2c0b4b..9d382295 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -53,7 +53,8 @@ workflow PREPARE_GENOME { HISAT2_EXTRACTSPLICESITES.out.versions, HISAT2_BUILD.out.versions, SEGEMEHL_INDEX.out.versions, - STAR_GENOMEGENERATE.out.versions) + STAR_GENOMEGENERATE.out.versions, + SAMTOOLS_FAIDX.out.versions) emit: faidx = SAMTOOLS_FAIDX.out.fai From eeb35ed90332747606bc111097a8db40d13f556d Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 9 May 2024 21:35:21 +0200 Subject: [PATCH 218/491] Remove unnecessary nextflow schema entry --- nextflow_schema.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index 558c619c..2aaea8bb 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -544,13 +544,6 @@ "description": "Validation of parameters in lenient more.", "hidden": true, "help_text": "Allows string values that are parseable as numbers or booleans. For further information see [JSONSchema docs](https://github.com/everit-org/json-schema#lenient-mode)." - }, - "pipelines_testdata_base_path": { - "type": "string", - "fa_icon": "far fa-check-circle", - "description": "Base URL or local path to location of pipeline test dataset files", - "default": "https://raw.githubusercontent.com/nf-core/test-datasets/", - "hidden": true } } } From b3256a6965f97368a0217ad759fb6e3b8cd8a51c Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 29 Apr 2024 17:38:53 +0200 Subject: [PATCH 219/491] Implement process for removing overlong transcripts --- conf/modules.config | 5 +++++ subworkflows/local/quantification.nf | 10 ++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 1d82c383..cfb38ae1 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -601,6 +601,11 @@ if (!params.skip_trimming) { ext.suffix = "gtf" } + withName: EXCLUDE_OVERLONG_TRANSCRIPTS { + ext.args = "-v FS='\\t' -v OFS='\\t' '\$5-\$4 <= 10000 { print }'" + ext.suffix = "filtered.gtf" + } + withName: MARK_CIRCULAR { // GAWK process that marks FASTA headers. // Leaves headers starting with "ENS" and non-header lines as is. diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index 86cee630..b1c0d576 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -1,4 +1,5 @@ include { GNU_SORT as COMBINE_TRANSCRIPTOME_GTFS } from '../../modules/nf-core/gnu/sort' +include { GAWK as EXCLUDE_OVERLONG_TRANSCRIPTS } from '../../modules/nf-core/gawk' include { TRANSCRIPTOME } from '../../modules/local/quantification/transcriptome' include { GAWK as MARK_CIRCULAR } from '../../modules/nf-core/gawk' include { PSIRC_INDEX } from '../../modules/local/psirc/index' @@ -33,13 +34,18 @@ workflow QUANTIFICATION { ch_gtf.mix(circ_annotation_gtf).map{meta, gtf -> gtf}.collect().map{[[id: "transcriptome"], it]}, ) - TRANSCRIPTOME(COMBINE_TRANSCRIPTOME_GTFS.out.sorted, ch_fasta) + EXCLUDE_OVERLONG_TRANSCRIPTS( + COMBINE_TRANSCRIPTOME_GTFS.out.sorted, [] + ) + + TRANSCRIPTOME(EXCLUDE_OVERLONG_TRANSCRIPTS.out.output, ch_fasta) MARK_CIRCULAR(TRANSCRIPTOME.out.transcriptome, []) ch_versions = ch_versions.mix( COMBINE_TRANSCRIPTOME_GTFS.out.versions, TRANSCRIPTOME.out.versions, - MARK_CIRCULAR.out.versions + MARK_CIRCULAR.out.versions, + EXCLUDE_OVERLONG_TRANSCRIPTS.out.versions ) PSIRC_INDEX(MARK_CIRCULAR.out.output) From 1eea22c3ad3500be4e5f2a76c5b7b3e50708dcfb Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Wed, 1 May 2024 22:48:45 +0200 Subject: [PATCH 220/491] Use only merged circRNAs in further analyses --- bin/counts_combined.py | 12 ++-- bin/merge_tools.py | 5 ++ .../local/annotation/full_annotation/main.nf | 2 +- subworkflows/local/circrna_discovery.nf | 62 ++++++++++--------- 4 files changed, 42 insertions(+), 39 deletions(-) diff --git a/bin/counts_combined.py b/bin/counts_combined.py index 99a9304e..5c326451 100755 --- a/bin/counts_combined.py +++ b/bin/counts_combined.py @@ -11,21 +11,17 @@ args = parser.parse_args() -columns = ['chr', 'start', 'end', 'strand', 'count', 'tools'] +columns = ['chr', 'start', 'end', 'name', 'count', 'strand'] dfs = {os.path.basename(bed).split('.')[0]: pd.read_csv(bed, sep='\t', header=None, - names=columns, - index_col=[0, 1, 2, 3]) - .drop('tools', axis=1) for bed in args.beds} + names=columns) for bed in args.beds} dfs = [df.rename(columns={'count': sample}) for sample, df in dfs.items()] - df = pd.concat(dfs, axis=1) -df = df.fillna(0).astype(int) - df.to_csv(args.out_bed, sep='\t') -df.index = df.index.map(lambda x: f'{x[0]}:{x[1]}-{x[2]}:{x[3]}') +df.index = df['name'] df.index.name = 'ID' +df.drop('name', axis=1, inplace=True) df.to_csv(args.out_tsv, sep='\t') diff --git a/bin/merge_tools.py b/bin/merge_tools.py index fe81353d..32bacab1 100755 --- a/bin/merge_tools.py +++ b/bin/merge_tools.py @@ -21,4 +21,9 @@ 'tool_count': 'sum'}).reset_index() df = df[df['tool_count'] >= args.tool_filter] +df.drop('tool_count', axis=1, inplace=True) +df["name"] = df["chr"] + ":" + df["start"].astype(str) + "-" + df["end"].astype(str) + ":" + df["strand"] + +df = df[['chr', 'start', 'end', 'name', 'count', 'strand']] + df.to_csv(args.output, sep='\t', index=False, header=False) diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/full_annotation/main.nf index 43030ca4..207cd463 100644 --- a/modules/local/annotation/full_annotation/main.nf +++ b/modules/local/annotation/full_annotation/main.nf @@ -1,5 +1,5 @@ process ANNOTATION { - tag "$meta.id" + tag "$meta.id:$meta.tool" label 'process_single' conda "bioconda::pandas=1.5.2" diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 8ac26e69..7eb06ef7 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -201,6 +201,26 @@ workflow CIRCRNA_DISCOVERY { ch_versions = ch_versions.mix(MAPSPLICE_ANNOTATE.out.versions) ch_versions = ch_versions.mix(MAPSPLICE_FILTER.out.versions) + // + // COUNT MATRIX WORKFLOW: + // + + ch_matrix = CIRCEXPLORER2_FLT.out.matrix.mix(SEGEMEHL_FILTER.out.matrix, + CIRCRNA_FINDER_FILTER.out.matrix, + FIND_CIRC_FILTER.out.matrix, + CIRIQUANT_FILTER.out.matrix, + DCC_FILTER.out.matrix, + MAPSPLICE_FILTER.out.matrix) + + tools_selected = params.tool.split(',').collect{it.trim().toLowerCase()} + + MERGE_TOOLS( ch_matrix.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), + tools_selected.size() > 1 ? tool_filter : 1, duplicates_fun ) + COUNTS_COMBINED( MERGE_TOOLS.out.merged.map{ meta, bed -> bed }.collect() ) + + ch_versions = ch_versions.mix(MERGE_TOOLS.out.versions) + ch_versions = ch_versions.mix(COUNTS_COMBINED.out.versions) + // // ANNOTATION WORKFLOW: // @@ -212,13 +232,18 @@ workflow CIRCRNA_DISCOVERY { FIND_CIRC_FILTER.out.results, CIRIQUANT_FILTER.out.results, DCC_FILTER.out.results, - MAPSPLICE_FILTER.out.results) + MAPSPLICE_FILTER.out.results, + MERGE_TOOLS.out.merged.map{ meta, bed -> [meta + [tool: "merged"], bed] }) INTERSECT_ANNOTATION( circrna_filtered.combine(gtf), [[], []]) ANNOTATION( INTERSECT_ANNOTATION.out.intersect, exon_boundary ) - COMBINE_ANNOTATION_BEDS(ANNOTATION.out.bed.map{ meta, bed -> bed}.collect().map{[[id: "annotation"], it]}) + + ch_annotation_bed_merged = ANNOTATION.out.bed.filter{ meta, bed -> meta.tool == "merged" } + ch_annotation_gtf_merged = ANNOTATION.out.gtf.filter{ meta, gtf -> meta.tool == "merged" } + + COMBINE_ANNOTATION_BEDS(ch_annotation_bed_merged.map{ meta, bed -> bed}.collect().map{[[id: "annotation"], it]}) REMOVE_SCORE_STRAND( COMBINE_ANNOTATION_BEDS.out.sorted, []) - COMBINE_ANNOTATION_GTFS(ANNOTATION.out.gtf.map{ meta, gtf -> gtf}.collect().map{[[id: "annotation"], it]}) + COMBINE_ANNOTATION_GTFS(ch_annotation_gtf_merged.map{ meta, gtf -> gtf}.collect().map{[[id: "annotation"], it]}) ch_versions = ch_versions.mix(INTERSECT_ANNOTATION.out.versions) ch_versions = ch_versions.mix(ANNOTATION.out.versions) @@ -230,40 +255,17 @@ workflow CIRCRNA_DISCOVERY { // FASTA WORKFLOW: // - FASTA( ANNOTATION.out.bed, fasta ) + FASTA( ch_annotation_bed_merged, fasta ) ch_versions = ch_versions.mix(FASTA.out.versions) - // - // COUNT MATRIX WORKFLOW: - // - - ch_matrix = CIRCEXPLORER2_FLT.out.matrix.mix(SEGEMEHL_FILTER.out.matrix, - CIRCRNA_FINDER_FILTER.out.matrix, - FIND_CIRC_FILTER.out.matrix, - CIRIQUANT_FILTER.out.matrix, - DCC_FILTER.out.matrix, - MAPSPLICE_FILTER.out.matrix) - - tools_selected = params.tool.split(',').collect{it.trim().toLowerCase()} - - MERGE_TOOLS( ch_matrix.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), - tools_selected.size() > 1 ? tool_filter : 1, duplicates_fun ) - - COUNTS_COMBINED( MERGE_TOOLS.out.merged.map{ meta, bed -> bed }.collect() ) - - counts_bed = COUNTS_COMBINED.out.counts_bed - counts_tsv = COUNTS_COMBINED.out.counts_tsv - ch_versions = ch_versions.mix(MERGE_TOOLS.out.versions) - ch_versions = ch_versions.mix(COUNTS_COMBINED.out.versions) - emit: - circrna_bed12 = ANNOTATION.out.bed + circrna_bed12 = ch_annotation_bed_merged fasta = FASTA.out.analysis_fasta annotation_bed = REMOVE_SCORE_STRAND.out.output annotation_gtf = COMBINE_ANNOTATION_GTFS.out.sorted - counts_bed - counts_tsv + counts_bed = COUNTS_COMBINED.out.counts_bed + counts_tsv = COUNTS_COMBINED.out.counts_tsv versions = ch_versions } From 5ebf6b8d55fda41662ca9578952493eda593cc43 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 2 May 2024 18:56:53 +0200 Subject: [PATCH 221/491] Implement upset plots --- modules/local/upset/main.nf | 17 +++++ modules/local/upset/templates/upset.py | 60 +++++++++++++++ subworkflows/local/circrna_discovery.nf | 99 ++++++++++++++----------- 3 files changed, 132 insertions(+), 44 deletions(-) create mode 100644 modules/local/upset/main.nf create mode 100644 modules/local/upset/templates/upset.py diff --git a/modules/local/upset/main.nf b/modules/local/upset/main.nf new file mode 100644 index 00000000..0381e74b --- /dev/null +++ b/modules/local/upset/main.nf @@ -0,0 +1,17 @@ +process UPSET { + tag "$meta.id" + label 'process_single' + + conda "conda-forge::python=3.8.3 conda-forge::numpy=1.20.* conda-forge::pandas=1.2.* conda-forge::upsetplot=0.4.4" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-f42a44964bca5225c7860882e231a7b5488b5485:47ef981087c59f79fdbcab4d9d7316e9ac2e688d-0' : + 'biocontainers/mulled-v2-f42a44964bca5225c7860882e231a7b5488b5485:47ef981087c59f79fdbcab4d9d7316e9ac2e688d-0' }" + input: + tuple val(meta), val(tools), path(beds) + + output: + path "versions.yml", emit: versions + + script: + template "upset.py" +} diff --git a/modules/local/upset/templates/upset.py b/modules/local/upset/templates/upset.py new file mode 100644 index 00000000..778f57aa --- /dev/null +++ b/modules/local/upset/templates/upset.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +import pandas as pd +import platform +import upsetplot +import matplotlib +import matplotlib.pyplot as plt +import distutils.version + + +def format_yaml_like(data: dict, indent: int = 0) -> str: + """Formats a dictionary to a YAML-like string. + + Args: + data (dict): The dictionary to format. + indent (int): The current indentation level. + + Returns: + str: A string formatted as YAML. + """ + yaml_str = "" + for key, value in data.items(): + spaces = " " * indent + if isinstance(value, dict): + yaml_str += f"{spaces}{key}:\\n{format_yaml_like(value, indent + 1)}" + else: + yaml_str += f"{spaces}{key}: {value}\\n" + return yaml_str + +df_tools = pd.DataFrame( + { + "tool": "${tools.join(' ')}".split(" "), + "file": "${beds.join(' ')}".split(" ") + } +) + +tool_files = df_tools.groupby("tool")["file"].apply(lambda x: set(x)).to_dict() +tool_ids = {} + +for tool, files in tool_files.items(): + df_tool = pd.concat([pd.read_csv(f, sep="\\t", header=None) for f in files]) + tool_ids[tool] = set(df_tool[3].unique()) + +dataset = upsetplot.from_contents(tool_ids) + +upsetplot.plot(dataset, orientation='horizontal') +plt.savefig("${meta.id}.png") + +# Create version file +versions = { + "${task.process}" : { + "python": platform.python_version(), + "pandas": pd.__version__, + "upsetplot": upsetplot.__version__, + "matplotlib": matplotlib.__version__ + } +} + +with open("versions.yml", "w") as f: + f.write(format_yaml_like(versions)) \ No newline at end of file diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 7eb06ef7..8a37b33d 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -1,43 +1,45 @@ -include { ANNOTATION } from '../../modules/local/annotation/full_annotation/main' -include { GNU_SORT as COMBINE_ANNOTATION_BEDS } from '../../modules/nf-core/gnu/sort/main' -include { GNU_SORT as COMBINE_ANNOTATION_GTFS } from '../../modules/nf-core/gnu/sort/main' -include { GAWK as REMOVE_SCORE_STRAND } from '../../modules/nf-core/gawk/main' -include { BEDTOOLS_INTERSECT as INTERSECT_ANNOTATION } from '../../modules/nf-core/bedtools/intersect/main' -include { BOWTIE2_ALIGN as FIND_CIRC_ALIGN } from '../../modules/nf-core/bowtie2/align/main' -include { SAMTOOLS_VIEW } from '../../modules/nf-core/samtools/view/main' -include { SAMTOOLS_INDEX } from '../../modules/nf-core/samtools/index/main' -include { FIND_CIRC_ANCHORS } from '../../modules/local/find_circ/anchors/main' -include { FIND_CIRC } from '../../modules/local/find_circ/find_circ/main' -include { FIND_CIRC_FILTER } from '../../modules/local/find_circ/filter/main' -include { CIRIQUANT } from '../../modules/local/ciriquant/ciriquant/main' -include { CIRIQUANT_FILTER } from '../../modules/local/ciriquant/filter/main' -include { CIRCRNA_FINDER_FILTER } from '../../modules/local/circrna_finder/filter/main' -include { SEGEMEHL_ALIGN } from '../../modules/nf-core/segemehl/align/main' -include { SEGEMEHL_FILTER } from '../../modules/local/segemehl/filter/main' -include { STAR_ALIGN as STAR_1ST_PASS } from '../../modules/nf-core/star/align/main' -include { STAR_ALIGN as STAR_2ND_PASS } from '../../modules/nf-core/star/align/main' -include { SJDB as STAR_SJDB } from '../../modules/local/star/sjdb/main' -include { STAR_ALIGN as DCC_MATE1_1ST_PASS } from '../../modules/nf-core/star/align/main' -include { STAR_ALIGN as DCC_MATE1_2ND_PASS } from '../../modules/nf-core/star/align/main' -include { SJDB as DCC_MATE1_SJDB } from '../../modules/local/star/sjdb/main' -include { STAR_ALIGN as DCC_MATE2_1ST_PASS } from '../../modules/nf-core/star/align/main' -include { STAR_ALIGN as DCC_MATE2_2ND_PASS } from '../../modules/nf-core/star/align/main' -include { SJDB as DCC_MATE2_SJDB } from '../../modules/local/star/sjdb/main' -include { DCC } from '../../modules/local/dcc/dcc/main' -include { DCC_FILTER } from '../../modules/local/dcc/filter/main' -include { MAPSPLICE_ALIGN } from '../../modules/local/mapsplice/align/main' -include { FASTA } from '../../modules/local/fasta/main' -include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools/main' -include { COUNTS_COMBINED } from '../../modules/local/count_matrix/combined/main' -include { CIRCEXPLORER2_REFERENCE as CIRCEXPLORER2_REF } from '../../modules/local/circexplorer2/reference/main' -include { CIRCEXPLORER2_PARSE as CIRCEXPLORER2_PAR } from '../../modules/nf-core/circexplorer2/parse/main' -include { CIRCEXPLORER2_ANNOTATE as CIRCEXPLORER2_ANN } from '../../modules/nf-core/circexplorer2/annotate/main' -include { CIRCEXPLORER2_FILTER as CIRCEXPLORER2_FLT } from '../../modules/local/circexplorer2/filter/main' -include { CIRCEXPLORER2_REFERENCE as MAPSPLICE_REFERENCE } from '../../modules/local/circexplorer2/reference/main' -include { CIRCEXPLORER2_PARSE as MAPSPLICE_PARSE } from '../../modules/nf-core/circexplorer2/parse/main' -include { CIRCEXPLORER2_ANNOTATE as MAPSPLICE_ANNOTATE } from '../../modules/nf-core/circexplorer2/annotate/main' -include { CIRCEXPLORER2_FILTER as MAPSPLICE_FILTER } from '../../modules/local/circexplorer2/filter/main' +include { ANNOTATION } from '../../modules/local/annotation/full_annotation' +include { GNU_SORT as COMBINE_ANNOTATION_BEDS } from '../../modules/nf-core/gnu/sort' +include { GNU_SORT as COMBINE_ANNOTATION_GTFS } from '../../modules/nf-core/gnu/sort' +include { GAWK as REMOVE_SCORE_STRAND } from '../../modules/nf-core/gawk' +include { BEDTOOLS_INTERSECT as INTERSECT_ANNOTATION } from '../../modules/nf-core/bedtools/intersect' +include { BOWTIE2_ALIGN as FIND_CIRC_ALIGN } from '../../modules/nf-core/bowtie2/align' +include { SAMTOOLS_VIEW } from '../../modules/nf-core/samtools/view' +include { SAMTOOLS_INDEX } from '../../modules/nf-core/samtools/index' +include { FIND_CIRC_ANCHORS } from '../../modules/local/find_circ/anchors' +include { FIND_CIRC } from '../../modules/local/find_circ/find_circ' +include { FIND_CIRC_FILTER } from '../../modules/local/find_circ/filter' +include { CIRIQUANT } from '../../modules/local/ciriquant/ciriquant' +include { CIRIQUANT_FILTER } from '../../modules/local/ciriquant/filter' +include { CIRCRNA_FINDER_FILTER } from '../../modules/local/circrna_finder/filter' +include { SEGEMEHL_ALIGN } from '../../modules/nf-core/segemehl/align' +include { SEGEMEHL_FILTER } from '../../modules/local/segemehl/filter' +include { STAR_ALIGN as STAR_1ST_PASS } from '../../modules/nf-core/star/align' +include { STAR_ALIGN as STAR_2ND_PASS } from '../../modules/nf-core/star/align' +include { SJDB as STAR_SJDB } from '../../modules/local/star/sjdb' +include { STAR_ALIGN as DCC_MATE1_1ST_PASS } from '../../modules/nf-core/star/align' +include { STAR_ALIGN as DCC_MATE1_2ND_PASS } from '../../modules/nf-core/star/align' +include { SJDB as DCC_MATE1_SJDB } from '../../modules/local/star/sjdb' +include { STAR_ALIGN as DCC_MATE2_1ST_PASS } from '../../modules/nf-core/star/align' +include { STAR_ALIGN as DCC_MATE2_2ND_PASS } from '../../modules/nf-core/star/align' +include { SJDB as DCC_MATE2_SJDB } from '../../modules/local/star/sjdb' +include { DCC } from '../../modules/local/dcc/dcc' +include { DCC_FILTER } from '../../modules/local/dcc/filter' +include { MAPSPLICE_ALIGN } from '../../modules/local/mapsplice/align' +include { FASTA } from '../../modules/local/fasta' +include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools' +include { COUNTS_COMBINED } from '../../modules/local/count_matrix/combined' +include { CIRCEXPLORER2_REFERENCE as CIRCEXPLORER2_REF } from '../../modules/local/circexplorer2/reference' +include { CIRCEXPLORER2_PARSE as CIRCEXPLORER2_PAR } from '../../modules/nf-core/circexplorer2/parse' +include { CIRCEXPLORER2_ANNOTATE as CIRCEXPLORER2_ANN } from '../../modules/nf-core/circexplorer2/annotate' +include { CIRCEXPLORER2_FILTER as CIRCEXPLORER2_FLT } from '../../modules/local/circexplorer2/filter' +include { CIRCEXPLORER2_REFERENCE as MAPSPLICE_REFERENCE } from '../../modules/local/circexplorer2/reference' +include { CIRCEXPLORER2_PARSE as MAPSPLICE_PARSE } from '../../modules/nf-core/circexplorer2/parse' +include { CIRCEXPLORER2_ANNOTATE as MAPSPLICE_ANNOTATE } from '../../modules/nf-core/circexplorer2/annotate' +include { CIRCEXPLORER2_FILTER as MAPSPLICE_FILTER } from '../../modules/local/circexplorer2/filter' +include { UPSET as UPSET_SAMPLES } from '../../modules/local/upset' +include { UPSET as UPSET_ALL } from '../../modules/local/upset' workflow CIRCRNA_DISCOVERY { @@ -227,15 +229,24 @@ workflow CIRCRNA_DISCOVERY { ch_biotypes = Channel.fromPath("${projectDir}/bin/unwanted_biotypes.txt") - circrna_filtered = CIRCEXPLORER2_FLT.out.results.mix(SEGEMEHL_FILTER.out.results, + circrna_tools = CIRCEXPLORER2_FLT.out.results.mix(SEGEMEHL_FILTER.out.results, CIRCRNA_FINDER_FILTER.out.results, FIND_CIRC_FILTER.out.results, CIRIQUANT_FILTER.out.results, DCC_FILTER.out.results, - MAPSPLICE_FILTER.out.results, - MERGE_TOOLS.out.merged.map{ meta, bed -> [meta + [tool: "merged"], bed] }) - - INTERSECT_ANNOTATION( circrna_filtered.combine(gtf), [[], []]) + MAPSPLICE_FILTER.out.results) + + UPSET_SAMPLES( circrna_tools.map{ meta, bed -> [meta.id, meta.tool, bed]} + .groupTuple() + .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) + UPSET_ALL( circrna_tools.map{ meta, bed -> ["all", meta.tool, bed] } + .groupTuple() + .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) + + circrna_incl_merged = circrna_tools.mix( + MERGE_TOOLS.out.merged.map{ meta, bed -> [meta + [tool: "merged"], bed] }) + + INTERSECT_ANNOTATION( circrna_incl_merged.combine(gtf), [[], []]) ANNOTATION( INTERSECT_ANNOTATION.out.intersect, exon_boundary ) ch_annotation_bed_merged = ANNOTATION.out.bed.filter{ meta, bed -> meta.tool == "merged" } From a9bd254bc673562070283c8d4bfa2478752c9281 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 2 May 2024 19:01:47 +0200 Subject: [PATCH 222/491] Refine upset functionality --- modules/local/upset/main.nf | 3 ++- modules/local/upset/templates/upset.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/local/upset/main.nf b/modules/local/upset/main.nf index 0381e74b..75fed9ad 100644 --- a/modules/local/upset/main.nf +++ b/modules/local/upset/main.nf @@ -10,7 +10,8 @@ process UPSET { tuple val(meta), val(tools), path(beds) output: - path "versions.yml", emit: versions + tuple val(meta), path("*.png"), emit: plot + path "versions.yml" , emit: versions script: template "upset.py" diff --git a/modules/local/upset/templates/upset.py b/modules/local/upset/templates/upset.py index 778f57aa..050900d1 100644 --- a/modules/local/upset/templates/upset.py +++ b/modules/local/upset/templates/upset.py @@ -43,7 +43,7 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: dataset = upsetplot.from_contents(tool_ids) -upsetplot.plot(dataset, orientation='horizontal') +upsetplot.plot(dataset, orientation='horizontal', show_counts=True) plt.savefig("${meta.id}.png") # Create version file From d5f511ce2f20cc87480ba1cf7bd82015146d822f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 2 May 2024 21:06:39 +0200 Subject: [PATCH 223/491] Add upset plots to multiqc --- modules/local/upset/main.nf | 1 + modules/local/upset/templates/upset.py | 23 +++++++++++++++++++++-- subworkflows/local/circrna_discovery.nf | 5 +++++ workflows/circrna/main.nf | 1 + 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/modules/local/upset/main.nf b/modules/local/upset/main.nf index 75fed9ad..e8ab89d1 100644 --- a/modules/local/upset/main.nf +++ b/modules/local/upset/main.nf @@ -11,6 +11,7 @@ process UPSET { output: tuple val(meta), path("*.png"), emit: plot + path "*.upset_mqc.json" , emit: multiqc path "versions.yml" , emit: versions script: diff --git a/modules/local/upset/templates/upset.py b/modules/local/upset/templates/upset.py index 050900d1..ff4a78da 100644 --- a/modules/local/upset/templates/upset.py +++ b/modules/local/upset/templates/upset.py @@ -6,7 +6,8 @@ import matplotlib import matplotlib.pyplot as plt import distutils.version - +import base64 +import json def format_yaml_like(data: dict, indent: int = 0) -> str: """Formats a dictionary to a YAML-like string. @@ -44,7 +45,25 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: dataset = upsetplot.from_contents(tool_ids) upsetplot.plot(dataset, orientation='horizontal', show_counts=True) -plt.savefig("${meta.id}.png") +plot_file = "${meta.id}.upset.png" +plt.savefig(plot_file) + +image_string = base64.b64encode(open(plot_file, "rb").read()).decode("utf-8") +image_html = f'
    ' + +multiqc = { + 'id': "${meta.id}_upset", + 'parent_id': "upset_plots", + 'parent_name': 'UpSet Plots', + 'parent_description': 'UpSet plots showing the overlap between tools for each sample', + 'section_name': 'UpSet: ${meta.id}', + 'description': 'UpSet plot showing the overlap between tools for sample ${meta.id}', + 'plot_type': 'image', + 'data': image_html +} + +with open("${meta.id}.upset_mqc.json", "w") as f: + f.write(json.dumps(multiqc, indent=4)) # Create version file versions = { diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 8a37b33d..f706161f 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -61,6 +61,7 @@ workflow CIRCRNA_DISCOVERY { main: ch_versions = Channel.empty() + ch_multiqc_files = Channel.empty() fasta = ch_fasta.map{meta, fasta -> fasta} gtf = ch_gtf.map{meta, gtf -> gtf} @@ -242,6 +243,9 @@ workflow CIRCRNA_DISCOVERY { UPSET_ALL( circrna_tools.map{ meta, bed -> ["all", meta.tool, bed] } .groupTuple() .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) + + ch_multiqc_files = ch_multiqc_files.mix(UPSET_SAMPLES.out.multiqc) + ch_multiqc_files = ch_multiqc_files.mix(UPSET_ALL.out.multiqc) circrna_incl_merged = circrna_tools.mix( MERGE_TOOLS.out.merged.map{ meta, bed -> [meta + [tool: "merged"], bed] }) @@ -278,5 +282,6 @@ workflow CIRCRNA_DISCOVERY { counts_bed = COUNTS_COMBINED.out.counts_bed counts_tsv = COUNTS_COMBINED.out.counts_tsv + multiqc_files = ch_multiqc_files versions = ch_versions } diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index b8bfa62d..1b0f89cd 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -151,6 +151,7 @@ workflow CIRCRNA { params.exon_boundary ) + ch_multiqc_files = ch_multiqc_files.mix(CIRCRNA_DISCOVERY.out.multiqc_files) ch_versions = ch_versions.mix(CIRCRNA_DISCOVERY.out.versions) // From 8095b809542fe4e91b2900ca4276e88be9ffa6b1 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 2 May 2024 21:18:46 +0200 Subject: [PATCH 224/491] Fix linting --- modules/local/upset/templates/upset.py | 2 +- subworkflows/local/circrna_discovery.nf | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/local/upset/templates/upset.py b/modules/local/upset/templates/upset.py index ff4a78da..ed70890b 100644 --- a/modules/local/upset/templates/upset.py +++ b/modules/local/upset/templates/upset.py @@ -76,4 +76,4 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: } with open("versions.yml", "w") as f: - f.write(format_yaml_like(versions)) \ No newline at end of file + f.write(format_yaml_like(versions)) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index f706161f..35e2fe72 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -236,7 +236,7 @@ workflow CIRCRNA_DISCOVERY { CIRIQUANT_FILTER.out.results, DCC_FILTER.out.results, MAPSPLICE_FILTER.out.results) - + UPSET_SAMPLES( circrna_tools.map{ meta, bed -> [meta.id, meta.tool, bed]} .groupTuple() .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) @@ -246,7 +246,9 @@ workflow CIRCRNA_DISCOVERY { ch_multiqc_files = ch_multiqc_files.mix(UPSET_SAMPLES.out.multiqc) ch_multiqc_files = ch_multiqc_files.mix(UPSET_ALL.out.multiqc) - + ch_versions = ch_versions.mix(UPSET_SAMPLES.out.versions) + ch_versions = ch_versions.mix(UPSET_ALL.out.versions) + circrna_incl_merged = circrna_tools.mix( MERGE_TOOLS.out.merged.map{ meta, bed -> [meta + [tool: "merged"], bed] }) From 020c8eaa1f06e41db05ea43bbb91c3c4b67cff79 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 2 May 2024 22:11:32 +0200 Subject: [PATCH 225/491] Fix pandas bug --- modules/local/upset/templates/upset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/upset/templates/upset.py b/modules/local/upset/templates/upset.py index ed70890b..f0378bf8 100644 --- a/modules/local/upset/templates/upset.py +++ b/modules/local/upset/templates/upset.py @@ -35,7 +35,7 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: } ) -tool_files = df_tools.groupby("tool")["file"].apply(lambda x: set(x)).to_dict() +tool_files = df_tools.groupby("tool").agg(lambda x: x.tolist())["file"].to_dict() tool_ids = {} for tool, files in tool_files.items(): From d99821cffa322096998f3d549e71e0937183a037 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 2 May 2024 22:33:35 +0200 Subject: [PATCH 226/491] Disable upset plots if only one tool is enabled --- conf/modules.config | 8 ++++++++ modules/local/upset/main.nf | 3 +++ 2 files changed, 11 insertions(+) diff --git a/conf/modules.config b/conf/modules.config index cfb38ae1..68535f27 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -562,6 +562,14 @@ if (!params.skip_trimming) { ] } + withName: UPSET_SAMPLES { + ext.when = { params.tool.split(',').length > 1 } + } + + withName: UPSET_ALL { + ext.when = { params.tool.split(',').length > 1 } + } + withName: INTERSECT_ANNOTATION { ext.args = "-loj" ext.suffix = "intersect.bed" diff --git a/modules/local/upset/main.nf b/modules/local/upset/main.nf index e8ab89d1..1ff4bf6f 100644 --- a/modules/local/upset/main.nf +++ b/modules/local/upset/main.nf @@ -9,6 +9,9 @@ process UPSET { input: tuple val(meta), val(tools), path(beds) + when: + task.ext.when == null || task.ext.when + output: tuple val(meta), path("*.png"), emit: plot path "*.upset_mqc.json" , emit: multiqc From bf06573eeeccd8302ac7c3ce9404fea3f45f472c Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 6 May 2024 12:17:32 +0200 Subject: [PATCH 227/491] Add annotation as rowdata to summarizedExperiment --- .../local/quantification/merge_experiments/environment.yml | 2 +- modules/local/quantification/merge_experiments/main.nf | 5 +++-- .../merge_experiments/templates/merge_experiments.r | 5 +++++ modules/local/upset/main.nf | 2 +- subworkflows/local/quantification.nf | 3 ++- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/modules/local/quantification/merge_experiments/environment.yml b/modules/local/quantification/merge_experiments/environment.yml index 381dba4d..cfc21aba 100644 --- a/modules/local/quantification/merge_experiments/environment.yml +++ b/modules/local/quantification/merge_experiments/environment.yml @@ -6,4 +6,4 @@ channels: - bioconda - defaults dependencies: - - "bioconda::bioconductor-summarizedexperiment=1.32.0" + - "bioconda::bioconductor-rtracklayer==1.62.0--r43ha9d7317_0" diff --git a/modules/local/quantification/merge_experiments/main.nf b/modules/local/quantification/merge_experiments/main.nf index 367a3082..3b422b75 100644 --- a/modules/local/quantification/merge_experiments/main.nf +++ b/modules/local/quantification/merge_experiments/main.nf @@ -4,12 +4,13 @@ process MERGE_EXPERIMENTS { conda "${moduleDir}/environment.yaml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/bioconductor-summarizedexperiment:1.32.0--r43hdfd78af_0' : - 'biocontainers/bioconductor-summarizedexperiment:1.32.0--r43hdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/bioconductor-rtracklayer:1.62.0--r43ha9d7317_0' : + 'biocontainers/bioconductor-rtracklayer:1.62.0--r43ha9d7317_0' }" input: tuple val(meta), path(experiments) tuple val(meta2), path(phenotype) + tuple val(meta3), path(gtf) output: tuple val(meta), path("${meta.id}.merged.rds"), emit: merged diff --git a/modules/local/quantification/merge_experiments/templates/merge_experiments.r b/modules/local/quantification/merge_experiments/templates/merge_experiments.r index 51b5b666..5dd2bfb2 100644 --- a/modules/local/quantification/merge_experiments/templates/merge_experiments.r +++ b/modules/local/quantification/merge_experiments/templates/merge_experiments.r @@ -6,6 +6,7 @@ paths <- c('${experiments.join("\', \'")}') experiments <- lapply(paths, readRDS) phenotype <- read.csv('${phenotype}', stringsAsFactors = FALSE) +annotation <- rtracklayer::import('${gtf}') se_assays <- list() @@ -37,6 +38,10 @@ for (col in colnames(colData(se))) { } } +# Add transcript annotation +annotation <- annotation[match(rownames(se), annotation\$transcript_id),] +rowData(se) <- annotation + saveRDS(se, '${meta.id}.merged.rds') writeLines( diff --git a/modules/local/upset/main.nf b/modules/local/upset/main.nf index 1ff4bf6f..08babf76 100644 --- a/modules/local/upset/main.nf +++ b/modules/local/upset/main.nf @@ -14,7 +14,7 @@ process UPSET { output: tuple val(meta), path("*.png"), emit: plot - path "*.upset_mqc.json" , emit: multiqc + path "*.upset_mqc.json" , emit: multiqc path "versions.yml" , emit: versions script: diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index b1c0d576..403140ce 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -66,7 +66,8 @@ workflow QUANTIFICATION { MERGE_EXPERIMENTS( TXIMETA_TXIMETA.out.se.map{meta, se -> se}.collect().map{[[id: "experiments"], it]}, - ch_phenotype + ch_phenotype, + EXCLUDE_OVERLONG_TRANSCRIPTS.out.output ) TXIMETA_TXIMPORT( From 15bd62c5ea248972782a7f5995a153f838f7ec0d Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 10 May 2024 14:18:50 +0200 Subject: [PATCH 228/491] Prepare for TPM addition --- subworkflows/local/quantification.nf | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index 403140ce..df65579a 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -64,12 +64,6 @@ workflow QUANTIFICATION { "kallisto" ) - MERGE_EXPERIMENTS( - TXIMETA_TXIMETA.out.se.map{meta, se -> se}.collect().map{[[id: "experiments"], it]}, - ch_phenotype, - EXCLUDE_OVERLONG_TRANSCRIPTS.out.output - ) - TXIMETA_TXIMPORT( PSIRC_QUANT.out.directory, CUSTOM_TX2GENE.out.tx2gene, @@ -81,8 +75,7 @@ workflow QUANTIFICATION { PSIRC_QUANT.out.versions, CUSTOM_TX2GENE.out.versions, TXIMETA_TXIMETA.out.versions, - TXIMETA_TXIMPORT.out.versions, - MERGE_EXPERIMENTS.out.versions + TXIMETA_TXIMPORT.out.versions ) JOIN_GENE_COUNTS( @@ -109,13 +102,21 @@ workflow QUANTIFICATION { JOIN_TX_TPM.out.csv ) + + MERGE_EXPERIMENTS( + TXIMETA_TXIMETA.out.se.map{meta, se -> se}.collect().map{[[id: "experiments"], it]}, + ch_phenotype, + EXCLUDE_OVERLONG_TRANSCRIPTS.out.output + ) + ch_versions = ch_versions.mix( JOIN_GENE_COUNTS.out.versions, JOIN_GENE_TPM.out.versions, JOIN_TX_COUNTS.out.versions, JOIN_TX_TPM.out.versions, SPLIT_TYPES_COUNTS.out.versions, - SPLIT_TYPES_TPM.out.versions + SPLIT_TYPES_TPM.out.versions, + MERGE_EXPERIMENTS.out.versions ) emit: From dbc4042750510c4394d17162c9aa57e4a669e053 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 10 May 2024 17:46:10 +0200 Subject: [PATCH 229/491] Fix DeSeq compatibility problems --- bin/DEA.R | 2 +- bin/counts_combined.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/bin/DEA.R b/bin/DEA.R index b40dbfa7..ea5960b7 100755 --- a/bin/DEA.R +++ b/bin/DEA.R @@ -283,7 +283,7 @@ DESeq2 <- function(inputdata, data_type){ rm(tmp) dds <- DESeqDataSetFromMatrix( - countData=inputdata$circ, + countData=round(inputdata$circ), colData=inputdata$pheno, design = inputdata$design) diff --git a/bin/counts_combined.py b/bin/counts_combined.py index 5c326451..f50fe3db 100755 --- a/bin/counts_combined.py +++ b/bin/counts_combined.py @@ -15,13 +15,15 @@ dfs = {os.path.basename(bed).split('.')[0]: pd.read_csv(bed, sep='\t', header=None, + index_col=["chr", "start", "end", "strand"], + usecols=["chr", "start", "end", "strand", "count"], names=columns) for bed in args.beds} dfs = [df.rename(columns={'count': sample}) for sample, df in dfs.items()] df = pd.concat(dfs, axis=1) -df.to_csv(args.out_bed, sep='\t') +df = df.fillna(0) +df.to_csv(args.out_bed, sep='\t', header=True, index=True) -df.index = df['name'] +df.index = df.index.map(lambda x: f'{x[0]}:{x[1]}-{x[2]}:{x[3]}') df.index.name = 'ID' -df.drop('name', axis=1, inplace=True) df.to_csv(args.out_tsv, sep='\t') From 86af7b2abe18e63d6efbac38c88b1d87e76c1428 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 10 May 2024 18:45:25 +0200 Subject: [PATCH 230/491] Add TPM the quantification RDS --- modules/local/quantification/merge_experiments/main.nf | 3 ++- .../merge_experiments/templates/merge_experiments.r | 4 ++++ subworkflows/local/quantification.nf | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/local/quantification/merge_experiments/main.nf b/modules/local/quantification/merge_experiments/main.nf index 3b422b75..9e14df7e 100644 --- a/modules/local/quantification/merge_experiments/main.nf +++ b/modules/local/quantification/merge_experiments/main.nf @@ -8,9 +8,10 @@ process MERGE_EXPERIMENTS { 'biocontainers/bioconductor-rtracklayer:1.62.0--r43ha9d7317_0' }" input: - tuple val(meta), path(experiments) + tuple val(meta), path(experiments) tuple val(meta2), path(phenotype) tuple val(meta3), path(gtf) + tuple val(meta4), path(tpm) output: tuple val(meta), path("${meta.id}.merged.rds"), emit: merged diff --git a/modules/local/quantification/merge_experiments/templates/merge_experiments.r b/modules/local/quantification/merge_experiments/templates/merge_experiments.r index 5dd2bfb2..a166190b 100644 --- a/modules/local/quantification/merge_experiments/templates/merge_experiments.r +++ b/modules/local/quantification/merge_experiments/templates/merge_experiments.r @@ -7,6 +7,7 @@ experiments <- lapply(paths, readRDS) phenotype <- read.csv('${phenotype}', stringsAsFactors = FALSE) annotation <- rtracklayer::import('${gtf}') +tpm <- read.table('${tpm}', header=TRUE, row.names=1)[, -1] se_assays <- list() @@ -42,6 +43,9 @@ for (col in colnames(colData(se))) { annotation <- annotation[match(rownames(se), annotation\$transcript_id),] rowData(se) <- annotation +# Add TPM +assay(se, "tpm", withDimnames = FALSE) <- tpm[rownames(se), colData(se)\$names] + saveRDS(se, '${meta.id}.merged.rds') writeLines( diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index df65579a..ee9ad8be 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -106,7 +106,8 @@ workflow QUANTIFICATION { MERGE_EXPERIMENTS( TXIMETA_TXIMETA.out.se.map{meta, se -> se}.collect().map{[[id: "experiments"], it]}, ch_phenotype, - EXCLUDE_OVERLONG_TRANSCRIPTS.out.output + EXCLUDE_OVERLONG_TRANSCRIPTS.out.output, + JOIN_TX_TPM.out.csv ) ch_versions = ch_versions.mix( From 6cdc67feb88413349d85e77bcaf52be2b9a09c88 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Wed, 22 May 2024 07:35:05 +0200 Subject: [PATCH 231/491] Fix GTF attribute splitting --- bin/annotation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/annotation.py b/bin/annotation.py index 17001e36..877ed877 100755 --- a/bin/annotation.py +++ b/bin/annotation.py @@ -43,7 +43,7 @@ df_intergenic['transcript_id'] = 'intergenic_' + df_intergenic['name'] # Convert attributes to a dictionary -df['attributes'] = df['attributes'].apply(lambda row: dict([[value.strip(r'"') for value in entry.strip().split(' ')] for entry in row.split(';') if entry])) +df['attributes'] = df['attributes'].apply(lambda row: dict([[value.strip(r'"') for value in entry.strip().split(' ', 1)] for entry in row.split(';') if entry])) # Keep only the attributes we want df['attributes'] = df['attributes'].apply(lambda row: {key: row[key] for key in attributes if key in row}) # Convert attributes to columns From e273f70e30a6654ec46058b13efabf40e7438d14 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Wed, 22 May 2024 09:15:38 +0200 Subject: [PATCH 232/491] Simplify FASTA extraction --- bin/backsplice_gen.sh | 37 --------------------- conf/modules.config | 7 ++-- modules/local/fasta/main.nf | 44 ------------------------- subworkflows/local/circrna_discovery.nf | 11 ++++--- 4 files changed, 11 insertions(+), 88 deletions(-) delete mode 100755 bin/backsplice_gen.sh delete mode 100644 modules/local/fasta/main.nf diff --git a/bin/backsplice_gen.sh b/bin/backsplice_gen.sh deleted file mode 100755 index 3134046b..00000000 --- a/bin/backsplice_gen.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash - -## Shell script to generate backsplice sequence from circRNA sequence. -## Author: Barry Digby -## License: MIT - -## .fa = backsplice .fasta = canonical to publish - -file_prefix=$(basename $1 .fa) - -# Split multi-fasta file into single records -mkdir canonical_seqs && mv $1 canonical_seqs/ -ls -d canonical_seqs/*.fa | while read -r line; do -cat $line | awk '{if (substr($0, 1, 1)==">") {filename=(substr($0,2) ".fa")} print $0 > filename}' -done - -# add backsplice site to individual fasta files -for file in *.fa; do - fn=$(basename $file .fa) - cat $file | grep ">" > header.txt - cat $file | grep -v ">" | cut -c1-20 > 20bp.txt - cat $file | grep -v ">" > seqs.txt - paste seqs.txt 20bp.txt | sed -e 's/\t//' > seqs_20bp.txt - paste header.txt seqs_20bp.txt | sed -e 's/\t/\n/' > ${fn}.fasta - rm header.txt 20bp.txt seqs.txt seqs_20bp.txt -done - -# rm single fasta entries from while read line -rm *.fa -# merge backsplice fastas into one for miRNA pred -cat *.fasta > ${file_prefix}.fa -# remove intermediate for loop fasta file -rm *.fasta -# move canonical seqs back to publish to outdir -ls -d canonical_seqs/*.fa | while read -r line; do -mv $line ${file_prefix}.fasta -done diff --git a/conf/modules.config b/conf/modules.config index 68535f27..7cf1f74c 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -590,13 +590,14 @@ if (!params.skip_trimming) { ext.suffix = "tidy.bed" } - withName: FASTA { - ext.when = { params.module.split(',').contains('circrna_discovery') } + withName: ADD_BACKSPLICE { + ext.args = "'{ if (/^>/) { print \$0 } else { start = substr(\$0, 1, 25); print \$0 start } }'" + ext.suffix = "backspliced.fa" publishDir = [ path: { "${params.outdir}/circrna_discovery/${meta.tool}/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - pattern: "*.fasta" + pattern: "*.backspliced.fa" ] } diff --git a/modules/local/fasta/main.nf b/modules/local/fasta/main.nf deleted file mode 100644 index d17b17d7..00000000 --- a/modules/local/fasta/main.nf +++ /dev/null @@ -1,44 +0,0 @@ -process FASTA { - tag "${meta.id}:${meta.tool}" - label 'process_single' - - conda "bioconda::bedtools=2.30.0" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/bedtools:2.30.0--h7d7f7ad_2': - 'biocontainers/bedtools:2.30.0--h7d7f7ad_2' }" - - input: - tuple val(meta), path(bed) - path(fasta, stageAs: 'fasta.input') // TODO: Remove input renaming, currently necessary to prevent problems with the backsplice_gen.sh script - - output: - tuple val(meta), path("${prefix}.fa"), emit: analysis_fasta - path("${prefix}.fasta") , emit: publish_fasta - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - prefix = task.ext.prefix ?: "${meta.id}" - """ - ## FASTA sequences (bedtools does not like the extra annotation info - split will not work properly) - cut -d\$'\\t' -f1-12 $bed > bed12.tmp - bedtools getfasta -fi $fasta -bed bed12.tmp -s -split -name > circ_seq.tmp - - ## clean fasta header - grep -A 1 '>' circ_seq.tmp | cut -d: -f1,2,3 > ${prefix}.fa && rm circ_seq.tmp - - ## add backsplice sequence for miRanda Targetscan, publish canonical FASTA to results. - backsplice_gen.sh ${prefix}.fa - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bedtools: \$(bedtools --version | sed -e "s/bedtools v//g") - cut: \$(cut --version | head -n 1 | cut -d' ' -f4) - END_VERSIONS - """ -} - - diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 35e2fe72..c162f8f8 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -27,7 +27,6 @@ include { SJDB as DCC_MATE2_SJDB } from '../../modules/l include { DCC } from '../../modules/local/dcc/dcc' include { DCC_FILTER } from '../../modules/local/dcc/filter' include { MAPSPLICE_ALIGN } from '../../modules/local/mapsplice/align' -include { FASTA } from '../../modules/local/fasta' include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools' include { COUNTS_COMBINED } from '../../modules/local/count_matrix/combined' include { CIRCEXPLORER2_REFERENCE as CIRCEXPLORER2_REF } from '../../modules/local/circexplorer2/reference' @@ -40,6 +39,8 @@ include { CIRCEXPLORER2_ANNOTATE as MAPSPLICE_ANNOTATE } from '../../modules/n include { CIRCEXPLORER2_FILTER as MAPSPLICE_FILTER } from '../../modules/local/circexplorer2/filter' include { UPSET as UPSET_SAMPLES } from '../../modules/local/upset' include { UPSET as UPSET_ALL } from '../../modules/local/upset' +include { BEDTOOLS_GETFASTA } from '../../modules/nf-core/bedtools/getfasta' +include { GAWK as ADD_BACKSPLICE } from '../../modules/nf-core/gawk' workflow CIRCRNA_DISCOVERY { @@ -272,13 +273,15 @@ workflow CIRCRNA_DISCOVERY { // FASTA WORKFLOW: // - FASTA( ch_annotation_bed_merged, fasta ) + BEDTOOLS_GETFASTA( ch_annotation_bed_merged, fasta ) + ADD_BACKSPLICE( BEDTOOLS_GETFASTA.out.fasta, []) - ch_versions = ch_versions.mix(FASTA.out.versions) + ch_versions = ch_versions.mix(BEDTOOLS_GETFASTA.out.versions) + ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) emit: circrna_bed12 = ch_annotation_bed_merged - fasta = FASTA.out.analysis_fasta + fasta = ADD_BACKSPLICE.out.output annotation_bed = REMOVE_SCORE_STRAND.out.output annotation_gtf = COMBINE_ANNOTATION_GTFS.out.sorted counts_bed = COUNTS_COMBINED.out.counts_bed From 1bb983b2b80d80779ad5aad61a7d4cb57e60c95b Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 08:21:50 +0200 Subject: [PATCH 233/491] Simplify STAR and SEGEMEHL discovery --- conf/modules.config | 15 +++---- subworkflows/local/circrna_discovery.nf | 55 +++++++++-------------- subworkflows/local/discovery/segemehl.nf | 29 ++++++++++++ subworkflows/local/discovery/star2pass.nf | 34 ++++++++++++++ subworkflows/local/prepare_genome.nf | 5 --- workflows/circrna/main.nf | 2 - 6 files changed, 89 insertions(+), 51 deletions(-) create mode 100644 subworkflows/local/discovery/segemehl.nf create mode 100644 subworkflows/local/discovery/star2pass.nf diff --git a/conf/modules.config b/conf/modules.config index 7cf1f74c..b13926e9 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -143,7 +143,7 @@ if (!params.skip_trimming) { ] } - withName: SEGEMEHL_INDEX { + withName: '.*:SEGEMEHL:INDEX' { ext.when = { !params.segemehl && params.tool.split(',').contains('segemehl') && params.module.split(',').contains('circrna_discovery') } publishDir = [ path: { "${params.outdir}/references/index/segemehl" }, @@ -155,7 +155,7 @@ if (!params.skip_trimming) { // circRNA - withName: SEGEMEHL_ALIGN { + withName: '.*:SEGEMEHL:ALIGN' { ext.when = { params.tool.split(',').contains('segemehl') && params.module.split(',').contains('circrna_discovery') } ext.args = [ "", "-b", @@ -169,8 +169,7 @@ if (!params.skip_trimming) { ] } - withName: SEGEMEHL_FILTER { - ext.when = { params.tool.split(',').contains('segemehl') && params.module.split(',').contains('circrna_discovery') } + withName: '.*:SEGEMEHL:FILTER' { publishDir = [ path: { "${params.outdir}/circrna_discovery/segemehl/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -180,7 +179,7 @@ if (!params.skip_trimming) { ] } - withName: STAR_1ST_PASS { + withName: '.*:STAR2PASS:PASS_1' { ext.when = { params.module.split(',').contains('circrna_discovery') && ( params.tool.split(',').contains('circexplorer2') || params.tool.split(',').contains('circrna_finder') ) } ext.args = [ "", "--chimOutType Junctions WithinBAM", @@ -201,8 +200,7 @@ if (!params.skip_trimming) { ] } - withName: STAR_SJDB { - ext.when = { params.module.split(',').contains('circrna_discovery') && ( params.tool.split(',').contains('circexplorer2') || params.tool.split(',').contains('circrna_finder') ) } + withName: '.*:STAR2PASS:SJDB' { publishDir = [ path: { "${params.outdir}/circrna_discovery/star/sjdb" }, mode: params.publish_dir_mode, @@ -211,8 +209,7 @@ if (!params.skip_trimming) { ] } - withName: STAR_2ND_PASS { - ext.when = { params.module.split(',').contains('circrna_discovery') && ( params.tool.split(',').contains('circexplorer2') || params.tool.split(',').contains('circrna_finder') ) } + withName: '.*:STAR2PASS:PASS_2' { ext.args = [ "", params.tool.split(',').contains('circrna_finder') ? "--chimOutType Junctions SeparateSAMold" : "--chimOutType Junctions WithinBAM", "--outSAMunmapped Within", diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index c162f8f8..f0688cc0 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -1,4 +1,4 @@ - +// MODULES include { ANNOTATION } from '../../modules/local/annotation/full_annotation' include { GNU_SORT as COMBINE_ANNOTATION_BEDS } from '../../modules/nf-core/gnu/sort' include { GNU_SORT as COMBINE_ANNOTATION_GTFS } from '../../modules/nf-core/gnu/sort' @@ -13,11 +13,6 @@ include { FIND_CIRC_FILTER } from '../../modules/l include { CIRIQUANT } from '../../modules/local/ciriquant/ciriquant' include { CIRIQUANT_FILTER } from '../../modules/local/ciriquant/filter' include { CIRCRNA_FINDER_FILTER } from '../../modules/local/circrna_finder/filter' -include { SEGEMEHL_ALIGN } from '../../modules/nf-core/segemehl/align' -include { SEGEMEHL_FILTER } from '../../modules/local/segemehl/filter' -include { STAR_ALIGN as STAR_1ST_PASS } from '../../modules/nf-core/star/align' -include { STAR_ALIGN as STAR_2ND_PASS } from '../../modules/nf-core/star/align' -include { SJDB as STAR_SJDB } from '../../modules/local/star/sjdb' include { STAR_ALIGN as DCC_MATE1_1ST_PASS } from '../../modules/nf-core/star/align' include { STAR_ALIGN as DCC_MATE1_2ND_PASS } from '../../modules/nf-core/star/align' include { SJDB as DCC_MATE1_SJDB } from '../../modules/local/star/sjdb' @@ -42,6 +37,10 @@ include { UPSET as UPSET_ALL } from '../../modules/l include { BEDTOOLS_GETFASTA } from '../../modules/nf-core/bedtools/getfasta' include { GAWK as ADD_BACKSPLICE } from '../../modules/nf-core/gawk' +// SUBWORKFLOWS +include { SEGEMEHL } from './discovery/segemehl' +include { STAR2PASS } from './discovery/star2pass' + workflow CIRCRNA_DISCOVERY { take: @@ -53,7 +52,6 @@ workflow CIRCRNA_DISCOVERY { bwa_index chromosomes hisat2_index - segemehl_index star_index bsj_reads tool_filter @@ -66,40 +64,27 @@ workflow CIRCRNA_DISCOVERY { fasta = ch_fasta.map{meta, fasta -> fasta} gtf = ch_gtf.map{meta, gtf -> gtf} - // - // SEGEMEHL WORKFLOW: - // - SEGEMEHL_ALIGN( reads, fasta, segemehl_index ) - segemehl_filter = SEGEMEHL_ALIGN.out.results.map{ meta, results -> [ meta + [tool: "segemehl"], results ] } - SEGEMEHL_FILTER( segemehl_filter, bsj_reads ) - - ch_versions = ch_versions.mix(SEGEMEHL_ALIGN.out.versions) - ch_versions = ch_versions.mix(SEGEMEHL_FILTER.out.versions) + // STAR CONSTANT PARAMETERS + star_ignore_sjdbgtf = true + seq_center = params.seq_center ?: '' + seq_platform = '' // - // STAR WORFKLOW: + // DISCOVERY TOOLS: // + tools = params.tool.split(',').collect{it.trim().toLowerCase()} + SEGEMEHL( reads, fasta, params.segemehl, bsj_reads ) + STAR2PASS( reads, star_index, ch_gtf, bsj_reads, star_ignore_sjdbgtf, seq_center, seq_platform ) - // Define variables here, star_ignore_sjdbgtf not supposed to be toggled by user. - star_ignore_sjdbgtf = true - seq_center = params.seq_center ?: '' - seq_platform = '' - - STAR_1ST_PASS( reads, star_index, ch_gtf, star_ignore_sjdbgtf, seq_platform, seq_center) - sjdb = STAR_1ST_PASS.out.tab.map{ meta, tab -> return tab }.collect().map{[[id: "star_sjdb"], it]} - STAR_SJDB( sjdb, bsj_reads ) - STAR_2ND_PASS( reads, star_index, STAR_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) - - ch_versions = ch_versions.mix(STAR_1ST_PASS.out.versions) - ch_versions = ch_versions.mix(STAR_SJDB.out.versions) - ch_versions = ch_versions.mix(STAR_2ND_PASS.out.versions) + ch_versions = ch_versions.mix(SEGEMEHL.out.versions) + ch_versions = ch_versions.mix(STAR2PASS.out.versions) // // CIRCEXPLORER2 WORKFLOW: // CIRCEXPLORER2_REF( gtf ) - CIRCEXPLORER2_PAR( STAR_2ND_PASS.out.junction ) + CIRCEXPLORER2_PAR( STAR2PASS.out.junction ) CIRCEXPLORER2_ANN( CIRCEXPLORER2_PAR.out.junction, fasta, CIRCEXPLORER2_REF.out.txt ) circexplorer2_filter = CIRCEXPLORER2_ANN.out.txt.map{ meta, txt -> [ meta + [tool: "circexplorer2"], txt ] } CIRCEXPLORER2_FLT( circexplorer2_filter, bsj_reads ) @@ -113,7 +98,7 @@ workflow CIRCRNA_DISCOVERY { // CIRCRNA_FINDER WORKFLOW: // - circrna_finder_stage = STAR_2ND_PASS.out.sam.join( STAR_2ND_PASS.out.junction).join(STAR_2ND_PASS.out.tab) + circrna_finder_stage = STAR2PASS.out.sam.join( STAR2PASS.out.junction).join(STAR2PASS.out.tab) circrna_finder_filter = circrna_finder_stage.map{ meta, sam, junction, tab -> [ meta + [tool: "circrna_finder"], sam, junction, tab ] } CIRCRNA_FINDER_FILTER( circrna_finder_filter, fasta, bsj_reads ) @@ -164,7 +149,7 @@ workflow CIRCRNA_DISCOVERY { DCC_MATE2_SJDB( DCC_MATE2_1ST_PASS.out.tab.map{ meta, tab -> return tab }.collect().map{[[id: "mate2_sjdb"], it]}, bsj_reads ) DCC_MATE2_2ND_PASS( mate2, star_index, DCC_MATE2_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) - dcc_stage = STAR_2ND_PASS.out.junction.map{ meta, junction -> return [ meta.id, meta, junction]} + dcc_stage = STAR2PASS.out.junction.map{ meta, junction -> return [ meta.id, meta, junction]} .join( DCC_MATE1_2ND_PASS.out.junction.map{ meta, junction -> return [ meta.id, junction] }, remainder: true @@ -209,7 +194,7 @@ workflow CIRCRNA_DISCOVERY { // COUNT MATRIX WORKFLOW: // - ch_matrix = CIRCEXPLORER2_FLT.out.matrix.mix(SEGEMEHL_FILTER.out.matrix, + ch_matrix = CIRCEXPLORER2_FLT.out.matrix.mix(SEGEMEHL.out.matrix, CIRCRNA_FINDER_FILTER.out.matrix, FIND_CIRC_FILTER.out.matrix, CIRIQUANT_FILTER.out.matrix, @@ -231,7 +216,7 @@ workflow CIRCRNA_DISCOVERY { ch_biotypes = Channel.fromPath("${projectDir}/bin/unwanted_biotypes.txt") - circrna_tools = CIRCEXPLORER2_FLT.out.results.mix(SEGEMEHL_FILTER.out.results, + circrna_tools = CIRCEXPLORER2_FLT.out.results.mix(SEGEMEHL.out.results, CIRCRNA_FINDER_FILTER.out.results, FIND_CIRC_FILTER.out.results, CIRIQUANT_FILTER.out.results, diff --git a/subworkflows/local/discovery/segemehl.nf b/subworkflows/local/discovery/segemehl.nf new file mode 100644 index 00000000..1d380fd1 --- /dev/null +++ b/subworkflows/local/discovery/segemehl.nf @@ -0,0 +1,29 @@ +include { SEGEMEHL_INDEX as INDEX } from '../../../modules/nf-core/segemehl/index' +include { SEGEMEHL_ALIGN as ALIGN } from '../../../modules/nf-core/segemehl/align' +include { SEGEMEHL_FILTER as FILTER } from '../../../modules/local/segemehl/filter' + + +workflow SEGEMEHL { + take: + reads + fasta + index + bsj_reads + + main: + ch_versions = Channel.empty() + + index = index ?: INDEX( fasta ).index + ALIGN( reads, fasta, index ) + FILTER( ALIGN.out.results + .map{ meta, results -> [ meta + [tool: "segemehl"], results ] }, bsj_reads ) + + ch_versions = ch_versions.mix(ALIGN.out.versions) + ch_versions = ch_versions.mix(FILTER.out.versions) + + emit: + matrix = FILTER.out.matrix + results = FILTER.out.results + + versions = ch_versions +} \ No newline at end of file diff --git a/subworkflows/local/discovery/star2pass.nf b/subworkflows/local/discovery/star2pass.nf new file mode 100644 index 00000000..65ce3e34 --- /dev/null +++ b/subworkflows/local/discovery/star2pass.nf @@ -0,0 +1,34 @@ +include { STAR_ALIGN as PASS_1 } from '../../../modules/nf-core/star/align' +include { STAR_ALIGN as PASS_2 } from '../../../modules/nf-core/star/align' +include { SJDB } from '../../../modules/local/star/sjdb' + + +workflow STAR2PASS { + take: + reads + star_index + ch_gtf + bsj_reads + ignore_sjdbgtf + seq_center + seq_platform + + main: + ch_versions = Channel.empty() + + PASS_1( reads, star_index, ch_gtf, ignore_sjdbgtf, seq_platform, seq_center) + sjdb = PASS_1.out.tab.map{ meta, tab -> return tab }.collect().map{[[id: "star_sjdb"], it]} + SJDB( sjdb, bsj_reads ) + PASS_2( reads, star_index, SJDB.out.sjtab, ignore_sjdbgtf, seq_platform, seq_center ) + + ch_versions = ch_versions.mix(PASS_1.out.versions) + ch_versions = ch_versions.mix(SJDB.out.versions) + ch_versions = ch_versions.mix(PASS_2.out.versions) + + emit: + junction = PASS_2.out.junction + sam = PASS_2.out.sam + tab = PASS_2.out.tab + + versions = ch_versions +} \ No newline at end of file diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 9d382295..140ba463 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -5,7 +5,6 @@ include { BWA_INDEX } from '../../modules/nf-core/bwa/index' include { HISAT2_EXTRACTSPLICESITES } from '../../modules/nf-core/hisat2/extractsplicesites' include { HISAT2_BUILD } from '../../modules/nf-core/hisat2/build' include { STAR_GENOMEGENERATE } from '../../modules/nf-core/star/genomegenerate' -include { SEGEMEHL_INDEX } from '../../modules/nf-core/segemehl/index' include { GAWK as CLEAN_FASTA } from '../../modules/nf-core/gawk' include { SAMTOOLS_FAIDX } from '../../modules/nf-core/samtools/faidx' @@ -41,8 +40,6 @@ workflow PREPARE_GENOME { STAR_GENOMEGENERATE(ch_fasta, ch_gtf) - SEGEMEHL_INDEX(ch_fasta.map{ meta, fasta -> fasta}) // TODO: Add support for meta - SAMTOOLS_FAIDX(ch_fasta, [[], []]) // Collect versions @@ -52,14 +49,12 @@ workflow PREPARE_GENOME { BWA_INDEX.out.versions, HISAT2_EXTRACTSPLICESITES.out.versions, HISAT2_BUILD.out.versions, - SEGEMEHL_INDEX.out.versions, STAR_GENOMEGENERATE.out.versions, SAMTOOLS_FAIDX.out.versions) emit: faidx = SAMTOOLS_FAIDX.out.fai bowtie = params.bowtie ?: BOWTIE_BUILD.out.index - segemehl = params.segemehl ?: SEGEMEHL_INDEX.out.index bowtie2 = params.bowtie2 ? Channel.value([[id: "bowtie2"], file(params.bowtie2, checkIfExists: true)]) : BOWTIE2_BUILD.out.index.collect() bwa = params.bwa ? Channel.value([[id: "bwa"], file(params.bwa, checkIfExists: true)]) : BWA_INDEX.out.index.collect() hisat2 = params.hisat2 ? Channel.value([[id: "hisat2"], file(params.hisat2, checkIfExists: true)]) : HISAT2_BUILD.out.index.collect() diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 1b0f89cd..4da9fe94 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -117,7 +117,6 @@ workflow CIRCRNA { chromosomes = PREPARE_GENOME.out.chromosomes hisat2_index = PREPARE_GENOME.out.hisat2 star_index = PREPARE_GENOME.out.star - segemehl_index = PREPARE_GENOME.out.segemehl ch_versions = ch_versions.mix(PREPARE_GENOME.out.versions) // MODULE: Run FastQC, trimgalore! @@ -143,7 +142,6 @@ workflow CIRCRNA { bwa_index, chromosomes, hisat2_index, - segemehl_index, star_index, params.bsj_reads, params.tool_filter, From aa4597e03c593af17cdcd1b7c92a64ac78a19758 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 08:33:13 +0200 Subject: [PATCH 234/491] Simplify CIRCEXPLORER2 workflow --- conf/modules.config | 8 ++--- subworkflows/local/circrna_discovery.nf | 30 ++++------------- subworkflows/local/discovery/circexplorer2.nf | 32 +++++++++++++++++++ 3 files changed, 43 insertions(+), 27 deletions(-) create mode 100644 subworkflows/local/discovery/circexplorer2.nf diff --git a/conf/modules.config b/conf/modules.config index b13926e9..fcd3213c 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -230,7 +230,7 @@ if (!params.skip_trimming) { ] } - withName: CIRCEXPLORER2_REF { + withName: '.*:CIRCEXPLORER2:REFERENCE' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } ext.args = [ "", "-genePredExt", @@ -244,7 +244,7 @@ if (!params.skip_trimming) { ] } - withName: CIRCEXPLORER2_PAR { + withName: '.*:CIRCEXPLORER2:PARSE' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } publishDir = [ path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates/${meta.id}" }, @@ -254,7 +254,7 @@ if (!params.skip_trimming) { ] } - withName: CIRCEXPLORER2_ANN { + withName: '.*:CIRCEXPLORER2:ANNOTATE' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } publishDir = [ path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates/${meta.id}" }, @@ -264,7 +264,7 @@ if (!params.skip_trimming) { ] } - withName: CIRCEXPLORER2_FLT { + withName: '.*:CIRCEXPLORER2:FILTER' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } publishDir = [ path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates/${meta.id}" }, diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index f0688cc0..91a7e2c7 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -24,10 +24,6 @@ include { DCC_FILTER } from '../../modules/l include { MAPSPLICE_ALIGN } from '../../modules/local/mapsplice/align' include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools' include { COUNTS_COMBINED } from '../../modules/local/count_matrix/combined' -include { CIRCEXPLORER2_REFERENCE as CIRCEXPLORER2_REF } from '../../modules/local/circexplorer2/reference' -include { CIRCEXPLORER2_PARSE as CIRCEXPLORER2_PAR } from '../../modules/nf-core/circexplorer2/parse' -include { CIRCEXPLORER2_ANNOTATE as CIRCEXPLORER2_ANN } from '../../modules/nf-core/circexplorer2/annotate' -include { CIRCEXPLORER2_FILTER as CIRCEXPLORER2_FLT } from '../../modules/local/circexplorer2/filter' include { CIRCEXPLORER2_REFERENCE as MAPSPLICE_REFERENCE } from '../../modules/local/circexplorer2/reference' include { CIRCEXPLORER2_PARSE as MAPSPLICE_PARSE } from '../../modules/nf-core/circexplorer2/parse' include { CIRCEXPLORER2_ANNOTATE as MAPSPLICE_ANNOTATE } from '../../modules/nf-core/circexplorer2/annotate' @@ -38,8 +34,9 @@ include { BEDTOOLS_GETFASTA } from '../../modules/n include { GAWK as ADD_BACKSPLICE } from '../../modules/nf-core/gawk' // SUBWORKFLOWS -include { SEGEMEHL } from './discovery/segemehl' -include { STAR2PASS } from './discovery/star2pass' +include { SEGEMEHL } from './discovery/segemehl' +include { STAR2PASS } from './discovery/star2pass' +include { CIRCEXPLORER2 } from './discovery/circexplorer2' workflow CIRCRNA_DISCOVERY { @@ -75,24 +72,11 @@ workflow CIRCRNA_DISCOVERY { tools = params.tool.split(',').collect{it.trim().toLowerCase()} SEGEMEHL( reads, fasta, params.segemehl, bsj_reads ) STAR2PASS( reads, star_index, ch_gtf, bsj_reads, star_ignore_sjdbgtf, seq_center, seq_platform ) + CIRCEXPLORER2( gtf, fasta, STAR2PASS.out.junction, bsj_reads ) ch_versions = ch_versions.mix(SEGEMEHL.out.versions) ch_versions = ch_versions.mix(STAR2PASS.out.versions) - - // - // CIRCEXPLORER2 WORKFLOW: - // - - CIRCEXPLORER2_REF( gtf ) - CIRCEXPLORER2_PAR( STAR2PASS.out.junction ) - CIRCEXPLORER2_ANN( CIRCEXPLORER2_PAR.out.junction, fasta, CIRCEXPLORER2_REF.out.txt ) - circexplorer2_filter = CIRCEXPLORER2_ANN.out.txt.map{ meta, txt -> [ meta + [tool: "circexplorer2"], txt ] } - CIRCEXPLORER2_FLT( circexplorer2_filter, bsj_reads ) - - ch_versions = ch_versions.mix(CIRCEXPLORER2_REF.out.versions) - ch_versions = ch_versions.mix(CIRCEXPLORER2_PAR.out.versions) - ch_versions = ch_versions.mix(CIRCEXPLORER2_ANN.out.versions) - ch_versions = ch_versions.mix(CIRCEXPLORER2_FLT.out.versions) + ch_versions = ch_versions.mix(CIRCEXPLORER2.out.versions) // // CIRCRNA_FINDER WORKFLOW: @@ -194,7 +178,7 @@ workflow CIRCRNA_DISCOVERY { // COUNT MATRIX WORKFLOW: // - ch_matrix = CIRCEXPLORER2_FLT.out.matrix.mix(SEGEMEHL.out.matrix, + ch_matrix = CIRCEXPLORER2.out.matrix.mix(SEGEMEHL.out.matrix, CIRCRNA_FINDER_FILTER.out.matrix, FIND_CIRC_FILTER.out.matrix, CIRIQUANT_FILTER.out.matrix, @@ -216,7 +200,7 @@ workflow CIRCRNA_DISCOVERY { ch_biotypes = Channel.fromPath("${projectDir}/bin/unwanted_biotypes.txt") - circrna_tools = CIRCEXPLORER2_FLT.out.results.mix(SEGEMEHL.out.results, + circrna_tools = CIRCEXPLORER2.out.results.mix(SEGEMEHL.out.results, CIRCRNA_FINDER_FILTER.out.results, FIND_CIRC_FILTER.out.results, CIRIQUANT_FILTER.out.results, diff --git a/subworkflows/local/discovery/circexplorer2.nf b/subworkflows/local/discovery/circexplorer2.nf new file mode 100644 index 00000000..ce39f039 --- /dev/null +++ b/subworkflows/local/discovery/circexplorer2.nf @@ -0,0 +1,32 @@ +include { CIRCEXPLORER2_REFERENCE as REFERENCE } from '../../../modules/local/circexplorer2/reference' +include { CIRCEXPLORER2_PARSE as PARSE } from '../../../modules/nf-core/circexplorer2/parse' +include { CIRCEXPLORER2_ANNOTATE as ANNOTATE } from '../../../modules/nf-core/circexplorer2/annotate' +include { CIRCEXPLORER2_FILTER as FILTER } from '../../../modules/local/circexplorer2/filter' + +workflow CIRCEXPLORER2 { + take: + gtf + fasta + star_junctions + bsj_reads + + main: + ch_versions = Channel.empty() + + REFERENCE( gtf ) + PARSE( star_junctions ) + ANNOTATE( PARSE.out.junction, fasta, REFERENCE.out.txt ) + FILTER( ANNOTATE.out.txt + .map{ meta, txt -> [ meta + [tool: "circexplorer2"], txt ] }, bsj_reads ) + + ch_versions = ch_versions.mix(REFERENCE.out.versions) + ch_versions = ch_versions.mix(PARSE.out.versions) + ch_versions = ch_versions.mix(ANNOTATE.out.versions) + ch_versions = ch_versions.mix(FILTER.out.versions) + + emit: + matrix = FILTER.out.matrix + results = FILTER.out.results + + versions = ch_versions +} \ No newline at end of file From 14b0f122e0136f2736f5e9e87aa1b5652043ed81 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 08:41:18 +0200 Subject: [PATCH 235/491] Simplify CIRCRNA_FINDER --- conf/modules.config | 2 +- subworkflows/local/circrna_discovery.nf | 23 ++++++---------- .../local/discovery/circrna_finder.nf | 27 +++++++++++++++++++ 3 files changed, 36 insertions(+), 16 deletions(-) create mode 100644 subworkflows/local/discovery/circrna_finder.nf diff --git a/conf/modules.config b/conf/modules.config index fcd3213c..e45acb8e 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -275,7 +275,7 @@ if (!params.skip_trimming) { ] } - withName: CIRCRNA_FINDER_FILTER { + withName: '.*:CIRCRNA_FINDER:FILTER' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circrna_finder') } publishDir = [ path: { "${params.outdir}/circrna_discovery/circrna_finder/intermediates/${meta.id}" }, diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 91a7e2c7..7ae57095 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -12,7 +12,6 @@ include { FIND_CIRC } from '../../modules/l include { FIND_CIRC_FILTER } from '../../modules/local/find_circ/filter' include { CIRIQUANT } from '../../modules/local/ciriquant/ciriquant' include { CIRIQUANT_FILTER } from '../../modules/local/ciriquant/filter' -include { CIRCRNA_FINDER_FILTER } from '../../modules/local/circrna_finder/filter' include { STAR_ALIGN as DCC_MATE1_1ST_PASS } from '../../modules/nf-core/star/align' include { STAR_ALIGN as DCC_MATE1_2ND_PASS } from '../../modules/nf-core/star/align' include { SJDB as DCC_MATE1_SJDB } from '../../modules/local/star/sjdb' @@ -34,9 +33,10 @@ include { BEDTOOLS_GETFASTA } from '../../modules/n include { GAWK as ADD_BACKSPLICE } from '../../modules/nf-core/gawk' // SUBWORKFLOWS -include { SEGEMEHL } from './discovery/segemehl' -include { STAR2PASS } from './discovery/star2pass' -include { CIRCEXPLORER2 } from './discovery/circexplorer2' +include { SEGEMEHL } from './discovery/segemehl' +include { STAR2PASS } from './discovery/star2pass' +include { CIRCEXPLORER2 } from './discovery/circexplorer2' +include { CIRCRNA_FINDER } from './discovery/circrna_finder' workflow CIRCRNA_DISCOVERY { @@ -73,20 +73,13 @@ workflow CIRCRNA_DISCOVERY { SEGEMEHL( reads, fasta, params.segemehl, bsj_reads ) STAR2PASS( reads, star_index, ch_gtf, bsj_reads, star_ignore_sjdbgtf, seq_center, seq_platform ) CIRCEXPLORER2( gtf, fasta, STAR2PASS.out.junction, bsj_reads ) + CIRCRNA_FINDER( fasta, STAR2PASS.out.sam, STAR2PASS.out.junction, STAR2PASS.out.tab, bsj_reads ) ch_versions = ch_versions.mix(SEGEMEHL.out.versions) ch_versions = ch_versions.mix(STAR2PASS.out.versions) ch_versions = ch_versions.mix(CIRCEXPLORER2.out.versions) + ch_versions = ch_versions.mix(CIRCRNA_FINDER.out.versions) - // - // CIRCRNA_FINDER WORKFLOW: - // - - circrna_finder_stage = STAR2PASS.out.sam.join( STAR2PASS.out.junction).join(STAR2PASS.out.tab) - circrna_finder_filter = circrna_finder_stage.map{ meta, sam, junction, tab -> [ meta + [tool: "circrna_finder"], sam, junction, tab ] } - CIRCRNA_FINDER_FILTER( circrna_finder_filter, fasta, bsj_reads ) - - ch_versions = ch_versions.mix(CIRCRNA_FINDER_FILTER.out.versions) // // FIND_CIRC WORKFLOW: @@ -179,7 +172,7 @@ workflow CIRCRNA_DISCOVERY { // ch_matrix = CIRCEXPLORER2.out.matrix.mix(SEGEMEHL.out.matrix, - CIRCRNA_FINDER_FILTER.out.matrix, + CIRCRNA_FINDER.out.matrix, FIND_CIRC_FILTER.out.matrix, CIRIQUANT_FILTER.out.matrix, DCC_FILTER.out.matrix, @@ -201,7 +194,7 @@ workflow CIRCRNA_DISCOVERY { ch_biotypes = Channel.fromPath("${projectDir}/bin/unwanted_biotypes.txt") circrna_tools = CIRCEXPLORER2.out.results.mix(SEGEMEHL.out.results, - CIRCRNA_FINDER_FILTER.out.results, + CIRCRNA_FINDER.out.results, FIND_CIRC_FILTER.out.results, CIRIQUANT_FILTER.out.results, DCC_FILTER.out.results, diff --git a/subworkflows/local/discovery/circrna_finder.nf b/subworkflows/local/discovery/circrna_finder.nf new file mode 100644 index 00000000..b4564b7b --- /dev/null +++ b/subworkflows/local/discovery/circrna_finder.nf @@ -0,0 +1,27 @@ +include { CIRCRNA_FINDER_FILTER as FILTER } from '../../../modules/local/circrna_finder/filter' + +workflow CIRCRNA_FINDER { + take: + fasta + star_sam + star_junctions + star_tab + bsj_reads + + main: + ch_versions = Channel.empty() + + ch_joined = star_sam.join(star_junctions).join(star_tab) + .map{ meta, sam, junction, tab -> + [ meta + [tool: "circrna_finder"], sam, junction, tab ] } + + FILTER( ch_joined, fasta, bsj_reads ) + + ch_versions = ch_versions.mix(FILTER.out.versions) + + emit: + matrix = FILTER.out.matrix + results = FILTER.out.results + + versions = ch_versions +} \ No newline at end of file From 5032443a80f86bbcfd1225ad6ad6df641a8c6ffb Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 08:55:58 +0200 Subject: [PATCH 236/491] Simplify FIND_CIRC --- conf/modules.config | 10 +++--- subworkflows/local/circrna_discovery.nf | 31 +++--------------- subworkflows/local/discovery/find_circ.nf | 39 +++++++++++++++++++++++ 3 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 subworkflows/local/discovery/find_circ.nf diff --git a/conf/modules.config b/conf/modules.config index e45acb8e..f405c3c6 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -286,7 +286,7 @@ if (!params.skip_trimming) { ] } - withName: FIND_CIRC_ALIGN { + withName: '.*:FIND_CIRC:ALIGN' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('find_circ') } ext.args = [ "", "--very-sensitive", @@ -303,7 +303,7 @@ if (!params.skip_trimming) { ] } - withName: SAMTOOLS_VIEW { + withName: '.*:FIND_CIRC:SAMTOOLS_VIEW' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('find_circ') } ext.prefix = { "${meta.id}_unmapped" } ext.args = "-hf 4" @@ -315,7 +315,7 @@ if (!params.skip_trimming) { ] } - withName: FIND_CIRC_ANCHORS { + withName: '.*:FIND_CIRC:ANCHORS' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('find_circ') } publishDir = [ path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, @@ -325,7 +325,7 @@ if (!params.skip_trimming) { ] } - withName: FIND_CIRC { + withName: '.*:FIND_CIRC:RUN' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('find_circ') } publishDir = [ path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, @@ -335,7 +335,7 @@ if (!params.skip_trimming) { ] } - withName: FIND_CIRC_FILTER { + withName: '.*:FIND_CIRC:FILTER' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('find_circ') } publishDir = [ path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 7ae57095..9249319a 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -4,12 +4,6 @@ include { GNU_SORT as COMBINE_ANNOTATION_BEDS } from '../../modules/n include { GNU_SORT as COMBINE_ANNOTATION_GTFS } from '../../modules/nf-core/gnu/sort' include { GAWK as REMOVE_SCORE_STRAND } from '../../modules/nf-core/gawk' include { BEDTOOLS_INTERSECT as INTERSECT_ANNOTATION } from '../../modules/nf-core/bedtools/intersect' -include { BOWTIE2_ALIGN as FIND_CIRC_ALIGN } from '../../modules/nf-core/bowtie2/align' -include { SAMTOOLS_VIEW } from '../../modules/nf-core/samtools/view' -include { SAMTOOLS_INDEX } from '../../modules/nf-core/samtools/index' -include { FIND_CIRC_ANCHORS } from '../../modules/local/find_circ/anchors' -include { FIND_CIRC } from '../../modules/local/find_circ/find_circ' -include { FIND_CIRC_FILTER } from '../../modules/local/find_circ/filter' include { CIRIQUANT } from '../../modules/local/ciriquant/ciriquant' include { CIRIQUANT_FILTER } from '../../modules/local/ciriquant/filter' include { STAR_ALIGN as DCC_MATE1_1ST_PASS } from '../../modules/nf-core/star/align' @@ -37,6 +31,7 @@ include { SEGEMEHL } from './discovery/segemehl' include { STAR2PASS } from './discovery/star2pass' include { CIRCEXPLORER2 } from './discovery/circexplorer2' include { CIRCRNA_FINDER } from './discovery/circrna_finder' +include { FIND_CIRC } from './discovery/find_circ' workflow CIRCRNA_DISCOVERY { @@ -74,31 +69,13 @@ workflow CIRCRNA_DISCOVERY { STAR2PASS( reads, star_index, ch_gtf, bsj_reads, star_ignore_sjdbgtf, seq_center, seq_platform ) CIRCEXPLORER2( gtf, fasta, STAR2PASS.out.junction, bsj_reads ) CIRCRNA_FINDER( fasta, STAR2PASS.out.sam, STAR2PASS.out.junction, STAR2PASS.out.tab, bsj_reads ) + FIND_CIRC( reads, bowtie2_index, ch_fasta, bsj_reads ) ch_versions = ch_versions.mix(SEGEMEHL.out.versions) ch_versions = ch_versions.mix(STAR2PASS.out.versions) ch_versions = ch_versions.mix(CIRCEXPLORER2.out.versions) ch_versions = ch_versions.mix(CIRCRNA_FINDER.out.versions) - - - // - // FIND_CIRC WORKFLOW: - // - - FIND_CIRC_ALIGN( reads, bowtie2_index, ch_fasta, false, true ) - SAMTOOLS_INDEX( FIND_CIRC_ALIGN.out.bam ) - SAMTOOLS_VIEW( FIND_CIRC_ALIGN.out.bam.join( SAMTOOLS_INDEX.out.bai ), ch_fasta, [] ) - FIND_CIRC_ANCHORS( SAMTOOLS_VIEW.out.bam ) - FIND_CIRC( FIND_CIRC_ANCHORS.out.anchors, bowtie2_index, fasta ) - find_circ_filter = FIND_CIRC.out.bed.map{ meta, bed -> [ meta + [tool: "find_circ"], bed ] } - FIND_CIRC_FILTER( find_circ_filter, bsj_reads ) - - ch_versions = ch_versions.mix(FIND_CIRC_ALIGN.out.versions) - ch_versions = ch_versions.mix(SAMTOOLS_INDEX.out.versions) - ch_versions = ch_versions.mix(SAMTOOLS_VIEW.out.versions) - ch_versions = ch_versions.mix(FIND_CIRC_ANCHORS.out.versions) ch_versions = ch_versions.mix(FIND_CIRC.out.versions) - ch_versions = ch_versions.mix(FIND_CIRC_FILTER.out.versions) // // CIRIQUANT WORKFLOW: @@ -173,7 +150,7 @@ workflow CIRCRNA_DISCOVERY { ch_matrix = CIRCEXPLORER2.out.matrix.mix(SEGEMEHL.out.matrix, CIRCRNA_FINDER.out.matrix, - FIND_CIRC_FILTER.out.matrix, + FIND_CIRC.out.matrix, CIRIQUANT_FILTER.out.matrix, DCC_FILTER.out.matrix, MAPSPLICE_FILTER.out.matrix) @@ -195,7 +172,7 @@ workflow CIRCRNA_DISCOVERY { circrna_tools = CIRCEXPLORER2.out.results.mix(SEGEMEHL.out.results, CIRCRNA_FINDER.out.results, - FIND_CIRC_FILTER.out.results, + FIND_CIRC.out.results, CIRIQUANT_FILTER.out.results, DCC_FILTER.out.results, MAPSPLICE_FILTER.out.results) diff --git a/subworkflows/local/discovery/find_circ.nf b/subworkflows/local/discovery/find_circ.nf new file mode 100644 index 00000000..d8d0a14c --- /dev/null +++ b/subworkflows/local/discovery/find_circ.nf @@ -0,0 +1,39 @@ +include { BOWTIE2_ALIGN as ALIGN } from '../../../modules/nf-core/bowtie2/align' +include { SAMTOOLS_VIEW } from '../../../modules/nf-core/samtools/view' +include { SAMTOOLS_INDEX } from '../../../modules/nf-core/samtools/index' +include { FIND_CIRC_ANCHORS as ANCHORS } from '../../../modules/local/find_circ/anchors' +include { FIND_CIRC as RUN } from '../../../modules/local/find_circ/find_circ' +include { FIND_CIRC_FILTER as FILTER } from '../../../modules/local/find_circ/filter' + + +workflow FIND_CIRC { + take: + reads + bowtie2_index + ch_fasta + bsj_reads + + main: + ch_versions = Channel.empty() + + ALIGN( reads, bowtie2_index, ch_fasta, false, true ) + SAMTOOLS_INDEX( ALIGN.out.bam ) + SAMTOOLS_VIEW( ALIGN.out.bam.join( SAMTOOLS_INDEX.out.bai ), ch_fasta, [] ) + ANCHORS( SAMTOOLS_VIEW.out.bam ) + RUN( ANCHORS.out.anchors, bowtie2_index, ch_fasta.map{ meta, fasta -> fasta } ) + FILTER( RUN.out.bed.map{ meta, bed -> + [ meta + [tool: "find_circ"], bed ] }, bsj_reads ) + + ch_versions = ch_versions.mix(ALIGN.out.versions) + ch_versions = ch_versions.mix(SAMTOOLS_INDEX.out.versions) + ch_versions = ch_versions.mix(SAMTOOLS_VIEW.out.versions) + ch_versions = ch_versions.mix(ANCHORS.out.versions) + ch_versions = ch_versions.mix(RUN.out.versions) + ch_versions = ch_versions.mix(FILTER.out.versions) + + emit: + matrix = FILTER.out.matrix + results = FILTER.out.results + + versions = ch_versions +} \ No newline at end of file From bb73664bb526f1dea2d4b0d60720724e47fc4b47 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 09:03:42 +0200 Subject: [PATCH 237/491] Simplify CIRIQUANT --- conf/modules.config | 4 ++-- subworkflows/local/circrna_discovery.nf | 19 ++++----------- subworkflows/local/discovery/ciriquant.nf | 28 +++++++++++++++++++++++ 3 files changed, 34 insertions(+), 17 deletions(-) create mode 100644 subworkflows/local/discovery/ciriquant.nf diff --git a/conf/modules.config b/conf/modules.config index f405c3c6..496763cb 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -346,7 +346,7 @@ if (!params.skip_trimming) { ] } - withName: CIRIQUANT { + withName: '.*:CIRIQUANT:RUN' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('ciriquant') } publishDir = [ path: { "${params.outdir}/circrna_discovery/ciriquant/intermediates/${meta.id}" }, @@ -356,7 +356,7 @@ if (!params.skip_trimming) { ] } - withName: CIRIQUANT_FILTER { + withName: '.*:CIRIQUANT:FILTER' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('ciriquant') } publishDir = [ path: { "${params.outdir}/circrna_discovery/ciriquant/intermediates/${meta.id}" }, diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 9249319a..5216240a 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -4,8 +4,6 @@ include { GNU_SORT as COMBINE_ANNOTATION_BEDS } from '../../modules/n include { GNU_SORT as COMBINE_ANNOTATION_GTFS } from '../../modules/nf-core/gnu/sort' include { GAWK as REMOVE_SCORE_STRAND } from '../../modules/nf-core/gawk' include { BEDTOOLS_INTERSECT as INTERSECT_ANNOTATION } from '../../modules/nf-core/bedtools/intersect' -include { CIRIQUANT } from '../../modules/local/ciriquant/ciriquant' -include { CIRIQUANT_FILTER } from '../../modules/local/ciriquant/filter' include { STAR_ALIGN as DCC_MATE1_1ST_PASS } from '../../modules/nf-core/star/align' include { STAR_ALIGN as DCC_MATE1_2ND_PASS } from '../../modules/nf-core/star/align' include { SJDB as DCC_MATE1_SJDB } from '../../modules/local/star/sjdb' @@ -32,6 +30,7 @@ include { STAR2PASS } from './discovery/star2pass' include { CIRCEXPLORER2 } from './discovery/circexplorer2' include { CIRCRNA_FINDER } from './discovery/circrna_finder' include { FIND_CIRC } from './discovery/find_circ' +include { CIRIQUANT } from './discovery/ciriquant' workflow CIRCRNA_DISCOVERY { @@ -70,24 +69,14 @@ workflow CIRCRNA_DISCOVERY { CIRCEXPLORER2( gtf, fasta, STAR2PASS.out.junction, bsj_reads ) CIRCRNA_FINDER( fasta, STAR2PASS.out.sam, STAR2PASS.out.junction, STAR2PASS.out.tab, bsj_reads ) FIND_CIRC( reads, bowtie2_index, ch_fasta, bsj_reads ) + CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index, bsj_reads ) ch_versions = ch_versions.mix(SEGEMEHL.out.versions) ch_versions = ch_versions.mix(STAR2PASS.out.versions) ch_versions = ch_versions.mix(CIRCEXPLORER2.out.versions) ch_versions = ch_versions.mix(CIRCRNA_FINDER.out.versions) ch_versions = ch_versions.mix(FIND_CIRC.out.versions) - - // - // CIRIQUANT WORKFLOW: - // - - // only need path to bwa, only need path to hisat2. - // do not want to upset the collect declr for all indices just for this. - CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index ) - CIRIQUANT_FILTER( CIRIQUANT.out.gtf.map{ meta, gtf -> [ meta + [tool: "ciriquant"], gtf ] }, bsj_reads ) - ch_versions = ch_versions.mix(CIRIQUANT.out.versions) - ch_versions = ch_versions.mix(CIRIQUANT_FILTER.out.versions) // // DCC WORKFLOW @@ -151,7 +140,7 @@ workflow CIRCRNA_DISCOVERY { ch_matrix = CIRCEXPLORER2.out.matrix.mix(SEGEMEHL.out.matrix, CIRCRNA_FINDER.out.matrix, FIND_CIRC.out.matrix, - CIRIQUANT_FILTER.out.matrix, + CIRIQUANT.out.matrix, DCC_FILTER.out.matrix, MAPSPLICE_FILTER.out.matrix) @@ -173,7 +162,7 @@ workflow CIRCRNA_DISCOVERY { circrna_tools = CIRCEXPLORER2.out.results.mix(SEGEMEHL.out.results, CIRCRNA_FINDER.out.results, FIND_CIRC.out.results, - CIRIQUANT_FILTER.out.results, + CIRIQUANT.out.results, DCC_FILTER.out.results, MAPSPLICE_FILTER.out.results) diff --git a/subworkflows/local/discovery/ciriquant.nf b/subworkflows/local/discovery/ciriquant.nf new file mode 100644 index 00000000..b4e4c381 --- /dev/null +++ b/subworkflows/local/discovery/ciriquant.nf @@ -0,0 +1,28 @@ +include { CIRIQUANT as RUN } from '../../../modules/local/ciriquant/ciriquant' +include { CIRIQUANT_FILTER as FILTER } from '../../../modules/local/ciriquant/filter' + +workflow CIRIQUANT { + take: + reads + ch_gtf + ch_fasta + bwa_index + hisat2_index + bsj_reads + + main: + ch_versions = Channel.empty() + + RUN( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index ) + FILTER( RUN.out.gtf.map{ meta, gtf -> + [ meta + [tool: "ciriquant"], gtf ] }, bsj_reads ) + + ch_versions = ch_versions.mix(RUN.out.versions) + ch_versions = ch_versions.mix(FILTER.out.versions) + + emit: + matrix = FILTER.out.matrix + results = FILTER.out.results + + versions = ch_versions +} \ No newline at end of file From 3491bed6acdda18c1b2bb1c1f64ceaefc5c444f3 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 09:17:42 +0200 Subject: [PATCH 238/491] Simplify DCC --- conf/modules.config | 14 ++--- subworkflows/local/circrna_discovery.nf | 52 ++----------------- subworkflows/local/discovery/dcc.nf | 68 +++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 54 deletions(-) create mode 100644 subworkflows/local/discovery/dcc.nf diff --git a/conf/modules.config b/conf/modules.config index 496763cb..2848a9d1 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -367,7 +367,7 @@ if (!params.skip_trimming) { ] } - withName: DCC_MATE1_1ST_PASS { + withName: '.*:DCC:MATE1_1ST_PASS' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } ext.prefix = { "${meta.id}_mate1" } ext.args = [ "", @@ -389,7 +389,7 @@ if (!params.skip_trimming) { ] } - withName: DCC_MATE1_SJDB { + withName: '.*:DCC:MATE1_SJDB' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate1/sjdb" }, @@ -399,7 +399,7 @@ if (!params.skip_trimming) { ] } - withName: DCC_MATE1_2ND_PASS { + withName: '.*:DCC:MATE1_2ND_PASS' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } ext.prefix = { "${meta.id}_mate1" } ext.args = [ "", @@ -422,7 +422,7 @@ if (!params.skip_trimming) { ] } - withName: DCC_MATE2_1ST_PASS { + withName: '.*:DCC:MATE2_1ST_PASS' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } ext.prefix = { "${meta.id}_mate2" } ext.args = [ "", @@ -444,7 +444,7 @@ if (!params.skip_trimming) { ] } - withName: DCC_MATE2_SJDB { + withName: '.*:DCC:MATE2_SJDB' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate2/sjdb" }, @@ -454,7 +454,7 @@ if (!params.skip_trimming) { ] } - withName: DCC_MATE2_2ND_PASS { + withName: '.*:DCC:MATE2_2ND_PASS' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } ext.prefix = { "${meta.id}_mate2" } ext.args = [ "", @@ -477,7 +477,7 @@ if (!params.skip_trimming) { ] } - withName: DCC { + withName: '.*:DCC:RUN' { ext.when = { params.tool.split(',').contains('dcc') && params.module.split(',').contains('circrna_discovery') } publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/${meta.id}" }, diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 5216240a..eaa03e61 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -4,14 +4,6 @@ include { GNU_SORT as COMBINE_ANNOTATION_BEDS } from '../../modules/n include { GNU_SORT as COMBINE_ANNOTATION_GTFS } from '../../modules/nf-core/gnu/sort' include { GAWK as REMOVE_SCORE_STRAND } from '../../modules/nf-core/gawk' include { BEDTOOLS_INTERSECT as INTERSECT_ANNOTATION } from '../../modules/nf-core/bedtools/intersect' -include { STAR_ALIGN as DCC_MATE1_1ST_PASS } from '../../modules/nf-core/star/align' -include { STAR_ALIGN as DCC_MATE1_2ND_PASS } from '../../modules/nf-core/star/align' -include { SJDB as DCC_MATE1_SJDB } from '../../modules/local/star/sjdb' -include { STAR_ALIGN as DCC_MATE2_1ST_PASS } from '../../modules/nf-core/star/align' -include { STAR_ALIGN as DCC_MATE2_2ND_PASS } from '../../modules/nf-core/star/align' -include { SJDB as DCC_MATE2_SJDB } from '../../modules/local/star/sjdb' -include { DCC } from '../../modules/local/dcc/dcc' -include { DCC_FILTER } from '../../modules/local/dcc/filter' include { MAPSPLICE_ALIGN } from '../../modules/local/mapsplice/align' include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools' include { COUNTS_COMBINED } from '../../modules/local/count_matrix/combined' @@ -31,6 +23,7 @@ include { CIRCEXPLORER2 } from './discovery/circexplorer2' include { CIRCRNA_FINDER } from './discovery/circrna_finder' include { FIND_CIRC } from './discovery/find_circ' include { CIRIQUANT } from './discovery/ciriquant' +include { DCC } from './discovery/dcc' workflow CIRCRNA_DISCOVERY { @@ -70,6 +63,7 @@ workflow CIRCRNA_DISCOVERY { CIRCRNA_FINDER( fasta, STAR2PASS.out.sam, STAR2PASS.out.junction, STAR2PASS.out.tab, bsj_reads ) FIND_CIRC( reads, bowtie2_index, ch_fasta, bsj_reads ) CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index, bsj_reads ) + DCC( reads, ch_fasta, ch_gtf, star_index, STAR2PASS.out.junction, star_ignore_sjdbgtf, seq_platform, seq_center, bsj_reads ) ch_versions = ch_versions.mix(SEGEMEHL.out.versions) ch_versions = ch_versions.mix(STAR2PASS.out.versions) @@ -77,44 +71,8 @@ workflow CIRCRNA_DISCOVERY { ch_versions = ch_versions.mix(CIRCRNA_FINDER.out.versions) ch_versions = ch_versions.mix(FIND_CIRC.out.versions) ch_versions = ch_versions.mix(CIRIQUANT.out.versions) - - // - // DCC WORKFLOW - // - - mate1 = reads.filter{ meta, reads -> !meta.single_end }.map{ meta, reads -> return [ [id: meta.id, single_end: true], reads[0] ] } - DCC_MATE1_1ST_PASS( mate1, star_index, ch_gtf, star_ignore_sjdbgtf, seq_platform, seq_center ) - DCC_MATE1_SJDB( DCC_MATE1_1ST_PASS.out.tab.map{ meta, tab -> return tab }.collect().map{[[id: "mate1_sjdb"], it]}, bsj_reads ) - DCC_MATE1_2ND_PASS( mate1, star_index, DCC_MATE1_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) - - mate2 = reads.filter{ meta, reads -> !meta.single_end }.map{ meta, reads -> return [ [id: meta.id, single_end: true], reads[1] ] } - DCC_MATE2_1ST_PASS( mate2, star_index, ch_gtf, star_ignore_sjdbgtf, seq_platform, seq_center ) - DCC_MATE2_SJDB( DCC_MATE2_1ST_PASS.out.tab.map{ meta, tab -> return tab }.collect().map{[[id: "mate2_sjdb"], it]}, bsj_reads ) - DCC_MATE2_2ND_PASS( mate2, star_index, DCC_MATE2_SJDB.out.sjtab, star_ignore_sjdbgtf, seq_platform, seq_center ) - - dcc_stage = STAR2PASS.out.junction.map{ meta, junction -> return [ meta.id, meta, junction]} - .join( - DCC_MATE1_2ND_PASS.out.junction.map{ meta, junction -> return [ meta.id, junction] }, - remainder: true - ) - .join( - DCC_MATE2_2ND_PASS.out.junction.map{ meta, junction -> return [ meta.id, junction] }, - remainder: true - ) - .map{ id, meta, junction, mate1, mate2 -> return [ meta, junction, mate1, mate2 ]} - - dcc = dcc_stage.map{ it -> [ it[0], it[1], it[2] ?: [], it[3] ?: [] ] } - DCC( dcc, fasta, gtf ) - DCC_FILTER( DCC.out.txt.map{ meta, txt -> [ meta + [tool: "dcc"], txt ] }, bsj_reads ) - - ch_versions = ch_versions.mix(DCC_MATE1_1ST_PASS.out.versions) - ch_versions = ch_versions.mix(DCC_MATE1_SJDB.out.versions) - ch_versions = ch_versions.mix(DCC_MATE1_2ND_PASS.out.versions) - ch_versions = ch_versions.mix(DCC_MATE2_1ST_PASS.out.versions) - ch_versions = ch_versions.mix(DCC_MATE2_SJDB.out.versions) - ch_versions = ch_versions.mix(DCC_MATE2_2ND_PASS.out.versions) ch_versions = ch_versions.mix(DCC.out.versions) - ch_versions = ch_versions.mix(DCC_FILTER.out.versions) + // // MAPSPLICE WORKFLOW: @@ -141,7 +99,7 @@ workflow CIRCRNA_DISCOVERY { CIRCRNA_FINDER.out.matrix, FIND_CIRC.out.matrix, CIRIQUANT.out.matrix, - DCC_FILTER.out.matrix, + DCC.out.matrix, MAPSPLICE_FILTER.out.matrix) tools_selected = params.tool.split(',').collect{it.trim().toLowerCase()} @@ -163,7 +121,7 @@ workflow CIRCRNA_DISCOVERY { CIRCRNA_FINDER.out.results, FIND_CIRC.out.results, CIRIQUANT.out.results, - DCC_FILTER.out.results, + DCC.out.results, MAPSPLICE_FILTER.out.results) UPSET_SAMPLES( circrna_tools.map{ meta, bed -> [meta.id, meta.tool, bed]} diff --git a/subworkflows/local/discovery/dcc.nf b/subworkflows/local/discovery/dcc.nf new file mode 100644 index 00000000..96ccca6b --- /dev/null +++ b/subworkflows/local/discovery/dcc.nf @@ -0,0 +1,68 @@ +include { STAR_ALIGN as MATE1_1ST_PASS } from '../../../modules/nf-core/star/align' +include { STAR_ALIGN as MATE1_2ND_PASS } from '../../../modules/nf-core/star/align' +include { SJDB as MATE1_SJDB } from '../../../modules/local/star/sjdb' +include { STAR_ALIGN as MATE2_1ST_PASS } from '../../../modules/nf-core/star/align' +include { STAR_ALIGN as MATE2_2ND_PASS } from '../../../modules/nf-core/star/align' +include { SJDB as MATE2_SJDB } from '../../../modules/local/star/sjdb' +include { DCC as RUN } from '../../../modules/local/dcc/dcc' +include { DCC_FILTER as FILTER } from '../../../modules/local/dcc/filter' + +workflow DCC { + take: + reads + ch_fasta + ch_gtf + star_index + star_junction + ignore_sjdbgtf + seq_platform + seq_center + bsj_reads + + main: + ch_versions = Channel.empty() + + mate1 = reads.filter{ meta, reads -> !meta.single_end } + .map{ meta, reads -> return [ [id: meta.id, single_end: true], reads[0] ] } + MATE1_1ST_PASS( mate1, star_index, ch_gtf, ignore_sjdbgtf, seq_platform, seq_center ) + MATE1_SJDB( MATE1_1ST_PASS.out.tab + .map{ meta, tab -> return tab }.collect().map{[[id: "mate1_sjdb"], it]}, bsj_reads ) + MATE1_2ND_PASS( mate1, star_index, MATE1_SJDB.out.sjtab, ignore_sjdbgtf, seq_platform, seq_center ) + + mate2 = reads.filter{ meta, reads -> !meta.single_end } + .map{ meta, reads -> return [ [id: meta.id, single_end: true], reads[1] ] } + MATE2_1ST_PASS( mate2, star_index, ch_gtf, ignore_sjdbgtf, seq_platform, seq_center ) + MATE2_SJDB( MATE2_1ST_PASS.out.tab + .map{ meta, tab -> return tab }.collect().map{[[id: "mate2_sjdb"], it]}, bsj_reads ) + MATE2_2ND_PASS( mate2, star_index, MATE2_SJDB.out.sjtab, ignore_sjdbgtf, seq_platform, seq_center ) + + dcc_stage = star_junction.map{ meta, junction -> return [ meta.id, meta, junction]} + .join( + MATE1_2ND_PASS.out.junction.map{ meta, junction -> return [ meta.id, junction] }, + remainder: true + ) + .join( + MATE2_2ND_PASS.out.junction.map{ meta, junction -> return [ meta.id, junction] }, + remainder: true + ) + .map{ id, meta, junction, mate1, mate2 -> return [ meta, junction, mate1, mate2 ]} + + dcc = dcc_stage.map{ it -> [ it[0], it[1], it[2] ?: [], it[3] ?: [] ] } + RUN( dcc, ch_fasta.map{ meta, fasta -> fasta }, ch_gtf.map{ meta, gtf -> gtf } ) + FILTER( RUN.out.txt.map{ meta, txt -> [ meta + [tool: "dcc"], txt ] }, bsj_reads ) + + ch_versions = ch_versions.mix(MATE1_1ST_PASS.out.versions) + ch_versions = ch_versions.mix(MATE1_SJDB.out.versions) + ch_versions = ch_versions.mix(MATE1_2ND_PASS.out.versions) + ch_versions = ch_versions.mix(MATE2_1ST_PASS.out.versions) + ch_versions = ch_versions.mix(MATE2_SJDB.out.versions) + ch_versions = ch_versions.mix(MATE2_2ND_PASS.out.versions) + ch_versions = ch_versions.mix(RUN.out.versions) + ch_versions = ch_versions.mix(FILTER.out.versions) + + emit: + matrix = FILTER.out.matrix + results = FILTER.out.results + + versions = ch_versions +} \ No newline at end of file From 6c9eefc2654bbaab8819a07a90c19f4ce002942c Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 09:36:41 +0200 Subject: [PATCH 239/491] Simplify MAPSPLICE --- conf/modules.config | 10 +++--- subworkflows/local/circrna_discovery.nf | 31 +++--------------- subworkflows/local/discovery/mapsplice.nf | 39 +++++++++++++++++++++++ 3 files changed, 49 insertions(+), 31 deletions(-) create mode 100644 subworkflows/local/discovery/mapsplice.nf diff --git a/conf/modules.config b/conf/modules.config index 2848a9d1..fba00b41 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -487,7 +487,7 @@ if (!params.skip_trimming) { ] } - withName: MAPSPLICE_REFERENCE { + withName: '.*:MAPSPLICE:REFERENCE' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } ext.args = [ "", "-genePredExt", @@ -501,7 +501,7 @@ if (!params.skip_trimming) { ] } - withName: MAPSPLICE_ALIGN { + withName: '.*:MAPSPLICE:ALIGN' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } ext.args = [ "", "--seglen ${params.seglen}", @@ -519,7 +519,7 @@ if (!params.skip_trimming) { ] } - withName: MAPSPLICE_PARSE { + withName: '.*:MAPSPLICE:PARSE' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } publishDir = [ path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, @@ -529,7 +529,7 @@ if (!params.skip_trimming) { ] } - withName: MAPSPLICE_ANNOTATE { + withName: '.*:MAPSPLICE:ANNOTATE' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } publishDir = [ path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, @@ -539,7 +539,7 @@ if (!params.skip_trimming) { ] } - withName: MAPSPLICE_FILTER { + withName: '.*:MAPSPLICE:FILTER' { ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } publishDir = [ path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index eaa03e61..09978746 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -4,13 +4,8 @@ include { GNU_SORT as COMBINE_ANNOTATION_BEDS } from '../../modules/n include { GNU_SORT as COMBINE_ANNOTATION_GTFS } from '../../modules/nf-core/gnu/sort' include { GAWK as REMOVE_SCORE_STRAND } from '../../modules/nf-core/gawk' include { BEDTOOLS_INTERSECT as INTERSECT_ANNOTATION } from '../../modules/nf-core/bedtools/intersect' -include { MAPSPLICE_ALIGN } from '../../modules/local/mapsplice/align' include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools' include { COUNTS_COMBINED } from '../../modules/local/count_matrix/combined' -include { CIRCEXPLORER2_REFERENCE as MAPSPLICE_REFERENCE } from '../../modules/local/circexplorer2/reference' -include { CIRCEXPLORER2_PARSE as MAPSPLICE_PARSE } from '../../modules/nf-core/circexplorer2/parse' -include { CIRCEXPLORER2_ANNOTATE as MAPSPLICE_ANNOTATE } from '../../modules/nf-core/circexplorer2/annotate' -include { CIRCEXPLORER2_FILTER as MAPSPLICE_FILTER } from '../../modules/local/circexplorer2/filter' include { UPSET as UPSET_SAMPLES } from '../../modules/local/upset' include { UPSET as UPSET_ALL } from '../../modules/local/upset' include { BEDTOOLS_GETFASTA } from '../../modules/nf-core/bedtools/getfasta' @@ -24,6 +19,7 @@ include { CIRCRNA_FINDER } from './discovery/circrna_finder' include { FIND_CIRC } from './discovery/find_circ' include { CIRIQUANT } from './discovery/ciriquant' include { DCC } from './discovery/dcc' +include { MAPSPLICE } from './discovery/mapsplice' workflow CIRCRNA_DISCOVERY { @@ -56,7 +52,6 @@ workflow CIRCRNA_DISCOVERY { // // DISCOVERY TOOLS: // - tools = params.tool.split(',').collect{it.trim().toLowerCase()} SEGEMEHL( reads, fasta, params.segemehl, bsj_reads ) STAR2PASS( reads, star_index, ch_gtf, bsj_reads, star_ignore_sjdbgtf, seq_center, seq_platform ) CIRCEXPLORER2( gtf, fasta, STAR2PASS.out.junction, bsj_reads ) @@ -64,6 +59,7 @@ workflow CIRCRNA_DISCOVERY { FIND_CIRC( reads, bowtie2_index, ch_fasta, bsj_reads ) CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index, bsj_reads ) DCC( reads, ch_fasta, ch_gtf, star_index, STAR2PASS.out.junction, star_ignore_sjdbgtf, seq_platform, seq_center, bsj_reads ) + MAPSPLICE( reads, gtf, fasta, bowtie_index, chromosomes, STAR2PASS.out.junction, bsj_reads ) ch_versions = ch_versions.mix(SEGEMEHL.out.versions) ch_versions = ch_versions.mix(STAR2PASS.out.versions) @@ -72,24 +68,7 @@ workflow CIRCRNA_DISCOVERY { ch_versions = ch_versions.mix(FIND_CIRC.out.versions) ch_versions = ch_versions.mix(CIRIQUANT.out.versions) ch_versions = ch_versions.mix(DCC.out.versions) - - - // - // MAPSPLICE WORKFLOW: - // - - MAPSPLICE_REFERENCE( gtf ) - MAPSPLICE_ALIGN( reads, bowtie_index, chromosomes, gtf ) - MAPSPLICE_PARSE( MAPSPLICE_ALIGN.out.raw_fusions ) - MAPSPLICE_ANNOTATE( MAPSPLICE_PARSE.out.junction, fasta, MAPSPLICE_REFERENCE.out.txt ) - mapsplice_filter = MAPSPLICE_ANNOTATE.out.txt.map{ meta, txt -> [ meta + [tool: "mapsplice"], txt ] } - MAPSPLICE_FILTER( mapsplice_filter, bsj_reads ) - - ch_versions = ch_versions.mix(MAPSPLICE_REFERENCE.out.versions) - ch_versions = ch_versions.mix(MAPSPLICE_ALIGN.out.versions) - ch_versions = ch_versions.mix(MAPSPLICE_PARSE.out.versions) - ch_versions = ch_versions.mix(MAPSPLICE_ANNOTATE.out.versions) - ch_versions = ch_versions.mix(MAPSPLICE_FILTER.out.versions) + ch_versions = ch_versions.mix(MAPSPLICE.out.versions) // // COUNT MATRIX WORKFLOW: @@ -100,7 +79,7 @@ workflow CIRCRNA_DISCOVERY { FIND_CIRC.out.matrix, CIRIQUANT.out.matrix, DCC.out.matrix, - MAPSPLICE_FILTER.out.matrix) + MAPSPLICE.out.matrix) tools_selected = params.tool.split(',').collect{it.trim().toLowerCase()} @@ -122,7 +101,7 @@ workflow CIRCRNA_DISCOVERY { FIND_CIRC.out.results, CIRIQUANT.out.results, DCC.out.results, - MAPSPLICE_FILTER.out.results) + MAPSPLICE.out.results) UPSET_SAMPLES( circrna_tools.map{ meta, bed -> [meta.id, meta.tool, bed]} .groupTuple() diff --git a/subworkflows/local/discovery/mapsplice.nf b/subworkflows/local/discovery/mapsplice.nf new file mode 100644 index 00000000..d4640047 --- /dev/null +++ b/subworkflows/local/discovery/mapsplice.nf @@ -0,0 +1,39 @@ +include { CIRCEXPLORER2_REFERENCE as REFERENCE } from '../../../modules/local/circexplorer2/reference' +include { MAPSPLICE_ALIGN as ALIGN } from '../../../modules/local/mapsplice/align' +include { CIRCEXPLORER2_PARSE as PARSE } from '../../../modules/nf-core/circexplorer2/parse' +include { CIRCEXPLORER2_ANNOTATE as ANNOTATE } from '../../../modules/nf-core/circexplorer2/annotate' +include { CIRCEXPLORER2_FILTER as FILTER } from '../../../modules/local/circexplorer2/filter' + + +workflow MAPSPLICE { + take: + reads + gtf + fasta + bowtie_index + chromosomes + star_junctions + bsj_reads + + main: + ch_versions = Channel.empty() + + REFERENCE( gtf ) + ALIGN( reads, bowtie_index, chromosomes, gtf ) + PARSE( ALIGN.out.raw_fusions ) + ANNOTATE( PARSE.out.junction, fasta, REFERENCE.out.txt ) + FILTER( ANNOTATE.out.txt.map{ meta, txt -> + [ meta + [tool: "mapsplice"], txt ] }, bsj_reads ) + + ch_versions = ch_versions.mix(REFERENCE.out.versions) + ch_versions = ch_versions.mix(ALIGN.out.versions) + ch_versions = ch_versions.mix(PARSE.out.versions) + ch_versions = ch_versions.mix(ANNOTATE.out.versions) + ch_versions = ch_versions.mix(FILTER.out.versions) + + emit: + matrix = FILTER.out.matrix + results = FILTER.out.results + + versions = ch_versions +} \ No newline at end of file From 291c14e3c4a9e391658f9156f10ec0f6038e473e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 09:50:24 +0200 Subject: [PATCH 240/491] Restructure discovery tool calls --- subworkflows/local/circrna_discovery.nf | 70 ++++++++++++++----------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 09978746..53b99144 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -39,48 +39,65 @@ workflow CIRCRNA_DISCOVERY { exon_boundary main: - ch_versions = Channel.empty() + ch_versions = Channel.empty() + ch_matrix = Channel.empty() + ch_results = Channel.empty() ch_multiqc_files = Channel.empty() - fasta = ch_fasta.map{meta, fasta -> fasta} - gtf = ch_gtf.map{meta, gtf -> gtf} + fasta = ch_fasta.map{meta, fasta -> fasta} + gtf = ch_gtf.map{meta, gtf -> gtf} - // STAR CONSTANT PARAMETERS + // STAR 2-PASS-MODE star_ignore_sjdbgtf = true seq_center = params.seq_center ?: '' seq_platform = '' + STAR2PASS( reads, star_index, ch_gtf, bsj_reads, star_ignore_sjdbgtf, seq_center, seq_platform ) + ch_versions = ch_versions.mix(STAR2PASS.out.versions) // // DISCOVERY TOOLS: // SEGEMEHL( reads, fasta, params.segemehl, bsj_reads ) - STAR2PASS( reads, star_index, ch_gtf, bsj_reads, star_ignore_sjdbgtf, seq_center, seq_platform ) - CIRCEXPLORER2( gtf, fasta, STAR2PASS.out.junction, bsj_reads ) - CIRCRNA_FINDER( fasta, STAR2PASS.out.sam, STAR2PASS.out.junction, STAR2PASS.out.tab, bsj_reads ) - FIND_CIRC( reads, bowtie2_index, ch_fasta, bsj_reads ) - CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index, bsj_reads ) - DCC( reads, ch_fasta, ch_gtf, star_index, STAR2PASS.out.junction, star_ignore_sjdbgtf, seq_platform, seq_center, bsj_reads ) - MAPSPLICE( reads, gtf, fasta, bowtie_index, chromosomes, STAR2PASS.out.junction, bsj_reads ) - ch_versions = ch_versions.mix(SEGEMEHL.out.versions) - ch_versions = ch_versions.mix(STAR2PASS.out.versions) + ch_matrix = ch_matrix .mix(SEGEMEHL.out.matrix) + ch_results = ch_results .mix(SEGEMEHL.out.results) + + CIRCEXPLORER2( gtf, fasta, STAR2PASS.out.junction, bsj_reads ) ch_versions = ch_versions.mix(CIRCEXPLORER2.out.versions) + ch_matrix = ch_matrix .mix(CIRCEXPLORER2.out.matrix) + ch_results = ch_results .mix(CIRCEXPLORER2.out.results) + + CIRCRNA_FINDER( fasta, STAR2PASS.out.sam, STAR2PASS.out.junction, + STAR2PASS.out.tab, bsj_reads ) ch_versions = ch_versions.mix(CIRCRNA_FINDER.out.versions) + ch_matrix = ch_matrix .mix(CIRCRNA_FINDER.out.matrix) + ch_results = ch_results .mix(CIRCRNA_FINDER.out.results) + + FIND_CIRC( reads, bowtie2_index, ch_fasta, bsj_reads ) ch_versions = ch_versions.mix(FIND_CIRC.out.versions) + ch_matrix = ch_matrix .mix(FIND_CIRC.out.matrix) + ch_results = ch_results .mix(FIND_CIRC.out.results) + + CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index, bsj_reads ) ch_versions = ch_versions.mix(CIRIQUANT.out.versions) + ch_matrix = ch_matrix.mix(CIRIQUANT.out.matrix) + ch_results = ch_results.mix(CIRIQUANT.out.results) + + DCC( reads, ch_fasta, ch_gtf, star_index, STAR2PASS.out.junction, + star_ignore_sjdbgtf, seq_platform, seq_center, bsj_reads ) ch_versions = ch_versions.mix(DCC.out.versions) + ch_matrix = ch_matrix.mix(DCC.out.matrix) + ch_results = ch_results.mix(DCC.out.results) + + MAPSPLICE( reads, gtf, fasta, bowtie_index, chromosomes, + STAR2PASS.out.junction, bsj_reads ) ch_versions = ch_versions.mix(MAPSPLICE.out.versions) + ch_matrix = ch_matrix.mix(MAPSPLICE.out.matrix) + ch_results = ch_results.mix(MAPSPLICE.out.results) // // COUNT MATRIX WORKFLOW: // - ch_matrix = CIRCEXPLORER2.out.matrix.mix(SEGEMEHL.out.matrix, - CIRCRNA_FINDER.out.matrix, - FIND_CIRC.out.matrix, - CIRIQUANT.out.matrix, - DCC.out.matrix, - MAPSPLICE.out.matrix) - tools_selected = params.tool.split(',').collect{it.trim().toLowerCase()} MERGE_TOOLS( ch_matrix.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), @@ -96,17 +113,10 @@ workflow CIRCRNA_DISCOVERY { ch_biotypes = Channel.fromPath("${projectDir}/bin/unwanted_biotypes.txt") - circrna_tools = CIRCEXPLORER2.out.results.mix(SEGEMEHL.out.results, - CIRCRNA_FINDER.out.results, - FIND_CIRC.out.results, - CIRIQUANT.out.results, - DCC.out.results, - MAPSPLICE.out.results) - - UPSET_SAMPLES( circrna_tools.map{ meta, bed -> [meta.id, meta.tool, bed]} + UPSET_SAMPLES( ch_results.map{ meta, bed -> [meta.id, meta.tool, bed]} .groupTuple() .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) - UPSET_ALL( circrna_tools.map{ meta, bed -> ["all", meta.tool, bed] } + UPSET_ALL( ch_results.map{ meta, bed -> ["all", meta.tool, bed] } .groupTuple() .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) @@ -115,7 +125,7 @@ workflow CIRCRNA_DISCOVERY { ch_versions = ch_versions.mix(UPSET_SAMPLES.out.versions) ch_versions = ch_versions.mix(UPSET_ALL.out.versions) - circrna_incl_merged = circrna_tools.mix( + circrna_incl_merged = ch_results.mix( MERGE_TOOLS.out.merged.map{ meta, bed -> [meta + [tool: "merged"], bed] }) INTERSECT_ANNOTATION( circrna_incl_merged.combine(gtf), [[], []]) From 5fa979b254e04bd2b1bfdb7273a792279d9e83f5 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 10:08:33 +0200 Subject: [PATCH 241/491] Restructure discovery downstream workflows --- subworkflows/local/circrna_discovery.nf | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 53b99144..324eb223 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -95,7 +95,7 @@ workflow CIRCRNA_DISCOVERY { ch_results = ch_results.mix(MAPSPLICE.out.results) // - // COUNT MATRIX WORKFLOW: + // CREATE COUNT MATRIX // tools_selected = params.tool.split(',').collect{it.trim().toLowerCase()} @@ -108,11 +108,9 @@ workflow CIRCRNA_DISCOVERY { ch_versions = ch_versions.mix(COUNTS_COMBINED.out.versions) // - // ANNOTATION WORKFLOW: + // UPSET PLOTS // - ch_biotypes = Channel.fromPath("${projectDir}/bin/unwanted_biotypes.txt") - UPSET_SAMPLES( ch_results.map{ meta, bed -> [meta.id, meta.tool, bed]} .groupTuple() .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) @@ -125,6 +123,10 @@ workflow CIRCRNA_DISCOVERY { ch_versions = ch_versions.mix(UPSET_SAMPLES.out.versions) ch_versions = ch_versions.mix(UPSET_ALL.out.versions) + // + // ANNOTATION WORKFLOW: + // + circrna_incl_merged = ch_results.mix( MERGE_TOOLS.out.merged.map{ meta, bed -> [meta + [tool: "merged"], bed] }) From a7465489e0934293ae8993b3ad3711fbfdb19124 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 10:23:50 +0200 Subject: [PATCH 242/491] Simplify annotation workflow --- conf/modules.config | 8 ++-- subworkflows/local/circrna_discovery.nf | 47 +++++++--------------- subworkflows/local/discovery/annotation.nf | 38 +++++++++++++++++ 3 files changed, 57 insertions(+), 36 deletions(-) create mode 100644 subworkflows/local/discovery/annotation.nf diff --git a/conf/modules.config b/conf/modules.config index fba00b41..5cf8f43b 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -567,22 +567,22 @@ if (!params.skip_trimming) { ext.when = { params.tool.split(',').length > 1 } } - withName: INTERSECT_ANNOTATION { + withName: '.*:ANNOTATION:INTERSECT' { ext.args = "-loj" ext.suffix = "intersect.bed" } - withName: COMBINE_ANNOTATION_BEDS { + withName: '.*:ANNOTATION:COMBINE_BEDS' { ext.args = "-k 1,1 -k2,2n -k3,3n -u" ext.suffix = "combined.bed" } - withName: COMBINE_ANNOTATION_GTFS { + withName: '.*:ANNOTATION:COMBINE_GTFS' { ext.args = "-k 1,1 -k3,3n -k4,4n -u" ext.suffix = "combined.gtf" } - withName: REMOVE_SCORE_STRAND { + withName: '.*:ANNOTATION:REMOVE_SCORE_STRAND' { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3, \".\", \".\", \$7, \$8, \$9, \$10 }'" ext.suffix = "tidy.bed" } diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 324eb223..740dc3a4 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -1,9 +1,4 @@ // MODULES -include { ANNOTATION } from '../../modules/local/annotation/full_annotation' -include { GNU_SORT as COMBINE_ANNOTATION_BEDS } from '../../modules/nf-core/gnu/sort' -include { GNU_SORT as COMBINE_ANNOTATION_GTFS } from '../../modules/nf-core/gnu/sort' -include { GAWK as REMOVE_SCORE_STRAND } from '../../modules/nf-core/gawk' -include { BEDTOOLS_INTERSECT as INTERSECT_ANNOTATION } from '../../modules/nf-core/bedtools/intersect' include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools' include { COUNTS_COMBINED } from '../../modules/local/count_matrix/combined' include { UPSET as UPSET_SAMPLES } from '../../modules/local/upset' @@ -20,6 +15,7 @@ include { FIND_CIRC } from './discovery/find_circ' include { CIRIQUANT } from './discovery/ciriquant' include { DCC } from './discovery/dcc' include { MAPSPLICE } from './discovery/mapsplice' +include { ANNOTATION } from './discovery/annotation' workflow CIRCRNA_DISCOVERY { @@ -104,6 +100,9 @@ workflow CIRCRNA_DISCOVERY { tools_selected.size() > 1 ? tool_filter : 1, duplicates_fun ) COUNTS_COMBINED( MERGE_TOOLS.out.merged.map{ meta, bed -> bed }.collect() ) + ch_results_incl_merged = ch_results.mix( + MERGE_TOOLS.out.merged.map{ meta, bed -> [meta + [tool: "merged"], bed] }) + ch_versions = ch_versions.mix(MERGE_TOOLS.out.versions) ch_versions = ch_versions.mix(COUNTS_COMBINED.out.versions) @@ -127,43 +126,27 @@ workflow CIRCRNA_DISCOVERY { // ANNOTATION WORKFLOW: // - circrna_incl_merged = ch_results.mix( - MERGE_TOOLS.out.merged.map{ meta, bed -> [meta + [tool: "merged"], bed] }) - - INTERSECT_ANNOTATION( circrna_incl_merged.combine(gtf), [[], []]) - ANNOTATION( INTERSECT_ANNOTATION.out.intersect, exon_boundary ) - - ch_annotation_bed_merged = ANNOTATION.out.bed.filter{ meta, bed -> meta.tool == "merged" } - ch_annotation_gtf_merged = ANNOTATION.out.gtf.filter{ meta, gtf -> meta.tool == "merged" } - - COMBINE_ANNOTATION_BEDS(ch_annotation_bed_merged.map{ meta, bed -> bed}.collect().map{[[id: "annotation"], it]}) - REMOVE_SCORE_STRAND( COMBINE_ANNOTATION_BEDS.out.sorted, []) - COMBINE_ANNOTATION_GTFS(ch_annotation_gtf_merged.map{ meta, gtf -> gtf}.collect().map{[[id: "annotation"], it]}) - - ch_versions = ch_versions.mix(INTERSECT_ANNOTATION.out.versions) + ANNOTATION( ch_results_incl_merged, gtf, exon_boundary ) ch_versions = ch_versions.mix(ANNOTATION.out.versions) - ch_versions = ch_versions.mix(COMBINE_ANNOTATION_BEDS.out.versions) - ch_versions = ch_versions.mix(REMOVE_SCORE_STRAND.out.versions) - ch_versions = ch_versions.mix(COMBINE_ANNOTATION_GTFS.out.versions) // // FASTA WORKFLOW: // - BEDTOOLS_GETFASTA( ch_annotation_bed_merged, fasta ) + BEDTOOLS_GETFASTA( ANNOTATION.out.merged_bed, fasta ) ADD_BACKSPLICE( BEDTOOLS_GETFASTA.out.fasta, []) ch_versions = ch_versions.mix(BEDTOOLS_GETFASTA.out.versions) ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) emit: - circrna_bed12 = ch_annotation_bed_merged - fasta = ADD_BACKSPLICE.out.output - annotation_bed = REMOVE_SCORE_STRAND.out.output - annotation_gtf = COMBINE_ANNOTATION_GTFS.out.sorted - counts_bed = COUNTS_COMBINED.out.counts_bed - counts_tsv = COUNTS_COMBINED.out.counts_tsv - - multiqc_files = ch_multiqc_files - versions = ch_versions + circrna_bed12 = ANNOTATION.out.merged_bed + fasta = ADD_BACKSPLICE.out.output + annotation_bed = ANNOTATION.out.bed + annotation_gtf = ANNOTATION.out.gtf + counts_bed = COUNTS_COMBINED.out.counts_bed + counts_tsv = COUNTS_COMBINED.out.counts_tsv + + multiqc_files = ch_multiqc_files + versions = ch_versions } diff --git a/subworkflows/local/discovery/annotation.nf b/subworkflows/local/discovery/annotation.nf new file mode 100644 index 00000000..feded6a5 --- /dev/null +++ b/subworkflows/local/discovery/annotation.nf @@ -0,0 +1,38 @@ +include { BEDTOOLS_INTERSECT as INTERSECT } from '../../../modules/nf-core/bedtools/intersect' +include { ANNOTATION as ANNOTATE } from '../../../modules/local/annotation/full_annotation' +include { GNU_SORT as COMBINE_BEDS } from '../../../modules/nf-core/gnu/sort' +include { GAWK as REMOVE_SCORE_STRAND } from '../../../modules/nf-core/gawk' +include { GNU_SORT as COMBINE_GTFS } from '../../../modules/nf-core/gnu/sort' + +workflow ANNOTATION { + take: + regions + gtf + exon_boundary + + main: + ch_versions = Channel.empty() + + INTERSECT( regions.combine(gtf), [[], []]) + ANNOTATE( INTERSECT.out.intersect, exon_boundary ) + + ch_bed_merged = ANNOTATE.out.bed.filter{ meta, bed -> meta.tool == "merged" } + ch_gtf_merged = ANNOTATE.out.gtf.filter{ meta, gtf -> meta.tool == "merged" } + + COMBINE_BEDS(ch_bed_merged.map{ meta, bed -> bed}.collect().map{[[id: "annotation"], it]}) + REMOVE_SCORE_STRAND( COMBINE_BEDS.out.sorted, []) + COMBINE_GTFS(ch_gtf_merged.map{ meta, gtf -> gtf}.collect().map{[[id: "annotation"], it]}) + + ch_versions = ch_versions.mix(INTERSECT.out.versions) + ch_versions = ch_versions.mix(ANNOTATE.out.versions) + ch_versions = ch_versions.mix(COMBINE_BEDS.out.versions) + ch_versions = ch_versions.mix(REMOVE_SCORE_STRAND.out.versions) + ch_versions = ch_versions.mix(COMBINE_GTFS.out.versions) + + emit: + merged_bed = ch_bed_merged + bed = REMOVE_SCORE_STRAND.out.output + gtf = COMBINE_GTFS.out.sorted + + versions = ch_versions +} \ No newline at end of file From ca5abfaedf5e81760f2bce211f4be0898647aade Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 10:48:01 +0200 Subject: [PATCH 243/491] Change the way discovery tools are disabled --- conf/modules.config | 26 ------- subworkflows/local/circrna_discovery.nf | 96 +++++++++++++++---------- 2 files changed, 57 insertions(+), 65 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 5cf8f43b..781bce3c 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -144,7 +144,6 @@ if (!params.skip_trimming) { } withName: '.*:SEGEMEHL:INDEX' { - ext.when = { !params.segemehl && params.tool.split(',').contains('segemehl') && params.module.split(',').contains('circrna_discovery') } publishDir = [ path: { "${params.outdir}/references/index/segemehl" }, mode: params.publish_dir_mode, @@ -156,7 +155,6 @@ if (!params.skip_trimming) { // circRNA withName: '.*:SEGEMEHL:ALIGN' { - ext.when = { params.tool.split(',').contains('segemehl') && params.module.split(',').contains('circrna_discovery') } ext.args = [ "", "-b", "-S" @@ -231,7 +229,6 @@ if (!params.skip_trimming) { } withName: '.*:CIRCEXPLORER2:REFERENCE' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } ext.args = [ "", "-genePredExt", "-geneNameAsName2" @@ -245,7 +242,6 @@ if (!params.skip_trimming) { } withName: '.*:CIRCEXPLORER2:PARSE' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } publishDir = [ path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -255,7 +251,6 @@ if (!params.skip_trimming) { } withName: '.*:CIRCEXPLORER2:ANNOTATE' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } publishDir = [ path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -265,7 +260,6 @@ if (!params.skip_trimming) { } withName: '.*:CIRCEXPLORER2:FILTER' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circexplorer2') } publishDir = [ path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -276,7 +270,6 @@ if (!params.skip_trimming) { } withName: '.*:CIRCRNA_FINDER:FILTER' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('circrna_finder') } publishDir = [ path: { "${params.outdir}/circrna_discovery/circrna_finder/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -287,7 +280,6 @@ if (!params.skip_trimming) { } withName: '.*:FIND_CIRC:ALIGN' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('find_circ') } ext.args = [ "", "--very-sensitive", "--mm", @@ -304,7 +296,6 @@ if (!params.skip_trimming) { } withName: '.*:FIND_CIRC:SAMTOOLS_VIEW' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('find_circ') } ext.prefix = { "${meta.id}_unmapped" } ext.args = "-hf 4" publishDir = [ @@ -316,7 +307,6 @@ if (!params.skip_trimming) { } withName: '.*:FIND_CIRC:ANCHORS' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('find_circ') } publishDir = [ path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -326,7 +316,6 @@ if (!params.skip_trimming) { } withName: '.*:FIND_CIRC:RUN' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('find_circ') } publishDir = [ path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -336,7 +325,6 @@ if (!params.skip_trimming) { } withName: '.*:FIND_CIRC:FILTER' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('find_circ') } publishDir = [ path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -347,7 +335,6 @@ if (!params.skip_trimming) { } withName: '.*:CIRIQUANT:RUN' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('ciriquant') } publishDir = [ path: { "${params.outdir}/circrna_discovery/ciriquant/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -357,7 +344,6 @@ if (!params.skip_trimming) { } withName: '.*:CIRIQUANT:FILTER' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('ciriquant') } publishDir = [ path: { "${params.outdir}/circrna_discovery/ciriquant/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -368,7 +354,6 @@ if (!params.skip_trimming) { } withName: '.*:DCC:MATE1_1ST_PASS' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } ext.prefix = { "${meta.id}_mate1" } ext.args = [ "", "--chimOutType Junctions WithinBAM", @@ -390,7 +375,6 @@ if (!params.skip_trimming) { } withName: '.*:DCC:MATE1_SJDB' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate1/sjdb" }, mode: params.publish_dir_mode, @@ -400,7 +384,6 @@ if (!params.skip_trimming) { } withName: '.*:DCC:MATE1_2ND_PASS' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } ext.prefix = { "${meta.id}_mate1" } ext.args = [ "", "--chimOutType Junctions WithinBAM", @@ -423,7 +406,6 @@ if (!params.skip_trimming) { } withName: '.*:DCC:MATE2_1ST_PASS' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } ext.prefix = { "${meta.id}_mate2" } ext.args = [ "", "--chimOutType Junctions WithinBAM", @@ -445,7 +427,6 @@ if (!params.skip_trimming) { } withName: '.*:DCC:MATE2_SJDB' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate2/sjdb" }, mode: params.publish_dir_mode, @@ -455,7 +436,6 @@ if (!params.skip_trimming) { } withName: '.*:DCC:MATE2_2ND_PASS' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('dcc') } ext.prefix = { "${meta.id}_mate2" } ext.args = [ "", "--chimOutType Junctions WithinBAM", @@ -478,7 +458,6 @@ if (!params.skip_trimming) { } withName: '.*:DCC:RUN' { - ext.when = { params.tool.split(',').contains('dcc') && params.module.split(',').contains('circrna_discovery') } publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -488,7 +467,6 @@ if (!params.skip_trimming) { } withName: '.*:MAPSPLICE:REFERENCE' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } ext.args = [ "", "-genePredExt", "-geneNameAsName2" @@ -502,7 +480,6 @@ if (!params.skip_trimming) { } withName: '.*:MAPSPLICE:ALIGN' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } ext.args = [ "", "--seglen ${params.seglen}", "--min-intron ${params.min_intron}", @@ -520,7 +497,6 @@ if (!params.skip_trimming) { } withName: '.*:MAPSPLICE:PARSE' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } publishDir = [ path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -530,7 +506,6 @@ if (!params.skip_trimming) { } withName: '.*:MAPSPLICE:ANNOTATE' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } publishDir = [ path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -540,7 +515,6 @@ if (!params.skip_trimming) { } withName: '.*:MAPSPLICE:FILTER' { - ext.when = { params.module.split(',').contains('circrna_discovery') && params.tool.split(',').contains('mapsplice') } publishDir = [ path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 740dc3a4..2096ddb7 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -52,50 +52,68 @@ workflow CIRCRNA_DISCOVERY { // // DISCOVERY TOOLS: // - SEGEMEHL( reads, fasta, params.segemehl, bsj_reads ) - ch_versions = ch_versions.mix(SEGEMEHL.out.versions) - ch_matrix = ch_matrix .mix(SEGEMEHL.out.matrix) - ch_results = ch_results .mix(SEGEMEHL.out.results) - - CIRCEXPLORER2( gtf, fasta, STAR2PASS.out.junction, bsj_reads ) - ch_versions = ch_versions.mix(CIRCEXPLORER2.out.versions) - ch_matrix = ch_matrix .mix(CIRCEXPLORER2.out.matrix) - ch_results = ch_results .mix(CIRCEXPLORER2.out.results) - - CIRCRNA_FINDER( fasta, STAR2PASS.out.sam, STAR2PASS.out.junction, - STAR2PASS.out.tab, bsj_reads ) - ch_versions = ch_versions.mix(CIRCRNA_FINDER.out.versions) - ch_matrix = ch_matrix .mix(CIRCRNA_FINDER.out.matrix) - ch_results = ch_results .mix(CIRCRNA_FINDER.out.results) - - FIND_CIRC( reads, bowtie2_index, ch_fasta, bsj_reads ) - ch_versions = ch_versions.mix(FIND_CIRC.out.versions) - ch_matrix = ch_matrix .mix(FIND_CIRC.out.matrix) - ch_results = ch_results .mix(FIND_CIRC.out.results) - - CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index, bsj_reads ) - ch_versions = ch_versions.mix(CIRIQUANT.out.versions) - ch_matrix = ch_matrix.mix(CIRIQUANT.out.matrix) - ch_results = ch_results.mix(CIRIQUANT.out.results) - - DCC( reads, ch_fasta, ch_gtf, star_index, STAR2PASS.out.junction, - star_ignore_sjdbgtf, seq_platform, seq_center, bsj_reads ) - ch_versions = ch_versions.mix(DCC.out.versions) - ch_matrix = ch_matrix.mix(DCC.out.matrix) - ch_results = ch_results.mix(DCC.out.results) - - MAPSPLICE( reads, gtf, fasta, bowtie_index, chromosomes, - STAR2PASS.out.junction, bsj_reads ) - ch_versions = ch_versions.mix(MAPSPLICE.out.versions) - ch_matrix = ch_matrix.mix(MAPSPLICE.out.matrix) - ch_results = ch_results.mix(MAPSPLICE.out.results) + tools_selected = params.tool.split(',').collect{it.trim().toLowerCase()} + + if (tools_selected.size() == 0) { + error 'No tools selected for circRNA discovery.' + } + + if (tools_selected.contains('segemehl')) { + SEGEMEHL( reads, fasta, params.segemehl, bsj_reads ) + ch_versions = ch_versions.mix(SEGEMEHL.out.versions) + ch_matrix = ch_matrix .mix(SEGEMEHL.out.matrix) + ch_results = ch_results .mix(SEGEMEHL.out.results) + } + + if (tools_selected.contains('circexplorer2')) { + CIRCEXPLORER2( gtf, fasta, STAR2PASS.out.junction, bsj_reads ) + ch_versions = ch_versions.mix(CIRCEXPLORER2.out.versions) + ch_matrix = ch_matrix .mix(CIRCEXPLORER2.out.matrix) + ch_results = ch_results .mix(CIRCEXPLORER2.out.results) + } + + if (tools_selected.contains('circrna_finder')) { + CIRCRNA_FINDER( fasta, STAR2PASS.out.sam, STAR2PASS.out.junction, + STAR2PASS.out.tab, bsj_reads ) + ch_versions = ch_versions.mix(CIRCRNA_FINDER.out.versions) + ch_matrix = ch_matrix .mix(CIRCRNA_FINDER.out.matrix) + ch_results = ch_results .mix(CIRCRNA_FINDER.out.results) + } + + if (tools_selected.contains('find_circ')) { + FIND_CIRC( reads, bowtie2_index, ch_fasta, bsj_reads ) + ch_versions = ch_versions.mix(FIND_CIRC.out.versions) + ch_matrix = ch_matrix .mix(FIND_CIRC.out.matrix) + ch_results = ch_results .mix(FIND_CIRC.out.results) + } + + if (tools_selected.contains('ciriquant')) { + CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index, bsj_reads ) + ch_versions = ch_versions.mix(CIRIQUANT.out.versions) + ch_matrix = ch_matrix .mix(CIRIQUANT.out.matrix) + ch_results = ch_results .mix(CIRIQUANT.out.results) + } + + if (tools_selected.contains('dcc')) { + DCC( reads, ch_fasta, ch_gtf, star_index, STAR2PASS.out.junction, + star_ignore_sjdbgtf, seq_platform, seq_center, bsj_reads ) + ch_versions = ch_versions.mix(DCC.out.versions) + ch_matrix = ch_matrix.mix(DCC.out.matrix) + ch_results = ch_results.mix(DCC.out.results) + } + + if (tools_selected.contains('mapsplice')) { + MAPSPLICE( reads, gtf, fasta, bowtie_index, chromosomes, + STAR2PASS.out.junction, bsj_reads ) + ch_versions = ch_versions.mix(MAPSPLICE.out.versions) + ch_matrix = ch_matrix.mix(MAPSPLICE.out.matrix) + ch_results = ch_results.mix(MAPSPLICE.out.results) + } // // CREATE COUNT MATRIX // - tools_selected = params.tool.split(',').collect{it.trim().toLowerCase()} - MERGE_TOOLS( ch_matrix.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), tools_selected.size() > 1 ? tool_filter : 1, duplicates_fun ) COUNTS_COMBINED( MERGE_TOOLS.out.merged.map{ meta, bed -> bed }.collect() ) From 27b5ab7b2972cedb10023c19cf8993b05e03bef1 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 11:13:12 +0200 Subject: [PATCH 244/491] Switch segemehl to bed output --- bin/merge_tools.py | 11 +++------- conf/modules.config | 10 ++++++--- subworkflows/local/circrna_discovery.nf | 28 ++++++++++-------------- subworkflows/local/discovery/segemehl.nf | 11 +++++----- 4 files changed, 26 insertions(+), 34 deletions(-) diff --git a/bin/merge_tools.py b/bin/merge_tools.py index 32bacab1..3d6a1396 100755 --- a/bin/merge_tools.py +++ b/bin/merge_tools.py @@ -11,19 +11,14 @@ args = parser.parse_args() -columns = ['chr', 'start', 'end', 'strand', 'count'] +columns = ['chr', 'start', 'end', 'name', 'count', 'strand'] dfs = [pd.read_csv(bed, sep='\t', header=None, names=columns) for bed in args.beds] df = pd.concat(dfs) df['tool_count'] = 1 - -df = df.groupby(['chr', 'start', 'end', 'strand']).agg({'count': args.duplicates_fun, +df = df.groupby(['chr', 'start', 'end', 'strand', 'name']).agg({'count': args.duplicates_fun, 'tool_count': 'sum'}).reset_index() df = df[df['tool_count'] >= args.tool_filter] -df.drop('tool_count', axis=1, inplace=True) -df["name"] = df["chr"] + ":" + df["start"].astype(str) + "-" + df["end"].astype(str) + ":" + df["strand"] - -df = df[['chr', 'start', 'end', 'name', 'count', 'strand']] - +df = df[columns] df.to_csv(args.output, sep='\t', index=False, header=False) diff --git a/conf/modules.config b/conf/modules.config index 781bce3c..c284c678 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -167,13 +167,17 @@ if (!params.skip_trimming) { ] } - withName: '.*:SEGEMEHL:FILTER' { + withName: '.*:SEGEMEHL:UNIFY' { + // Keep only rows with ";C;" in column 4 + // Print $1 $2 $3 $1:$2-$3 $5 $6 + ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$4 ~ /;C;/) { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 } }'" + ext.suffix = "segemehl.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/segemehl/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/segemehl/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates, - pattern: "*circs.bed" + pattern: "*.segemehl.bed" ] } diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 2096ddb7..9cbbf4a0 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -36,8 +36,7 @@ workflow CIRCRNA_DISCOVERY { main: ch_versions = Channel.empty() - ch_matrix = Channel.empty() - ch_results = Channel.empty() + ch_bed = Channel.empty() ch_multiqc_files = Channel.empty() fasta = ch_fasta.map{meta, fasta -> fasta} gtf = ch_gtf.map{meta, gtf -> gtf} @@ -61,60 +60,55 @@ workflow CIRCRNA_DISCOVERY { if (tools_selected.contains('segemehl')) { SEGEMEHL( reads, fasta, params.segemehl, bsj_reads ) ch_versions = ch_versions.mix(SEGEMEHL.out.versions) - ch_matrix = ch_matrix .mix(SEGEMEHL.out.matrix) - ch_results = ch_results .mix(SEGEMEHL.out.results) + ch_bed = ch_bed .mix(SEGEMEHL.out.bed) } if (tools_selected.contains('circexplorer2')) { CIRCEXPLORER2( gtf, fasta, STAR2PASS.out.junction, bsj_reads ) ch_versions = ch_versions.mix(CIRCEXPLORER2.out.versions) - ch_matrix = ch_matrix .mix(CIRCEXPLORER2.out.matrix) - ch_results = ch_results .mix(CIRCEXPLORER2.out.results) + ch_bed = ch_bed .mix(CIRCEXPLORER2.out.bed) } if (tools_selected.contains('circrna_finder')) { CIRCRNA_FINDER( fasta, STAR2PASS.out.sam, STAR2PASS.out.junction, STAR2PASS.out.tab, bsj_reads ) ch_versions = ch_versions.mix(CIRCRNA_FINDER.out.versions) - ch_matrix = ch_matrix .mix(CIRCRNA_FINDER.out.matrix) - ch_results = ch_results .mix(CIRCRNA_FINDER.out.results) + ch_bed = ch_bed .mix(CIRCRNA_FINDER.out.bed) } if (tools_selected.contains('find_circ')) { FIND_CIRC( reads, bowtie2_index, ch_fasta, bsj_reads ) ch_versions = ch_versions.mix(FIND_CIRC.out.versions) - ch_matrix = ch_matrix .mix(FIND_CIRC.out.matrix) - ch_results = ch_results .mix(FIND_CIRC.out.results) + ch_bed = ch_bed .mix(FIND_CIRC.out.bed) } if (tools_selected.contains('ciriquant')) { CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index, bsj_reads ) ch_versions = ch_versions.mix(CIRIQUANT.out.versions) - ch_matrix = ch_matrix .mix(CIRIQUANT.out.matrix) - ch_results = ch_results .mix(CIRIQUANT.out.results) + ch_bed = ch_bed .mix(CIRIQUANT.out.bed) } if (tools_selected.contains('dcc')) { DCC( reads, ch_fasta, ch_gtf, star_index, STAR2PASS.out.junction, star_ignore_sjdbgtf, seq_platform, seq_center, bsj_reads ) ch_versions = ch_versions.mix(DCC.out.versions) - ch_matrix = ch_matrix.mix(DCC.out.matrix) - ch_results = ch_results.mix(DCC.out.results) + ch_bed = ch_bed .mix(DCC.out.bed) } if (tools_selected.contains('mapsplice')) { MAPSPLICE( reads, gtf, fasta, bowtie_index, chromosomes, STAR2PASS.out.junction, bsj_reads ) ch_versions = ch_versions.mix(MAPSPLICE.out.versions) - ch_matrix = ch_matrix.mix(MAPSPLICE.out.matrix) - ch_results = ch_results.mix(MAPSPLICE.out.results) + ch_bed = ch_bed .mix(MAPSPLICE.out.bed) } // // CREATE COUNT MATRIX // - MERGE_TOOLS( ch_matrix.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), + ch_results = Channel.empty() + + MERGE_TOOLS( ch_bed.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), tools_selected.size() > 1 ? tool_filter : 1, duplicates_fun ) COUNTS_COMBINED( MERGE_TOOLS.out.merged.map{ meta, bed -> bed }.collect() ) diff --git a/subworkflows/local/discovery/segemehl.nf b/subworkflows/local/discovery/segemehl.nf index 1d380fd1..1d0aae2f 100644 --- a/subworkflows/local/discovery/segemehl.nf +++ b/subworkflows/local/discovery/segemehl.nf @@ -1,6 +1,6 @@ include { SEGEMEHL_INDEX as INDEX } from '../../../modules/nf-core/segemehl/index' include { SEGEMEHL_ALIGN as ALIGN } from '../../../modules/nf-core/segemehl/align' -include { SEGEMEHL_FILTER as FILTER } from '../../../modules/local/segemehl/filter' +include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' workflow SEGEMEHL { @@ -15,15 +15,14 @@ workflow SEGEMEHL { index = index ?: INDEX( fasta ).index ALIGN( reads, fasta, index ) - FILTER( ALIGN.out.results - .map{ meta, results -> [ meta + [tool: "segemehl"], results ] }, bsj_reads ) + UNIFY( ALIGN.out.results + .map{ meta, results -> [ meta + [tool: "segemehl"], results ] }, [] ) ch_versions = ch_versions.mix(ALIGN.out.versions) - ch_versions = ch_versions.mix(FILTER.out.versions) + ch_versions = ch_versions.mix(UNIFY.out.versions) emit: - matrix = FILTER.out.matrix - results = FILTER.out.results + bed = UNIFY.out.output versions = ch_versions } \ No newline at end of file From d5d0f26c87ea7ae71e7d8674924e417a35c53690 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 11:22:42 +0200 Subject: [PATCH 245/491] Implement central BSJ filtering --- conf/modules.config | 6 ++++++ subworkflows/local/circrna_discovery.nf | 8 ++++++-- subworkflows/local/discovery/segemehl.nf | 1 - 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index c284c678..5bba4969 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -528,6 +528,12 @@ if (!params.skip_trimming) { ] } + withName: 'FILTER_BSJS' { + // Make sure score is higher or equal to the threshold + ext.args = { "-v FS='\\t' -v OFS='\\t' '{ if (\$5 >= ${params.bsj_reads}) { print } }'" } + ext.suffix = "filtered.bed" + } + withName: ANNOTATION { ext.prefix = { "${meta.id}.${meta.tool}.annotated" } publishDir = [ diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 9cbbf4a0..4f6bd514 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -1,4 +1,5 @@ // MODULES +include { GAWK as FILTER_BSJS } from '../../modules/nf-core/gawk' include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools' include { COUNTS_COMBINED } from '../../modules/local/count_matrix/combined' include { UPSET as UPSET_SAMPLES } from '../../modules/local/upset' @@ -58,7 +59,7 @@ workflow CIRCRNA_DISCOVERY { } if (tools_selected.contains('segemehl')) { - SEGEMEHL( reads, fasta, params.segemehl, bsj_reads ) + SEGEMEHL( reads, fasta, params.segemehl ) ch_versions = ch_versions.mix(SEGEMEHL.out.versions) ch_bed = ch_bed .mix(SEGEMEHL.out.bed) } @@ -102,13 +103,16 @@ workflow CIRCRNA_DISCOVERY { ch_bed = ch_bed .mix(MAPSPLICE.out.bed) } + FILTER_BSJS( ch_bed, [] ) + ch_versions = ch_versions.mix(FILTER_BSJS.out.versions) + // // CREATE COUNT MATRIX // ch_results = Channel.empty() - MERGE_TOOLS( ch_bed.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), + MERGE_TOOLS( FILTER_BSJS.out.output.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), tools_selected.size() > 1 ? tool_filter : 1, duplicates_fun ) COUNTS_COMBINED( MERGE_TOOLS.out.merged.map{ meta, bed -> bed }.collect() ) diff --git a/subworkflows/local/discovery/segemehl.nf b/subworkflows/local/discovery/segemehl.nf index 1d0aae2f..d50ed70a 100644 --- a/subworkflows/local/discovery/segemehl.nf +++ b/subworkflows/local/discovery/segemehl.nf @@ -8,7 +8,6 @@ workflow SEGEMEHL { reads fasta index - bsj_reads main: ch_versions = Channel.empty() From 749c4362a281dad4eff859f214c064fc5d3c192c Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 11:37:27 +0200 Subject: [PATCH 246/491] Implement circexplorer2 unification --- conf/modules.config | 10 ++++++---- subworkflows/local/circrna_discovery.nf | 2 +- subworkflows/local/discovery/circexplorer2.nf | 12 +++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 5bba4969..694ea5bd 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -263,13 +263,15 @@ if (!params.skip_trimming) { ] } - withName: '.*:CIRCEXPLORER2:FILTER' { + withName: '.*:CIRCEXPLORER2:UNIFY' { + ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$10, \$6 }'" + ext.suffix = "circexplorer2.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/circexplorer2/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates, - pattern: "*circs.bed" + pattern: "*.circexplorer2.bed" ] } @@ -531,7 +533,7 @@ if (!params.skip_trimming) { withName: 'FILTER_BSJS' { // Make sure score is higher or equal to the threshold ext.args = { "-v FS='\\t' -v OFS='\\t' '{ if (\$5 >= ${params.bsj_reads}) { print } }'" } - ext.suffix = "filtered.bed" + ext.suffix = {"${meta.tool}.filtered.bed"} } withName: ANNOTATION { diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 4f6bd514..cc263643 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -65,7 +65,7 @@ workflow CIRCRNA_DISCOVERY { } if (tools_selected.contains('circexplorer2')) { - CIRCEXPLORER2( gtf, fasta, STAR2PASS.out.junction, bsj_reads ) + CIRCEXPLORER2( gtf, fasta, STAR2PASS.out.junction ) ch_versions = ch_versions.mix(CIRCEXPLORER2.out.versions) ch_bed = ch_bed .mix(CIRCEXPLORER2.out.bed) } diff --git a/subworkflows/local/discovery/circexplorer2.nf b/subworkflows/local/discovery/circexplorer2.nf index ce39f039..2a04386c 100644 --- a/subworkflows/local/discovery/circexplorer2.nf +++ b/subworkflows/local/discovery/circexplorer2.nf @@ -1,14 +1,13 @@ include { CIRCEXPLORER2_REFERENCE as REFERENCE } from '../../../modules/local/circexplorer2/reference' include { CIRCEXPLORER2_PARSE as PARSE } from '../../../modules/nf-core/circexplorer2/parse' include { CIRCEXPLORER2_ANNOTATE as ANNOTATE } from '../../../modules/nf-core/circexplorer2/annotate' -include { CIRCEXPLORER2_FILTER as FILTER } from '../../../modules/local/circexplorer2/filter' +include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' workflow CIRCEXPLORER2 { take: gtf fasta star_junctions - bsj_reads main: ch_versions = Channel.empty() @@ -16,17 +15,16 @@ workflow CIRCEXPLORER2 { REFERENCE( gtf ) PARSE( star_junctions ) ANNOTATE( PARSE.out.junction, fasta, REFERENCE.out.txt ) - FILTER( ANNOTATE.out.txt - .map{ meta, txt -> [ meta + [tool: "circexplorer2"], txt ] }, bsj_reads ) + UNIFY( ANNOTATE.out.txt + .map{ meta, txt -> [ meta + [tool: "circexplorer2"], txt ] }, [] ) ch_versions = ch_versions.mix(REFERENCE.out.versions) ch_versions = ch_versions.mix(PARSE.out.versions) ch_versions = ch_versions.mix(ANNOTATE.out.versions) - ch_versions = ch_versions.mix(FILTER.out.versions) + ch_versions = ch_versions.mix(UNIFY.out.versions) emit: - matrix = FILTER.out.matrix - results = FILTER.out.results + bed = UNIFY.out.output versions = ch_versions } \ No newline at end of file From bc09e30aa576dcefbe50b0a1d19f7d4d6ef9e4a1 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 11:55:09 +0200 Subject: [PATCH 247/491] Unify find_circ --- conf/modules.config | 9 ++++++--- subworkflows/local/circrna_discovery.nf | 2 +- subworkflows/local/discovery/find_circ.nf | 13 +++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 694ea5bd..e4f6ae77 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -330,13 +330,16 @@ if (!params.skip_trimming) { ] } - withName: '.*:FIND_CIRC:FILTER' { + withName: '.*:FIND_CIRC:UNIFY' { + // Keep only rows with UNAMBIGUOUS_BP and ANCHOR_UNIQUE in $18 + ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$18 ~ /UNAMBIGUOUS_BP/ && \$18 ~ /ANCHOR_UNIQUE/) { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 } }'" + ext.suffix = "find_circ.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/find_circ/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates, - pattern: "*circs.bed" + pattern: "*.find_circ.bed" ] } diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index cc263643..804046fc 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -78,7 +78,7 @@ workflow CIRCRNA_DISCOVERY { } if (tools_selected.contains('find_circ')) { - FIND_CIRC( reads, bowtie2_index, ch_fasta, bsj_reads ) + FIND_CIRC( reads, bowtie2_index, ch_fasta ) ch_versions = ch_versions.mix(FIND_CIRC.out.versions) ch_bed = ch_bed .mix(FIND_CIRC.out.bed) } diff --git a/subworkflows/local/discovery/find_circ.nf b/subworkflows/local/discovery/find_circ.nf index d8d0a14c..de4cb143 100644 --- a/subworkflows/local/discovery/find_circ.nf +++ b/subworkflows/local/discovery/find_circ.nf @@ -3,15 +3,13 @@ include { SAMTOOLS_VIEW } from '../../../modules/nf-core/samtools include { SAMTOOLS_INDEX } from '../../../modules/nf-core/samtools/index' include { FIND_CIRC_ANCHORS as ANCHORS } from '../../../modules/local/find_circ/anchors' include { FIND_CIRC as RUN } from '../../../modules/local/find_circ/find_circ' -include { FIND_CIRC_FILTER as FILTER } from '../../../modules/local/find_circ/filter' - +include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' workflow FIND_CIRC { take: reads bowtie2_index ch_fasta - bsj_reads main: ch_versions = Channel.empty() @@ -21,19 +19,18 @@ workflow FIND_CIRC { SAMTOOLS_VIEW( ALIGN.out.bam.join( SAMTOOLS_INDEX.out.bai ), ch_fasta, [] ) ANCHORS( SAMTOOLS_VIEW.out.bam ) RUN( ANCHORS.out.anchors, bowtie2_index, ch_fasta.map{ meta, fasta -> fasta } ) - FILTER( RUN.out.bed.map{ meta, bed -> - [ meta + [tool: "find_circ"], bed ] }, bsj_reads ) + UNIFY( RUN.out.bed.map{ meta, bed -> + [ meta + [tool: "find_circ"], bed ] }, [] ) ch_versions = ch_versions.mix(ALIGN.out.versions) ch_versions = ch_versions.mix(SAMTOOLS_INDEX.out.versions) ch_versions = ch_versions.mix(SAMTOOLS_VIEW.out.versions) ch_versions = ch_versions.mix(ANCHORS.out.versions) ch_versions = ch_versions.mix(RUN.out.versions) - ch_versions = ch_versions.mix(FILTER.out.versions) + ch_versions = ch_versions.mix(UNIFY.out.versions) emit: - matrix = FILTER.out.matrix - results = FILTER.out.results + bed = UNIFY.out.output versions = ch_versions } \ No newline at end of file From e02cb54dc09fbe98e1c651f4540f39460e3afdad Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 12:13:22 +0200 Subject: [PATCH 248/491] Unify ciriquant --- conf/modules.config | 13 +++++++++---- subworkflows/local/circrna_discovery.nf | 2 +- subworkflows/local/discovery/ciriquant.nf | 14 ++++++-------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index e4f6ae77..ebe7ff50 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -352,13 +352,18 @@ if (!params.skip_trimming) { ] } - withName: '.*:CIRIQUANT:FILTER' { + withName: '.*:CIRIQUANT:UNIFY' { + // Drop all rows starting with # + // $count is $14 until the dot (never has decimals) + // Print $1 $4 $5 $1:$4-$5:$7 $count $7 + ext.args = "-v OFS='\\t' '{ count = substr(\$14, 1, index(\$14, \".\") - 1); print \$1, \$4, \$5, \$1 \":\" \$4 \"-\" \$5 \":\" \$7, count, \$7 }'" + ext.suffix = "ciriquant.bed" + publishDir = [ - path: { "${params.outdir}/circrna_discovery/ciriquant/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/ciriquant/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates, - pattern: "*circs.bed" + pattern: "*.ciriquant.bed" ] } diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 804046fc..95650a4b 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -84,7 +84,7 @@ workflow CIRCRNA_DISCOVERY { } if (tools_selected.contains('ciriquant')) { - CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index, bsj_reads ) + CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index ) ch_versions = ch_versions.mix(CIRIQUANT.out.versions) ch_bed = ch_bed .mix(CIRIQUANT.out.bed) } diff --git a/subworkflows/local/discovery/ciriquant.nf b/subworkflows/local/discovery/ciriquant.nf index b4e4c381..eb85bbe1 100644 --- a/subworkflows/local/discovery/ciriquant.nf +++ b/subworkflows/local/discovery/ciriquant.nf @@ -1,5 +1,5 @@ -include { CIRIQUANT as RUN } from '../../../modules/local/ciriquant/ciriquant' -include { CIRIQUANT_FILTER as FILTER } from '../../../modules/local/ciriquant/filter' +include { CIRIQUANT as RUN } from '../../../modules/local/ciriquant/ciriquant' +include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' workflow CIRIQUANT { take: @@ -8,21 +8,19 @@ workflow CIRIQUANT { ch_fasta bwa_index hisat2_index - bsj_reads main: ch_versions = Channel.empty() RUN( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index ) - FILTER( RUN.out.gtf.map{ meta, gtf -> - [ meta + [tool: "ciriquant"], gtf ] }, bsj_reads ) + UNIFY( RUN.out.gtf.map{ meta, gtf -> + [ meta + [tool: "ciriquant"], gtf ] }, [] ) ch_versions = ch_versions.mix(RUN.out.versions) - ch_versions = ch_versions.mix(FILTER.out.versions) + ch_versions = ch_versions.mix(UNIFY.out.versions) emit: - matrix = FILTER.out.matrix - results = FILTER.out.results + bed = UNIFY.out.output versions = ch_versions } \ No newline at end of file From de9645cd44710b8985d821f01e940ad3bed6640b Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 12:19:36 +0200 Subject: [PATCH 249/491] Unify DCC --- conf/modules.config | 12 ++++++++++++ subworkflows/local/discovery/dcc.nf | 9 ++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index ebe7ff50..7004d0b4 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -480,6 +480,18 @@ if (!params.skip_trimming) { ] } + withName: '.*:DCC:UNIFY' { + ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$4, \$5, \$4 }'" + ext.suffix = "dcc.bed" + publishDir = [ + path: { "${params.outdir}/circrna_discovery/dcc/${meta.id}" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + enabled: params.save_intermediates, + pattern: "*.dcc.bed" + ] + } + withName: '.*:MAPSPLICE:REFERENCE' { ext.args = [ "", "-genePredExt", diff --git a/subworkflows/local/discovery/dcc.nf b/subworkflows/local/discovery/dcc.nf index 96ccca6b..52772c93 100644 --- a/subworkflows/local/discovery/dcc.nf +++ b/subworkflows/local/discovery/dcc.nf @@ -5,7 +5,7 @@ include { STAR_ALIGN as MATE2_1ST_PASS } from '../../../modules/nf-core/star/ali include { STAR_ALIGN as MATE2_2ND_PASS } from '../../../modules/nf-core/star/align' include { SJDB as MATE2_SJDB } from '../../../modules/local/star/sjdb' include { DCC as RUN } from '../../../modules/local/dcc/dcc' -include { DCC_FILTER as FILTER } from '../../../modules/local/dcc/filter' +include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' workflow DCC { take: @@ -49,7 +49,7 @@ workflow DCC { dcc = dcc_stage.map{ it -> [ it[0], it[1], it[2] ?: [], it[3] ?: [] ] } RUN( dcc, ch_fasta.map{ meta, fasta -> fasta }, ch_gtf.map{ meta, gtf -> gtf } ) - FILTER( RUN.out.txt.map{ meta, txt -> [ meta + [tool: "dcc"], txt ] }, bsj_reads ) + UNIFY( RUN.out.txt.map{ meta, txt -> [ meta + [tool: "dcc"], txt ] }, [] ) ch_versions = ch_versions.mix(MATE1_1ST_PASS.out.versions) ch_versions = ch_versions.mix(MATE1_SJDB.out.versions) @@ -58,11 +58,10 @@ workflow DCC { ch_versions = ch_versions.mix(MATE2_SJDB.out.versions) ch_versions = ch_versions.mix(MATE2_2ND_PASS.out.versions) ch_versions = ch_versions.mix(RUN.out.versions) - ch_versions = ch_versions.mix(FILTER.out.versions) + ch_versions = ch_versions.mix(UNIFY.out.versions) emit: - matrix = FILTER.out.matrix - results = FILTER.out.results + bed = UNIFY.out.output versions = ch_versions } \ No newline at end of file From 0dd9a4f7f73e0ef8621660ff6bbcf7c0d433662f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 12:26:42 +0200 Subject: [PATCH 250/491] Unify mapsplice --- conf/modules.config | 13 +++++-------- subworkflows/local/circrna_discovery.nf | 2 +- subworkflows/local/discovery/mapsplice.nf | 13 +++++-------- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 7004d0b4..2641f9ef 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -176,7 +176,6 @@ if (!params.skip_trimming) { path: { "${params.outdir}/circrna_discovery/segemehl/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates, pattern: "*.segemehl.bed" ] } @@ -270,7 +269,6 @@ if (!params.skip_trimming) { path: { "${params.outdir}/circrna_discovery/circexplorer2/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates, pattern: "*.circexplorer2.bed" ] } @@ -338,7 +336,6 @@ if (!params.skip_trimming) { path: { "${params.outdir}/circrna_discovery/find_circ/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates, pattern: "*.find_circ.bed" ] } @@ -487,7 +484,6 @@ if (!params.skip_trimming) { path: { "${params.outdir}/circrna_discovery/dcc/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates, pattern: "*.dcc.bed" ] } @@ -540,13 +536,14 @@ if (!params.skip_trimming) { ] } - withName: '.*:MAPSPLICE:FILTER' { + withName: '.*:MAPSPLICE:UNIFY' { + ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$10, \$6 }'" + ext.suffix = "mapsplice.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/mapsplice/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates, - pattern: "*circs.bed" + pattern: "*.mapsplice.bed" ] } diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 95650a4b..984546f0 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -98,7 +98,7 @@ workflow CIRCRNA_DISCOVERY { if (tools_selected.contains('mapsplice')) { MAPSPLICE( reads, gtf, fasta, bowtie_index, chromosomes, - STAR2PASS.out.junction, bsj_reads ) + STAR2PASS.out.junction ) ch_versions = ch_versions.mix(MAPSPLICE.out.versions) ch_bed = ch_bed .mix(MAPSPLICE.out.bed) } diff --git a/subworkflows/local/discovery/mapsplice.nf b/subworkflows/local/discovery/mapsplice.nf index d4640047..847515de 100644 --- a/subworkflows/local/discovery/mapsplice.nf +++ b/subworkflows/local/discovery/mapsplice.nf @@ -2,8 +2,7 @@ include { CIRCEXPLORER2_REFERENCE as REFERENCE } from '../../../modules/local/ci include { MAPSPLICE_ALIGN as ALIGN } from '../../../modules/local/mapsplice/align' include { CIRCEXPLORER2_PARSE as PARSE } from '../../../modules/nf-core/circexplorer2/parse' include { CIRCEXPLORER2_ANNOTATE as ANNOTATE } from '../../../modules/nf-core/circexplorer2/annotate' -include { CIRCEXPLORER2_FILTER as FILTER } from '../../../modules/local/circexplorer2/filter' - +include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' workflow MAPSPLICE { take: @@ -13,7 +12,6 @@ workflow MAPSPLICE { bowtie_index chromosomes star_junctions - bsj_reads main: ch_versions = Channel.empty() @@ -22,18 +20,17 @@ workflow MAPSPLICE { ALIGN( reads, bowtie_index, chromosomes, gtf ) PARSE( ALIGN.out.raw_fusions ) ANNOTATE( PARSE.out.junction, fasta, REFERENCE.out.txt ) - FILTER( ANNOTATE.out.txt.map{ meta, txt -> - [ meta + [tool: "mapsplice"], txt ] }, bsj_reads ) + UNIFY( ANNOTATE.out.txt.map{ meta, txt -> + [ meta + [tool: "mapsplice"], txt ] }, [] ) ch_versions = ch_versions.mix(REFERENCE.out.versions) ch_versions = ch_versions.mix(ALIGN.out.versions) ch_versions = ch_versions.mix(PARSE.out.versions) ch_versions = ch_versions.mix(ANNOTATE.out.versions) - ch_versions = ch_versions.mix(FILTER.out.versions) + ch_versions = ch_versions.mix(UNIFY.out.versions) emit: - matrix = FILTER.out.matrix - results = FILTER.out.results + bed = UNIFY.out.output versions = ch_versions } \ No newline at end of file From 4fa56f31fd8a9328a5881911c26aaa45a73a8c95 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 15:33:39 +0200 Subject: [PATCH 251/491] Unify circrna_finder --- conf/modules.config | 15 ++++++- modules/local/circrna_finder/filter/main.nf | 43 ------------------- modules/local/circrna_finder/main.nf | 34 +++++++++++++++ subworkflows/local/circrna_discovery.nf | 2 +- .../local/discovery/circrna_finder.nf | 14 +++--- 5 files changed, 55 insertions(+), 53 deletions(-) delete mode 100644 modules/local/circrna_finder/filter/main.nf create mode 100644 modules/local/circrna_finder/main.nf diff --git a/conf/modules.config b/conf/modules.config index 2641f9ef..a2425657 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -273,13 +273,24 @@ if (!params.skip_trimming) { ] } - withName: '.*:CIRCRNA_FINDER:FILTER' { + withName: '.*:CIRCRNA_FINDER:MAIN' { publishDir = [ path: { "${params.outdir}/circrna_discovery/circrna_finder/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, enabled: params.save_intermediates, - pattern: "*circs.bed" + pattern: "*.bed" + ] + } + + withName: '.*:CIRCRNA_FINDER:UNIFY' { + ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 }'" + ext.suffix = "circrna_finder.bed" + publishDir = [ + path: { "${params.outdir}/circrna_discovery/circrna_finder/${meta.id}" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + pattern: "*.circrna_finder.bed" ] } diff --git a/modules/local/circrna_finder/filter/main.nf b/modules/local/circrna_finder/filter/main.nf deleted file mode 100644 index 1f781a32..00000000 --- a/modules/local/circrna_finder/filter/main.nf +++ /dev/null @@ -1,43 +0,0 @@ -process CIRCRNA_FINDER_FILTER { - tag "$meta.id" - label 'process_low' - - conda "bioconda::circrna_finder=1.2" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/circrna_finder%3A1.2--pl5321hdfd78af_1' : - 'biocontainers/circrna_finder:1.2--pl5321hdfd78af_1' }" - - input: - tuple val(meta), path(sam), path(junction), path(tab) - path fasta - val bsj_reads - - output: - tuple val(meta), path("${prefix}_circrna_finder_circs.bed"), emit: results - tuple val(meta), path("${prefix}_circrna_finder.bed") , emit: matrix - tuple val(meta), path("*filteredJunctions*") , emit: intermediates - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - prefix = task.ext.prefix ?: "${meta.id}" - def VERSION = 'v1.2' - """ - mkdir -p star_dir && mv *.tab *.junction *.sam star_dir - postProcessStarAlignment.pl --starDir star_dir/ --outDir ./ - - awk '{if(\$5 >= ${bsj_reads}) print \$0}' ${prefix}.filteredJunctions.bed | awk -v OFS="\\t" -F"\\t" '{print \$1,\$2,\$3,\$6,\$5}' > ${prefix}_circrna_finder.bed - - awk -v OFS="\\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_circrna_finder.bed > ${prefix}_circrna_finder_circs.bed - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) - cat: \$(cat --version | head -n 1 | sed -e 's/cat (GNU coreutils) //') - circRNA_finder: $VERSION - END_VERSIONS - """ -} diff --git a/modules/local/circrna_finder/main.nf b/modules/local/circrna_finder/main.nf new file mode 100644 index 00000000..e9a40720 --- /dev/null +++ b/modules/local/circrna_finder/main.nf @@ -0,0 +1,34 @@ +process CIRCRNA_FINDER { + tag "$meta.id" + label 'process_low' + + conda "bioconda::circrna_finder=1.2" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/circrna_finder%3A1.2--pl5321hdfd78af_1' : + 'biocontainers/circrna_finder:1.2--pl5321hdfd78af_1' }" + + input: + tuple val(meta), path(star_input, stageAs: 'input/') + + output: + tuple val(meta), path("${prefix}.filteredJunctions.bed"), emit: results + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${meta.id}" + def VERSION = 'v1.2' + """ + postProcessStarAlignment.pl --starDir input/ --outDir ./ + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + awk: \$(awk --version | head -n1 | cut -d' ' -f3 | sed 's/,//g' ) + cat: \$(cat --version | head -n 1 | sed -e 's/cat (GNU coreutils) //') + circRNA_finder: $VERSION + END_VERSIONS + """ +} diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 984546f0..ccb2a332 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -72,7 +72,7 @@ workflow CIRCRNA_DISCOVERY { if (tools_selected.contains('circrna_finder')) { CIRCRNA_FINDER( fasta, STAR2PASS.out.sam, STAR2PASS.out.junction, - STAR2PASS.out.tab, bsj_reads ) + STAR2PASS.out.tab ) ch_versions = ch_versions.mix(CIRCRNA_FINDER.out.versions) ch_bed = ch_bed .mix(CIRCRNA_FINDER.out.bed) } diff --git a/subworkflows/local/discovery/circrna_finder.nf b/subworkflows/local/discovery/circrna_finder.nf index b4564b7b..4e9c7e4e 100644 --- a/subworkflows/local/discovery/circrna_finder.nf +++ b/subworkflows/local/discovery/circrna_finder.nf @@ -1,4 +1,5 @@ -include { CIRCRNA_FINDER_FILTER as FILTER } from '../../../modules/local/circrna_finder/filter' +include { CIRCRNA_FINDER as MAIN } from '../../../modules/local/circrna_finder' +include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' workflow CIRCRNA_FINDER { take: @@ -6,22 +7,21 @@ workflow CIRCRNA_FINDER { star_sam star_junctions star_tab - bsj_reads main: ch_versions = Channel.empty() ch_joined = star_sam.join(star_junctions).join(star_tab) .map{ meta, sam, junction, tab -> - [ meta + [tool: "circrna_finder"], sam, junction, tab ] } + [ meta + [tool: "circrna_finder"], [sam, junction, tab] ] } - FILTER( ch_joined, fasta, bsj_reads ) + MAIN( ch_joined ) + UNIFY( MAIN.out.results, [] ) - ch_versions = ch_versions.mix(FILTER.out.versions) + ch_versions = ch_versions.mix(MAIN.out.versions) emit: - matrix = FILTER.out.matrix - results = FILTER.out.results + bed = UNIFY.out.output versions = ch_versions } \ No newline at end of file From 01b7899d89c78e2aa6c8187cd836203042dfe3e6 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 15:36:57 +0200 Subject: [PATCH 252/491] Rename RUN to MAIN in all occurrences --- conf/modules.config | 6 +++--- subworkflows/local/discovery/ciriquant.nf | 10 +++++----- subworkflows/local/discovery/dcc.nf | 8 ++++---- subworkflows/local/discovery/find_circ.nf | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index a2425657..ef25fa26 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -330,7 +330,7 @@ if (!params.skip_trimming) { ] } - withName: '.*:FIND_CIRC:RUN' { + withName: '.*:FIND_CIRC:MAIN' { publishDir = [ path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -351,7 +351,7 @@ if (!params.skip_trimming) { ] } - withName: '.*:CIRIQUANT:RUN' { + withName: '.*:CIRIQUANT:MAIN' { publishDir = [ path: { "${params.outdir}/circrna_discovery/ciriquant/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -479,7 +479,7 @@ if (!params.skip_trimming) { ] } - withName: '.*:DCC:RUN' { + withName: '.*:DCC:MAIN' { publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/${meta.id}" }, mode: params.publish_dir_mode, diff --git a/subworkflows/local/discovery/ciriquant.nf b/subworkflows/local/discovery/ciriquant.nf index eb85bbe1..63b0d26c 100644 --- a/subworkflows/local/discovery/ciriquant.nf +++ b/subworkflows/local/discovery/ciriquant.nf @@ -1,5 +1,5 @@ -include { CIRIQUANT as RUN } from '../../../modules/local/ciriquant/ciriquant' -include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' +include { CIRIQUANT as MAIN } from '../../../modules/local/ciriquant/ciriquant' +include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' workflow CIRIQUANT { take: @@ -12,11 +12,11 @@ workflow CIRIQUANT { main: ch_versions = Channel.empty() - RUN( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index ) - UNIFY( RUN.out.gtf.map{ meta, gtf -> + MAIN( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index ) + UNIFY( MAIN.out.gtf.map{ meta, gtf -> [ meta + [tool: "ciriquant"], gtf ] }, [] ) - ch_versions = ch_versions.mix(RUN.out.versions) + ch_versions = ch_versions.mix(MAIN.out.versions) ch_versions = ch_versions.mix(UNIFY.out.versions) emit: diff --git a/subworkflows/local/discovery/dcc.nf b/subworkflows/local/discovery/dcc.nf index 52772c93..6cb613ae 100644 --- a/subworkflows/local/discovery/dcc.nf +++ b/subworkflows/local/discovery/dcc.nf @@ -4,7 +4,7 @@ include { SJDB as MATE1_SJDB } from '../../../modules/local/star/sjdb' include { STAR_ALIGN as MATE2_1ST_PASS } from '../../../modules/nf-core/star/align' include { STAR_ALIGN as MATE2_2ND_PASS } from '../../../modules/nf-core/star/align' include { SJDB as MATE2_SJDB } from '../../../modules/local/star/sjdb' -include { DCC as RUN } from '../../../modules/local/dcc/dcc' +include { DCC as MAIN } from '../../../modules/local/dcc/dcc' include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' workflow DCC { @@ -48,8 +48,8 @@ workflow DCC { .map{ id, meta, junction, mate1, mate2 -> return [ meta, junction, mate1, mate2 ]} dcc = dcc_stage.map{ it -> [ it[0], it[1], it[2] ?: [], it[3] ?: [] ] } - RUN( dcc, ch_fasta.map{ meta, fasta -> fasta }, ch_gtf.map{ meta, gtf -> gtf } ) - UNIFY( RUN.out.txt.map{ meta, txt -> [ meta + [tool: "dcc"], txt ] }, [] ) + MAIN( dcc, ch_fasta.map{ meta, fasta -> fasta }, ch_gtf.map{ meta, gtf -> gtf } ) + UNIFY( MAIN.out.txt.map{ meta, txt -> [ meta + [tool: "dcc"], txt ] }, [] ) ch_versions = ch_versions.mix(MATE1_1ST_PASS.out.versions) ch_versions = ch_versions.mix(MATE1_SJDB.out.versions) @@ -57,7 +57,7 @@ workflow DCC { ch_versions = ch_versions.mix(MATE2_1ST_PASS.out.versions) ch_versions = ch_versions.mix(MATE2_SJDB.out.versions) ch_versions = ch_versions.mix(MATE2_2ND_PASS.out.versions) - ch_versions = ch_versions.mix(RUN.out.versions) + ch_versions = ch_versions.mix(MAIN.out.versions) ch_versions = ch_versions.mix(UNIFY.out.versions) emit: diff --git a/subworkflows/local/discovery/find_circ.nf b/subworkflows/local/discovery/find_circ.nf index de4cb143..c1f3772d 100644 --- a/subworkflows/local/discovery/find_circ.nf +++ b/subworkflows/local/discovery/find_circ.nf @@ -2,7 +2,7 @@ include { BOWTIE2_ALIGN as ALIGN } from '../../../modules/nf-core/bowtie2/ include { SAMTOOLS_VIEW } from '../../../modules/nf-core/samtools/view' include { SAMTOOLS_INDEX } from '../../../modules/nf-core/samtools/index' include { FIND_CIRC_ANCHORS as ANCHORS } from '../../../modules/local/find_circ/anchors' -include { FIND_CIRC as RUN } from '../../../modules/local/find_circ/find_circ' +include { FIND_CIRC as MAIN } from '../../../modules/local/find_circ/find_circ' include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' workflow FIND_CIRC { @@ -18,15 +18,15 @@ workflow FIND_CIRC { SAMTOOLS_INDEX( ALIGN.out.bam ) SAMTOOLS_VIEW( ALIGN.out.bam.join( SAMTOOLS_INDEX.out.bai ), ch_fasta, [] ) ANCHORS( SAMTOOLS_VIEW.out.bam ) - RUN( ANCHORS.out.anchors, bowtie2_index, ch_fasta.map{ meta, fasta -> fasta } ) - UNIFY( RUN.out.bed.map{ meta, bed -> + MAIN( ANCHORS.out.anchors, bowtie2_index, ch_fasta.map{ meta, fasta -> fasta } ) + UNIFY( MAIN.out.bed.map{ meta, bed -> [ meta + [tool: "find_circ"], bed ] }, [] ) ch_versions = ch_versions.mix(ALIGN.out.versions) ch_versions = ch_versions.mix(SAMTOOLS_INDEX.out.versions) ch_versions = ch_versions.mix(SAMTOOLS_VIEW.out.versions) ch_versions = ch_versions.mix(ANCHORS.out.versions) - ch_versions = ch_versions.mix(RUN.out.versions) + ch_versions = ch_versions.mix(MAIN.out.versions) ch_versions = ch_versions.mix(UNIFY.out.versions) emit: From a6a82f3155b0e8a53bdd81c9fde60d60968435d9 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 15:39:38 +0200 Subject: [PATCH 253/491] Add circrna_finder unify version capture --- subworkflows/local/discovery/circrna_finder.nf | 1 + 1 file changed, 1 insertion(+) diff --git a/subworkflows/local/discovery/circrna_finder.nf b/subworkflows/local/discovery/circrna_finder.nf index 4e9c7e4e..c57bbe94 100644 --- a/subworkflows/local/discovery/circrna_finder.nf +++ b/subworkflows/local/discovery/circrna_finder.nf @@ -19,6 +19,7 @@ workflow CIRCRNA_FINDER { UNIFY( MAIN.out.results, [] ) ch_versions = ch_versions.mix(MAIN.out.versions) + ch_versions = ch_versions.mix(UNIFY.out.versions) emit: bed = UNIFY.out.output From aca81ce88d857a9e32cc63ca3b0176f5dc3762af Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 15:47:45 +0200 Subject: [PATCH 254/491] Remove tool-specific filtering artifacts --- modules/local/circexplorer2/filter/main.nf | 36 ---------------- modules/local/ciriquant/filter/main.nf | 43 ------------------- .../local/ciriquant/{ciriquant => }/main.nf | 0 modules/local/dcc/filter/main.nf | 35 --------------- modules/local/dcc/{dcc => }/main.nf | 0 modules/local/find_circ/filter/main.nf | 42 ------------------ modules/local/segemehl/filter/main.nf | 39 ----------------- subworkflows/local/discovery/ciriquant.nf | 2 +- subworkflows/local/discovery/dcc.nf | 2 +- 9 files changed, 2 insertions(+), 197 deletions(-) delete mode 100644 modules/local/circexplorer2/filter/main.nf delete mode 100644 modules/local/ciriquant/filter/main.nf rename modules/local/ciriquant/{ciriquant => }/main.nf (100%) delete mode 100644 modules/local/dcc/filter/main.nf rename modules/local/dcc/{dcc => }/main.nf (100%) delete mode 100644 modules/local/find_circ/filter/main.nf delete mode 100644 modules/local/segemehl/filter/main.nf diff --git a/modules/local/circexplorer2/filter/main.nf b/modules/local/circexplorer2/filter/main.nf deleted file mode 100644 index 3b6cc9bf..00000000 --- a/modules/local/circexplorer2/filter/main.nf +++ /dev/null @@ -1,36 +0,0 @@ -process CIRCEXPLORER2_FILTER { - tag "$meta.id" - label 'process_single' - - conda "conda-forge::sed=4.7" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : - 'nf-core/ubuntu:20.04' }" - - input: - tuple val(meta), path(txt) - val(bsj_reads) - - output: - tuple val(meta), path("${prefix}_${meta.tool}_circs.bed"), emit: results - tuple val(meta), path("${prefix}_${meta.tool}.bed") , emit: matrix - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - prefix = task.ext.prefix ?: "${meta.id}" - def VERSION = '1.3.4' - """ - awk '{if(\$13 >= ${bsj_reads}) print \$0}' ${prefix}.txt | awk -v OFS="\\t" '{print \$1,\$2,\$3,\$6,\$13}' > ${prefix}_${meta.tool}.bed - - awk -v OFS="\\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_${meta.tool}.bed > ${prefix}_${meta.tool}_circs.bed - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - mawk: $VERSION - END_VERSIONS - """ -} diff --git a/modules/local/ciriquant/filter/main.nf b/modules/local/ciriquant/filter/main.nf deleted file mode 100644 index c36e4638..00000000 --- a/modules/local/ciriquant/filter/main.nf +++ /dev/null @@ -1,43 +0,0 @@ -process CIRIQUANT_FILTER { - tag "$meta.id" - label 'process_single' - - conda "conda-forge::sed=4.7" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : - 'nf-core/ubuntu:20.04' }" - - input: - tuple val(meta), path(gtf) - val bsj_reads - - output: - tuple val(meta), path("${prefix}_ciriquant_circs.bed"), emit: results - tuple val(meta), path("${prefix}_ciriquant.bed") , emit: matrix - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - prefix = task.ext.prefix ?: "${meta.id}" - def VERSION = '1.3.4' - """ - grep -v "#" ${prefix}.gtf | awk '{print \$14}' | cut -d '.' -f1 > counts - grep -v "#" ${prefix}.gtf | awk -v OFS="\\t" '{print \$1,\$4,\$5,\$7}' > ${prefix}.tmp - paste ${prefix}.tmp counts > ${prefix}_unfilt.bed - - awk '{if(\$5 >= ${bsj_reads}) print \$0}' ${prefix}_unfilt.bed > ${prefix}_filt.bed - grep -v '^\$' ${prefix}_filt.bed > ${prefix}_ciriquant - - awk -v OFS="\\t" '{\$2-=1;print}' ${prefix}_ciriquant > ${prefix}_ciriquant.bed - rm ${prefix}.gtf - - awk -v OFS="\\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_ciriquant.bed > ${prefix}_ciriquant_circs.bed - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - mawk: $VERSION - END_VERSIONS - """ -} diff --git a/modules/local/ciriquant/ciriquant/main.nf b/modules/local/ciriquant/main.nf similarity index 100% rename from modules/local/ciriquant/ciriquant/main.nf rename to modules/local/ciriquant/main.nf diff --git a/modules/local/dcc/filter/main.nf b/modules/local/dcc/filter/main.nf deleted file mode 100644 index 78d3e571..00000000 --- a/modules/local/dcc/filter/main.nf +++ /dev/null @@ -1,35 +0,0 @@ -process DCC_FILTER { - tag "$meta.id" - label 'process_single' - - conda "conda-forge::sed=4.7" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : - 'nf-core/ubuntu:20.04' }" - - input: - tuple val(meta), path(txt) - val bsj_reads - - output: - tuple val(meta), path("${prefix}_dcc_circs.bed"), emit: results - tuple val(meta), path("${prefix}_dcc.bed") , emit: matrix - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - prefix = task.ext.prefix ?: "${meta.id}" - def VERSION = '1.3.4' - """ - awk '{if(\$5 >= ${bsj_reads}) print \$0}' ${prefix}.txt > ${prefix}_dcc.filtered - awk -v OFS="\\t" '{\$2-=1;print}' ${prefix}_dcc.filtered > ${prefix}_dcc.bed - awk -v OFS="\\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_dcc.bed > ${prefix}_dcc_circs.bed - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - mawk: $VERSION - END_VERSIONS - """ -} diff --git a/modules/local/dcc/dcc/main.nf b/modules/local/dcc/main.nf similarity index 100% rename from modules/local/dcc/dcc/main.nf rename to modules/local/dcc/main.nf diff --git a/modules/local/find_circ/filter/main.nf b/modules/local/find_circ/filter/main.nf deleted file mode 100644 index c4313b20..00000000 --- a/modules/local/find_circ/filter/main.nf +++ /dev/null @@ -1,42 +0,0 @@ -process FIND_CIRC_FILTER { - tag "$meta.id" - label "process_low" - - conda "bioconda::find_circ=1.2" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/find_circ%3A1.2--hdfd78af_0' : - 'biocontainers/find_circ:1.2--hdfd78af_0' }" - - input: - tuple val(meta), path(bed) - val bsj_reads - - output: - tuple val(meta), path("${prefix}_find_circ_circs.bed"), emit: results - tuple val(meta), path("${prefix}_find_circ.bed") , emit: matrix - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - prefix = task.ext.prefix ?: "${meta.id}" - def VERSION = '1.2' - """ - grep CIRCULAR $bed | \ - grep -v chrM | \ - awk '\$5>=${bsj_reads}' | \ - grep UNAMBIGUOUS_BP | grep ANCHOR_UNIQUE | \ - maxlength.py 100000 \ - > ${prefix}.txt - - tail -n +2 ${prefix}.txt | awk -v OFS="\\t" '{print \$1,\$2,\$3,\$6,\$5}' > ${prefix}_find_circ.bed - - awk -v OFS="\\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_find_circ.bed > ${prefix}_find_circ_circs.bed - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - find_circ: $VERSION - END_VERSIONS - """ -} diff --git a/modules/local/segemehl/filter/main.nf b/modules/local/segemehl/filter/main.nf deleted file mode 100644 index a1cf9929..00000000 --- a/modules/local/segemehl/filter/main.nf +++ /dev/null @@ -1,39 +0,0 @@ -process SEGEMEHL_FILTER { - tag "$meta.id" - label 'process_single' - - conda "conda-forge::sed=4.7" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : - 'nf-core/ubuntu:20.04' }" - - input: - tuple val(meta), path(results) - val(bsj_reads) - - output: - tuple val(meta), path("${prefix}_segemehl_circs.bed"), emit: results - tuple val(meta), path("${prefix}_segemehl.bed") , emit: matrix - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - prefix = task.ext.prefix ?: "${meta.id}" - def VERSION = '1.3.4' - """ - grep ';C;' ${prefix}.sngl.bed | awk -v OFS="\\t" '{print \$1,\$2,\$3,\$6}' | sort | uniq -c | awk -v OFS="\\t" '{print \$2,\$3,\$4,\$5,\$1}' > ${prefix}_collapsed.bed - - awk -v OFS="\\t" -v BSJ=${bsj_reads} '{if(\$5>=BSJ) print \$0}' ${prefix}_collapsed.bed > ${prefix}_segemehl.bed - - awk -v OFS="\\t" '{print \$1, \$2, \$3, \$1":"\$2"-"\$3":"\$4, \$5, \$4}' ${prefix}_segemehl.bed > ${prefix}_segemehl_circs.bed - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - mawk: $VERSION - sort: \$(sort --version | head -n 1 | sed -e 's/sort (GNU coreutils) //g') - END_VERSIONS - """ -} diff --git a/subworkflows/local/discovery/ciriquant.nf b/subworkflows/local/discovery/ciriquant.nf index 63b0d26c..7bf8c617 100644 --- a/subworkflows/local/discovery/ciriquant.nf +++ b/subworkflows/local/discovery/ciriquant.nf @@ -1,4 +1,4 @@ -include { CIRIQUANT as MAIN } from '../../../modules/local/ciriquant/ciriquant' +include { CIRIQUANT as MAIN } from '../../../modules/local/ciriquant' include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' workflow CIRIQUANT { diff --git a/subworkflows/local/discovery/dcc.nf b/subworkflows/local/discovery/dcc.nf index 6cb613ae..ecc88c2b 100644 --- a/subworkflows/local/discovery/dcc.nf +++ b/subworkflows/local/discovery/dcc.nf @@ -4,7 +4,7 @@ include { SJDB as MATE1_SJDB } from '../../../modules/local/star/sjdb' include { STAR_ALIGN as MATE2_1ST_PASS } from '../../../modules/nf-core/star/align' include { STAR_ALIGN as MATE2_2ND_PASS } from '../../../modules/nf-core/star/align' include { SJDB as MATE2_SJDB } from '../../../modules/local/star/sjdb' -include { DCC as MAIN } from '../../../modules/local/dcc/dcc' +include { DCC as MAIN } from '../../../modules/local/dcc' include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' workflow DCC { From fca047500f674091ba5a04cc9499ccc76fa6b6af Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 16:04:27 +0200 Subject: [PATCH 255/491] Remove technical debt with former "results" channel --- bin/{counts_combined.py => merge_samples.py} | 0 conf/modules.config | 4 --- .../{combined => merge_samples}/main.nf | 4 +-- subworkflows/local/circrna_discovery.nf | 36 +++++++++---------- 4 files changed, 19 insertions(+), 25 deletions(-) rename bin/{counts_combined.py => merge_samples.py} (100%) rename modules/local/count_matrix/{combined => merge_samples}/main.nf (85%) diff --git a/bin/counts_combined.py b/bin/merge_samples.py similarity index 100% rename from bin/counts_combined.py rename to bin/merge_samples.py diff --git a/conf/modules.config b/conf/modules.config index ef25fa26..1636d137 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -612,10 +612,6 @@ if (!params.skip_trimming) { ] } - withName: COUNTS_COMBINED { - ext.when = { params.module.split(',').contains('circrna_discovery') } - } - withName: COMBINE_TRANSCRIPTOME_GTFS { ext.args = "-k 1,1 -k3,3n -k4,4n" ext.suffix = "gtf" diff --git a/modules/local/count_matrix/combined/main.nf b/modules/local/count_matrix/merge_samples/main.nf similarity index 85% rename from modules/local/count_matrix/combined/main.nf rename to modules/local/count_matrix/merge_samples/main.nf index 7d1e1269..b286c757 100644 --- a/modules/local/count_matrix/combined/main.nf +++ b/modules/local/count_matrix/merge_samples/main.nf @@ -1,4 +1,4 @@ -process COUNTS_COMBINED { +process MERGE_SAMPLES { label "process_single" conda "bioconda::pandas=1.5.2" @@ -16,7 +16,7 @@ process COUNTS_COMBINED { script: """ - counts_combined.py --beds ${beds} --out_bed merged_counts.bed --out_tsv merged_counts.tsv + merge_samples.py --beds ${beds} --out_bed merged_counts.bed --out_tsv merged_counts.tsv cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index ccb2a332..a8ae043a 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -1,11 +1,11 @@ // MODULES -include { GAWK as FILTER_BSJS } from '../../modules/nf-core/gawk' -include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools' -include { COUNTS_COMBINED } from '../../modules/local/count_matrix/combined' -include { UPSET as UPSET_SAMPLES } from '../../modules/local/upset' -include { UPSET as UPSET_ALL } from '../../modules/local/upset' -include { BEDTOOLS_GETFASTA } from '../../modules/nf-core/bedtools/getfasta' -include { GAWK as ADD_BACKSPLICE } from '../../modules/nf-core/gawk' +include { GAWK as FILTER_BSJS } from '../../modules/nf-core/gawk' +include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools' +include { MERGE_SAMPLES } from '../../modules/local/count_matrix/merge_samples' +include { UPSET as UPSET_SAMPLES } from '../../modules/local/upset' +include { UPSET as UPSET_ALL } from '../../modules/local/upset' +include { BEDTOOLS_GETFASTA } from '../../modules/nf-core/bedtools/getfasta' +include { GAWK as ADD_BACKSPLICE } from '../../modules/nf-core/gawk' // SUBWORKFLOWS include { SEGEMEHL } from './discovery/segemehl' @@ -103,33 +103,31 @@ workflow CIRCRNA_DISCOVERY { ch_bed = ch_bed .mix(MAPSPLICE.out.bed) } - FILTER_BSJS( ch_bed, [] ) + ch_bed = FILTER_BSJS( ch_bed, [] ).output ch_versions = ch_versions.mix(FILTER_BSJS.out.versions) // // CREATE COUNT MATRIX // - ch_results = Channel.empty() - - MERGE_TOOLS( FILTER_BSJS.out.output.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), + MERGE_TOOLS( ch_bed.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), tools_selected.size() > 1 ? tool_filter : 1, duplicates_fun ) - COUNTS_COMBINED( MERGE_TOOLS.out.merged.map{ meta, bed -> bed }.collect() ) + MERGE_SAMPLES( MERGE_TOOLS.out.merged.map{ meta, bed -> bed }.collect() ) - ch_results_incl_merged = ch_results.mix( + ch_bed_incl_merged = ch_bed.mix( MERGE_TOOLS.out.merged.map{ meta, bed -> [meta + [tool: "merged"], bed] }) ch_versions = ch_versions.mix(MERGE_TOOLS.out.versions) - ch_versions = ch_versions.mix(COUNTS_COMBINED.out.versions) + ch_versions = ch_versions.mix(MERGE_SAMPLES.out.versions) // // UPSET PLOTS // - UPSET_SAMPLES( ch_results.map{ meta, bed -> [meta.id, meta.tool, bed]} + UPSET_SAMPLES( ch_bed.map{ meta, bed -> [meta.id, meta.tool, bed]} .groupTuple() .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) - UPSET_ALL( ch_results.map{ meta, bed -> ["all", meta.tool, bed] } + UPSET_ALL( ch_bed.map{ meta, bed -> ["all", meta.tool, bed] } .groupTuple() .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) @@ -142,7 +140,7 @@ workflow CIRCRNA_DISCOVERY { // ANNOTATION WORKFLOW: // - ANNOTATION( ch_results_incl_merged, gtf, exon_boundary ) + ANNOTATION( ch_bed_incl_merged, gtf, exon_boundary ) ch_versions = ch_versions.mix(ANNOTATION.out.versions) // @@ -160,8 +158,8 @@ workflow CIRCRNA_DISCOVERY { fasta = ADD_BACKSPLICE.out.output annotation_bed = ANNOTATION.out.bed annotation_gtf = ANNOTATION.out.gtf - counts_bed = COUNTS_COMBINED.out.counts_bed - counts_tsv = COUNTS_COMBINED.out.counts_tsv + counts_bed = MERGE_SAMPLES.out.counts_bed + counts_tsv = MERGE_SAMPLES.out.counts_tsv multiqc_files = ch_multiqc_files versions = ch_versions From e6e31570ec418ab3d44752e40095954e80f8a5b1 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 24 May 2024 16:18:40 +0200 Subject: [PATCH 256/491] Remove unnecessary checks if circrna_discovery is enabled --- conf/modules.config | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 1636d137..a1cd75c2 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -81,7 +81,7 @@ if (!params.skip_trimming) { } withName: BOWTIE_BUILD { - ext.when = { !params.bowtie && params.tool.split(',').contains('mapsplice') && params.module.split(',').contains('circrna_discovery') } + ext.when = { !params.bowtie && params.tool.split(',').contains('mapsplice') } publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, @@ -91,7 +91,7 @@ if (!params.skip_trimming) { } withName: BOWTIE2_BUILD { - ext.when = { !params.bowtie2 && params.tool.split(',').contains('find_circ') && params.module.split(',').contains('circrna_discovery') } + ext.when = { !params.bowtie2 && params.tool.split(',').contains('find_circ') } publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, @@ -101,7 +101,7 @@ if (!params.skip_trimming) { } withName: BWA_INDEX { - ext.when = { !params.bwa && params.tool.split(',').contains('ciriquant') && params.module.split(',').contains('circrna_discovery') } + ext.when = { !params.bwa && params.tool.split(',').contains('ciriquant') } publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, @@ -131,7 +131,7 @@ if (!params.skip_trimming) { } withName: STAR_GENOMEGENERATE { - ext.when = { !params.star && params.module.split(',').contains('circrna_discovery') && ( params.tool.split(',').contains('circexplorer2') || params.tool.split(',').contains('dcc') || params.tool.split(',').contains('circrna_finder') ) } + ext.when = { !params.star && ( params.tool.split(',').contains('circexplorer2') || params.tool.split(',').contains('dcc') || params.tool.split(',').contains('circrna_finder') ) } ext.args = [ "", params.sjdboverhang ? "--sjdbOverhang ${params.sjdboverhang}" : '', ].join(' ').trim() @@ -181,7 +181,7 @@ if (!params.skip_trimming) { } withName: '.*:STAR2PASS:PASS_1' { - ext.when = { params.module.split(',').contains('circrna_discovery') && ( params.tool.split(',').contains('circexplorer2') || params.tool.split(',').contains('circrna_finder') ) } + ext.when = { params.tool.split(',').contains('circexplorer2') || params.tool.split(',').contains('circrna_finder') } ext.args = [ "", "--chimOutType Junctions WithinBAM", "--outSAMunmapped Within", From f351b961d185f7173f3d7a4c2f73bf051930595f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 27 May 2024 15:09:40 +0200 Subject: [PATCH 257/491] Fix code style problems --- subworkflows/local/discovery/annotation.nf | 4 ++-- subworkflows/local/discovery/circexplorer2.nf | 6 +++--- subworkflows/local/discovery/circrna_finder.nf | 10 +++++----- subworkflows/local/discovery/ciriquant.nf | 4 ++-- subworkflows/local/discovery/dcc.nf | 8 ++++---- subworkflows/local/discovery/find_circ.nf | 4 ++-- subworkflows/local/discovery/mapsplice.nf | 6 +++--- subworkflows/local/discovery/segemehl.nf | 2 +- subworkflows/local/discovery/star2pass.nf | 4 ++-- 9 files changed, 24 insertions(+), 24 deletions(-) diff --git a/subworkflows/local/discovery/annotation.nf b/subworkflows/local/discovery/annotation.nf index feded6a5..d865a5da 100644 --- a/subworkflows/local/discovery/annotation.nf +++ b/subworkflows/local/discovery/annotation.nf @@ -9,7 +9,7 @@ workflow ANNOTATION { regions gtf exon_boundary - + main: ch_versions = Channel.empty() @@ -35,4 +35,4 @@ workflow ANNOTATION { gtf = COMBINE_GTFS.out.sorted versions = ch_versions -} \ No newline at end of file +} diff --git a/subworkflows/local/discovery/circexplorer2.nf b/subworkflows/local/discovery/circexplorer2.nf index 2a04386c..b3908e91 100644 --- a/subworkflows/local/discovery/circexplorer2.nf +++ b/subworkflows/local/discovery/circexplorer2.nf @@ -8,10 +8,10 @@ workflow CIRCEXPLORER2 { gtf fasta star_junctions - + main: ch_versions = Channel.empty() - + REFERENCE( gtf ) PARSE( star_junctions ) ANNOTATE( PARSE.out.junction, fasta, REFERENCE.out.txt ) @@ -27,4 +27,4 @@ workflow CIRCEXPLORER2 { bed = UNIFY.out.output versions = ch_versions -} \ No newline at end of file +} diff --git a/subworkflows/local/discovery/circrna_finder.nf b/subworkflows/local/discovery/circrna_finder.nf index c57bbe94..a4545939 100644 --- a/subworkflows/local/discovery/circrna_finder.nf +++ b/subworkflows/local/discovery/circrna_finder.nf @@ -7,22 +7,22 @@ workflow CIRCRNA_FINDER { star_sam star_junctions star_tab - + main: ch_versions = Channel.empty() ch_joined = star_sam.join(star_junctions).join(star_tab) - .map{ meta, sam, junction, tab -> + .map{ meta, sam, junction, tab -> [ meta + [tool: "circrna_finder"], [sam, junction, tab] ] } - + MAIN( ch_joined ) UNIFY( MAIN.out.results, [] ) ch_versions = ch_versions.mix(MAIN.out.versions) ch_versions = ch_versions.mix(UNIFY.out.versions) - + emit: bed = UNIFY.out.output versions = ch_versions -} \ No newline at end of file +} diff --git a/subworkflows/local/discovery/ciriquant.nf b/subworkflows/local/discovery/ciriquant.nf index 7bf8c617..7340e6e1 100644 --- a/subworkflows/local/discovery/ciriquant.nf +++ b/subworkflows/local/discovery/ciriquant.nf @@ -8,7 +8,7 @@ workflow CIRIQUANT { ch_fasta bwa_index hisat2_index - + main: ch_versions = Channel.empty() @@ -23,4 +23,4 @@ workflow CIRIQUANT { bed = UNIFY.out.output versions = ch_versions -} \ No newline at end of file +} diff --git a/subworkflows/local/discovery/dcc.nf b/subworkflows/local/discovery/dcc.nf index ecc88c2b..4bb1103d 100644 --- a/subworkflows/local/discovery/dcc.nf +++ b/subworkflows/local/discovery/dcc.nf @@ -18,10 +18,10 @@ workflow DCC { seq_platform seq_center bsj_reads - + main: ch_versions = Channel.empty() - + mate1 = reads.filter{ meta, reads -> !meta.single_end } .map{ meta, reads -> return [ [id: meta.id, single_end: true], reads[0] ] } MATE1_1ST_PASS( mate1, star_index, ch_gtf, ignore_sjdbgtf, seq_platform, seq_center ) @@ -62,6 +62,6 @@ workflow DCC { emit: bed = UNIFY.out.output - + versions = ch_versions -} \ No newline at end of file +} diff --git a/subworkflows/local/discovery/find_circ.nf b/subworkflows/local/discovery/find_circ.nf index c1f3772d..ce0cc557 100644 --- a/subworkflows/local/discovery/find_circ.nf +++ b/subworkflows/local/discovery/find_circ.nf @@ -10,7 +10,7 @@ workflow FIND_CIRC { reads bowtie2_index ch_fasta - + main: ch_versions = Channel.empty() @@ -33,4 +33,4 @@ workflow FIND_CIRC { bed = UNIFY.out.output versions = ch_versions -} \ No newline at end of file +} diff --git a/subworkflows/local/discovery/mapsplice.nf b/subworkflows/local/discovery/mapsplice.nf index 847515de..f8112426 100644 --- a/subworkflows/local/discovery/mapsplice.nf +++ b/subworkflows/local/discovery/mapsplice.nf @@ -12,7 +12,7 @@ workflow MAPSPLICE { bowtie_index chromosomes star_junctions - + main: ch_versions = Channel.empty() @@ -28,9 +28,9 @@ workflow MAPSPLICE { ch_versions = ch_versions.mix(PARSE.out.versions) ch_versions = ch_versions.mix(ANNOTATE.out.versions) ch_versions = ch_versions.mix(UNIFY.out.versions) - + emit: bed = UNIFY.out.output versions = ch_versions -} \ No newline at end of file +} diff --git a/subworkflows/local/discovery/segemehl.nf b/subworkflows/local/discovery/segemehl.nf index d50ed70a..5aa4b342 100644 --- a/subworkflows/local/discovery/segemehl.nf +++ b/subworkflows/local/discovery/segemehl.nf @@ -24,4 +24,4 @@ workflow SEGEMEHL { bed = UNIFY.out.output versions = ch_versions -} \ No newline at end of file +} diff --git a/subworkflows/local/discovery/star2pass.nf b/subworkflows/local/discovery/star2pass.nf index 65ce3e34..4e216545 100644 --- a/subworkflows/local/discovery/star2pass.nf +++ b/subworkflows/local/discovery/star2pass.nf @@ -12,7 +12,7 @@ workflow STAR2PASS { ignore_sjdbgtf seq_center seq_platform - + main: ch_versions = Channel.empty() @@ -31,4 +31,4 @@ workflow STAR2PASS { tab = PASS_2.out.tab versions = ch_versions -} \ No newline at end of file +} From 43a1c4d7521101d34c073ebf04d780a76a4c7fd2 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 30 May 2024 13:48:16 +0200 Subject: [PATCH 258/491] Update nf-core modules --- modules.json | 16 +- modules/nf-core/bowtie2/align/main.nf | 2 +- modules/nf-core/bowtie2/align/meta.yml | 43 ++++-- modules/nf-core/bwa/index/environment.yml | 2 +- modules/nf-core/bwa/index/main.nf | 4 +- modules/nf-core/bwa/index/meta.yml | 1 + .../nf-core/bwa/index/tests/main.nf.test.snap | 10 +- modules/nf-core/cat/fastq/tests/main.nf.test | 2 + modules/nf-core/csvtk/join/environment.yml | 2 +- modules/nf-core/csvtk/join/main.nf | 5 +- modules/nf-core/csvtk/join/tests/main.nf.test | 64 ++++++++ .../csvtk/join/tests/main.nf.test.snap | 60 ++++++++ .../nf-core/csvtk/join/tests/nextflow.config | 5 + modules/nf-core/csvtk/join/tests/tags.yml | 2 + modules/nf-core/csvtk/split/environment.yml | 3 +- modules/nf-core/csvtk/split/main.nf | 17 ++- .../nf-core/csvtk/split/tests/main.nf.test | 62 ++++++++ .../csvtk/split/tests/main.nf.test.snap | 72 +++++++++ .../nf-core/csvtk/split/tests/nextflow.config | 5 + modules/nf-core/csvtk/split/tests/tags.yml | 2 + modules/nf-core/gawk/environment.yml | 2 +- modules/nf-core/gawk/main.nf | 4 +- modules/nf-core/gawk/tests/main.nf.test.snap | 16 +- modules/nf-core/segemehl/align/main.nf | 11 +- modules/nf-core/segemehl/align/meta.yml | 35 ++++- .../nf-core/segemehl/align/tests/main.nf.test | 140 ++++++++++++++++++ .../segemehl/align/tests/main.nf.test.snap | 50 +++++++ .../nf-core/segemehl/align/tests/split.config | 5 + modules/nf-core/segemehl/align/tests/tags.yml | 2 + .../tximeta/tximport/templates/tximport.r | 2 - .../tximeta/tximport/tests/main.nf.test.snap | 72 ++++----- 31 files changed, 626 insertions(+), 92 deletions(-) create mode 100644 modules/nf-core/csvtk/join/tests/main.nf.test create mode 100644 modules/nf-core/csvtk/join/tests/main.nf.test.snap create mode 100644 modules/nf-core/csvtk/join/tests/nextflow.config create mode 100644 modules/nf-core/csvtk/join/tests/tags.yml create mode 100644 modules/nf-core/csvtk/split/tests/main.nf.test create mode 100644 modules/nf-core/csvtk/split/tests/main.nf.test.snap create mode 100644 modules/nf-core/csvtk/split/tests/nextflow.config create mode 100644 modules/nf-core/csvtk/split/tests/tags.yml create mode 100644 modules/nf-core/segemehl/align/tests/main.nf.test create mode 100644 modules/nf-core/segemehl/align/tests/main.nf.test.snap create mode 100644 modules/nf-core/segemehl/align/tests/split.config create mode 100644 modules/nf-core/segemehl/align/tests/tags.yml diff --git a/modules.json b/modules.json index acc410f5..6e535782 100644 --- a/modules.json +++ b/modules.json @@ -32,7 +32,7 @@ }, "bowtie2/align": { "branch": "master", - "git_sha": "0fe30831abbc2ed115e46e92330edf38f56edc3d", + "git_sha": "e4bad511789f16d0df39ee306b2cd50418365048", "installed_by": ["modules"] }, "bowtie2/build": { @@ -42,7 +42,7 @@ }, "bwa/index": { "branch": "master", - "git_sha": "6278bf9afd4a4b2d00fa6052250e73da3d91546f", + "git_sha": "086fa66260595e123b0ea47a6512539b72a9afa3", "installed_by": ["modules"] }, "cat/cat": { @@ -52,7 +52,7 @@ }, "cat/fastq": { "branch": "master", - "git_sha": "0997b47c93c06b49aa7b3fefda87e728312cf2ca", + "git_sha": "4fc983ad0b30e6e32696fa7d980c76c7bfe1c03e", "installed_by": ["modules"] }, "circexplorer2/annotate": { @@ -67,12 +67,12 @@ }, "csvtk/join": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "614abbf126f287a3068dc86997b2e1b6a93abe20", "installed_by": ["modules"] }, "csvtk/split": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "614abbf126f287a3068dc86997b2e1b6a93abe20", "installed_by": ["modules"] }, "custom/dumpsoftwareversions": { @@ -92,7 +92,7 @@ }, "gawk": { "branch": "master", - "git_sha": "b42fec6f7c6e5d0716685cabb825ef6bf6e386b5", + "git_sha": "cf3ed075695639b0a0924eb0901146df1996dc08", "installed_by": ["modules"] }, "gnu/sort": { @@ -162,7 +162,7 @@ }, "segemehl/align": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "9a6b0745dbb5359286d36dee2183ffab240abba0", "installed_by": ["modules"] }, "segemehl/index": { @@ -192,7 +192,7 @@ }, "tximeta/tximport": { "branch": "master", - "git_sha": "c275c3baac6df8f0c7c500760a0cf014ce7b525d", + "git_sha": "5d095e8413da1f4c72b7d07ce87f75c09482486f", "installed_by": ["modules"] } } diff --git a/modules/nf-core/bowtie2/align/main.nf b/modules/nf-core/bowtie2/align/main.nf index 96a7027d..809525ad 100644 --- a/modules/nf-core/bowtie2/align/main.nf +++ b/modules/nf-core/bowtie2/align/main.nf @@ -1,6 +1,6 @@ process BOWTIE2_ALIGN { tag "$meta.id" - label "process_high" + label 'process_high' conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? diff --git a/modules/nf-core/bowtie2/align/meta.yml b/modules/nf-core/bowtie2/align/meta.yml index e66811d0..38610e0e 100644 --- a/modules/nf-core/bowtie2/align/meta.yml +++ b/modules/nf-core/bowtie2/align/meta.yml @@ -36,6 +36,15 @@ input: type: file description: Bowtie2 genome index files pattern: "*.ebwt" + - meta3: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'test', single_end:false ] + - fasta: + type: file + description: Bowtie2 genome fasta file + pattern: "*.fasta" - save_unaligned: type: boolean description: | @@ -46,22 +55,38 @@ input: description: use samtools sort (true) or samtools view (false) pattern: "true or false" output: - - aligned: + - sam: type: file - description: Output BAM/SAM file containing read alignments - pattern: "*.{bam,sam}" - - versions: + description: Output SAM file containing read alignments + pattern: "*.sam" + - bam: type: file - description: File containing software versions - pattern: "versions.yml" - - fastq: + description: Output BAM file containing read alignments + pattern: "*.bam" + - cram: type: file - description: Unaligned FastQ files - pattern: "*.fastq.gz" + description: Output CRAM file containing read alignments + pattern: "*.cram" + - csi: + type: file + description: Output SAM/BAM index for large inputs + pattern: "*.csi" + - crai: + type: file + description: Output CRAM index + pattern: "*.crai" - log: type: file description: Aligment log pattern: "*.log" + - fastq: + type: file + description: Unaligned FastQ files + pattern: "*.fastq.gz" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" authors: - "@joseespinosa" - "@drpatelh" diff --git a/modules/nf-core/bwa/index/environment.yml b/modules/nf-core/bwa/index/environment.yml index 5d3cb323..126e0034 100644 --- a/modules/nf-core/bwa/index/environment.yml +++ b/modules/nf-core/bwa/index/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - bioconda::bwa=0.7.17 + - bioconda::bwa=0.7.18 diff --git a/modules/nf-core/bwa/index/main.nf b/modules/nf-core/bwa/index/main.nf index 24b5a2ea..2e48b6ca 100644 --- a/modules/nf-core/bwa/index/main.nf +++ b/modules/nf-core/bwa/index/main.nf @@ -4,8 +4,8 @@ process BWA_INDEX { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/bwa:0.7.17--hed695b0_7' : - 'biocontainers/bwa:0.7.17--hed695b0_7' }" + 'https://depot.galaxyproject.org/singularity/bwa:0.7.18--he4a0461_0' : + 'biocontainers/bwa:0.7.18--he4a0461_0' }" input: tuple val(meta), path(fasta) diff --git a/modules/nf-core/bwa/index/meta.yml b/modules/nf-core/bwa/index/meta.yml index 730628d0..4c7d30f3 100644 --- a/modules/nf-core/bwa/index/meta.yml +++ b/modules/nf-core/bwa/index/meta.yml @@ -43,3 +43,4 @@ authors: maintainers: - "@drpatelh" - "@maxulysse" + - "@gallvp" diff --git a/modules/nf-core/bwa/index/tests/main.nf.test.snap b/modules/nf-core/bwa/index/tests/main.nf.test.snap index e51ad5bf..7c8f0465 100644 --- a/modules/nf-core/bwa/index/tests/main.nf.test.snap +++ b/modules/nf-core/bwa/index/tests/main.nf.test.snap @@ -17,7 +17,7 @@ ] ], "1": [ - "versions.yml:md5,0f20525da90e7489a7ebb02adca3265f" + "versions.yml:md5,a64462ac7dfb21f4ade9b02e7f65c5bb" ], "index": [ [ @@ -34,10 +34,14 @@ ] ], "versions": [ - "versions.yml:md5,0f20525da90e7489a7ebb02adca3265f" + "versions.yml:md5,a64462ac7dfb21f4ade9b02e7f65c5bb" ] } ], - "timestamp": "2023-10-17T17:20:20.180927714" + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-05-16T11:40:09.925307" } } \ No newline at end of file diff --git a/modules/nf-core/cat/fastq/tests/main.nf.test b/modules/nf-core/cat/fastq/tests/main.nf.test index dab2e14c..a71dcb8d 100644 --- a/modules/nf-core/cat/fastq/tests/main.nf.test +++ b/modules/nf-core/cat/fastq/tests/main.nf.test @@ -1,3 +1,5 @@ +// NOTE The version snaps may not be consistant +// https://github.com/nf-core/modules/pull/4087#issuecomment-1767948035 nextflow_process { name "Test Process CAT_FASTQ" diff --git a/modules/nf-core/csvtk/join/environment.yml b/modules/nf-core/csvtk/join/environment.yml index b488c861..5b6c6468 100644 --- a/modules/nf-core/csvtk/join/environment.yml +++ b/modules/nf-core/csvtk/join/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - bioconda::csvtk=0.26.0 + - bioconda::csvtk=0.30.0 diff --git a/modules/nf-core/csvtk/join/main.nf b/modules/nf-core/csvtk/join/main.nf index bf02e7f5..5f3afeea 100644 --- a/modules/nf-core/csvtk/join/main.nf +++ b/modules/nf-core/csvtk/join/main.nf @@ -4,8 +4,8 @@ process CSVTK_JOIN { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/csvtk:0.26.0--h9ee0642_0': - 'biocontainers/csvtk:0.26.0--h9ee0642_0' }" + 'https://depot.galaxyproject.org/singularity/csvtk:0.30.0--h9ee0642_0': + 'biocontainers/csvtk:0.30.0--h9ee0642_0' }" input: tuple val(meta), path(csv) @@ -36,7 +36,6 @@ process CSVTK_JOIN { """ stub: - def args = task.ext.args ?: '' prefix = task.ext.prefix ?: "${meta.id}" out_extension = args.contains('--out-delimiter "\t"') || args.contains('-D "\t"') || args.contains("-D \$'\t'") ? "tsv" : "csv" """ diff --git a/modules/nf-core/csvtk/join/tests/main.nf.test b/modules/nf-core/csvtk/join/tests/main.nf.test new file mode 100644 index 00000000..3cf178c4 --- /dev/null +++ b/modules/nf-core/csvtk/join/tests/main.nf.test @@ -0,0 +1,64 @@ +nextflow_process { + + name "Test Process CSVTK_JOIN" + script "../main.nf" + process "CSVTK_JOIN" + + tag "modules" + tag "modules_nfcore" + tag "csvtk" + tag "csvtk/join" + + test("join - csv") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + [ + file("https://github.com/nf-core/test-datasets/raw/bacass/bacass_hybrid.csv", checkIfExists: true), + file("https://github.com/nf-core/test-datasets/raw/bacass/bacass_short.csv", checkIfExists: true), + ] + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("join - csv - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + [ + file("https://github.com/nf-core/test-datasets/raw/bacass/bacass_hybrid.csv", checkIfExists: true), + file("https://github.com/nf-core/test-datasets/raw/bacass/bacass_short.csv", checkIfExists: true), + ] + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/nf-core/csvtk/join/tests/main.nf.test.snap b/modules/nf-core/csvtk/join/tests/main.nf.test.snap new file mode 100644 index 00000000..b124788b --- /dev/null +++ b/modules/nf-core/csvtk/join/tests/main.nf.test.snap @@ -0,0 +1,60 @@ +{ + "join - csv": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.csv:md5,d0ad82ca096c7e05eb9f9a04194c9e30" + ] + ], + "1": [ + "versions.yml:md5,e76147e4eca968d23543e7007522f1d3" + ], + "csv": [ + [ + { + "id": "test" + }, + "test.csv:md5,d0ad82ca096c7e05eb9f9a04194c9e30" + ] + ], + "versions": [ + "versions.yml:md5,e76147e4eca968d23543e7007522f1d3" + ] + } + ], + "timestamp": "2024-05-21T15:45:44.045434" + }, + "join - csv - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.csv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,e76147e4eca968d23543e7007522f1d3" + ], + "csv": [ + [ + { + "id": "test" + }, + "test.csv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e76147e4eca968d23543e7007522f1d3" + ] + } + ], + "timestamp": "2024-05-21T15:45:55.59201" + } +} \ No newline at end of file diff --git a/modules/nf-core/csvtk/join/tests/nextflow.config b/modules/nf-core/csvtk/join/tests/nextflow.config new file mode 100644 index 00000000..1b14393a --- /dev/null +++ b/modules/nf-core/csvtk/join/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: CSVTK_JOIN { + ext.args = "--fields 'ID;ID' -p -e -d \"\t\" -D \",\"" + } +} diff --git a/modules/nf-core/csvtk/join/tests/tags.yml b/modules/nf-core/csvtk/join/tests/tags.yml new file mode 100644 index 00000000..6c3a0fa6 --- /dev/null +++ b/modules/nf-core/csvtk/join/tests/tags.yml @@ -0,0 +1,2 @@ +csvtk/join: + - "modules/nf-core/csvtk/join/**" diff --git a/modules/nf-core/csvtk/split/environment.yml b/modules/nf-core/csvtk/split/environment.yml index 146d94db..ec08bb43 100644 --- a/modules/nf-core/csvtk/split/environment.yml +++ b/modules/nf-core/csvtk/split/environment.yml @@ -1,6 +1,7 @@ +name: csvtk_split channels: - conda-forge - bioconda - defaults dependencies: - - bioconda::csvtk=0.23.0 + - bioconda::csvtk=0.30.0 diff --git a/modules/nf-core/csvtk/split/main.nf b/modules/nf-core/csvtk/split/main.nf index cf17556c..1b7d5dd1 100644 --- a/modules/nf-core/csvtk/split/main.nf +++ b/modules/nf-core/csvtk/split/main.nf @@ -4,8 +4,8 @@ process CSVTK_SPLIT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/csvtk:0.23.0--h9ee0642_0' : - 'biocontainers/csvtk:0.23.0--h9ee0642_0' }" + 'https://depot.galaxyproject.org/singularity/csvtk:0.30.0--h9ee0642_0' : + 'biocontainers/csvtk:0.30.0--h9ee0642_0' }" input: tuple val(meta), path(csv) @@ -40,4 +40,17 @@ process CSVTK_SPLIT { csvtk: \$(echo \$( csvtk version | sed -e 's/csvtk v//g' )) END_VERSIONS """ + + stub: + def args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${meta.id}" + out_extension = args.contains('--out-delimiter "\t"') || args.contains('-D "\t"') || args.contains("-D \$'\t'") ? "tsv" : "csv" + """ + touch ${prefix}.${out_extension} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + csvtk: \$(echo \$( csvtk version | sed -e "s/csvtk v//g" )) + END_VERSIONS + """ } diff --git a/modules/nf-core/csvtk/split/tests/main.nf.test b/modules/nf-core/csvtk/split/tests/main.nf.test new file mode 100644 index 00000000..f3c49926 --- /dev/null +++ b/modules/nf-core/csvtk/split/tests/main.nf.test @@ -0,0 +1,62 @@ +nextflow_process { + + name "Test Process CSVTK_SPLIT" + script "../main.nf" + process "CSVTK_SPLIT" + + tag "modules" + tag "modules_nfcore" + tag "csvtk" + tag "csvtk/split" + + test("split - csv") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + [ file(params.modules_testdata_base_path + '/generic/tsv/test.tsv', checkIfExists: true) ] + ] + input[1] = "tsv" + input[2] = "tsv" + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("split - csv - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + [ file(params.modules_testdata_base_path + '/generic/tsv/test.tsv', checkIfExists: true) ] + ] + input[1] = "tsv" + input[2] = "tsv" + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/nf-core/csvtk/split/tests/main.nf.test.snap b/modules/nf-core/csvtk/split/tests/main.nf.test.snap new file mode 100644 index 00000000..f0ec9def --- /dev/null +++ b/modules/nf-core/csvtk/split/tests/main.nf.test.snap @@ -0,0 +1,72 @@ +{ + "split - csv - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.csv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,b17a61b0c41b19f7df3740979d68a8a0" + ], + "split_csv": [ + [ + { + "id": "test" + }, + "test.csv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,b17a61b0c41b19f7df3740979d68a8a0" + ] + } + ], + "timestamp": "2024-05-22T10:02:46.053585" + }, + "split - csv": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + [ + "test-1.tsv:md5,2827284f1a6f41dd14ef82fb6a36ebad", + "test-11.tsv:md5,6c5555d689c4e685d35d6e394ad6e1e6", + "test-2.tsv:md5,589a2add7f0b8e998d4959e5d883e7d5", + "test-4.tsv:md5,e51cd0bfc35f5353d1fb75f723772ed0", + "test-NA.tsv:md5,20afd42832c6cf5821f9862d285c9350" + ] + ] + ], + "1": [ + "versions.yml:md5,b17a61b0c41b19f7df3740979d68a8a0" + ], + "split_csv": [ + [ + { + "id": "test" + }, + [ + "test-1.tsv:md5,2827284f1a6f41dd14ef82fb6a36ebad", + "test-11.tsv:md5,6c5555d689c4e685d35d6e394ad6e1e6", + "test-2.tsv:md5,589a2add7f0b8e998d4959e5d883e7d5", + "test-4.tsv:md5,e51cd0bfc35f5353d1fb75f723772ed0", + "test-NA.tsv:md5,20afd42832c6cf5821f9862d285c9350" + ] + ] + ], + "versions": [ + "versions.yml:md5,b17a61b0c41b19f7df3740979d68a8a0" + ] + } + ], + "timestamp": "2024-05-22T10:02:35.8578" + } +} \ No newline at end of file diff --git a/modules/nf-core/csvtk/split/tests/nextflow.config b/modules/nf-core/csvtk/split/tests/nextflow.config new file mode 100644 index 00000000..8f5a6f7e --- /dev/null +++ b/modules/nf-core/csvtk/split/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: CSVTK_SPLIT { + ext.args = "-C \'&\' --fields \'first_name\' " + } +} diff --git a/modules/nf-core/csvtk/split/tests/tags.yml b/modules/nf-core/csvtk/split/tests/tags.yml new file mode 100644 index 00000000..0d7dc029 --- /dev/null +++ b/modules/nf-core/csvtk/split/tests/tags.yml @@ -0,0 +1,2 @@ +csvtk/split: + - "modules/nf-core/csvtk/split/**" diff --git a/modules/nf-core/gawk/environment.yml b/modules/nf-core/gawk/environment.yml index 34513c7f..3d98a08b 100644 --- a/modules/nf-core/gawk/environment.yml +++ b/modules/nf-core/gawk/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - anaconda::gawk=5.1.0 + - conda-forge::gawk=5.3.0 diff --git a/modules/nf-core/gawk/main.nf b/modules/nf-core/gawk/main.nf index 578b448c..ca468929 100644 --- a/modules/nf-core/gawk/main.nf +++ b/modules/nf-core/gawk/main.nf @@ -4,8 +4,8 @@ process GAWK { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/gawk:5.1.0' : - 'biocontainers/gawk:5.1.0' }" + 'https://depot.galaxyproject.org/singularity/gawk:5.3.0' : + 'biocontainers/gawk:5.3.0' }" input: tuple val(meta), path(input) diff --git a/modules/nf-core/gawk/tests/main.nf.test.snap b/modules/nf-core/gawk/tests/main.nf.test.snap index ce207478..4f3a759c 100644 --- a/modules/nf-core/gawk/tests/main.nf.test.snap +++ b/modules/nf-core/gawk/tests/main.nf.test.snap @@ -11,7 +11,7 @@ ] ], "1": [ - "versions.yml:md5,4c320d8c98ca80690afd7651da1ba520" + "versions.yml:md5,842acc9870dc8ac280954047cb2aa23a" ], "output": [ [ @@ -22,15 +22,15 @@ ] ], "versions": [ - "versions.yml:md5,4c320d8c98ca80690afd7651da1ba520" + "versions.yml:md5,842acc9870dc8ac280954047cb2aa23a" ] } ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.02.0" + "nextflow": "24.03.0" }, - "timestamp": "2024-04-05T11:00:28.097563" + "timestamp": "2024-05-17T15:20:02.495430346" }, "convert fasta to bed": { "content": [ @@ -44,7 +44,7 @@ ] ], "1": [ - "versions.yml:md5,4c320d8c98ca80690afd7651da1ba520" + "versions.yml:md5,842acc9870dc8ac280954047cb2aa23a" ], "output": [ [ @@ -55,14 +55,14 @@ ] ], "versions": [ - "versions.yml:md5,4c320d8c98ca80690afd7651da1ba520" + "versions.yml:md5,842acc9870dc8ac280954047cb2aa23a" ] } ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.02.0" + "nextflow": "24.03.0" }, - "timestamp": "2024-04-05T10:28:15.625869" + "timestamp": "2024-05-17T15:19:53.291809648" } } \ No newline at end of file diff --git a/modules/nf-core/segemehl/align/main.nf b/modules/nf-core/segemehl/align/main.nf index 77f88820..fa829a73 100644 --- a/modules/nf-core/segemehl/align/main.nf +++ b/modules/nf-core/segemehl/align/main.nf @@ -13,8 +13,11 @@ process SEGEMEHL_ALIGN { path(index) output: - tuple val(meta), path("${prefix}/*"), emit: results - path "versions.yml" , emit: versions + tuple val(meta), path("${prefix}/${prefix}.${suffix}"), emit: alignment + tuple val(meta), path("${prefix}/${prefix}.trns.txt") , emit: trans_alignments, optional: true + tuple val(meta), path("${prefix}/${prefix}.mult.bed") , emit: multi_bed, optional: true + tuple val(meta), path("${prefix}/${prefix}.sngl.bed") , emit: single_bed, optional: true + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -23,7 +26,7 @@ process SEGEMEHL_ALIGN { def args = task.ext.args ?: '' prefix = task.ext.prefix ?: "${meta.id}" def reads = meta.single_end ? "-q ${reads}" : "-q ${reads[0]} -p ${reads[1]}" - def suffix = ( args.contains("-b") || args.contains("--bamabafixoida") ) ? "bam" : "sam" + suffix = ( args.contains("-b") || args.contains("--bamabafixoida") ) ? "bam" : "sam" """ mkdir -p $prefix @@ -43,7 +46,7 @@ process SEGEMEHL_ALIGN { stub: prefix = task.ext.prefix ?: "${meta.id}" - def suffix = ( args.contains("-b") || args.contains("--bamabafixoida") ) ? "bam" : "sam" + suffix = ( args.contains("-b") || args.contains("--bamabafixoida") ) ? "bam" : "sam" """ mkdir -p $prefix touch ${prefix}/${prefix}.${suffix} diff --git a/modules/nf-core/segemehl/align/meta.yml b/modules/nf-core/segemehl/align/meta.yml index aaad17eb..fc8e43ba 100644 --- a/modules/nf-core/segemehl/align/meta.yml +++ b/modules/nf-core/segemehl/align/meta.yml @@ -11,7 +11,7 @@ tools: homepage: "https://www.bioinf.uni-leipzig.de/Software/segemehl/" documentation: "https://www.bioinf.uni-leipzig.de/Software/segemehl/" doi: "10.1186/gb-2014-15-2-r34" - licence: "GPL v3" + licence: ["GPL v3"] input: - meta: type: map @@ -36,19 +36,38 @@ output: description: | Groovy Map containing sample information e.g. [ id:'test', single_end:false ] - - results: - type: directory + - alignment: + type: file description: | - Directory containing genomic alignments in SAM format + File containing genomic alignments in SAM format (please add "-b" flag to task.ext.args for BAM) - In addition to split-read alignments files when -S parameter used. - [ *.{sam,bam}, *.trns.txt, *.mult.bed, *.sngl.bed ] - pattern: "${meta.id}*" + pattern: "*.{sam,bam}" + - trans_alignments: + type: file + description: | + Custom text file containing all single split alignments predicted to be in trans + (optional, only if -S flag is set in task.ext.args) + pattern: "*.trns.txt" + - single_bed: + type: file + description: | + Bed file containing all single splice events predicted + in the split read alignments. + (optional, only if -S flag is set in task.ext.args) + pattern: "*.sngl.bed" + - multi_bed: + type: file + description: | + Bed file containing all splice events predicted + in the split read alignments. + (optional, only if -S flag is set in task.ext.args) + pattern: "*.mult.bed" - versions: type: file description: File containing software versions pattern: "versions.yml" authors: - "@BarryDigby" + - "@nictru" maintainers: - - "@BarryDigby" + - "@nictru" diff --git a/modules/nf-core/segemehl/align/tests/main.nf.test b/modules/nf-core/segemehl/align/tests/main.nf.test new file mode 100644 index 00000000..c1b4921e --- /dev/null +++ b/modules/nf-core/segemehl/align/tests/main.nf.test @@ -0,0 +1,140 @@ +nextflow_process { + + name "Test Process SEGEMEHL_ALIGN" + script "../main.nf" + process "SEGEMEHL_ALIGN" + tag "modules" + tag "modules_nfcore" + tag "segemehl" + tag "segemehl/align" + tag "segemehl/index" + + setup { + run("SEGEMEHL_INDEX") { + script "../../../segemehl/index/main.nf" + process { + """ + input[0] = Channel.of([ + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) + """ + } + } + } + + test("homo_sapiens - single_end") { + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true) ] + ]) + input[1] = Channel.of([ + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) + input[2] = SEGEMEHL_INDEX.out.index + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert path(process.out.alignment[0][1]).exists() }, + { assert snapshot(process.out.versions).match("homo_sapiens - single_end - versions") } + ) + } + } + + test("homo_sapiens - paired_end") { + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true) + ] + ]) + input[1] = Channel.of([ + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) + input[2] = SEGEMEHL_INDEX.out.index + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert path(process.out.alignment[0][1]).exists() }, + { assert snapshot(process.out.versions).match("homo_sapiens - paired_end - versions") } + ) + } + } + + test("homo_sapiens - split - single_end") { + config "./split.config" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true) ] + ]) + input[1] = Channel.of([ + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) + input[2] = SEGEMEHL_INDEX.out.index + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert path(process.out.alignment[0][1]).exists() }, + { assert path(process.out.trans_alignments[0][1]).exists() }, + { assert path(process.out.multi_bed[0][1]).exists() }, + { assert path(process.out.single_bed[0][1]).exists() }, + { assert snapshot(process.out.versions).match("homo_sapiens - split - single_end - versions") } + ) + } + } + + test("homo_sapiens - split - paired_end") { + config "./split.config" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true) + ] + ]) + input[1] = Channel.of([ + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) + input[2] = SEGEMEHL_INDEX.out.index + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert path(process.out.alignment[0][1]).exists() }, + { assert path(process.out.trans_alignments[0][1]).exists() }, + { assert path(process.out.multi_bed[0][1]).exists() }, + { assert path(process.out.single_bed[0][1]).exists() }, + { assert snapshot(process.out.versions).match("homo_sapiens - split - paired_end - versions") } + ) + } + } +} \ No newline at end of file diff --git a/modules/nf-core/segemehl/align/tests/main.nf.test.snap b/modules/nf-core/segemehl/align/tests/main.nf.test.snap new file mode 100644 index 00000000..c914bc3d --- /dev/null +++ b/modules/nf-core/segemehl/align/tests/main.nf.test.snap @@ -0,0 +1,50 @@ +{ + "homo_sapiens - paired_end - versions": { + "content": [ + [ + "versions.yml:md5,0c6afcd6ae65e27a0ea87f5b42c853eb" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-05-30T12:58:05.434115758" + }, + "homo_sapiens - single_end - versions": { + "content": [ + [ + "versions.yml:md5,0c6afcd6ae65e27a0ea87f5b42c853eb" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-05-30T12:57:56.488707635" + }, + "homo_sapiens - split - single_end - versions": { + "content": [ + [ + "versions.yml:md5,0c6afcd6ae65e27a0ea87f5b42c853eb" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-05-30T13:06:11.217385877" + }, + "homo_sapiens - split - paired_end - versions": { + "content": [ + [ + "versions.yml:md5,0c6afcd6ae65e27a0ea87f5b42c853eb" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-05-30T13:06:29.757385118" + } +} \ No newline at end of file diff --git a/modules/nf-core/segemehl/align/tests/split.config b/modules/nf-core/segemehl/align/tests/split.config new file mode 100644 index 00000000..d4f6aab8 --- /dev/null +++ b/modules/nf-core/segemehl/align/tests/split.config @@ -0,0 +1,5 @@ +process{ + withName: SEGEMEHL_ALIGN { + ext.args = "-S" + } +} \ No newline at end of file diff --git a/modules/nf-core/segemehl/align/tests/tags.yml b/modules/nf-core/segemehl/align/tests/tags.yml new file mode 100644 index 00000000..6e7bf26e --- /dev/null +++ b/modules/nf-core/segemehl/align/tests/tags.yml @@ -0,0 +1,2 @@ +segemehl/align: + - modules/nf-core/segemehl/align/** diff --git a/modules/nf-core/tximeta/tximport/templates/tximport.r b/modules/nf-core/tximeta/tximport/templates/tximport.r index 92f1a9e8..40d79eb9 100755 --- a/modules/nf-core/tximeta/tximport/templates/tximport.r +++ b/modules/nf-core/tximeta/tximport/templates/tximport.r @@ -169,9 +169,7 @@ if ("tx2gene" %in% names(transcript_info) && !is.null(transcript_info\$tx2gene)) list(obj = gse, slot = "length", suffix = "gene_lengths.tsv"), list(obj = gse, slot = "abundance", suffix = "gene_tpm.tsv"), list(obj = gse, slot = "counts", suffix = "gene_counts.tsv"), - list(obj = gse.ls, slot = "abundance", suffix = "gene_tpm_length_scaled.tsv"), list(obj = gse.ls, slot = "counts", suffix = "gene_counts_length_scaled.tsv"), - list(obj = gse.s, slot = "abundance", suffix = "gene_tpm_scaled.tsv"), list(obj = gse.s, slot = "counts", suffix = "gene_counts_scaled.tsv") )) } diff --git a/modules/nf-core/tximeta/tximport/tests/main.nf.test.snap b/modules/nf-core/tximeta/tximport/tests/main.nf.test.snap index fe972d09..3cd0ee9e 100644 --- a/modules/nf-core/tximeta/tximport/tests/main.nf.test.snap +++ b/modules/nf-core/tximeta/tximport/tests/main.nf.test.snap @@ -14,7 +14,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:54.169267" + "timestamp": "2024-05-28T12:35:50.683744" }, "lengths_gene_kallisto - stub": { "content": [ @@ -31,7 +31,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:20.838048" + "timestamp": "2024-05-28T12:35:16.126128" }, "counts_gene_scaled_salmon - stub": { "content": [ @@ -48,7 +48,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:54.139493" + "timestamp": "2024-05-28T12:35:50.654405" }, "counts_gene_kallisto - stub": { "content": [ @@ -65,7 +65,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:20.823542" + "timestamp": "2024-05-28T12:35:16.112898" }, "lengths_transcript_salmon - stub": { "content": [ @@ -82,7 +82,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:54.157265" + "timestamp": "2024-05-28T12:35:50.67148" }, "versions_salmon - stub": { "content": [ @@ -94,7 +94,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:54.175019" + "timestamp": "2024-05-28T12:35:50.690592" }, "counts_gene_length_scaled_kallisto": { "content": [ @@ -111,7 +111,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:04.116135" + "timestamp": "2024-05-28T12:34:59.621599" }, "lengths_transcript_salmon": { "content": [ @@ -128,7 +128,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:37.664041" + "timestamp": "2024-05-28T12:35:32.876208" }, "counts_transcript_kallisto": { "content": [ @@ -145,7 +145,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:04.162273" + "timestamp": "2024-05-28T12:34:59.62725" }, "counts_transcript_kallisto - stub": { "content": [ @@ -162,7 +162,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:20.834743" + "timestamp": "2024-05-28T12:35:16.122852" }, "counts_transcript_salmon": { "content": [ @@ -179,7 +179,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:37.652813" + "timestamp": "2024-05-28T12:35:32.866731" }, "lengths_gene_salmon - stub": { "content": [ @@ -196,7 +196,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:54.151603" + "timestamp": "2024-05-28T12:35:50.6654" }, "tpm_gene_salmon": { "content": [ @@ -213,7 +213,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:37.669821" + "timestamp": "2024-05-28T12:35:32.881193" }, "tpm_transcript_salmon": { "content": [ @@ -230,7 +230,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:37.674895" + "timestamp": "2024-05-28T12:35:32.886363" }, "tpm_gene_salmon - stub": { "content": [ @@ -247,7 +247,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:54.163303" + "timestamp": "2024-05-28T12:35:50.677538" }, "lengths_transcript_kallisto": { "content": [ @@ -264,7 +264,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:04.1686" + "timestamp": "2024-05-28T12:34:59.632822" }, "counts_gene_length_scaled_kallisto - stub": { "content": [ @@ -281,7 +281,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:20.827742" + "timestamp": "2024-05-28T12:35:16.11652" }, "tpm_gene_kallisto - stub": { "content": [ @@ -298,7 +298,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:20.846428" + "timestamp": "2024-05-28T12:35:16.133742" }, "counts_transcript_salmon - stub": { "content": [ @@ -315,7 +315,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:54.145564" + "timestamp": "2024-05-28T12:35:50.660144" }, "counts_gene_scaled_kallisto": { "content": [ @@ -332,7 +332,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:04.159638" + "timestamp": "2024-05-28T12:34:59.624732" }, "counts_gene_salmon": { "content": [ @@ -349,7 +349,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:37.636972" + "timestamp": "2024-05-28T12:35:32.852188" }, "versions_salmon": { "content": [ @@ -361,7 +361,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:37.680246" + "timestamp": "2024-05-28T12:35:32.892224" }, "counts_gene_length_scaled_salmon": { "content": [ @@ -378,7 +378,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:37.642848" + "timestamp": "2024-05-28T12:35:32.857451" }, "tpm_gene_kallisto": { "content": [ @@ -395,7 +395,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:04.172531" + "timestamp": "2024-05-28T12:34:59.636454" }, "lengths_transcript_kallisto - stub": { "content": [ @@ -412,7 +412,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:20.842475" + "timestamp": "2024-05-28T12:35:16.129712" }, "lengths_gene_kallisto": { "content": [ @@ -429,7 +429,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:04.16551" + "timestamp": "2024-05-28T12:34:59.630042" }, "counts_gene_scaled_kallisto - stub": { "content": [ @@ -446,7 +446,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:20.831518" + "timestamp": "2024-05-28T12:35:16.119638" }, "tpm_transcript_kallisto": { "content": [ @@ -463,7 +463,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:04.177955" + "timestamp": "2024-05-28T12:34:59.639525" }, "lengths_gene_salmon": { "content": [ @@ -480,7 +480,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:37.658624" + "timestamp": "2024-05-28T12:35:32.871162" }, "counts_gene_length_scaled_salmon - stub": { "content": [ @@ -497,7 +497,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:54.13369" + "timestamp": "2024-05-28T12:35:50.605613" }, "counts_gene_kallisto": { "content": [ @@ -514,7 +514,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:04.113216" + "timestamp": "2024-05-28T12:34:59.61832" }, "versions_kallisto": { "content": [ @@ -526,7 +526,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:04.181904" + "timestamp": "2024-05-28T12:34:59.642751" }, "counts_gene_salmon - stub": { "content": [ @@ -543,7 +543,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:54.127272" + "timestamp": "2024-05-28T12:35:50.598457" }, "versions_kallisto - stub": { "content": [ @@ -555,7 +555,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:20.86053" + "timestamp": "2024-05-28T12:35:16.141689" }, "tpm_transcript_kallisto - stub": { "content": [ @@ -572,7 +572,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:20.856075" + "timestamp": "2024-05-28T12:35:16.137716" }, "counts_gene_scaled_salmon": { "content": [ @@ -589,6 +589,6 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-11T11:35:37.647691" + "timestamp": "2024-05-28T12:35:32.862272" } } \ No newline at end of file From b81a30a9826388d2b693b606d531b96414bdc63e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 30 May 2024 14:12:14 +0200 Subject: [PATCH 259/491] Update segemehl unify call --- subworkflows/local/discovery/segemehl.nf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subworkflows/local/discovery/segemehl.nf b/subworkflows/local/discovery/segemehl.nf index 5aa4b342..71669032 100644 --- a/subworkflows/local/discovery/segemehl.nf +++ b/subworkflows/local/discovery/segemehl.nf @@ -14,8 +14,8 @@ workflow SEGEMEHL { index = index ?: INDEX( fasta ).index ALIGN( reads, fasta, index ) - UNIFY( ALIGN.out.results - .map{ meta, results -> [ meta + [tool: "segemehl"], results ] }, [] ) + UNIFY( ALIGN.out.single_bed + .map{ meta, bed -> [ meta + [tool: "segemehl"], bed ] }, [] ) ch_versions = ch_versions.mix(ALIGN.out.versions) ch_versions = ch_versions.mix(UNIFY.out.versions) From 0a98534fd6a368dd7c643ef38e82e0b96dbacc0b Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 31 May 2024 13:04:46 +0200 Subject: [PATCH 260/491] Add support for ext.args in ciriquant --- modules/local/ciriquant/main.nf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/local/ciriquant/main.nf b/modules/local/ciriquant/main.nf index 5c96fe14..c1c29bfb 100644 --- a/modules/local/ciriquant/main.nf +++ b/modules/local/ciriquant/main.nf @@ -47,7 +47,8 @@ process CIRIQUANT { --config config.yml \\ --no-gene \\ -o ${prefix} \\ - -p ${prefix} + -p ${prefix} \\ + ${args} cat <<-END_VERSIONS > versions.yml "${task.process}": From 0cc85b036de4a7d9c74e109216c39b4caa5c999a Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 31 May 2024 13:51:03 +0200 Subject: [PATCH 261/491] Add strandedness to samplesheet --- assets/schema_input.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/assets/schema_input.json b/assets/schema_input.json index fe551cb8..7e9257a0 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -26,6 +26,13 @@ "exists": true, "pattern": "^\\S+\\.f(ast)?q\\.gz$", "errorMessage": "FastQ file for reads 2 cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz'" + }, + "strandedness": { + "type": "string", + "enum": ["unstranded", "forward", "reverse", "auto"], + "default": "auto", + "errorMessage": "Strandedness must be one of 'unstranded', 'forward', 'reverse' or 'auto'", + "meta": ["strandedness"] } }, "required": ["sample", "fastq_1"] From 30af702000fb90ec112240d620976639eeb75735 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 31 May 2024 14:03:27 +0200 Subject: [PATCH 262/491] Add support for strandedness in ciriquant --- modules/local/ciriquant/main.nf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/local/ciriquant/main.nf b/modules/local/ciriquant/main.nf index c1c29bfb..db228929 100644 --- a/modules/local/ciriquant/main.nf +++ b/modules/local/ciriquant/main.nf @@ -26,6 +26,8 @@ process CIRIQUANT { def args = task.ext.args ?: '' prefix = task.ext.prefix ?: "${meta.id}" def VERSION = '2.1.0' + def strandedness = meta.strandedness ?: 'auto' + def library_type = strandedness == 'auto' ? '' : strandedness == 'unstranded' ? '-l 0' : strandedness == 'forward' ? '-l 1' : '-l 2' """ BWA=`which bwa` HISAT2=`which hisat2` @@ -48,6 +50,7 @@ process CIRIQUANT { --no-gene \\ -o ${prefix} \\ -p ${prefix} \\ + ${library_type} \\ ${args} cat <<-END_VERSIONS > versions.yml From 9c5889989200b6781fcbbb7cfeca186395c5a794 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 31 May 2024 20:29:07 +0200 Subject: [PATCH 263/491] Revise DCC parameters --- modules/local/dcc/main.nf | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/local/dcc/main.nf b/modules/local/dcc/main.nf index 9baad3ff..429d7dc5 100644 --- a/modules/local/dcc/main.nf +++ b/modules/local/dcc/main.nf @@ -22,13 +22,15 @@ process DCC { script: def args = task.ext.args ?: '' prefix = task.ext.prefix ?: "${meta.id}" + def strandedness = meta.strandedness ?: 'auto' + def strand_args = strandedness == 'auto' || strandedness == 'unstranded' ? '-N' : strandedness == 'forward' ? '' : '-ss' if(meta.single_end){ """ sed -i 's/^chr//g' $gtf mkdir ${prefix} && mv ${prefix}.Chimeric.out.junction ${prefix} && printf "${prefix}/${prefix}.Chimeric.out.junction" > samplesheet - DCC @samplesheet -D -an $gtf -Pi -ss -F -M -Nr 1 1 -fg -A $fasta -N -T ${task.cpus} + DCC @samplesheet -D -an $gtf -F -M -Nr 1 1 -A $fasta $strand_args -T ${task.cpus} awk '{print \$6}' CircCoordinates >> strand paste CircRNACount strand | tail -n +2 | awk -v OFS="\\t" '{print \$1,\$2,\$3,\$5,\$4}' >> ${prefix}.txt @@ -46,7 +48,7 @@ process DCC { mkdir ${prefix}_mate1 && mv ${prefix}_mate1.Chimeric.out.junction ${prefix}_mate1 && printf "${prefix}_mate1/${prefix}_mate1.Chimeric.out.junction" > mate1file mkdir ${prefix}_mate2 && mv ${prefix}_mate2.Chimeric.out.junction ${prefix}_mate2 && printf "${prefix}_mate2/${prefix}_mate2.Chimeric.out.junction" > mate2file - DCC @samplesheet -mt1 @mate1file -mt2 @mate2file -D -an $gtf -Pi -ss -F -M -Nr 1 1 -fg -A $fasta -N -T ${task.cpus} + DCC @samplesheet -mt1 @mate1file -mt2 @mate2file -D -an $gtf -Pi -F -M -Nr 1 1 -A $fasta $strand_args -T ${task.cpus} awk '{print \$6}' CircCoordinates >> strand paste CircRNACount strand | tail -n +2 | awk -v OFS="\\t" '{print \$1,\$2,\$3,\$5,\$4}' >> ${prefix}.txt From f38c58cd5b13c61f646e6131f032a9fc7627d2d6 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 31 May 2024 20:43:19 +0200 Subject: [PATCH 264/491] Implement ext.args interface for find_circ --- modules/local/find_circ/find_circ/main.nf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/local/find_circ/find_circ/main.nf b/modules/local/find_circ/find_circ/main.nf index bd1bced2..3c367cf9 100644 --- a/modules/local/find_circ/find_circ/main.nf +++ b/modules/local/find_circ/find_circ/main.nf @@ -23,6 +23,8 @@ process FIND_CIRC { script: prefix = task.ext.prefix ?: "${meta.id}" + args = task.ext.args ?: "" + args2 = task.ext.args2 ?: "" def VERSION = '1.2' """ INDEX=`find -L ./ -name "*.rev.1.bt2" | sed "s/.rev.1.bt2//"` @@ -37,8 +39,9 @@ process FIND_CIRC { --score-min=C,-15,0 \\ -q \\ -x \$INDEX \\ + $args \\ -U $anchors | \\ - find_circ.py --genome=$fasta --prefix=${prefix} --stats=${prefix}.sites.log --reads=${prefix}.sites.reads > ${prefix}.sites.bed + find_circ.py --genome=$fasta $args2 --prefix=${prefix} --stats=${prefix}.sites.log --reads=${prefix}.sites.reads > ${prefix}.sites.bed cat <<-END_VERSIONS > versions.yml "${task.process}": From ca15b3a91c97acd8ec301425a283c890d0e4129b Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 31 May 2024 20:50:07 +0200 Subject: [PATCH 265/491] Fix trimming indentation in modules.config --- conf/modules.config | 54 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index a1cd75c2..03c820e7 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -28,36 +28,36 @@ process { // TRIMMING courtesy of nf-core/rnaseq -if (!params.skip_trimming) { - process { - withName: '.*:FASTQC_TRIMGALORE:TRIMGALORE' { - ext.args = { - [ - "--fastqc_args '-t ${task.cpus}' ", - params.trim_nextseq > 0 ? "--nextseq ${params.trim_nextseq}" : '' - ].join(' ').trim() - } - publishDir = [ - [ - path: { "${params.outdir}/quality_control/trimgalore/fastqc" }, - mode: params.publish_dir_mode, - pattern: "*.{html,zip}" - ], - [ - path: { "${params.outdir}/quality_control/trimgalore" }, - mode: params.publish_dir_mode, - pattern: "*.fq.gz", - enabled: params.save_trimmed - ], - [ - path: { "${params.outdir}/quality_control/trimgalore" }, - mode: params.publish_dir_mode, - pattern: "*.txt" + if (!params.skip_trimming) { + process { + withName: '.*:FASTQC_TRIMGALORE:TRIMGALORE' { + ext.args = { + [ + "--fastqc_args '-t ${task.cpus}' ", + params.trim_nextseq > 0 ? "--nextseq ${params.trim_nextseq}" : '' + ].join(' ').trim() + } + publishDir = [ + [ + path: { "${params.outdir}/quality_control/trimgalore/fastqc" }, + mode: params.publish_dir_mode, + pattern: "*.{html,zip}" + ], + [ + path: { "${params.outdir}/quality_control/trimgalore" }, + mode: params.publish_dir_mode, + pattern: "*.fq.gz", + enabled: params.save_trimmed + ], + [ + path: { "${params.outdir}/quality_control/trimgalore" }, + mode: params.publish_dir_mode, + pattern: "*.txt" + ] ] - ] + } } } -} // PREPARE GENOME withName: CLEAN_FASTA { From 2b54d433bf21d7ea00d3276ce03bd60a29461020 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 31 May 2024 20:50:49 +0200 Subject: [PATCH 266/491] Move segemehl index location in modules.config --- conf/modules.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 03c820e7..1a8754f2 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -143,6 +143,8 @@ process { ] } + // circRNA + withName: '.*:SEGEMEHL:INDEX' { publishDir = [ path: { "${params.outdir}/references/index/segemehl" }, @@ -152,8 +154,6 @@ process { ] } - // circRNA - withName: '.*:SEGEMEHL:ALIGN' { ext.args = [ "", "-b", From 022d66e0c85d6b7db58aafc7c2833bccfc356ec0 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 31 May 2024 20:59:09 +0200 Subject: [PATCH 267/491] Add strandedness to bowtie2 calls --- conf/modules.config | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 1a8754f2..569cedf4 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -295,13 +295,9 @@ process { } withName: '.*:FIND_CIRC:ALIGN' { - ext.args = [ "", - "--very-sensitive", - "--mm", - "-D 20", - "--score-min=C,-15,0", - "-q" - ].join(' ').trim() + ext.args = { "--very-sensitive --mm -D 20 --score-min=C,-15,0 -q " + + (!meta.strandedness || meta.strandedness == 'unstranded' || meta.strandedness == 'auto' ? '' : + meta.strandedness == 'forward' ? ' --norc' : ' --nofw') } publishDir = [ path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, @@ -331,6 +327,8 @@ process { } withName: '.*:FIND_CIRC:MAIN' { + ext.args = { !meta.strandedness || meta.strandedness == 'unstranded' || meta.strandedness == 'auto' ? '' : + meta.strandedness == 'forward' ? ' --norc' : ' --nofw' } publishDir = [ path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, From a41eab1fcd68ba9585cc475f087ba69d4ef8ef71 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 31 May 2024 21:06:20 +0200 Subject: [PATCH 268/491] Add strandedness to find_circ --- modules/local/find_circ/find_circ/main.nf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/local/find_circ/find_circ/main.nf b/modules/local/find_circ/find_circ/main.nf index 3c367cf9..8a4ca128 100644 --- a/modules/local/find_circ/find_circ/main.nf +++ b/modules/local/find_circ/find_circ/main.nf @@ -25,6 +25,7 @@ process FIND_CIRC { prefix = task.ext.prefix ?: "${meta.id}" args = task.ext.args ?: "" args2 = task.ext.args2 ?: "" + def strand_arg = meta.strandedness && (meta.strandedness == 'forward' || meta.strandedness == 'reverse') ? "--stranded" : "" def VERSION = '1.2' """ INDEX=`find -L ./ -name "*.rev.1.bt2" | sed "s/.rev.1.bt2//"` @@ -41,7 +42,7 @@ process FIND_CIRC { -x \$INDEX \\ $args \\ -U $anchors | \\ - find_circ.py --genome=$fasta $args2 --prefix=${prefix} --stats=${prefix}.sites.log --reads=${prefix}.sites.reads > ${prefix}.sites.bed + find_circ.py --genome=$fasta $strand_arg $args2 --prefix=${prefix} --stats=${prefix}.sites.log --reads=${prefix}.sites.reads > ${prefix}.sites.bed cat <<-END_VERSIONS > versions.yml "${task.process}": From 8957a7ee752f63ee031eaf27fa51d1551bcaeef3 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sun, 9 Jun 2024 15:26:49 +0200 Subject: [PATCH 269/491] Add strandedness documentation --- docs/usage.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 5c6337d5..e84dc944 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -24,21 +24,22 @@ The pipeline will auto-detect whether a sample is single- or paired-end using th A final samplesheet file consisting of both single- and paired-end data may look something like the one below. This is for 6 samples, where `TREATMENT_REP3` has been sequenced twice. ```csv title="samplesheet.csv" -sample,fastq_1,fastq_2 -CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz -CONTROL_REP2,AEG588A2_S2_L002_R1_001.fastq.gz,AEG588A2_S2_L002_R2_001.fastq.gz -CONTROL_REP3,AEG588A3_S3_L002_R1_001.fastq.gz,AEG588A3_S3_L002_R2_001.fastq.gz -TREATMENT_REP1,AEG588A4_S4_L003_R1_001.fastq.gz, -TREATMENT_REP2,AEG588A5_S5_L003_R1_001.fastq.gz, -TREATMENT_REP3,AEG588A6_S6_L003_R1_001.fastq.gz, -TREATMENT_REP3,AEG588A6_S6_L004_R1_001.fastq.gz, +sample,fastq_1,fastq_2,strandedness +CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz, +CONTROL_REP2,AEG588A2_S2_L002_R1_001.fastq.gz,AEG588A2_S2_L002_R2_001.fastq.gz, +CONTROL_REP3,AEG588A3_S3_L002_R1_001.fastq.gz,AEG588A3_S3_L002_R2_001.fastq.gz, +TREATMENT_REP1,AEG588A4_S4_L003_R1_001.fastq.gz,, +TREATMENT_REP2,AEG588A5_S5_L003_R1_001.fastq.gz,, +TREATMENT_REP3,AEG588A6_S6_L003_R1_001.fastq.gz,, +TREATMENT_REP3,AEG588A6_S6_L004_R1_001.fastq.gz,, ``` -| Column | Description | -| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `sample` | Custom sample name. This entry will be identical for multiple sequencing libraries/runs from the same sample. Spaces in sample names are automatically converted to underscores (`_`). | -| `fastq_1` | Full path to FastQ file for Illumina short reads 1. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | -| `fastq_2` | Full path to FastQ file for Illumina short reads 2. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | +| Column | Description | +| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `sample` | Custom sample name. This entry will be identical for multiple sequencing libraries/runs from the same sample. Spaces in sample names are automatically converted to underscores (`_`). | +| `fastq_1` | Full path to FastQ file for Illumina short reads 1. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | +| `fastq_2` | Full path to FastQ file for Illumina short reads 2. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | +| `strandedness` | Strandedness of the library. Options are `auto`, `unstranded`, `forward`, `reverse`. Default is `auto`. | An [example samplesheet](../assets/samplesheet.csv) has been provided with the pipeline. From c65e604d913e3657f6f5bef065acb08e556df726 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sun, 9 Jun 2024 15:33:17 +0200 Subject: [PATCH 270/491] Add samplesheet validation for strandedness of runs of the same sample --- docs/usage.md | 22 +++++++++---------- .../utils_nfcore_circrna_pipeline/main.nf | 6 +++++ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index e84dc944..c5312fa6 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -25,21 +25,21 @@ A final samplesheet file consisting of both single- and paired-end data may look ```csv title="samplesheet.csv" sample,fastq_1,fastq_2,strandedness -CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz, +CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz,auto CONTROL_REP2,AEG588A2_S2_L002_R1_001.fastq.gz,AEG588A2_S2_L002_R2_001.fastq.gz, CONTROL_REP3,AEG588A3_S3_L002_R1_001.fastq.gz,AEG588A3_S3_L002_R2_001.fastq.gz, -TREATMENT_REP1,AEG588A4_S4_L003_R1_001.fastq.gz,, -TREATMENT_REP2,AEG588A5_S5_L003_R1_001.fastq.gz,, -TREATMENT_REP3,AEG588A6_S6_L003_R1_001.fastq.gz,, -TREATMENT_REP3,AEG588A6_S6_L004_R1_001.fastq.gz,, +TREATMENT_REP1,AEG588A4_S4_L003_R1_001.fastq.gz,,forward +TREATMENT_REP2,AEG588A5_S5_L003_R1_001.fastq.gz,,reverse +TREATMENT_REP3,AEG588A6_S6_L003_R1_001.fastq.gz,,unstranded +TREATMENT_REP3,AEG588A6_S6_L004_R1_001.fastq.gz,,unstranded ``` -| Column | Description | -| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `sample` | Custom sample name. This entry will be identical for multiple sequencing libraries/runs from the same sample. Spaces in sample names are automatically converted to underscores (`_`). | -| `fastq_1` | Full path to FastQ file for Illumina short reads 1. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | -| `fastq_2` | Full path to FastQ file for Illumina short reads 2. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | -| `strandedness` | Strandedness of the library. Options are `auto`, `unstranded`, `forward`, `reverse`. Default is `auto`. | +| Column | Description | +| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `sample` | Custom sample name. This entry will be identical for multiple sequencing libraries/runs from the same sample. Spaces in sample names are automatically converted to underscores (`_`). | +| `fastq_1` | Full path to FastQ file for Illumina short reads 1. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | +| `fastq_2` | Full path to FastQ file for Illumina short reads 2. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | +| `strandedness` | Strandedness of the library. Options are `auto`, `unstranded`, `forward`, `reverse`. Default is `auto`. Make sure to use the same strandedness for each library/run of the same sample. | An [example samplesheet](../assets/samplesheet.csv) has been provided with the pipeline. diff --git a/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf b/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf index 15c32930..646b5476 100644 --- a/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_circrna_pipeline/main.nf @@ -170,6 +170,12 @@ def validateInputSamplesheet(input) { error("Please check input samplesheet -> Multiple runs of a sample must be of the same datatype i.e. single-end or paired-end: ${metas[0].id}") } + // Check that multiple runs of the same sample are of the same strandedness i.e. auto / unstranded / forward / reverse + def strandedness_ok = metas.collect{ it.strandedness }.unique().size == 1 + if (!strandedness_ok) { + error("Please check input samplesheet -> Multiple runs of a sample must be of the same strandedness: ${metas[0].id}") + } + return [ metas[0], fastqs ] } // From 0ea2e7538c0768e168998946666ffd847e319928 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sun, 9 Jun 2024 15:40:03 +0200 Subject: [PATCH 271/491] Update modules --- modules.json | 20 +- modules/nf-core/bwa/index/meta.yml | 2 +- .../nf-core/samtools/faidx/environment.yml | 4 +- modules/nf-core/samtools/faidx/main.nf | 4 +- .../samtools/faidx/tests/main.nf.test.snap | 30 +-- .../nf-core/samtools/flagstat/environment.yml | 4 +- modules/nf-core/samtools/flagstat/main.nf | 4 +- .../samtools/flagstat/tests/main.nf.test.snap | 6 +- .../nf-core/samtools/idxstats/environment.yml | 4 +- modules/nf-core/samtools/idxstats/main.nf | 4 +- .../samtools/idxstats/tests/main.nf.test.snap | 6 +- .../nf-core/samtools/index/environment.yml | 4 +- modules/nf-core/samtools/index/main.nf | 4 +- .../samtools/index/tests/main.nf.test.snap | 18 +- modules/nf-core/samtools/sort/environment.yml | 4 +- modules/nf-core/samtools/sort/main.nf | 4 +- .../nf-core/samtools/sort/tests/main.nf.test | 16 +- .../samtools/sort/tests/main.nf.test.snap | 198 +++++++----------- .../nf-core/samtools/stats/environment.yml | 4 +- modules/nf-core/samtools/stats/main.nf | 4 +- .../samtools/stats/tests/main.nf.test.snap | 24 +-- modules/nf-core/samtools/view/environment.yml | 4 +- modules/nf-core/samtools/view/main.nf | 4 +- .../samtools/view/tests/main.nf.test.snap | 36 ++-- .../tests/main.nf.test.snap | 12 +- 25 files changed, 196 insertions(+), 228 deletions(-) diff --git a/modules.json b/modules.json index 6e535782..9f5b1a68 100644 --- a/modules.json +++ b/modules.json @@ -42,7 +42,7 @@ }, "bwa/index": { "branch": "master", - "git_sha": "086fa66260595e123b0ea47a6512539b72a9afa3", + "git_sha": "e0ff65e1fb313677de09f5f477ae3da30ce19b7b", "installed_by": ["modules"] }, "cat/cat": { @@ -127,37 +127,37 @@ }, "samtools/faidx": { "branch": "master", - "git_sha": "f153f1f10e1083c49935565844cccb7453021682", + "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", "installed_by": ["modules"] }, "samtools/flagstat": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", "installed_by": ["bam_stats_samtools"] }, "samtools/idxstats": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", "installed_by": ["bam_stats_samtools"] }, "samtools/index": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", "installed_by": ["bam_sort_stats_samtools", "modules"] }, "samtools/sort": { "branch": "master", - "git_sha": "4352dbdb09ec40db71e9b172b97a01dcf5622c26", + "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", "installed_by": ["bam_sort_stats_samtools", "modules"] }, "samtools/stats": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", "installed_by": ["bam_stats_samtools"] }, "samtools/view": { "branch": "master", - "git_sha": "0bd7d2333a88483aa0476acea172e9f5f6dd83bb", + "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", "installed_by": ["modules"] }, "segemehl/align": { @@ -201,12 +201,12 @@ "nf-core": { "bam_sort_stats_samtools": { "branch": "master", - "git_sha": "4352dbdb09ec40db71e9b172b97a01dcf5622c26", + "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", "installed_by": ["subworkflows"] }, "bam_stats_samtools": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", "installed_by": ["bam_sort_stats_samtools", "subworkflows"] }, "utils_nextflow_pipeline": { diff --git a/modules/nf-core/bwa/index/meta.yml b/modules/nf-core/bwa/index/meta.yml index 4c7d30f3..6bbc87a6 100644 --- a/modules/nf-core/bwa/index/meta.yml +++ b/modules/nf-core/bwa/index/meta.yml @@ -11,7 +11,7 @@ tools: BWA is a software package for mapping DNA sequences against a large reference genome, such as the human genome. homepage: http://bio-bwa.sourceforge.net/ - documentation: http://www.htslib.org/doc/samtools.html + documentation: https://bio-bwa.sourceforge.net/bwa.shtml arxiv: arXiv:1303.3997 licence: ["GPL-3.0-or-later"] input: diff --git a/modules/nf-core/samtools/faidx/environment.yml b/modules/nf-core/samtools/faidx/environment.yml index 9c24eb0a..f8450fa5 100644 --- a/modules/nf-core/samtools/faidx/environment.yml +++ b/modules/nf-core/samtools/faidx/environment.yml @@ -6,5 +6,5 @@ channels: - defaults dependencies: - - bioconda::htslib=1.19.1 - - bioconda::samtools=1.19.2 + - bioconda::htslib=1.20 + - bioconda::samtools=1.20 diff --git a/modules/nf-core/samtools/faidx/main.nf b/modules/nf-core/samtools/faidx/main.nf index cfe7ad95..bdcdbc95 100644 --- a/modules/nf-core/samtools/faidx/main.nf +++ b/modules/nf-core/samtools/faidx/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_FAIDX { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.19.2--h50ea8bc_0' : - 'biocontainers/samtools:1.19.2--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.20--h50ea8bc_0' : + 'biocontainers/samtools:1.20--h50ea8bc_0' }" input: tuple val(meta), path(fasta) diff --git a/modules/nf-core/samtools/faidx/tests/main.nf.test.snap b/modules/nf-core/samtools/faidx/tests/main.nf.test.snap index 3e651ef6..3223b72b 100644 --- a/modules/nf-core/samtools/faidx/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/faidx/tests/main.nf.test.snap @@ -18,7 +18,7 @@ ], "3": [ - "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + "versions.yml:md5,2db78952923a61e05d50b95518b21856" ], "fa": [ @@ -36,7 +36,7 @@ ], "versions": [ - "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + "versions.yml:md5,2db78952923a61e05d50b95518b21856" ] } ], @@ -44,7 +44,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-18T16:22:39.412601" + "timestamp": "2024-05-28T15:42:14.779784761" }, "test_samtools_faidx_bgzip": { "content": [ @@ -71,7 +71,7 @@ ] ], "3": [ - "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + "versions.yml:md5,2db78952923a61e05d50b95518b21856" ], "fa": [ @@ -95,7 +95,7 @@ ] ], "versions": [ - "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + "versions.yml:md5,2db78952923a61e05d50b95518b21856" ] } ], @@ -103,7 +103,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-18T16:23:22.427966" + "timestamp": "2024-05-28T15:42:20.256633877" }, "test_samtools_faidx_fasta": { "content": [ @@ -124,7 +124,7 @@ ], "3": [ - "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + "versions.yml:md5,2db78952923a61e05d50b95518b21856" ], "fa": [ [ @@ -142,7 +142,7 @@ ], "versions": [ - "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + "versions.yml:md5,2db78952923a61e05d50b95518b21856" ] } ], @@ -150,7 +150,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-18T16:24:04.107537" + "timestamp": "2024-05-28T15:42:25.632577273" }, "test_samtools_faidx_stub_fasta": { "content": [ @@ -171,7 +171,7 @@ ], "3": [ - "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + "versions.yml:md5,2db78952923a61e05d50b95518b21856" ], "fa": [ [ @@ -189,7 +189,7 @@ ], "versions": [ - "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + "versions.yml:md5,2db78952923a61e05d50b95518b21856" ] } ], @@ -197,7 +197,7 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-18T16:24:45.868463" + "timestamp": "2024-05-28T15:42:31.058424849" }, "test_samtools_faidx_stub_fai": { "content": [ @@ -218,7 +218,7 @@ ], "3": [ - "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + "versions.yml:md5,2db78952923a61e05d50b95518b21856" ], "fa": [ @@ -236,7 +236,7 @@ ], "versions": [ - "versions.yml:md5,4870fc0a88c616aa937f8325a2db0c3c" + "versions.yml:md5,2db78952923a61e05d50b95518b21856" ] } ], @@ -244,6 +244,6 @@ "nf-test": "0.8.4", "nextflow": "23.10.1" }, - "timestamp": "2024-03-18T16:25:27.550554" + "timestamp": "2024-05-28T15:42:36.479929617" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/flagstat/environment.yml b/modules/nf-core/samtools/flagstat/environment.yml index bd57cb54..68b81558 100644 --- a/modules/nf-core/samtools/flagstat/environment.yml +++ b/modules/nf-core/samtools/flagstat/environment.yml @@ -4,5 +4,5 @@ channels: - bioconda - defaults dependencies: - - bioconda::samtools=1.19.2 - - bioconda::htslib=1.19.1 + - bioconda::samtools=1.20 + - bioconda::htslib=1.20 diff --git a/modules/nf-core/samtools/flagstat/main.nf b/modules/nf-core/samtools/flagstat/main.nf index eb5f5252..754d84b7 100644 --- a/modules/nf-core/samtools/flagstat/main.nf +++ b/modules/nf-core/samtools/flagstat/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_FLAGSTAT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.19.2--h50ea8bc_0' : - 'biocontainers/samtools:1.19.2--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.20--h50ea8bc_0' : + 'biocontainers/samtools:1.20--h50ea8bc_0' }" input: tuple val(meta), path(bam), path(bai) diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap index a76fc27e..e9f85efa 100644 --- a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap @@ -20,13 +20,13 @@ "versions": { "content": [ [ - "versions.yml:md5,fd0030ce49ab3a92091ad80260226452" + "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:11:44.299617452" + "timestamp": "2024-05-28T15:41:52.516253882" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/idxstats/environment.yml b/modules/nf-core/samtools/idxstats/environment.yml index 174973b8..eb6c8809 100644 --- a/modules/nf-core/samtools/idxstats/environment.yml +++ b/modules/nf-core/samtools/idxstats/environment.yml @@ -4,5 +4,5 @@ channels: - bioconda - defaults dependencies: - - bioconda::samtools=1.19.2 - - bioconda::htslib=1.19.1 + - bioconda::samtools=1.20 + - bioconda::htslib=1.20 diff --git a/modules/nf-core/samtools/idxstats/main.nf b/modules/nf-core/samtools/idxstats/main.nf index a544026f..2ea2a5cc 100644 --- a/modules/nf-core/samtools/idxstats/main.nf +++ b/modules/nf-core/samtools/idxstats/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_IDXSTATS { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.19.2--h50ea8bc_0' : - 'biocontainers/samtools:1.19.2--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.20--h50ea8bc_0' : + 'biocontainers/samtools:1.20--h50ea8bc_0' }" input: tuple val(meta), path(bam), path(bai) diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap index a7050bdc..4eacdb90 100644 --- a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap @@ -2,14 +2,14 @@ "versions": { "content": [ [ - "versions.yml:md5,613dde56f108418039ffcdeeddba397a" + "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:16:50.147462763" + "timestamp": "2024-05-28T15:46:46.617989517" }, "idxstats": { "content": [ diff --git a/modules/nf-core/samtools/index/environment.yml b/modules/nf-core/samtools/index/environment.yml index a5e50649..260d516b 100644 --- a/modules/nf-core/samtools/index/environment.yml +++ b/modules/nf-core/samtools/index/environment.yml @@ -4,5 +4,5 @@ channels: - bioconda - defaults dependencies: - - bioconda::samtools=1.19.2 - - bioconda::htslib=1.19.1 + - bioconda::samtools=1.20 + - bioconda::htslib=1.20 diff --git a/modules/nf-core/samtools/index/main.nf b/modules/nf-core/samtools/index/main.nf index dc14f98d..b523c21b 100644 --- a/modules/nf-core/samtools/index/main.nf +++ b/modules/nf-core/samtools/index/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_INDEX { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.19.2--h50ea8bc_0' : - 'biocontainers/samtools:1.19.2--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.20--h50ea8bc_0' : + 'biocontainers/samtools:1.20--h50ea8bc_0' }" input: tuple val(meta), path(input) diff --git a/modules/nf-core/samtools/index/tests/main.nf.test.snap b/modules/nf-core/samtools/index/tests/main.nf.test.snap index 3dc8e7de..52756e85 100644 --- a/modules/nf-core/samtools/index/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/index/tests/main.nf.test.snap @@ -2,26 +2,26 @@ "crai_versions": { "content": [ [ - "versions.yml:md5,cc4370091670b64bba7c7206403ffb3e" + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:12:00.324667957" + "timestamp": "2024-05-28T15:42:04.203740976" }, "csi_versions": { "content": [ [ - "versions.yml:md5,cc4370091670b64bba7c7206403ffb3e" + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:12:07.885103162" + "timestamp": "2024-05-28T15:42:09.57475878" }, "crai": { "content": [ @@ -62,13 +62,13 @@ "bai_versions": { "content": [ [ - "versions.yml:md5,cc4370091670b64bba7c7206403ffb3e" + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:11:51.641425452" + "timestamp": "2024-05-28T15:41:57.929287369" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/sort/environment.yml b/modules/nf-core/samtools/sort/environment.yml index 4d898e48..36a12eab 100644 --- a/modules/nf-core/samtools/sort/environment.yml +++ b/modules/nf-core/samtools/sort/environment.yml @@ -4,5 +4,5 @@ channels: - bioconda - defaults dependencies: - - bioconda::samtools=1.19.2 - - bioconda::htslib=1.19.1 + - bioconda::samtools=1.20 + - bioconda::htslib=1.20 diff --git a/modules/nf-core/samtools/sort/main.nf b/modules/nf-core/samtools/sort/main.nf index fc374f98..596c6f7e 100644 --- a/modules/nf-core/samtools/sort/main.nf +++ b/modules/nf-core/samtools/sort/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_SORT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.19.2--h50ea8bc_0' : - 'biocontainers/samtools:1.19.2--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.20--h50ea8bc_0' : + 'biocontainers/samtools:1.20--h50ea8bc_0' }" input: tuple val(meta) , path(bam) diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test b/modules/nf-core/samtools/sort/tests/main.nf.test index 8360e2b1..fb38ed9b 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test +++ b/modules/nf-core/samtools/sort/tests/main.nf.test @@ -30,7 +30,11 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot( + process.out.bam, + process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } } + ).match("test_bam") + } ) } } @@ -44,11 +48,11 @@ nextflow_process { """ input[0] = Channel.of([ [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true) ]) input[1] = Channel.of([ [ id:'fasta' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ]) """ } @@ -57,7 +61,11 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot( + process.out.bam, + process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } } + ).match("test_cram") + } ) } } diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test.snap b/modules/nf-core/samtools/sort/tests/main.nf.test.snap index 38477656..5a27de1d 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/sort/tests/main.nf.test.snap @@ -1,68 +1,21 @@ { "cram": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,bc0b7c25da26384a006ed84cc9e4da23" - ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam.csi:md5,8d4e836c2fed6c0bf874d5e8cdba5831" - ] - ], - "4": [ - "versions.yml:md5,e6d43fefc9a8bff91c2ce6e3a1716eca" - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,bc0b7c25da26384a006ed84cc9e4da23" - ] - ], - "crai": [ - - ], - "cram": [ - - ], - "csi": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam.csi:md5,8d4e836c2fed6c0bf874d5e8cdba5831" - ] - ], - "versions": [ - "versions.yml:md5,e6d43fefc9a8bff91c2ce6e3a1716eca" + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,21c992d59615936b99f2ad008aa54400" ] - } + ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nextflow": "24.04.2" }, - "timestamp": "2024-03-04T15:08:00.830294" + "timestamp": "2024-05-31T08:13:54.512837189" }, "bam_stub_bam": { "content": [ @@ -70,85 +23,92 @@ ], "meta": { "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nextflow": "24.04.2" + }, + "timestamp": "2024-05-31T07:29:00.761845507" + }, + "test_cram": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,22b2093be34a7637f5fbc84272b89d06" + ] + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.csi" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" }, - "timestamp": "2024-02-12T19:21:04.364044" + "timestamp": "2024-05-31T09:16:51.924951855" + }, + "test_bam": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,21c992d59615936b99f2ad008aa54400" + ] + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.csi" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-05-31T08:28:12.15952312" }, "bam_stub_versions": { "content": [ [ - "versions.yml:md5,e6d43fefc9a8bff91c2ce6e3a1716eca" + "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "24.04.2" }, - "timestamp": "2024-02-13T16:15:00.20800281" + "timestamp": "2024-05-31T07:29:00.765038811" }, "bam": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,bc0b7c25da26384a006ed84cc9e4da23" - ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam.csi:md5,8d4e836c2fed6c0bf874d5e8cdba5831" - ] - ], - "4": [ - "versions.yml:md5,e6d43fefc9a8bff91c2ce6e3a1716eca" - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,bc0b7c25da26384a006ed84cc9e4da23" - ] - ], - "crai": [ - - ], - "cram": [ - - ], - "csi": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam.csi:md5,8d4e836c2fed6c0bf874d5e8cdba5831" - ] - ], - "versions": [ - "versions.yml:md5,e6d43fefc9a8bff91c2ce6e3a1716eca" + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,21c992d59615936b99f2ad008aa54400" ] - } + ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nextflow": "24.04.2" }, - "timestamp": "2024-03-04T15:07:48.773803" + "timestamp": "2024-05-31T08:13:48.538030517" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/stats/environment.yml b/modules/nf-core/samtools/stats/environment.yml index 67bb0ca4..1cc83bd9 100644 --- a/modules/nf-core/samtools/stats/environment.yml +++ b/modules/nf-core/samtools/stats/environment.yml @@ -4,5 +4,5 @@ channels: - bioconda - defaults dependencies: - - bioconda::samtools=1.19.2 - - bioconda::htslib=1.19.1 + - bioconda::samtools=1.20 + - bioconda::htslib=1.20 diff --git a/modules/nf-core/samtools/stats/main.nf b/modules/nf-core/samtools/stats/main.nf index 52b00f4b..982bc28e 100644 --- a/modules/nf-core/samtools/stats/main.nf +++ b/modules/nf-core/samtools/stats/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_STATS { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.19.2--h50ea8bc_0' : - 'biocontainers/samtools:1.19.2--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.20--h50ea8bc_0' : + 'biocontainers/samtools:1.20--h50ea8bc_0' }" input: tuple val(meta), path(input), path(input_index) diff --git a/modules/nf-core/samtools/stats/tests/main.nf.test.snap b/modules/nf-core/samtools/stats/tests/main.nf.test.snap index 1b7c9ba4..2747fd6c 100644 --- a/modules/nf-core/samtools/stats/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/stats/tests/main.nf.test.snap @@ -8,11 +8,11 @@ "id": "test", "single_end": false }, - "test.stats:md5,01812900aa4027532906c5d431114233" + "test.stats:md5,c9d39b38c22de2057fc2f89949090975" ] ], "1": [ - "versions.yml:md5,0514ceb1769b2a88843e08c1f82624a9" + "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" ], "stats": [ [ @@ -20,19 +20,19 @@ "id": "test", "single_end": false }, - "test.stats:md5,01812900aa4027532906c5d431114233" + "test.stats:md5,c9d39b38c22de2057fc2f89949090975" ] ], "versions": [ - "versions.yml:md5,0514ceb1769b2a88843e08c1f82624a9" + "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" ] } ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:15:25.562429714" + "timestamp": "2024-05-28T15:45:24.403941966" }, "bam": { "content": [ @@ -43,11 +43,11 @@ "id": "test", "single_end": false }, - "test.stats:md5,5d8681bf541199898c042bf400391d59" + "test.stats:md5,d522a1fa016b259d6a55620ae53dcd63" ] ], "1": [ - "versions.yml:md5,0514ceb1769b2a88843e08c1f82624a9" + "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" ], "stats": [ [ @@ -55,18 +55,18 @@ "id": "test", "single_end": false }, - "test.stats:md5,5d8681bf541199898c042bf400391d59" + "test.stats:md5,d522a1fa016b259d6a55620ae53dcd63" ] ], "versions": [ - "versions.yml:md5,0514ceb1769b2a88843e08c1f82624a9" + "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" ] } ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:15:07.857611509" + "timestamp": "2024-05-28T15:45:06.711251947" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/view/environment.yml b/modules/nf-core/samtools/view/environment.yml index b0676f33..150c3777 100644 --- a/modules/nf-core/samtools/view/environment.yml +++ b/modules/nf-core/samtools/view/environment.yml @@ -4,5 +4,5 @@ channels: - bioconda - defaults dependencies: - - bioconda::samtools=1.19.2 - - bioconda::htslib=1.19.1 + - bioconda::samtools=1.20 + - bioconda::htslib=1.20 diff --git a/modules/nf-core/samtools/view/main.nf b/modules/nf-core/samtools/view/main.nf index 5a8989d6..38df8576 100644 --- a/modules/nf-core/samtools/view/main.nf +++ b/modules/nf-core/samtools/view/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_VIEW { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.19.2--h50ea8bc_0' : - 'biocontainers/samtools:1.19.2--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.20--h50ea8bc_0' : + 'biocontainers/samtools:1.20--h50ea8bc_0' }" input: tuple val(meta), path(input), path(index) diff --git a/modules/nf-core/samtools/view/tests/main.nf.test.snap b/modules/nf-core/samtools/view/tests/main.nf.test.snap index f55943a7..eb0c577c 100644 --- a/modules/nf-core/samtools/view/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/view/tests/main.nf.test.snap @@ -56,14 +56,14 @@ "bam_stub_versions": { "content": [ [ - "versions.yml:md5,4ea32c57d546102a1b32d9693ada7cf1" + "versions.yml:md5,6cd41a9a3b4a95271ec011ea990a2838" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:13:09.713353823" + "timestamp": "2024-05-28T15:43:20.390692583" }, "cram_to_bam_index_cram": { "content": [ @@ -208,14 +208,14 @@ "cram_to_bam_index_qname_versions": { "content": [ [ - "versions.yml:md5,4ea32c57d546102a1b32d9693ada7cf1" + "versions.yml:md5,6cd41a9a3b4a95271ec011ea990a2838" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:13:03.935041046" + "timestamp": "2024-05-28T15:43:15.007493874" }, "cram_to_bam_bam": { "content": [ @@ -240,14 +240,14 @@ "cram_to_bam_index_versions": { "content": [ [ - "versions.yml:md5,4ea32c57d546102a1b32d9693ada7cf1" + "versions.yml:md5,6cd41a9a3b4a95271ec011ea990a2838" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:12:55.910685496" + "timestamp": "2024-05-28T15:43:09.472376824" }, "cram_to_bam_bai": { "content": [ @@ -264,14 +264,14 @@ "cram_to_bam_versions": { "content": [ [ - "versions.yml:md5,4ea32c57d546102a1b32d9693ada7cf1" + "versions.yml:md5,6cd41a9a3b4a95271ec011ea990a2838" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:12:47.715221169" + "timestamp": "2024-05-28T15:43:04.080050906" }, "cram_bam": { "content": [ @@ -358,14 +358,14 @@ "bam_versions": { "content": [ [ - "versions.yml:md5,4ea32c57d546102a1b32d9693ada7cf1" + "versions.yml:md5,6cd41a9a3b4a95271ec011ea990a2838" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:12:31.692607421" + "timestamp": "2024-05-28T15:42:52.978954857" }, "cram_to_bam_index_qname_cram": { "content": [ @@ -430,14 +430,14 @@ "cram_versions": { "content": [ [ - "versions.yml:md5,4ea32c57d546102a1b32d9693ada7cf1" + "versions.yml:md5,6cd41a9a3b4a95271ec011ea990a2838" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:12:39.913411036" + "timestamp": "2024-05-28T15:42:58.400776109" }, "bam_sam": { "content": [ diff --git a/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap b/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap index 6645a092..db063837 100644 --- a/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap +++ b/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap @@ -43,15 +43,15 @@ "id": "test", "single_end": false }, - "test.stats:md5,cb0bf2b79de52fdf0c61e80efcdb0bb4" + "test.stats:md5,d32de3b3716a11039cef2367c3c1a56e" ] ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:44:38.553256801" + "timestamp": "2024-05-29T07:47:44.044172487" }, "test_bam_sort_stats_samtools_paired_end_stats": { "content": [ @@ -61,15 +61,15 @@ "id": "test", "single_end": false }, - "test.stats:md5,d7796222a087b9bb97f631f1c21b9c95" + "test.stats:md5,cca83e4fc9406fc3875b5e60055d6574" ] ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "23.10.1" }, - "timestamp": "2024-02-13T16:44:48.355870518" + "timestamp": "2024-05-29T07:47:51.426232891" }, "test_bam_sort_stats_samtools_single_end_idxstats": { "content": [ From 8150c43055c65172b5a85c83809cde8c3075043c Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 10 Jun 2024 12:29:21 +0200 Subject: [PATCH 272/491] Add new STATISTICAL_TESTS subworkflow --- subworkflows/local/quantification.nf | 1 + subworkflows/local/statistical_tests.nf | 11 +++++++++++ workflows/circrna/main.nf | 12 +++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 subworkflows/local/statistical_tests.nf diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index ee9ad8be..bc33dbf1 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -121,6 +121,7 @@ workflow QUANTIFICATION { ) emit: + se = MERGE_EXPERIMENTS.out.merged gene_counts = JOIN_GENE_COUNTS.out.csv gene_tpm = JOIN_GENE_TPM.out.csv tx_counts = JOIN_TX_COUNTS.out.csv diff --git a/subworkflows/local/statistical_tests.nf b/subworkflows/local/statistical_tests.nf new file mode 100644 index 00000000..149d6f53 --- /dev/null +++ b/subworkflows/local/statistical_tests.nf @@ -0,0 +1,11 @@ +workflow STATISTICAL_TESTS { + take: + ch_quantification + + main: + ch_versions = Channel.empty() + + ch_quantification.view() + + +} \ No newline at end of file diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 4da9fe94..839b3af6 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -31,7 +31,7 @@ include { PREPARE_GENOME } from '../../subworkflows/local/prep include { CIRCRNA_DISCOVERY } from '../../subworkflows/local/circrna_discovery' include { QUANTIFICATION } from '../../subworkflows/local/quantification' include { MIRNA_PREDICTION } from '../../subworkflows/local/mirna_prediction' -include { DIFFERENTIAL_EXPRESSION } from '../../subworkflows/local/differential_expression' +include { STATISTICAL_TESTS } from '../../subworkflows/local/statistical_tests' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -182,6 +182,15 @@ workflow CIRCRNA { ch_versions = ch_versions.mix(MIRNA_PREDICTION.out.versions) + // + // 5. Statistical tests + // + + STATISTICAL_TESTS( + QUANTIFICATION.out.se + ) + + /* // // 5. Differential expression tests // @@ -204,6 +213,7 @@ workflow CIRCRNA { ch_versions = ch_versions.mix(DIFFERENTIAL_EXPRESSION.out.versions) ch_multiqc_files = ch_multiqc_files.mix(DIFFERENTIAL_EXPRESSION.out.reports) + */ // // Collate and save software versions From 7ef6b03ed5d726e49f307277444869ca93fb3832 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 10 Jun 2024 13:38:03 +0200 Subject: [PATCH 273/491] Implement CIRCTEST_PREPARE --- bin/prepare_circ_test.R | 69 ------------------- .../local/circtest/prepare/environment.yml | 5 ++ modules/local/circtest/prepare/main.nf | 34 ++++----- .../circtest/prepare/templates/prepare.R | 30 ++++++++ subworkflows/local/statistical_tests.nf | 9 ++- workflows/circrna/main.nf | 5 +- 6 files changed, 59 insertions(+), 93 deletions(-) delete mode 100755 bin/prepare_circ_test.R create mode 100644 modules/local/circtest/prepare/environment.yml create mode 100644 modules/local/circtest/prepare/templates/prepare.R diff --git a/bin/prepare_circ_test.R b/bin/prepare_circ_test.R deleted file mode 100755 index 95057f19..00000000 --- a/bin/prepare_circ_test.R +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env Rscript - -## Author: Barry Digby -## License: MIT - -circ_mat = read.table("merged_counts.tsv", header=T, sep="\t", check.names = FALSE, stringsAsFactors = F, row.names = "ID") -gene_mat = read.table("gene_count_matrix.csv", sep=",", header=T, row.names="gene_id", stringsAsFactors = F) -map = read.table("circrna_host-gene.txt", header = F, sep="\t", stringsAsFactors = F) - -# some circrnas do not have a host gene. -map <- na.omit(map) -colnames(map) <- c("circrna", "gene") - -# resolve multiple host genes by creating a new 'map' dataframe -# to enforce 1-1 mapping. - -new_circ = c() -new_gene = c() - -for(i in 1:nrow(map)){ - row <- map[i,] - circ <- row$circrna - gene <- row$gene - - # multiple host genes? - multiple_genes <- unlist(strsplit(gene, ",")) - #print(multiple_genes) - if(length(multiple_genes) > 1){ - for(gene in multiple_genes){ - new_circ <- c(new_circ, circ) - new_gene <- c(new_gene, gene) - } - } - new_circ <- c(new_circ, circ) - new_gene <- c(new_gene, gene) -} - -new_map <- data.frame(new_circ, new_gene) - -#create circTest dataframe. really odd formatting..! -new_circ_mat <- circ_mat[c(new_map$new_circ),] - -# unique names for duplicated circrna ids, resolve below -Chr <- c() -Start <- c() -End <- c() -for(i in 1:nrow(new_circ_mat)){ - row <- new_circ_mat[i,] - print(rownames(row)) - chr_ <- unlist(strsplit(rownames(row), ':'))[1] - coords <- unlist(strsplit(rownames(row), ':'))[2] - start_ <- unlist(strsplit(coords, '-'))[1] - end_ <- unlist(strsplit(coords, '-'))[2] - - Chr <- c(Chr, chr_) - Start <- c(Start, start_) - End <- c(End, end_) - -} - -Gene <- new_map$new_gene -circ_csv <- data.frame(Chr, Start, End, Gene, new_circ_mat) -# DROP the rownames, do not write to file. - -gene_csv <- gene_mat[c(new_map$new_gene),] -gene_csv <- data.frame(Chr, Start, End, Gene, gene_csv) - -write.csv(circ_csv, "circ.csv", quote=F, row.names = FALSE) -write.csv(gene_csv, "linear.csv", quote=F, row.names = FALSE) diff --git a/modules/local/circtest/prepare/environment.yml b/modules/local/circtest/prepare/environment.yml new file mode 100644 index 00000000..602dc60d --- /dev/null +++ b/modules/local/circtest/prepare/environment.yml @@ -0,0 +1,5 @@ +name: circtest_prepare +channels: + - conda-forge +dependencies: + - conda-forge::r-base=4.2.1 \ No newline at end of file diff --git a/modules/local/circtest/prepare/main.nf b/modules/local/circtest/prepare/main.nf index 834c6063..e41b6c46 100644 --- a/modules/local/circtest/prepare/main.nf +++ b/modules/local/circtest/prepare/main.nf @@ -1,32 +1,26 @@ -process PREPARE_CLR_TEST { - label 'process_medium' +process CIRCTEST_PREPARE { + label 'process_low' - conda "conda-forge::r-base=4.2.2 conda-forge::r-aod=1.3.2 conda-forge::r-ggplot2=3.4.0 conda-forge::r-plyr=1.8.8" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' : - 'biocontainers/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' }" + 'https://depot.galaxyproject.org/singularity/biocontainers/r-base:4.2.1' : + 'biocontainers/r-base:4.2.1' }" input: - path(gene_matrix) - path(circrna_matrix) - path(circ_host_map) - path(gtf) + tuple val(meta), path(circ_counts) + tuple val(meta2), path(gene_counts) output: - path "circ.csv" , emit: circular - path "linear.csv" , emit: linear - path "versions.yml", emit: versions + tuple val(meta), path('*_circs.tsv'), emit: circ_counts + tuple val(meta), path('*_genes.tsv'), emit: gene_counts + + path "versions.yml" , emit: versions + when: task.ext.when == null || task.ext.when script: - """ - prepare_circ_test.R - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - r-base: \$(echo \$(R --version 2>&1) | sed 's/^.*R version //; s/ .*\$//') - END_VERSIONS - """ + prefix = task.ext.prefix ?: meta.id + template 'prepare.R' } diff --git a/modules/local/circtest/prepare/templates/prepare.R b/modules/local/circtest/prepare/templates/prepare.R new file mode 100644 index 00000000..96ad9bd2 --- /dev/null +++ b/modules/local/circtest/prepare/templates/prepare.R @@ -0,0 +1,30 @@ +#!/usr/bin/env Rscript + +circ = read.table("${circ_counts}", header=T, sep="\\t", check.names = FALSE) +gene = read.table("${gene_counts}", header=T, sep="\\t", check.names = FALSE, row.names = 1) + +gene = gene[circ\$gene_id, -1] +circ = circ[, -2] + +write.table(circ, "${prefix}_circs.tsv", sep="\\t", quote=F, row.names=F) +write.table(gene, "${prefix}_genes.tsv", sep="\\t", quote=F, row.names=T) + +################################################ +################################################ +## VERSIONS FILE ## +################################################ +################################################ + +r.version <- strsplit(version[['version.string']], ' ')[[1]][3] + +writeLines( + c( + '"${task.process}":', + paste(' r-base:', r.version) + ), +'versions.yml') + +################################################ +################################################ +################################################ +################################################ \ No newline at end of file diff --git a/subworkflows/local/statistical_tests.nf b/subworkflows/local/statistical_tests.nf index 149d6f53..1b822a4c 100644 --- a/subworkflows/local/statistical_tests.nf +++ b/subworkflows/local/statistical_tests.nf @@ -1,11 +1,14 @@ +include { CIRCTEST_PREPARE } from '../../modules/local/circtest/prepare' + workflow STATISTICAL_TESTS { take: ch_quantification + ch_gene_counts + ch_circ_counts + ch_phenotype main: ch_versions = Channel.empty() - ch_quantification.view() - - + CIRCTEST_PREPARE(ch_circ_counts, ch_gene_counts) } \ No newline at end of file diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 839b3af6..18021678 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -187,7 +187,10 @@ workflow CIRCRNA { // STATISTICAL_TESTS( - QUANTIFICATION.out.se + QUANTIFICATION.out.se, + QUANTIFICATION.out.gene_counts, + QUANTIFICATION.out.circular_tx_counts, + ch_phenotype ) /* From 5893d6dcb0e5c3c766d14d476ebd688f965bfc36 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 10:49:36 +0200 Subject: [PATCH 274/491] Implement circTest --- assets/schema_phenotype.json | 23 +++++++ .../local/circtest/{test => circtest}/main.nf | 21 ++----- .../circtest/circtest/templates/circtest.R | 63 ++++++++----------- .../circtest/prepare/templates/prepare.R | 15 +++-- nextflow_schema.json | 11 ++-- subworkflows/local/statistical_tests.nf | 9 ++- 6 files changed, 78 insertions(+), 64 deletions(-) create mode 100644 assets/schema_phenotype.json rename modules/local/circtest/{test => circtest}/main.nf (50%) rename bin/circ_test.R => modules/local/circtest/circtest/templates/circtest.R (91%) diff --git a/assets/schema_phenotype.json b/assets/schema_phenotype.json new file mode 100644 index 00000000..bdeeaef8 --- /dev/null +++ b/assets/schema_phenotype.json @@ -0,0 +1,23 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://raw.githubusercontent.com/nf-core/circrna/master/assets/schema_phenotype.json", + "title": "nf-core/circrna pipeline - params.phenotype schema", + "description": "Schema for the file provided with params.phenotype", + "type": "array", + "items": { + "type": "object", + "properties": { + "sample": { + "type": "string", + "pattern": "^\\S+$", + "errorMessage": "Sample name must be provided and cannot contain spaces" + }, + "condition": { + "type": "string", + "pattern": "^\\S+$", + "errorMessage": "Condition name must be provided and cannot contain spaces" + } + }, + "required": ["sample", "condition"] + } +} diff --git a/modules/local/circtest/test/main.nf b/modules/local/circtest/circtest/main.nf similarity index 50% rename from modules/local/circtest/test/main.nf rename to modules/local/circtest/circtest/main.nf index c7add5e6..cbe33474 100644 --- a/modules/local/circtest/test/main.nf +++ b/modules/local/circtest/circtest/main.nf @@ -1,4 +1,4 @@ -process CIRCTEST { +process CIRCTEST_CIRCTEST { label 'process_medium' conda "conda-forge::r-base=4.2.2 conda-forge::r-aod=1.3.2 conda-forge::r-ggplot2=3.4.0 conda-forge::r-plyr=1.8.8" @@ -7,9 +7,9 @@ process CIRCTEST { 'biocontainers/mulled-v2-c79b00aa4647c739dbe7e8480789d3ba67988f2e:0' }" input: - path(circ_csv) - path(linear_csv) - tuple val(meta), path(phenotype) + tuple val(meta) , path(circ_counts) + tuple val(meta2), path(gene_counts) + tuple val(meta3), path(phenotype) output: path "*" , emit: results @@ -19,15 +19,6 @@ process CIRCTEST { task.ext.when == null || task.ext.when script: - """ - circ_test.R $circ_csv $linear_csv $phenotype - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - r-base: \$(echo \$(R --version 2>&1) | sed 's/^.*R version //; s/ .*\$//') - aod: \$(Rscript -e "library(aod); cat(as.character(packageVersion('aod')))") - ggplot2: \$(Rscript -e "library(ggplot2); cat(as.character(packageVersion('ggplot2')))") - plyr: \$(Rscript -e "library(plyr); cat(as.character(packageVersion('plyr')))") - END_VERSIONS - """ + prefix = task.ext.prefix ?: meta.id + template 'circtest.R' } diff --git a/bin/circ_test.R b/modules/local/circtest/circtest/templates/circtest.R similarity index 91% rename from bin/circ_test.R rename to modules/local/circtest/circtest/templates/circtest.R index 3e9ea6af..13b4f167 100755 --- a/bin/circ_test.R +++ b/modules/local/circtest/circtest/templates/circtest.R @@ -46,13 +46,13 @@ summarySE <- function(data=NULL, measurevar, groupvars=NULL, na.rm=FALSE, # Rename the "mean" column datac <- rename(datac, c("mean" = measurevar)) - datac$se <- datac$sd / sqrt(datac$N) # Calculate standard error of the mean + datac\$se <- datac\$sd / sqrt(datac\$N) # Calculate standard error of the mean # Confidence interval multiplier for standard error # Calculate t-statistic for confidence interval: # e.g., if conf.interval is .95, use .975 (above/below), and use df=N-1 - ciMult <- qt(conf.interval/2 + .5, datac$N-1) - datac$ci <- datac$se * ciMult + ciMult <- qt(conf.interval/2 + .5, datac\$N-1) + datac\$ci <- datac\$se * ciMult return(datac) } @@ -144,7 +144,7 @@ Circ.ratioplot <- function(Circ,Linear,CircCoordinates = None,plotrow='1',size=2 theme(legend.text=element_text(size=size)) + theme(plot.title = element_text(size=size)) + theme(axis.text.y = element_text(margin=margin(5,5,10,5,"pt")))+ - ggtitle(paste("Annotation: ", genename, "\nChr ", toString(Circ[plotrow,circle_description]),sep="")) + + ggtitle(paste("Annotation: ", genename, "\\nChr ", toString(Circ[plotrow,circle_description]),sep="")) + ylab("circRNA/(circRNA + Linear RNA)") + xlab("Sample") + geom_errorbar(aes(ymin=Ratio, ymax=Ratio+se), width=.2 , size=2) + @@ -329,6 +329,8 @@ Circ.test <- function(Circ, Linear, CircCoordinates=None, group, alpha=0.05, plo # groups if ( length(group) != ncol(Circ)-length(circle_description) ){ + print(length(group)) + print(ncol(Circ)-length(circle_description)) stop("length of 'group' must be equal to the number of samples of 'Circ' and 'Linear'. ") } group <- factor(group) @@ -364,7 +366,7 @@ Circ.test <- function(Circ, Linear, CircCoordinates=None, group, alpha=0.05, plo tmp_rations <- data.frame(Ratio=as.numeric(Circ[i,-circle_description])/(as.numeric(Linear[i,-circle_description])+as.numeric(Circ[i,-circle_description])), group=group) for (rep_group in seq(1,max(as.numeric(levels(group))),1)){ - tmp_df[i, paste("group_",rep_group,"_ratio_mean",sep="")] <- mean(na.omit(unlist(tmp_rations[tmp_rations$group==rep_group,1]))) + tmp_df[i, paste("group_",rep_group,"_ratio_mean",sep="")] <- mean(na.omit(unlist(tmp_rations[tmp_rations\$group==rep_group,1]))) } # Constract data frame @@ -382,7 +384,7 @@ Circ.test <- function(Circ, Linear, CircCoordinates=None, group, alpha=0.05, plo } message(paste(counter, "candidates processed in total")) - Circ$direction <- direction + Circ\$direction <- direction p.adj <- p.adjust(p.val,n=sum(!is.na(p.val)),'BH') # select significant ones sig_dat <- Circ[p.adj<=alpha & !is.na(p.adj),] @@ -418,40 +420,25 @@ Circ.test <- function(Circ, Linear, CircCoordinates=None, group, alpha=0.05, plo ) } -## MY CODE +## MAIN -args = commandArgs(trailingOnly = TRUE) +circs = read.table("${circ_counts}", header=T, sep="\\t") +genes = read.table("${gene_counts}", header=T, sep="\\t") +pheno = read.csv ("${phenotype}" , header=T, row.names = "sample") -circ = read.table(args[1], header=T, sep=",") -linear = read.table(args[2], header=T, sep=",") -pheno = read.table(args[3], header=T, sep=",", row.names = "Sample_ID") +circs <- Circ.filter(circ = circs, linear = genes, filter.sample = 2, filter.count = 5, percentage = 0.00001) +genes <- genes[rownames(circs),] +description <- c(1) +pheno <- pheno[colnames(circs[,-description]),,drop=FALSE] -# No need to enforce any filtering for circTest. -# 'filter.sample' - this has been applied to called circs using the 'tool.filter' param -# 'filter.count' - this has been applied to called circs using bsj_filter param -# 'percentage' - set to extremely low value (do not want to discard circRNAs - let the user inspect themselves). +print(head(circs)) +print(head(genes)) -# Need to apply the phenotype csv file correctly to circtest. -n_covars <- ncol(pheno) -if( n_covars == 2){ - covariate_1 <- as.factor(pheno[,1]) - covariate_2 <- as.factor(pheno[,2]) -}else{ - covariate_1 <- as.factor(pheno[,1]) -} - -n_reps <- as.numeric(table(covariate_1)[1]) - -Circ_filtered <- Circ.filter(circ = circ, linear = linear, Nreplicates = n_reps, filter.sample = 1, filter.count = 1, percentage = 0.00001, circle_description = c(1:4)) -Linear_filtered <- linear[rownames(Circ_filtered),] - - -# groups must be numerically encoded -group = as.numeric(covariate_1) -test <- Circ.test(Circ_filtered, Linear_filtered, group=group, circle_description = c(1:4)) -write.table(test$summary_table, "summary_table.txt", row.names=F) +test <- Circ.test(circs, genes, group=pheno\$condition, circle_description = description) +write.table(test\$summary_table, "${prefix}_summary.txt", row.names=F) +q() # Apply pheno to output once more.. @@ -461,14 +448,14 @@ if( n_covars == 2 ){ group_indicator2 <- as.character(covariate_2) pdf("circ_linear_ratio_plots.pdf", width = 8, height = 10) - for (i in rownames(test$summary_table)) { + for (i in rownames(test\$summary_table)) { Circ.ratioplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=groupindicator1, groupindicator2 = group_indicator2, circle_description = c(1:4) ) } dev.off() pdf("circ_linear_line_plots.pdf", width = 8, height = 10) - for (i in rownames(test$summary_table)) { + for (i in rownames(test\$summary_table)) { Circ.lineplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=group_indicator1, groupindicator2 = group_indicator2, circle_description = c(1:4) ) } @@ -479,14 +466,14 @@ if( n_covars == 2 ){ group_indicator1 <- as.character(covariate_1) pdf("circ_linear_ratio_plots.pdf", width = 8, height = 10) - for (i in rownames(test$summary_table)) { + for (i in rownames(test\$summary_table)) { Circ.ratioplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=group_indicator1, lab_legend = colnames(pheno)[1], circle_description = c(1:4) ) } dev.off() pdf("circ_linear_line_plots.pdf", width = 8, height = 10) - for (i in rownames(test$summary_table)) { + for (i in rownames(test\$summary_table)) { Circ.lineplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=group_indicator1, circle_description = c(1:4) ) } diff --git a/modules/local/circtest/prepare/templates/prepare.R b/modules/local/circtest/prepare/templates/prepare.R index 96ad9bd2..5eb2c55e 100644 --- a/modules/local/circtest/prepare/templates/prepare.R +++ b/modules/local/circtest/prepare/templates/prepare.R @@ -1,12 +1,15 @@ #!/usr/bin/env Rscript -circ = read.table("${circ_counts}", header=T, sep="\\t", check.names = FALSE) -gene = read.table("${gene_counts}", header=T, sep="\\t", check.names = FALSE, row.names = 1) +circ <- read.table("${circ_counts}", header=T, sep="\\t", check.names = FALSE) +gene <- read.table("${gene_counts}", header=T, sep="\\t", check.names = FALSE, row.names = 1) -gene = gene[circ\$gene_id, -1] -circ = circ[, -2] +gene <- gene[circ\$gene_id, ] -write.table(circ, "${prefix}_circs.tsv", sep="\\t", quote=F, row.names=F) +rownames(circ) <- circ\$tx +rownames(gene) <- rownames(circ) +circ\$tx <- NULL + +write.table(circ, "${prefix}_circs.tsv", sep="\\t", quote=F, row.names=T) write.table(gene, "${prefix}_genes.tsv", sep="\\t", quote=F, row.names=T) ################################################ @@ -27,4 +30,4 @@ writeLines( ################################################ ################################################ ################################################ -################################################ \ No newline at end of file +################################################ diff --git a/nextflow_schema.json b/nextflow_schema.json index 2aaea8bb..9bd91654 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -32,11 +32,14 @@ }, "phenotype": { "type": "string", - "description": "Phenotype CSV file specifying the experimental design for DESeq2.", - "fa_icon": "fas fa-file-csv", + "format": "file-path", + "exists": true, + "schema": "assets/schema_phenotype.json", "mimetype": "text/csv", - "help_text": "There are two rules for providing the phenotype CSV file. 1) The phenotype 'sample' column must match the sample sheets 'sample' column. 2) The response variable containing the phenotype of primary interest in the experiment must have the column name condition. All other columns included in the file are controlled for in the `DESeq2` design. \n\n| sample \t| condition \t| replicate \t|\n|-----------\t|-----------\t|-----------\t|\n| control_1 \t| ctr \t| 1 \t|\n| control_2 \t| ctr \t| 2 \t|\n| control_3 \t| ctr \t| 3 \t|\n| treated_1 \t| trt \t| 1 \t|\n| treated_2 \t| trt \t| 2 \t|\n| treated_3 \t| trt \t| 3 \t|\n\nThe above phenotype file will identify differentially expressed circRNAs/mRNAs between control and treatment cells, whilst controlling for the effect of variation between replicates: ` ~ replicates + condition`", - "pattern": "\\.csv$" + "pattern": "^\\S+\\.csv$", + "description": "Phenotype CSV file specifying the experimental design.", + "help_text": "There are two rules for providing the phenotype CSV file. 1) The 'sample' column must match the sample sheets 'sample' column. 2) The response variable containing the phenotype of primary interest in the experiment must have the column name condition. All other columns included in the file are controlled for in the `DESeq2` design. \n\n| sample \t| condition \t| replicate \t|\n|-----------\t|-----------\t|-----------\t|\n| control_1 \t| ctr \t| 1 \t|\n| control_2 \t| ctr \t| 2 \t|\n| control_3 \t| ctr \t| 3 \t|\n| treated_1 \t| trt \t| 1 \t|\n| treated_2 \t| trt \t| 2 \t|\n| treated_3 \t| trt \t| 3 \t|\n\nThe above phenotype file will identify differentially expressed circRNAs/mRNAs between control and treatment cells, whilst controlling for the effect of variation between replicates: ` ~ replicates + condition`", + "fa_icon": "fas fa-file-csv" } } }, diff --git a/subworkflows/local/statistical_tests.nf b/subworkflows/local/statistical_tests.nf index 1b822a4c..3c977f9a 100644 --- a/subworkflows/local/statistical_tests.nf +++ b/subworkflows/local/statistical_tests.nf @@ -1,4 +1,5 @@ -include { CIRCTEST_PREPARE } from '../../modules/local/circtest/prepare' +include { CIRCTEST_PREPARE } from '../../modules/local/circtest/prepare' +include { CIRCTEST_CIRCTEST } from '../../modules/local/circtest/circtest' workflow STATISTICAL_TESTS { take: @@ -11,4 +12,10 @@ workflow STATISTICAL_TESTS { ch_versions = Channel.empty() CIRCTEST_PREPARE(ch_circ_counts, ch_gene_counts) + ch_versions = ch_versions.mix(CIRCTEST_PREPARE.out.versions) + + CIRCTEST_CIRCTEST(CIRCTEST_PREPARE.out.circ_counts, + CIRCTEST_PREPARE.out.gene_counts, + ch_phenotype) + } \ No newline at end of file From 9c5906d82682a334cd4976f0257994e74050e5b8 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 11:09:25 +0200 Subject: [PATCH 275/491] Fix circtest problems --- modules/local/circtest/circtest/main.nf | 4 +- .../circtest/circtest/templates/circtest.R | 107 ++++++++++-------- 2 files changed, 63 insertions(+), 48 deletions(-) diff --git a/modules/local/circtest/circtest/main.nf b/modules/local/circtest/circtest/main.nf index cbe33474..e9367be2 100644 --- a/modules/local/circtest/circtest/main.nf +++ b/modules/local/circtest/circtest/main.nf @@ -12,8 +12,8 @@ process CIRCTEST_CIRCTEST { tuple val(meta3), path(phenotype) output: - path "*" , emit: results - path "versions.yml", emit: versions + path "${prefix}_summary.txt", emit: summary + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/circtest/circtest/templates/circtest.R b/modules/local/circtest/circtest/templates/circtest.R index 13b4f167..6f36f7fa 100755 --- a/modules/local/circtest/circtest/templates/circtest.R +++ b/modules/local/circtest/circtest/templates/circtest.R @@ -432,53 +432,68 @@ genes <- genes[rownames(circs),] description <- c(1) pheno <- pheno[colnames(circs[,-description]),,drop=FALSE] -print(head(circs)) -print(head(genes)) - -test <- Circ.test(circs, genes, group=pheno\$condition, circle_description = description) +test <- Circ.test(circs, genes, group=as.numeric(as.factor(pheno\$condition)), circle_description = description) write.table(test\$summary_table, "${prefix}_summary.txt", row.names=F) -q() - # Apply pheno to output once more.. -if( n_covars == 2 ){ - - group_indicator1 <- as.character(covariate_1) - group_indicator2 <- as.character(covariate_2) - - pdf("circ_linear_ratio_plots.pdf", width = 8, height = 10) - for (i in rownames(test\$summary_table)) { - Circ.ratioplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=groupindicator1, groupindicator2 = group_indicator2, - circle_description = c(1:4) ) - } - dev.off() - - pdf("circ_linear_line_plots.pdf", width = 8, height = 10) - for (i in rownames(test\$summary_table)) { - Circ.lineplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=group_indicator1, groupindicator2 = group_indicator2, - circle_description = c(1:4) ) - } - dev.off() - -}else{ - - group_indicator1 <- as.character(covariate_1) - - pdf("circ_linear_ratio_plots.pdf", width = 8, height = 10) - for (i in rownames(test\$summary_table)) { - Circ.ratioplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=group_indicator1, - lab_legend = colnames(pheno)[1], circle_description = c(1:4) ) - } - dev.off() - - pdf("circ_linear_line_plots.pdf", width = 8, height = 10) - for (i in rownames(test\$summary_table)) { - Circ.lineplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=group_indicator1, - circle_description = c(1:4) ) - } - dev.off() -} - -# include variables, makes life easier in case user wishes to report bugs to workflow. -save.image("circ_test.RData") +# if( n_covars == 2 ){ +# +# group_indicator1 <- as.character(covariate_1) +# group_indicator2 <- as.character(covariate_2) +# +# pdf("circ_linear_ratio_plots.pdf", width = 8, height = 10) +# for (i in rownames(test\$summary_table)) { +# Circ.ratioplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=groupindicator1, groupindicator2 = group_indicator2, +# circle_description = c(1:4) ) +# } +# dev.off() +# +# pdf("circ_linear_line_plots.pdf", width = 8, height = 10) +# for (i in rownames(test\$summary_table)) { +# Circ.lineplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=group_indicator1, groupindicator2 = group_indicator2, +# circle_description = c(1:4) ) +# } +# dev.off() +# +# }else{ +# +# group_indicator1 <- as.character(covariate_1) +# +# pdf("circ_linear_ratio_plots.pdf", width = 8, height = 10) +# for (i in rownames(test\$summary_table)) { +# Circ.ratioplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=group_indicator1, +# lab_legend = colnames(pheno)[1], circle_description = c(1:4) ) +# } +# dev.off() +# +# pdf("circ_linear_line_plots.pdf", width = 8, height = 10) +# for (i in rownames(test\$summary_table)) { +# Circ.lineplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=group_indicator1, +# circle_description = c(1:4) ) +# } +# dev.off() +# } + +################################################ +################################################ +## VERSIONS FILE ## +################################################ +################################################ + +r.version <- strsplit(version[['version.string']], ' ')[[1]][3] + +writeLines( + c( + '"${task.process}":', + paste(' r-base:', r.version), + paste(' aod:', packageVersion('aod')), + paste(' plyr:', packageVersion('plyr')), + paste(' ggplot2:', packageVersion('ggplot2')) + ), +'versions.yml') + +################################################ +################################################ +################################################ +################################################ From 21236c891a3171774e86590cd26545372a20cad7 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 11:23:00 +0200 Subject: [PATCH 276/491] Re-enable circtest plots --- modules/local/circtest/circtest/main.nf | 6 ++- .../circtest/circtest/templates/circtest.R | 54 ++++++------------- 2 files changed, 19 insertions(+), 41 deletions(-) diff --git a/modules/local/circtest/circtest/main.nf b/modules/local/circtest/circtest/main.nf index e9367be2..beaf10c1 100644 --- a/modules/local/circtest/circtest/main.nf +++ b/modules/local/circtest/circtest/main.nf @@ -12,8 +12,10 @@ process CIRCTEST_CIRCTEST { tuple val(meta3), path(phenotype) output: - path "${prefix}_summary.txt", emit: summary - path "versions.yml" , emit: versions + tuple val(meta), path("${prefix}_summary.txt"), emit: summary + tuple val(meta), path("*.pdf") , emit: plots + + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/circtest/circtest/templates/circtest.R b/modules/local/circtest/circtest/templates/circtest.R index 6f36f7fa..b1633c53 100755 --- a/modules/local/circtest/circtest/templates/circtest.R +++ b/modules/local/circtest/circtest/templates/circtest.R @@ -435,45 +435,21 @@ pheno <- pheno[colnames(circs[,-description]),,drop=FALSE] test <- Circ.test(circs, genes, group=as.numeric(as.factor(pheno\$condition)), circle_description = description) write.table(test\$summary_table, "${prefix}_summary.txt", row.names=F) -# Apply pheno to output once more.. - -# if( n_covars == 2 ){ -# -# group_indicator1 <- as.character(covariate_1) -# group_indicator2 <- as.character(covariate_2) -# -# pdf("circ_linear_ratio_plots.pdf", width = 8, height = 10) -# for (i in rownames(test\$summary_table)) { -# Circ.ratioplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=groupindicator1, groupindicator2 = group_indicator2, -# circle_description = c(1:4) ) -# } -# dev.off() -# -# pdf("circ_linear_line_plots.pdf", width = 8, height = 10) -# for (i in rownames(test\$summary_table)) { -# Circ.lineplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=group_indicator1, groupindicator2 = group_indicator2, -# circle_description = c(1:4) ) -# } -# dev.off() -# -# }else{ -# -# group_indicator1 <- as.character(covariate_1) -# -# pdf("circ_linear_ratio_plots.pdf", width = 8, height = 10) -# for (i in rownames(test\$summary_table)) { -# Circ.ratioplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=group_indicator1, -# lab_legend = colnames(pheno)[1], circle_description = c(1:4) ) -# } -# dev.off() -# -# pdf("circ_linear_line_plots.pdf", width = 8, height = 10) -# for (i in rownames(test\$summary_table)) { -# Circ.lineplot(Circ_filtered, Linear_filtered, plotrow=i, groupindicator1=group_indicator1, -# circle_description = c(1:4) ) -# } -# dev.off() -# } + +pdf("circ_linear_ratio_plots.pdf", width = 8, height = 10) +for (i in rownames(test\$summary_table)) { + Circ.ratioplot(circs, genes, plotrow=i, groupindicator1=pheno\$condition, + lab_legend = condition, circle_description = c(1:4) ) +} +dev.off() + +pdf("circ_linear_line_plots.pdf", width = 8, height = 10) +for (i in rownames(test\$summary_table)) { + Circ.lineplot(circs, genes, plotrow=i, groupindicator1=pheno\$condition, + circle_description = description ) +} +dev.off() + ################################################ ################################################ From 69f82c08a6466ff0d0dfd2ce6eed34a34df7562e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 11:34:31 +0200 Subject: [PATCH 277/491] Fix circtest plot problem --- modules/local/circtest/circtest/templates/circtest.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/circtest/circtest/templates/circtest.R b/modules/local/circtest/circtest/templates/circtest.R index b1633c53..debdf039 100755 --- a/modules/local/circtest/circtest/templates/circtest.R +++ b/modules/local/circtest/circtest/templates/circtest.R @@ -439,7 +439,7 @@ write.table(test\$summary_table, "${prefix}_summary.txt", row.names=F) pdf("circ_linear_ratio_plots.pdf", width = 8, height = 10) for (i in rownames(test\$summary_table)) { Circ.ratioplot(circs, genes, plotrow=i, groupindicator1=pheno\$condition, - lab_legend = condition, circle_description = c(1:4) ) + lab_legend = 'condition', circle_description = description ) } dev.off() From d2839a315a88987403d4b072e4771811d778a67e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 11:53:21 +0200 Subject: [PATCH 278/491] Remove artifacts of old differential expression analysis --- bin/DEA.R | 621 ------------------ bin/annotate_outputs.sh | 143 ---- bin/check_empty.sh | 28 - modules/local/annotation/parent_gene/main.nf | 53 -- subworkflows/local/differential_expression.nf | 75 --- 5 files changed, 920 deletions(-) delete mode 100755 bin/DEA.R delete mode 100755 bin/annotate_outputs.sh delete mode 100755 bin/check_empty.sh delete mode 100644 modules/local/annotation/parent_gene/main.nf delete mode 100644 subworkflows/local/differential_expression.nf diff --git a/bin/DEA.R b/bin/DEA.R deleted file mode 100755 index ea5960b7..00000000 --- a/bin/DEA.R +++ /dev/null @@ -1,621 +0,0 @@ -#!/usr/bin/env Rscript - -## Author: Barry Digby -## License: MIT - -get_args <- function(){ - - argp <- arg_parser( - description="this script is designed to automate DESeq2 analysis for circRNA nextflow script", - hide.opts=TRUE) - - argp <- add_argument( - parser=argp, - arg="gene_counts", - short="g", - help="gene_count_matrix.csv produced by prepDE.py downstream of Stringtie quant with -e flag", - default="gene_count_matrix.csv") - - argp <- add_argument( - parser=argp, - arg="phenotype", - short="p", - help="file containing sample metadata information to guide the design", - default="phenotype.csv") - - argp <- add_argument( - parser=argp, - arg="circRNA", - short="c", - help="circRNA counts matrix", - default="merged_counts.bed") - - argp <- add_argument( - parser=argp, - arg="species", - short="s", - help="species ID", - default="hsa") - - argp <- add_argument( - parser=argp, - arg="map", - short="m", - help="ensDB", - "default"="ensemblDatabase.txt") - - argv <- parse_args( - parser=argp, - argv = commandArgs(trailingOnly = TRUE)) - - return(argv) - -} - -giveError <- function(message){ - cat(paste("\n", message, sep="")) - quit() -} - -usage <- function(){giveError("USAGE: DEA.R ")} - - -stage_data <- function(gene_counts, phenotype, circRNA, species, map){ - - inputdata <- list() - - dbmap <- read.table(map, sep="\t", header=T, quote="", stringsAsFactors=FALSE) - gene_mat <- read.csv(gene_counts, row.names="gene_id", check.names=F) - circ <- read.table(circRNA, sep ="\t", header = T, stringsAsFactors=FALSE) - - # Merge circRNA genomic loci to ID - circ$circ <- with(circ, paste0(chr, sep=":", start, sep="-", end, sep=":", strand)) - rownames(circ) <- circ$circ - circ <- subset(circ, select=-c(chr, start, end, strand, circ)) - - # R converts '-' to '.' in colnames here and results in failures. - # If you need to make this 'smarter' check that colnames contains '.', - # compare gsub to colnames(gene_mat), then apply. - colnames(circ) <- gsub("\\.", "-", colnames(circ)) - - ## add pseudocount of 1 - gene_mat <- gene_mat + 1 - circ <- circ + 1 - - inputdata$pheno <- checkinputdata(phenotype) - cols <- rownames(inputdata$pheno) - - if(identical(rownames(inputdata$pheno), colnames(gene_mat))){ - circ <- circ[, cols,] - }else{ - giveError(c("Samples in phenotype file do not match sequencing sample names.\n", - "Please check that phenotype samples match gene_count_matrix.csv headers.\n", - "*Make sure they are sorted in alphabetical order:", - "tail -n +2 phenotype.txt | sort -k1,1\n\n")) - } - - inputdata$gene <- gene_mat - inputdata$circ <- circ - inputdata$design <- makedesign(inputdata$pheno) - inputdata$species <- species - inputdata$map <- dbmap - - inputdata$gene <- ens2symbol(inputdata$gene, inputdata) - - save.image(file='inputdata.RData') - - return(inputdata) -} - - -checkinputdata <- function(phenotype){ - - # Stage phenotype file - pheno <- read.csv(phenotype, row.names=1, header = T, stringsAsFactors = T) - - # Check if there are at least 3 replicates (DESeq2 fails if < 3) - if(min(table(pheno$condition)) >= 3){ - print("Suitable sample size for DE analysis") - }else{ - giveError("Not enough samples per condition to perform DE analysis!") - } - - ## check if all columns are factors. If numeric, convert to factor. - factor_cols <- sapply(pheno, is.factor) - if(all(factor_cols) == TRUE){ - print("All columns in phenotype are factors and suitable for analysis.") - }else{ - numeric_cols <- sapply(pheno, is.numeric) - names <- colnames(pheno)[numeric_cols] - print(paste0("Column(s) ", names, " is numeric. Converting to factor.")) - pheno[numeric_cols] <- as.data.frame(lapply(pheno[numeric_cols], factor)) - final_check <- sapply(pheno, is.factor) - if(all(final_check) == TRUE){ - print("Finished coverting to factor") - }else{ - giveError("Error in converting to factors. See checkinputdata function.") - } - } - - return(pheno) - -} - - - -makedesign <- function(phenotype){ - - # Covariates i.e explanatory variables. - covariates <- names(phenotype)[which(!names(phenotype) %in% c("condition"))] - design <- formula(paste("~", paste(c(covariates, "condition"), sep="", collapse=" + "))) - return(design) - -} - - - - -ens2symbol <- function(mat, inputdata){ - - ## designed to work on input gene_count_matrix.csv file - ## everything else downstream no longer needs to be converted - - mat <- as.data.frame(mat) - map <- inputdata$map - species <- inputdata$species - - if(all(grepl(pattern="^ENSG", rownames(mat)))){ - filter = "ensembl_gene_id" - if(all(grepl(pattern=".", rownames(mat)))){ - filter = "ensembl_gene_id_version" - } - }else{ - filter = "external_gene_name" - } - - if(filter == "external_gene_name"){ - print("Using external gene name as gene symbol") - }else{ - print("Setting up Mart to convert ENS IDs to gene symbols") - ## set up Mart - mart_call <- as.character(subset(map$command, map$species == species)) - print("ENS2SYMBOL") - mart <- eval(str2expression(mart_call)) - } - - ## now go about converting ENS2SYMBOL - if(filter == "ensembl_gene_id"){ - - mat$ensembl_gene_id <- rownames(mat) - info <- getBM(attributes=c("ensembl_gene_id","external_gene_name"), - filters = c("ensembl_gene_id"), - values = mat$ensembl_gene_id, - mart = mart, - useCache=FALSE) - - tmp <- merge(mat, info, by="ensembl_gene_id") - tmp$external_gene_name <- make.names(tmp$external_gene_name, unique = T) - rownames(tmp) <- tmp$external_gene_name - tmp <- subset(tmp, select=-c(ensembl_gene_id, external_gene_name)) - - mat <- tmp - print("input mat ensembl gene id detected and converted") - return(mat) - }else if(filter == "ensembl_gene_id_version"){ - - mat$ensembl_gene_id_version <- rownames(mat) - info <- getBM(attributes=c("ensembl_gene_id_version","external_gene_name"), - filters = c("ensembl_gene_id_version"), - values = mat$ensembl_gene_id_version, - mart = mart, - useCache=FALSE) - - tmp <- merge(mat, info, by="ensembl_gene_id_version") - tmp$external_gene_name <- make.names(tmp$external_gene_name, unique = T) - rownames(tmp) <- tmp$external_gene_name - tmp <- subset(tmp, select=-c(ensembl_gene_id_version, external_gene_name)) - - mat <- tmp - print("input mat ensembl gene id version detected and converted") - return(mat) - }else{ - print("NO change made to input mat ") - return(mat) - } - -} - -get_upregulated <- function(df){ - - key <- intersect(rownames(df)[which(df$log2FoldChange>=1)], rownames(df)[which(df$pvalue<=0.05)]) - results <- as.data.frame((df)[which(rownames(df) %in% key),]) - return(results) - -} - -get_downregulated <- function(df){ - - key <- intersect(rownames(df)[which(df$log2FoldChange<=-1)], rownames(df)[which(df$pvalue<=0.05)]) - results <- as.data.frame((df)[which(rownames(df) %in% key),]) - return(results) - -} - -# Data type provided at end of script to activate RNA-Seq / circRNA analysis. -DESeq2 <- function(inputdata, data_type){ - - if(data_type == "RNA-Seq"){ - outdir <- "RNA-Seq/" - - dds <- DESeqDataSetFromMatrix( - countData=inputdata$gene, - colData=inputdata$pheno, - design = inputdata$design) - - levels <- as.character(unique(inputdata$pheno$condition)) - for(level in levels){ - reference <- level - contrasts <- levels[levels != paste0(reference)] - dds$condition <- relevel(dds$condition, ref = paste0(reference)) - dds <- DESeq(dds, quiet=TRUE) - - DESeq2_plots(dds, outdir) - - for(var in contrasts){ - contrast <- paste(var, "vs", reference, sep="_") - DEG <- getDESeqDEAbyContrast(dds, contrast, reference, var, outdir, inputdata) - } - - save.image(file='RNA-Seq.RData') - - } - }else if(data_type == "circRNA"){ - outdir <- "circRNA/" - - ## use gene sizeFactors - tmp <- DESeqDataSetFromMatrix( - countData=inputdata$gene, - colData=inputdata$pheno, - design = inputdata$design) - tmp <- DESeq(tmp, quiet=TRUE) - - sizefactors <- estimateSizeFactorsForMatrix(counts(tmp)) - rm(tmp) - - dds <- DESeqDataSetFromMatrix( - countData=round(inputdata$circ), - colData=inputdata$pheno, - design = inputdata$design) - - levels <- as.character(unique(inputdata$pheno$condition)) - for(level in levels){ - reference <- level - contrasts <- levels[levels != paste0(reference)] - dds$condition <- relevel(dds$condition, ref = paste0(reference)) - dds <- DESeq(dds, quiet=TRUE) - sizeFactors(dds) <- sizefactors - - DESeq2_plots(dds, outdir) - - for(var in contrasts){ - contrast <- paste(var, "vs", reference, sep="_") - DEG <- getDESeqDEAbyContrast(dds, contrast, reference, var, outdir) - } - - save.image(file='circRNA.RData') - } - }else{ - giveError("Data type not provided correctly, check end of script") - } - return(DEG) -} - - -getDESeqDEAbyContrast <- function(dds, contrast, reference, var, outdir, inputdata) { - - res <- results(dds, filterFun=ihw, alpha=0.05, contrast=c("condition", var, reference)) - cat('\n\nSummary data from DESeq2 for ', contrast, ':', sep="") - summary(res) - - ma_plot(res, contrast, outdir) - - up_regulated <- get_upregulated(res) - down_regulated <- get_downregulated(res) - - de_up <- rownames(up_regulated) - de_down <- rownames(down_regulated) - de <- c(de_up, de_down) - cts <- counts(dds, normalized=T) - - # attempt boxplots here - if(outdir == "circRNA/"){ - make_boxplots(de, cts, contrast) - } - - log2 <- log2(cts +1) - global_heatmap(de, log2, contrast, outdir) - - if(outdir == "RNA-Seq/"){ - up_regulated <- tibble::rownames_to_column(up_regulated, "ID") - down_regulated <- tibble::rownames_to_column(down_regulated, "ID") - }else{ - up_regulated <- tibble::rownames_to_column(up_regulated, "ID") - down_regulated <- tibble::rownames_to_column(down_regulated, "ID") - } - - dir <- paste(outdir, contrast, sep="") - dir.create(dir) - write.table(up_regulated, file.path(dir, paste("DESeq2", contrast, "up_regulated_differential_expression.txt", sep="_")), sep="\t", row.names=F, quote=F) - write.table(down_regulated, file.path(dir, paste("DESeq2", contrast, "down_regulated_differential_expression.txt", sep="_")), sep="\t", row.names=F, quote=F) - - res_df <- as.data.frame(res) - - volcano_plot(res_df, contrast, outdir) - - pdf(file.path(dir, paste("DESeq2", contrast, "fold_change_distribution.pdf", sep="_")), width=8, height=8) - hist(res$log2FoldChange, breaks=50, col="seagreen", xlab=paste("(Fold change)", contrast, sep=" "), main="Distribution of differential expression fold change") - abline(v=c(-1,1), col="black", lwd=2, lty=2) - legend("topright", "Fold change <-1 and >1", lwd=2, lty=2) - dev.off() - - pdf(file.path(dir, paste("DESeq2", contrast, "pvalue_distribution.pdf", sep="_")), width=8, height=8) - hist(res$pvalue, breaks=50, col="seagreen", xlab=paste("P-Value (Fold change)", contrast, sep=" "), main="Distribution of P-Values") - abline(v=c(0.05),col="black",lwd=2,lty=2) - legend("topright", "P-Value <0.05",lwd=2,lty=2) - dev.off() - - pdf(file.path(dir, paste("DESeq2", contrast, "Adj_pvalue_distribution.pdf", sep="_")), width=8, height=8) - hist(res$padj, breaks=50, col="seagreen", xlab=paste("P-Adj (Fold change)", contrast, sep=" "), main="Distribution of AdjP-Values") - abline(v=c(0.05),col="black",lwd=2,lty=2) - legend("top", "P-Adj <0.05",lwd=2,lty=2) - dev.off() -} - - -DESeq2_plots <- function(dds, outdir){ - - dir.create("DESeq2_QC") - dir.create(paste("DESeq2_QC/", outdir, sep="")) - dir=paste("DESeq2_QC/", outdir, sep="") - - pdf(file.path(dir, "DESeq2_dispersion.pdf"), width=8, height=8) - plotDispEsts(dds) - dev.off() - - counts <- counts(dds, normalized=T) - - if(outdir == "RNA-Seq/"){ - counts <- ens2symbol(counts, inputdata) - log2 <- log2(counts + 1) - }else{ - counts <- as.data.frame(counts) - log2 <- log2(counts + 1) - } - - write_counts <- tibble::rownames_to_column(counts, "ID") - write_log2 <- tibble::rownames_to_column(log2, "ID") - - write.table(write_counts, file.path(outdir, "DESeq2_normalized_counts.txt"), sep="\t", quote=F, row.names = F) - write.table(write_log2, file.path(outdir, "DESeq2_log2_transformed_counts.txt"), sep="\t", quote=F, row.names = F) - - sample_to_sample_heatmap(log2, outdir) - sample_to_sample_dendogram(log2, outdir) - PCA_plot(log2, outdir) - -} - - -ma_plot <- function(res, contrast, outdir){ - dir <- paste(outdir, contrast, sep="") - dir.create(dir) - pdf(file.path(dir, paste("DESeq2", contrast, "MA_plot.pdf", sep="_")), width=8, height=8) - plotMA(res) - dev.off() - -} - -sample_to_sample_heatmap <- function(log2, outdir){ - - dir.create("DESeq2_QC") - dir.create(paste("DESeq2_QC/", outdir, sep="")) - dir=paste("DESeq2_QC/", outdir, sep="") - - sampleDists <- dist(t(log2)) - sampleDistMatrix <- as.matrix(sampleDists) - pdf(file.path(dir, "DESeq2_sample_heatmap.pdf"), width=8, height=8) - pheatmap(mat=sampleDistMatrix, - clustering_distance_rows=sampleDists, - clustering_distance_cols=sampleDists, - col=colorRampPalette( rev(brewer.pal(9, "Blues")) )(255), - fontsize_row=8) - dev.off() - -} - - - -sample_to_sample_dendogram <- function(log2, outdir){ - - dir.create("DESeq2_QC") - dir.create(paste("DESeq2_QC/", outdir, sep="")) - dir=paste("DESeq2_QC/", outdir, sep="") - - d=t(log2) - d=dist(d) - hc=hclust(d, method="complete") - print("test hclust") - print(head(d)) - pdf(file.path(dir, "DESeq2_sample_dendogram.pdf")) - plot(hc) - dev.off() - -} - - -PCA_plot <- function(log2, outdir){ - - p <- pca(log2, metadata=inputdata$pheno) - - for(exp_var in names(inputdata$pheno)){ - dir.create("DESeq2_QC") - dir=paste("DESeq2_QC/", outdir, sep="") - pdf(file.path(dir, paste("DESeq2", exp_var, "PCA.pdf", sep="_"))) - biplot <- biplot(p, - colby=paste(exp_var), - hline=0, - vline=0, - legendPosition="right", - legendLabSize=12, - legendIconSize=8, - lab = TRUE, - labSize = 0.0, - drawConnectors=FALSE, - title="PCA bi-plot", - subtitle="PC1 vs. PC2") - plot(biplot) - dev.off() - } -} - - -volcano_plot <- function(res, contrast, outdir){ - - res <- na.omit(res) - - min_width <- min(res$log2FoldChange) - max_width <- max(res$log2FoldChange) - symmetric_plot <- max(max_width, abs(min_width)) - min_width <- symmetric_plot * -1 - max_width <- symmetric_plot - max_height <- -log10(min(res[res$pvalue>0, 5])) - - up <- subset(res, res$log2FoldChange > 1 & res$pvalue <= 0.05) - up <- up[order(-up$log2FoldChange),] - up_list <- head(rownames(up), n=10L) - - down <- subset(res, res$log2FoldChange < 1 & res$pvalue <= 0.05) - down <- down[order(down$log2FoldChange),] - down_list <- head(rownames(down), n=10L) - - plot_top_20 <- c(up_list, down_list) - - dir <- paste(outdir, contrast, sep="") - dir.create(dir) - pdf(file.path(dir, paste("DESeq2", contrast, "volcano_plot.pdf", sep="_"))) - p <- EnhancedVolcano(res, - lab=rownames(res), - x="log2FoldChange", - y="pvalue", - selectLab=FALSE, - drawConnectors=FALSE, - FCcutoff=1.0, - pCutoff=0.05, - title="Volcano Plot", - subtitle=paste(contrast), - #legendVisible=F, - caption = paste0('Total Genes = ', nrow(res)), - xlim=c(min_width, max_width), - ylim=c(0, max_height), - pointSize = 1.5) - plot(p) - dev.off() - -} - - -global_heatmap <- function(de, log2, contrast, outdir){ - - # Split contrast e.g normal_vs_tumor -> "normal", "tumor" - levels <- unlist(strsplit(contrast, "_vs_")) - pheno <- inputdata$pheno - # subset phenotype file for contrast samples - pheno_subset <- subset(pheno, pheno$condition %in% levels) - # check it worked? - #print(pheno_subset) - # subset log2 counts for contrast samples - mat <- log2[,rownames(pheno_subset)] - # subset de genes/circRNAs - mat <- mat[de,] - # Perform scaling and centering on DE expr data - mat <- t(mat) - mat <- scale(mat, center=T) - mat <- t(mat) - - dir <- paste(outdir, contrast, sep="") - dir.create(dir) - pdf(file.path(dir, paste("DESeq2", contrast, "heatmap.pdf", sep="_"))) - pheatmap(mat, - annotation_col=pheno_subset, - color=greenred(75), - cluster_rows = T, - show_rownames = F) - dev.off() - -} - - - -make_boxplots <- function(de, cts, contrast){ - - pheno <- inputdata$pheno - levels <- unlist(strsplit(contrast, "_vs_")) - pheno_subset <- subset(pheno, pheno$condition %in% levels) - # subset counts for levels of interest - counts <- cts[,rownames(pheno_subset)] - # subset for de genes - counts <- as.data.frame(counts[de,]) - dir.create("boxplots") - dir.create(paste("boxplots/", contrast, sep="")) - dir=paste("boxplots/", contrast, sep="") - for( i in 1:nrow(counts)){ - circ_id <- rownames(counts[i,]); - mat <- as.data.frame(t(counts[i,])); - mat <- cbind(mat, pheno_subset); - names <- c("counts", "condition"); - colnames(mat) <- names; - - p1 <- ggboxplot(mat, x="condition", y="counts", - fill="condition", palette = "npg", - title = paste(circ_id), - ylab = "normalized counts", xlab="", - add = c("dotplot"), - add.params = list(size=0.5, jitter=0.1), - legend = "none", - bxp.errorbar = T, - bxp.errorbar.width = 0.2, width=0.3, - ggtheme = theme_classic()) + - rotate_x_text(angle = 0) + - theme(plot.title = element_text(face = "bold", size=16, hjust = 0.5)) + - theme(axis.text.x = element_text( colour = "black", size=14)) + - theme(axis.title.y = element_text(size=14, face = "italic")) + - theme(axis.title.x = element_blank()) + - theme(axis.text.y = element_text(color = "black", size=10)) - - pdf(file.path(dir, paste(circ_id, "boxplot.pdf", sep="_"))) - plot(p1) - dev.off() - } -} - - -options(error=function()traceback(2)) -suppressPackageStartupMessages(library("argparser")) -suppressPackageStartupMessages(library("biomaRt")) -suppressPackageStartupMessages(library("DESeq2")) -suppressPackageStartupMessages(library("dplyr")) -suppressPackageStartupMessages(library("EnhancedVolcano")) -suppressPackageStartupMessages(library("ggplot2")) -suppressPackageStartupMessages(library("ggpubr")) -suppressPackageStartupMessages(library("gplots")) -suppressPackageStartupMessages(library("IHW")) -suppressPackageStartupMessages(library("PCAtools")) -suppressPackageStartupMessages(library("pheatmap")) -suppressPackageStartupMessages(library("RColorBrewer")) - -arg <- get_args() - -inputdata <- stage_data(arg$gene_counts, arg$phenotype, arg$circRNA, arg$species, arg$map) -dir.create("RNA-Seq") -dir.create("circRNA") -x <- DESeq2(inputdata, "RNA-Seq") -y <- DESeq2(inputdata, "circRNA") diff --git a/bin/annotate_outputs.sh b/bin/annotate_outputs.sh deleted file mode 100755 index 3c2054f2..00000000 --- a/bin/annotate_outputs.sh +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/env bash - -echo "====================================================================================" -echo "[nf-core/circrna]: circRNA annotation script " -echo "[nf-core/circrna]: Author: Barry Digby " -echo "[nf-core/circrna]: Institution: National University of Ireland, Galway " -echo "[nf-core/circrna]: " -echo "[nf-core/circrna]: MIT license " -echo "====================================================================================" - -mkdir -p bed12 - -EB=$1 - -while IFS='' read -r line; do - - name=$(echo $line | awk '{print $4}') - count=$(echo $line | awk '{print $5}') - touch ${name}.bed - echo "$line" >> ${name}.bed_tmp - sed 's/[\t]*$//' ${name}.bed_tmp > ${name}.bed && rm ${name}.bed_tmp - - bedtools intersect -a filt.gtf -b ${name}.bed -s -f 1.00 > ${name}.gtf - - start=$(echo $line | awk '{print $2}') - stop=$(echo $line | awk '{print $3}') - - echo "[nf-core/circrna]: Starting analysis for: $name" - - # is the gtf file NOT (-s) empty? i.e did it overlap biotypes? - if [[ -s ${name}.gtf ]]; - then - - echo "[nf-core/circrna]: $name overlaps features in GTF file" - echo "[nf-core/circrna]: Inspecting Genes..." - - gene_id=$(awk -F'gene_id ' '{print $2}' ${name}.gtf | \ - awk -F';' '{print $1}' | sed 's/"//g' | sort -u | paste -s -d, -) - - tx_id=$(awk -F'transcript_id ' '{print $2}' ${name}.gtf | \ - awk -F';' '{print $1}' | sed 's/"//g' | sort -u | paste -s -d, -) - - echo "[nf-core/circrna]: Overlapping Gene IDs: $gene_id" - echo "[nf-core/circrna]: Converting to BED12" - - gtfToGenePred ${name}.gtf ${name}.genepred - genePredToBed ${name}.genepred ${name}_predtobed.bed - - # Attempting perfect exon boundary overlaps - echo "[nf-core/circrna]: Attempting to fit circRNA to gene exon boundaries" - awk -v OFS="\t" -v start="$start" -v stop="$stop" \ - '{if($2==start && $3==stop) print $0}' ${name}_predtobed.bed | \ - sort -rnk10 | head -n 1 > ${name}.bed12.bed - - # Resulting file not empty? i.e perfectly overlapped with exon boundaries? - if [[ -s ${name}.bed12.bed ]]; - then - echo "[nf-core/circrna]: ${name} fits gene exons, is a circRNA" - type="circRNA" - else - - echo "[nf-core/circrna]: circRNA overlaps exons, but not boundaries" - echo "[nf-core/circrna]: Investigating if EIciRNA or acceptable to take underlying transcript" - echo "[nf-core/circrna]: Retrying with longest underlying transcript" - - awk -v OFS="\t" '{$13 = $3 - $2; print}' ${name}_predtobed.bed | \ - sort -rnk13 | cut -f13 --complement | head -n 1 > ${name}.bed12.bed_tmp - - tx_len=$(awk -v OFS="\t" '{$13 = $3 - $2; print}' ${name}_predtobed.bed | \ - sort -rnk13 | awk '{print $13}' | head -n 1) - - circ_len=$(awk -v OFS="\t" '{$7 = $3 - $2; print}' ${name}.bed | awk '{print $7}') - - echo "[nf-core/circrna]: Best transcript length: $tx_len" - echo "[nf-core/circrna]: $name length: $circ_len" - - difference=$(($circ_len - $tx_len)) - - if [[ $difference -gt $EB ]]; - then - - echo "[nf-core/circrna]: Transcript exon boundaries more than ${EB}bp off $name" - echo "[nf-core/circrna]: Treating as EIciRNA" - - type="EIciRNA" - block_count=1 - block_size=$(($stop-$start)) - rgb="0,0,0" - block_start=0 - awk -v OFS="\t" -v thick=$start -v rgb=$rgb -v count=$block_count -v start=$block_start -v size=$block_size \ - '{print $0, thick, thick, rgb, count, size, start}' ${name}.bed > ${name}.bed12.bed - rm ${name}.bed12.bed_tmp - else - - echo "[nf-core/circrna]: Transcript exon boundaries within ${EB}bp ${name}" - echo "[nf-core/circrna]: Treating ${name} as circRNA." - type="circRNA" - mv ${name}.bed12.bed_tmp ${name}.bed12.bed - fi - fi - else - - echo "[nf-core/circrna]: $name returned no GTF overlaps." - echo "[nf-core/circrna]: Treating as an intronic circRNA" - - gene_id="NA" - tx_id="NA" - type="ciRNA" - block_count=1 - block_size=$(($stop-$start)) - rgb="0,0,0" - block_start=0 - awk -v OFS="\t" -v thick=$start -v rgb=$rgb -v count=$block_count -v start=$block_start -v size=$block_size \ - '{print $0, thick, thick, rgb, count, size, start}' ${name}.bed > ${name}.bed12.bed - fi - # add type, geneid tx_id and count - awk -v type="$type" -v gene="$gene_id" -v tx="$tx_id" -v count="$count" 'BEGIN{FS=OFS="\t"}{$5=count;$13=type;$14=gene;$15=tx}1' ${name}.bed12.bed > ${name}.bed12.bed_tmp - awk -v OFS="\t" -v name=$name '{$4 = name; print}' ${name}.bed12.bed_tmp > ${name}.bed12.bed_tmp1 - - rm ${name}.bed12.bed - rm ${name}.bed12.bed_tmp - mv ${name}.bed12.bed_tmp1 ${name}.bed12.bed - echo "[nf-core/circrna]: cleaning up intermediate files" - rm -f ${name}.gtf - rm -f ${name}.genepred - rm -f ${name}_predtobed.bed - rm -f ${name}.bed - - cp ${name}.bed12.bed bed12/ - rm -rf ${name}.bed12.bed - echo "====================================================================================" - echo "====================================================================================" - -done < circs.bed - -# remove the trailing commas that appear on end of Exon Size, Exon Starts (col 11, 12) -cat bed12/*.bed12.bed > master_bed12.bed.tmp - -awk 'BEGIN{FS=OFS="\t"} {gsub(/,$/,"",$11);gsub(/,$/,"",$12)} 1' master_bed12.bed.tmp > master_bed12.bed && rm master_bed12.bed.tmp - -echo " Thank you for using nf-core/circrna! - Barry " -echo "====================================================================================" -echo "====================================================================================" diff --git a/bin/check_empty.sh b/bin/check_empty.sh deleted file mode 100755 index 8f28e88c..00000000 --- a/bin/check_empty.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -## When consolidating tool outputs for a sample, check if any are empty. -## This will prevent R from throwing errors -## Author: Barry Digby -## License: MIT - -for i in *bed; do - - if [[ -s $i ]]; - then - : - else - echo "${i}" >> remove_empty_sample.txt - fi - -done - -## sample.csv contains all tool bed files by default -mv samples.csv checkme.csv - -## if there are empty tool outputs then remove them from samples.csv and rewrite. -if [[ -s remove_empty_sample.txt ]]; -then - grep -vf remove_empty_sample.txt checkme.csv > samples.csv -else - mv checkme.csv samples.csv -fi diff --git a/modules/local/annotation/parent_gene/main.nf b/modules/local/annotation/parent_gene/main.nf deleted file mode 100644 index 21f0b892..00000000 --- a/modules/local/annotation/parent_gene/main.nf +++ /dev/null @@ -1,53 +0,0 @@ -process PARENT_GENE { - label 'process_high' - - conda "bioconda::ucsc-gtftogenepred=377 bioconda::ucsc-genepredtobed=377 bioconda::bedtools=2.27.0" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' : - 'biocontainers/mulled-v2-d7ee3552d06d8acebbc660507b48487c7369e221:07daadbfe8182aa3c974c7b78924d5c8730b922d-0' }" - - input: - path circrna_matrix - path gtf - path biotypes - val exon_boundary - - output: - path "circrna_host-gene.txt" , emit: circ_host_map - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def VERSION = '377' - """ - # remove redundant biotypes from GTF. - grep -vf $biotypes $gtf > filt.gtf - - # generate circrna BED file. - tail -n +2 $circrna_matrix | awk '{print \$1}' > IDs.txt - - # ID_to_BED - while IFS='' read -r line; do - name=\$(echo \$line) - chr=\$(echo \$line | cut -d: -f1) - start=\$(echo \$line | cut -d- -f1 | cut -d: -f2) - stop=\$(echo \$line | cut -d- -f2 | cut -d: -f1) - sign=\$(echo \$line | cut -d: -f3) - echo -e "\$chr\\t\$start\\t\$stop\\t\$name\\t0\\t\$sign" >> \${name}.bed - done < IDs.txt - - cat *.bed > merged.txt && rm IDs.txt && rm *.bed && mv merged.txt circs.bed - - # Re-use annotation script to identify the host gene. - annotate_outputs.sh $exon_boundary &> annotation.log - awk -v OFS="\\t" '{print \$4, \$14}' master_bed12.bed > circrna_host-gene.txt - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bedtools: \$(bedtools --version | sed -e "s/bedtools v//g") - ucsc: $VERSION - END_VERSIONS - """ -} diff --git a/subworkflows/local/differential_expression.nf b/subworkflows/local/differential_expression.nf deleted file mode 100644 index d4199b86..00000000 --- a/subworkflows/local/differential_expression.nf +++ /dev/null @@ -1,75 +0,0 @@ -include { HISAT2_ALIGN } from '../../modules/nf-core/hisat2/align/main' -include { STRINGTIE_STRINGTIE } from '../../modules/nf-core/stringtie/stringtie/main' -include { STRINGTIE_PREPDE } from '../../modules/local/stringtie/prepde/main' -include { PARENT_GENE } from '../../modules/local/annotation/parent_gene/main' -include { PREPARE_CLR_TEST } from '../../modules/local/circtest/prepare/main' -include { CIRCTEST } from '../../modules/local/circtest/test/main' -include { DESEQ2_DIFFERENTIAL_EXPRESSION } from '../../modules/local/deseq2/differential_expression/main' -include { BAM_SORT_STATS_SAMTOOLS } from '../nf-core/bam_sort_stats_samtools/main' - -workflow DIFFERENTIAL_EXPRESSION { - - take: - reads - ch_gtf - ch_fasta - hisat2_index - splice_sites - phenotype - counts_bed - counts_tsv - species - ensembl_map - exon_boundary - - main: - ch_versions = Channel.empty() - qc_reports = Channel.empty() - - fasta = ch_fasta.map{ meta, fasta -> fasta } - gtf = ch_gtf.map{ meta, gtf -> gtf } - - // - // LINEAR RNA ALIGNEMT WORKFLOW: - // - - HISAT2_ALIGN( reads, hisat2_index, splice_sites ) - BAM_SORT_STATS_SAMTOOLS( HISAT2_ALIGN.out.bam, ch_fasta ) - STRINGTIE_STRINGTIE( BAM_SORT_STATS_SAMTOOLS.out.bam, gtf ) - STRINGTIE_PREPDE( STRINGTIE_STRINGTIE.out.transcript_gtf.map{ meta, gtf -> return [ gtf ] }.collect() ) - - qc_reports = qc_reports.mix(HISAT2_ALIGN.out.summary.map{ meta, log -> log}) - qc_reports = qc_reports.mix(BAM_SORT_STATS_SAMTOOLS.out.stats.map{ meta, stats -> stats}) - qc_reports = qc_reports.mix(BAM_SORT_STATS_SAMTOOLS.out.flagstat.map{ meta, flagstat -> flagstat}) - qc_reports = qc_reports.mix(BAM_SORT_STATS_SAMTOOLS.out.idxstats.map{ meta, idxstats -> idxstats}) - - - // - // Circular, Linear Differential Expression - // - - DESEQ2_DIFFERENTIAL_EXPRESSION( STRINGTIE_PREPDE.out.gene_matrix, phenotype, counts_bed, species, ensembl_map ) - - // - // CircRNA - Host Gene Ratio tests - // - - ch_biotypes = Channel.fromPath("${projectDir}/bin/unwanted_biotypes.txt") - - PARENT_GENE( counts_tsv, gtf, ch_biotypes.collect(), exon_boundary ) - PREPARE_CLR_TEST( STRINGTIE_PREPDE.out.gene_matrix, counts_tsv, PARENT_GENE.out.circ_host_map, gtf ) - CIRCTEST( PREPARE_CLR_TEST.out.circular, PREPARE_CLR_TEST.out.linear, phenotype ) - - ch_versions = ch_versions.mix(HISAT2_ALIGN.out.versions) - ch_versions = ch_versions.mix(BAM_SORT_STATS_SAMTOOLS.out.versions) - ch_versions = ch_versions.mix(STRINGTIE_STRINGTIE.out.versions) - ch_versions = ch_versions.mix(STRINGTIE_PREPDE.out.versions) - ch_versions = ch_versions.mix(DESEQ2_DIFFERENTIAL_EXPRESSION.out.versions) - ch_versions = ch_versions.mix(PARENT_GENE.out.versions) - ch_versions = ch_versions.mix(PREPARE_CLR_TEST.out.versions) - ch_versions = ch_versions.mix(CIRCTEST.out.versions) - - emit: - versions = ch_versions - reports = qc_reports -} From b67e980fda09fb2775be33e7e870eff933818958 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 14:41:02 +0200 Subject: [PATCH 279/491] Simplify annotation module --- modules/local/annotation/{full_annotation => }/main.nf | 0 subworkflows/local/discovery/annotation.nf | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename modules/local/annotation/{full_annotation => }/main.nf (100%) diff --git a/modules/local/annotation/full_annotation/main.nf b/modules/local/annotation/main.nf similarity index 100% rename from modules/local/annotation/full_annotation/main.nf rename to modules/local/annotation/main.nf diff --git a/subworkflows/local/discovery/annotation.nf b/subworkflows/local/discovery/annotation.nf index d865a5da..518260b6 100644 --- a/subworkflows/local/discovery/annotation.nf +++ b/subworkflows/local/discovery/annotation.nf @@ -1,5 +1,5 @@ include { BEDTOOLS_INTERSECT as INTERSECT } from '../../../modules/nf-core/bedtools/intersect' -include { ANNOTATION as ANNOTATE } from '../../../modules/local/annotation/full_annotation' +include { ANNOTATION as ANNOTATE } from '../../../modules/local/annotation' include { GNU_SORT as COMBINE_BEDS } from '../../../modules/nf-core/gnu/sort' include { GAWK as REMOVE_SCORE_STRAND } from '../../../modules/nf-core/gawk' include { GNU_SORT as COMBINE_GTFS } from '../../../modules/nf-core/gnu/sort' From 6fdc23d8a02672c6a18f966977f32577bdde81b4 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 14:54:03 +0200 Subject: [PATCH 280/491] Switch annotation to template syntax --- modules/local/annotation/main.nf | 22 +++------ .../local/annotation/templates}/annotation.py | 46 ++++++++++++++----- 2 files changed, 41 insertions(+), 27 deletions(-) rename {bin => modules/local/annotation/templates}/annotation.py (75%) diff --git a/modules/local/annotation/main.nf b/modules/local/annotation/main.nf index 207cd463..a5b6d77a 100644 --- a/modules/local/annotation/main.nf +++ b/modules/local/annotation/main.nf @@ -12,22 +12,12 @@ process ANNOTATION { val(exon_boundary) output: - tuple val(meta), path("${out_bed}"), emit: bed - tuple val(meta), path("${out_gtf}"), emit: gtf - path "versions.yml", emit: versions + tuple val(meta), path("${prefix}.bed"), emit: bed + tuple val(meta), path("${prefix}.gtf"), emit: gtf - script: - prefix = task.ext.prefix ?: "${meta.id}.annotation" - out_bed = "${prefix}.bed" - out_gtf = "${prefix}.gtf" - """ - annotation.py --input ${intersection} --exon_boundary ${exon_boundary} --output_bed ${out_bed} --output_gtf ${out_gtf} + path "versions.yml" , emit: versions - cat <<-END_VERSIONS > versions.yml - "${task.process}": - python: \$(python --version | sed 's/Python //g') - pandas: \$(python -c "import pandas; print(pandas.__version__)") - numpy: \$(python -c "import numpy; print(numpy.__version__)") - END_VERSIONS - """ + script: + prefix = task.ext.prefix ?: meta.id + template 'annotation.py' } diff --git a/bin/annotation.py b/modules/local/annotation/templates/annotation.py similarity index 75% rename from bin/annotation.py rename to modules/local/annotation/templates/annotation.py index 877ed877..6cd1d68d 100755 --- a/bin/annotation.py +++ b/modules/local/annotation/templates/annotation.py @@ -2,16 +2,27 @@ import pandas as pd import numpy as np -import argparse +import platform import csv -parser = argparse.ArgumentParser(description='Annotate circRNAs') -parser.add_argument('--input', type=str, help='Path to the input file') -parser.add_argument('--exon_boundary', type=int, help='Exon boundary') -parser.add_argument('--output_bed', type=str, help='Path to the output bed file') -parser.add_argument('--output_gtf', type=str, help='Path to the output gtf') +def format_yaml_like(data: dict, indent: int = 0) -> str: + """Formats a dictionary to a YAML-like string. -args = parser.parse_args() + Args: + data (dict): The dictionary to format. + indent (int): The current indentation level. + + Returns: + str: A string formatted as YAML. + """ + yaml_str = "" + for key, value in data.items(): + spaces = " " * indent + if isinstance(value, dict): + yaml_str += f"{spaces}{key}:\\n{format_yaml_like(value, indent + 1)}" + else: + yaml_str += f"{spaces}{key}: {value}\\n" + return yaml_str columns = { @@ -28,9 +39,9 @@ attributes = ['gene_id', 'gene_name', 'transcript_id'] -exon_boundary = args.exon_boundary +exon_boundary = int("${exon_boundary}") -df = pd.read_csv(args.input, sep="\t", header=None, usecols=columns.keys()) +df = pd.read_csv("${intersection}", sep="\\t", header=None, usecols=columns.keys()) df = df.rename(columns=columns) # Extract circRNAs without match @@ -99,7 +110,7 @@ def determine_type(row): # Sort by chr, start, end df = df.sort_values(['chr', 'start', 'end']) -df.to_csv(args.output_bed, sep='\t', index=False, header=False) +df.to_csv("${prefix}.bed", sep='\\t', index=False, header=False) # Convert to GTF df['source'] = 'circRNA' @@ -109,4 +120,17 @@ def determine_type(row): gtf_order = ['chr', 'source', 'type', 'start', 'end', 'score', 'strand', 'frame', 'attributes'] df = df[gtf_order] -df.to_csv(args.output_gtf, sep='\t', index=False, header=False, quoting=csv.QUOTE_NONE) +df.to_csv("${prefix}.gtf", sep='\\t', index=False, header=False, quoting=csv.QUOTE_NONE) + +# Versions + +versions = { + "${task.process}": { + "python": platform.python_version(), + "pandas": pd.__version__, + "numpy": np.__version__ + } +} + +with open("versions.yml", "w") as f: + f.write(format_yaml_like(versions)) From a87569b2f2f53b7ea53a78a04bcf0cb2ae4713cb Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 14:59:11 +0200 Subject: [PATCH 281/491] Remove unused combine_quantification script --- bin/combine_quantification.py | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100755 bin/combine_quantification.py diff --git a/bin/combine_quantification.py b/bin/combine_quantification.py deleted file mode 100755 index dd0b1307..00000000 --- a/bin/combine_quantification.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import pandas as pd -import os - -parser = argparse.ArgumentParser(description='Merge quantification files into a single file') -parser.add_argument('--inputs', type=str, nargs='+', help='List input files to merge') -parser.add_argument('--output', type=str, help='Path to output combined quantification file') - -args = parser.parse_args() - -dfs = [pd.read_csv(f, sep='\t', index_col=[0, 1]) for f in args.inputs] -df_combined = pd.concat(dfs, axis=1, sort=True) - -df_combined.to_csv(args.output, sep='\t') From fa7cc09cac1c9e8a2fdc6b23d238a0df9278dbe0 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 15:05:17 +0200 Subject: [PATCH 282/491] Switch merge_samples to template syntax --- bin/merge_samples.py | 29 ---------- .../local/count_matrix/merge_samples/main.nf | 11 +--- .../merge_samples/templates/merge_samples.py | 53 +++++++++++++++++++ 3 files changed, 55 insertions(+), 38 deletions(-) delete mode 100755 bin/merge_samples.py create mode 100755 modules/local/count_matrix/merge_samples/templates/merge_samples.py diff --git a/bin/merge_samples.py b/bin/merge_samples.py deleted file mode 100755 index f50fe3db..00000000 --- a/bin/merge_samples.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import pandas as pd -import os - -parser = argparse.ArgumentParser(description='Merge counts across tools for a single sample') -parser.add_argument('--beds', type=str, nargs='+', help='List of bed files to merge') -parser.add_argument('--out_bed', type=str, help='Output bed file') -parser.add_argument('--out_tsv', type=str, help='Output tsv file') - -args = parser.parse_args() - -columns = ['chr', 'start', 'end', 'name', 'count', 'strand'] -dfs = {os.path.basename(bed).split('.')[0]: pd.read_csv(bed, - sep='\t', - header=None, - index_col=["chr", "start", "end", "strand"], - usecols=["chr", "start", "end", "strand", "count"], - names=columns) for bed in args.beds} - -dfs = [df.rename(columns={'count': sample}) for sample, df in dfs.items()] -df = pd.concat(dfs, axis=1) -df = df.fillna(0) -df.to_csv(args.out_bed, sep='\t', header=True, index=True) - -df.index = df.index.map(lambda x: f'{x[0]}:{x[1]}-{x[2]}:{x[3]}') -df.index.name = 'ID' -df.to_csv(args.out_tsv, sep='\t') diff --git a/modules/local/count_matrix/merge_samples/main.nf b/modules/local/count_matrix/merge_samples/main.nf index b286c757..410d2097 100644 --- a/modules/local/count_matrix/merge_samples/main.nf +++ b/modules/local/count_matrix/merge_samples/main.nf @@ -12,16 +12,9 @@ process MERGE_SAMPLES { output: path("merged_counts.bed") , emit: counts_bed path("merged_counts.tsv") , emit: counts_tsv + path "versions.yml" , emit: versions script: - """ - merge_samples.py --beds ${beds} --out_bed merged_counts.bed --out_tsv merged_counts.tsv - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - python: \$(python --version | sed 's/Python //g') - pandas: \$(python -c "import pandas; print(pandas.__version__)") - END_VERSIONS - """ + template "merge_samples.py" } diff --git a/modules/local/count_matrix/merge_samples/templates/merge_samples.py b/modules/local/count_matrix/merge_samples/templates/merge_samples.py new file mode 100755 index 00000000..010eb616 --- /dev/null +++ b/modules/local/count_matrix/merge_samples/templates/merge_samples.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +import platform +import pandas as pd +import os + +def format_yaml_like(data: dict, indent: int = 0) -> str: + """Formats a dictionary to a YAML-like string. + + Args: + data (dict): The dictionary to format. + indent (int): The current indentation level. + + Returns: + str: A string formatted as YAML. + """ + yaml_str = "" + for key, value in data.items(): + spaces = " " * indent + if isinstance(value, dict): + yaml_str += f"{spaces}{key}:\\n{format_yaml_like(value, indent + 1)}" + else: + yaml_str += f"{spaces}{key}: {value}\\n" + return yaml_str + +columns = ['chr', 'start', 'end', 'name', 'count', 'strand'] +dfs = {os.path.basename(bed).split('.')[0]: pd.read_csv(bed, + sep='\t', + header=None, + index_col=["chr", "start", "end", "strand"], + usecols=["chr", "start", "end", "strand", "count"], + names=columns) for bed in "${beds}".split()} + +dfs = [df.rename(columns={'count': sample}) for sample, df in dfs.items()] +df = pd.concat(dfs, axis=1) +df = df.fillna(0) +df.to_csv("merged_counts.bed", sep='\\t', header=True, index=True) + +df.index = df.index.map(lambda x: f'{x[0]}:{x[1]}-{x[2]}:{x[3]}') +df.index.name = 'ID' +df.to_csv("merged_counts.tsv", sep='\\t') + +# Versions + +versions = { + "${task.process}": { + "python": platform.python_version(), + "pandas": pd.__version__ + } +} + +with open("versions.yml", "w") as f: + f.write(format_yaml_like(versions)) From f3e63fda741b81eb64add683f6df7b6ab30dc4a1 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 15:24:02 +0200 Subject: [PATCH 283/491] Switch to template syntax in merge_tools --- bin/merge_tools.py | 24 --------- .../local/count_matrix/merge_tools/main.nf | 12 +---- .../merge_tools/templates/merge_tools.py | 52 +++++++++++++++++++ 3 files changed, 54 insertions(+), 34 deletions(-) delete mode 100755 bin/merge_tools.py create mode 100755 modules/local/count_matrix/merge_tools/templates/merge_tools.py diff --git a/bin/merge_tools.py b/bin/merge_tools.py deleted file mode 100755 index 3d6a1396..00000000 --- a/bin/merge_tools.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import pandas as pd - -parser = argparse.ArgumentParser(description='Merge counts across tools for a single sample') -parser.add_argument('--beds', type=str, nargs='+', help='List of bed files to merge') -parser.add_argument('--tool_filter', type=int, help='Minimum number of tools to keep a circRNA') -parser.add_argument('--duplicates_fun', type=str, help='Function to apply to duplicates', choices=['sum', 'mean', 'max', 'min']) -parser.add_argument('--output', type=str, help='Output file') - -args = parser.parse_args() - -columns = ['chr', 'start', 'end', 'name', 'count', 'strand'] -dfs = [pd.read_csv(bed, sep='\t', header=None, names=columns) for bed in args.beds] -df = pd.concat(dfs) - -df['tool_count'] = 1 -df = df.groupby(['chr', 'start', 'end', 'strand', 'name']).agg({'count': args.duplicates_fun, - 'tool_count': 'sum'}).reset_index() -df = df[df['tool_count'] >= args.tool_filter] - -df = df[columns] -df.to_csv(args.output, sep='\t', index=False, header=False) diff --git a/modules/local/count_matrix/merge_tools/main.nf b/modules/local/count_matrix/merge_tools/main.nf index 17f8556f..dc80f483 100644 --- a/modules/local/count_matrix/merge_tools/main.nf +++ b/modules/local/count_matrix/merge_tools/main.nf @@ -15,16 +15,8 @@ process MERGE_TOOLS { output: tuple val(meta), path("${meta.id}.merged.bed"), emit: merged - path "versions.yml" , emit: versions + path "versions.yml" , emit: versions script: - """ - merge_tools.py --beds ${beds} --tool_filter ${tool_filter} --duplicates_fun ${duplicates_fun} --output ${meta.id}.merged.bed - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - python: \$(python --version | sed 's/Python //g') - pandas: \$(python -c "import pandas; print(pandas.__version__)") - END_VERSIONS - """ + template 'merge_tools.py' } diff --git a/modules/local/count_matrix/merge_tools/templates/merge_tools.py b/modules/local/count_matrix/merge_tools/templates/merge_tools.py new file mode 100755 index 00000000..debb85bf --- /dev/null +++ b/modules/local/count_matrix/merge_tools/templates/merge_tools.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 + +import platform +import pandas as pd + +def format_yaml_like(data: dict, indent: int = 0) -> str: + """Formats a dictionary to a YAML-like string. + + Args: + data (dict): The dictionary to format. + indent (int): The current indentation level. + + Returns: + str: A string formatted as YAML. + """ + yaml_str = "" + for key, value in data.items(): + spaces = " " * indent + if isinstance(value, dict): + yaml_str += f"{spaces}{key}:\\n{format_yaml_like(value, indent + 1)}" + else: + yaml_str += f"{spaces}{key}: {value}\\n" + return yaml_str + +duplicates_fun = "${duplicates_fun}" + +if duplicates_fun not in ['sum', 'mean', 'max', 'min']: + raise ValueError(f"Invalid value for duplicates_fun: {duplicates_fun}") + +columns = ['chr', 'start', 'end', 'name', 'count', 'strand'] +dfs = [pd.read_csv(bed, sep='\t', header=None, names=columns) for bed in "${beds}".split()] +df = pd.concat(dfs) + +df['tool_count'] = 1 +df = df.groupby(['chr', 'start', 'end', 'strand', 'name']).agg({'count': duplicates_fun, + 'tool_count': 'sum'}).reset_index() +df = df[df['tool_count'] >= int("${tool_filter}")] + +df = df[columns] +df.to_csv("${meta.id}.merged.bed", sep='\t', index=False, header=False) + +# Versions + +versions = { + "${task.process}": { + "python": platform.python_version(), + "pandas": pd.__version__ + } +} + +with open("versions.yml", "w") as f: + f.write(format_yaml_like(versions)) From 4a49a485db7410736f0d3ba6697c7c355859a38d Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 15:34:32 +0200 Subject: [PATCH 284/491] Remove custom DESeq2 module --- bin/ensembl_database_map.txt | 18 ------ .../deseq2/differential_expression/main.nf | 55 ------------------- 2 files changed, 73 deletions(-) delete mode 100755 bin/ensembl_database_map.txt delete mode 100644 modules/local/deseq2/differential_expression/main.nf diff --git a/bin/ensembl_database_map.txt b/bin/ensembl_database_map.txt deleted file mode 100755 index 86e6bb55..00000000 --- a/bin/ensembl_database_map.txt +++ /dev/null @@ -1,18 +0,0 @@ -species command -cel useMart(biomart = "ensembl", dataset = "celegans_gene_ensembl", host="https://www.ensembl.org", archive=FALSE) -hsa useMart(biomart = "ensembl", dataset = "hsapiens_gene_ensembl", host="https://www.ensembl.org", archive=FALSE) -mmu useMart(biomart = "ensembl", dataset = "mmusculus_gene_ensembl", host="https://www.ensembl.org", archive=FALSE) -ath useMart(biomart = "plants_mart", dataset = "athaliana_eg_gene", host="plants.ensembl.org", archive=FALSE) -bta useMart(biomart = "ensembl", dataset = "btaurus_gene_ensembl", host="https://www.ensembl.org", archive=FALSE) -cfa useMart(biomart = "ensembl", dataset = "clfamiliaris_gene_ensembl", host="https://www.ensembl.org", archive=FALSE) -dre useMart(biomart = "ensembl", dataset = "drerio_gene_ensembl", host="https://www.ensembl.org", archive=FALSE) -dme useMart(biomart = "ensembl", dataset = "dmelanogaster_gene_ensembl", host="https://www.ensembl.org", archive=FALSE) -eca useMart(biomart = "ensembl", dataset = "ecaballus_gene_ensembl", host="https://www.ensembl.org", archive=FALSE) -gga useMart(biomart = "ensembl", dataset = "ggallus_gene_ensembl", host="https://www.ensembl.org", archive=FALSE) -osa useMart(biomart = "plants_mart", dataset = "osativa_eg_gene", host="plants.ensembl.org", archive=FALSE) -ptr useMart(biomart = "ensembl", dataset = "ptroglodytes_gene_ensembl", host="https://www.ensembl.org", archive=FALSE) -rno useMart(biomart = "ensembl", dataset = "rnorvegicus_gene_ensembl", host="https://www.ensembl.org", archive=FALSE) -sbi useMart(biomart = "plants_mart", dataset = "sbicolor_eg_gene", host="plants.ensembl.org", archive=FALSE) -ssc useMart(biomart = "ensembl", dataset = "sscrofa_gene_ensembl", host="https://www.ensembl.org", archive=FALSE) -zma useMart(biomart = "plants_mart", dataset = "zmays_eg_gene", host="plants.ensembl.org", archive=FALSE) -mml useMart(biomart = "ensembl", dataset = "mmulatta_gene_ensembl", host="https://www.ensembl.org", archive=FALSE) diff --git a/modules/local/deseq2/differential_expression/main.nf b/modules/local/deseq2/differential_expression/main.nf deleted file mode 100644 index 560df2fc..00000000 --- a/modules/local/deseq2/differential_expression/main.nf +++ /dev/null @@ -1,55 +0,0 @@ -process DESEQ2_DIFFERENTIAL_EXPRESSION { - label 'process_medium' - - conda "r-base=3.6.3 conda-forge::r-argparser=0.6 conda-forge::r-dplyr=1.0.5 conda-forge::r-ggplot2=3.3.3 r-ggpubr=0.4.0 conda-forge::r-gplots=3.1.1 conda-forge::r-pheatmap=1.0.12 r-plyr=1.8.6 r-pvclust=2.2_0 r-rcolorbrewer=1.1_2 conda-forge::r-circlize=0.4.12 bioconductor-biomart=2.42.0 bioconductor-complexheatmap=2.2.0 bioconductor-deseq2=1.26.0 bioconductor-enhancedvolcano=1.4.0 bioconductor-ihw=1.14.0 bioconductor-org.hs.eg.db=3.10.0 bioconductor-pcatools=1.2.0 bioconductor-tximport=1.14.0" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-04b2ef814c9c6ab8c196c3e372521b88160dc260:e0cb4046baee3fd35fdbf883ba8af34e3e8af2e8-0' : - 'biocontainers/mulled-v2-04b2ef814c9c6ab8c196c3e372521b88160dc260:e0cb4046baee3fd35fdbf883ba8af34e3e8af2e8-0' }" - - input: - path(gene_matrix) - tuple val(meta), path(phenotype) - path(circrna_matrix) - val(species) - path(biomart_keys) - - output: - path "circRNA" , emit: circular_results - path "RNA-Seq" , emit: linear_results - path "DESeq2_QC" , emit: deseq2_qc - path "versions.yml", emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - """ - ## prepDE && circRNA counts headers are sorted such that uppercase preceedes lowercase i.e Z before a - ## reformat the phenotype file to match the order of the samples. - head -n 1 $phenotype > header - tail -n +2 $phenotype | LC_COLLATE=C sort > sorted_pheno - cat header sorted_pheno > tmp && rm phenotype.csv && mv tmp phenotype.csv - - DEA.R $gene_matrix $phenotype $circrna_matrix $species ensembl_database_map.txt - mv boxplots/ circRNA/ - mv *.RData DESeq2_QC/ - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - r-base: \$(echo \$(R --version 2>&1) | sed 's/^.*R version //; s/ .*\$//') - argparser: \$(Rscript -e "library(argparser); cat(as.character(packageVersion('argparser')))") - biomart: \$(Rscript -e "library(biomaRt); cat(as.character(packageVersion('biomaRt')))") - deseq2: \$(Rscript -e "library(DESeq2); cat(as.character(packageVersion('DESeq2')))") - dplyr: \$(Rscript -e "library(dplyr); cat(as.character(packageVersion('dplyr')))") - enhancedvolcano: \$(Rscript -e "library(EnhancedVolcano); cat(as.character(packageVersion('EnhancedVolcano')))") - gplots: \$(Rscript -e "library(gplots); cat(as.character(packageVersion('gplots')))") - ggplot2: \$(Rscript -e "library(ggplot2); cat(as.character(packageVersion('ggplot2')))") - ggpubr: \$(Rscript -e "library(ggpubr); cat(as.character(packageVersion('ggpubr')))") - ihw: \$(Rscript -e "library(IHW); cat(as.character(packageVersion('IHW')))") - pvclust: \$(Rscript -e "library(pvclust); cat(as.character(packageVersion('pvclust')))") - pcatools: \$(Rscript -e "library(PCAtools); cat(as.character(packageVersion('PCAtools')))") - pheatmap: \$(Rscript -e "library(pheatmap); cat(as.character(packageVersion('pheatmap')))") - rcolorbrewer: \$(Rscript -e "library(RColorBrewer); cat(as.character(packageVersion('RColorBrewer')))") - END_VERSIONS - """ -} From ec9198bf6bfd0d99c2020150059524b5e7b7ad85 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 15:34:44 +0200 Subject: [PATCH 285/491] Remove DIFFERENTIAL_EXPRESSION traces --- workflows/circrna/main.nf | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 18021678..be782faa 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -194,26 +194,6 @@ workflow CIRCRNA { ) /* - // - // 5. Differential expression tests - // - - ch_ensembl_database_map = params.module.contains('differential_expression') ? Channel.fromPath("${projectDir}/bin/ensembl_database_map.txt") : Channel.empty() - - DIFFERENTIAL_EXPRESSION( - FASTQC_TRIMGALORE.out.reads, - ch_gtf, - ch_fasta, - hisat2_index, - PREPARE_GENOME.out.splice_sites, - ch_phenotype, - CIRCRNA_DISCOVERY.out.counts_bed, - CIRCRNA_DISCOVERY.out.counts_tsv, - ch_species, - ch_ensembl_database_map, - params.exon_boundary - ) - ch_versions = ch_versions.mix(DIFFERENTIAL_EXPRESSION.out.versions) ch_multiqc_files = ch_multiqc_files.mix(DIFFERENTIAL_EXPRESSION.out.reports) */ From 344104858e0120a61a0a6b3058f560f8144e05f0 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 15:46:26 +0200 Subject: [PATCH 286/491] Remove unwanted biotypes --- bin/unwanted_biotypes.txt | 55 --------------------------------------- 1 file changed, 55 deletions(-) delete mode 100755 bin/unwanted_biotypes.txt diff --git a/bin/unwanted_biotypes.txt b/bin/unwanted_biotypes.txt deleted file mode 100755 index ef5a6b2b..00000000 --- a/bin/unwanted_biotypes.txt +++ /dev/null @@ -1,55 +0,0 @@ -IG_C_gene -IG_D_gene -IG_J_gene -IG_LV_gene -IG_V_gene -TR_C_gene -TR_J_gene -TR_V_gene -TR_D_gene -IG_pseudogene -IG_C_pseudogene -IG_J_pseudogene -IG_V_pseudogene -TR_V_pseudogene -TR_J_pseudogene -Mt_rRNA -Mt_tRNA -miRNA -misc_RNA -rRNA -scRNA -snRNA -snoRNA -ribozyme -sRNA -scaRNA -TEC -Mt_tRNA_pseudogene -tRNA_pseudogene -snoRNA_pseudogene -snRNA_pseudogene -scRNA_pseudogene -rRNA_pseudogene -misc_RNA_pseudogene -miRNA_pseudogene -vaultRNA/vault_RNA -disrupted_domain -macro_lncRNA -artifact -unitary_pseudogene -GL000009.2 -GL000194.1 -GL000195.1 -GL000205.2 -GL000213.1 -GL000218.1 -GL000219.1 -KI270711.1 -KI270713.1 -KI270721.1 -KI270726.1 -KI270727.1 -KI270728.1 -KI270731.1 -KI270734.1 From abd9dcd8de435ef2b47e74965431d2f979fd4da2 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 16:04:57 +0200 Subject: [PATCH 287/491] Fix linting problems --- conf/modules.config | 85 ------------------------- subworkflows/local/statistical_tests.nf | 7 +- workflows/circrna/main.nf | 6 +- 3 files changed, 7 insertions(+), 91 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 569cedf4..6752d858 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -689,89 +689,4 @@ process { pattern: "*.txt" ] } - - // DIFF EXP - - withName: HISAT2_ALIGN { - ext.when = { params.module.split(',').contains('differential_expression') } - ext.args = ["", - "--dta", - "--no-spliced-alignment" - ].join(' ').trim() - publishDir = [ - path: { "${params.outdir}/differential_expression/intermediates/hisat2/" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates, - ] - } - - withName: SAMTOOLS_SORT { - ext.when = { params.module.split(',').contains('differential_expression') } - ext.prefix = { "${meta.id}.sorted" } - publishDir = [ - path: { "${params.outdir}/differential_expression/intermediates/hisat2/" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates, - pattern: "*.bam" - ] - } - - withName: STRINGTIE_STRINGTIE { - ext.when = { params.module.split(',').contains('differential_expression') } - ext.args = "-e" - publishDir = [ - path: { "${params.outdir}/differential_expression/intermediates/stringtie/" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates - ] - } - - withName: STRINGTIE_PREPDE { - ext.when = { params.module.split(',').contains('differential_expression') } - publishDir = [ - path: { "${params.outdir}/differential_expression/RNA-Seq/" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates - ] - } - - withName: DESEQ2_DIFFERENTIAL_EXPRESSION { - ext.when = { params.module.split(',').contains('differential_expression') } - publishDir = [ - path: { "${params.outdir}/differential_expression/" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - withName: PARENT_GENE { - ext.when = { params.module.split(',').contains('differential_expression') } - publishDir = [ - path: { "${params.outdir}/differential_expression/circular_linear_ratio_test" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - withName: PREPARE_CLR_TEST { - ext.when = { params.module.split(',').contains('differential_expression') } - publishDir = [ - path: { "${params.outdir}/differential_expression/circular_linear_ratio_test" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - withName: CIRCTEST { - ext.when = { params.module.split(',').contains('differential_expression') } - publishDir = [ - path: { "${params.outdir}/differential_expression/circular_linear_ratio_test" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } } diff --git a/subworkflows/local/statistical_tests.nf b/subworkflows/local/statistical_tests.nf index 3c977f9a..332f9ac7 100644 --- a/subworkflows/local/statistical_tests.nf +++ b/subworkflows/local/statistical_tests.nf @@ -7,7 +7,7 @@ workflow STATISTICAL_TESTS { ch_gene_counts ch_circ_counts ch_phenotype - + main: ch_versions = Channel.empty() @@ -17,5 +17,8 @@ workflow STATISTICAL_TESTS { CIRCTEST_CIRCTEST(CIRCTEST_PREPARE.out.circ_counts, CIRCTEST_PREPARE.out.gene_counts, ch_phenotype) + ch_versions = ch_versions.mix(CIRCTEST_CIRCTEST.out.versions) -} \ No newline at end of file + emit: + versions = ch_versions +} diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index be782faa..0b74ace1 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -193,10 +193,8 @@ workflow CIRCRNA { ch_phenotype ) - /* - ch_versions = ch_versions.mix(DIFFERENTIAL_EXPRESSION.out.versions) - ch_multiqc_files = ch_multiqc_files.mix(DIFFERENTIAL_EXPRESSION.out.reports) - */ + ch_versions = ch_versions.mix(STATISTICAL_TESTS.out.versions) + // // Collate and save software versions From ffbada60f3d7cc87d14e7a608c678c32be22b601 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 11 Jun 2024 16:07:16 +0200 Subject: [PATCH 288/491] Prettier --- modules/local/circtest/prepare/environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/circtest/prepare/environment.yml b/modules/local/circtest/prepare/environment.yml index 602dc60d..02becc7c 100644 --- a/modules/local/circtest/prepare/environment.yml +++ b/modules/local/circtest/prepare/environment.yml @@ -2,4 +2,4 @@ name: circtest_prepare channels: - conda-forge dependencies: - - conda-forge::r-base=4.2.1 \ No newline at end of file + - conda-forge::r-base=4.2.1 From 2d259c38ff51689fafca50fc3ed5706bcd10dd6e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Wed, 12 Jun 2024 09:18:16 +0200 Subject: [PATCH 289/491] Remove traces of differential_expression in docs --- README.md | 5 +- docs/output.md | 184 ++----------------------------------------------- docs/usage.md | 47 ++----------- 3 files changed, 13 insertions(+), 223 deletions(-) diff --git a/README.md b/README.md index fe77e560..b289dbf1 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ ## Introduction -**nf-core/circrna** is a bioinformatics best-practice analysis pipeline for Quantification, miRNA target prediction and differential expression analysis of circular RNAs. +**nf-core/circrna** is a bioinformatics best-practice analysis pipeline for BSJ detection, quantification, annotation and miRNA target prediction of circular RNAs. The pipeline is built using [Nextflow](https://www.nextflow.io), a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It uses Docker/Singularity containers making installation trivial and results highly reproducible. The [Nextflow DSL2](https://www.nextflow.io/docs/latest/dsl2.html) implementation of this pipeline uses one container per process which makes it much easier to maintain and update software dependencies. Where possible, these processes have been submitted to and installed from [nf-core/modules](https://github.com/nf-core/modules) in order to make them available to all nf-core pipelines, and to everyone within the Nextflow community! @@ -50,7 +50,6 @@ On release, automated continuous integration tests run the pipeline on a full-si - [`miRanda`](http://cbio.mskcc.org/miRNA2003/miranda.html) - [`TargetScan`](http://www.targetscan.org/cgi-bin/targetscan/data_download.vert72.cgi) - Filter results, miRNAs must be called by both tools -- Differential expression analysis [`DESeq2`](https://bioconductor.org/packages/release/bioc/html/DESeq2.html) - Circular - Linear ratio tests ['CircTest'](https://github.com/dieterich-lab/CircTest) diff --git a/nextflow_schema.json b/nextflow_schema.json index 2196197e..9d814605 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -37,7 +37,7 @@ "schema": "assets/schema_phenotype.json", "mimetype": "text/csv", "pattern": "^\\S+\\.csv$", - "description": "Phenotype CSV file specifying the experimental design.", + "description": "Phenotype CSV file specifying the experimental design. If provided, the pipeline will run CIRCTEST.", "help_text": "There are two rules for providing the phenotype CSV file. 1) The 'sample' column must match the sample sheets 'sample' column. 2) The response variable containing the phenotype of primary interest in the experiment must have the column name condition. All other columns included in the file are controlled for in the `DESeq2` design. \n\n| sample \t| condition \t| replicate \t|\n|-----------\t|-----------\t|-----------\t|\n| control_1 \t| ctr \t| 1 \t|\n| control_2 \t| ctr \t| 2 \t|\n| control_3 \t| ctr \t| 3 \t|\n| treated_1 \t| trt \t| 1 \t|\n| treated_2 \t| trt \t| 2 \t|\n| treated_3 \t| trt \t| 3 \t|\n\nThe above phenotype file will identify differentially expressed circRNAs/mRNAs between control and treatment cells, whilst controlling for the effect of variation between replicates: ` ~ replicates + condition`", "fa_icon": "fas fa-file-csv" } From 9f9e967c20c406b9ae59479ccded73e684e5b199 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 14 Jun 2024 13:30:21 +0200 Subject: [PATCH 299/491] Update documentation for enabling miRNA prediction --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 722e9df3..2d3f427b 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ On release, automated continuous integration tests run the pipeline on a full-si - Export mature spliced length as FASTA file - Annotate parent gene, underlying transcripts. - circRNA count matrix -- miRNA target prediction +- miRNA target prediction (only if the `mature` parameter is provided) - [`miRanda`](http://cbio.mskcc.org/miRNA2003/miranda.html) - [`TargetScan`](http://www.targetscan.org/cgi-bin/targetscan/data_download.vert72.cgi) - Filter results, miRNAs must be called by both tools From a0fb084fd4accde02bf9753bec9033ee5c332b3c Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 14 Jun 2024 14:31:57 +0200 Subject: [PATCH 300/491] Update README --- README.md | 57 ++++++++++++++------------------------ docs/images/metro-map.png | Bin 0 -> 289348 bytes 2 files changed, 21 insertions(+), 36 deletions(-) create mode 100644 docs/images/metro-map.png diff --git a/README.md b/README.md index 2d3f427b..b769e066 100644 --- a/README.md +++ b/README.md @@ -30,64 +30,49 @@ On release, automated continuous integration tests run the pipeline on a full-si ## Pipeline summary +![Metro Map](./docs/images/metro-map.png) + - Raw read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/)) - Adapter trimming ([`Trim Galore!`](https://www.bioinformatics.babraham.ac.uk/projects/trim_galore/)) -- MultiQC report [`MultiQC`](http://multiqc.info/) -- circRNA quantification -- [`CIRIquant`](https://github.com/Kevinzjy/CIRIquant) -- [`STAR 2-Pass mode`](https://github.com/alexdobin/STAR) - - [`CIRCexplorer2`](https://circexplorer2.readthedocs.io/en/latest/) - - [`circRNA finder`](https://github.com/orzechoj/circRNA_finder) - - [`DCC`](https://github.com/dieterich-lab/DCC) -- [`find circ`](https://github.com/marvin-jens/find_circ) -- [`MapSplice`](http://www.netlab.uky.edu/p/bioinfo/MapSplice2) -- [`Segemehl`](https://www.bioinf.uni-leipzig.de/Software/segemehl/) +- BSJ detection + - [`CIRIquant`](https://github.com/Kevinzjy/CIRIquant) + - [`STAR 2-Pass mode`](https://github.com/alexdobin/STAR) + - [`CIRCexplorer2`](https://circexplorer2.readthedocs.io/en/latest/) + - [`circRNA finder`](https://github.com/orzechoj/circRNA_finder) + - [`DCC`](https://github.com/dieterich-lab/DCC) + - [`find circ`](https://github.com/marvin-jens/find_circ) + - [`MapSplice`](http://www.netlab.uky.edu/p/bioinfo/MapSplice2) + - [`Segemehl`](https://www.bioinf.uni-leipzig.de/Software/segemehl/) - circRNA annotation -- Export mature spliced length as FASTA file -- Annotate parent gene, underlying transcripts. -- circRNA count matrix -- miRNA target prediction (only if the `mature` parameter is provided) +- Extract circRNA sequences and build circular transcriptome +- Merge circular transcriptome with linear transcriptome derived from provided GTF +- Quantification of combined circular and linear transcriptome + - [`psirc-quant`](https://github.com/Christina-hshi/psirc) +- miRNA binding affinity analysis (only if the `mature` parameter is provided) - [`miRanda`](http://cbio.mskcc.org/miRNA2003/miranda.html) - [`TargetScan`](http://www.targetscan.org/cgi-bin/targetscan/data_download.vert72.cgi) - - Filter results, miRNAs must be called by both tools -- Circular - circRNA-Host ratio tests ['CircTest'](https://github.com/dieterich-lab/CircTest) (only if the `phenotype` parameter is provided) - - +- Statistical tests (only if the `phenotype` parameter is provided) + - [`CircTest`](https://github.com/dieterich-lab/CircTest) +- MultiQC report [`MultiQC`](http://multiqc.info/) ## Usage > [!NOTE] > If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data. - - Now, you can run the pipeline using: -```bash -nextflow run nf-core/circrna \ - --input samplesheet.csv \ - --outdir \ - --genome GRCh37 \ - -profile \ - --tool 'ciriquant' \ - --bsj_reads 2 -``` - ```bash nextflow run nf-core/circrna \ -profile \ diff --git a/docs/images/metro-map.png b/docs/images/metro-map.png new file mode 100644 index 0000000000000000000000000000000000000000..2f4f8af8970272b3404fdd5684c0e563b0e2289b GIT binary patch literal 289348 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
      ^2Z%SazwnMa17 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 Ula*hUiUEh2$%Qj{r(L7}1nR3bU;qFB literal 0 HcmV?d00001 From 7fb28add1edffa3595e8bb607264b6a7951de0d4 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 14 Jun 2024 14:51:14 +0200 Subject: [PATCH 301/491] Update usage documentation to follow rnaseq example --- README.md | 3 +- assets/samplesheet.csv | 6 ++-- docs/usage.md | 66 +++++++++++++++++++++++++++--------------- 3 files changed, 46 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index b769e066..2c75af9d 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,7 @@ On release, automated continuous integration tests run the pipeline on a full-si First, prepare a samplesheet with your input data that looks as follows: -`samplesheet.csv`: -```csv +```csv title="samplesheet.csv" sample,fastq_1,fastq_2 CONTROL,CONTROL_R1.fastq.gz,CONTROL_R2.fastq.gz TREATMENT,TREATMENT_R1.fastq.gz,TREATMENT_R2.fastq.gz diff --git a/assets/samplesheet.csv b/assets/samplesheet.csv index 5f653ab7..8d222a80 100644 --- a/assets/samplesheet.csv +++ b/assets/samplesheet.csv @@ -1,3 +1,3 @@ -sample,fastq_1,fastq_2 -SAMPLE_PAIRED_END,/path/to/fastq/files/AEG588A1_S1_L002_R1_001.fastq.gz,/path/to/fastq/files/AEG588A1_S1_L002_R2_001.fastq.gz -SAMPLE_SINGLE_END,/path/to/fastq/files/AEG588A4_S4_L003_R1_001.fastq.gz, +sample,fastq_1,fastq_2,strandedness +SAMPLE_PAIRED_END,/path/to/fastq/files/AEG588A1_S1_L002_R1_001.fastq.gz,/path/to/fastq/files/AEG588A1_S1_L002_R2_001.fastq.gz,forward +SAMPLE_SINGLE_END,/path/to/fastq/files/AEG588A4_S4_L003_R1_001.fastq.gz,,auto diff --git a/docs/usage.md b/docs/usage.md index c3cae0ba..0db384c2 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,45 +1,54 @@ # nf-core/circrna: Usage -It is recommended that first time users run `nf-core/circrna` with the minimal test dataset either locally or on a HPC, referring to the [output documentation](https://nf-co.re/circrna/dev/output) before running a full analysis. +## :warning: Please read this documentation on the nf-core website: [https://nf-co.re/rnaseq/usage](https://nf-co.re/rnaseq/usage) + +> _Documentation of pipeline parameters is generated automatically from the pipeline schema and can no longer be found in markdown files._ + +## Pipeline parameters + +Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration except for parameters; see [docs](https://nf-co.re/usage/configuration#custom-configuration-files). + +## Samplesheet input +You will need to create a samplesheet with information about the samples you would like to analyse before running the pipeline. Use this parameter to specify its location. It has to be a comma-separated file with 4 columns, and a header row as shown in the examples below. ```bash -nextflow run nf-core/circrna -profile test, +--input '[path to samplesheet file]' ``` -# Running the pipeline +### Multiple runs of the same sample -The `sample` identifiers have to be the same when you have re-sequenced the same sample more than once e.g. to increase sequencing depth. The pipeline will concatenate the raw reads before performing any downstream analysis. Below is an example for the same sample sequenced across 3 lanes: +The `sample` identifiers have to be the same when you have re-sequenced the same sample more than once e.g. to increase sequencing depth. The pipeline will concatenate the raw reads before performing any downstream analysis. Below is an example for the same sample sequenced across 3 lanes. If you set the strandedness value to `auto` the pipeline will use the tool-defaults throughout the pipeline. ```csv title="samplesheet.csv" -sample,fastq_1,fastq_2 -CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz -CONTROL_REP1,AEG588A1_S1_L003_R1_001.fastq.gz,AEG588A1_S1_L003_R2_001.fastq.gz -CONTROL_REP1,AEG588A1_S1_L004_R1_001.fastq.gz,AEG588A1_S1_L004_R2_001.fastq.gz +sample,fastq_1,fastq_2,strandedness +CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz,auto +CONTROL_REP1,AEG588A1_S1_L003_R1_001.fastq.gz,AEG588A1_S1_L003_R2_001.fastq.gz,auto +CONTROL_REP1,AEG588A1_S1_L004_R1_001.fastq.gz,AEG588A1_S1_L004_R2_001.fastq.gz,auto ``` ### Full samplesheet -The pipeline will auto-detect whether a sample is single- or paired-end using the information provided in the samplesheet. The samplesheet can have as many columns as you desire, however, there is a strict requirement for the first 3 columns to match those defined in the table below. +The pipeline will auto-detect whether a sample is single- or paired-end using the information provided in the samplesheet. The samplesheet can have as many columns as you desire, however, there is a strict requirement for the first 4 columns to match those defined in the table below. A final samplesheet file consisting of both single- and paired-end data may look something like the one below. This is for 6 samples, where `TREATMENT_REP3` has been sequenced twice. ```csv title="samplesheet.csv" sample,fastq_1,fastq_2,strandedness -CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz,auto -CONTROL_REP2,AEG588A2_S2_L002_R1_001.fastq.gz,AEG588A2_S2_L002_R2_001.fastq.gz, -CONTROL_REP3,AEG588A3_S3_L002_R1_001.fastq.gz,AEG588A3_S3_L002_R2_001.fastq.gz, -TREATMENT_REP1,AEG588A4_S4_L003_R1_001.fastq.gz,,forward +CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz,forward +CONTROL_REP2,AEG588A2_S2_L002_R1_001.fastq.gz,AEG588A2_S2_L002_R2_001.fastq.gz,forward +CONTROL_REP3,AEG588A3_S3_L002_R1_001.fastq.gz,AEG588A3_S3_L002_R2_001.fastq.gz,forward +TREATMENT_REP1,AEG588A4_S4_L003_R1_001.fastq.gz,,reverse TREATMENT_REP2,AEG588A5_S5_L003_R1_001.fastq.gz,,reverse -TREATMENT_REP3,AEG588A6_S6_L003_R1_001.fastq.gz,,unstranded -TREATMENT_REP3,AEG588A6_S6_L004_R1_001.fastq.gz,,unstranded +TREATMENT_REP3,AEG588A6_S6_L003_R1_001.fastq.gz,,reverse +TREATMENT_REP3,AEG588A6_S6_L004_R1_001.fastq.gz,,reverse ``` -| Column | Description | -| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `sample` | Custom sample name. This entry will be identical for multiple sequencing libraries/runs from the same sample. Spaces in sample names are automatically converted to underscores (`_`). | -| `fastq_1` | Full path to FastQ file for Illumina short reads 1. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | -| `fastq_2` | Full path to FastQ file for Illumina short reads 2. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | -| `strandedness` | Strandedness of the library. Options are `auto`, `unstranded`, `forward`, `reverse`. Default is `auto`. Make sure to use the same strandedness for each library/run of the same sample. | +| Column | Description | +| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `sample` | Custom sample name. This entry will be identical for multiple sequencing libraries/runs from the same sample. Spaces in sample names are automatically converted to underscores (`_`). | +| `fastq_1` | Full path to FastQ file for Illumina short reads 1. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | +| `fastq_2` | Full path to FastQ file for Illumina short reads 2. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | +| `strandedness` | Sample strand-specificity. Must be one of `unstranded`, `forward`, `reverse` or `auto`. | An [example samplesheet](../assets/samplesheet.csv) has been provided with the pipeline. @@ -48,9 +57,19 @@ An [example samplesheet](../assets/samplesheet.csv) has been provided with the p The typical command for running the pipeline is as follows: ```bash -nextflow run nf-core/circrna --input ./samplesheet.csv --outdir ./results --genome GRCh37 -profile docker +nextflow run \ + nf-core/circrna \ + --input \ + --outdir \ + --gtf \ + --fasta \ + --igenomes_ignore \ + --genome null \ + -profile docker ``` +> **NB:** Loading iGenomes configuration remains the default for reasons of consistency with other workflows, but should be disabled when not using iGenomes, applying the recommended usage above. + This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. Note that the pipeline will create the following files in your working directory: @@ -115,7 +134,7 @@ If you wish to share such profile (such as upload as supplementary material for Input data can be passed to `nf-core/circrna` using a CSV file containing the absolute paths to input fastq files. -The headers of the CSV file must be: `sample,fastq_1,fastq_2`. +The header of the CSV file must at least contain the `sample` and `fastq_1` columns. The `fastq_2` column is optional and only required for paired-end data. With an additional `strandness` column, the user can specify the strandedness of the library. The `sample` column should contain a unique identifier for each sample, and the `fastq_1` and `fastq_2` columns should contain the paths to the input fastq files. Valid examples for fastq input data in a CSV file is given below: @@ -128,7 +147,6 @@ Valid examples for fastq input data in a CSV file is given below: | TCGA-EJ-5518-01A | /data/afbbc370-5970-43d3-b9f8-f40f8e649bb6_gdc_realn_rehead_R1.fastq.gz | /data/afbbc370-5970-43d3-b9f8-f40f8e649bb6_gdc_realn_rehead_R2.fastq.gz | | TCGA-KK-A8I4-01A | /data/81254692-ee1e-4985-bd0a-4929eed4c620_gdc_realn_rehead_R1.fastq.gz | /data/81254692-ee1e-4985-bd0a-4929eed4c620_gdc_realn_rehead_R2.fastq.gz | -> Do not leave any cell empty in the CSV file. ## Phenotype file From 1d6668878587c26d21d9751fc0f3929f9ebd602b Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 14 Jun 2024 14:55:57 +0200 Subject: [PATCH 302/491] Update nextflow schema order --- nextflow_schema.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index 9d814605..e8229303 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -543,19 +543,19 @@ }, "allOf": [ { - "$ref": "#/definitions/alignment_options" + "$ref": "#/definitions/input_output_options" }, { - "$ref": "#/definitions/input_output_options" + "$ref": "#/definitions/reference_genome_options" }, { - "$ref": "#/definitions/discovery_options" + "$ref": "#/definitions/read_trimming_options" }, { - "$ref": "#/definitions/reference_genome_options" + "$ref": "#/definitions/alignment_options" }, { - "$ref": "#/definitions/read_trimming_options" + "$ref": "#/definitions/discovery_options" }, { "$ref": "#/definitions/institutional_config_options" From ee159a2ed61b62905e123cd6799d69f13ac724f8 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 14 Jun 2024 15:04:09 +0200 Subject: [PATCH 303/491] Update ouput docs --- docs/output.md | 53 +++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/docs/output.md b/docs/output.md index f20ae72d..aef45d17 100644 --- a/docs/output.md +++ b/docs/output.md @@ -2,45 +2,46 @@ ## Introduction -This documentation describes the output of `nf-core/circrna` for the test dataset which runs all modules in the workflow. +:::warning +This page has not been updated for a long time and might not align with the current pipeline output. We are working on updating it. +If you have questions regarding the pipeline output, feel free to reach out in the [nf-core slack](https://nfcore.slack.com/channels/circrna) channel. +::: -A full run of the workflow will produce the following directory output structure: +This document describes the output produced by the pipeline. Most of the plots are taken from the MultiQC report generated from the [full-sized test dataset](https://github.com/nf-core/test-datasets/tree/circrna) for the pipeline using a command similar to the one below: -```console -|-- results/ - |-- circrna_discovery - |-- mirna_prediction - |-- multiqc - |-- pipeline_info - |-- quality_control - |-- references +```bash +nextflow run nf-core/circrna -profile test_full, ``` +The directories listed below will be created in the results directory after the pipeline has finished. All paths are relative to the top-level results directory. + ## Pipeline Overview The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes data using the following steps: - Raw read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/)) - Adapter trimming ([`Trim Galore!`](https://www.bioinformatics.babraham.ac.uk/projects/trim_galore/)) -- MultiQC report [`MultiQC`](http://multiqc.info/) -- circRNA quantification -- [`CIRIquant`](https://github.com/Kevinzjy/CIRIquant) -- [`STAR 2-Pass mode`](https://github.com/alexdobin/STAR) - - [`CIRCexplorer2`](https://circexplorer2.readthedocs.io/en/latest/) - - [`circRNA finder`](https://github.com/orzechoj/circRNA_finder) - - [`DCC`](https://github.com/dieterich-lab/DCC) -- [`find circ`](https://github.com/marvin-jens/find_circ) -- [`MapSplice`](http://www.netlab.uky.edu/p/bioinfo/MapSplice2) -- [`Segemehl`](https://www.bioinf.uni-leipzig.de/Software/segemehl/) +- BSJ detection + - [`CIRIquant`](https://github.com/Kevinzjy/CIRIquant) + - [`STAR 2-Pass mode`](https://github.com/alexdobin/STAR) + - [`CIRCexplorer2`](https://circexplorer2.readthedocs.io/en/latest/) + - [`circRNA finder`](https://github.com/orzechoj/circRNA_finder) + - [`DCC`](https://github.com/dieterich-lab/DCC) + - [`find circ`](https://github.com/marvin-jens/find_circ) + - [`MapSplice`](http://www.netlab.uky.edu/p/bioinfo/MapSplice2) + - [`Segemehl`](https://www.bioinf.uni-leipzig.de/Software/segemehl/) - circRNA annotation -- Export mature spliced length as FASTA file -- Annotate parent gene, underlying transcripts. -- circRNA count matrix -- miRNA target prediction +- Extract circRNA sequences and build circular transcriptome +- Merge circular transcriptome with linear transcriptome derived from provided GTF +- Quantification of combined circular and linear transcriptome + - [`psirc-quant`](https://github.com/Christina-hshi/psirc) +- miRNA binding affinity analysis (only if the `mature` parameter is provided) - [`miRanda`](http://cbio.mskcc.org/miRNA2003/miranda.html) - [`TargetScan`](http://www.targetscan.org/cgi-bin/targetscan/data_download.vert72.cgi) - - Filter results, miRNAs must be called by both tools -- Circular - Linear ratio tests ['CircTest'](https://github.com/dieterich-lab/CircTest) +- Statistical tests (only if the `phenotype` parameter is provided) + - [`CircTest`](https://github.com/dieterich-lab/CircTest) +- MultiQC report [`MultiQC`](http://multiqc.info/) + ## Quality Control From ab74eb5e56eadc64ed59f003f7b88d99bf4c0903 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 14 Jun 2024 15:05:40 +0200 Subject: [PATCH 304/491] Prettier --- README.md | 2 +- docs/output.md | 1 - docs/usage.md | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2c75af9d..e3d02d62 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,6 @@ On release, automated continuous integration tests run the pipeline on a full-si > [!NOTE] > If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data. - First, prepare a samplesheet with your input data that looks as follows: ```csv title="samplesheet.csv" @@ -68,6 +67,7 @@ sample,fastq_1,fastq_2 CONTROL,CONTROL_R1.fastq.gz,CONTROL_R2.fastq.gz TREATMENT,TREATMENT_R1.fastq.gz,TREATMENT_R2.fastq.gz ``` + Each row represents a fastq file (single-end) or a pair of fastq files (paired end). Now, you can run the pipeline using: diff --git a/docs/output.md b/docs/output.md index aef45d17..fdd9bf48 100644 --- a/docs/output.md +++ b/docs/output.md @@ -42,7 +42,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d - [`CircTest`](https://github.com/dieterich-lab/CircTest) - MultiQC report [`MultiQC`](http://multiqc.info/) - ## Quality Control ### FastQC diff --git a/docs/usage.md b/docs/usage.md index 0db384c2..137fb841 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -9,6 +9,7 @@ Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration except for parameters; see [docs](https://nf-co.re/usage/configuration#custom-configuration-files). ## Samplesheet input + You will need to create a samplesheet with information about the samples you would like to analyse before running the pipeline. Use this parameter to specify its location. It has to be a comma-separated file with 4 columns, and a header row as shown in the examples below. ```bash @@ -147,7 +148,6 @@ Valid examples for fastq input data in a CSV file is given below: | TCGA-EJ-5518-01A | /data/afbbc370-5970-43d3-b9f8-f40f8e649bb6_gdc_realn_rehead_R1.fastq.gz | /data/afbbc370-5970-43d3-b9f8-f40f8e649bb6_gdc_realn_rehead_R2.fastq.gz | | TCGA-KK-A8I4-01A | /data/81254692-ee1e-4985-bd0a-4929eed4c620_gdc_realn_rehead_R1.fastq.gz | /data/81254692-ee1e-4985-bd0a-4929eed4c620_gdc_realn_rehead_R2.fastq.gz | - ## Phenotype file The CSV file provided via the `phenotype` parameter can be used to provide additional metadata about the samples in the input CSV file. If provided, it needs to at least contain a column called `sample` which corresponds to the `sample` column in the input CSV file and a column called `condition`. The `condition` column will be used to group samples for the [CircTest](https://github.com/dieterich-lab/CircTest) functionality. All metadata columns will be included in the result `SummarizedExperiment` RDS file. From b8474a0fb3e9d296c0bda3e35a953b8d279fc696 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 17 Jun 2024 19:27:35 +0200 Subject: [PATCH 305/491] Add annotations parameter and pass it to the according position --- assets/schema_annotation.json | 32 ++++++++++++++++++++++ main.nf | 2 ++ nextflow.config | 1 + nextflow_schema.json | 11 ++++++++ subworkflows/local/circrna_discovery.nf | 3 +- subworkflows/local/discovery/annotation.nf | 3 ++ workflows/circrna/main.nf | 2 ++ 7 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 assets/schema_annotation.json diff --git a/assets/schema_annotation.json b/assets/schema_annotation.json new file mode 100644 index 00000000..fa0b63db --- /dev/null +++ b/assets/schema_annotation.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://raw.githubusercontent.com/nf-core/circrna/master/assets/schema_annotation.json", + "title": "nf-core/circrna pipeline - params.annotation schema", + "description": "Schema for the file provided with params.annotation", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "pattern": "^\\S+$", + "errorMessage": "Annotation file name must be provided and cannot contain spaces" + }, + "file": { + "type": "string", + "format": "file-path", + "exists": true, + "pattern": "^\\S+\\.bed$", + "errorMessage": "Annotation file must be provided and must be a BED file" + }, + "min_overlap": { + "type": "number", + "minimum": 0, + "maximum": 1, + "default": 0.9, + "errorMessage": "Minimum overlap must be a number between 0 and 1" + } + }, + "required": ["name", "file"] + } +} diff --git a/main.nf b/main.nf index 7717ffc7..438b11ec 100644 --- a/main.nf +++ b/main.nf @@ -61,6 +61,7 @@ workflow NFCORE_CIRCRNA { ch_mature = params.mature ? Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) : Channel.empty() ch_phenotype = params.phenotype ? Channel.value([[id: "phenotype"], file(params.phenotype, checkIfExists:true)]) : Channel.empty() ch_species = params.phenotype ? Channel.value(params.species_id) : Channel.empty() + ch_annotations = Channel.fromSamplesheet("annotations") CIRCRNA ( ch_samplesheet, @@ -68,6 +69,7 @@ workflow NFCORE_CIRCRNA { ch_fasta, ch_gtf, ch_mature, + ch_annotations, ch_species, ch_versions ) diff --git a/nextflow.config b/nextflow.config index 7fdfaeaa..e2c6308d 100644 --- a/nextflow.config +++ b/nextflow.config @@ -13,6 +13,7 @@ params { input = null outdir = null phenotype = null + annotation = null // workflow options tool = 'circexplorer2' diff --git a/nextflow_schema.json b/nextflow_schema.json index e8229303..c1b06562 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -40,6 +40,17 @@ "description": "Phenotype CSV file specifying the experimental design. If provided, the pipeline will run CIRCTEST.", "help_text": "There are two rules for providing the phenotype CSV file. 1) The 'sample' column must match the sample sheets 'sample' column. 2) The response variable containing the phenotype of primary interest in the experiment must have the column name condition. All other columns included in the file are controlled for in the `DESeq2` design. \n\n| sample \t| condition \t| replicate \t|\n|-----------\t|-----------\t|-----------\t|\n| control_1 \t| ctr \t| 1 \t|\n| control_2 \t| ctr \t| 2 \t|\n| control_3 \t| ctr \t| 3 \t|\n| treated_1 \t| trt \t| 1 \t|\n| treated_2 \t| trt \t| 2 \t|\n| treated_3 \t| trt \t| 3 \t|\n\nThe above phenotype file will identify differentially expressed circRNAs/mRNAs between control and treatment cells, whilst controlling for the effect of variation between replicates: ` ~ replicates + condition`", "fa_icon": "fas fa-file-csv" + }, + "annotation": { + "type": "string", + "format": "file-path", + "exists": true, + "schema": "assets/schema_annotation.json", + "mimetype": "text/csv", + "pattern": "^\\S+\\.csv$", + "description": "Path to a CSV file containing BED files that should be used for annotation.", + "help_text": "The annotation file should be a CSV file with the following columns: `name`, `file` and `min_overlap`. The `name` column should contain a unique identifier for the annotation, the `file` column should contain the path to the BED file and the `min_overlap` column should contain the minimum overlap required for a circRNA to be considered as overlapping with the annotation. The `min_overlap` column is optional and defaults to 0.9 if not provided.", + "fa_icon": "fas fa-file-csv" } } }, diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index a8ae043a..91d6fbcc 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -30,6 +30,7 @@ workflow CIRCRNA_DISCOVERY { chromosomes hisat2_index star_index + ch_annotations bsj_reads tool_filter duplicates_fun @@ -140,7 +141,7 @@ workflow CIRCRNA_DISCOVERY { // ANNOTATION WORKFLOW: // - ANNOTATION( ch_bed_incl_merged, gtf, exon_boundary ) + ANNOTATION( ch_bed_incl_merged, gtf, exon_boundary, ch_annotations ) ch_versions = ch_versions.mix(ANNOTATION.out.versions) // diff --git a/subworkflows/local/discovery/annotation.nf b/subworkflows/local/discovery/annotation.nf index 518260b6..87b2446b 100644 --- a/subworkflows/local/discovery/annotation.nf +++ b/subworkflows/local/discovery/annotation.nf @@ -9,6 +9,7 @@ workflow ANNOTATION { regions gtf exon_boundary + ch_annotations main: ch_versions = Channel.empty() @@ -16,6 +17,8 @@ workflow ANNOTATION { INTERSECT( regions.combine(gtf), [[], []]) ANNOTATE( INTERSECT.out.intersect, exon_boundary ) + ch_annotations.view() + ch_bed_merged = ANNOTATE.out.bed.filter{ meta, bed -> meta.tool == "merged" } ch_gtf_merged = ANNOTATE.out.gtf.filter{ meta, gtf -> meta.tool == "merged" } diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 11783898..6df3470e 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -58,6 +58,7 @@ workflow CIRCRNA { ch_fasta ch_gtf ch_mature + ch_annotations ch_species ch_versions @@ -143,6 +144,7 @@ workflow CIRCRNA { chromosomes, hisat2_index, star_index, + ch_annotations, params.bsj_reads, params.tool_filter, params.duplicates_fun, From 30e28ddbc1bb2ac99ba825b64f905297c187b779 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 17 Jun 2024 19:30:51 +0200 Subject: [PATCH 306/491] Make annotations parameter optional --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 438b11ec..9d50c5f4 100644 --- a/main.nf +++ b/main.nf @@ -61,7 +61,7 @@ workflow NFCORE_CIRCRNA { ch_mature = params.mature ? Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) : Channel.empty() ch_phenotype = params.phenotype ? Channel.value([[id: "phenotype"], file(params.phenotype, checkIfExists:true)]) : Channel.empty() ch_species = params.phenotype ? Channel.value(params.species_id) : Channel.empty() - ch_annotations = Channel.fromSamplesheet("annotations") + ch_annotations = params.annotations ? Channel.fromSamplesheet("annotations") : Channel.empty() CIRCRNA ( ch_samplesheet, From a3f165cb1de9dd43c0409739d710df3cf6fed314 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 17 Jun 2024 19:56:00 +0200 Subject: [PATCH 307/491] Unify annotation naming --- conf/modules.config | 9 --------- main.nf | 4 ++-- subworkflows/local/circrna_discovery.nf | 4 ++-- subworkflows/local/discovery/annotation.nf | 14 +++++++------- workflows/circrna/main.nf | 4 ++-- 5 files changed, 13 insertions(+), 22 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 05169f07..40cfece6 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -562,15 +562,6 @@ process { ext.suffix = {"${meta.tool}.filtered.bed"} } - withName: ANNOTATION { - ext.prefix = { "${meta.id}.${meta.tool}.annotated" } - publishDir = [ - path: { "${params.outdir}/circrna_discovery/${meta.tool}/${meta.id}" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - withName: UPSET_SAMPLES { ext.when = { params.tool.split(',').length > 1 } } diff --git a/main.nf b/main.nf index 9d50c5f4..022b6be8 100644 --- a/main.nf +++ b/main.nf @@ -61,7 +61,7 @@ workflow NFCORE_CIRCRNA { ch_mature = params.mature ? Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) : Channel.empty() ch_phenotype = params.phenotype ? Channel.value([[id: "phenotype"], file(params.phenotype, checkIfExists:true)]) : Channel.empty() ch_species = params.phenotype ? Channel.value(params.species_id) : Channel.empty() - ch_annotations = params.annotations ? Channel.fromSamplesheet("annotations") : Channel.empty() + ch_annotation = params.annotation ? Channel.fromSamplesheet("annotation") : Channel.empty() CIRCRNA ( ch_samplesheet, @@ -69,7 +69,7 @@ workflow NFCORE_CIRCRNA { ch_fasta, ch_gtf, ch_mature, - ch_annotations, + ch_annotation, ch_species, ch_versions ) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 91d6fbcc..2a163ce7 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -30,7 +30,7 @@ workflow CIRCRNA_DISCOVERY { chromosomes hisat2_index star_index - ch_annotations + ch_annotation bsj_reads tool_filter duplicates_fun @@ -141,7 +141,7 @@ workflow CIRCRNA_DISCOVERY { // ANNOTATION WORKFLOW: // - ANNOTATION( ch_bed_incl_merged, gtf, exon_boundary, ch_annotations ) + ANNOTATION( ch_bed_incl_merged, gtf, exon_boundary, ch_annotation ) ch_versions = ch_versions.mix(ANNOTATION.out.versions) // diff --git a/subworkflows/local/discovery/annotation.nf b/subworkflows/local/discovery/annotation.nf index 87b2446b..c9e0dfa8 100644 --- a/subworkflows/local/discovery/annotation.nf +++ b/subworkflows/local/discovery/annotation.nf @@ -1,5 +1,5 @@ include { BEDTOOLS_INTERSECT as INTERSECT } from '../../../modules/nf-core/bedtools/intersect' -include { ANNOTATION as ANNOTATE } from '../../../modules/local/annotation' +include { ANNOTATION as GTF_ANNOTATION } from '../../../modules/local/annotation' include { GNU_SORT as COMBINE_BEDS } from '../../../modules/nf-core/gnu/sort' include { GAWK as REMOVE_SCORE_STRAND } from '../../../modules/nf-core/gawk' include { GNU_SORT as COMBINE_GTFS } from '../../../modules/nf-core/gnu/sort' @@ -9,25 +9,25 @@ workflow ANNOTATION { regions gtf exon_boundary - ch_annotations + ch_annotation main: ch_versions = Channel.empty() INTERSECT( regions.combine(gtf), [[], []]) - ANNOTATE( INTERSECT.out.intersect, exon_boundary ) + GTF_ANNOTATION( INTERSECT.out.intersect, exon_boundary ) - ch_annotations.view() + ch_annotation.view() - ch_bed_merged = ANNOTATE.out.bed.filter{ meta, bed -> meta.tool == "merged" } - ch_gtf_merged = ANNOTATE.out.gtf.filter{ meta, gtf -> meta.tool == "merged" } + ch_bed_merged = GTF_ANNOTATION.out.bed.filter{ meta, bed -> meta.tool == "merged" } + ch_gtf_merged = GTF_ANNOTATION.out.gtf.filter{ meta, gtf -> meta.tool == "merged" } COMBINE_BEDS(ch_bed_merged.map{ meta, bed -> bed}.collect().map{[[id: "annotation"], it]}) REMOVE_SCORE_STRAND( COMBINE_BEDS.out.sorted, []) COMBINE_GTFS(ch_gtf_merged.map{ meta, gtf -> gtf}.collect().map{[[id: "annotation"], it]}) ch_versions = ch_versions.mix(INTERSECT.out.versions) - ch_versions = ch_versions.mix(ANNOTATE.out.versions) + ch_versions = ch_versions.mix(GTF_ANNOTATION.out.versions) ch_versions = ch_versions.mix(COMBINE_BEDS.out.versions) ch_versions = ch_versions.mix(REMOVE_SCORE_STRAND.out.versions) ch_versions = ch_versions.mix(COMBINE_GTFS.out.versions) diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 6df3470e..a16fb752 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -58,7 +58,7 @@ workflow CIRCRNA { ch_fasta ch_gtf ch_mature - ch_annotations + ch_annotation ch_species ch_versions @@ -144,7 +144,7 @@ workflow CIRCRNA { chromosomes, hisat2_index, star_index, - ch_annotations, + ch_annotation, params.bsj_reads, params.tool_filter, params.duplicates_fun, From 706e797de17af356040fcfd8e82d89013b9bc69d Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 18 Jun 2024 10:24:13 +0200 Subject: [PATCH 308/491] First database annotation implementation --- assets/schema_annotation.json | 6 ++-- conf/modules.config | 15 ++++++++++ subworkflows/local/discovery/annotation.nf | 32 ++++++++++++++++------ 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/assets/schema_annotation.json b/assets/schema_annotation.json index fa0b63db..4158373d 100644 --- a/assets/schema_annotation.json +++ b/assets/schema_annotation.json @@ -10,7 +10,8 @@ "name": { "type": "string", "pattern": "^\\S+$", - "errorMessage": "Annotation file name must be provided and cannot contain spaces" + "errorMessage": "Annotation file name must be provided and cannot contain spaces", + "meta": ["id"] }, "file": { "type": "string", @@ -24,7 +25,8 @@ "minimum": 0, "maximum": 1, "default": 0.9, - "errorMessage": "Minimum overlap must be a number between 0 and 1" + "errorMessage": "Minimum overlap must be a number between 0 and 1", + "meta": ["min_overlap"] } }, "required": ["name", "file"] diff --git a/conf/modules.config b/conf/modules.config index 40cfece6..3929576c 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -575,6 +575,21 @@ process { ext.suffix = "intersect.bed" } + withName: '.*:ANNOTATION:INGEST_DATABASE_NAMES' { + ext.args = { "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \"${meta.id}:\" + \$4, \$5, \$6 }'" } + ext.suffix = "named.bed" + } + + withName: '.*:ANNOTATION:DATABASE_ANNOTATION' { + ext.args = { "-f ${meta.min_overlap} -r -loj" } + ext.suffix = "annotated.bed" + } + + withName: '.*:ANNOTATION:COMBINE_DATABASES' { + ext.args = "-k 1,1 -k2,2n -k3,3n -u" + ext.suffix = "combined.bed" + } + withName: '.*:ANNOTATION:COMBINE_BEDS' { ext.args = "-k 1,1 -k2,2n -k3,3n -u" ext.suffix = "combined.bed" diff --git a/subworkflows/local/discovery/annotation.nf b/subworkflows/local/discovery/annotation.nf index c9e0dfa8..d6277f04 100644 --- a/subworkflows/local/discovery/annotation.nf +++ b/subworkflows/local/discovery/annotation.nf @@ -1,8 +1,11 @@ -include { BEDTOOLS_INTERSECT as INTERSECT } from '../../../modules/nf-core/bedtools/intersect' -include { ANNOTATION as GTF_ANNOTATION } from '../../../modules/local/annotation' -include { GNU_SORT as COMBINE_BEDS } from '../../../modules/nf-core/gnu/sort' -include { GAWK as REMOVE_SCORE_STRAND } from '../../../modules/nf-core/gawk' -include { GNU_SORT as COMBINE_GTFS } from '../../../modules/nf-core/gnu/sort' +include { BEDTOOLS_INTERSECT as INTERSECT } from '../../../modules/nf-core/bedtools/intersect' +include { ANNOTATION as GTF_ANNOTATION } from '../../../modules/local/annotation' +include { GAWK as INGEST_DATABASE_NAMES } from '../../../modules/nf-core/gawk' +include { GNU_SORT as COMBINE_DATABASES } from '../../../modules/nf-core/gnu/sort' +include { BEDTOOLS_INTERSECT as DATABASE_ANNOTATION } from '../../../modules/nf-core/bedtools/intersect' +include { GNU_SORT as COMBINE_BEDS } from '../../../modules/nf-core/gnu/sort' +include { GAWK as REMOVE_SCORE_STRAND } from '../../../modules/nf-core/gawk' +include { GNU_SORT as COMBINE_GTFS } from '../../../modules/nf-core/gnu/sort' workflow ANNOTATION { take: @@ -14,20 +17,33 @@ workflow ANNOTATION { main: ch_versions = Channel.empty() - INTERSECT( regions.combine(gtf), [[], []]) + INTERSECT( regions.combine(gtf), [[], []] ) GTF_ANNOTATION( INTERSECT.out.intersect, exon_boundary ) - ch_annotation.view() - ch_bed_merged = GTF_ANNOTATION.out.bed.filter{ meta, bed -> meta.tool == "merged" } ch_gtf_merged = GTF_ANNOTATION.out.gtf.filter{ meta, gtf -> meta.tool == "merged" } + INGEST_DATABASE_NAMES( ch_annotation, [] ) + DATABASE_ANNOTATION( ch_bed_merged.combine(INGEST_DATABASE_NAMES.out.output) + .map{ meta1, regions, meta2, database -> + [meta1 + [id: "${meta1.id}:${meta2.id}", + sample: meta1.id, + db: meta2.id, + min_overlap: meta2.min_overlap], regions, database] }, + [[], []]) + COMBINE_DATABASES( DATABASE_ANNOTATION.out.intersect + .map{ meta, annotated -> [[id: meta.sample], annotated] } + .groupTuple()) + COMBINE_BEDS(ch_bed_merged.map{ meta, bed -> bed}.collect().map{[[id: "annotation"], it]}) REMOVE_SCORE_STRAND( COMBINE_BEDS.out.sorted, []) COMBINE_GTFS(ch_gtf_merged.map{ meta, gtf -> gtf}.collect().map{[[id: "annotation"], it]}) ch_versions = ch_versions.mix(INTERSECT.out.versions) ch_versions = ch_versions.mix(GTF_ANNOTATION.out.versions) + ch_versions = ch_versions.mix(INGEST_DATABASE_NAMES.out.versions) + ch_versions = ch_versions.mix(COMBINE_DATABASES.out.versions) + ch_versions = ch_versions.mix(DATABASE_ANNOTATION.out.versions) ch_versions = ch_versions.mix(COMBINE_BEDS.out.versions) ch_versions = ch_versions.mix(REMOVE_SCORE_STRAND.out.versions) ch_versions = ch_versions.mix(COMBINE_GTFS.out.versions) From 8ecd3cd9de8d6f6454e702b01245ec2ede9b7fdf Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 18 Jun 2024 10:58:37 +0200 Subject: [PATCH 309/491] Fix per-sample DB annotation --- conf/modules.config | 12 +++++++++--- subworkflows/local/discovery/annotation.nf | 4 +++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 3929576c..5ae54e6e 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -576,18 +576,24 @@ process { } withName: '.*:ANNOTATION:INGEST_DATABASE_NAMES' { - ext.args = { "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \"${meta.id}:\" + \$4, \$5, \$6 }'" } + ext.args = { "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \"${meta.id}:\" \$4, \$5, \$6 }'" } ext.suffix = "named.bed" } withName: '.*:ANNOTATION:DATABASE_ANNOTATION' { - ext.args = { "-f ${meta.min_overlap} -r -loj" } + ext.args = { "-f ${meta.min_overlap} -r -loj -wa -wb" } ext.suffix = "annotated.bed" } + withName: '.*:ANNOTATION:CLEAN_DATABASE_ANNOTATION' { + // Keep first 10 columns and the 14th column + ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$4, \$5, \$6, \$7, \$8, \$9, \$10, \$14 }'" + ext.suffix = "cleaned_db.bed" + } + withName: '.*:ANNOTATION:COMBINE_DATABASES' { ext.args = "-k 1,1 -k2,2n -k3,3n -u" - ext.suffix = "combined.bed" + ext.suffix = "combined_dbs.bed" } withName: '.*:ANNOTATION:COMBINE_BEDS' { diff --git a/subworkflows/local/discovery/annotation.nf b/subworkflows/local/discovery/annotation.nf index d6277f04..c3e55b55 100644 --- a/subworkflows/local/discovery/annotation.nf +++ b/subworkflows/local/discovery/annotation.nf @@ -3,6 +3,7 @@ include { ANNOTATION as GTF_ANNOTATION } from '../../../modules/loc include { GAWK as INGEST_DATABASE_NAMES } from '../../../modules/nf-core/gawk' include { GNU_SORT as COMBINE_DATABASES } from '../../../modules/nf-core/gnu/sort' include { BEDTOOLS_INTERSECT as DATABASE_ANNOTATION } from '../../../modules/nf-core/bedtools/intersect' +include { GAWK as CLEAN_DATABASE_ANNOTATION } from '../../../modules/nf-core/gawk' include { GNU_SORT as COMBINE_BEDS } from '../../../modules/nf-core/gnu/sort' include { GAWK as REMOVE_SCORE_STRAND } from '../../../modules/nf-core/gawk' include { GNU_SORT as COMBINE_GTFS } from '../../../modules/nf-core/gnu/sort' @@ -31,7 +32,8 @@ workflow ANNOTATION { db: meta2.id, min_overlap: meta2.min_overlap], regions, database] }, [[], []]) - COMBINE_DATABASES( DATABASE_ANNOTATION.out.intersect + CLEAN_DATABASE_ANNOTATION( DATABASE_ANNOTATION.out.intersect, [] ) + COMBINE_DATABASES( CLEAN_DATABASE_ANNOTATION.out.output .map{ meta, annotated -> [[id: meta.sample], annotated] } .groupTuple()) From 6a97b0ccd3707152f075b42216fd0eead9f5bbce Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 18 Jun 2024 11:43:47 +0200 Subject: [PATCH 310/491] Change database intersection strategy --- conf/modules.config | 15 +------ modules/local/annotation/main.nf | 2 +- .../local/annotation/templates/annotation.py | 2 +- subworkflows/local/discovery/annotation.nf | 40 +++++++++---------- 4 files changed, 23 insertions(+), 36 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 5ae54e6e..307ea313 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -570,7 +570,7 @@ process { ext.when = { params.tool.split(',').length > 1 } } - withName: '.*:ANNOTATION:INTERSECT' { + withName: '.*:ANNOTATION:INTERSECT_GTF' { ext.args = "-loj" ext.suffix = "intersect.bed" } @@ -580,22 +580,11 @@ process { ext.suffix = "named.bed" } - withName: '.*:ANNOTATION:DATABASE_ANNOTATION' { + withName: '.*:ANNOTATION:INTERSECT_DATABASE' { ext.args = { "-f ${meta.min_overlap} -r -loj -wa -wb" } ext.suffix = "annotated.bed" } - withName: '.*:ANNOTATION:CLEAN_DATABASE_ANNOTATION' { - // Keep first 10 columns and the 14th column - ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$4, \$5, \$6, \$7, \$8, \$9, \$10, \$14 }'" - ext.suffix = "cleaned_db.bed" - } - - withName: '.*:ANNOTATION:COMBINE_DATABASES' { - ext.args = "-k 1,1 -k2,2n -k3,3n -u" - ext.suffix = "combined_dbs.bed" - } - withName: '.*:ANNOTATION:COMBINE_BEDS' { ext.args = "-k 1,1 -k2,2n -k3,3n -u" ext.suffix = "combined.bed" diff --git a/modules/local/annotation/main.nf b/modules/local/annotation/main.nf index a5b6d77a..c06f03b9 100644 --- a/modules/local/annotation/main.nf +++ b/modules/local/annotation/main.nf @@ -8,7 +8,7 @@ process ANNOTATION { 'biocontainers/pandas:1.5.2' }" input: - tuple val(meta), path(intersection) + tuple val(meta), path(gtf_intersection), path(db_intersections) val(exon_boundary) output: diff --git a/modules/local/annotation/templates/annotation.py b/modules/local/annotation/templates/annotation.py index 6cd1d68d..f45e3ae8 100755 --- a/modules/local/annotation/templates/annotation.py +++ b/modules/local/annotation/templates/annotation.py @@ -41,7 +41,7 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: exon_boundary = int("${exon_boundary}") -df = pd.read_csv("${intersection}", sep="\\t", header=None, usecols=columns.keys()) +df = pd.read_csv("${gtf_intersection}", sep="\\t", header=None, usecols=columns.keys()) df = df.rename(columns=columns) # Extract circRNAs without match diff --git a/subworkflows/local/discovery/annotation.nf b/subworkflows/local/discovery/annotation.nf index c3e55b55..88cc5c76 100644 --- a/subworkflows/local/discovery/annotation.nf +++ b/subworkflows/local/discovery/annotation.nf @@ -1,8 +1,8 @@ -include { BEDTOOLS_INTERSECT as INTERSECT } from '../../../modules/nf-core/bedtools/intersect' -include { ANNOTATION as GTF_ANNOTATION } from '../../../modules/local/annotation' +include { BEDTOOLS_INTERSECT as INTERSECT_GTF } from '../../../modules/nf-core/bedtools/intersect' +include { ANNOTATION as ANNOTATE } from '../../../modules/local/annotation' include { GAWK as INGEST_DATABASE_NAMES } from '../../../modules/nf-core/gawk' include { GNU_SORT as COMBINE_DATABASES } from '../../../modules/nf-core/gnu/sort' -include { BEDTOOLS_INTERSECT as DATABASE_ANNOTATION } from '../../../modules/nf-core/bedtools/intersect' +include { BEDTOOLS_INTERSECT as INTERSECT_DATABASE } from '../../../modules/nf-core/bedtools/intersect' include { GAWK as CLEAN_DATABASE_ANNOTATION } from '../../../modules/nf-core/gawk' include { GNU_SORT as COMBINE_BEDS } from '../../../modules/nf-core/gnu/sort' include { GAWK as REMOVE_SCORE_STRAND } from '../../../modules/nf-core/gawk' @@ -18,34 +18,32 @@ workflow ANNOTATION { main: ch_versions = Channel.empty() - INTERSECT( regions.combine(gtf), [[], []] ) - GTF_ANNOTATION( INTERSECT.out.intersect, exon_boundary ) - - ch_bed_merged = GTF_ANNOTATION.out.bed.filter{ meta, bed -> meta.tool == "merged" } - ch_gtf_merged = GTF_ANNOTATION.out.gtf.filter{ meta, gtf -> meta.tool == "merged" } - + INTERSECT_GTF( regions.combine(gtf), [[], []] ) INGEST_DATABASE_NAMES( ch_annotation, [] ) - DATABASE_ANNOTATION( ch_bed_merged.combine(INGEST_DATABASE_NAMES.out.output) + INTERSECT_DATABASE( regions.combine(INGEST_DATABASE_NAMES.out.output) .map{ meta1, regions, meta2, database -> - [meta1 + [id: "${meta1.id}:${meta2.id}", - sample: meta1.id, - db: meta2.id, + [[id: "${meta1.id}:${meta2.id}", + original_meta: meta1, min_overlap: meta2.min_overlap], regions, database] }, [[], []]) - CLEAN_DATABASE_ANNOTATION( DATABASE_ANNOTATION.out.intersect, [] ) - COMBINE_DATABASES( CLEAN_DATABASE_ANNOTATION.out.output - .map{ meta, annotated -> [[id: meta.sample], annotated] } - .groupTuple()) + + ANNOTATE( INTERSECT_GTF.out.intersect + .join(INTERSECT_DATABASE.out.intersect + .map{ meta, bed -> [meta.original_meta, bed] } + .groupTuple()), + exon_boundary ) + + ch_bed_merged = ANNOTATE.out.bed.filter{ meta, bed -> meta.tool == "merged" } + ch_gtf_merged = ANNOTATE.out.gtf.filter{ meta, gtf -> meta.tool == "merged" } COMBINE_BEDS(ch_bed_merged.map{ meta, bed -> bed}.collect().map{[[id: "annotation"], it]}) REMOVE_SCORE_STRAND( COMBINE_BEDS.out.sorted, []) COMBINE_GTFS(ch_gtf_merged.map{ meta, gtf -> gtf}.collect().map{[[id: "annotation"], it]}) - ch_versions = ch_versions.mix(INTERSECT.out.versions) - ch_versions = ch_versions.mix(GTF_ANNOTATION.out.versions) + ch_versions = ch_versions.mix(INTERSECT_GTF.out.versions) ch_versions = ch_versions.mix(INGEST_DATABASE_NAMES.out.versions) - ch_versions = ch_versions.mix(COMBINE_DATABASES.out.versions) - ch_versions = ch_versions.mix(DATABASE_ANNOTATION.out.versions) + ch_versions = ch_versions.mix(INTERSECT_DATABASE.out.versions) + ch_versions = ch_versions.mix(ANNOTATE.out.versions) ch_versions = ch_versions.mix(COMBINE_BEDS.out.versions) ch_versions = ch_versions.mix(REMOVE_SCORE_STRAND.out.versions) ch_versions = ch_versions.mix(COMBINE_GTFS.out.versions) From b511c0cf24df8958c29dd6ef3ca12066ab823f8e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 18 Jun 2024 11:52:14 +0200 Subject: [PATCH 311/491] Make sure databases are optional --- subworkflows/local/discovery/annotation.nf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subworkflows/local/discovery/annotation.nf b/subworkflows/local/discovery/annotation.nf index 88cc5c76..7c9801b6 100644 --- a/subworkflows/local/discovery/annotation.nf +++ b/subworkflows/local/discovery/annotation.nf @@ -30,7 +30,8 @@ workflow ANNOTATION { ANNOTATE( INTERSECT_GTF.out.intersect .join(INTERSECT_DATABASE.out.intersect .map{ meta, bed -> [meta.original_meta, bed] } - .groupTuple()), + .groupTuple(), remainder: true) + .map{ meta, gtf_intersection, db_intersections -> [meta, gtf_intersection, db_intersections ?: []]}, exon_boundary ) ch_bed_merged = ANNOTATE.out.bed.filter{ meta, bed -> meta.tool == "merged" } From b4c2f4969a9b5af012bd029bd7ad4b2091c859b4 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 18 Jun 2024 12:31:46 +0200 Subject: [PATCH 312/491] Add db annotation to annotation python script --- modules/local/annotation/templates/annotation.py | 11 +++++++++++ subworkflows/local/discovery/annotation.nf | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/modules/local/annotation/templates/annotation.py b/modules/local/annotation/templates/annotation.py index f45e3ae8..479980b1 100755 --- a/modules/local/annotation/templates/annotation.py +++ b/modules/local/annotation/templates/annotation.py @@ -107,6 +107,17 @@ def determine_type(row): df = pd.concat([df, df_intergenic], axis=0) +db_colnames = ['chr', 'start', 'end', 'name', 'score', 'strand', 'db_chr', 'db_start', 'db_end', 'db_name', 'db_score', 'db_strand'] +db_usecols = ['chr', 'start', 'end', 'name', 'score', 'strand', 'db_name'] +df_databases = pd.concat([pd.read_csv(db_path, sep="\\t", header=0, names=db_colnames, usecols=db_usecols) for db_path in "${db_intersections}".split()]) + +# Group by chr, start, end, name, score, strand, and aggregate the db_name to csv string +df_databases = df_databases.groupby(['chr', 'start', 'end', 'name', 'score', 'strand']).aggregate({ + 'db_name': lambda x: ",".join(x) if len(x) > 0 else "." +}) + +df = df.merge(df_databases, how='left', on=['chr', 'start', 'end', 'name', 'score', 'strand']) + # Sort by chr, start, end df = df.sort_values(['chr', 'start', 'end']) diff --git a/subworkflows/local/discovery/annotation.nf b/subworkflows/local/discovery/annotation.nf index 7c9801b6..da2c7b99 100644 --- a/subworkflows/local/discovery/annotation.nf +++ b/subworkflows/local/discovery/annotation.nf @@ -22,7 +22,7 @@ workflow ANNOTATION { INGEST_DATABASE_NAMES( ch_annotation, [] ) INTERSECT_DATABASE( regions.combine(INGEST_DATABASE_NAMES.out.output) .map{ meta1, regions, meta2, database -> - [[id: "${meta1.id}:${meta2.id}", + [[id: "${meta1.id}-${meta2.id}", original_meta: meta1, min_overlap: meta2.min_overlap], regions, database] }, [[], []]) From cbaf4fd8053c8ca8d0dee20691fafdc48ec0bc76 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 18 Jun 2024 12:56:44 +0200 Subject: [PATCH 313/491] Fix first row length bug --- conf/modules.config | 2 +- modules/local/annotation/templates/annotation.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 307ea313..ab9245e2 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -596,7 +596,7 @@ process { } withName: '.*:ANNOTATION:REMOVE_SCORE_STRAND' { - ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3, \".\", \".\", \$7, \$8, \$9, \$10 }'" + ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3, \".\", \".\", \$7, \$8, \$9, \$10, \$11 }'" ext.suffix = "tidy.bed" } diff --git a/modules/local/annotation/templates/annotation.py b/modules/local/annotation/templates/annotation.py index 479980b1..9bb3519d 100755 --- a/modules/local/annotation/templates/annotation.py +++ b/modules/local/annotation/templates/annotation.py @@ -109,7 +109,7 @@ def determine_type(row): db_colnames = ['chr', 'start', 'end', 'name', 'score', 'strand', 'db_chr', 'db_start', 'db_end', 'db_name', 'db_score', 'db_strand'] db_usecols = ['chr', 'start', 'end', 'name', 'score', 'strand', 'db_name'] -df_databases = pd.concat([pd.read_csv(db_path, sep="\\t", header=0, names=db_colnames, usecols=db_usecols) for db_path in "${db_intersections}".split()]) +df_databases = pd.concat([pd.read_csv(db_path, sep="\\t", names=db_colnames, usecols=db_usecols) for db_path in "${db_intersections}".split()]) # Group by chr, start, end, name, score, strand, and aggregate the db_name to csv string df_databases = df_databases.groupby(['chr', 'start', 'end', 'name', 'score', 'strand']).aggregate({ From 8999212aae6026c51d0d9d5da08f1133b6a9d5f7 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 18 Jun 2024 13:13:10 +0200 Subject: [PATCH 314/491] Make sure annotation input is optional --- .../local/annotation/templates/annotation.py | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/modules/local/annotation/templates/annotation.py b/modules/local/annotation/templates/annotation.py index 9bb3519d..91121d78 100755 --- a/modules/local/annotation/templates/annotation.py +++ b/modules/local/annotation/templates/annotation.py @@ -107,16 +107,24 @@ def determine_type(row): df = pd.concat([df, df_intergenic], axis=0) -db_colnames = ['chr', 'start', 'end', 'name', 'score', 'strand', 'db_chr', 'db_start', 'db_end', 'db_name', 'db_score', 'db_strand'] -db_usecols = ['chr', 'start', 'end', 'name', 'score', 'strand', 'db_name'] -df_databases = pd.concat([pd.read_csv(db_path, sep="\\t", names=db_colnames, usecols=db_usecols) for db_path in "${db_intersections}".split()]) +db_intersections = "${db_intersections}".split() +has_db = len(db_intersections) > 0 -# Group by chr, start, end, name, score, strand, and aggregate the db_name to csv string -df_databases = df_databases.groupby(['chr', 'start', 'end', 'name', 'score', 'strand']).aggregate({ - 'db_name': lambda x: ",".join(x) if len(x) > 0 else "." -}) +if has_db: + db_colnames = ['chr', 'start', 'end', 'name', 'score', 'strand', 'db_chr', 'db_start', 'db_end', 'db_name', 'db_score', 'db_strand'] + db_usecols = ['chr', 'start', 'end', 'name', 'score', 'strand', 'db_name'] + df_databases = pd.concat([pd.read_csv(db_path, sep="\\t", names=db_colnames, usecols=db_usecols) for db_path in db_intersections]) + + # Group by chr, start, end, name, score, strand, and aggregate the db_name to list + df_databases = df_databases.groupby(['chr', 'start', 'end', 'name', 'score', 'strand']).aggregate({ + 'db_name': lambda x: ",".join([val for val in x if val != '.']) + }) + + df_databases['db_name'] = df_databases['db_name'].apply(lambda x: x if x else '.') -df = df.merge(df_databases, how='left', on=['chr', 'start', 'end', 'name', 'score', 'strand']) + df = df.merge(df_databases, how='left', on=['chr', 'start', 'end', 'name', 'score', 'strand']) +else: + df['db_name'] = "." # Sort by chr, start, end df = df.sort_values(['chr', 'start', 'end']) @@ -126,7 +134,7 @@ def determine_type(row): # Convert to GTF df['source'] = 'circRNA' df['frame'] = '.' -df['attributes'] = 'gene_id "' + df['gene_id'] + '"; gene_name "' + df['gene_name'] + '"; transcript_id "circ_' + df['name'] + '";' +df['attributes'] = 'gene_id "' + df['gene_id'] + '"; gene_name "' + df['gene_name'] + '"; transcript_id "circ_' + df['name'] + '"; db_ids "' + df['db_name'] + '";' gtf_order = ['chr', 'source', 'type', 'start', 'end', 'score', 'strand', 'frame', 'attributes'] df = df[gtf_order] From fab59a31e6af998289be2681447aaf463d472099 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Wed, 19 Jun 2024 09:30:19 +0200 Subject: [PATCH 315/491] Use psirc bioconda package --- modules/local/psirc/index/environment.yml | 6 ++++++ modules/local/psirc/index/main.nf | 8 +++++--- modules/local/psirc/quant/environment.yml | 6 ++++++ modules/local/psirc/quant/main.nf | 8 +++++--- 4 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 modules/local/psirc/index/environment.yml create mode 100644 modules/local/psirc/quant/environment.yml diff --git a/modules/local/psirc/index/environment.yml b/modules/local/psirc/index/environment.yml new file mode 100644 index 00000000..e0303603 --- /dev/null +++ b/modules/local/psirc/index/environment.yml @@ -0,0 +1,6 @@ +name: psirc_index +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::psirc=1.0.0 diff --git a/modules/local/psirc/index/main.nf b/modules/local/psirc/index/main.nf index 7c10a533..b975d414 100644 --- a/modules/local/psirc/index/main.nf +++ b/modules/local/psirc/index/main.nf @@ -2,7 +2,10 @@ process PSIRC_INDEX { tag "${meta.id}" label 'process_high' - container "registry.hub.docker.com/bigdatainbiomedicine/psirc" + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/psirc:1.0.0--he1fd2f9_0' : + 'biocontainers/psirc:1.0.0--he1fd2f9_0' }" input: tuple val(meta), path(fasta) @@ -12,13 +15,12 @@ process PSIRC_INDEX { path "versions.yml", emit: versions script: - def VERSION = '1.0' """ psirc-quant index -i psirc.index --make-unique $fasta cat <<-END_VERSIONS > versions.yml "${task.process}": - psirc-quant: $VERSION + psirc-quant: \$(psirc-quant version | sed -n 's/^psirc-quant, version \\([0-9.]*\\).*$/\\1/p') END_VERSIONS """ } diff --git a/modules/local/psirc/quant/environment.yml b/modules/local/psirc/quant/environment.yml new file mode 100644 index 00000000..222b4e89 --- /dev/null +++ b/modules/local/psirc/quant/environment.yml @@ -0,0 +1,6 @@ +name: psirc_quant +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::psirc=1.0.0 diff --git a/modules/local/psirc/quant/main.nf b/modules/local/psirc/quant/main.nf index edecc8f9..20cddf32 100644 --- a/modules/local/psirc/quant/main.nf +++ b/modules/local/psirc/quant/main.nf @@ -2,7 +2,10 @@ process PSIRC_QUANT { tag "${meta.id}" label 'process_high' - container "registry.hub.docker.com/bigdatainbiomedicine/psirc" + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/psirc:1.0.0--he1fd2f9_0' : + 'biocontainers/psirc:1.0.0--he1fd2f9_0' }" input: tuple val(meta), path(reads) @@ -19,13 +22,12 @@ process PSIRC_QUANT { def single_end = meta.single_end ? "--single -l 76 -s 20" : "" def genomebam = gtf ? "--genomebam -g $gtf" : "" def chromosomes = chrom_sizes ? "-c $chrom_sizes" : "" - def VERSION = '1.0' """ psirc-quant quant -t $task.cpus -i $index -o $meta.id $single_end $reads -b $bootstrap_samples $genomebam $chromosomes cat <<-END_VERSIONS > versions.yml "${task.process}": - psirc-quant: $VERSION + psirc-quant: \$(psirc-quant version | sed -n 's/^psirc-quant, version \\([0-9.]*\\).*$/\\1/p') END_VERSIONS """ } From 8311bab8356d2e825d1412172d089929556bef57 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Wed, 19 Jun 2024 09:35:14 +0200 Subject: [PATCH 316/491] Escape problematic $ --- modules/local/psirc/quant/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/psirc/quant/main.nf b/modules/local/psirc/quant/main.nf index 20cddf32..862e9ccd 100644 --- a/modules/local/psirc/quant/main.nf +++ b/modules/local/psirc/quant/main.nf @@ -27,7 +27,7 @@ process PSIRC_QUANT { cat <<-END_VERSIONS > versions.yml "${task.process}": - psirc-quant: \$(psirc-quant version | sed -n 's/^psirc-quant, version \\([0-9.]*\\).*$/\\1/p') + psirc-quant: \$(psirc-quant version | sed -n 's/^psirc-quant, version \\([0-9.]*\\).*\$/\\1/p') END_VERSIONS """ } From 9b57e7f2caab961aa3c1eab2169cda93cf1ba8e9 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Wed, 19 Jun 2024 09:41:11 +0200 Subject: [PATCH 317/491] Fix problematic $ also in psirc index --- modules/local/psirc/index/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/psirc/index/main.nf b/modules/local/psirc/index/main.nf index b975d414..c0cae596 100644 --- a/modules/local/psirc/index/main.nf +++ b/modules/local/psirc/index/main.nf @@ -20,7 +20,7 @@ process PSIRC_INDEX { cat <<-END_VERSIONS > versions.yml "${task.process}": - psirc-quant: \$(psirc-quant version | sed -n 's/^psirc-quant, version \\([0-9.]*\\).*$/\\1/p') + psirc-quant: \$(psirc-quant version | sed -n 's/^psirc-quant, version \\([0-9.]*\\).*\$/\\1/p') END_VERSIONS """ } From fbabe351540646c7d8796e07d9df46e88d255031 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sun, 23 Jun 2024 08:59:16 +0200 Subject: [PATCH 318/491] Implement GTF filtering --- conf/modules.config | 4 + modules/local/gtf_filter/main.nf | 24 +++++ .../local/gtf_filter/templates/gtf_filter.py | 94 +++++++++++++++++++ subworkflows/local/prepare_genome.nf | 24 +++-- workflows/circrna/main.nf | 1 + 5 files changed, 138 insertions(+), 9 deletions(-) create mode 100644 modules/local/gtf_filter/main.nf create mode 100644 modules/local/gtf_filter/templates/gtf_filter.py diff --git a/conf/modules.config b/conf/modules.config index ab9245e2..0885b37e 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -70,6 +70,10 @@ process { ] } + withName: GTF_FILTER { + ext.suffix = "filtered.gtf" + } + withName: SEQKIT_SPLIT { ext.args = "-i --by-id-prefix \"\"" publishDir = [ diff --git a/modules/local/gtf_filter/main.nf b/modules/local/gtf_filter/main.nf new file mode 100644 index 00000000..4606b97e --- /dev/null +++ b/modules/local/gtf_filter/main.nf @@ -0,0 +1,24 @@ +process GTF_FILTER { + tag "$fasta" + + conda "conda-forge::python=3.9.5" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/python:3.9--1' : + 'biocontainers/python:3.9--1' }" + + input: + tuple val(meta), path(fasta) + tuple val(meta2), path(gtf) + + output: + tuple val(meta), path("${prefix}.${suffix}"), emit: filtered + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + prefix = task.ext.prefix ?: meta.id + suffix = task.ext.suffix ?: "gtf" + template 'gtf_filter.py' +} diff --git a/modules/local/gtf_filter/templates/gtf_filter.py b/modules/local/gtf_filter/templates/gtf_filter.py new file mode 100644 index 00000000..f82d8055 --- /dev/null +++ b/modules/local/gtf_filter/templates/gtf_filter.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +# Written by Olga Botvinnik with subsequent reworking by Jonathan Manning and Nico Trummer. +# Released under the MIT license. + +import logging +import re +import statistics +import platform +from typing import Set + +# Create a logger +logging.basicConfig(format="%(name)s - %(asctime)s %(levelname)s: %(message)s") +logger = logging.getLogger("fasta_gtf_filter") +logger.setLevel(logging.INFO) + +def format_yaml_like(data: dict, indent: int = 0) -> str: + """Formats a dictionary to a YAML-like string. + + Args: + data (dict): The dictionary to format. + indent (int): The current indentation level. + + Returns: + str: A string formatted as YAML. + """ + yaml_str = "" + for key, value in data.items(): + spaces = " " * indent + if isinstance(value, dict): + yaml_str += f"{spaces}{key}:\\n{format_yaml_like(value, indent + 1)}" + else: + yaml_str += f"{spaces}{key}: {value}\\n" + return yaml_str + + +def extract_fasta_seq_names(fasta_name: str) -> Set[str]: + """Extracts the sequence names from a FASTA file.""" + with open(fasta_name) as fasta: + return {line[1:].split(None, 1)[0] for line in fasta if line.startswith(">")} + + +def tab_delimited(file: str) -> float: + """Check if file is tab-delimited and return median number of tabs.""" + with open(file, "r") as f: + data = f.read(102400) + return statistics.median(line.count("\t") for line in data.split("\n")) + + +def filter_gtf(fasta: str, gtf_in: str, filtered_gtf_out: str, skip_transcript_id_check: bool) -> None: + """Filter GTF file based on FASTA sequence names.""" + if tab_delimited(gtf_in) != 8: + raise ValueError("Invalid GTF file: Expected 9 tab-separated columns.") + + seq_names_in_genome = extract_fasta_seq_names(fasta) + logger.info(f"Extracted chromosome sequence names from {fasta}") + logger.debug("All sequence IDs from FASTA: " + ", ".join(sorted(seq_names_in_genome))) + + seq_names_in_gtf = set() + try: + with open(gtf_in) as gtf, open(filtered_gtf_out, "w") as out: + line_count = 0 + for line in gtf: + seq_name = line.split("\t")[0] + seq_names_in_gtf.add(seq_name) # Add sequence name to the set + + if seq_name in seq_names_in_genome: + if skip_transcript_id_check or re.search(r'transcript_id "([^"]+)"', line): + out.write(line) + line_count += 1 + + if line_count == 0: + raise ValueError("All GTF lines removed by filters") + + except IOError as e: + logger.error(f"File operation failed: {e}") + return + + logger.debug("All sequence IDs from GTF: " + ", ".join(sorted(seq_names_in_gtf))) + logger.info(f"Extracted {line_count} matching sequences from {gtf_in} into {filtered_gtf_out}") + + +filter_gtf("${fasta}", "${gtf}", "${prefix}.${suffix}", False) + +# Versions + +versions = { + "${task.process}": { + "python": platform.python_version() + } +} + +with open("versions.yml", "w") as f: + f.write(format_yaml_like(versions)) diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 473d314b..715ce125 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -1,12 +1,13 @@ -include { SEQKIT_SPLIT } from '../../modules/local/seqkit/split' -include { BOWTIE_BUILD } from '../../modules/nf-core/bowtie/build' -include { BOWTIE2_BUILD } from '../../modules/nf-core/bowtie2/build' -include { BWA_INDEX } from '../../modules/nf-core/bwa/index' +include { GTF_FILTER } from '../../modules/local/gtf_filter' +include { SEQKIT_SPLIT } from '../../modules/local/seqkit/split' +include { BOWTIE_BUILD } from '../../modules/nf-core/bowtie/build' +include { BOWTIE2_BUILD } from '../../modules/nf-core/bowtie2/build' +include { BWA_INDEX } from '../../modules/nf-core/bwa/index' include { HISAT2_EXTRACTSPLICESITES } from '../../modules/nf-core/hisat2/extractsplicesites' -include { HISAT2_BUILD } from '../../modules/nf-core/hisat2/build' -include { STAR_GENOMEGENERATE } from '../../modules/nf-core/star/genomegenerate' -include { GAWK as CLEAN_FASTA } from '../../modules/nf-core/gawk' -include { SAMTOOLS_FAIDX } from '../../modules/nf-core/samtools/faidx' +include { HISAT2_BUILD } from '../../modules/nf-core/hisat2/build' +include { STAR_GENOMEGENERATE } from '../../modules/nf-core/star/genomegenerate' +include { GAWK as CLEAN_FASTA } from '../../modules/nf-core/gawk' +include { SAMTOOLS_FAIDX } from '../../modules/nf-core/samtools/faidx' workflow PREPARE_GENOME { @@ -26,6 +27,9 @@ workflow PREPARE_GENOME { ch_versions = ch_versions.mix(CLEAN_FASTA.out.versions) } + GTF_FILTER(ch_fasta, ch_gtf) + ch_gtf = GTF_FILTER.out.filtered + SEQKIT_SPLIT(ch_fasta) BOWTIE_BUILD(ch_fasta.map{ meta, fasta -> fasta }) @@ -43,7 +47,8 @@ workflow PREPARE_GENOME { SAMTOOLS_FAIDX(ch_fasta, [[], []]) // Collect versions - ch_versions = ch_versions.mix(SEQKIT_SPLIT.out.versions, + ch_versions = ch_versions.mix(GTF_FILTER.out.versions, + SEQKIT_SPLIT.out.versions, BOWTIE_BUILD.out.versions, BOWTIE2_BUILD.out.versions, BWA_INDEX.out.versions, @@ -53,6 +58,7 @@ workflow PREPARE_GENOME { SAMTOOLS_FAIDX.out.versions) emit: + gtf = ch_gtf faidx = SAMTOOLS_FAIDX.out.fai bowtie = params.bowtie ?: BOWTIE_BUILD.out.index bowtie2 = params.bowtie2 ? Channel.value([[id: "bowtie2"], file(params.bowtie2, checkIfExists: true)]) : BOWTIE2_BUILD.out.index.collect() diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index a16fb752..0d852ae7 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -112,6 +112,7 @@ workflow CIRCRNA { ch_gtf ) + ch_gtf = PREPARE_GENOME.out.gtf bowtie_index = PREPARE_GENOME.out.bowtie bowtie2_index = PREPARE_GENOME.out.bowtie2 bwa_index = PREPARE_GENOME.out.bwa From 15ffbb0338116ce06a494717d93e4f1905df90a2 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sun, 23 Jun 2024 09:02:14 +0200 Subject: [PATCH 319/491] Escape backslashes --- modules/local/gtf_filter/templates/gtf_filter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/local/gtf_filter/templates/gtf_filter.py b/modules/local/gtf_filter/templates/gtf_filter.py index f82d8055..20343cef 100644 --- a/modules/local/gtf_filter/templates/gtf_filter.py +++ b/modules/local/gtf_filter/templates/gtf_filter.py @@ -44,7 +44,7 @@ def tab_delimited(file: str) -> float: """Check if file is tab-delimited and return median number of tabs.""" with open(file, "r") as f: data = f.read(102400) - return statistics.median(line.count("\t") for line in data.split("\n")) + return statistics.median(line.count("\\t") for line in data.split("\\n")) def filter_gtf(fasta: str, gtf_in: str, filtered_gtf_out: str, skip_transcript_id_check: bool) -> None: @@ -61,7 +61,7 @@ def filter_gtf(fasta: str, gtf_in: str, filtered_gtf_out: str, skip_transcript_i with open(gtf_in) as gtf, open(filtered_gtf_out, "w") as out: line_count = 0 for line in gtf: - seq_name = line.split("\t")[0] + seq_name = line.split("\\t")[0] seq_names_in_gtf.add(seq_name) # Add sequence name to the set if seq_name in seq_names_in_genome: From 50226e88623c85f61d51ecd624363680df5842d5 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 24 Jun 2024 09:56:12 +0200 Subject: [PATCH 320/491] Fix pandas references --- modules/local/annotation/environment.yml | 5 +++++ modules/local/annotation/main.nf | 2 +- modules/local/count_matrix/merge_tools/environment.yml | 5 +++++ modules/local/count_matrix/merge_tools/main.nf | 2 +- 4 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 modules/local/annotation/environment.yml create mode 100644 modules/local/count_matrix/merge_tools/environment.yml diff --git a/modules/local/annotation/environment.yml b/modules/local/annotation/environment.yml new file mode 100644 index 00000000..8c311352 --- /dev/null +++ b/modules/local/annotation/environment.yml @@ -0,0 +1,5 @@ +name: annotation +channels: + - conda-forge +dependencies: + - pandas=1.5.2 diff --git a/modules/local/annotation/main.nf b/modules/local/annotation/main.nf index c06f03b9..1f20cc72 100644 --- a/modules/local/annotation/main.nf +++ b/modules/local/annotation/main.nf @@ -2,7 +2,7 @@ process ANNOTATION { tag "$meta.id:$meta.tool" label 'process_single' - conda "bioconda::pandas=1.5.2" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : 'biocontainers/pandas:1.5.2' }" diff --git a/modules/local/count_matrix/merge_tools/environment.yml b/modules/local/count_matrix/merge_tools/environment.yml new file mode 100644 index 00000000..796e68fc --- /dev/null +++ b/modules/local/count_matrix/merge_tools/environment.yml @@ -0,0 +1,5 @@ +name: merge_tools +channels: + - conda-forge +dependencies: + - pandas=1.5.2 diff --git a/modules/local/count_matrix/merge_tools/main.nf b/modules/local/count_matrix/merge_tools/main.nf index dc80f483..cdd3f2c0 100644 --- a/modules/local/count_matrix/merge_tools/main.nf +++ b/modules/local/count_matrix/merge_tools/main.nf @@ -2,7 +2,7 @@ process MERGE_TOOLS { tag "$meta.id" label "process_single" - conda "bioconda::pandas=1.5.2" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : 'biocontainers/pandas:1.5.2' }" From 81adab0398e3e530234b98675a3bcd34ccd58af3 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 24 Jun 2024 10:13:34 +0200 Subject: [PATCH 321/491] Remove problematic r-base singularity image --- modules/local/circtest/prepare/main.nf | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/local/circtest/prepare/main.nf b/modules/local/circtest/prepare/main.nf index e41b6c46..bfc32b4e 100644 --- a/modules/local/circtest/prepare/main.nf +++ b/modules/local/circtest/prepare/main.nf @@ -2,9 +2,7 @@ process CIRCTEST_PREPARE { label 'process_low' conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/biocontainers/r-base:4.2.1' : - 'biocontainers/r-base:4.2.1' }" + container "biocontainers/r-base:4.2.1" input: tuple val(meta), path(circ_counts) From bed731cf1b6b4d8b77ce379415aa045ce860358f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 24 Jun 2024 10:24:05 +0200 Subject: [PATCH 322/491] Add missing environment yml files --- modules/local/quantification/split_types/environment.yml | 6 ++++++ modules/local/quantification/transcriptome/environment.yml | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 modules/local/quantification/split_types/environment.yml create mode 100644 modules/local/quantification/transcriptome/environment.yml diff --git a/modules/local/quantification/split_types/environment.yml b/modules/local/quantification/split_types/environment.yml new file mode 100644 index 00000000..0c6dab50 --- /dev/null +++ b/modules/local/quantification/split_types/environment.yml @@ -0,0 +1,6 @@ +name: split_types +channels: + - conda-forge + - bioconda +dependencies: + - gawk=5.1.0 diff --git a/modules/local/quantification/transcriptome/environment.yml b/modules/local/quantification/transcriptome/environment.yml new file mode 100644 index 00000000..b07ac902 --- /dev/null +++ b/modules/local/quantification/transcriptome/environment.yml @@ -0,0 +1,6 @@ +name: transcriptome +channels: + - conda-forge + - bioconda +dependencies: + - gffread=0.12.1 From bc8acdf4d3cd746b57ea77fed4f4f97b87c90dc1 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 24 Jun 2024 10:28:41 +0200 Subject: [PATCH 323/491] Add another missing environment yml --- modules/local/count_matrix/merge_samples/environment.yml | 5 +++++ modules/local/count_matrix/merge_samples/main.nf | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 modules/local/count_matrix/merge_samples/environment.yml diff --git a/modules/local/count_matrix/merge_samples/environment.yml b/modules/local/count_matrix/merge_samples/environment.yml new file mode 100644 index 00000000..d5f9e211 --- /dev/null +++ b/modules/local/count_matrix/merge_samples/environment.yml @@ -0,0 +1,5 @@ +name: merge_samples +channels: + - conda-forge +dependencies: + - pandas=1.5.2 diff --git a/modules/local/count_matrix/merge_samples/main.nf b/modules/local/count_matrix/merge_samples/main.nf index 410d2097..8f8d3789 100644 --- a/modules/local/count_matrix/merge_samples/main.nf +++ b/modules/local/count_matrix/merge_samples/main.nf @@ -1,7 +1,7 @@ process MERGE_SAMPLES { label "process_single" - conda "bioconda::pandas=1.5.2" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : 'biocontainers/pandas:1.5.2' }" From 900e1fc9c036ad55e6eaf1d291e324939b49f9e9 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 25 Jun 2024 08:28:42 +0200 Subject: [PATCH 324/491] Add tximeta environment.yml --- modules/local/tximeta/tximeta/environment.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 modules/local/tximeta/tximeta/environment.yml diff --git a/modules/local/tximeta/tximeta/environment.yml b/modules/local/tximeta/tximeta/environment.yml new file mode 100644 index 00000000..be4bcd30 --- /dev/null +++ b/modules/local/tximeta/tximeta/environment.yml @@ -0,0 +1,8 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +name: "tximeta_tximeta" +channels: + - conda-forge + - bioconda +dependencies: + - "bioconda::bioconductor-tximeta=1.20.1" From c3783b9acb0c69399a7d4ccd4e6f145fd9a9da40 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 25 Jun 2024 08:37:26 +0200 Subject: [PATCH 325/491] Fix GTF sorting --- conf/modules.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index ab9245e2..b236e177 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -591,7 +591,7 @@ process { } withName: '.*:ANNOTATION:COMBINE_GTFS' { - ext.args = "-k 1,1 -k3,3n -k4,4n -u" + ext.args = "-k 1,1 -k4,4n -k5,5n -u" ext.suffix = "combined.gtf" } @@ -612,7 +612,7 @@ process { } withName: COMBINE_TRANSCRIPTOME_GTFS { - ext.args = "-k 1,1 -k3,3n -k4,4n" + ext.args = "-k 1,1 -k4,4n -k5,5n" ext.suffix = "gtf" } From cb72c91b1ea0e470bf75146d47b3928a74bf10a1 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 25 Jun 2024 09:24:32 +0200 Subject: [PATCH 326/491] Fix typo on merge_experiments conda environment --- modules/local/quantification/merge_experiments/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/quantification/merge_experiments/main.nf b/modules/local/quantification/merge_experiments/main.nf index 9e14df7e..32fadcd8 100644 --- a/modules/local/quantification/merge_experiments/main.nf +++ b/modules/local/quantification/merge_experiments/main.nf @@ -2,7 +2,7 @@ process MERGE_EXPERIMENTS { tag "$meta.id" label "process_medium" - conda "${moduleDir}/environment.yaml" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/bioconductor-rtracklayer:1.62.0--r43ha9d7317_0' : 'biocontainers/bioconductor-rtracklayer:1.62.0--r43ha9d7317_0' }" From 6c73c83b9b31f93394bff80bb83f81c50616bd4c Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 25 Jun 2024 10:03:51 +0200 Subject: [PATCH 327/491] Fix merge_experiments environment definition --- modules/local/quantification/merge_experiments/environment.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/local/quantification/merge_experiments/environment.yml b/modules/local/quantification/merge_experiments/environment.yml index cfc21aba..b27efe1e 100644 --- a/modules/local/quantification/merge_experiments/environment.yml +++ b/modules/local/quantification/merge_experiments/environment.yml @@ -4,6 +4,5 @@ name: "fishpond_swish" channels: - conda-forge - bioconda - - defaults dependencies: - - "bioconda::bioconductor-rtracklayer==1.62.0--r43ha9d7317_0" + - "biocnda::bioconductor-rtracklayer=1.62.0" From aaebb740f7575fb3fe60f349e42168fd66b106d5 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 25 Jun 2024 10:04:36 +0200 Subject: [PATCH 328/491] Fix typo --- modules/local/quantification/merge_experiments/environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/quantification/merge_experiments/environment.yml b/modules/local/quantification/merge_experiments/environment.yml index b27efe1e..07f95f05 100644 --- a/modules/local/quantification/merge_experiments/environment.yml +++ b/modules/local/quantification/merge_experiments/environment.yml @@ -5,4 +5,4 @@ channels: - conda-forge - bioconda dependencies: - - "biocnda::bioconductor-rtracklayer=1.62.0" + - "bioconda::bioconductor-rtracklayer=1.62.0" From 34a3a80d4d372820a759956eda5bac21d2d7a2dc Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 27 Jun 2024 09:51:06 +0200 Subject: [PATCH 329/491] Fix circexplorer2 count location --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index b236e177..369b900d 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -263,7 +263,7 @@ process { } withName: '.*:CIRCEXPLORER2:UNIFY' { - ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$10, \$6 }'" + ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$13, \$6 }'" ext.suffix = "circexplorer2.bed" publishDir = [ path: { "${params.outdir}/circrna_discovery/circexplorer2/${meta.id}" }, From 5b25150f3d0a4c50bd46e4a8d5e557cd7492db54 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 15 Jul 2024 15:50:24 +0200 Subject: [PATCH 330/491] Use nf core module for gtffilter functionality --- modules.json | 5 + modules/local/gtf_filter/main.nf | 24 ---- .../nf-core/custom/gtffilter/environment.yml | 9 ++ modules/nf-core/custom/gtffilter/main.nf | 37 +++++ modules/nf-core/custom/gtffilter/meta.yml | 51 +++++++ .../custom/gtffilter/templates/gtffilter.py} | 66 +++++++-- .../custom/gtffilter/tests/main.nf.test | 115 +++++++++++++++ .../custom/gtffilter/tests/main.nf.test.snap | 134 ++++++++++++++++++ .../nf-core/custom/gtffilter/tests/tags.yml | 2 + subworkflows/local/prepare_genome.nf | 26 ++-- 10 files changed, 418 insertions(+), 51 deletions(-) delete mode 100644 modules/local/gtf_filter/main.nf create mode 100644 modules/nf-core/custom/gtffilter/environment.yml create mode 100644 modules/nf-core/custom/gtffilter/main.nf create mode 100644 modules/nf-core/custom/gtffilter/meta.yml rename modules/{local/gtf_filter/templates/gtf_filter.py => nf-core/custom/gtffilter/templates/gtffilter.py} (50%) create mode 100644 modules/nf-core/custom/gtffilter/tests/main.nf.test create mode 100644 modules/nf-core/custom/gtffilter/tests/main.nf.test.snap create mode 100644 modules/nf-core/custom/gtffilter/tests/tags.yml diff --git a/modules.json b/modules.json index 3792423c..007ae30d 100644 --- a/modules.json +++ b/modules.json @@ -80,6 +80,11 @@ "git_sha": "de45447d060b8c8b98575bc637a4a575fd0638e1", "installed_by": ["modules"] }, + "custom/gtffilter": { + "branch": "master", + "git_sha": "7888e16f3c8678dfc5d59c899f79b7286271f177", + "installed_by": ["modules"] + }, "custom/tx2gene": { "branch": "master", "git_sha": "ec155021a9104441bf6a9bae3b55d1b5b0bfdb3a", diff --git a/modules/local/gtf_filter/main.nf b/modules/local/gtf_filter/main.nf deleted file mode 100644 index 4606b97e..00000000 --- a/modules/local/gtf_filter/main.nf +++ /dev/null @@ -1,24 +0,0 @@ -process GTF_FILTER { - tag "$fasta" - - conda "conda-forge::python=3.9.5" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/python:3.9--1' : - 'biocontainers/python:3.9--1' }" - - input: - tuple val(meta), path(fasta) - tuple val(meta2), path(gtf) - - output: - tuple val(meta), path("${prefix}.${suffix}"), emit: filtered - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - prefix = task.ext.prefix ?: meta.id - suffix = task.ext.suffix ?: "gtf" - template 'gtf_filter.py' -} diff --git a/modules/nf-core/custom/gtffilter/environment.yml b/modules/nf-core/custom/gtffilter/environment.yml new file mode 100644 index 00000000..115f4123 --- /dev/null +++ b/modules/nf-core/custom/gtffilter/environment.yml @@ -0,0 +1,9 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +name: "custom_gtffilter" +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - "conda-forge::python=3.9.5" diff --git a/modules/nf-core/custom/gtffilter/main.nf b/modules/nf-core/custom/gtffilter/main.nf new file mode 100644 index 00000000..e921d94f --- /dev/null +++ b/modules/nf-core/custom/gtffilter/main.nf @@ -0,0 +1,37 @@ +process CUSTOM_GTFFILTER { + tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/python:3.9--1' : + 'biocontainers/python:3.9--1' }" + + input: + tuple val(meta), path(gtf) + tuple val(meta2), path(fasta) + + output: + tuple val(meta), path("*.gtf"), emit: gtf + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + prefix = task.ext.prefix ?: "${meta.id}" + suffix = task.ext.suffix ?: "gtf" + (gtf.extension == 'gz' ? '.gz' : '') + template 'gtffilter.py' + + stub: + prefix = task.ext.prefix ?: "${meta.id}" + suffix = task.ext.suffix ?: "gtf" + (gtf.extension == 'gz' ? '.gz' : '') + """ + touch ${prefix}.${suffix} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + python: \$(python --version 2>&1 | cut -d ' ' -f 2) + END_VERSIONS + """ +} diff --git a/modules/nf-core/custom/gtffilter/meta.yml b/modules/nf-core/custom/gtffilter/meta.yml new file mode 100644 index 00000000..2c869221 --- /dev/null +++ b/modules/nf-core/custom/gtffilter/meta.yml @@ -0,0 +1,51 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json +name: "custom_gtffilter" +description: Filter a gtf file to keep only regions that are located on a chromosome represented in a given fasta file +keywords: + - gtf + - fasta + - filter +tools: + - "gtffilter": + description: "Filter a gtf file to keep only regions that are located on a chromosome represented in a given fasta file" + tool_dev_url: "https://github.com/nf-core/modules/blob/master/modules/nf-core/custom/gtffilter/main.nf" + +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + + - gtf: + type: file + description: GTF file + pattern: "*.{gtf}" + + - fasta: + type: file + description: Genome fasta file + pattern: "*.{fasta,fa}" + +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + + - gtf: + type: file + description: Filtered GTF file + pattern: "*.{gtf}" + + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + +authors: + - "@nictru" +maintainers: + - "@nictru" diff --git a/modules/local/gtf_filter/templates/gtf_filter.py b/modules/nf-core/custom/gtffilter/templates/gtffilter.py similarity index 50% rename from modules/local/gtf_filter/templates/gtf_filter.py rename to modules/nf-core/custom/gtffilter/templates/gtffilter.py index 20343cef..764ec2ef 100644 --- a/modules/local/gtf_filter/templates/gtf_filter.py +++ b/modules/nf-core/custom/gtffilter/templates/gtffilter.py @@ -1,10 +1,30 @@ #!/usr/bin/env python # Written by Olga Botvinnik with subsequent reworking by Jonathan Manning and Nico Trummer. -# Released under the MIT license. + +# MIT License + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. import logging import re +import gzip import statistics import platform from typing import Set @@ -14,6 +34,7 @@ logger = logging.getLogger("fasta_gtf_filter") logger.setLevel(logging.INFO) + def format_yaml_like(data: dict, indent: int = 0) -> str: """Formats a dictionary to a YAML-like string. @@ -36,8 +57,18 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: def extract_fasta_seq_names(fasta_name: str) -> Set[str]: """Extracts the sequence names from a FASTA file.""" - with open(fasta_name) as fasta: - return {line[1:].split(None, 1)[0] for line in fasta if line.startswith(">")} + + is_gz = fasta_name.endswith(".gz") + open_fn = gzip.open if is_gz else open + + with open_fn(fasta_name) as fasta: + sequences = set() + for line in fasta: + line = line.decode("utf-8") if is_gz else line + if line.startswith(">"): + sequences.add(line[1:].split(None, 1)[0]) + + return sequences def tab_delimited(file: str) -> float: @@ -47,26 +78,35 @@ def tab_delimited(file: str) -> float: return statistics.median(line.count("\\t") for line in data.split("\\n")) -def filter_gtf(fasta: str, gtf_in: str, filtered_gtf_out: str, skip_transcript_id_check: bool) -> None: +def filter_gtf( + fasta: str, gtf_in: str, filtered_gtf_out: str, skip_transcript_id_check: bool +) -> None: """Filter GTF file based on FASTA sequence names.""" if tab_delimited(gtf_in) != 8: raise ValueError("Invalid GTF file: Expected 9 tab-separated columns.") seq_names_in_genome = extract_fasta_seq_names(fasta) logger.info(f"Extracted chromosome sequence names from {fasta}") - logger.debug("All sequence IDs from FASTA: " + ", ".join(sorted(seq_names_in_genome))) + logger.debug( + "All sequence IDs from FASTA: " + ", ".join(sorted(seq_names_in_genome)) + ) seq_names_in_gtf = set() try: - with open(gtf_in) as gtf, open(filtered_gtf_out, "w") as out: + is_gz = gtf_in.endswith(".gz") + open_fn = gzip.open if is_gz else open + with open_fn(gtf_in) as gtf, open_fn(filtered_gtf_out, "wb" if is_gz else "w") as out: line_count = 0 for line in gtf: + line = line.decode("utf-8") if is_gz else line seq_name = line.split("\\t")[0] seq_names_in_gtf.add(seq_name) # Add sequence name to the set if seq_name in seq_names_in_genome: - if skip_transcript_id_check or re.search(r'transcript_id "([^"]+)"', line): - out.write(line) + if skip_transcript_id_check or re.search( + r'transcript_id "([^"]+)"', line + ): + out.write(line.encode() if is_gz else line) line_count += 1 if line_count == 0: @@ -77,18 +117,16 @@ def filter_gtf(fasta: str, gtf_in: str, filtered_gtf_out: str, skip_transcript_i return logger.debug("All sequence IDs from GTF: " + ", ".join(sorted(seq_names_in_gtf))) - logger.info(f"Extracted {line_count} matching sequences from {gtf_in} into {filtered_gtf_out}") + logger.info( + f"Extracted {line_count} matching sequences from {gtf_in} into {filtered_gtf_out}" + ) filter_gtf("${fasta}", "${gtf}", "${prefix}.${suffix}", False) # Versions -versions = { - "${task.process}": { - "python": platform.python_version() - } -} +versions = {"${task.process}": {"python": platform.python_version()}} with open("versions.yml", "w") as f: f.write(format_yaml_like(versions)) diff --git a/modules/nf-core/custom/gtffilter/tests/main.nf.test b/modules/nf-core/custom/gtffilter/tests/main.nf.test new file mode 100644 index 00000000..252d11a1 --- /dev/null +++ b/modules/nf-core/custom/gtffilter/tests/main.nf.test @@ -0,0 +1,115 @@ +nextflow_process { + + name "Test Process CUSTOM_GTFFILTER" + script "../main.nf" + process "CUSTOM_GTFFILTER" + + tag "modules" + tag "modules_nfcore" + tag "custom" + tag "custom/gtffilter" + + test("test_custom_gtffilter") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ] + input[1] = [ + [ id: 'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_custom_gtffilter_gzip") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ] + input[1] = [ + [ id: 'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_custom_gtffilter - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ] + input[1] = [ + [ id: 'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_custom_gtffilter_gzip - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ] + input[1] = [ + [ id: 'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } +} diff --git a/modules/nf-core/custom/gtffilter/tests/main.nf.test.snap b/modules/nf-core/custom/gtffilter/tests/main.nf.test.snap new file mode 100644 index 00000000..787dd42e --- /dev/null +++ b/modules/nf-core/custom/gtffilter/tests/main.nf.test.snap @@ -0,0 +1,134 @@ +{ + "test_custom_gtffilter_gzip": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.gtf:md5,aa8b2aa1e0b5fbbba3b04d471e1b0535" + ] + ], + "1": [ + "versions.yml:md5,39c43040514c93566d2e3dca39e54cf2" + ], + "gtf": [ + [ + { + "id": "test" + }, + "test.gtf:md5,aa8b2aa1e0b5fbbba3b04d471e1b0535" + ] + ], + "versions": [ + "versions.yml:md5,39c43040514c93566d2e3dca39e54cf2" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-07-15T14:23:11.091273747" + }, + "test_custom_gtffilter": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.gtf:md5,aa8b2aa1e0b5fbbba3b04d471e1b0535" + ] + ], + "1": [ + "versions.yml:md5,39c43040514c93566d2e3dca39e54cf2" + ], + "gtf": [ + [ + { + "id": "test" + }, + "test.gtf:md5,aa8b2aa1e0b5fbbba3b04d471e1b0535" + ] + ], + "versions": [ + "versions.yml:md5,39c43040514c93566d2e3dca39e54cf2" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-07-15T14:23:03.654104046" + }, + "test_custom_gtffilter_gzip - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,4547ffaa530b6d65b2dd1f607d7f85e3" + ], + "gtf": [ + [ + { + "id": "test" + }, + "test.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,4547ffaa530b6d65b2dd1f607d7f85e3" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-07-15T14:23:24.216284615" + }, + "test_custom_gtffilter - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,4547ffaa530b6d65b2dd1f607d7f85e3" + ], + "gtf": [ + [ + { + "id": "test" + }, + "test.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,4547ffaa530b6d65b2dd1f607d7f85e3" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-07-15T14:23:17.765499066" + } +} \ No newline at end of file diff --git a/modules/nf-core/custom/gtffilter/tests/tags.yml b/modules/nf-core/custom/gtffilter/tests/tags.yml new file mode 100644 index 00000000..34dda217 --- /dev/null +++ b/modules/nf-core/custom/gtffilter/tests/tags.yml @@ -0,0 +1,2 @@ +custom/gtffilter: + - "modules/nf-core/custom/gtffilter/**" diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 715ce125..76fe152d 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -1,13 +1,13 @@ -include { GTF_FILTER } from '../../modules/local/gtf_filter' -include { SEQKIT_SPLIT } from '../../modules/local/seqkit/split' -include { BOWTIE_BUILD } from '../../modules/nf-core/bowtie/build' -include { BOWTIE2_BUILD } from '../../modules/nf-core/bowtie2/build' -include { BWA_INDEX } from '../../modules/nf-core/bwa/index' -include { HISAT2_EXTRACTSPLICESITES } from '../../modules/nf-core/hisat2/extractsplicesites' -include { HISAT2_BUILD } from '../../modules/nf-core/hisat2/build' -include { STAR_GENOMEGENERATE } from '../../modules/nf-core/star/genomegenerate' -include { GAWK as CLEAN_FASTA } from '../../modules/nf-core/gawk' -include { SAMTOOLS_FAIDX } from '../../modules/nf-core/samtools/faidx' +include { CUSTOM_GTFFILTER as GTFFILTER } from '../../modules/nf-core/custom/gtffilter' +include { SEQKIT_SPLIT } from '../../modules/local/seqkit/split' +include { BOWTIE_BUILD } from '../../modules/nf-core/bowtie/build' +include { BOWTIE2_BUILD } from '../../modules/nf-core/bowtie2/build' +include { BWA_INDEX } from '../../modules/nf-core/bwa/index' +include { HISAT2_EXTRACTSPLICESITES } from '../../modules/nf-core/hisat2/extractsplicesites' +include { HISAT2_BUILD } from '../../modules/nf-core/hisat2/build' +include { STAR_GENOMEGENERATE } from '../../modules/nf-core/star/genomegenerate' +include { GAWK as CLEAN_FASTA } from '../../modules/nf-core/gawk' +include { SAMTOOLS_FAIDX } from '../../modules/nf-core/samtools/faidx' workflow PREPARE_GENOME { @@ -27,8 +27,8 @@ workflow PREPARE_GENOME { ch_versions = ch_versions.mix(CLEAN_FASTA.out.versions) } - GTF_FILTER(ch_fasta, ch_gtf) - ch_gtf = GTF_FILTER.out.filtered + GTFFILTER(ch_gtf, ch_fasta) + ch_gtf = GTFFILTER.out.gtf SEQKIT_SPLIT(ch_fasta) @@ -47,7 +47,7 @@ workflow PREPARE_GENOME { SAMTOOLS_FAIDX(ch_fasta, [[], []]) // Collect versions - ch_versions = ch_versions.mix(GTF_FILTER.out.versions, + ch_versions = ch_versions.mix(GTFFILTER.out.versions, SEQKIT_SPLIT.out.versions, BOWTIE_BUILD.out.versions, BOWTIE2_BUILD.out.versions, From 853e9dab978488d0347350297056d52cf6459eb2 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 15 Jul 2024 15:53:18 +0200 Subject: [PATCH 331/491] Rename GTFFILTER module accession --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 0885b37e..6252fa89 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -70,7 +70,7 @@ process { ] } - withName: GTF_FILTER { + withName: GTFFILTER { ext.suffix = "filtered.gtf" } From 73bf5e4998cc12f08b9ca8c34141eb7c62be5c85 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Mon, 15 Jul 2024 16:26:52 +0200 Subject: [PATCH 332/491] Update GTFFILTER module --- modules.json | 2 +- modules/nf-core/custom/gtffilter/main.nf | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules.json b/modules.json index 007ae30d..8a2d096a 100644 --- a/modules.json +++ b/modules.json @@ -82,7 +82,7 @@ }, "custom/gtffilter": { "branch": "master", - "git_sha": "7888e16f3c8678dfc5d59c899f79b7286271f177", + "git_sha": "a0aee18374b7f072aa0f89f4d66f5a3a9f8176d2", "installed_by": ["modules"] }, "custom/tx2gene": { diff --git a/modules/nf-core/custom/gtffilter/main.nf b/modules/nf-core/custom/gtffilter/main.nf index e921d94f..b682ff8c 100644 --- a/modules/nf-core/custom/gtffilter/main.nf +++ b/modules/nf-core/custom/gtffilter/main.nf @@ -12,8 +12,8 @@ process CUSTOM_GTFFILTER { tuple val(meta2), path(fasta) output: - tuple val(meta), path("*.gtf"), emit: gtf - path "versions.yml" , emit: versions + tuple val(meta), path("${prefix}.${suffix}"), emit: gtf + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when From 342964d9d51732bd68a0bf579de842880d68dbe9 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 1 Aug 2024 10:55:57 +0200 Subject: [PATCH 333/491] Add filter for circular RNAs to find_circ --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 40a6398c..ed733627 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -343,7 +343,7 @@ process { withName: '.*:FIND_CIRC:UNIFY' { // Keep only rows with UNAMBIGUOUS_BP and ANCHOR_UNIQUE in $18 - ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$18 ~ /UNAMBIGUOUS_BP/ && \$18 ~ /ANCHOR_UNIQUE/) { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 } }'" + ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$18 ~ /CIRCULAR/ && \$18 ~ /UNAMBIGUOUS_BP/ && \$18 ~ /ANCHOR_UNIQUE/) { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 } }'" ext.suffix = "find_circ.bed" publishDir = [ path: { "${params.outdir}/circrna_discovery/find_circ/${meta.id}" }, From 3be2733652701c021ebb08bcc5f6a9d3ded57f07 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 1 Aug 2024 10:57:48 +0200 Subject: [PATCH 334/491] Update comment --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index ed733627..ec811890 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -342,7 +342,7 @@ process { } withName: '.*:FIND_CIRC:UNIFY' { - // Keep only rows with UNAMBIGUOUS_BP and ANCHOR_UNIQUE in $18 + // Keep only rows with CIRCULAR, UNAMBIGUOUS_BP and ANCHOR_UNIQUE in $18 ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$18 ~ /CIRCULAR/ && \$18 ~ /UNAMBIGUOUS_BP/ && \$18 ~ /ANCHOR_UNIQUE/) { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 } }'" ext.suffix = "find_circ.bed" publishDir = [ From a66fcd3800bf3ae30a89394e4d1b3f155c542722 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 12 Jul 2024 10:53:44 +0200 Subject: [PATCH 335/491] Add error message for empty intersections --- modules/local/annotation/templates/annotation.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/local/annotation/templates/annotation.py b/modules/local/annotation/templates/annotation.py index 91121d78..20ea682c 100755 --- a/modules/local/annotation/templates/annotation.py +++ b/modules/local/annotation/templates/annotation.py @@ -41,7 +41,10 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: exon_boundary = int("${exon_boundary}") -df = pd.read_csv("${gtf_intersection}", sep="\\t", header=None, usecols=columns.keys()) +try: + df = pd.read_csv("${gtf_intersection}", sep="\\t", header=None, usecols=columns.keys()) +except pd.errors.EmptyDataError: + raise ValueError("Intersection between circRNAs and GTF file is empty.") df = df.rename(columns=columns) # Extract circRNAs without match From 02a19f2b6ba30cf16d2e42e71bb6c11aaf15bda2 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 12 Jul 2024 10:58:17 +0200 Subject: [PATCH 336/491] Add docs for GTF required attributes --- nextflow_schema.json | 1 + 1 file changed, 1 insertion(+) diff --git a/nextflow_schema.json b/nextflow_schema.json index c1b06562..64df9eb1 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -216,6 +216,7 @@ "fa_icon": "fas fa-address-book", "mimetype": "text/plain", "description": "Path to reference GTF file.", + "help_text": "This parameter is *mandatory* if `--genome` is not specified. Needs to contain the following attributes: `gene_id`, `transcript_id` and `gene_name`.", "pattern": "\\.gtf$" }, "mature": { From 2e3d66732edbf494379b54ac3c3d6839e5ce1a5c Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 12 Jul 2024 11:15:03 +0200 Subject: [PATCH 337/491] Add check for presence of attributes in annotation intersection --- modules/local/annotation/templates/annotation.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/local/annotation/templates/annotation.py b/modules/local/annotation/templates/annotation.py index 20ea682c..eb0aadd0 100755 --- a/modules/local/annotation/templates/annotation.py +++ b/modules/local/annotation/templates/annotation.py @@ -58,6 +58,13 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: # Convert attributes to a dictionary df['attributes'] = df['attributes'].apply(lambda row: dict([[value.strip(r'"') for value in entry.strip().split(' ', 1)] for entry in row.split(';') if entry])) +# Make sure all attributes are present +df_incomplete = df['attributes'].apply(lambda row: ", ".join([key for key in attributes if key not in row])) +if len(df_incomplete) > 0: + counts = df_incomplete.value_counts() + counts.name = 'count' + counts.index.name = 'missing' + raise ValueError(f"The following attributes are missing in the intersection file:\\n\\n{counts.to_frame()}") # Keep only the attributes we want df['attributes'] = df['attributes'].apply(lambda row: {key: row[key] for key in attributes if key in row}) # Convert attributes to columns From 3a8e88c84ababea4ce20b98eb3983b573326aea1 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 12 Jul 2024 11:53:03 +0200 Subject: [PATCH 338/491] Fix bug in missing attribute check --- modules/local/annotation/templates/annotation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/local/annotation/templates/annotation.py b/modules/local/annotation/templates/annotation.py index eb0aadd0..b0ff285b 100755 --- a/modules/local/annotation/templates/annotation.py +++ b/modules/local/annotation/templates/annotation.py @@ -60,6 +60,7 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: df['attributes'] = df['attributes'].apply(lambda row: dict([[value.strip(r'"') for value in entry.strip().split(' ', 1)] for entry in row.split(';') if entry])) # Make sure all attributes are present df_incomplete = df['attributes'].apply(lambda row: ", ".join([key for key in attributes if key not in row])) +df_incomplete = df_incomplete[df_incomplete != ""] if len(df_incomplete) > 0: counts = df_incomplete.value_counts() counts.name = 'count' From b0086537b4c8627c13616d57145fb91ec00c243b Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 1 Aug 2024 22:46:39 +0200 Subject: [PATCH 339/491] Implement Segemehl grouping --- conf/modules.config | 5 +++++ subworkflows/local/discovery/segemehl.nf | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index ec811890..233c766b 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -184,6 +184,11 @@ process { ] } + withName: '.*:SEGEMEHL:GROUP' { + ext.summary_col = 5 + ext.args = "-g 1,2,3,4,6 -o count" + } + withName: '.*:STAR2PASS:PASS_1' { ext.when = { params.tool.split(',').contains('circexplorer2') || params.tool.split(',').contains('circrna_finder') } ext.args = [ "", diff --git a/subworkflows/local/discovery/segemehl.nf b/subworkflows/local/discovery/segemehl.nf index 71669032..10ac9b4c 100644 --- a/subworkflows/local/discovery/segemehl.nf +++ b/subworkflows/local/discovery/segemehl.nf @@ -1,7 +1,7 @@ include { SEGEMEHL_INDEX as INDEX } from '../../../modules/nf-core/segemehl/index' include { SEGEMEHL_ALIGN as ALIGN } from '../../../modules/nf-core/segemehl/align' include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' - +include { BEDTOOLS_GROUPBY as GROUP } from '../../../modules/nf-core/bedtools/groupby' workflow SEGEMEHL { take: @@ -17,11 +17,14 @@ workflow SEGEMEHL { UNIFY( ALIGN.out.single_bed .map{ meta, bed -> [ meta + [tool: "segemehl"], bed ] }, [] ) + GROUP( UNIFY.out.output, 5 ) + ch_versions = ch_versions.mix(ALIGN.out.versions) ch_versions = ch_versions.mix(UNIFY.out.versions) + ch_versions = ch_versions.mix(GROUP.out.versions) emit: - bed = UNIFY.out.output + bed = GROUP.out.bed versions = ch_versions } From 9d799725f41a882c2da2fa38fee2e81ab2ad666e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 1 Aug 2024 22:47:45 +0200 Subject: [PATCH 340/491] Add bedtools groupby --- modules.json | 5 ++ .../nf-core/bedtools/groupby/environment.yml | 7 +++ modules/nf-core/bedtools/groupby/main.nf | 50 +++++++++++++++++++ modules/nf-core/bedtools/groupby/meta.yml | 47 +++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 modules/nf-core/bedtools/groupby/environment.yml create mode 100644 modules/nf-core/bedtools/groupby/main.nf create mode 100644 modules/nf-core/bedtools/groupby/meta.yml diff --git a/modules.json b/modules.json index 8a2d096a..36315754 100644 --- a/modules.json +++ b/modules.json @@ -10,6 +10,11 @@ "git_sha": "cdcdd5e3d806f0ff3983c40c69e0b07bb44ec299", "installed_by": ["modules"] }, + "bedtools/groupby": { + "branch": "master", + "git_sha": "3b248b84694d1939ac4bb33df84bf6233a34d668", + "installed_by": ["modules"] + }, "bedtools/intersect": { "branch": "master", "git_sha": "575e1bc54b083fb15e7dd8b5fcc40bea60e8ce83", diff --git a/modules/nf-core/bedtools/groupby/environment.yml b/modules/nf-core/bedtools/groupby/environment.yml new file mode 100644 index 00000000..dab99ea1 --- /dev/null +++ b/modules/nf-core/bedtools/groupby/environment.yml @@ -0,0 +1,7 @@ +name: bedtools_groupby +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::bedtools=2.31.1 diff --git a/modules/nf-core/bedtools/groupby/main.nf b/modules/nf-core/bedtools/groupby/main.nf new file mode 100644 index 00000000..063e7ba2 --- /dev/null +++ b/modules/nf-core/bedtools/groupby/main.nf @@ -0,0 +1,50 @@ +process BEDTOOLS_GROUPBY { + tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/bedtools:2.31.1--hf5e1c6e_0' : + 'biocontainers/bedtools:2.31.1--hf5e1c6e_0' }" + + input: + tuple val(meta), path(bed) + val(summary_col) + + output: + tuple val(meta), path('*.bed'), emit: bed + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}.grouped" + def summary_col = task.ext.summary_col ? "-c ${task.ext.summary_col}" : "-c 5" + if ("$bed" == "${prefix}.bed") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" + """ + bedtools \\ + groupby \\ + -i $bed \\ + ${summary_col} \\ + $args \\ + > ${prefix}.bed + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + bedtools: \$(bedtools --version | sed -e "s/bedtools v//g") + END_VERSIONS + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.bed + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + bedtools: \$(bedtools --version | sed -e "s/bedtools v//g") + END_VERSIONS + """ +} diff --git a/modules/nf-core/bedtools/groupby/meta.yml b/modules/nf-core/bedtools/groupby/meta.yml new file mode 100644 index 00000000..bcbc561a --- /dev/null +++ b/modules/nf-core/bedtools/groupby/meta.yml @@ -0,0 +1,47 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/yaml-schema.json +name: bedtools_groupby +description: Groups features in a BED file by given column(s) and computes summary statistics for each group to another column. +keywords: + - bed + - groupby + - bedtools +tools: + - bedtools: + description: | + A set of tools for genomic analysis tasks, specifically enabling genome arithmetic (merge, count, complement) on various file types. + documentation: https://bedtools.readthedocs.io/en/latest/content/tools/groupby.html + homepage: https://bedtools.readthedocs.io/en/latest/ + doi: 10.1093/bioinformatics/btq033 + licence: ["MIT"] +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - bed: + type: file + description: Input BED file + pattern: "*.{bed}" + - summary_column: + type: integer + description: Column to be summarized (1-based) +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - bed: + type: file + description: Grouped by bed file with combined features + pattern: "*.{bed}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@mashehu" +maintainers: + - "@mashehu" From 50a18178ce4709536c84ca33f775bf602c118356 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 1 Aug 2024 23:01:03 +0200 Subject: [PATCH 341/491] Fix segemehl grouping --- conf/modules.config | 18 ++++++++++++------ subworkflows/local/discovery/segemehl.nf | 14 +++++++++----- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 233c766b..df9fe0b3 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -171,10 +171,21 @@ process { ] } - withName: '.*:SEGEMEHL:UNIFY' { + withName: '.*:SEGEMEHL:EXTRACT' { // Keep only rows with ";C;" in column 4 // Print $1 $2 $3 $1:$2-$3 $5 $6 ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$4 ~ /;C;/) { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 } }'" + ext.suffix = "segemehl_extracted.bed" + } + + withName: '.*:SEGEMEHL:GROUP' { + ext.summary_col = 5 + ext.args = "-g 1,2,3,4,6 -o count" + ext.suffix = "segemehl_grouped.bed" + } + + withName: '.*:SEGEMEHL:UNIFY' { + ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$4, \$6, \$5 }'" ext.suffix = "segemehl.bed" publishDir = [ path: { "${params.outdir}/circrna_discovery/segemehl/${meta.id}" }, @@ -184,11 +195,6 @@ process { ] } - withName: '.*:SEGEMEHL:GROUP' { - ext.summary_col = 5 - ext.args = "-g 1,2,3,4,6 -o count" - } - withName: '.*:STAR2PASS:PASS_1' { ext.when = { params.tool.split(',').contains('circexplorer2') || params.tool.split(',').contains('circrna_finder') } ext.args = [ "", diff --git a/subworkflows/local/discovery/segemehl.nf b/subworkflows/local/discovery/segemehl.nf index 10ac9b4c..7c61e46d 100644 --- a/subworkflows/local/discovery/segemehl.nf +++ b/subworkflows/local/discovery/segemehl.nf @@ -1,7 +1,8 @@ include { SEGEMEHL_INDEX as INDEX } from '../../../modules/nf-core/segemehl/index' include { SEGEMEHL_ALIGN as ALIGN } from '../../../modules/nf-core/segemehl/align' -include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' +include { GAWK as EXTRACT } from '../../../modules/nf-core/gawk' include { BEDTOOLS_GROUPBY as GROUP } from '../../../modules/nf-core/bedtools/groupby' +include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' workflow SEGEMEHL { take: @@ -13,18 +14,21 @@ workflow SEGEMEHL { ch_versions = Channel.empty() index = index ?: INDEX( fasta ).index + ALIGN( reads, fasta, index ) - UNIFY( ALIGN.out.single_bed + EXTRACT( ALIGN.out.single_bed .map{ meta, bed -> [ meta + [tool: "segemehl"], bed ] }, [] ) - GROUP( UNIFY.out.output, 5 ) + GROUP( EXTRACT.out.output, 5 ) + UNIFY( GROUP.out.bed, [] ) ch_versions = ch_versions.mix(ALIGN.out.versions) - ch_versions = ch_versions.mix(UNIFY.out.versions) + ch_versions = ch_versions.mix(EXTRACT.out.versions) ch_versions = ch_versions.mix(GROUP.out.versions) + ch_versions = ch_versions.mix(UNIFY.out.versions) emit: - bed = GROUP.out.bed + bed = UNIFY.out.output versions = ch_versions } From 9fc67a1ff6f90475a2edb667ef71aaf2e22a3fa9 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 1 Aug 2024 23:17:32 +0200 Subject: [PATCH 342/491] Implement ordering of segemehl results --- conf/modules.config | 5 +++++ subworkflows/local/discovery/segemehl.nf | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index df9fe0b3..8fe2a0ea 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -178,6 +178,11 @@ process { ext.suffix = "segemehl_extracted.bed" } + withName: '.*:SEGEMEHL:SORT' { + ext.args = "-k1,1 -k2,2n -k3,3n -k4,4 -k6,6" + ext.suffix = "segemehl_sorted.bed" + } + withName: '.*:SEGEMEHL:GROUP' { ext.summary_col = 5 ext.args = "-g 1,2,3,4,6 -o count" diff --git a/subworkflows/local/discovery/segemehl.nf b/subworkflows/local/discovery/segemehl.nf index 7c61e46d..9e8e2c0d 100644 --- a/subworkflows/local/discovery/segemehl.nf +++ b/subworkflows/local/discovery/segemehl.nf @@ -1,6 +1,7 @@ include { SEGEMEHL_INDEX as INDEX } from '../../../modules/nf-core/segemehl/index' include { SEGEMEHL_ALIGN as ALIGN } from '../../../modules/nf-core/segemehl/align' include { GAWK as EXTRACT } from '../../../modules/nf-core/gawk' +include { GNU_SORT as SORT } from '../../../modules/nf-core/gnu/sort' include { BEDTOOLS_GROUPBY as GROUP } from '../../../modules/nf-core/bedtools/groupby' include { GAWK as UNIFY } from '../../../modules/nf-core/gawk' @@ -19,11 +20,13 @@ workflow SEGEMEHL { EXTRACT( ALIGN.out.single_bed .map{ meta, bed -> [ meta + [tool: "segemehl"], bed ] }, [] ) - GROUP( EXTRACT.out.output, 5 ) + SORT( EXTRACT.out.output ) + GROUP( SORT.out.sorted, 5 ) UNIFY( GROUP.out.bed, [] ) ch_versions = ch_versions.mix(ALIGN.out.versions) ch_versions = ch_versions.mix(EXTRACT.out.versions) + ch_versions = ch_versions.mix(SORT.out.versions) ch_versions = ch_versions.mix(GROUP.out.versions) ch_versions = ch_versions.mix(UNIFY.out.versions) From 08d56cc44cc1a41937ef643137dde5e32a210996 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 1 Aug 2024 23:17:44 +0200 Subject: [PATCH 343/491] Implement check for duplicates in tool results --- .../merge_tools/templates/merge_tools.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/modules/local/count_matrix/merge_tools/templates/merge_tools.py b/modules/local/count_matrix/merge_tools/templates/merge_tools.py index debb85bf..8e514993 100755 --- a/modules/local/count_matrix/merge_tools/templates/merge_tools.py +++ b/modules/local/count_matrix/merge_tools/templates/merge_tools.py @@ -28,7 +28,19 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: raise ValueError(f"Invalid value for duplicates_fun: {duplicates_fun}") columns = ['chr', 'start', 'end', 'name', 'count', 'strand'] -dfs = [pd.read_csv(bed, sep='\t', header=None, names=columns) for bed in "${beds}".split()] +columns_no_count = ['chr', 'start', 'end', 'name', 'strand'] +dfs = [] + +for bed_path in "${beds}".split(): + df = pd.read_csv(bed_path, sep='\\t', header=None, names=columns) + + # If there are duplicate rows, throw an error + if df.duplicated(subset=columns_no_count).any(): + print(df[df.duplicated(subset=columns_no_count)]) + raise ValueError("Duplicate rows found in input BED file: " + bed_path) + + dfs.append(df) + df = pd.concat(dfs) df['tool_count'] = 1 From 7d470e60c0690fd3a91550f480db924fab0a4a91 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 11:18:25 +0200 Subject: [PATCH 344/491] Implement custom BSJome generation --- conf/modules.config | 32 +++++++++++++++++++ subworkflows/local/circrna_discovery.nf | 41 ++++++++++++++++++++----- 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 8fe2a0ea..45a698b3 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -582,6 +582,38 @@ process { ext.suffix = {"${meta.tool}.filtered.bed"} } + withName: 'MASK_SCORES' { + // Take bed file and replace the score column with a dot + ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$4, \".\", \$6 }'" + ext.suffix = {"${meta.tool}.masked.bed"} + } + + withName: 'CONCAT_TOOLS_PER_SAMPLE' { + // GNU sort by columns 1,2,3,4,6 + ext.args = "-k1,1 -k2,2n -k3,3n -k4,4 -k6,6" + ext.suffix = {"sorted.bed"} + } + + withName: 'COUNT_TOOLS' { + // Count the number of tools that support each circRNA + ext.summary_col = 5 + ext.args = "-g 1,2,3,4,6 -o count" + ext.suffix = {"grouped.bed"} + } + + withName: 'FILTER_MIN_TOOLS' { + // Keep only rows with at least the minimum number of tools + // Replace the score column with a dot + ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$5 >= ${params.tool_filter}) { print \$1, \$2, \$3, \$4, \".\", \$6 } }'" + ext.suffix = {"filtered.bed"} + } + + withName: 'CONCAT_SAMPLES' { + // GNU sort by columns 1,2,3,4,6 + ext.args = "-k1,1 -k2,2n -k3,3n -k4,4 -k6,6 -u" + ext.suffix = {"sorted.bed"} + } + withName: UPSET_SAMPLES { ext.when = { params.tool.split(',').length > 1 } } diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 2a163ce7..6e682f06 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -1,11 +1,16 @@ // MODULES -include { GAWK as FILTER_BSJS } from '../../modules/nf-core/gawk' -include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools' -include { MERGE_SAMPLES } from '../../modules/local/count_matrix/merge_samples' -include { UPSET as UPSET_SAMPLES } from '../../modules/local/upset' -include { UPSET as UPSET_ALL } from '../../modules/local/upset' -include { BEDTOOLS_GETFASTA } from '../../modules/nf-core/bedtools/getfasta' -include { GAWK as ADD_BACKSPLICE } from '../../modules/nf-core/gawk' +include { GAWK as FILTER_BSJS } from '../../modules/nf-core/gawk' +include { GAWK as MASK_SCORES } from '../../modules/nf-core/gawk' +include { GNU_SORT as CONCAT_TOOLS_PER_SAMPLE } from '../../modules/nf-core/gnu/sort' +include { BEDTOOLS_GROUPBY as COUNT_TOOLS } from '../../modules/nf-core/bedtools/groupby' +include { GAWK as FILTER_MIN_TOOLS } from '../../modules/nf-core/gawk' +include { GNU_SORT as CONCAT_SAMPLES } from '../../modules/nf-core/gnu/sort' +include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools' +include { MERGE_SAMPLES } from '../../modules/local/count_matrix/merge_samples' +include { UPSET as UPSET_SAMPLES } from '../../modules/local/upset' +include { UPSET as UPSET_ALL } from '../../modules/local/upset' +include { BEDTOOLS_GETFASTA } from '../../modules/nf-core/bedtools/getfasta' +include { GAWK as ADD_BACKSPLICE } from '../../modules/nf-core/gawk' // SUBWORKFLOWS include { SEGEMEHL } from './discovery/segemehl' @@ -111,6 +116,28 @@ workflow CIRCRNA_DISCOVERY { // CREATE COUNT MATRIX // + MASK_SCORES( ch_bed, [] ) + ch_versions = ch_versions.mix(MASK_SCORES.out.versions) + + CONCAT_TOOLS_PER_SAMPLE( + MASK_SCORES.out.output.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple() + ) + ch_versions = ch_versions.mix(CONCAT_TOOLS_PER_SAMPLE.out.versions) + + COUNT_TOOLS( CONCAT_TOOLS_PER_SAMPLE.out.sorted, 5 ) + ch_versions = ch_versions.mix(COUNT_TOOLS.out.versions) + + FILTER_MIN_TOOLS( COUNT_TOOLS.out.bed, [] ) + ch_versions = ch_versions.mix(FILTER_MIN_TOOLS.out.versions) + + ch_bsjome_per_sample = FILTER_MIN_TOOLS.out.output + + CONCAT_SAMPLES( + ch_bsjome_per_sample.map{ meta, bed -> [[id: "all"], bed] }.groupTuple() + ) + ch_versions = ch_versions.mix(CONCAT_SAMPLES.out.versions) + ch_bsjome = CONCAT_SAMPLES.out.sorted + MERGE_TOOLS( ch_bed.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), tools_selected.size() > 1 ? tool_filter : 1, duplicates_fun ) MERGE_SAMPLES( MERGE_TOOLS.out.merged.map{ meta, bed -> bed }.collect() ) From 8719a3f821e31dbc8be68fcfbd554eeb7411de89 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 16:00:02 +0200 Subject: [PATCH 345/491] Extract annotation from discovery --- conf/modules.config | 6 -- modules/local/annotation/main.nf | 2 +- .../local/{discovery => }/annotation.nf | 43 ++++------- subworkflows/local/circrna_discovery.nf | 76 ++++++++----------- subworkflows/local/mirna_prediction.nf | 12 ++- workflows/circrna/main.nf | 33 +++++--- 6 files changed, 75 insertions(+), 97 deletions(-) rename subworkflows/local/{discovery => }/annotation.nf (51%) diff --git a/conf/modules.config b/conf/modules.config index 45a698b3..8f0bfc8d 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -655,12 +655,6 @@ process { withName: ADD_BACKSPLICE { ext.args = "'{ if (/^>/) { print \$0 } else { start = substr(\$0, 1, 25); print \$0 start } }'" ext.suffix = "backspliced.fa" - publishDir = [ - path: { "${params.outdir}/circrna_discovery/${meta.tool}/${meta.id}" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - pattern: "*.backspliced.fa" - ] } withName: COMBINE_TRANSCRIPTOME_GTFS { diff --git a/modules/local/annotation/main.nf b/modules/local/annotation/main.nf index 1f20cc72..7a698e40 100644 --- a/modules/local/annotation/main.nf +++ b/modules/local/annotation/main.nf @@ -1,5 +1,5 @@ process ANNOTATION { - tag "$meta.id:$meta.tool" + tag "$meta.id" label 'process_single' conda "${moduleDir}/environment.yml" diff --git a/subworkflows/local/discovery/annotation.nf b/subworkflows/local/annotation.nf similarity index 51% rename from subworkflows/local/discovery/annotation.nf rename to subworkflows/local/annotation.nf index da2c7b99..f1887d93 100644 --- a/subworkflows/local/discovery/annotation.nf +++ b/subworkflows/local/annotation.nf @@ -1,31 +1,33 @@ -include { BEDTOOLS_INTERSECT as INTERSECT_GTF } from '../../../modules/nf-core/bedtools/intersect' -include { ANNOTATION as ANNOTATE } from '../../../modules/local/annotation' -include { GAWK as INGEST_DATABASE_NAMES } from '../../../modules/nf-core/gawk' -include { GNU_SORT as COMBINE_DATABASES } from '../../../modules/nf-core/gnu/sort' -include { BEDTOOLS_INTERSECT as INTERSECT_DATABASE } from '../../../modules/nf-core/bedtools/intersect' -include { GAWK as CLEAN_DATABASE_ANNOTATION } from '../../../modules/nf-core/gawk' -include { GNU_SORT as COMBINE_BEDS } from '../../../modules/nf-core/gnu/sort' -include { GAWK as REMOVE_SCORE_STRAND } from '../../../modules/nf-core/gawk' -include { GNU_SORT as COMBINE_GTFS } from '../../../modules/nf-core/gnu/sort' +include { BEDTOOLS_INTERSECT as INTERSECT_GTF } from '../../modules/nf-core/bedtools/intersect' +include { GAWK as INGEST_DATABASE_NAMES } from '../../modules/nf-core/gawk' +include { GNU_SORT as COMBINE_DATABASES } from '../../modules/nf-core/gnu/sort' +include { BEDTOOLS_INTERSECT as INTERSECT_DATABASE } from '../../modules/nf-core/bedtools/intersect' +include { ANNOTATION as ANNOTATE } from '../../modules/local/annotation' workflow ANNOTATION { take: regions - gtf + ch_gtf exon_boundary ch_annotation main: ch_versions = Channel.empty() - INTERSECT_GTF( regions.combine(gtf), [[], []] ) + INTERSECT_GTF( regions.combine(ch_gtf.map{meta, gtf -> gtf}), [[], []] ) + ch_versions = ch_versions.mix(INTERSECT_GTF.out.versions) + INGEST_DATABASE_NAMES( ch_annotation, [] ) + ch_versions = ch_versions.mix(INGEST_DATABASE_NAMES.out.versions) + INTERSECT_DATABASE( regions.combine(INGEST_DATABASE_NAMES.out.output) .map{ meta1, regions, meta2, database -> [[id: "${meta1.id}-${meta2.id}", original_meta: meta1, min_overlap: meta2.min_overlap], regions, database] }, [[], []]) + ch_versions = ch_versions.mix(INTERSECT_DATABASE.out.versions) + ANNOTATE( INTERSECT_GTF.out.intersect .join(INTERSECT_DATABASE.out.intersect @@ -33,26 +35,11 @@ workflow ANNOTATION { .groupTuple(), remainder: true) .map{ meta, gtf_intersection, db_intersections -> [meta, gtf_intersection, db_intersections ?: []]}, exon_boundary ) - - ch_bed_merged = ANNOTATE.out.bed.filter{ meta, bed -> meta.tool == "merged" } - ch_gtf_merged = ANNOTATE.out.gtf.filter{ meta, gtf -> meta.tool == "merged" } - - COMBINE_BEDS(ch_bed_merged.map{ meta, bed -> bed}.collect().map{[[id: "annotation"], it]}) - REMOVE_SCORE_STRAND( COMBINE_BEDS.out.sorted, []) - COMBINE_GTFS(ch_gtf_merged.map{ meta, gtf -> gtf}.collect().map{[[id: "annotation"], it]}) - - ch_versions = ch_versions.mix(INTERSECT_GTF.out.versions) - ch_versions = ch_versions.mix(INGEST_DATABASE_NAMES.out.versions) - ch_versions = ch_versions.mix(INTERSECT_DATABASE.out.versions) ch_versions = ch_versions.mix(ANNOTATE.out.versions) - ch_versions = ch_versions.mix(COMBINE_BEDS.out.versions) - ch_versions = ch_versions.mix(REMOVE_SCORE_STRAND.out.versions) - ch_versions = ch_versions.mix(COMBINE_GTFS.out.versions) emit: - merged_bed = ch_bed_merged - bed = REMOVE_SCORE_STRAND.out.output - gtf = COMBINE_GTFS.out.sorted + bed = ANNOTATE.out.bed + gtf = ANNOTATE.out.gtf versions = ch_versions } diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 6e682f06..35205ac8 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -5,12 +5,9 @@ include { GNU_SORT as CONCAT_TOOLS_PER_SAMPLE } from '../../modules/nf-core/gnu/ include { BEDTOOLS_GROUPBY as COUNT_TOOLS } from '../../modules/nf-core/bedtools/groupby' include { GAWK as FILTER_MIN_TOOLS } from '../../modules/nf-core/gawk' include { GNU_SORT as CONCAT_SAMPLES } from '../../modules/nf-core/gnu/sort' -include { MERGE_TOOLS } from '../../modules/local/count_matrix/merge_tools' -include { MERGE_SAMPLES } from '../../modules/local/count_matrix/merge_samples' include { UPSET as UPSET_SAMPLES } from '../../modules/local/upset' include { UPSET as UPSET_ALL } from '../../modules/local/upset' include { BEDTOOLS_GETFASTA } from '../../modules/nf-core/bedtools/getfasta' -include { GAWK as ADD_BACKSPLICE } from '../../modules/nf-core/gawk' // SUBWORKFLOWS include { SEGEMEHL } from './discovery/segemehl' @@ -21,7 +18,6 @@ include { FIND_CIRC } from './discovery/find_circ' include { CIRIQUANT } from './discovery/ciriquant' include { DCC } from './discovery/dcc' include { MAPSPLICE } from './discovery/mapsplice' -include { ANNOTATION } from './discovery/annotation' workflow CIRCRNA_DISCOVERY { @@ -35,11 +31,7 @@ workflow CIRCRNA_DISCOVERY { chromosomes hisat2_index star_index - ch_annotation bsj_reads - tool_filter - duplicates_fun - exon_boundary main: ch_versions = Channel.empty() @@ -113,11 +105,12 @@ workflow CIRCRNA_DISCOVERY { ch_versions = ch_versions.mix(FILTER_BSJS.out.versions) // - // CREATE COUNT MATRIX + // MERGE BED FILES // MASK_SCORES( ch_bed, [] ) ch_versions = ch_versions.mix(MASK_SCORES.out.versions) + ch_bsj_bed_per_sample_tool = MASK_SCORES.out.output CONCAT_TOOLS_PER_SAMPLE( MASK_SCORES.out.output.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple() @@ -129,24 +122,13 @@ workflow CIRCRNA_DISCOVERY { FILTER_MIN_TOOLS( COUNT_TOOLS.out.bed, [] ) ch_versions = ch_versions.mix(FILTER_MIN_TOOLS.out.versions) - - ch_bsjome_per_sample = FILTER_MIN_TOOLS.out.output + ch_bsj_bed_per_sample = FILTER_MIN_TOOLS.out.output CONCAT_SAMPLES( - ch_bsjome_per_sample.map{ meta, bed -> [[id: "all"], bed] }.groupTuple() + ch_bsj_bed_per_sample.map{ meta, bed -> [[id: "all"], bed] }.groupTuple() ) ch_versions = ch_versions.mix(CONCAT_SAMPLES.out.versions) - ch_bsjome = CONCAT_SAMPLES.out.sorted - - MERGE_TOOLS( ch_bed.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple(), - tools_selected.size() > 1 ? tool_filter : 1, duplicates_fun ) - MERGE_SAMPLES( MERGE_TOOLS.out.merged.map{ meta, bed -> bed }.collect() ) - - ch_bed_incl_merged = ch_bed.mix( - MERGE_TOOLS.out.merged.map{ meta, bed -> [meta + [tool: "merged"], bed] }) - - ch_versions = ch_versions.mix(MERGE_TOOLS.out.versions) - ch_versions = ch_versions.mix(MERGE_SAMPLES.out.versions) + ch_bsj_bed_combined = CONCAT_SAMPLES.out.sorted // // UPSET PLOTS @@ -155,40 +137,42 @@ workflow CIRCRNA_DISCOVERY { UPSET_SAMPLES( ch_bed.map{ meta, bed -> [meta.id, meta.tool, bed]} .groupTuple() .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) + ch_multiqc_files = ch_multiqc_files.mix(UPSET_SAMPLES.out.multiqc) + ch_versions = ch_versions.mix(UPSET_SAMPLES.out.versions) + UPSET_ALL( ch_bed.map{ meta, bed -> ["all", meta.tool, bed] } .groupTuple() .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) - - ch_multiqc_files = ch_multiqc_files.mix(UPSET_SAMPLES.out.multiqc) ch_multiqc_files = ch_multiqc_files.mix(UPSET_ALL.out.multiqc) - ch_versions = ch_versions.mix(UPSET_SAMPLES.out.versions) ch_versions = ch_versions.mix(UPSET_ALL.out.versions) - // - // ANNOTATION WORKFLOW: - // - - ANNOTATION( ch_bed_incl_merged, gtf, exon_boundary, ch_annotation ) - ch_versions = ch_versions.mix(ANNOTATION.out.versions) - // // FASTA WORKFLOW: // - BEDTOOLS_GETFASTA( ANNOTATION.out.merged_bed, fasta ) - ADD_BACKSPLICE( BEDTOOLS_GETFASTA.out.fasta, []) - + BEDTOOLS_GETFASTA( + ch_bsj_bed_combined.mix(ch_bsj_bed_per_sample).mix(ch_bsj_bed_per_sample_tool), + fasta + ) ch_versions = ch_versions.mix(BEDTOOLS_GETFASTA.out.versions) - ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) + + ch_bsj_fasta = BEDTOOLS_GETFASTA.out.fasta.branch{ + meta, fasta -> + combined: meta.id == 'all' + per_sample_tool: meta.containsKey('tool') + per_sample: true + } emit: - circrna_bed12 = ANNOTATION.out.merged_bed - fasta = ADD_BACKSPLICE.out.output - annotation_bed = ANNOTATION.out.bed - annotation_gtf = ANNOTATION.out.gtf - counts_bed = MERGE_SAMPLES.out.counts_bed - counts_tsv = MERGE_SAMPLES.out.counts_tsv - - multiqc_files = ch_multiqc_files - versions = ch_versions + bsj_bed_combined = ch_bsj_bed_combined + bsj_fasta_combined = ch_bsj_fasta.combined + + bsj_bed_per_sample = ch_bsj_bed_per_sample + bsj_fasta_per_sample = ch_bsj_fasta.per_sample + + bsj_bed_per_sample_tool = ch_bsj_bed_per_sample_tool + bsj_fasta_per_sample_tool = ch_bsj_fasta.per_sample_tool + + multiqc_files = ch_multiqc_files + versions = ch_versions } diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index cdd6f86d..1bf7623f 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -1,7 +1,8 @@ -include { TARGETSCAN_DATABASE } from '../../modules/local/targetscan/database/main' -include { TARGETSCAN } from '../../modules/local/targetscan/predict/main' -include { MIRANDA } from '../../modules/nf-core/miranda/main' -include { MIRNA_TARGETS } from '../../modules/local/mirna_targets/main' +include { GAWK as ADD_BACKSPLICE } from '../../modules/nf-core/gawk' +include { TARGETSCAN_DATABASE } from '../../modules/local/targetscan/database/main' +include { TARGETSCAN } from '../../modules/local/targetscan/predict/main' +include { MIRANDA } from '../../modules/nf-core/miranda/main' +include { MIRNA_TARGETS } from '../../modules/local/mirna_targets/main' workflow MIRNA_PREDICTION{ @@ -13,6 +14,9 @@ workflow MIRNA_PREDICTION{ main: ch_versions = Channel.empty() + ADD_BACKSPLICE( circrna_fasta, [] ) + ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) + // // TARGETSCAN WORKFLOW: // diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 0d852ae7..aa7f4ea3 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -29,6 +29,7 @@ include { validateInputSamplesheet } from '../../subworkflows/local/util include { softwareVersionsToYAML } from '../../subworkflows/nf-core/utils_nfcore_pipeline' include { PREPARE_GENOME } from '../../subworkflows/local/prepare_genome' include { CIRCRNA_DISCOVERY } from '../../subworkflows/local/circrna_discovery' +include { ANNOTATION } from '../../subworkflows/local/annotation' include { QUANTIFICATION } from '../../subworkflows/local/quantification' include { MIRNA_PREDICTION } from '../../subworkflows/local/mirna_prediction' include { STATISTICAL_TESTS } from '../../subworkflows/local/statistical_tests' @@ -145,27 +146,35 @@ workflow CIRCRNA { chromosomes, hisat2_index, star_index, - ch_annotation, params.bsj_reads, - params.tool_filter, - params.duplicates_fun, - params.exon_boundary ) ch_multiqc_files = ch_multiqc_files.mix(CIRCRNA_DISCOVERY.out.multiqc_files) ch_versions = ch_versions.mix(CIRCRNA_DISCOVERY.out.versions) // - // 3. Quantification + // 3. circRNA Annotation + // + + ANNOTATION( + CIRCRNA_DISCOVERY.out.bsj_bed_combined, + ch_gtf, + params.exon_boundary, + ch_annotation + ) + ch_versions = ch_versions.mix(ANNOTATION.out.versions) + + // + // 4. circRNA quantification // QUANTIFICATION( ch_gtf, ch_fasta, - CIRCRNA_DISCOVERY.out.counts_bed, + CIRCRNA_DISCOVERY.out.bsj_bed_combined, FASTQC_TRIMGALORE.out.reads, - CIRCRNA_DISCOVERY.out.annotation_bed, - CIRCRNA_DISCOVERY.out.annotation_gtf, + ANNOTATION.out.bed, + ANNOTATION.out.gtf, params.bootstrap_samples, ch_phenotype, PREPARE_GENOME.out.faidx @@ -174,19 +183,19 @@ workflow CIRCRNA { ch_versions = ch_versions.mix(QUANTIFICATION.out.versions) // - // 4. miRNA prediction + // 5. miRNA prediction // if (params.mature) { MIRNA_PREDICTION( - CIRCRNA_DISCOVERY.out.fasta, - CIRCRNA_DISCOVERY.out.circrna_bed12, + CIRCRNA_DISCOVERY.out.bsj_fasta_combined, + ANNOTATION.out.bed, ch_mature ) ch_versions = ch_versions.mix(MIRNA_PREDICTION.out.versions) } // - // 5. Statistical tests + // 6. Statistical tests // STATISTICAL_TESTS( From 8509cb015306e64c62aee5eb2a8454629b559a66 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 16:22:49 +0200 Subject: [PATCH 346/491] Fix bug in tool filtering --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 8f0bfc8d..4efbd418 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -604,7 +604,7 @@ process { withName: 'FILTER_MIN_TOOLS' { // Keep only rows with at least the minimum number of tools // Replace the score column with a dot - ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$5 >= ${params.tool_filter}) { print \$1, \$2, \$3, \$4, \".\", \$6 } }'" + ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$6 >= ${params.tool_filter}) { print \$1, \$2, \$3, \$4, \".\", \$5 } }'" ext.suffix = {"filtered.bed"} } From d26712ef1e433de1aaf34751d1331e821399b91f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 17:15:53 +0200 Subject: [PATCH 347/491] Fix saveAs conditions --- conf/modules.config | 103 +++++++++++++++----------------------------- 1 file changed, 35 insertions(+), 68 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 4efbd418..41e0dd13 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -65,8 +65,7 @@ process { publishDir = [ path: { "${params.outdir}/references/clean_fasta" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_reference + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] } @@ -79,8 +78,7 @@ process { publishDir = [ path: { "${params.outdir}/references/chromosomes" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_reference + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] } @@ -89,8 +87,7 @@ process { publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_reference + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] } @@ -99,8 +96,7 @@ process { publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_reference + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] } @@ -109,8 +105,7 @@ process { publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_reference + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] } @@ -119,8 +114,7 @@ process { publishDir = [ path: { "${params.outdir}/references/index/hisat2" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_reference + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] } @@ -129,8 +123,7 @@ process { publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_reference + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] } @@ -142,8 +135,7 @@ process { publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_reference + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] } @@ -153,8 +145,7 @@ process { publishDir = [ path: { "${params.outdir}/references/index/segemehl" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_reference + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] } @@ -164,10 +155,9 @@ process { "-S" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/segemehl/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/segemehl/raw" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -193,7 +183,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$4, \$6, \$5 }'" ext.suffix = "segemehl.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/segemehl/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/segemehl/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.segemehl.bed" @@ -216,8 +206,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/star/1st_pass" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -225,8 +214,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/star/sjdb" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -246,8 +234,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/star/2nd_pass" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -259,8 +246,7 @@ process { publishDir = [ path: { "${params.outdir}/references/circexplorer2" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_reference + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] } @@ -268,8 +254,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates/${meta.id}" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -277,8 +262,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates/${meta.id}" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -297,8 +281,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/circrna_finder/intermediates/${meta.id}" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null }, pattern: "*.bed" ] } @@ -321,8 +304,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -332,8 +314,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -341,8 +322,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -352,8 +332,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -373,8 +352,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/ciriquant/intermediates/${meta.id}" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -409,8 +387,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate1/1st_pass" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -418,8 +395,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate1/sjdb" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -440,8 +416,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate1/2nd_pass" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -461,8 +436,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate2/1st_pass" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -470,8 +444,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate2/sjdb" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -492,8 +465,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate2/2nd_pass" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -501,8 +473,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/dcc/intermediates/${meta.id}" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -525,8 +496,7 @@ process { publishDir = [ path: { "${params.outdir}/references/mapsplice" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_reference + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] } @@ -542,8 +512,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -551,8 +520,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } @@ -560,8 +528,7 @@ process { publishDir = [ path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - enabled: params.save_intermediates + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] } From b45cea81abfcab53e8925a6dd14e93d7a47ad59e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 17:28:34 +0200 Subject: [PATCH 348/491] Fix some output definitions --- conf/modules.config | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 41e0dd13..7ae54354 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -604,24 +604,22 @@ process { ext.suffix = "annotated.bed" } - withName: '.*:ANNOTATION:COMBINE_BEDS' { - ext.args = "-k 1,1 -k2,2n -k3,3n -u" - ext.suffix = "combined.bed" - } - - withName: '.*:ANNOTATION:COMBINE_GTFS' { - ext.args = "-k 1,1 -k4,4n -k5,5n -u" - ext.suffix = "combined.gtf" - } - - withName: '.*:ANNOTATION:REMOVE_SCORE_STRAND' { - ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3, \".\", \".\", \$7, \$8, \$9, \$10, \$11 }'" - ext.suffix = "tidy.bed" + withName: '.*:ANNOTATION:ANNOTATE' { + publishDir = [ + path: { "${params.outdir}/annotation" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] } withName: ADD_BACKSPLICE { ext.args = "'{ if (/^>/) { print \$0 } else { start = substr(\$0, 1, 25); print \$0 start } }'" ext.suffix = "backspliced.fa" + publishDir = [ + path: { "${params.outdir}/mirna_prediction" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] } withName: COMBINE_TRANSCRIPTOME_GTFS { From 11892e281e452404ce181976e0d1b6e781303b14 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 17:39:04 +0200 Subject: [PATCH 349/491] Add per-sample and combined output directories for discovery --- conf/modules.config | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 7ae54354..ac71479e 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -565,7 +565,12 @@ process { // Count the number of tools that support each circRNA ext.summary_col = 5 ext.args = "-g 1,2,3,4,6 -o count" - ext.suffix = {"grouped.bed"} + ext.suffix = {"tool_counts.bed"} + publishDir = [ + path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] } withName: 'FILTER_MIN_TOOLS' { @@ -573,20 +578,40 @@ process { // Replace the score column with a dot ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$6 >= ${params.tool_filter}) { print \$1, \$2, \$3, \$4, \".\", \$5 } }'" ext.suffix = {"filtered.bed"} + publishDir = [ + path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] } withName: 'CONCAT_SAMPLES' { // GNU sort by columns 1,2,3,4,6 ext.args = "-k1,1 -k2,2n -k3,3n -k4,4 -k6,6 -u" - ext.suffix = {"sorted.bed"} + ext.suffix = {"combined.bed"} + publishDir = [ + path: { "${params.outdir}/circrna_discovery/combined" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] } withName: UPSET_SAMPLES { ext.when = { params.tool.split(',').length > 1 } + publishDir = [ + path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] } withName: UPSET_ALL { ext.when = { params.tool.split(',').length > 1 } + publishDir = [ + path: { "${params.outdir}/circrna_discovery/combined" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] } withName: '.*:ANNOTATION:INTERSECT_GTF' { From a0f3e731060212f14efab1c8ec5dbcb7ed3f44d0 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 17:44:07 +0200 Subject: [PATCH 350/491] Add tools subdirectory to discovery outdir --- conf/modules.config | 58 ++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index ac71479e..21241788 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -155,7 +155,7 @@ process { "-S" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/segemehl/raw" }, + path: { "${params.outdir}/circrna_discovery/tools/segemehl/raw" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -183,7 +183,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$4, \$6, \$5 }'" ext.suffix = "segemehl.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/segemehl/unified" }, + path: { "${params.outdir}/circrna_discovery/tools/segemehl/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.segemehl.bed" @@ -204,7 +204,7 @@ process { "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/star/1st_pass" }, + path: { "${params.outdir}/circrna_discovery/tools/star/1st_pass" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -212,7 +212,7 @@ process { withName: '.*:STAR2PASS:SJDB' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/star/sjdb" }, + path: { "${params.outdir}/circrna_discovery/tools/star/sjdb" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -232,7 +232,7 @@ process { "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/star/2nd_pass" }, + path: { "${params.outdir}/circrna_discovery/tools/star/2nd_pass" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -252,7 +252,7 @@ process { withName: '.*:CIRCEXPLORER2:PARSE' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/circexplorer2/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -260,7 +260,7 @@ process { withName: '.*:CIRCEXPLORER2:ANNOTATE' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/circexplorer2/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/circexplorer2/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -270,7 +270,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$13, \$6 }'" ext.suffix = "circexplorer2.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/circexplorer2/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/circexplorer2/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.circexplorer2.bed" @@ -279,7 +279,7 @@ process { withName: '.*:CIRCRNA_FINDER:MAIN' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/circrna_finder/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/circrna_finder/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null }, pattern: "*.bed" @@ -290,7 +290,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 }'" ext.suffix = "circrna_finder.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/circrna_finder/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/circrna_finder/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.circrna_finder.bed" @@ -302,7 +302,7 @@ process { (!meta.strandedness || meta.strandedness == 'unstranded' || meta.strandedness == 'auto' ? '' : meta.strandedness == 'forward' ? ' --norc' : ' --nofw') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -312,7 +312,7 @@ process { ext.prefix = { "${meta.id}_unmapped" } ext.args = "-hf 4" publishDir = [ - path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -320,7 +320,7 @@ process { withName: '.*:FIND_CIRC:ANCHORS' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -330,7 +330,7 @@ process { ext.args = { !meta.strandedness || meta.strandedness == 'unstranded' || meta.strandedness == 'auto' ? '' : meta.strandedness == 'forward' ? ' --norc' : ' --nofw' } publishDir = [ - path: { "${params.outdir}/circrna_discovery/find_circ/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -341,7 +341,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$18 ~ /CIRCULAR/ && \$18 ~ /UNAMBIGUOUS_BP/ && \$18 ~ /ANCHOR_UNIQUE/) { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 } }'" ext.suffix = "find_circ.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/find_circ/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/find_circ/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.find_circ.bed" @@ -350,7 +350,7 @@ process { withName: '.*:CIRIQUANT:MAIN' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/ciriquant/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/ciriquant/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -364,7 +364,7 @@ process { ext.suffix = "ciriquant.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/ciriquant/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/ciriquant/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.ciriquant.bed" @@ -385,7 +385,7 @@ process { "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate1/1st_pass" }, + path: { "${params.outdir}/circrna_discovery/tools/dcc/intermediates/mate1/1st_pass" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -393,7 +393,7 @@ process { withName: '.*:DCC:MATE1_SJDB' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate1/sjdb" }, + path: { "${params.outdir}/circrna_discovery/tools/dcc/intermediates/mate1/sjdb" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -414,7 +414,7 @@ process { "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate1/2nd_pass" }, + path: { "${params.outdir}/circrna_discovery/tools/dcc/intermediates/mate1/2nd_pass" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -434,7 +434,7 @@ process { "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate2/1st_pass" }, + path: { "${params.outdir}/circrna_discovery/tools/dcc/intermediates/mate2/1st_pass" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -442,7 +442,7 @@ process { withName: '.*:DCC:MATE2_SJDB' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate2/sjdb" }, + path: { "${params.outdir}/circrna_discovery/tools/dcc/intermediates/mate2/sjdb" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -463,7 +463,7 @@ process { "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/dcc/intermediates/mate2/2nd_pass" }, + path: { "${params.outdir}/circrna_discovery/tools/dcc/intermediates/mate2/2nd_pass" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -471,7 +471,7 @@ process { withName: '.*:DCC:MAIN' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/dcc/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/dcc/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -481,7 +481,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$4, \$5, \$4 }'" ext.suffix = "dcc.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/dcc/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/dcc/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.dcc.bed" @@ -510,7 +510,7 @@ process { "--fusion-non-canonical" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -518,7 +518,7 @@ process { withName: '.*:MAPSPLICE:PARSE' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -526,7 +526,7 @@ process { withName: '.*:MAPSPLICE:ANNOTATE' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/mapsplice/intermediates/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -536,7 +536,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$10, \$6 }'" ext.suffix = "mapsplice.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/mapsplice/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/mapsplice/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.mapsplice.bed" From ea4ef3442ffc6c79748cd5ccfe40f8446acd6171 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 17:48:22 +0200 Subject: [PATCH 351/491] Implement separate processes for FASTA extraction --- subworkflows/local/circrna_discovery.nf | 47 +++++++++++++------------ 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 35205ac8..b0ed9288 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -1,13 +1,15 @@ // MODULES -include { GAWK as FILTER_BSJS } from '../../modules/nf-core/gawk' -include { GAWK as MASK_SCORES } from '../../modules/nf-core/gawk' -include { GNU_SORT as CONCAT_TOOLS_PER_SAMPLE } from '../../modules/nf-core/gnu/sort' -include { BEDTOOLS_GROUPBY as COUNT_TOOLS } from '../../modules/nf-core/bedtools/groupby' -include { GAWK as FILTER_MIN_TOOLS } from '../../modules/nf-core/gawk' -include { GNU_SORT as CONCAT_SAMPLES } from '../../modules/nf-core/gnu/sort' -include { UPSET as UPSET_SAMPLES } from '../../modules/local/upset' -include { UPSET as UPSET_ALL } from '../../modules/local/upset' -include { BEDTOOLS_GETFASTA } from '../../modules/nf-core/bedtools/getfasta' +include { GAWK as FILTER_BSJS } from '../../modules/nf-core/gawk' +include { GAWK as MASK_SCORES } from '../../modules/nf-core/gawk' +include { GNU_SORT as CONCAT_TOOLS_PER_SAMPLE } from '../../modules/nf-core/gnu/sort' +include { BEDTOOLS_GROUPBY as COUNT_TOOLS } from '../../modules/nf-core/bedtools/groupby' +include { GAWK as FILTER_MIN_TOOLS } from '../../modules/nf-core/gawk' +include { GNU_SORT as CONCAT_SAMPLES } from '../../modules/nf-core/gnu/sort' +include { UPSET as UPSET_SAMPLES } from '../../modules/local/upset' +include { UPSET as UPSET_ALL } from '../../modules/local/upset' +include { BEDTOOLS_GETFASTA as FASTA_COMBINED } from '../../modules/nf-core/bedtools/getfasta' +include { BEDTOOLS_GETFASTA as FASTA_PER_SAMPLE } from '../../modules/nf-core/bedtools/getfasta' +include { BEDTOOLS_GETFASTA as FASTA_PER_SAMPLE_TOOL } from '../../modules/nf-core/bedtools/getfasta' // SUBWORKFLOWS include { SEGEMEHL } from './discovery/segemehl' @@ -150,28 +152,27 @@ workflow CIRCRNA_DISCOVERY { // FASTA WORKFLOW: // - BEDTOOLS_GETFASTA( - ch_bsj_bed_combined.mix(ch_bsj_bed_per_sample).mix(ch_bsj_bed_per_sample_tool), - fasta - ) - ch_versions = ch_versions.mix(BEDTOOLS_GETFASTA.out.versions) + FASTA_COMBINED( ch_bsj_bed_combined, fasta ) + ch_versions = ch_versions.mix(FASTA_COMBINED.out.versions) + ch_bsj_fasta_combined = FASTA_COMBINED.out.fasta - ch_bsj_fasta = BEDTOOLS_GETFASTA.out.fasta.branch{ - meta, fasta -> - combined: meta.id == 'all' - per_sample_tool: meta.containsKey('tool') - per_sample: true - } + FASTA_PER_SAMPLE( ch_bsj_bed_per_sample, fasta ) + ch_versions = ch_versions.mix(FASTA_PER_SAMPLE.out.versions) + ch_bsj_fasta_per_sample = FASTA_PER_SAMPLE.out.fasta + + FASTA_PER_SAMPLE_TOOL( ch_bsj_bed_per_sample_tool, fasta ) + ch_versions = ch_versions.mix(FASTA_PER_SAMPLE_TOOL.out.versions) + ch_bsj_fasta_per_sample_tool = FASTA_PER_SAMPLE_TOOL.out.fasta emit: bsj_bed_combined = ch_bsj_bed_combined - bsj_fasta_combined = ch_bsj_fasta.combined + bsj_fasta_combined = ch_bsj_fasta_combined bsj_bed_per_sample = ch_bsj_bed_per_sample - bsj_fasta_per_sample = ch_bsj_fasta.per_sample + bsj_fasta_per_sample = ch_bsj_fasta_per_sample bsj_bed_per_sample_tool = ch_bsj_bed_per_sample_tool - bsj_fasta_per_sample_tool = ch_bsj_fasta.per_sample_tool + bsj_fasta_per_sample_tool = ch_bsj_fasta_per_sample_tool multiqc_files = ch_multiqc_files versions = ch_versions From 8e7e441b800a5b016d63dac2a3f63e56c12e6815 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 18:00:18 +0200 Subject: [PATCH 352/491] Add fastas to discovery output --- conf/modules.config | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/conf/modules.config b/conf/modules.config index 21241788..a1f4394b 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -614,6 +614,33 @@ process { ] } + withName: FASTA_COMBINED { + ext.suffix = "fasta" + publishDir = [ + path: { "${params.outdir}/circrna_discovery/combined" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + + withName: FASTA_PER_SAMPLE { + ext.suffix = "fasta" + publishDir = [ + path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + + withName: FASTA_PER_SAMPLE_TOOL { + ext.suffix = { "${meta.tool}.fasta" } + publishDir = [ + path: { "${params.outdir}/circrna_discovery/tools/${meta.tool}/${meta.id}" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + withName: '.*:ANNOTATION:INTERSECT_GTF' { ext.args = "-loj" ext.suffix = "intersect.bed" From 4e9f4abcaaba5b4981fda5236471b9ab4183c96a Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 18:06:56 +0200 Subject: [PATCH 353/491] Add output directory for statistical tests --- conf/modules.config | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/conf/modules.config b/conf/modules.config index a1f4394b..f3dbfd75 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -26,6 +26,14 @@ process { ] } + withName: CAT_FASTQ { + publishDir = [ + path: { "${params.outdir}/preprocessing/merged_samples" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + // TRIMMING courtesy of nf-core/rnaseq if (!params.skip_trimming) { @@ -749,4 +757,12 @@ process { pattern: "*.txt" ] } + + withName: CIRCTEST_CIRCTEST { + publishDir = [ + path: { "${params.outdir}/statistical_tests/circtest" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } } From 4e2ce6cca687bde955b775949179bdcce3718121 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 18:08:15 +0200 Subject: [PATCH 354/491] Handle output of circtest_prepare --- conf/modules.config | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/conf/modules.config b/conf/modules.config index f3dbfd75..7f072016 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -758,6 +758,14 @@ process { ] } + withName: CIRCTEST_PREPARE { + publishDir = [ + path: { "${params.outdir}/statistical_tests/circtest" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] + } + withName: CIRCTEST_CIRCTEST { publishDir = [ path: { "${params.outdir}/statistical_tests/circtest" }, From ca5e4b664113706ac13f9c63deb9e8a7dccea8ae Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 20:22:42 +0200 Subject: [PATCH 355/491] Improve QC output directory structure --- conf/modules.config | 77 +++++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 7f072016..5bda6597 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -34,37 +34,34 @@ process { ] } - // TRIMMING courtesy of nf-core/rnaseq - - if (!params.skip_trimming) { - process { - withName: '.*:FASTQC_TRIMGALORE:TRIMGALORE' { - ext.args = { - [ - "--fastqc_args '-t ${task.cpus}' ", - params.trim_nextseq > 0 ? "--nextseq ${params.trim_nextseq}" : '' - ].join(' ').trim() - } - publishDir = [ - [ - path: { "${params.outdir}/quality_control/trimgalore/fastqc" }, - mode: params.publish_dir_mode, - pattern: "*.{html,zip}" - ], - [ - path: { "${params.outdir}/quality_control/trimgalore" }, - mode: params.publish_dir_mode, - pattern: "*.fq.gz", - enabled: params.save_trimmed - ], - [ - path: { "${params.outdir}/quality_control/trimgalore" }, - mode: params.publish_dir_mode, - pattern: "*.txt" - ] - ] - } + withName: '.*:FASTQC_TRIMGALORE:FASTQC' { + publishDir = [ + path: { "${params.outdir}/quality_control/fastqc" }, + mode: params.publish_dir_mode, + pattern: "*.{html,zip}" + ] + } + + withName: '.*:FASTQC_TRIMGALORE:TRIMGALORE' { + ext.args = { + [ + "--fastqc_args '-t ${task.cpus}' ", + params.trim_nextseq > 0 ? "--nextseq ${params.trim_nextseq}" : '' + ].join(' ').trim() } + publishDir = [ + [ + path: { "${params.outdir}/quality_control/trimgalore" }, + mode: params.publish_dir_mode, + pattern: "*.fq.gz", + enabled: params.save_trimmed + ], + [ + path: { "${params.outdir}/quality_control/trimgalore" }, + mode: params.publish_dir_mode, + pattern: "*.txt" + ] + ] } // PREPARE GENOME @@ -567,6 +564,11 @@ process { // GNU sort by columns 1,2,3,4,6 ext.args = "-k1,1 -k2,2n -k3,3n -k4,4 -k6,6" ext.suffix = {"sorted.bed"} + publishDir = [ + path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + mode: params.publish_dir_mode, + saveAs: { filename -> null } // The same data will be published in COUNT_TOOLS in a better format + ] } withName: 'COUNT_TOOLS' { @@ -684,7 +686,12 @@ process { withName: COMBINE_TRANSCRIPTOME_GTFS { ext.args = "-k 1,1 -k4,4n -k5,5n" - ext.suffix = "gtf" + ext.suffix = "combined.gtf" + publishDir = [ + path: { "${params.outdir}/quantification" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] } withName: EXCLUDE_OVERLONG_TRANSCRIPTS { @@ -700,6 +707,14 @@ process { ext.suffix = "marked.fasta" } + withName: 'CUSTOM_TX2GENE' { + publishDir = [ + path: { "${params.outdir}/quantification/tx2gene" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + withName: ".*:JOIN_(GENE|TX)_(COUNTS|TPM)" { ext.args = "-f 1,2 -t" label = "process_medium" From f78404efdca51ea94af9658c001581a0cc519bfa Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 20:33:55 +0200 Subject: [PATCH 356/491] Unify discovery tool output directories --- conf/modules.config | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 5bda6597..45ea43b4 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -171,17 +171,32 @@ process { // Print $1 $2 $3 $1:$2-$3 $5 $6 ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$4 ~ /;C;/) { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 } }'" ext.suffix = "segemehl_extracted.bed" + publishDir = [ + path: { "${params.outdir}/circrna_discovery/tools/segemehl/extracted" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] } withName: '.*:SEGEMEHL:SORT' { ext.args = "-k1,1 -k2,2n -k3,3n -k4,4 -k6,6" ext.suffix = "segemehl_sorted.bed" + publishDir = [ + path: { "${params.outdir}/circrna_discovery/tools/segemehl/sorted" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] } withName: '.*:SEGEMEHL:GROUP' { ext.summary_col = 5 ext.args = "-g 1,2,3,4,6 -o count" ext.suffix = "segemehl_grouped.bed" + publishDir = [ + path: { "${params.outdir}/circrna_discovery/tools/segemehl/grouped" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] } withName: '.*:SEGEMEHL:UNIFY' { @@ -275,7 +290,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$13, \$6 }'" ext.suffix = "circexplorer2.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/circexplorer2/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/circexplorer2/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.circexplorer2.bed" @@ -295,7 +310,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 }'" ext.suffix = "circrna_finder.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/circrna_finder/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/circrna_finder/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.circrna_finder.bed" @@ -346,7 +361,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$18 ~ /CIRCULAR/ && \$18 ~ /UNAMBIGUOUS_BP/ && \$18 ~ /ANCHOR_UNIQUE/) { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 } }'" ext.suffix = "find_circ.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/find_circ/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/find_circ/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.find_circ.bed" @@ -369,7 +384,7 @@ process { ext.suffix = "ciriquant.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/ciriquant/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/ciriquant/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.ciriquant.bed" @@ -486,7 +501,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$4, \$5, \$4 }'" ext.suffix = "dcc.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/dcc/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/dcc/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.dcc.bed" @@ -541,7 +556,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$10, \$6 }'" ext.suffix = "mapsplice.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/mapsplice/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/mapsplice/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.mapsplice.bed" @@ -645,7 +660,7 @@ process { withName: FASTA_PER_SAMPLE_TOOL { ext.suffix = { "${meta.tool}.fasta" } publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/${meta.tool}/${meta.id}" }, + path: { "${params.outdir}/circrna_discovery/tools/${meta.tool}/fasta" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -697,6 +712,11 @@ process { withName: EXCLUDE_OVERLONG_TRANSCRIPTS { ext.args = "-v FS='\\t' -v OFS='\\t' '\$5-\$4 <= 10000 { print }'" ext.suffix = "filtered.gtf" + publishDir = [ + path: { "${params.outdir}/quantification" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] } withName: MARK_CIRCULAR { From 654caa5f0b62e4c5ac4856dbc88b39483189411f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 21:09:31 +0200 Subject: [PATCH 357/491] Improve quantification outdir structure --- conf/modules.config | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 45ea43b4..4ead8236 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -76,6 +76,11 @@ process { withName: GTFFILTER { ext.suffix = "filtered.gtf" + publishDir = [ + path: { "${params.outdir}/references/filtered_gtf" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + ] } withName: SEQKIT_SPLIT { @@ -567,12 +572,22 @@ process { // Make sure score is higher or equal to the threshold ext.args = { "-v FS='\\t' -v OFS='\\t' '{ if (\$5 >= ${params.bsj_reads}) { print } }'" } ext.suffix = {"${meta.tool}.filtered.bed"} + publishDir = [ + path: { "${params.outdir}/circrna_discovery/tools/${meta.tool}/filtered" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + ] } withName: 'MASK_SCORES' { // Take bed file and replace the score column with a dot ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$4, \".\", \$6 }'" ext.suffix = {"${meta.tool}.masked.bed"} + publishDir = [ + path: { "${params.outdir}/circrna_discovery/tools/${meta.tool}/masked" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] } withName: 'CONCAT_TOOLS_PER_SAMPLE' { @@ -703,7 +718,7 @@ process { ext.args = "-k 1,1 -k4,4n -k5,5n" ext.suffix = "combined.gtf" publishDir = [ - path: { "${params.outdir}/quantification" }, + path: { "${params.outdir}/quantification/transcriptome" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -713,7 +728,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '\$5-\$4 <= 10000 { print }'" ext.suffix = "filtered.gtf" publishDir = [ - path: { "${params.outdir}/quantification" }, + path: { "${params.outdir}/quantification/transcriptome" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -727,6 +742,22 @@ process { ext.suffix = "marked.fasta" } + withName: PSIRC_INDEX { + publishDir = [ + path: { "${params.outdir}/references/psirc" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } + ] + } + + withName: PSIRC_QUANT { + publishDir = [ + path: { "${params.outdir}/quantification/psirc" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + withName: 'CUSTOM_TX2GENE' { publishDir = [ path: { "${params.outdir}/quantification/tx2gene" }, @@ -740,7 +771,7 @@ process { label = "process_medium" maxRetries = 3 publishDir = [ - path: { "${params.outdir}/quantification/" }, + path: { "${params.outdir}/quantification/matrices" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -748,7 +779,7 @@ process { withName: ".*:SPLIT_TYPES_(COUNTS|TPM)" { publishDir = [ - path: { "${params.outdir}/quantification/" }, + path: { "${params.outdir}/quantification/matrices" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] From 395febd9cfaf1d01fcb828758f55fad5d10032d6 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 21:21:23 +0200 Subject: [PATCH 358/491] Improve quantification outdir structure --- conf/modules.config | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 4ead8236..2c460abe 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -752,7 +752,7 @@ process { withName: PSIRC_QUANT { publishDir = [ - path: { "${params.outdir}/quantification/psirc" }, + path: { "${params.outdir}/quantification/samples/${meta.id}/psirc" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -760,7 +760,23 @@ process { withName: 'CUSTOM_TX2GENE' { publishDir = [ - path: { "${params.outdir}/quantification/tx2gene" }, + path: { "${params.outdir}/quantification/transcriptome" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + + withName: TXIMETA_TXIMETA { + publishDir = [ + path: { "${params.outdir}/quantification/samples/${meta.id}/tximeta" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + + withName: TXIMETA_TXIMPORT { + publishDir = [ + path: { "${params.outdir}/quantification/samples/${meta.id}/tximport" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -771,7 +787,7 @@ process { label = "process_medium" maxRetries = 3 publishDir = [ - path: { "${params.outdir}/quantification/matrices" }, + path: { "${params.outdir}/quantification/combined" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -779,7 +795,7 @@ process { withName: ".*:SPLIT_TYPES_(COUNTS|TPM)" { publishDir = [ - path: { "${params.outdir}/quantification/matrices" }, + path: { "${params.outdir}/quantification/combined" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] From 45cfd02de5d5abc216bff3f789fd0d78394b5cff Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 21:37:20 +0200 Subject: [PATCH 359/491] Make some more outdir optimizations --- conf/modules.config | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/conf/modules.config b/conf/modules.config index 2c460abe..51940524 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -34,6 +34,14 @@ process { ] } + withName: SAMTOOLS_FAIDX { + publishDir = [ + path: { "${params.outdir}/references/index/fasta" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } + ] + } + withName: '.*:FASTQC_TRIMGALORE:FASTQC' { publishDir = [ path: { "${params.outdir}/quality_control/fastqc" }, @@ -333,6 +341,14 @@ process { ] } + withName: '.*:FIND_CIRC:SAMTOOLS_INDEX' { + publishDir = [ + path: { "${params.outdir}/circrna_discovery/tools/find_circ/intermediates/${meta.id}" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] + } + withName: '.*:FIND_CIRC:SAMTOOLS_VIEW' { ext.prefix = { "${meta.id}_unmapped" } ext.args = "-hf 4" @@ -734,12 +750,25 @@ process { ] } + withName: TRANSCRIPTOME { + publishDir = [ + path: { "${params.outdir}/quantification/transcriptome" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + withName: MARK_CIRCULAR { // GAWK process that marks FASTA headers. // Leaves headers starting with "ENS" and non-header lines as is. // Adds "\tC" to the end of the header for all other headers ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (!/^>circ_/) { print } else { print \$1 \"\\tC\" } }'" ext.suffix = "marked.fasta" + publishDir = [ + path: { "${params.outdir}/quantification/transcriptome" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] } withName: PSIRC_INDEX { @@ -801,6 +830,14 @@ process { ] } + withName: MERGE_EXPERIMENTS { + publishDir = [ + path: { "${params.outdir}/quantification/combined" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + withName: TARGETSCAN_DATABASE { publishDir = [ path: { "${params.outdir}/references/targetscan" }, From dd682fb1ad6c96c12c45ec40f18df313d037ea62 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 21:41:35 +0200 Subject: [PATCH 360/491] Remove tool reference in mirna outdir --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 51940524..2ff7a549 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -870,7 +870,7 @@ process { withName: MIRNA_TARGETS { publishDir = [ - path: { "${params.outdir}/mirna_prediction/${meta.tool}" }, + path: { "${params.outdir}/mirna_prediction/combined" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.txt" From baf6d37ae2ee2bf508c9f94d61e86e17aa565b3f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 22:20:07 +0200 Subject: [PATCH 361/491] Add annotation back to discovery --- conf/modules.config | 26 +++++++++++--- subworkflows/local/annotation.nf | 1 - subworkflows/local/circrna_discovery.nf | 45 ++++++++++++++++++++----- subworkflows/local/quantification.nf | 1 - workflows/circrna/main.nf | 29 +++++----------- 5 files changed, 67 insertions(+), 35 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 2ff7a549..13951291 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -697,24 +697,40 @@ process { ] } - withName: '.*:ANNOTATION:INTERSECT_GTF' { + withName: '.*:ANNOTATE_(COMBINED|PER_SAMPLE|PER_SAMPLE_TOOL):INTERSECT_GTF' { ext.args = "-loj" ext.suffix = "intersect.bed" } - withName: '.*:ANNOTATION:INGEST_DATABASE_NAMES' { + withName: '.*:ANNOTATE_(COMBINED|PER_SAMPLE|PER_SAMPLE_TOOL):INGEST_DATABASE_NAMES' { ext.args = { "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \"${meta.id}:\" \$4, \$5, \$6 }'" } ext.suffix = "named.bed" } - withName: '.*:ANNOTATION:INTERSECT_DATABASE' { + withName: '.*:ANNOTATE_(COMBINED|PER_SAMPLE|PER_SAMPLE_TOOL):INTERSECT_DATABASE' { ext.args = { "-f ${meta.min_overlap} -r -loj -wa -wb" } ext.suffix = "annotated.bed" } - withName: '.*:ANNOTATION:ANNOTATE' { + withName: '.*:ANNOTATE_COMBINED:ANNOTATE' { publishDir = [ - path: { "${params.outdir}/annotation" }, + path: { "${params.outdir}/circrna_discovery/combined" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + + withName: '.*:ANNOTATE_PER_SAMPLE:ANNOTATE' { + publishDir = [ + path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + + withName: '.*:ANNOTATE_PER_SAMPLE_TOOL:ANNOTATE' { + publishDir = [ + path: { "${params.outdir}/circrna_discovery/tools/${meta.tool}/annotated" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] diff --git a/subworkflows/local/annotation.nf b/subworkflows/local/annotation.nf index f1887d93..dea819a6 100644 --- a/subworkflows/local/annotation.nf +++ b/subworkflows/local/annotation.nf @@ -28,7 +28,6 @@ workflow ANNOTATION { [[], []]) ch_versions = ch_versions.mix(INTERSECT_DATABASE.out.versions) - ANNOTATE( INTERSECT_GTF.out.intersect .join(INTERSECT_DATABASE.out.intersect .map{ meta, bed -> [meta.original_meta, bed] } diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index b0ed9288..74485267 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -12,14 +12,17 @@ include { BEDTOOLS_GETFASTA as FASTA_PER_SAMPLE } from '../../modules/nf-co include { BEDTOOLS_GETFASTA as FASTA_PER_SAMPLE_TOOL } from '../../modules/nf-core/bedtools/getfasta' // SUBWORKFLOWS -include { SEGEMEHL } from './discovery/segemehl' -include { STAR2PASS } from './discovery/star2pass' -include { CIRCEXPLORER2 } from './discovery/circexplorer2' -include { CIRCRNA_FINDER } from './discovery/circrna_finder' -include { FIND_CIRC } from './discovery/find_circ' -include { CIRIQUANT } from './discovery/ciriquant' -include { DCC } from './discovery/dcc' -include { MAPSPLICE } from './discovery/mapsplice' +include { SEGEMEHL } from './discovery/segemehl' +include { STAR2PASS } from './discovery/star2pass' +include { CIRCEXPLORER2 } from './discovery/circexplorer2' +include { CIRCRNA_FINDER } from './discovery/circrna_finder' +include { FIND_CIRC } from './discovery/find_circ' +include { CIRIQUANT } from './discovery/ciriquant' +include { DCC } from './discovery/dcc' +include { MAPSPLICE } from './discovery/mapsplice' +include { ANNOTATION as ANNOTATE_COMBINED } from './annotation' +include { ANNOTATION as ANNOTATE_PER_SAMPLE } from './annotation' +include { ANNOTATION as ANNOTATE_PER_SAMPLE_TOOL } from './annotation' workflow CIRCRNA_DISCOVERY { @@ -27,6 +30,7 @@ workflow CIRCRNA_DISCOVERY { reads ch_fasta ch_gtf + ch_annotation bowtie_index bowtie2_index bwa_index @@ -34,6 +38,7 @@ workflow CIRCRNA_DISCOVERY { hisat2_index star_index bsj_reads + exon_boundary main: ch_versions = Channel.empty() @@ -148,6 +153,24 @@ workflow CIRCRNA_DISCOVERY { ch_multiqc_files = ch_multiqc_files.mix(UPSET_ALL.out.multiqc) ch_versions = ch_versions.mix(UPSET_ALL.out.versions) + // + // ANNOTATION + // + ANNOTATE_COMBINED( ch_bsj_bed_combined, ch_gtf, exon_boundary, ch_annotation ) + ch_versions = ch_versions.mix(ANNOTATE_COMBINED.out.versions) + ch_bsj_bed12_combined = ANNOTATE_COMBINED.out.bed + ch_bsj_gtf_combined = ANNOTATE_COMBINED.out.gtf + + ANNOTATE_PER_SAMPLE( ch_bsj_bed_per_sample, ch_gtf, exon_boundary, ch_annotation ) + ch_versions = ch_versions.mix(ANNOTATE_PER_SAMPLE.out.versions) + ch_bsj_bed12_per_sample = ANNOTATE_PER_SAMPLE.out.bed + ch_bsj_gtf_per_sample = ANNOTATE_PER_SAMPLE.out.gtf + + ANNOTATE_PER_SAMPLE_TOOL( ch_bsj_bed_per_sample_tool, ch_gtf, exon_boundary, ch_annotation ) + ch_versions = ch_versions.mix(ANNOTATE_PER_SAMPLE_TOOL.out.versions) + ch_bsj_bed12_per_sample_tool = ANNOTATE_PER_SAMPLE_TOOL.out.bed + ch_bsj_gtf_per_sample_tool = ANNOTATE_PER_SAMPLE_TOOL.out.gtf + // // FASTA WORKFLOW: // @@ -166,12 +189,18 @@ workflow CIRCRNA_DISCOVERY { emit: bsj_bed_combined = ch_bsj_bed_combined + bsj_bed12_combined = ch_bsj_bed12_combined + bsj_gtf_combined = ch_bsj_gtf_combined bsj_fasta_combined = ch_bsj_fasta_combined bsj_bed_per_sample = ch_bsj_bed_per_sample + bsj_bed12_per_sample = ch_bsj_bed12_per_sample + bsj_gtf_per_sample = ch_bsj_gtf_per_sample bsj_fasta_per_sample = ch_bsj_fasta_per_sample bsj_bed_per_sample_tool = ch_bsj_bed_per_sample_tool + bsj_bed12_per_sample_tool = ch_bsj_bed12_per_sample_tool + bsj_gtf_per_sample_tool = ch_bsj_gtf_per_sample_tool bsj_fasta_per_sample_tool = ch_bsj_fasta_per_sample_tool multiqc_files = ch_multiqc_files diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index 8b1fb10d..695fd524 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -19,7 +19,6 @@ workflow QUANTIFICATION { take: ch_gtf ch_fasta - counts reads circ_annotation_bed circ_annotation_gtf diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index aa7f4ea3..ffcc6e11 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -140,6 +140,7 @@ workflow CIRCRNA { FASTQC_TRIMGALORE.out.reads, ch_fasta, ch_gtf, + ch_annotation, bowtie_index, bowtie2_index, bwa_index, @@ -147,34 +148,22 @@ workflow CIRCRNA { hisat2_index, star_index, params.bsj_reads, + params.exon_boundary ) ch_multiqc_files = ch_multiqc_files.mix(CIRCRNA_DISCOVERY.out.multiqc_files) ch_versions = ch_versions.mix(CIRCRNA_DISCOVERY.out.versions) // - // 3. circRNA Annotation - // - - ANNOTATION( - CIRCRNA_DISCOVERY.out.bsj_bed_combined, - ch_gtf, - params.exon_boundary, - ch_annotation - ) - ch_versions = ch_versions.mix(ANNOTATION.out.versions) - - // - // 4. circRNA quantification + // 3. circRNA quantification // QUANTIFICATION( ch_gtf, ch_fasta, - CIRCRNA_DISCOVERY.out.bsj_bed_combined, FASTQC_TRIMGALORE.out.reads, - ANNOTATION.out.bed, - ANNOTATION.out.gtf, + CIRCRNA_DISCOVERY.out.bsj_bed12_combined, + CIRCRNA_DISCOVERY.out.bsj_gtf_combined, params.bootstrap_samples, ch_phenotype, PREPARE_GENOME.out.faidx @@ -183,19 +172,19 @@ workflow CIRCRNA { ch_versions = ch_versions.mix(QUANTIFICATION.out.versions) // - // 5. miRNA prediction + // 4. miRNA prediction // if (params.mature) { MIRNA_PREDICTION( CIRCRNA_DISCOVERY.out.bsj_fasta_combined, - ANNOTATION.out.bed, + CIRCRNA_DISCOVERY.out.bsj_bed_combined, ch_mature ) ch_versions = ch_versions.mix(MIRNA_PREDICTION.out.versions) } // - // 6. Statistical tests + // 5. Statistical tests // STATISTICAL_TESTS( @@ -215,7 +204,7 @@ workflow CIRCRNA { .collectFile(storeDir: "${params.outdir}/pipeline_info", name: 'nf_core_pipeline_software_mqc_versions.yml', sort: true, newLine: true) .set { ch_collated_versions } - // MODULE: MultiQC + // MultiQC ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath(params.multiqc_config) : Channel.empty() ch_multiqc_logo = params.multiqc_logo ? Channel.fromPath(params.multiqc_logo) : Channel.empty() summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") From 2ff430e2300f93176966977dca5b1fd16a9da398 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 22:27:29 +0200 Subject: [PATCH 362/491] Improve annotation output formatting --- conf/modules.config | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 13951291..cee4cb8d 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -699,7 +699,7 @@ process { withName: '.*:ANNOTATE_(COMBINED|PER_SAMPLE|PER_SAMPLE_TOOL):INTERSECT_GTF' { ext.args = "-loj" - ext.suffix = "intersect.bed" + ext.suffix = "intersect_gtf.bed" } withName: '.*:ANNOTATE_(COMBINED|PER_SAMPLE|PER_SAMPLE_TOOL):INGEST_DATABASE_NAMES' { @@ -709,7 +709,11 @@ process { withName: '.*:ANNOTATE_(COMBINED|PER_SAMPLE|PER_SAMPLE_TOOL):INTERSECT_DATABASE' { ext.args = { "-f ${meta.min_overlap} -r -loj -wa -wb" } - ext.suffix = "annotated.bed" + ext.suffix = "intersect_database.bed" + } + + withName: '.*:ANNOTATE_(COMBINED|PER_SAMPLE|PER_SAMPLE_TOOL):ANNOTATE' { + ext.prefix = { "${meta.id}.annotated" } } withName: '.*:ANNOTATE_COMBINED:ANNOTATE' { From c8fc5c3faa5ae457fde1be72add24abeee7326e3 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 22:37:22 +0200 Subject: [PATCH 363/491] Remove unnecessary outputs from circrna_discovery --- subworkflows/local/circrna_discovery.nf | 24 +++++++----------------- workflows/circrna/main.nf | 8 ++++---- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 74485267..de3077f2 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -188,21 +188,11 @@ workflow CIRCRNA_DISCOVERY { ch_bsj_fasta_per_sample_tool = FASTA_PER_SAMPLE_TOOL.out.fasta emit: - bsj_bed_combined = ch_bsj_bed_combined - bsj_bed12_combined = ch_bsj_bed12_combined - bsj_gtf_combined = ch_bsj_gtf_combined - bsj_fasta_combined = ch_bsj_fasta_combined - - bsj_bed_per_sample = ch_bsj_bed_per_sample - bsj_bed12_per_sample = ch_bsj_bed12_per_sample - bsj_gtf_per_sample = ch_bsj_gtf_per_sample - bsj_fasta_per_sample = ch_bsj_fasta_per_sample - - bsj_bed_per_sample_tool = ch_bsj_bed_per_sample_tool - bsj_bed12_per_sample_tool = ch_bsj_bed12_per_sample_tool - bsj_gtf_per_sample_tool = ch_bsj_gtf_per_sample_tool - bsj_fasta_per_sample_tool = ch_bsj_fasta_per_sample_tool - - multiqc_files = ch_multiqc_files - versions = ch_versions + bed = ch_bsj_bed_combined + bed12 = ch_bsj_bed12_combined + gtf = ch_bsj_gtf_combined + fasta = ch_bsj_fasta_combined + + multiqc_files = ch_multiqc_files + versions = ch_versions } diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index ffcc6e11..af779e8c 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -162,8 +162,8 @@ workflow CIRCRNA { ch_gtf, ch_fasta, FASTQC_TRIMGALORE.out.reads, - CIRCRNA_DISCOVERY.out.bsj_bed12_combined, - CIRCRNA_DISCOVERY.out.bsj_gtf_combined, + CIRCRNA_DISCOVERY.out.bed12, + CIRCRNA_DISCOVERY.out.gtf, params.bootstrap_samples, ch_phenotype, PREPARE_GENOME.out.faidx @@ -176,8 +176,8 @@ workflow CIRCRNA { // if (params.mature) { MIRNA_PREDICTION( - CIRCRNA_DISCOVERY.out.bsj_fasta_combined, - CIRCRNA_DISCOVERY.out.bsj_bed_combined, + CIRCRNA_DISCOVERY.out.fasta, + CIRCRNA_DISCOVERY.out.bed, ch_mature ) ch_versions = ch_versions.mix(MIRNA_PREDICTION.out.versions) From b19813a586c21922e200a10a5a4a91b7c8af8d8e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Fri, 2 Aug 2024 23:56:52 +0200 Subject: [PATCH 364/491] Fix bug in tool filtering --- conf/modules.config | 4 ++-- subworkflows/local/circrna_discovery.nf | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index cee4cb8d..bd415410 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -632,8 +632,8 @@ process { withName: 'FILTER_MIN_TOOLS' { // Keep only rows with at least the minimum number of tools // Replace the score column with a dot - ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$6 >= ${params.tool_filter}) { print \$1, \$2, \$3, \$4, \".\", \$5 } }'" - ext.suffix = {"filtered.bed"} + ext.args = { "-v FS='\\t' -v OFS='\\t' '{ if (\$6 >= ${params.tool_filter}) { print \$1, \$2, \$3, \$4, \".\", \$5 } }'" } + ext.suffix = "filtered.bed" publishDir = [ path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, mode: params.publish_dir_mode, diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index de3077f2..5c51f454 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -118,6 +118,7 @@ workflow CIRCRNA_DISCOVERY { MASK_SCORES( ch_bed, [] ) ch_versions = ch_versions.mix(MASK_SCORES.out.versions) ch_bsj_bed_per_sample_tool = MASK_SCORES.out.output + .filter{ meta, bed -> !bed.empty } CONCAT_TOOLS_PER_SAMPLE( MASK_SCORES.out.output.map{ meta, bed -> [ [id: meta.id], bed ] }.groupTuple() @@ -130,6 +131,7 @@ workflow CIRCRNA_DISCOVERY { FILTER_MIN_TOOLS( COUNT_TOOLS.out.bed, [] ) ch_versions = ch_versions.mix(FILTER_MIN_TOOLS.out.versions) ch_bsj_bed_per_sample = FILTER_MIN_TOOLS.out.output + .filter{ meta, bed -> !bed.empty } CONCAT_SAMPLES( ch_bsj_bed_per_sample.map{ meta, bed -> [[id: "all"], bed] }.groupTuple() From 1f00d9f56a5b0315e9dd45b96514dff873e768ee Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 00:28:23 +0200 Subject: [PATCH 365/491] Prevent pipeline from failing if no circRNAs are found --- modules/local/circtest/prepare/main.nf | 5 ++--- modules/local/circtest/prepare/templates/prepare.R | 10 ++++++++-- subworkflows/local/circrna_discovery.nf | 3 ++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/modules/local/circtest/prepare/main.nf b/modules/local/circtest/prepare/main.nf index bfc32b4e..4d3029c1 100644 --- a/modules/local/circtest/prepare/main.nf +++ b/modules/local/circtest/prepare/main.nf @@ -9,12 +9,11 @@ process CIRCTEST_PREPARE { tuple val(meta2), path(gene_counts) output: - tuple val(meta), path('*_circs.tsv'), emit: circ_counts - tuple val(meta), path('*_genes.tsv'), emit: gene_counts + tuple val(meta), path('*_circs.tsv'), emit: circ_counts, optional: true + tuple val(meta), path('*_genes.tsv'), emit: gene_counts, optional: true path "versions.yml" , emit: versions - when: task.ext.when == null || task.ext.when diff --git a/modules/local/circtest/prepare/templates/prepare.R b/modules/local/circtest/prepare/templates/prepare.R index 5eb2c55e..d5dcdebb 100644 --- a/modules/local/circtest/prepare/templates/prepare.R +++ b/modules/local/circtest/prepare/templates/prepare.R @@ -9,8 +9,14 @@ rownames(circ) <- circ\$tx rownames(gene) <- rownames(circ) circ\$tx <- NULL -write.table(circ, "${prefix}_circs.tsv", sep="\\t", quote=F, row.names=T) -write.table(gene, "${prefix}_genes.tsv", sep="\\t", quote=F, row.names=T) +if (nrow(circ) != nrow(gene)) { + stop("Number of rows in circ and gene counts do not match") +} + +if (nrow(circ) > 0) { + write.table(circ, "${prefix}_circs.tsv", sep="\\t", quote=F, row.names=T) + write.table(gene, "${prefix}_genes.tsv", sep="\\t", quote=F, row.names=T) +} ################################################ ################################################ diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index 5c51f454..cd7f7d79 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -131,7 +131,7 @@ workflow CIRCRNA_DISCOVERY { FILTER_MIN_TOOLS( COUNT_TOOLS.out.bed, [] ) ch_versions = ch_versions.mix(FILTER_MIN_TOOLS.out.versions) ch_bsj_bed_per_sample = FILTER_MIN_TOOLS.out.output - .filter{ meta, bed -> !bed.empty } + .filter{ meta, bed -> bed.size() > 0 } CONCAT_SAMPLES( ch_bsj_bed_per_sample.map{ meta, bed -> [[id: "all"], bed] }.groupTuple() @@ -158,6 +158,7 @@ workflow CIRCRNA_DISCOVERY { // // ANNOTATION // + ANNOTATE_COMBINED( ch_bsj_bed_combined, ch_gtf, exon_boundary, ch_annotation ) ch_versions = ch_versions.mix(ANNOTATE_COMBINED.out.versions) ch_bsj_bed12_combined = ANNOTATE_COMBINED.out.bed From 35ef315cf4182480840eac5ea35e74ca151881d0 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 08:59:06 +0200 Subject: [PATCH 366/491] Improve annotation output format --- conf/modules.config | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/conf/modules.config b/conf/modules.config index bd415410..fb251d3b 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -702,9 +702,39 @@ process { ext.suffix = "intersect_gtf.bed" } + withName: '.*:ANNOTATE_COMBINED:INTERSECT_GTF' { + publishDir = [ + path: { "${params.outdir}/circrna_discovery/combined" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] + } + + withName: '.*:ANNOTATE_PER_SAMPLE:INTERSECT_GTF' { + publishDir = [ + path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] + } + + withName: '.*:ANNOTATE_PER_SAMPLE_TOOL:INTERSECT_GTF' { + publishDir = [ + path: { "${params.outdir}/circrna_discovery/tools/${meta.tool}/annotated" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] + } + withName: '.*:ANNOTATE_(COMBINED|PER_SAMPLE|PER_SAMPLE_TOOL):INGEST_DATABASE_NAMES' { ext.args = { "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \"${meta.id}:\" \$4, \$5, \$6 }'" } ext.suffix = "named.bed" + + publishDir = [ + path: { "${params.outdir}/references/named_databases" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] } withName: '.*:ANNOTATE_(COMBINED|PER_SAMPLE|PER_SAMPLE_TOOL):INTERSECT_DATABASE' { @@ -712,6 +742,30 @@ process { ext.suffix = "intersect_database.bed" } + withName: '.*:ANNOTATE_COMBINED:INTERSECT_DATABASE' { + publishDir = [ + path: { "${params.outdir}/circrna_discovery/combined" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] + } + + withName: '.*:ANNOTATE_PER_SAMPLE:INTERSECT_DATABASE' { + publishDir = [ + path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] + } + + withName: '.*:ANNOTATE_PER_SAMPLE_TOOL:INTERSECT_DATABASE' { + publishDir = [ + path: { "${params.outdir}/circrna_discovery/tools/${meta.tool}/annotated" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] + } + withName: '.*:ANNOTATE_(COMBINED|PER_SAMPLE|PER_SAMPLE_TOOL):ANNOTATE' { ext.prefix = { "${meta.id}.annotated" } } From d153402dddc1c8f861dda3768e43db65118067ed Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 09:08:11 +0200 Subject: [PATCH 367/491] Remove traces of old merging functionality --- docs/usage.md | 4 -- .../merge_samples/environment.yml | 5 -- .../local/count_matrix/merge_samples/main.nf | 20 ------ .../merge_samples/templates/merge_samples.py | 53 --------------- .../count_matrix/merge_tools/environment.yml | 5 -- .../local/count_matrix/merge_tools/main.nf | 22 ------- .../merge_tools/templates/merge_tools.py | 64 ------------------- nextflow.config | 1 - nextflow_schema.json | 11 +--- 9 files changed, 2 insertions(+), 183 deletions(-) delete mode 100644 modules/local/count_matrix/merge_samples/environment.yml delete mode 100644 modules/local/count_matrix/merge_samples/main.nf delete mode 100755 modules/local/count_matrix/merge_samples/templates/merge_samples.py delete mode 100644 modules/local/count_matrix/merge_tools/environment.yml delete mode 100644 modules/local/count_matrix/merge_tools/main.nf delete mode 100755 modules/local/count_matrix/merge_tools/templates/merge_tools.py diff --git a/docs/usage.md b/docs/usage.md index 137fb841..978f2313 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -245,10 +245,6 @@ nextflow run nf-core/circrna \ > This filtering method is reflected in the circRNA count matrix. Per tool circRNA annotations are subject to back-splice read filtering only. -#### Handling duplicate circRNAs - -In the event a circRNA has been called by more than one quantification tool, the user can specify which aggregate function to apply to the duplicated circRNA. The accepted values are 'mean' and 'max', which are passed to the workflow using the `--duplicates_fun` parameter. - ## miRNA prediction The second module of `nf-core/circrna`, `mirna_prediction` analyses the mature spliced sequences of circRNAs to test for the presence of miRNA response elements using both `miRanda` and `TargetScan`. Results from both tools are consolidated and filtering methods are applied to produce robust miRNA target predictions of circRNAs in the dataset. diff --git a/modules/local/count_matrix/merge_samples/environment.yml b/modules/local/count_matrix/merge_samples/environment.yml deleted file mode 100644 index d5f9e211..00000000 --- a/modules/local/count_matrix/merge_samples/environment.yml +++ /dev/null @@ -1,5 +0,0 @@ -name: merge_samples -channels: - - conda-forge -dependencies: - - pandas=1.5.2 diff --git a/modules/local/count_matrix/merge_samples/main.nf b/modules/local/count_matrix/merge_samples/main.nf deleted file mode 100644 index 8f8d3789..00000000 --- a/modules/local/count_matrix/merge_samples/main.nf +++ /dev/null @@ -1,20 +0,0 @@ -process MERGE_SAMPLES { - label "process_single" - - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : - 'biocontainers/pandas:1.5.2' }" - - input: - path(beds) - - output: - path("merged_counts.bed") , emit: counts_bed - path("merged_counts.tsv") , emit: counts_tsv - - path "versions.yml" , emit: versions - - script: - template "merge_samples.py" -} diff --git a/modules/local/count_matrix/merge_samples/templates/merge_samples.py b/modules/local/count_matrix/merge_samples/templates/merge_samples.py deleted file mode 100755 index 010eb616..00000000 --- a/modules/local/count_matrix/merge_samples/templates/merge_samples.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python3 - -import platform -import pandas as pd -import os - -def format_yaml_like(data: dict, indent: int = 0) -> str: - """Formats a dictionary to a YAML-like string. - - Args: - data (dict): The dictionary to format. - indent (int): The current indentation level. - - Returns: - str: A string formatted as YAML. - """ - yaml_str = "" - for key, value in data.items(): - spaces = " " * indent - if isinstance(value, dict): - yaml_str += f"{spaces}{key}:\\n{format_yaml_like(value, indent + 1)}" - else: - yaml_str += f"{spaces}{key}: {value}\\n" - return yaml_str - -columns = ['chr', 'start', 'end', 'name', 'count', 'strand'] -dfs = {os.path.basename(bed).split('.')[0]: pd.read_csv(bed, - sep='\t', - header=None, - index_col=["chr", "start", "end", "strand"], - usecols=["chr", "start", "end", "strand", "count"], - names=columns) for bed in "${beds}".split()} - -dfs = [df.rename(columns={'count': sample}) for sample, df in dfs.items()] -df = pd.concat(dfs, axis=1) -df = df.fillna(0) -df.to_csv("merged_counts.bed", sep='\\t', header=True, index=True) - -df.index = df.index.map(lambda x: f'{x[0]}:{x[1]}-{x[2]}:{x[3]}') -df.index.name = 'ID' -df.to_csv("merged_counts.tsv", sep='\\t') - -# Versions - -versions = { - "${task.process}": { - "python": platform.python_version(), - "pandas": pd.__version__ - } -} - -with open("versions.yml", "w") as f: - f.write(format_yaml_like(versions)) diff --git a/modules/local/count_matrix/merge_tools/environment.yml b/modules/local/count_matrix/merge_tools/environment.yml deleted file mode 100644 index 796e68fc..00000000 --- a/modules/local/count_matrix/merge_tools/environment.yml +++ /dev/null @@ -1,5 +0,0 @@ -name: merge_tools -channels: - - conda-forge -dependencies: - - pandas=1.5.2 diff --git a/modules/local/count_matrix/merge_tools/main.nf b/modules/local/count_matrix/merge_tools/main.nf deleted file mode 100644 index cdd3f2c0..00000000 --- a/modules/local/count_matrix/merge_tools/main.nf +++ /dev/null @@ -1,22 +0,0 @@ -process MERGE_TOOLS { - tag "$meta.id" - label "process_single" - - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : - 'biocontainers/pandas:1.5.2' }" - - input: - tuple val(meta), path(beds) - val(tool_filter) - val(duplicates_fun) - - output: - tuple val(meta), path("${meta.id}.merged.bed"), emit: merged - - path "versions.yml" , emit: versions - - script: - template 'merge_tools.py' -} diff --git a/modules/local/count_matrix/merge_tools/templates/merge_tools.py b/modules/local/count_matrix/merge_tools/templates/merge_tools.py deleted file mode 100755 index 8e514993..00000000 --- a/modules/local/count_matrix/merge_tools/templates/merge_tools.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python3 - -import platform -import pandas as pd - -def format_yaml_like(data: dict, indent: int = 0) -> str: - """Formats a dictionary to a YAML-like string. - - Args: - data (dict): The dictionary to format. - indent (int): The current indentation level. - - Returns: - str: A string formatted as YAML. - """ - yaml_str = "" - for key, value in data.items(): - spaces = " " * indent - if isinstance(value, dict): - yaml_str += f"{spaces}{key}:\\n{format_yaml_like(value, indent + 1)}" - else: - yaml_str += f"{spaces}{key}: {value}\\n" - return yaml_str - -duplicates_fun = "${duplicates_fun}" - -if duplicates_fun not in ['sum', 'mean', 'max', 'min']: - raise ValueError(f"Invalid value for duplicates_fun: {duplicates_fun}") - -columns = ['chr', 'start', 'end', 'name', 'count', 'strand'] -columns_no_count = ['chr', 'start', 'end', 'name', 'strand'] -dfs = [] - -for bed_path in "${beds}".split(): - df = pd.read_csv(bed_path, sep='\\t', header=None, names=columns) - - # If there are duplicate rows, throw an error - if df.duplicated(subset=columns_no_count).any(): - print(df[df.duplicated(subset=columns_no_count)]) - raise ValueError("Duplicate rows found in input BED file: " + bed_path) - - dfs.append(df) - -df = pd.concat(dfs) - -df['tool_count'] = 1 -df = df.groupby(['chr', 'start', 'end', 'strand', 'name']).agg({'count': duplicates_fun, - 'tool_count': 'sum'}).reset_index() -df = df[df['tool_count'] >= int("${tool_filter}")] - -df = df[columns] -df.to_csv("${meta.id}.merged.bed", sep='\t', index=False, header=False) - -# Versions - -versions = { - "${task.process}": { - "python": platform.python_version(), - "pandas": pd.__version__ - } -} - -with open("versions.yml", "w") as f: - f.write(format_yaml_like(versions)) diff --git a/nextflow.config b/nextflow.config index e2c6308d..5e54776d 100644 --- a/nextflow.config +++ b/nextflow.config @@ -19,7 +19,6 @@ params { tool = 'circexplorer2' bsj_reads = 0 tool_filter = 0 - duplicates_fun = 'mean' exon_boundary = 200 save_intermediates = false diff --git a/nextflow_schema.json b/nextflow_schema.json index 64df9eb1..45770cb8 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -81,17 +81,10 @@ "type": "integer", "fa_icon": "fas fa-intersection", "description": "Specify the minimum number of tools circRNAs must be called by to be output by the workflow.", - "help_text": "When multiple circRNA quantification tools have been provided to `--tool`, set a filtering method whereby circRNAs are output if they have been called by at least *n* quantification tools.\n\nSetting `--tool_filter` to 0/1 is the same as taking the union, all circRNAs are included in the output.\n\nSetting `--tool_filter` to 2 will output circRNAs that have been called by at least 2 quantification tools and so on.\n\nPlease note this is only reflected in the circRNA count matrix generated.", + "help_text": "When multiple circRNA quantification tools have been provided to `--tool`, set a filtering method whereby circRNAs are output if they have been called by at least *n* quantification tools.\n\nSetting `--tool_filter` to 0/1 is the same as taking the union, all circRNAs are included in the output.\n\nSetting `--tool_filter` to 2 will output circRNAs that have been called by at least 2 quantification tools and so on.", "default": 0, "minimum": 0, - "maximum": 6 - }, - "duplicates_fun": { - "type": "string", - "fa_icon": "fas fa-copy", - "description": "Aggregate function to apply to duplicate circRNAs when more than one quantification tool has been selected. Options: max, mean", - "default": "mean", - "enum": ["mean", "max"] + "maximum": 7 }, "save_intermediates": { "type": "boolean", From eeb1895153b0b107b6c3326f89c2d7245172d846 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 10:28:54 +0200 Subject: [PATCH 368/491] Make sure pipeline fails in an ordered way if no circRNAs are found --- modules/local/fail_on_empty/main.nf | 19 +++++++++++++++++++ subworkflows/local/circrna_discovery.nf | 23 +++++++++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 modules/local/fail_on_empty/main.nf diff --git a/modules/local/fail_on_empty/main.nf b/modules/local/fail_on_empty/main.nf new file mode 100644 index 00000000..277310ae --- /dev/null +++ b/modules/local/fail_on_empty/main.nf @@ -0,0 +1,19 @@ +process FAIL_ON_EMPTY { + tag "$meta.id" + + input: + tuple val(meta), path(bed) + path(waitFor, stageAs: 'waitFor*.txt') + + exec: + if (!bed) { + if (params.tool_filter <= 1) { + log.error "No circular RNAs were found by any tool in any sample.\n" + + "Please check the input data." + } else { + log.error "No circular RNAs were found by at least ${params.tool_filter} tools in any sample.\n" + + "Please check the input data or lower the tool_filter parameter." + } + exit 1 + } +} diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/circrna_discovery.nf index cd7f7d79..1447aa0a 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/circrna_discovery.nf @@ -10,6 +10,7 @@ include { UPSET as UPSET_ALL } from '../../modules/local include { BEDTOOLS_GETFASTA as FASTA_COMBINED } from '../../modules/nf-core/bedtools/getfasta' include { BEDTOOLS_GETFASTA as FASTA_PER_SAMPLE } from '../../modules/nf-core/bedtools/getfasta' include { BEDTOOLS_GETFASTA as FASTA_PER_SAMPLE_TOOL } from '../../modules/nf-core/bedtools/getfasta' +include { FAIL_ON_EMPTY } from '../../modules/local/fail_on_empty' // SUBWORKFLOWS include { SEGEMEHL } from './discovery/segemehl' @@ -143,13 +144,15 @@ workflow CIRCRNA_DISCOVERY { // UPSET PLOTS // - UPSET_SAMPLES( ch_bed.map{ meta, bed -> [meta.id, meta.tool, bed]} + UPSET_SAMPLES( ch_bsj_bed_per_sample_tool + .map{ meta, bed -> [meta.id, meta.tool, bed]} .groupTuple() .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) ch_multiqc_files = ch_multiqc_files.mix(UPSET_SAMPLES.out.multiqc) ch_versions = ch_versions.mix(UPSET_SAMPLES.out.versions) - UPSET_ALL( ch_bed.map{ meta, bed -> ["all", meta.tool, bed] } + UPSET_ALL( ch_bsj_bed_per_sample_tool + .map{ meta, bed -> ["all", meta.tool, bed] } .groupTuple() .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) ch_multiqc_files = ch_multiqc_files.mix(UPSET_ALL.out.multiqc) @@ -190,6 +193,22 @@ workflow CIRCRNA_DISCOVERY { ch_versions = ch_versions.mix(FASTA_PER_SAMPLE_TOOL.out.versions) ch_bsj_fasta_per_sample_tool = FASTA_PER_SAMPLE_TOOL.out.fasta + // STOP PIPELINE IF NO CIRCULAR RNAs WERE FOUND + FAIL_ON_EMPTY( + ch_bsj_bed_combined.ifEmpty([[id: "empty"], []]), + // Make sure to wait for per-sample results + Channel.empty() + .mix(ch_bsj_bed12_combined) + .mix(ch_bsj_bed12_per_sample) + .mix(ch_bsj_bed12_per_sample_tool) + .mix(ch_bsj_fasta_combined) + .mix(ch_bsj_fasta_per_sample) + .mix(ch_bsj_fasta_per_sample_tool) + .mix(UPSET_SAMPLES.out.plot) + .map{ meta, f -> f } + .collect() + ) + emit: bed = ch_bsj_bed_combined bed12 = ch_bsj_bed12_combined From 9bf06090606e4aba0d1e2b2c24af4829d8cdb930 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 10:41:21 +0200 Subject: [PATCH 369/491] Improve error message for no circRNAs found --- modules/local/fail_on_empty/main.nf | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/local/fail_on_empty/main.nf b/modules/local/fail_on_empty/main.nf index 277310ae..95916684 100644 --- a/modules/local/fail_on_empty/main.nf +++ b/modules/local/fail_on_empty/main.nf @@ -7,13 +7,13 @@ process FAIL_ON_EMPTY { exec: if (!bed) { - if (params.tool_filter <= 1) { - log.error "No circular RNAs were found by any tool in any sample.\n" + - "Please check the input data." - } else { - log.error "No circular RNAs were found by at least ${params.tool_filter} tools in any sample.\n" + - "Please check the input data or lower the tool_filter parameter." - } + log.error ((params.tool_filter <= 1 ? + "No circular RNAs were found by any tool in any sample.\n" : + "No circular RNAs were found by at least ${params.tool_filter} tools in any sample.\n") + + "Feel free to check the preliminary results in '${params.outdir}'\n" + + (params.save_intermediates ? "" : + "You can enable saving intermediate files by setting the parameter 'save_intermediates' to 'true'.")) + exit 1 } } From ccd0bda7eeb09ec86beff8bac122984e69338d77 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 10:42:45 +0200 Subject: [PATCH 370/491] Linting --- modules/local/fail_on_empty/main.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/local/fail_on_empty/main.nf b/modules/local/fail_on_empty/main.nf index 95916684..aa97b9e8 100644 --- a/modules/local/fail_on_empty/main.nf +++ b/modules/local/fail_on_empty/main.nf @@ -7,11 +7,11 @@ process FAIL_ON_EMPTY { exec: if (!bed) { - log.error ((params.tool_filter <= 1 ? - "No circular RNAs were found by any tool in any sample.\n" : + log.error ((params.tool_filter <= 1 ? + "No circular RNAs were found by any tool in any sample.\n" : "No circular RNAs were found by at least ${params.tool_filter} tools in any sample.\n") + "Feel free to check the preliminary results in '${params.outdir}'\n" + - (params.save_intermediates ? "" : + (params.save_intermediates ? "" : "You can enable saving intermediate files by setting the parameter 'save_intermediates' to 'true'.")) exit 1 From ddbd2f53e0020d6a52f183213156acdcf18ccf0e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 10:48:53 +0200 Subject: [PATCH 371/491] Update first section of introduction --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index e3d02d62..03e28b14 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,7 @@ ## Introduction -**nf-core/circrna** is a bioinformatics best-practice analysis pipeline for back-splice junction (BSJ) detection, quantification, annotation and miRNA target prediction of circular RNAs. - -The pipeline is built using [Nextflow](https://www.nextflow.io), a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It uses Docker/Singularity containers making installation trivial and results highly reproducible. The [Nextflow DSL2](https://www.nextflow.io/docs/latest/dsl2.html) implementation of this pipeline uses one container per process which makes it much easier to maintain and update software dependencies. Where possible, these processes have been submitted to and installed from [nf-core/modules](https://github.com/nf-core/modules) in order to make them available to all nf-core pipelines, and to everyone within the Nextflow community! - -On release, automated continuous integration tests run the pipeline on a full-sized dataset on the AWS cloud infrastructure. This ensures that the pipeline runs on AWS, has sensible resource allocation defaults set to run on real-world datasets, and permits the persistent storage of results to benchmark between pipeline releases and other analysis sources.The results obtained from the full-sized test can be viewed on the [nf-core website](https://nf-co.re/circrna/results). +**nf-core/circrna** is a bioinformatics pipeline that can be used to analyse total RNA sequencing data obtained from organisms with a reference genome and annotation. It takes a samplesheet and FASTQ files as input, performs quality control (QC), trimming, back-splice junction (BSJ) detection, annotation, quantification and miRNA target prediction of circular RNAs. ## Pipeline summary From f8ce1a644359421f644bd2cc14c925605e442d33 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 10:56:31 +0200 Subject: [PATCH 372/491] Update credits --- README.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 03e28b14..ad73c3cb 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,8 @@ - [`MapSplice`](http://www.netlab.uky.edu/p/bioinfo/MapSplice2) - [`Segemehl`](https://www.bioinf.uni-leipzig.de/Software/segemehl/) - circRNA annotation + - Based on GTF file + - Based on database files (if provided) - Extract circRNA sequences and build circular transcriptome - Merge circular transcriptome with linear transcriptome derived from provided GTF - Quantification of combined circular and linear transcriptome @@ -108,15 +110,17 @@ For more details about the output files and reports, please refer to the ## Credits -nf-core/circrna was originally written by Barry Digby. +nf-core/circrna was originally written by [Barry Digby](https://github.com/BarryDigby). +It was later refactored, extended and improved by [Nico Trummer](https://github.com/nictru). -We thank the following people for their extensive assistance in the development of this pipeline: +We thank the following people for their extensive assistance in the development of this pipeline (in alphabetical order): -- @apeltzer -- @ewels -- @maxulysse -- @KevinMenden -- @bj-w +- [Alexander Peltzer](https://github.com/apeltzer) +- [Ben Whittle](https://github.com/bj-w) +- [Kevin Menden](https://github.com/KevinMenden) +- [Marieke Vromman](https://github.com/MariekeVromman) +- [Maxime Garcia](https://github.com/maxulysse) +- [Phil Ewels](https://github.com/ewels) ## Acknowledgements From 17c692d9fe2f81a16556812e1c1f995693a1e065 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 11:08:58 +0200 Subject: [PATCH 373/491] Restructure usage docs --- docs/usage.md | 194 +++++++++++++++++++++++--------------------------- 1 file changed, 90 insertions(+), 104 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 978f2313..be4519df 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -53,115 +53,23 @@ TREATMENT_REP3,AEG588A6_S6_L004_R1_001.fastq.gz,,reverse An [example samplesheet](../assets/samplesheet.csv) has been provided with the pipeline. -## Running the pipeline - -The typical command for running the pipeline is as follows: - -```bash -nextflow run \ - nf-core/circrna \ - --input \ - --outdir \ - --gtf \ - --fasta \ - --igenomes_ignore \ - --genome null \ - -profile docker -``` - -> **NB:** Loading iGenomes configuration remains the default for reasons of consistency with other workflows, but should be disabled when not using iGenomes, applying the recommended usage above. - -This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. - -Note that the pipeline will create the following files in your working directory: - -```bash -work # Directory containing the nextflow working files - # Finished results in specified location (defined with --outdir) -.nextflow_log # Log file from Nextflow -# Other nextflow hidden files, eg. history of pipeline runs and old logs. -``` - -If you wish to repeatedly use the same parameters for multiple runs, rather than specifying each flag in the command, you can specify these in a params file. - -Pipeline settings can be provided in a `yaml` or `json` file via `-params-file `. - -:::warning -Do not use `-c ` to specify parameters as this will result in errors. Custom config files specified with `-c` must only be used for [tuning process resource specifications](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources), other infrastructural tweaks (such as output directories), or module arguments (args). -::: - -The above pipeline run specified with a params file in yaml format: - -```bash -nextflow run nf-core/circrna -profile docker -params-file params.yaml -``` - -with `params.yaml` containing: - -```yaml -input: './samplesheet.csv' -outdir: './results/' -genome: 'GRCh37' -<...> -``` - -You can also generate such `YAML`/`JSON` files via [nf-core/launch](https://nf-co.re/launch). - -### Updating the pipeline - -When you run the above command, Nextflow automatically pulls the pipeline code from GitHub and stores it as a cached version. When running the pipeline after this, it will always use the cached version if available - even if the pipeline has been updated since. To make sure that you're running the latest version of the pipeline, make sure that you regularly update the cached version of the pipeline: - -```bash -nextflow pull nf-core/circrna -``` - -When you run the above command, Nextflow automatically pulls the pipeline code from GitHub and stores it as a cached version. When running the pipeline after this, it will always use the cached version if available - even if the pipeline has been updated since. - -### Reproducibility - -It's a good idea to specify a pipeline version when running the pipeline on your data. This ensures that a specific version of the pipeline code and software are used when you run your pipeline. If you keep using the same tag, you'll be running the same version of the pipeline, even if there have been changes to the code since. - -First, go to the [nf-core/circrna releases page](https://github.com/nf-core/circrna/releases) and find the latest pipeline version - numeric only (eg. `1.3.1`). Then specify this when running the pipeline with `-r` (one hyphen) - eg. `-r 1.3.1`. Of course, you can switch to another version by changing the number after the `-r` flag. - -This version number will be logged in reports when you run the pipeline, so that you'll know what you used when you look back in the future. For example, at the bottom of the MultiQC reports. - -To further assist in reproducbility, you can use share and re-use [parameter files](#running-the-pipeline) to repeat pipeline runs with the same settings without having to write out a command with every single parameter. - -:::tip -If you wish to share such profile (such as upload as supplementary material for academic publications), make sure to NOT include cluster specific paths to files, nor institutional specific profiles. -::: - -# Input specifications - -Input data can be passed to `nf-core/circrna` using a CSV file containing the absolute paths to input fastq files. - -The header of the CSV file must at least contain the `sample` and `fastq_1` columns. The `fastq_2` column is optional and only required for paired-end data. With an additional `strandness` column, the user can specify the strandedness of the library. The `sample` column should contain a unique identifier for each sample, and the `fastq_1` and `fastq_2` columns should contain the paths to the input fastq files. - -Valid examples for fastq input data in a CSV file is given below: - -| sample | fastq_1 | fastq_2 | -| ---------------- | :---------------------------------------------------------------------- | ----------------------------------------------------------------------- | -| TCGA-EJ-7783-11A | /data/f4c1b2b1-ba1f-4355-a1ac-3e952cf351a5_gdc_realn_rehead_R1.fastq.gz | /data/f4c1b2b1-ba1f-4355-a1ac-3e952cf351a5_gdc_realn_rehead_R2.fastq.gz | -| TCGA-G9-6365-11A | /data/8a36555b-9e27-40ee-a8df-4b15d6580a02_gdc_realn_rehead_R1.fastq.gz | /data/8a36555b-9e27-40ee-a8df-4b15d6580a02_gdc_realn_rehead_R2.fastq.gz | -| TCGA-EJ-7782-11A | /data/8b3d4a3d-2bfa-48f8-b31f-901f49a5bf6b_gdc_realn_rehead_R1.fastq.gz | /data/8b3d4a3d-2bfa-48f8-b31f-901f49a5bf6b_gdc_realn_rehead_R2.fastq.gz | -| TCGA-CH-5772-01A | /data/b6546f66-3c13-4390-9643-d1fb3d660a2f_gdc_realn_rehead_R1.fastq.gz | /data/b6546f66-3c13-4390-9643-d1fb3d660a2f_gdc_realn_rehead_R2.fastq.gz | -| TCGA-EJ-5518-01A | /data/afbbc370-5970-43d3-b9f8-f40f8e649bb6_gdc_realn_rehead_R1.fastq.gz | /data/afbbc370-5970-43d3-b9f8-f40f8e649bb6_gdc_realn_rehead_R2.fastq.gz | -| TCGA-KK-A8I4-01A | /data/81254692-ee1e-4985-bd0a-4929eed4c620_gdc_realn_rehead_R1.fastq.gz | /data/81254692-ee1e-4985-bd0a-4929eed4c620_gdc_realn_rehead_R2.fastq.gz | - ## Phenotype file The CSV file provided via the `phenotype` parameter can be used to provide additional metadata about the samples in the input CSV file. If provided, it needs to at least contain a column called `sample` which corresponds to the `sample` column in the input CSV file and a column called `condition`. The `condition` column will be used to group samples for the [CircTest](https://github.com/dieterich-lab/CircTest) functionality. All metadata columns will be included in the result `SummarizedExperiment` RDS file. -A valid example of a `phenotype.csv` file (matching the TCGA example input CSV file above) is given: +A valid example of a `phenotype.csv` file (matching the "Full samplesheet") is given: + +```csv title="phenotype.csv" +sample,condition +CONTROL_REP1,control +CONTROL_REP2,control +CONTROL_REP3,control +TREATMENT_REP1,treatment +TREATMENT_REP2,treatment +TREATMENT_REP3,treatment +``` -| sample | condition | -| ---------------- | --------- | -| TCGA-EJ-7783-11A | control | -| TCGA-G9-6365-11A | control | -| TCGA-EJ-7782-11A | control | -| TCGA-CH-5772-01A | tumor | -| TCGA-EJ-5518-01A | tumor | -| TCGA-KK-A8I4-01A | tumor | +Note that `TREATMENT_REP3` only has one entry in the `phenotype.csv` file, even though it has two entries in the `samplesheet.csv` file. # Analysis modules @@ -261,6 +169,84 @@ nextflow run nf-core/circrna \ To view the outputs of the module, please see the output [documentation](https://nf-co.re/circrna/dev/output#mirna-prediction). +## Running the pipeline + +The typical command for running the pipeline is as follows: + +```bash +nextflow run \ + nf-core/circrna \ + --input \ + --outdir \ + --gtf \ + --fasta \ + --igenomes_ignore \ + --genome null \ + -profile docker +``` + +> **NB:** Loading iGenomes configuration remains the default for reasons of consistency with other workflows, but should be disabled when not using iGenomes, applying the recommended usage above. + +This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. + +Note that the pipeline will create the following files in your working directory: + +```bash +work # Directory containing the nextflow working files + # Finished results in specified location (defined with --outdir) +.nextflow_log # Log file from Nextflow +# Other nextflow hidden files, eg. history of pipeline runs and old logs. +``` + +If you wish to repeatedly use the same parameters for multiple runs, rather than specifying each flag in the command, you can specify these in a params file. + +Pipeline settings can be provided in a `yaml` or `json` file via `-params-file `. + +:::warning +Do not use `-c ` to specify parameters as this will result in errors. Custom config files specified with `-c` must only be used for [tuning process resource specifications](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources), other infrastructural tweaks (such as output directories), or module arguments (args). +::: + +The above pipeline run specified with a params file in yaml format: + +```bash +nextflow run nf-core/circrna -profile docker -params-file params.yaml +``` + +with `params.yaml` containing: + +```yaml +input: './samplesheet.csv' +outdir: './results/' +genome: 'GRCh37' +<...> +``` + +You can also generate such `YAML`/`JSON` files via [nf-core/launch](https://nf-co.re/launch). + +### Updating the pipeline + +When you run the above command, Nextflow automatically pulls the pipeline code from GitHub and stores it as a cached version. When running the pipeline after this, it will always use the cached version if available - even if the pipeline has been updated since. To make sure that you're running the latest version of the pipeline, make sure that you regularly update the cached version of the pipeline: + +```bash +nextflow pull nf-core/circrna +``` + +When you run the above command, Nextflow automatically pulls the pipeline code from GitHub and stores it as a cached version. When running the pipeline after this, it will always use the cached version if available - even if the pipeline has been updated since. + +### Reproducibility + +It's a good idea to specify a pipeline version when running the pipeline on your data. This ensures that a specific version of the pipeline code and software are used when you run your pipeline. If you keep using the same tag, you'll be running the same version of the pipeline, even if there have been changes to the code since. + +First, go to the [nf-core/circrna releases page](https://github.com/nf-core/circrna/releases) and find the latest pipeline version - numeric only (eg. `1.3.1`). Then specify this when running the pipeline with `-r` (one hyphen) - eg. `-r 1.3.1`. Of course, you can switch to another version by changing the number after the `-r` flag. + +This version number will be logged in reports when you run the pipeline, so that you'll know what you used when you look back in the future. For example, at the bottom of the MultiQC reports. + +To further assist in reproducbility, you can use share and re-use [parameter files](#running-the-pipeline) to repeat pipeline runs with the same settings without having to write out a command with every single parameter. + +:::tip +If you wish to share such profile (such as upload as supplementary material for academic publications), make sure to NOT include cluster specific paths to files, nor institutional specific profiles. +::: + ## Core Nextflow arguments :::note From 19820980ca3a71e5fccb4ca2c03f4879fb269b40 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 11:16:01 +0200 Subject: [PATCH 374/491] Add plans for future implementations to README --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index ad73c3cb..875ce95c 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,13 @@ **nf-core/circrna** is a bioinformatics pipeline that can be used to analyse total RNA sequencing data obtained from organisms with a reference genome and annotation. It takes a samplesheet and FASTQ files as input, performs quality control (QC), trimming, back-splice junction (BSJ) detection, annotation, quantification and miRNA target prediction of circular RNAs. +The pipeline is still under development, but the BSJ detection and quantification steps are already implemented and functional. The following features are planned to be implemented soon: +- Isoform-level circRNA detection and quantification +- circRNA-miRNA interaction analysis using [SPONGE](https://doi.org/10.1093/bioinformatics/btz314) and [spongEffects](https://doi.org/10.1093/bioinformatics/btad276) +- Improved downstream analyses + +If you want to contribute, feel free to create an issue or pull request on the [GitHub repository](https://github.com/nf-core/circrna) or join the [Slack channel](https://nf-co.re/join/slack). + ## Pipeline summary ![Metro Map](./docs/images/metro-map.png) From 9e9fdd9a69aa88882b25b9f4c3cff750a7f3f0be Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 11:22:22 +0200 Subject: [PATCH 375/491] Rename CIRCRNA_DISCOVERY to BSJ_DETECTION --- conf/modules.config | 106 +++++++++--------- docs/usage.md | 12 +- ...{circrna_discovery.nf => bsj_detection.nf} | 18 +-- .../circexplorer2.nf | 0 .../circrna_finder.nf | 0 .../ciriquant.nf | 0 .../{discovery => detection_tools}/dcc.nf | 0 .../find_circ.nf | 0 .../mapsplice.nf | 0 .../segemehl.nf | 0 .../star2pass.nf | 0 workflows/circrna/main.nf | 18 +-- 12 files changed, 74 insertions(+), 80 deletions(-) rename subworkflows/local/{circrna_discovery.nf => bsj_detection.nf} (91%) rename subworkflows/local/{discovery => detection_tools}/circexplorer2.nf (100%) rename subworkflows/local/{discovery => detection_tools}/circrna_finder.nf (100%) rename subworkflows/local/{discovery => detection_tools}/ciriquant.nf (100%) rename subworkflows/local/{discovery => detection_tools}/dcc.nf (100%) rename subworkflows/local/{discovery => detection_tools}/find_circ.nf (100%) rename subworkflows/local/{discovery => detection_tools}/mapsplice.nf (100%) rename subworkflows/local/{discovery => detection_tools}/segemehl.nf (100%) rename subworkflows/local/{discovery => detection_tools}/star2pass.nf (100%) diff --git a/conf/modules.config b/conf/modules.config index fb251d3b..d273ec07 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -173,7 +173,7 @@ process { "-S" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/segemehl/raw" }, + path: { "${params.outdir}/bsj_detection/tools/segemehl/raw" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -185,7 +185,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$4 ~ /;C;/) { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 } }'" ext.suffix = "segemehl_extracted.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/segemehl/extracted" }, + path: { "${params.outdir}/bsj_detection/tools/segemehl/extracted" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -195,7 +195,7 @@ process { ext.args = "-k1,1 -k2,2n -k3,3n -k4,4 -k6,6" ext.suffix = "segemehl_sorted.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/segemehl/sorted" }, + path: { "${params.outdir}/bsj_detection/tools/segemehl/sorted" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -206,7 +206,7 @@ process { ext.args = "-g 1,2,3,4,6 -o count" ext.suffix = "segemehl_grouped.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/segemehl/grouped" }, + path: { "${params.outdir}/bsj_detection/tools/segemehl/grouped" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -216,7 +216,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$4, \$6, \$5 }'" ext.suffix = "segemehl.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/segemehl/unified" }, + path: { "${params.outdir}/bsj_detection/tools/segemehl/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.segemehl.bed" @@ -237,7 +237,7 @@ process { "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/star/1st_pass" }, + path: { "${params.outdir}/bsj_detection/tools/star/1st_pass" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -245,7 +245,7 @@ process { withName: '.*:STAR2PASS:SJDB' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/star/sjdb" }, + path: { "${params.outdir}/bsj_detection/tools/star/sjdb" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -265,7 +265,7 @@ process { "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/star/2nd_pass" }, + path: { "${params.outdir}/bsj_detection/tools/star/2nd_pass" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -285,7 +285,7 @@ process { withName: '.*:CIRCEXPLORER2:PARSE' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/circexplorer2/intermediates/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/tools/circexplorer2/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -293,7 +293,7 @@ process { withName: '.*:CIRCEXPLORER2:ANNOTATE' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/circexplorer2/intermediates/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/tools/circexplorer2/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -303,7 +303,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$13, \$6 }'" ext.suffix = "circexplorer2.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/circexplorer2/unified" }, + path: { "${params.outdir}/bsj_detection/tools/circexplorer2/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.circexplorer2.bed" @@ -312,7 +312,7 @@ process { withName: '.*:CIRCRNA_FINDER:MAIN' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/circrna_finder/intermediates/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/tools/circrna_finder/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null }, pattern: "*.bed" @@ -323,7 +323,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 }'" ext.suffix = "circrna_finder.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/circrna_finder/unified" }, + path: { "${params.outdir}/bsj_detection/tools/circrna_finder/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.circrna_finder.bed" @@ -335,7 +335,7 @@ process { (!meta.strandedness || meta.strandedness == 'unstranded' || meta.strandedness == 'auto' ? '' : meta.strandedness == 'forward' ? ' --norc' : ' --nofw') } publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/find_circ/intermediates/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/tools/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -343,7 +343,7 @@ process { withName: '.*:FIND_CIRC:SAMTOOLS_INDEX' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/find_circ/intermediates/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/tools/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -353,7 +353,7 @@ process { ext.prefix = { "${meta.id}_unmapped" } ext.args = "-hf 4" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/find_circ/intermediates/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/tools/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -361,7 +361,7 @@ process { withName: '.*:FIND_CIRC:ANCHORS' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/find_circ/intermediates/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/tools/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -371,7 +371,7 @@ process { ext.args = { !meta.strandedness || meta.strandedness == 'unstranded' || meta.strandedness == 'auto' ? '' : meta.strandedness == 'forward' ? ' --norc' : ' --nofw' } publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/find_circ/intermediates/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/tools/find_circ/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -382,7 +382,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ if (\$18 ~ /CIRCULAR/ && \$18 ~ /UNAMBIGUOUS_BP/ && \$18 ~ /ANCHOR_UNIQUE/) { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$5, \$6 } }'" ext.suffix = "find_circ.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/find_circ/unified" }, + path: { "${params.outdir}/bsj_detection/tools/find_circ/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.find_circ.bed" @@ -391,7 +391,7 @@ process { withName: '.*:CIRIQUANT:MAIN' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/ciriquant/intermediates/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/tools/ciriquant/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -405,7 +405,7 @@ process { ext.suffix = "ciriquant.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/ciriquant/unified" }, + path: { "${params.outdir}/bsj_detection/tools/ciriquant/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.ciriquant.bed" @@ -426,7 +426,7 @@ process { "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/dcc/intermediates/mate1/1st_pass" }, + path: { "${params.outdir}/bsj_detection/tools/dcc/intermediates/mate1/1st_pass" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -434,7 +434,7 @@ process { withName: '.*:DCC:MATE1_SJDB' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/dcc/intermediates/mate1/sjdb" }, + path: { "${params.outdir}/bsj_detection/tools/dcc/intermediates/mate1/sjdb" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -455,7 +455,7 @@ process { "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/dcc/intermediates/mate1/2nd_pass" }, + path: { "${params.outdir}/bsj_detection/tools/dcc/intermediates/mate1/2nd_pass" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -475,7 +475,7 @@ process { "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/dcc/intermediates/mate2/1st_pass" }, + path: { "${params.outdir}/bsj_detection/tools/dcc/intermediates/mate2/1st_pass" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -483,7 +483,7 @@ process { withName: '.*:DCC:MATE2_SJDB' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/dcc/intermediates/mate2/sjdb" }, + path: { "${params.outdir}/bsj_detection/tools/dcc/intermediates/mate2/sjdb" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -504,7 +504,7 @@ process { "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/dcc/intermediates/mate2/2nd_pass" }, + path: { "${params.outdir}/bsj_detection/tools/dcc/intermediates/mate2/2nd_pass" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -512,7 +512,7 @@ process { withName: '.*:DCC:MAIN' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/dcc/intermediates/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/tools/dcc/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -522,7 +522,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$4, \$5, \$4 }'" ext.suffix = "dcc.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/dcc/unified" }, + path: { "${params.outdir}/bsj_detection/tools/dcc/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.dcc.bed" @@ -551,7 +551,7 @@ process { "--fusion-non-canonical" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/mapsplice/intermediates/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/tools/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -559,7 +559,7 @@ process { withName: '.*:MAPSPLICE:PARSE' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/mapsplice/intermediates/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/tools/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -567,7 +567,7 @@ process { withName: '.*:MAPSPLICE:ANNOTATE' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/mapsplice/intermediates/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/tools/mapsplice/intermediates/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -577,7 +577,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3 \":\" \$6, \$10, \$6 }'" ext.suffix = "mapsplice.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/mapsplice/unified" }, + path: { "${params.outdir}/bsj_detection/tools/mapsplice/unified" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.mapsplice.bed" @@ -589,7 +589,7 @@ process { ext.args = { "-v FS='\\t' -v OFS='\\t' '{ if (\$5 >= ${params.bsj_reads}) { print } }'" } ext.suffix = {"${meta.tool}.filtered.bed"} publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/${meta.tool}/filtered" }, + path: { "${params.outdir}/bsj_detection/tools/${meta.tool}/filtered" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, ] @@ -600,7 +600,7 @@ process { ext.args = "-v FS='\\t' -v OFS='\\t' '{ print \$1, \$2, \$3, \$4, \".\", \$6 }'" ext.suffix = {"${meta.tool}.masked.bed"} publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/${meta.tool}/masked" }, + path: { "${params.outdir}/bsj_detection/tools/${meta.tool}/masked" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -611,7 +611,7 @@ process { ext.args = "-k1,1 -k2,2n -k3,3n -k4,4 -k6,6" ext.suffix = {"sorted.bed"} publishDir = [ - path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/samples/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> null } // The same data will be published in COUNT_TOOLS in a better format ] @@ -623,7 +623,7 @@ process { ext.args = "-g 1,2,3,4,6 -o count" ext.suffix = {"tool_counts.bed"} publishDir = [ - path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/samples/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -635,7 +635,7 @@ process { ext.args = { "-v FS='\\t' -v OFS='\\t' '{ if (\$6 >= ${params.tool_filter}) { print \$1, \$2, \$3, \$4, \".\", \$5 } }'" } ext.suffix = "filtered.bed" publishDir = [ - path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/samples/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -646,7 +646,7 @@ process { ext.args = "-k1,1 -k2,2n -k3,3n -k4,4 -k6,6 -u" ext.suffix = {"combined.bed"} publishDir = [ - path: { "${params.outdir}/circrna_discovery/combined" }, + path: { "${params.outdir}/bsj_detection/combined" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -655,7 +655,7 @@ process { withName: UPSET_SAMPLES { ext.when = { params.tool.split(',').length > 1 } publishDir = [ - path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/samples/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -664,7 +664,7 @@ process { withName: UPSET_ALL { ext.when = { params.tool.split(',').length > 1 } publishDir = [ - path: { "${params.outdir}/circrna_discovery/combined" }, + path: { "${params.outdir}/bsj_detection/combined" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -673,7 +673,7 @@ process { withName: FASTA_COMBINED { ext.suffix = "fasta" publishDir = [ - path: { "${params.outdir}/circrna_discovery/combined" }, + path: { "${params.outdir}/bsj_detection/combined" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -682,7 +682,7 @@ process { withName: FASTA_PER_SAMPLE { ext.suffix = "fasta" publishDir = [ - path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/samples/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -691,7 +691,7 @@ process { withName: FASTA_PER_SAMPLE_TOOL { ext.suffix = { "${meta.tool}.fasta" } publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/${meta.tool}/fasta" }, + path: { "${params.outdir}/bsj_detection/tools/${meta.tool}/fasta" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -704,7 +704,7 @@ process { withName: '.*:ANNOTATE_COMBINED:INTERSECT_GTF' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/combined" }, + path: { "${params.outdir}/bsj_detection/combined" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -712,7 +712,7 @@ process { withName: '.*:ANNOTATE_PER_SAMPLE:INTERSECT_GTF' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/samples/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -720,7 +720,7 @@ process { withName: '.*:ANNOTATE_PER_SAMPLE_TOOL:INTERSECT_GTF' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/${meta.tool}/annotated" }, + path: { "${params.outdir}/bsj_detection/tools/${meta.tool}/annotated" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -744,7 +744,7 @@ process { withName: '.*:ANNOTATE_COMBINED:INTERSECT_DATABASE' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/combined" }, + path: { "${params.outdir}/bsj_detection/combined" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -752,7 +752,7 @@ process { withName: '.*:ANNOTATE_PER_SAMPLE:INTERSECT_DATABASE' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/samples/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -760,7 +760,7 @@ process { withName: '.*:ANNOTATE_PER_SAMPLE_TOOL:INTERSECT_DATABASE' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/${meta.tool}/annotated" }, + path: { "${params.outdir}/bsj_detection/tools/${meta.tool}/annotated" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -772,7 +772,7 @@ process { withName: '.*:ANNOTATE_COMBINED:ANNOTATE' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/combined" }, + path: { "${params.outdir}/bsj_detection/combined" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -780,7 +780,7 @@ process { withName: '.*:ANNOTATE_PER_SAMPLE:ANNOTATE' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/samples/${meta.id}" }, + path: { "${params.outdir}/bsj_detection/samples/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] @@ -788,7 +788,7 @@ process { withName: '.*:ANNOTATE_PER_SAMPLE_TOOL:ANNOTATE' { publishDir = [ - path: { "${params.outdir}/circrna_discovery/tools/${meta.tool}/annotated" }, + path: { "${params.outdir}/bsj_detection/tools/${meta.tool}/annotated" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] diff --git a/docs/usage.md b/docs/usage.md index be4519df..a0071d87 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -71,17 +71,11 @@ TREATMENT_REP3,treatment Note that `TREATMENT_REP3` only has one entry in the `phenotype.csv` file, even though it has two entries in the `samplesheet.csv` file. -# Analysis modules - -`nf-core/circrna` provides 3 analysis modules to the user: - -1. BSJ detection -2. Joint quantification of circular and linear transcriptome -3. miRNA target prediction - ## circRNA discovery -The core module of `nf-core/circrna`, a user can utilise up to seven circRNA quantification tools to fully characterise the circRNA profile in samples. Currently, supported tools include `CIRCexplorer2`, `circRNA finder`, `CIRIquant`, `DCC`, `find circ` , `MapSplice` & `Segemehl` however, the authors of `nf-core/circrna` welcome contributions from authors of novel quantification tools to keep the workflow current. +The core module of `nf-core/circrna`, a user can utilise up to seven circRNA quantification tools to fully characterise the circRNA profile in samples. + +Currently, supported tools include `CIRCexplorer2`, `circRNA finder`, `CIRIquant`, `DCC`, `find circ` , `MapSplice` & `Segemehl` however, the authors of `nf-core/circrna` welcome contributions from authors of novel quantification tools to keep the workflow current. By default, `nf-core/circrna` runs the circRNA discovery analysis module. diff --git a/subworkflows/local/circrna_discovery.nf b/subworkflows/local/bsj_detection.nf similarity index 91% rename from subworkflows/local/circrna_discovery.nf rename to subworkflows/local/bsj_detection.nf index 1447aa0a..7ebe8528 100644 --- a/subworkflows/local/circrna_discovery.nf +++ b/subworkflows/local/bsj_detection.nf @@ -13,19 +13,19 @@ include { BEDTOOLS_GETFASTA as FASTA_PER_SAMPLE_TOOL } from '../../modules/nf-co include { FAIL_ON_EMPTY } from '../../modules/local/fail_on_empty' // SUBWORKFLOWS -include { SEGEMEHL } from './discovery/segemehl' -include { STAR2PASS } from './discovery/star2pass' -include { CIRCEXPLORER2 } from './discovery/circexplorer2' -include { CIRCRNA_FINDER } from './discovery/circrna_finder' -include { FIND_CIRC } from './discovery/find_circ' -include { CIRIQUANT } from './discovery/ciriquant' -include { DCC } from './discovery/dcc' -include { MAPSPLICE } from './discovery/mapsplice' +include { SEGEMEHL } from './detection_tools/segemehl' +include { STAR2PASS } from './detection_tools/star2pass' +include { CIRCEXPLORER2 } from './detection_tools/circexplorer2' +include { CIRCRNA_FINDER } from './detection_tools/circrna_finder' +include { FIND_CIRC } from './detection_tools/find_circ' +include { CIRIQUANT } from './detection_tools/ciriquant' +include { DCC } from './detection_tools/dcc' +include { MAPSPLICE } from './detection_tools/mapsplice' include { ANNOTATION as ANNOTATE_COMBINED } from './annotation' include { ANNOTATION as ANNOTATE_PER_SAMPLE } from './annotation' include { ANNOTATION as ANNOTATE_PER_SAMPLE_TOOL } from './annotation' -workflow CIRCRNA_DISCOVERY { +workflow BSJ_DETECTION { take: reads diff --git a/subworkflows/local/discovery/circexplorer2.nf b/subworkflows/local/detection_tools/circexplorer2.nf similarity index 100% rename from subworkflows/local/discovery/circexplorer2.nf rename to subworkflows/local/detection_tools/circexplorer2.nf diff --git a/subworkflows/local/discovery/circrna_finder.nf b/subworkflows/local/detection_tools/circrna_finder.nf similarity index 100% rename from subworkflows/local/discovery/circrna_finder.nf rename to subworkflows/local/detection_tools/circrna_finder.nf diff --git a/subworkflows/local/discovery/ciriquant.nf b/subworkflows/local/detection_tools/ciriquant.nf similarity index 100% rename from subworkflows/local/discovery/ciriquant.nf rename to subworkflows/local/detection_tools/ciriquant.nf diff --git a/subworkflows/local/discovery/dcc.nf b/subworkflows/local/detection_tools/dcc.nf similarity index 100% rename from subworkflows/local/discovery/dcc.nf rename to subworkflows/local/detection_tools/dcc.nf diff --git a/subworkflows/local/discovery/find_circ.nf b/subworkflows/local/detection_tools/find_circ.nf similarity index 100% rename from subworkflows/local/discovery/find_circ.nf rename to subworkflows/local/detection_tools/find_circ.nf diff --git a/subworkflows/local/discovery/mapsplice.nf b/subworkflows/local/detection_tools/mapsplice.nf similarity index 100% rename from subworkflows/local/discovery/mapsplice.nf rename to subworkflows/local/detection_tools/mapsplice.nf diff --git a/subworkflows/local/discovery/segemehl.nf b/subworkflows/local/detection_tools/segemehl.nf similarity index 100% rename from subworkflows/local/discovery/segemehl.nf rename to subworkflows/local/detection_tools/segemehl.nf diff --git a/subworkflows/local/discovery/star2pass.nf b/subworkflows/local/detection_tools/star2pass.nf similarity index 100% rename from subworkflows/local/discovery/star2pass.nf rename to subworkflows/local/detection_tools/star2pass.nf diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index af779e8c..7a05e43b 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -28,7 +28,7 @@ include { validateInputSamplesheet } from '../../subworkflows/local/util include { softwareVersionsToYAML } from '../../subworkflows/nf-core/utils_nfcore_pipeline' include { PREPARE_GENOME } from '../../subworkflows/local/prepare_genome' -include { CIRCRNA_DISCOVERY } from '../../subworkflows/local/circrna_discovery' +include { BSJ_DETECTION } from '../../subworkflows/local/bsj_detection' include { ANNOTATION } from '../../subworkflows/local/annotation' include { QUANTIFICATION } from '../../subworkflows/local/quantification' include { MIRNA_PREDICTION } from '../../subworkflows/local/mirna_prediction' @@ -133,10 +133,10 @@ workflow CIRCRNA { ch_multiqc_files = ch_multiqc_files.mix(FASTQC_TRIMGALORE.out.trim_log.collect{it[1]}.ifEmpty([])) // - // 2. circRNA Discovery + // 2. BSJ Discovery // - CIRCRNA_DISCOVERY( + BSJ_DETECTION( FASTQC_TRIMGALORE.out.reads, ch_fasta, ch_gtf, @@ -151,8 +151,8 @@ workflow CIRCRNA { params.exon_boundary ) - ch_multiqc_files = ch_multiqc_files.mix(CIRCRNA_DISCOVERY.out.multiqc_files) - ch_versions = ch_versions.mix(CIRCRNA_DISCOVERY.out.versions) + ch_multiqc_files = ch_multiqc_files.mix(BSJ_DETECTION.out.multiqc_files) + ch_versions = ch_versions.mix(BSJ_DETECTION.out.versions) // // 3. circRNA quantification @@ -162,8 +162,8 @@ workflow CIRCRNA { ch_gtf, ch_fasta, FASTQC_TRIMGALORE.out.reads, - CIRCRNA_DISCOVERY.out.bed12, - CIRCRNA_DISCOVERY.out.gtf, + BSJ_DETECTION.out.bed12, + BSJ_DETECTION.out.gtf, params.bootstrap_samples, ch_phenotype, PREPARE_GENOME.out.faidx @@ -176,8 +176,8 @@ workflow CIRCRNA { // if (params.mature) { MIRNA_PREDICTION( - CIRCRNA_DISCOVERY.out.fasta, - CIRCRNA_DISCOVERY.out.bed, + BSJ_DETECTION.out.fasta, + BSJ_DETECTION.out.bed, ch_mature ) ch_versions = ch_versions.mix(MIRNA_PREDICTION.out.versions) From 532c956b372a3224ea808d2abc1aefcf6f913595 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 11:30:17 +0200 Subject: [PATCH 376/491] Rename params.tool to params.tools --- conf/modules.config | 20 ++++++++++---------- nextflow.config | 2 +- nextflow_schema.json | 14 +++++++------- subworkflows/local/bsj_detection.nf | 2 +- subworkflows/local/prepare_genome.nf | 2 +- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index d273ec07..99ace97d 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -101,7 +101,7 @@ process { } withName: BOWTIE_BUILD { - ext.when = { !params.bowtie && params.tool.split(',').contains('mapsplice') } + ext.when = { !params.bowtie && params.tools.split(',').contains('mapsplice') } publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, @@ -110,7 +110,7 @@ process { } withName: BOWTIE2_BUILD { - ext.when = { !params.bowtie2 && params.tool.split(',').contains('find_circ') } + ext.when = { !params.bowtie2 && params.tools.split(',').contains('find_circ') } publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, @@ -119,7 +119,7 @@ process { } withName: BWA_INDEX { - ext.when = { !params.bwa && params.tool.split(',').contains('ciriquant') } + ext.when = { !params.bwa && params.tools.split(',').contains('ciriquant') } publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, @@ -128,7 +128,7 @@ process { } withName: HISAT2_EXTRACTSPLICESITES { - ext.when = { params.tool.split(',').contains('ciriquant') } + ext.when = { params.tools.split(',').contains('ciriquant') } publishDir = [ path: { "${params.outdir}/references/index/hisat2" }, mode: params.publish_dir_mode, @@ -137,7 +137,7 @@ process { } withName: HISAT2_BUILD { - ext.when = { params.tool.split(',').contains('ciriquant') } + ext.when = { params.tools.split(',').contains('ciriquant') } publishDir = [ path: { "${params.outdir}/references/index" }, mode: params.publish_dir_mode, @@ -146,7 +146,7 @@ process { } withName: STAR_GENOMEGENERATE { - ext.when = { !params.star && ( params.tool.split(',').contains('circexplorer2') || params.tool.split(',').contains('dcc') || params.tool.split(',').contains('circrna_finder') ) } + ext.when = { !params.star && ( params.tools.split(',').contains('circexplorer2') || params.tools.split(',').contains('dcc') || params.tools.split(',').contains('circrna_finder') ) } ext.args = [ "", params.sjdboverhang ? "--sjdbOverhang ${params.sjdboverhang}" : '', ].join(' ').trim() @@ -224,7 +224,7 @@ process { } withName: '.*:STAR2PASS:PASS_1' { - ext.when = { params.tool.split(',').contains('circexplorer2') || params.tool.split(',').contains('circrna_finder') } + ext.when = { params.tools.split(',').contains('circexplorer2') || params.tools.split(',').contains('circrna_finder') } ext.args = [ "", "--chimOutType Junctions WithinBAM", "--outSAMunmapped Within", @@ -253,7 +253,7 @@ process { withName: '.*:STAR2PASS:PASS_2' { ext.args = [ "", - params.tool.split(',').contains('circrna_finder') ? "--chimOutType Junctions SeparateSAMold" : "--chimOutType Junctions WithinBAM", + params.tools.split(',').contains('circrna_finder') ? "--chimOutType Junctions SeparateSAMold" : "--chimOutType Junctions WithinBAM", "--outSAMunmapped Within", "--outFilterType BySJout", "--outReadsUnmapped None", @@ -653,7 +653,7 @@ process { } withName: UPSET_SAMPLES { - ext.when = { params.tool.split(',').length > 1 } + ext.when = { params.tools.split(',').length > 1 } publishDir = [ path: { "${params.outdir}/bsj_detection/samples/${meta.id}" }, mode: params.publish_dir_mode, @@ -662,7 +662,7 @@ process { } withName: UPSET_ALL { - ext.when = { params.tool.split(',').length > 1 } + ext.when = { params.tools.split(',').length > 1 } publishDir = [ path: { "${params.outdir}/bsj_detection/combined" }, mode: params.publish_dir_mode, diff --git a/nextflow.config b/nextflow.config index 5e54776d..cdee4d4d 100644 --- a/nextflow.config +++ b/nextflow.config @@ -16,7 +16,7 @@ params { annotation = null // workflow options - tool = 'circexplorer2' + tools = 'circexplorer2' bsj_reads = 0 tool_filter = 0 exon_boundary = 200 diff --git a/nextflow_schema.json b/nextflow_schema.json index 45770cb8..aebb0311 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -59,9 +59,9 @@ "type": "object", "fa_icon": "fas fa-circle-notch", "description": "Parameters for circrna discovery.", - "required": ["tool"], + "required": ["tools"], "properties": { - "tool": { + "tools": { "type": "string", "fa_icon": "fas fa-wrench", "description": "Comma separated list of circRNA quantification tools to use. Supported tools: ciriquant, circexplorer2, find_circ, circrna_finder, mapsplice, dcc, segemehl", @@ -74,16 +74,16 @@ "fa_icon": "fas fa-circle-notch", "description": "Minimum number of reads spanning circRNA back-splice junction required for circRNA to be output by workflow.", "help_text": "Filter low confidence circRNAs by removing circRNAs with read counts below a specified value. To disable, set the value to 0 (default).", - "default": 0, - "minimum": 0 + "default": 1, + "minimum": 1 }, "tool_filter": { "type": "integer", "fa_icon": "fas fa-intersection", "description": "Specify the minimum number of tools circRNAs must be called by to be output by the workflow.", - "help_text": "When multiple circRNA quantification tools have been provided to `--tool`, set a filtering method whereby circRNAs are output if they have been called by at least *n* quantification tools.\n\nSetting `--tool_filter` to 0/1 is the same as taking the union, all circRNAs are included in the output.\n\nSetting `--tool_filter` to 2 will output circRNAs that have been called by at least 2 quantification tools and so on.", - "default": 0, - "minimum": 0, + "help_text": "When multiple circRNA quantification tools have been provided to `--tool`, set a filtering method whereby circRNAs are output if they have been called by at least *n* quantification tools.\n\nSetting `--tool_filter` to 1 is the same as taking the union, all circRNAs are included in the output.\n\nSetting `--tool_filter` to 2 will output circRNAs that have been called by at least 2 quantification tools and so on.", + "default": 1, + "minimum": 1, "maximum": 7 }, "save_intermediates": { diff --git a/subworkflows/local/bsj_detection.nf b/subworkflows/local/bsj_detection.nf index 7ebe8528..5da9899f 100644 --- a/subworkflows/local/bsj_detection.nf +++ b/subworkflows/local/bsj_detection.nf @@ -58,7 +58,7 @@ workflow BSJ_DETECTION { // // DISCOVERY TOOLS: // - tools_selected = params.tool.split(',').collect{it.trim().toLowerCase()} + tools_selected = params.tools.split(',').collect{it.trim().toLowerCase()} if (tools_selected.size() == 0) { error 'No tools selected for circRNA discovery.' diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome.nf index 76fe152d..cb87f6b4 100644 --- a/subworkflows/local/prepare_genome.nf +++ b/subworkflows/local/prepare_genome.nf @@ -20,7 +20,7 @@ workflow PREPARE_GENOME { // MapSplice cannot deal with extra field in the fasta headers // this removes all additional fields in the headers of the input fasta file - if( params.tool.contains('mapsplice') ) { + if( params.tools.split(',').contains('mapsplice') ) { CLEAN_FASTA(ch_fasta, []) ch_fasta = CLEAN_FASTA.out.output From ac23046f1c24fb77ca11bb6421872ecf399b859c Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 11:40:33 +0200 Subject: [PATCH 377/491] Remove unused species_id parameter --- main.nf | 3 --- nextflow.config | 1 - nextflow_schema.json | 7 ------- workflows/circrna/main.nf | 1 - 4 files changed, 12 deletions(-) diff --git a/main.nf b/main.nf index 022b6be8..23b4c9c0 100644 --- a/main.nf +++ b/main.nf @@ -36,7 +36,6 @@ params.star = getGenomeAttribute('star') params.bowtie = getGenomeAttribute('bowtie') params.bowtie2 = getGenomeAttribute('bowtie2') params.mature = getGenomeAttribute('mature') -params.species_id = getGenomeAttribute('species_id') /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -60,7 +59,6 @@ workflow NFCORE_CIRCRNA { ch_gtf = Channel.value([[id: "gtf"], file(params.gtf, checkIfExists:true)]) ch_mature = params.mature ? Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) : Channel.empty() ch_phenotype = params.phenotype ? Channel.value([[id: "phenotype"], file(params.phenotype, checkIfExists:true)]) : Channel.empty() - ch_species = params.phenotype ? Channel.value(params.species_id) : Channel.empty() ch_annotation = params.annotation ? Channel.fromSamplesheet("annotation") : Channel.empty() CIRCRNA ( @@ -70,7 +68,6 @@ workflow NFCORE_CIRCRNA { ch_gtf, ch_mature, ch_annotation, - ch_species, ch_versions ) diff --git a/nextflow.config b/nextflow.config index cdee4d4d..2080b90c 100644 --- a/nextflow.config +++ b/nextflow.config @@ -34,7 +34,6 @@ params { hisat2_build_memory = '200.GB' segemehl = null save_reference = true - species_id = null // Trimming min_trimmed_reads = 10000 diff --git a/nextflow_schema.json b/nextflow_schema.json index aebb0311..0448bd36 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -220,13 +220,6 @@ "fa_icon": "fas fa-wheelchair", "default": null }, - "species_id": { - "type": "string", - "fa_icon": "fas fa-dog", - "description": "String identifying species.", - "help_text": "Check the igenomes.config file for species configured to work with nf-core/circrna", - "default": null - }, "bowtie": { "type": "string", "fa_icon": "fas fa-bold", diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 7a05e43b..4c1e76ea 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -60,7 +60,6 @@ workflow CIRCRNA { ch_gtf ch_mature ch_annotation - ch_species ch_versions main: From fde46d00ce42101495aab574fb712b680b492bdd Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 11:43:07 +0200 Subject: [PATCH 378/491] Apply parameter changes to test configs --- conf/full.config | 2 +- conf/test.config | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/conf/full.config b/conf/full.config index 4161771d..37cf7778 100644 --- a/conf/full.config +++ b/conf/full.config @@ -12,6 +12,6 @@ */ params { - tool = 'circexplorer2,ciriquant,find_circ,circrna_finder,mapsplice,dcc,segemehl' + tools = 'circexplorer2,ciriquant,find_circ,circrna_finder,mapsplice,dcc,segemehl' tool_filter = 2 } diff --git a/conf/test.config b/conf/test.config index 2f4323e2..6c40a460 100644 --- a/conf/test.config +++ b/conf/test.config @@ -24,10 +24,9 @@ params { fasta = "${params.test_data_base}/reference/chrI.fa" gtf = "${params.test_data_base}/reference/chrI.gtf" mature = "${params.test_data_base}/reference/mature.fa" - tool = "circexplorer2" + tools = "circexplorer2" phenotype = "${params.test_data_base}/phenotype.csv" skip_trimming = false outdir = "results/" bsj_reads = 2 - species_id = "cel" } From a8085274d81cd5a0c941fcd92cbb766589ffeae0 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 11:58:51 +0200 Subject: [PATCH 379/491] Change some default values --- nextflow.config | 6 +++--- nextflow_schema.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nextflow.config b/nextflow.config index 2080b90c..d693ca69 100644 --- a/nextflow.config +++ b/nextflow.config @@ -17,9 +17,9 @@ params { // workflow options tools = 'circexplorer2' - bsj_reads = 0 - tool_filter = 0 - exon_boundary = 200 + bsj_reads = 1 + tool_filter = 1 + exon_boundary = 0 save_intermediates = false // References diff --git a/nextflow_schema.json b/nextflow_schema.json index 0448bd36..eb5452be 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -96,7 +96,7 @@ "type": "integer", "description": "Specify the distance at which the annotation script decides if a candidate is a circRNA or EI-circRNA.", "help_text": "During annotation, if one of the start or end position of a circular candidate imperfectly overlaps an exon boundary, the script will consider positions within 'exon_boundary' (default 200bp) to be an exonic circRNA. If they fall outside of this range, the candidate is assumed to be an exonic-intronic circRNA, and the entire underlying sequence is taken for miRNA analysis, as opposed to just the exonic sequences for canonical exonic circRNAs. ", - "default": 200 + "default": 0 } } }, From 9f6a709459612205b5bb0151627127b649297218 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 11:59:01 +0200 Subject: [PATCH 380/491] Finish updating usage docs --- docs/usage.md | 136 +++++++++++++++++--------------------------------- 1 file changed, 46 insertions(+), 90 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index a0071d87..6f694f6e 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -53,115 +53,71 @@ TREATMENT_REP3,AEG588A6_S6_L004_R1_001.fastq.gz,,reverse An [example samplesheet](../assets/samplesheet.csv) has been provided with the pipeline. -## Phenotype file +## BSJ detection -The CSV file provided via the `phenotype` parameter can be used to provide additional metadata about the samples in the input CSV file. If provided, it needs to at least contain a column called `sample` which corresponds to the `sample` column in the input CSV file and a column called `condition`. The `condition` column will be used to group samples for the [CircTest](https://github.com/dieterich-lab/CircTest) functionality. All metadata columns will be included in the result `SummarizedExperiment` RDS file. +This part of the pipeline is responsible for the detection of back-splice junctions (BSJs) in the input data. The following tools are currently supported: +- `CIRCexplorer2` +- `circRNA finder` +- `CIRIquant` +- `DCC` +- `find circ` +- `MapSplice` +- `Segemehl` -A valid example of a `phenotype.csv` file (matching the "Full samplesheet") is given: +The tools to be used can be specified using the `tools` parameter. +Each of the tools also quantifies how many reads support each BSJ. You can specify a cutoff for the minimum number of reads supporting a BSJ using the `bsj_reads` parameter. +Additionally, the parameter `tool_filter` can be used to specify how many tools a BSJ has to be detected by to be considered as a valid hit. -```csv title="phenotype.csv" -sample,condition -CONTROL_REP1,control -CONTROL_REP2,control -CONTROL_REP3,control -TREATMENT_REP1,treatment -TREATMENT_REP2,treatment -TREATMENT_REP3,treatment -``` - -Note that `TREATMENT_REP3` only has one entry in the `phenotype.csv` file, even though it has two entries in the `samplesheet.csv` file. - -## circRNA discovery +For instructions on how to interpret the output of this section, please check out the [output documentation](https://nf-co.re/circrna/dev/output#bsj-detection). -The core module of `nf-core/circrna`, a user can utilise up to seven circRNA quantification tools to fully characterise the circRNA profile in samples. +## Annotation -Currently, supported tools include `CIRCexplorer2`, `circRNA finder`, `CIRIquant`, `DCC`, `find circ` , `MapSplice` & `Segemehl` however, the authors of `nf-core/circrna` welcome contributions from authors of novel quantification tools to keep the workflow current. +The annotation is generally based on the reference GTF file. It can also utilize BED files that are provided by the various circRNA databases. +The GTF-based annotation allows setting the parameter `exon_boundary` to specify a window around exons. If the BSJ is within this window, it will be annotated as a circRNA - otherwise, it will be annotated as an exon-intron circRNA (EI-circRNA). The default value is 0. -By default, `nf-core/circrna` runs the circRNA discovery analysis module. - -```bash -nextflow run nf-core/circrna \ - -profile \ - --genome 'GRCh37' \ - --input 'samples.csv' \ - --module 'circrna_discovery' -``` - -To view the outputs of the module, please see the output [documentation](https://nf-co.re/circrna/dev/output#circrna-quantification). - -> Please note that this module must be included for every run of the workflow - -### Tool selection - -The user may use one, all or any combination of circRNA quantification tools listed above in the analysis. To select which tools to use for the analysis, specify the `--tool` parameter in the configuration profile or pass it via the command line when running the workflow: - -```bash -nextflow run nf-core/circrna \ - -profile \ - --genome 'GRCh37' \ - --input 'samples.csv' \ - --tool 'ciriquant,dcc,find_circ' +For the database-based annotation, an additional sample sheet is required: +```csv title="annotation.csv" +name,file,min_overlap +db1,db1.bed,0.9 +db2,db2.bed,0.8 ``` -> When providing multiple tools, separate each entry with a comma. - -### circRNA filtering - -`nf-core/circrna` offers robust filtering of each called circRNA to reduce the number of spurious calls within the dataset. - -#### BSJ reads +| Column | Description | +| ------------ | --------------------------------------------------------------------------------------------- | +| `name` | Name of the database. This will be used as a prefix for the region names in the output files. | +| `file` | Path to the BED file. The file has to be a valid BED6 file. | +| `min_overlap`| Minimum bidirectional overlap required between the BSJ and the region in the BED file. | -The user can specify the minimum number of reads spanning the back-splice junction site required for a circRNA to be considered for further analysis. circRNAs with counts below this value will be filtered to remove from the results. +The output of the annotation step will be bundled with the outputs of the BSJ detection step. -To apply this filtering method, specify the `--bsj_reads` parameter in the configuration profile or pass it via the command line when running the workflow: - -```bash -nextflow run nf-core/circrna \ - -profile \ - --genome 'GRCh37' \ - --input 'samples.csv' \ - --phenotype 'phenotype.csv' \ - --tool 'ciriquant, dcc, find_circ' \ - --bsj_reads 2 -``` - -Disable the filter by setting the value to 0. - -#### Multiple tool filtering - -When more than one tool has been provided using the `--tool` parameter, the user can specify the minimum number of tools circRNAs must be called by using `--tool_filter`. Setting this parameter to 0 or 1 will result in the union being output, i.e no filtering is applied. Setting this parameter to 2 will output circRNAs that have been called by at least 2 quantification tools and so on. - -> The integer provided to the parameter must be less than or equal to the number of quantification tools provided to `--tool`. +## miRNA prediction -To apply this filtering method, specify the `--tool_filter` parameter in the configuration profile or pass it via the command line when running the workflow: +This section allows looking for miRNA binding sites in the circRNAs. The following tools are currently supported: +- `miRanda` +- `TargetScan` -```bash -nextflow run nf-core/circrna \ - -profile \ - --genome 'GRCh37' \ - --input 'samples.csv' \ - --tool 'ciriquant, dcc, find_circ' \ - --bsj_reads 2 \ - --tool_filter 2 -``` +This section will only be executed if the `mature` parameter is provided. The parameter should point to a FASTA file containing mature miRNA sequences. -> This filtering method is reflected in the circRNA count matrix. Per tool circRNA annotations are subject to back-splice read filtering only. +To view the outputs of the module, please see the output [documentation](https://nf-co.re/circrna/dev/output#mirna-prediction). -## miRNA prediction +## Statistical tests -The second module of `nf-core/circrna`, `mirna_prediction` analyses the mature spliced sequences of circRNAs to test for the presence of miRNA response elements using both `miRanda` and `TargetScan`. Results from both tools are consolidated and filtering methods are applied to produce robust miRNA target predictions of circRNAs in the dataset. +Currently, only [CircTest](https://github.com/dieterich-lab/CircTest) is supported for the statistical analysis of the circRNA expression data. The `phenotype` parameter is required for this step. -To invoke the module, specify the `--module` parameter via the configuration profile or pass it via the command line when running the workflow: +A valid example of a `phenotype.csv` file (matching the "Full samplesheet") is shown here: -```bash -nextflow run nf-core/circrna \ - -profile \ - --genome 'GRCh37' \ - --input 'samples.csv' \ - --module 'circrna_discovery,mirna_prediction' +```csv title="phenotype.csv" +sample,condition +CONTROL_REP1,control +CONTROL_REP2,control +CONTROL_REP3,control +TREATMENT_REP1,treatment +TREATMENT_REP2,treatment +TREATMENT_REP3,treatment ``` -To view the outputs of the module, please see the output [documentation](https://nf-co.re/circrna/dev/output#mirna-prediction). +Note that `TREATMENT_REP3` only has one entry in the `phenotype.csv` file, even though it has two entries in the `samplesheet.csv` file. +If the `phenotype` parameter is provided, the phenotype information will also be added to the `SummarizedExperiment` object, that results from the "Quantification" step. ## Running the pipeline From b0f797b37e67e63bfa6cffa536cca6250584d85e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 12:15:15 +0200 Subject: [PATCH 381/491] Add output directory structure documentation --- docs/output.md | 50 +++++++++++++++++++------------------------------- 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/docs/output.md b/docs/output.md index fdd9bf48..66a8f743 100644 --- a/docs/output.md +++ b/docs/output.md @@ -2,11 +2,6 @@ ## Introduction -:::warning -This page has not been updated for a long time and might not align with the current pipeline output. We are working on updating it. -If you have questions regarding the pipeline output, feel free to reach out in the [nf-core slack](https://nfcore.slack.com/channels/circrna) channel. -::: - This document describes the output produced by the pipeline. Most of the plots are taken from the MultiQC report generated from the [full-sized test dataset](https://github.com/nf-core/test-datasets/tree/circrna) for the pipeline using a command similar to the one below: ```bash @@ -15,32 +10,25 @@ nextflow run nf-core/circrna -profile test_full, The directories listed below will be created in the results directory after the pipeline has finished. All paths are relative to the top-level results directory. -## Pipeline Overview - -The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes data using the following steps: - -- Raw read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/)) -- Adapter trimming ([`Trim Galore!`](https://www.bioinformatics.babraham.ac.uk/projects/trim_galore/)) -- BSJ detection - - [`CIRIquant`](https://github.com/Kevinzjy/CIRIquant) - - [`STAR 2-Pass mode`](https://github.com/alexdobin/STAR) - - [`CIRCexplorer2`](https://circexplorer2.readthedocs.io/en/latest/) - - [`circRNA finder`](https://github.com/orzechoj/circRNA_finder) - - [`DCC`](https://github.com/dieterich-lab/DCC) - - [`find circ`](https://github.com/marvin-jens/find_circ) - - [`MapSplice`](http://www.netlab.uky.edu/p/bioinfo/MapSplice2) - - [`Segemehl`](https://www.bioinf.uni-leipzig.de/Software/segemehl/) -- circRNA annotation -- Extract circRNA sequences and build circular transcriptome -- Merge circular transcriptome with linear transcriptome derived from provided GTF -- Quantification of combined circular and linear transcriptome - - [`psirc-quant`](https://github.com/Christina-hshi/psirc) -- miRNA binding affinity analysis (only if the `mature` parameter is provided) - - [`miRanda`](http://cbio.mskcc.org/miRNA2003/miranda.html) - - [`TargetScan`](http://www.targetscan.org/cgi-bin/targetscan/data_download.vert72.cgi) -- Statistical tests (only if the `phenotype` parameter is provided) - - [`CircTest`](https://github.com/dieterich-lab/CircTest) -- MultiQC report [`MultiQC`](http://multiqc.info/) +- references: Indices for various tools and intermediate reference genome files +- preprocessing: Per-sample concatenated FASTQ files +- quality_control: FastQC reports and TrimGalore reports +- bsj_detection + - combined: Combined BSJ calls across all samples + - samples: Per sample BSJ calls + - tools: Per tool and sample BSJ calls +- quantification + - combined: Quantification results for linear and circular transcripts across samples + - samples: Per sample quantification results + - transcriptome: Combined linear and circular transcriptome, based on GTF file and detected BSJs +- mirna_prediction + - miranda + - targetscan + - combined +- statistical_tests + - circtest +- multiqc +- pipeline_info ## Quality Control From 5bdd08bd2b2e283adbc0562a5af4eee7ff577e17 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 14:46:10 +0200 Subject: [PATCH 382/491] Add documentation for references output --- conf/modules.config | 20 +++++++++--------- docs/output.md | 51 ++++++++++++++++++++++++++++++--------------- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 99ace97d..4f959433 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -76,7 +76,7 @@ process { withName: CLEAN_FASTA { ext.args2 = '\'/>/{ gsub(\$2, "",\$2);gsub(" ", "") };{print}\'' publishDir = [ - path: { "${params.outdir}/references/clean_fasta" }, + path: { "${params.outdir}/references/genome/clean_fasta" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] @@ -85,16 +85,16 @@ process { withName: GTFFILTER { ext.suffix = "filtered.gtf" publishDir = [ - path: { "${params.outdir}/references/filtered_gtf" }, + path: { "${params.outdir}/references/genome/filtered_gtf" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] } withName: SEQKIT_SPLIT { ext.args = "-i --by-id-prefix \"\"" publishDir = [ - path: { "${params.outdir}/references/chromosomes" }, + path: { "${params.outdir}/references/genome/chromosomes" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] @@ -277,7 +277,7 @@ process { "-geneNameAsName2" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/references/circexplorer2" }, + path: { "${params.outdir}/references/bsj_detection/circexplorer2" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] @@ -535,7 +535,7 @@ process { "-geneNameAsName2" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/references/mapsplice" }, + path: { "${params.outdir}/references/bsj_detection/mapsplice" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] @@ -733,7 +733,7 @@ process { publishDir = [ path: { "${params.outdir}/references/named_databases" }, mode: params.publish_dir_mode, - saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] } @@ -847,7 +847,7 @@ process { withName: PSIRC_INDEX { publishDir = [ - path: { "${params.outdir}/references/psirc" }, + path: { "${params.outdir}/references/index/psirc" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null } ] @@ -914,9 +914,9 @@ process { withName: TARGETSCAN_DATABASE { publishDir = [ - path: { "${params.outdir}/references/targetscan" }, + path: { "${params.outdir}/references/mirna_prediction/targetscan" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_reference ) ? filename : null }, pattern: "mature.txt" ] } diff --git a/docs/output.md b/docs/output.md index 66a8f743..cf002b53 100644 --- a/docs/output.md +++ b/docs/output.md @@ -12,7 +12,9 @@ The directories listed below will be created in the results directory after the - references: Indices for various tools and intermediate reference genome files - preprocessing: Per-sample concatenated FASTQ files -- quality_control: FastQC reports and TrimGalore reports +- quality_control + - fastqc: FastQC reports for raw reads + - trimgalore: Trim Galore! reports for trimmed reads - bsj_detection - combined: Combined BSJ calls across all samples - samples: Per sample BSJ calls @@ -45,7 +47,7 @@ The FastQC plots displayed in the MultiQC report show _untrimmed_ reads. They ma - `*_fastqc.html`: FastQC report containing quality metrics. - `*_fastqc.zip`: Zip archive containing the FastQC report, tab-delimited data file and plot images. -> **NB:** The FastQC plots in this directory are generated relative to the raw, input reads. They may contain adapter sequence and regions of low quality. To see how your reads look after adapter and quality trimming please refer to the FastQC reports in the `trimgalore/fastqc/` directory. +> **NB:** The FastQC plots in this directory are generated relative to the raw, input reads. They may contain adapter sequence and regions of low quality. @@ -73,8 +75,6 @@ The FastQC plots displayed in the MultiQC report show _untrimmed_ reads. They ma [Trim Galore!](https://www.bioinformatics.babraham.ac.uk/projects/trim_galore/) is a wrapper tool around Cutadapt and FastQC to peform quality and adapter trimming on FastQ files. By default, Trim Galore! will automatically detect and trim the appropriate adapter sequence. -> **NB:** TrimGalore! will only run using multiple cores if you are able to use more than > 5 and > 6 CPUs for single- and paired-end data, respectively. The total cores available to TrimGalore! will also be capped at 4 (7 and 8 CPUs in total for single- and paired-end data, respectively) because there is no longer a run-time benefit. See [release notes](https://github.com/FelixKrueger/TrimGalore/blob/master/Changelog.md#version-060-release-on-1-mar-2019) and [discussion whilst adding this logic to the nf-core/atacseq pipeline](https://github.com/nf-core/atacseq/pull/65). - ![MultiQC - cutadapt trimmed sequence length plot](images/mqc_cutadapt_trimmed.png) ### MultiQC @@ -90,29 +90,46 @@ The FastQC plots displayed in the MultiQC report show _untrimmed_ reads. They ma [MultiQC](http://multiqc.info) is a visualization tool that generates a single HTML report summarising all samples in your project. `nf-core` outputs HTML reports for sequencing read quality control. -## Genome Index Files +## Reference files + +

      +Output files + +- `references` + - `index` + - `bowtie`: Directory containing `Bowtie` indices. + - `bowtie2`: Directory containing `Bowtie2` indices. + - `bwa`: Directory containing `BWA` indices. + - `fasta`: Directory containing FASTA index (`.fai`). + - `hisat2`: Directory containing `HISAT2` indices. + - `segemehl`: Directory containing `Segemehl` index file. + - `star`: Directory containing `STAR` indices. + - `genome` + - `clean_fasta`: Directory containing a FASTA file with reduced headers, since MapSplice has problems with multiple header fields. + - `filtered_gtf`: Directory containing a GTF file with only entries that reside on chromosomes present in the reference FASTA file. + - `chromosomes`: Directory containing individual FASTA files for each chromosome. + - `bsh_detection` + - `circexplorer2`: Directory containing the `CIRCexplorer2` annotation file. + - `mapsplice`: Directory containing the `MapSplice` annotation file. + - `mirna_prediction` + - `targetscan`: Directory containing the TargetScan miRNA database. + +
      + +`nf-core/circrna` will add the reference files to the output directory if `save_reference` is set to `true`. The resulting files, especially the aligner indices, can be used for speeding up future runs (if the `resume` option cannot be used). In order to achieve this, copy the indices to a location outside of the pipeline's output directory and provide the path to the indices via the corresponding aligner flags (check the [parameters documentation](https://nf-co.re/circrna/dev/parameters/#reference-genome-options) for more information). + +## Pipeline info
      Output files -- `reference_genome` - - `BowtieIndex/`: Directory containing `Bowtie` indices. - - `Bowtie2Index/`: Directory containing `Bowtie2` indices. - - `BWAIndex/`: Directory containing `BWA` indices. - - `Hisat2Index/`: Directory containing `HISAT2` indices. - - `SAMtoolsIndex`: Directory containing `SAMtools` index file. - - `STARIndex`: Directory containing `STAR` indices. - - `SegemehlIndex`: Directory containing `Segemehl` index file. -- `pipeline_info/` +- `pipeline_info` - Reports generated by Nextflow: `execution_report.html`, `execution_timeline.html`, `execution_trace.txt` and `pipeline_dag.dot`/`pipeline_dag.svg`. - Reports generated by the pipeline: `pipeline_report.html`, `pipeline_report.txt` and `software_versions.yml`. The `pipeline_report*` files will only be present if the `--email` / `--email_on_fail` parameter's are used when running the pipeline. - - Reformatted samplesheet files used as input to the pipeline: `samplesheet.valid.csv`. - Parameters used by the pipeline run: `params.json`.
      -`nf-core/circrna` will save genome indices when `--save_reference true`. This is highly encouraged to reduce runtimes on redeployment of the workflow, as you can supply them to aligner in question via the aligner flag (for example `--star '/path/to/STAR/'`. Available: `bowtie`, `bowtie2`, `bwa`, `hisat2`, `star`, `segemehl`). Make sure to move the saved genome indicies to a different location before doing so. - ## circRNA Quantification ## Common Outputs From bd08029ac7ac2f35b73ec02972b8f319cba4a30f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 15:43:12 +0200 Subject: [PATCH 383/491] Improve STAR output documentation --- conf/modules.config | 6 +- docs/output.md | 145 +++++++++++++++++--------------------------- 2 files changed, 60 insertions(+), 91 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 4f959433..95fd32d9 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -237,7 +237,7 @@ process { "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/bsj_detection/tools/star/1st_pass" }, + path: { "${params.outdir}/bsj_detection/tools/star/1st_pass/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -245,7 +245,7 @@ process { withName: '.*:STAR2PASS:SJDB' { publishDir = [ - path: { "${params.outdir}/bsj_detection/tools/star/sjdb" }, + path: { "${params.outdir}/bsj_detection/tools/star/sjdb/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] @@ -265,7 +265,7 @@ process { "--chimSegmentMin ${params.chimSegmentMin}" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/bsj_detection/tools/star/2nd_pass" }, + path: { "${params.outdir}/bsj_detection/tools/star/2nd_pass/${meta.id}" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] diff --git a/docs/output.md b/docs/output.md index cf002b53..aa706260 100644 --- a/docs/output.md +++ b/docs/output.md @@ -130,86 +130,46 @@ The FastQC plots displayed in the MultiQC report show _untrimmed_ reads. They ma -## circRNA Quantification +## BSJ detection -## Common Outputs +The rough workflow for the BSJ detection looks like this: +1. Each tools detects BSJs in each sample and quantifies how many reads support each BSJ. +2. Bring the tool outputs into a common format. +3. Apply a threshold (parameter `bsj_reads) to the BSJ reads to filter out lowly supported BSJs. +4. Combine all tool-specific BSJ calls per sample into a single file. +5. Filter out BSJs that are not supported by at least `tool_filter` tools. +6. Merge all samples into a single file. This now represents the "circular transcriptome" -The workflow is designed to output three files _per sample_, _per quantification tool_ in the `circrna_discovery` directory. Using the test dataset as an example, the directory structure for the `fust_1` sample is: +### Per tool -````console -|-- results/ - |-- circrna_discovery/ - |-- circexplorer2/ - | -- fust_1/ - | -- fust_1.bed - | -- fust_1.fasta - | -- fust_1.log - - -- `${sample_id}.bed`: A customised BED 12 file containing filtered, annotated circRNAs. Columns: chromosome, start, end, name, read counts, strand, start, end, RGB, number of exon blocks, size of exon blocks, start positions (within sequence) of exon blocks, parent gene ID(s), parent transcript ID(s), mature spliced length. -- `${sample_id}.log`: Script detailing the decisions made by `annotate_outputs.sh` when annotating each circRNA. -- `${sample_id}.fasta`: Mature spliced sequence of circRNA in FASTA format. Includes splice junction site (+-20bp). - -Sample outputs for the corresponding `.log`, `.bed` and `.fasta` entry are given below for a circRNA called by `CIRCexplorer2`: - -```console -[nf-core/circrna]: Starting analysis for: chrI:1140805-1147588:- -[nf-core/circrna]: chrI:1140805-1147588:- overlaps features in GTF file -[nf-core/circrna]: Inspecting Genes... -[nf-core/circrna]: Overlapping Gene IDs: Y48G8AL.10 -[nf-core/circrna]: Converting to BED12 -[nf-core/circrna]: Attempting to fit circRNA to gene exon boundaries -[nf-core/circrna]: chrI:1140805-1147588:- fits gene exons, is a circRNA -[nf-core/circrna]: cleaning up intermediate files -```` - -```console -chrI 1140805 1147588 chrI:1140805-1147588:- 2 - 1140805 1147588 0 5 229,214,191,141,499 0,1282,2546,4912,6284 circRNA Y48G8AL.10 NM_001306296,NM_001306297,NM_001306298,NM_001306299 1274 -``` +
      +Output files available for all tools -```console ->chrI:1087252-1088602:- -CATGAAGTCTCGAGATCTCGTTTATAAGCACCAATATCCACGTTCAGCATTATTGATTGataaaattaatttataaattcgaaaataaaatttaaatttttCTTTAGAAATTATCGATTTATCGACTTCCACGTAATTCCACACCACGCTAAAATTCCATATCAATCTCGCGTTGTTTGGCTTCTCGTTGGGTGTCCGCCGCGTGGGAGTAGTATCTGCAAAAAAAAATTTGAGAATAAAAAATGTAAAATTGtttttcctattttctattgccgaaatttgagatttccggcaaatcggcaaattgccggaattgaaatttgcggcaaatcggcaaactgccgcaattgaaatttcgggtaaatcggcaaatttccggcaaatcggcatattgccggaatttaaatttccggcaaggcggccaatcggaaaattggcaaattgccgcaattgaaatttgcggcaaatcggcaattgtcgactattttcgacaacttctcgctttgcacttttttgtacatttcagattttttttcaatttcaatcggcaaaaacatttccggcaaatcggtaaattgccagaattgaaatttccggcaaatcggcaaattgccggaattgaaatttcccgcaaatcggcaaatttctttaattgaaatttccggcaaatcggtaaattgccggaatttaaatttccggcaactcggcaaactgccccaattgaaatttccggtaaatcggtaaaatgccgaaatttaaatttccggcaaggtggcaaatcggaaaattggcaaattgccggaattcaaatatccggcaaatcggcaagttgctggaattgaaatttccggcaaggcggcaaatttccggcaaatcggcaattGTCTTATattttcgacaacttctcgttttgcacttttttttgtacatttcaggttttttttcaatttcaatcggcaaaaacatttccggcaaatctgatatccggcaaacggcaaatcggcaatttgccgaaaataaaaaattcaagcaactcggcaaaccggcaaattTTATAGAGCACATTTGACCCACCTATTGAGAATAAACAATTGCGAGATAAAAATCTTGATGTAAATTCCGGCGAATGCGATCAAAATTGCTTTTCGATCTGAAAAAAATCCAATTTTGCTCAGCCAATAAATGGACGGAGCTAAAAACAAGGCGCTACTCACGAGAAATCCACTCATACGGGTCTTCTGTCACATTTTCCTGCTCGGATTTCGATTTTGGCGTATCTTCGGTCGGATTTCCGTGGTAATCGGACAACCAGGCAATCACTACAATTATTGCGCAAATGAATCGGGCAAC -``` +- `unified`: Directory containing the BSJ calls in the BED6 format. +- `filtered`: Based on `unified`, but filtered for BSJs with at least `bsj_reads` supporting reads. +- `masked`: Based on `filtered`, but scores are replaced by a dot (.) +- `annotated`: Based on `masked`, but with additional columns for the circRNA type, the host gene(s), host transcript(s) and potential database hits. Contains a BED and a GTF file for each sample. +- `fasta`: Extracted sequences of the circRNAs in FASTA format. Based on `masked`. +- `intermediates`: Contains intermediate files generated by the BSJ detection tools, as explained below. -The workflow's manual annotation process is designed to mimick annotation performed by `CIRCexplorer2` to standardise the annotation process for all circRNA quantification tools. +
      -Intermediate files generated by each quantification tool are described in depth below. +An exemption of the above is `star`, which is not used as a standalone BSJ detection tool, but the output of a 2-pass STAR alignment is used by `CIRCexplorer2`, `circRNA finder` and `DCC`. -### CIRCexplorer2 +#### CIRCexplorer2
      Output files -- `circrna_discovery/circexplorer2/intermediates/${sample_id}/` - - - `*.bed`: Intermediate file generated by `CIRCexplorer2 parse` module, identifying STAR fusion junctions for downstream annotation. - - `*_circexplorer2_circs.bed`: Filtered BED6 file containing circRNA counts used for count matrix generation. - - `*.txt`: Output files generated by `CIRCexplorer2 annotate` module, based on BED 12 format containing circRNA genomic location information, exon cassette composition and an additional 6 columns specifying circRNA annotations. Full descriptions of the 18 columns can be found in the `CIRCexplorer2` [documentation](https://circexplorer2.readthedocs.io/en/latest/modules/annotate/#output). - -- `circrna_discovery/star` - - `1st_pass` - - `*.Aligned.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. - - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). - - `*.Log.final.out`: Summary mapping statistics after mapping job is complete, useful for quality control. The statistics are calculated for each read (single- or paired-end) and then summed or averaged over all reads. - - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. - - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. - - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). - - `2nd_pass` - - `*.Aligned.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. - - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). - - `*.Log.final.out`: Summary mapping statistics after mapping job is complete, useful for quality control. The statistics are calculated for each read (single- or paired-end) and then summed or averaged over all reads. - - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. - - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. - - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). - - `sjdb` - - `dataset.SJ.out.tab`: Chromosome, start, end & strand coordinates of novel splice junctions for **all samples** aligned using STAR 1st pass. +- `bsj_detection/tools/circexplorer2/intermediates/${sample_id}/` + - `${sample_id}.bed`: Intermediate file generated by `CIRCexplorer2 parse` module, identifying STAR fusion junctions for downstream annotation. + - `${sample_id}.txt`: Output files generated by `CIRCexplorer2 annotate` module, based on BED 12 format containing circRNA genomic location information, exon cassette composition and an additional 6 columns specifying circRNA annotations. Full descriptions of the 18 columns can be found in the `CIRCexplorer2` [documentation](https://circexplorer2.readthedocs.io/en/latest/modules/annotate/#output).
      [CIRCexplorer2](https://circexplorer2.readthedocs.io/en/latest/) uses `*.Chimeric.out.junction` files generated from `STAR` 2 pass mode to extract back-splice junction sites using the `CIRCexplorer2 parse` module. Following this, `CIRCexplorer2 annotate` performs re-alignment of reads to the back-splice junction sites to determine the precise positions of downstream donor and upstream acceptor splice sites. Back-splice junction sites are subsequently updated and annotated using the customised annotation text file. -### circRNA finder +#### circRNA finder
      Output files @@ -220,30 +180,11 @@ Intermediate files generated by each quantification tool are described in depth - `*.s_filteredJunctions.bed`: A bed file with those junctions in `*.filteredJunctions.bed` that are flanked by GT-AG splice sites. The score column indicates the number reads spanning each junction. - `*.s_filteredJunctions_fw.bed`: A bed file with the same circular junctions as in file (b), but here the score column gives the average number of forward spliced reads at both splice sites around each circular junction. -- `circrna_discovery/star` - - `1st_pass` - - `*.Aligned.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. - - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). - - `*.Log.final.out`: Summary mapping statistics after mapping job is complete, useful for quality control. The statistics are calculated for each read (single- or paired-end) and then summed or averaged over all reads. - - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. - - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. - - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). - - `2nd_pass` - - `*.Aligned.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. - - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). - - `*.Chimeric.out.sam`: Chimeric alignments in SAM format. - - `*.Log.final.out`: Summary mapping statistics after mapping job is complete, useful for quality control. The statistics are calculated for each read (single- or paired-end) and then summed or averaged over all reads. - - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. - - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. - - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). - - `sjdb` - - `dataset.SJ.out.tab`: Chromosome, start, end & strand coordinates of novel splice junctions for **all samples** aligned using STAR 1st pass. -
      [circRNA finder](https://github.com/orzechoj/circRNA_finder) uses `*.Chimeric.out.sam`, `*.Chimeric.out.junction` & `*.SJ.out.tab` from STAR 2nd pass files to identify circular RNAs in RNA-Seq data. -### CIRIquant +#### CIRIquant
      Output files @@ -264,7 +205,7 @@ Intermediate files generated by each quantification tool are described in depth [CIRIquant](https://github.com/Kevinzjy/CIRIquant) operates by aligning RNA-Seq reads using `HISAT2` and [CIRI2](https://sourceforge.net/projects/ciri/files/CIRI2/) to identify putative circRNAs. Next, a pseudo reference index is generated using `bwa index` by concatenating the two full-length sequences of the putative back-splice junction regions. Candidate circular reads are re-aligned against this pseudo reference using `bwa mem`, and back-splice junction reads are determined if they can be linearly and completely aligned to the putative back-splice junction regions. -### DCC +#### DCC
      Output files @@ -288,7 +229,7 @@ Intermediate files generated by each quantification tool are described in depth 4. Circular reads aligning to mitochondrial genome are removed. 5. Circular reads that lack a canonical (GT/AG) splicing signal at the circRNA junction borders are removed. -### Find circ +#### Find circ
      Output files @@ -310,7 +251,7 @@ Intermediate files generated by each quantification tool are described in depth 4. Breakpoint cannot reside more than 2nt inside a 20mer anchor. 5. 2 reads must support the junction. -### MapSplice +#### MapSplice
      Output files @@ -332,7 +273,7 @@ Intermediate files generated by each quantification tool are described in depth [MapSplice](http://www.netlab.uky.edu/p/bioinfo/MapSplice2) first splits reads into segments, and maps them to reference genome by using `Bowtie`. `MapSplice` attempts to fix unmapped segments as gapped alignments, with each gap corresponding to a splice junction. Finally a remapping step is used to identify back-spliced alignments that are in the presence of small exons. -### Segemehl +#### Segemehl
      Output files @@ -347,6 +288,34 @@ Intermediate files generated by each quantification tool are described in depth `Segemehl` implements split read alignment mode for reads that failed the attempt of collinear alignment. The algorithm will consider circular alignments. Circular splits are output to `${sample_id}.sngl.bed` and parsed using customised scripts to produce counts representative of `Segemehl` quantification. +#### STAR + +
      +Output files + +- `bsj_detection/tools/star` + - `1st_pass` + - `*.Aligned.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. + - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). + - `*.Log.final.out`: Summary mapping statistics after mapping job is complete, useful for quality control. The statistics are calculated for each read (single- or paired-end) and then summed or averaged over all reads. + - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. + - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. + - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). + - `2nd_pass` + - `*.Aligned.out.bam`: Coordinate sorted bam file containing aligned reads and chimeric reads. + - `*.Chimeric.out.junction`: Each line contains the details of chimerically aligned reads. Full descriptions of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 5.4). + - `*.Chimeric.out.sam`: Chimeric alignments in SAM format. + - `*.Log.final.out`: Summary mapping statistics after mapping job is complete, useful for quality control. The statistics are calculated for each read (single- or paired-end) and then summed or averaged over all reads. + - `*.Log.out`: Main log file with a lot of detailed information about the run. This file is most useful for troubleshooting and debugging. + - `*.Log.progress.out`: Reports job progress statistics, such as the number of processed reads, % of mapped reads etc. + - `*.SJ.out.tab`: High confidence collapsed splice junctions in tab-delimited form. Full description of columns can be found in `STAR` [documentation](https://physiology.med.cornell.edu/faculty/skrabanek/lab/angsd/lecture_notes/STARmanual.pdf) (section 4.4). + - `sjdb` + - `dataset.SJ.out.tab`: Chromosome, start, end & strand coordinates of novel splice junctions for **all samples** aligned using STAR 1st pass. + +
      + +STAR in 2-pass mode is used to identify novel splice junctions in RNA-Seq data. The first pass of STAR is used to generate a genome index and align reads to the reference genome. The second pass of STAR uses the splice junctions identified in the first pass to align reads to the reference genome. This does not increase the number of detected novel junctions, but allows for more sensitive detection of splice reads mapping to novel junctions. + ### Count Matrix
      From a311c4a24f565e78cd79e03831ec6cea819ab9b7 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 15:49:21 +0200 Subject: [PATCH 384/491] Improve output docs for various detection tools --- conf/modules.config | 2 +- docs/output.md | 22 +++++++++------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 95fd32d9..fac43d45 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -173,7 +173,7 @@ process { "-S" ].join(' ').trim() publishDir = [ - path: { "${params.outdir}/bsj_detection/tools/segemehl/raw" }, + path: { "${params.outdir}/bsj_detection/tools/segemehl/intermediates" }, mode: params.publish_dir_mode, saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } ] diff --git a/docs/output.md b/docs/output.md index aa706260..a25daabb 100644 --- a/docs/output.md +++ b/docs/output.md @@ -162,8 +162,8 @@ An exemption of the above is `star`, which is not used as a standalone BSJ detec Output files - `bsj_detection/tools/circexplorer2/intermediates/${sample_id}/` - - `${sample_id}.bed`: Intermediate file generated by `CIRCexplorer2 parse` module, identifying STAR fusion junctions for downstream annotation. - - `${sample_id}.txt`: Output files generated by `CIRCexplorer2 annotate` module, based on BED 12 format containing circRNA genomic location information, exon cassette composition and an additional 6 columns specifying circRNA annotations. Full descriptions of the 18 columns can be found in the `CIRCexplorer2` [documentation](https://circexplorer2.readthedocs.io/en/latest/modules/annotate/#output). + - `*.bed`: Intermediate file generated by `CIRCexplorer2 parse` module, identifying STAR fusion junctions for downstream annotation. + - `*.txt`: Output files generated by `CIRCexplorer2 annotate` module, based on BED 12 format containing circRNA genomic location information, exon cassette composition and an additional 6 columns specifying circRNA annotations. Full descriptions of the 18 columns can be found in the `CIRCexplorer2` [documentation](https://circexplorer2.readthedocs.io/en/latest/modules/annotate/#output).
      @@ -174,7 +174,7 @@ An exemption of the above is `star`, which is not used as a standalone BSJ detec
      Output files -- `circrna_discovery/circrna_finder/intermediates/${sample_id}/` +- `bsj_detection/tools/circrna_finder/intermediates/${sample_id}/` - `*.filteredJunctions.bed`: A bed file with **all** circular junctions found by the pipeline. The score column indicates the number reads spanning each junction. - `*.s_filteredJunctions.bed`: A bed file with those junctions in `*.filteredJunctions.bed` that are flanked by GT-AG splice sites. The score column indicates the number reads spanning each junction. @@ -189,7 +189,7 @@ An exemption of the above is `star`, which is not used as a standalone BSJ detec
      Output files -- `circrna_discovery/ciriquant/intermediates/${sample_id}/` +- `bsj_detection/tools/ciriquant/intermediates/${sample_id}/` - `*.log`: A `CIRIerror.log` file which should be empty, and a `${sample_id}.log` file which contains the output log of `CIRIquant`. - `*.bed`: `CIRI2` output file in BED 6 format. - `*.gtf`: Output file from `CIRIquant` in GTF format. Full description of the columns available in the `CIRIquant` [documentation](https://ciriquant-cookbook.readthedocs.io/en/latest/quantification.html#output-format). @@ -210,12 +210,8 @@ An exemption of the above is `star`, which is not used as a standalone BSJ detec
      Output files -- `/circrna_discovery/DCC/intermediates/${sample_id}/` - - - `*CircCoordinates`: Circular RNA annotations in BED format. Full description of the columns are available in the `DCC` [documentation](https://github.com/dieterich-lab/DCC#output-files-generated-by-dcc). - - `*CircRNACount`: A table containing read counts for circRNAs detected. - - `mate1/`: Output directory of STAR 2nd pass alignment for R1. - - `mate2/`: Output directory of STAR 2nd pass alignment for R2. +- `/bsj_detection/tools/dcc/intermediates/${sample_id}/` + - `*.txt`: Output file from `DCC` containing position and BSJ read counts of circRNAs.
      @@ -234,7 +230,7 @@ An exemption of the above is `star`, which is not used as a standalone BSJ detec
      Output files -- `circrna_discovery/find_circ/intermediates/${sample_id}/` +- `bsj_detection/tools/find_circ/intermediates/${sample_id}/` - `*_anchors.qfa.gz`: 20mer anchors extracted from unmapped reads. - `*_unmapped.bam`: Unmapped RNA-Seq reads to reference genome. - `*.sites.bed`: Output from `find_circ`, first six columns are in standard BED format. A description of the remaining columns is available in the `find_circ` [documentation](https://github.com/marvin-jens/find_circ#output-format). @@ -256,7 +252,7 @@ An exemption of the above is `star`, which is not used as a standalone BSJ detec
      Output files -- `circrna_discovery/mapsplice/intermediates/${sample_id}/` +- `bsj_detection/tools/mapsplice/intermediates/${sample_id}/` - `alignments.bam`: Bam file containing aligned reads and fusion alignments. - `deletions.txt`: Report of deletions. - `Fusion output files`: @@ -278,7 +274,7 @@ An exemption of the above is `star`, which is not used as a standalone BSJ detec
      Output files -- `circrna_discovery/segemehl/intermediates/${sample_id}/` +- `bsj_detection/tools/segemehl/intermediates/${sample_id}/` - `*.bam`: Aligned reads in BAM format - `*.mult.bed`: Thus, this bed file contains all splice events of a read. The start and end positions indicate the nucleotide after the first split (i.e. the beginning of the first intron) and the nucleotide before the last split (i.e. the end of the last intron), respectively. The name and score are equivalent to the one in the \*.sngl file described above. The following fields 7 & 8 (thickStart and thickEnd) should be the identical to fields 2 & 3. Field 9 holds the color information for the item in RGB encoding (itemRGB). Field 10 (blockCount) indicates the number of splits represented by the BED item. Field 11 is a comma separated list of the intron sizes (blockSizes). Field 12 is the comma separated list of intron starts (blockStarts). - `*.sngl.bed`: The bed file contains all single splice events predicted in the split read alignments. From 7314a42a3057bde5518dc567c7d5545a68deb356 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 16:08:10 +0200 Subject: [PATCH 385/491] Finalize BSJ detection output docs --- docs/output.md | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/docs/output.md b/docs/output.md index a25daabb..787a7a00 100644 --- a/docs/output.md +++ b/docs/output.md @@ -312,17 +312,42 @@ An exemption of the above is `star`, which is not used as a standalone BSJ detec STAR in 2-pass mode is used to identify novel splice junctions in RNA-Seq data. The first pass of STAR is used to generate a genome index and align reads to the reference genome. The second pass of STAR uses the splice junctions identified in the first pass to align reads to the reference genome. This does not increase the number of detected novel junctions, but allows for more sensitive detection of splice reads mapping to novel junctions. -### Count Matrix +### Per sample
      Output files -- `circrna_discovery/` - - `count_matrix.txt`: Raw circRNA read counts for all samples in matrix format. +- `bsj_detection/samples/${sample_id}/` + - `*.grouped.bed`: Grouped BSJ calls in BED format. Score column represents the number of tools that support the BSJ. + - `*.filtered.bed`: Based on `*.grouped.bed`, but filtered for BSJs with at least `tool_filter` supporting tools. + - `*.intersect_gtf.bed`: Intersection of `*.filtered.bed` with the reference GTF file. Intermediate file for annotation. + - `*.intersect_database.bed`: Intersection of `*.filtered.bed` with the database BED file. Intermediate file for annotation. + - `*.annotated.bed`: Annotated BSJ calls in BED format, based on `*.filtered.bed`. + - `*.annotated.gtf`: Annotated BSJ calls in GTF format, based on `*.filtered.bed`. + - `*.fa`: Extracted sequences of the circRNAs in FASTA format, based on `*.filtered.bed`. + - `*.upset.png`: Sample-specific upset plot of BSJ calls across tools.
      -`nf-core/circrna` produces a counts matrix of circRNA read counts for each sample. circRNAs with BSJ reads < `--bsj_reads ` have been removed during the quantification step, with a further filtering step included depending on the number of quantification tools selected. If the user has selected more than one circRNA quantification tool, `nf-core/circrna` will demand that a circRNA be called by at least two quantification tools or else it is removed. This approach is recommended to reduce the number of false positives. +`nf-core/circrna` produces a sample-specific set of BSJ calls. The BSJ calls are filtered for BSJs with at least `tool_filter` supporting tools. The filtered BSJ calls are then annotated with the reference GTF file and the database BED file. An upset plot is generated to visualise the overlap of BSJ calls across tools. + +### Combined + +
      +Output files + +- `bsj_detection/combined/` + - `*.combined.bed`: Unique BSJ calls across samples in BED format. + - `*.intersect_gtf.bed`: Intersection of `*.filtered.bed` with the reference GTF file. Intermediate file for annotation. + - `*.intersect_database.bed`: Intersection of `*.filtered.bed` with the database BED file. Intermediate file for annotation. + - `*.annotated.bed`: Annotated BSJ calls in BED format, based on `*.filtered.bed`. + - `*.annotated.gtf`: Annotated BSJ calls in GTF format, based on `*.filtered.bed`. + - `*.fa`: Extracted sequences of the circRNAs in FASTA format, based on `*.filtered.bed`. + - `*.upset.png`: Combined upset plot of BSJ calls across samples. + +
      + +`nf-core/circrna` combines the sample-specific BSJ calls into a single file. The filtered BSJ calls are then annotated with the reference GTF file and the database BED file. An upset plot is generated to visualise the overlap of BSJ calls across tools. ## miRNA Prediction From c38f066d0c119c1df0f7864d78dc930b19c98bca Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 16:41:06 +0200 Subject: [PATCH 386/491] Update output docs for mirna prediction and quantification --- docs/output.md | 71 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/docs/output.md b/docs/output.md index 787a7a00..3138f9ba 100644 --- a/docs/output.md +++ b/docs/output.md @@ -349,6 +349,69 @@ STAR in 2-pass mode is used to identify novel splice junctions in RNA-Seq data. `nf-core/circrna` combines the sample-specific BSJ calls into a single file. The filtered BSJ calls are then annotated with the reference GTF file and the database BED file. An upset plot is generated to visualise the overlap of BSJ calls across tools. +## Quantification + +Since we now know the BSJ locations, we can now quantify their expression by mapping the reads to the region between the BSJ start and end coordinates. As each read can potentially originate from both linear and circular transcripts, the pipeline performs a joint quantification of the linear and circular transcriptome. +The quantification is performed using psirc-quant, which is a wrapper around `kallisto`. It allows for inferential-uncertainty aware quantification of linear and circular transcripts. + +### Transcriptome + +
      +Output files + +- `quantification/transcriptome/` + - `*.combined.gtf`: Combined linear and circular transcriptome in GTF format. + - `*.filtered.gtf`: Filtered linear and circular transcriptome in GTF format, based on `*.combined.gtf`. + - `*.fasta`: Combined linear and circular transcriptome in FASTA format, based on `*.filtered.gtf`. + - `*.marked.fasta`: Transcript sequences in FASTA format with the circRNA sequences marked with a `C` field in the header. + - `*.tx2gene.tsv`: Transcript to gene mapping file. + +### Per sample + +
      +Output files + +- `quantification/samples/${sample_id}/` + - `psirc` + - `*.abundance.h5`: Abundance estimates in HDF5 format. + - `*.abundance.tsv`: Abundance estimates in TSV format. + - `*.run_info.json`: Run information in JSON format. + - `pseudoalignments.bam`: Pseudoalignments in BAM format. + - `pseudoalignments.bai`: Index file for pseudoalignments. + - `tximeta/` + - `*.rds`: RDS file containing the the sample-specific transcript quantification data. + - `tximport/` + - `*.gene_counts_length_scaled.tsv`: Gene counts scaled by transcript length. + - `*.gene_counts_scaled.tsv`: Gene counts scaled by library size. + - `*.gene_counts.tsv`: Gene counts. + - `*.gene_lengths.tsv`: Gene lengths. + - `*.gene_tpm.tsv`: Gene TPM values. + - `*.transcript_counts.tsv`: Transcript counts. + - `*.transcript_lengths.tsv`: Transcript lengths. + - `*.transcript_tpm.tsv`: Transcript TPM values. + +
      + +`nf-core/circrna` performs quantification of linear and circular transcripts using `psirc-quant`. The quantification results are stored in HDF5 and TSV format. The pipeline also generates a `tximeta` RDS file containing the sample-specific transcript quantification data. The `tximport` directory contains gene and transcript counts, lengths and TPM values. + +### Combined + +
      +Output files + +- `quantification/combined/` + - `gene_counts.csv`: Count matrix of genes across samples. + - `gene_tpm.csv`: TPM matrix of genes across samples. + - `tx_counts.csv`: Count matrix of transcripts across samples. + - `tx_tpm.csv`: TPM matrix of transcripts across samples. + - `linear.tsv`: Count matrix of linear transcripts across samples. + - `circular.tsv`: Count matrix of circular transcripts across samples. + - `experiments.merged.rds`: RDS file containing a SummarizedExperiment with the merged transcript quantification data. + +
      + +`nf-core/circrna` combines the sample-specific quantification results into proper count matrices. It also generates an RDS file containing a SummarizedExperiment with the merged transcript quantification data. + ## miRNA Prediction ### miRanda @@ -356,7 +419,7 @@ STAR in 2-pass mode is used to identify novel splice junctions in RNA-Seq data.
      Output files -- `mirna_prediction/miRanda/${sample_id}/` +- `mirna_prediction/miranda/` - `*.miRanda.txt`: Raw outputs from `miRanda`.
      @@ -371,19 +434,19 @@ STAR in 2-pass mode is used to identify novel splice junctions in RNA-Seq data.
      Output files -- `mirna_prediction/TargetScan/${sample_id}/` +- `mirna_prediction/targetscan/` - `*.targetscan.txt`: Raw outputs from `TargetScan`.
      [TargetScan](http://www.targetscan.org/vert_72/) predicts biological targets of miRNAs by searching for the presence of conserved 8mer, 7mer, and 6mer sites within the circRNA mature sequence that match the seed region of each miRNA. -### miRNA targets +### Combined
      Output files -- `mirna_prediction/${sample_id}/` +- `mirna_prediction/combined/` - `*_miRNA_targets.txt`: Filtered target miRNAs of circRNAs called by quantification tools. Columns are self explanatory: miRNA, Score, Energy_KcalMol, Start, End, Site_type.
      From cd5c1d466bb686804b05e523de2e29e7e18937c2 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 3 Aug 2024 16:44:16 +0200 Subject: [PATCH 387/491] Prettier --- README.md | 1 + docs/output.md | 1 + docs/usage.md | 15 +++++++++------ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 875ce95c..9006955a 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ **nf-core/circrna** is a bioinformatics pipeline that can be used to analyse total RNA sequencing data obtained from organisms with a reference genome and annotation. It takes a samplesheet and FASTQ files as input, performs quality control (QC), trimming, back-splice junction (BSJ) detection, annotation, quantification and miRNA target prediction of circular RNAs. The pipeline is still under development, but the BSJ detection and quantification steps are already implemented and functional. The following features are planned to be implemented soon: + - Isoform-level circRNA detection and quantification - circRNA-miRNA interaction analysis using [SPONGE](https://doi.org/10.1093/bioinformatics/btz314) and [spongEffects](https://doi.org/10.1093/bioinformatics/btad276) - Improved downstream analyses diff --git a/docs/output.md b/docs/output.md index 3138f9ba..2e1da196 100644 --- a/docs/output.md +++ b/docs/output.md @@ -133,6 +133,7 @@ The FastQC plots displayed in the MultiQC report show _untrimmed_ reads. They ma ## BSJ detection The rough workflow for the BSJ detection looks like this: + 1. Each tools detects BSJs in each sample and quantifies how many reads support each BSJ. 2. Bring the tool outputs into a common format. 3. Apply a threshold (parameter `bsj_reads) to the BSJ reads to filter out lowly supported BSJs. diff --git a/docs/usage.md b/docs/usage.md index 6f694f6e..d39eb853 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -56,11 +56,12 @@ An [example samplesheet](../assets/samplesheet.csv) has been provided with the p ## BSJ detection This part of the pipeline is responsible for the detection of back-splice junctions (BSJs) in the input data. The following tools are currently supported: + - `CIRCexplorer2` - `circRNA finder` - `CIRIquant` - `DCC` -- `find circ` +- `find circ` - `MapSplice` - `Segemehl` @@ -76,23 +77,25 @@ The annotation is generally based on the reference GTF file. It can also utilize The GTF-based annotation allows setting the parameter `exon_boundary` to specify a window around exons. If the BSJ is within this window, it will be annotated as a circRNA - otherwise, it will be annotated as an exon-intron circRNA (EI-circRNA). The default value is 0. For the database-based annotation, an additional sample sheet is required: + ```csv title="annotation.csv" name,file,min_overlap db1,db1.bed,0.9 db2,db2.bed,0.8 ``` -| Column | Description | -| ------------ | --------------------------------------------------------------------------------------------- | -| `name` | Name of the database. This will be used as a prefix for the region names in the output files. | -| `file` | Path to the BED file. The file has to be a valid BED6 file. | -| `min_overlap`| Minimum bidirectional overlap required between the BSJ and the region in the BED file. | +| Column | Description | +| ------------- | --------------------------------------------------------------------------------------------- | +| `name` | Name of the database. This will be used as a prefix for the region names in the output files. | +| `file` | Path to the BED file. The file has to be a valid BED6 file. | +| `min_overlap` | Minimum bidirectional overlap required between the BSJ and the region in the BED file. | The output of the annotation step will be bundled with the outputs of the BSJ detection step. ## miRNA prediction This section allows looking for miRNA binding sites in the circRNAs. The following tools are currently supported: + - `miRanda` - `TargetScan` From 3d25e2d65a5dd66607b55cc7dc29aabbfa13a3c1 Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:24:26 +0200 Subject: [PATCH 388/491] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9006955a..a7feba50 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ ## Introduction -**nf-core/circrna** is a bioinformatics pipeline that can be used to analyse total RNA sequencing data obtained from organisms with a reference genome and annotation. It takes a samplesheet and FASTQ files as input, performs quality control (QC), trimming, back-splice junction (BSJ) detection, annotation, quantification and miRNA target prediction of circular RNAs. +**nf-core/circrna** is a bioinformatics pipeline to analyse total RNA sequencing data obtained from organisms with a reference genome and annotation. It takes a samplesheet and FASTQ files as input, performs quality control (QC), trimming, back-splice junction (BSJ) detection, annotation, quantification and miRNA target prediction of circular RNAs. The pipeline is still under development, but the BSJ detection and quantification steps are already implemented and functional. The following features are planned to be implemented soon: From ffd92e314bc05506a2cbd52b35281ba306c39e0a Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:24:43 +0200 Subject: [PATCH 389/491] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a7feba50..6e8bb401 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ If you want to contribute, feel free to create an issue or pull request on the [ - [`MapSplice`](http://www.netlab.uky.edu/p/bioinfo/MapSplice2) - [`Segemehl`](https://www.bioinf.uni-leipzig.de/Software/segemehl/) - circRNA annotation - - Based on GTF file + - Based on a GTF file - Based on database files (if provided) - Extract circRNA sequences and build circular transcriptome - Merge circular transcriptome with linear transcriptome derived from provided GTF From fd16cccd851c6dd76efcaaa0e16920e337bbe254 Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:25:26 +0200 Subject: [PATCH 390/491] Update docs/output.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- docs/output.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/output.md b/docs/output.md index 2e1da196..5731110c 100644 --- a/docs/output.md +++ b/docs/output.md @@ -47,7 +47,9 @@ The FastQC plots displayed in the MultiQC report show _untrimmed_ reads. They ma - `*_fastqc.html`: FastQC report containing quality metrics. - `*_fastqc.zip`: Zip archive containing the FastQC report, tab-delimited data file and plot images. -> **NB:** The FastQC plots in this directory are generated relative to the raw, input reads. They may contain adapter sequence and regions of low quality. +::: note +The FastQC plots in this directory are generated relative to the raw, input reads. They may contain adapter sequence and regions of low quality. +:::
      From 753517026c36fb524ffc0dd85a8c8d105364820d Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:25:51 +0200 Subject: [PATCH 391/491] Update docs/output.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- docs/output.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/output.md b/docs/output.md index 5731110c..8f3686a5 100644 --- a/docs/output.md +++ b/docs/output.md @@ -118,7 +118,7 @@ The FastQC plots in this directory are generated relative to the raw, input read
      -`nf-core/circrna` will add the reference files to the output directory if `save_reference` is set to `true`. The resulting files, especially the aligner indices, can be used for speeding up future runs (if the `resume` option cannot be used). In order to achieve this, copy the indices to a location outside of the pipeline's output directory and provide the path to the indices via the corresponding aligner flags (check the [parameters documentation](https://nf-co.re/circrna/dev/parameters/#reference-genome-options) for more information). +`nf-core/circrna` will add the reference files to the output directory if `save_reference` is set to `true`. The resulting files, especially the aligner indices, can be used for speeding up future runs (if the `resume` option cannot be used). In order to achieve this, copy the indices to a location outside of the pipeline's output directory and provide the path to the indices via the corresponding aligner flags (check the [parameters documentation](https://nf-co.re/circrna/parameters/#reference-genome-options) for more information). ## Pipeline info From 0ffaf3068ffe9dca1f702ba5d6488ae71f0d03a8 Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:27:23 +0200 Subject: [PATCH 392/491] Update nextflow_schema.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- nextflow_schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index eb5452be..8217b765 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -95,7 +95,7 @@ "exon_boundary": { "type": "integer", "description": "Specify the distance at which the annotation script decides if a candidate is a circRNA or EI-circRNA.", - "help_text": "During annotation, if one of the start or end position of a circular candidate imperfectly overlaps an exon boundary, the script will consider positions within 'exon_boundary' (default 200bp) to be an exonic circRNA. If they fall outside of this range, the candidate is assumed to be an exonic-intronic circRNA, and the entire underlying sequence is taken for miRNA analysis, as opposed to just the exonic sequences for canonical exonic circRNAs. ", + "help_text": "During annotation, if one of the start or end position of a circular candidate imperfectly overlaps an exon boundary, the script will consider positions within 'exon_boundary' (default 0bp) to be an exonic circRNA. If they fall outside of this range, the candidate is assumed to be an exonic-intronic circRNA, and the entire underlying sequence is taken for miRNA analysis, as opposed to just the exonic sequences for canonical exonic circRNAs. ", "default": 0 } } From 65497575c89658ed1998759bbb546c767b047c8d Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:29:14 +0200 Subject: [PATCH 393/491] Update nextflow_schema.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- nextflow_schema.json | 1 + 1 file changed, 1 insertion(+) diff --git a/nextflow_schema.json b/nextflow_schema.json index 8217b765..9c952c23 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -65,6 +65,7 @@ "type": "string", "fa_icon": "fas fa-wrench", "description": "Comma separated list of circRNA quantification tools to use. Supported tools: ciriquant, circexplorer2, find_circ, circrna_finder, mapsplice, dcc, segemehl", + "pattern": "^(ciriquant|circexplorer2|find_circ|circrna_finder|mapsplice|dcc|segemehl)(,(ciriquant|circexplorer2|find_circ|circrna_finder|mapsplice|dcc|segemehl))*$" "help_text": "Select one or a combination of circRNA quantification tools for the pipeline e.g:\n--tool 'circexplorer2, ciriquant, find_circ'\n\nN.B: Selecting more than one circRNA quantification tool will trigger the circRNA filtering parameter --tool_filter", "default": "circexplorer2", "pattern": "^((circexplorer2|circrna_finder|ciriquant|dcc|find_circ|mapsplice|segemehl)?,?)*[^,]+$" From 636330d58d7f269f0950eb455014c21ea45509ca Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:29:32 +0200 Subject: [PATCH 394/491] Update docs/output.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- docs/output.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/output.md b/docs/output.md index 8f3686a5..dfaaf826 100644 --- a/docs/output.md +++ b/docs/output.md @@ -136,7 +136,7 @@ The FastQC plots in this directory are generated relative to the raw, input read The rough workflow for the BSJ detection looks like this: -1. Each tools detects BSJs in each sample and quantifies how many reads support each BSJ. +1. Each tool detects BSJs in each sample and quantifies how many reads support each BSJ. 2. Bring the tool outputs into a common format. 3. Apply a threshold (parameter `bsj_reads) to the BSJ reads to filter out lowly supported BSJs. 4. Combine all tool-specific BSJ calls per sample into a single file. From f3b98806de007fd72a870dda8468d01ef6acf3fb Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:29:46 +0200 Subject: [PATCH 395/491] Update docs/output.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- docs/output.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/output.md b/docs/output.md index dfaaf826..a5249fbe 100644 --- a/docs/output.md +++ b/docs/output.md @@ -138,7 +138,7 @@ The rough workflow for the BSJ detection looks like this: 1. Each tool detects BSJs in each sample and quantifies how many reads support each BSJ. 2. Bring the tool outputs into a common format. -3. Apply a threshold (parameter `bsj_reads) to the BSJ reads to filter out lowly supported BSJs. +3. Apply a threshold (parameter `bsj_reads`) to the BSJ reads to filter out lowly supported BSJs. 4. Combine all tool-specific BSJ calls per sample into a single file. 5. Filter out BSJs that are not supported by at least `tool_filter` tools. 6. Merge all samples into a single file. This now represents the "circular transcriptome" From 96a20d50eb9b35e7b943a1d5c2206dc54c31006d Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:29:53 +0200 Subject: [PATCH 396/491] Update docs/usage.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- docs/usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage.md b/docs/usage.md index d39eb853..61fc076c 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -69,7 +69,7 @@ The tools to be used can be specified using the `tools` parameter. Each of the tools also quantifies how many reads support each BSJ. You can specify a cutoff for the minimum number of reads supporting a BSJ using the `bsj_reads` parameter. Additionally, the parameter `tool_filter` can be used to specify how many tools a BSJ has to be detected by to be considered as a valid hit. -For instructions on how to interpret the output of this section, please check out the [output documentation](https://nf-co.re/circrna/dev/output#bsj-detection). +For instructions on how to interpret the output of this section, please check out the [output documentation](https://nf-co.re/circrna/output#bsj-detection). ## Annotation From 6c45fa856a8ce6b5bec88b61b12c74183143c851 Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:30:06 +0200 Subject: [PATCH 397/491] Update docs/usage.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- docs/usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage.md b/docs/usage.md index 61fc076c..13a1b410 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -74,7 +74,7 @@ For instructions on how to interpret the output of this section, please check ou ## Annotation The annotation is generally based on the reference GTF file. It can also utilize BED files that are provided by the various circRNA databases. -The GTF-based annotation allows setting the parameter `exon_boundary` to specify a window around exons. If the BSJ is within this window, it will be annotated as a circRNA - otherwise, it will be annotated as an exon-intron circRNA (EI-circRNA). The default value is 0. +The GTF-based annotation allows setting the parameter `exon_boundary` to specify a window around exons. If the BSJ is within this window, it will be annotated as a circRNA - otherwise, it will be annotated as an exon-intron circRNA (EI-circRNA). The default value is `0`. For the database-based annotation, an additional sample sheet is required: From 2209284d5db8a907bb4c50d6cab97ea1c4bd245d Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:30:32 +0200 Subject: [PATCH 398/491] Update docs/output.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- docs/output.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/output.md b/docs/output.md index a5249fbe..1c9e2dbf 100644 --- a/docs/output.md +++ b/docs/output.md @@ -140,7 +140,7 @@ The rough workflow for the BSJ detection looks like this: 2. Bring the tool outputs into a common format. 3. Apply a threshold (parameter `bsj_reads`) to the BSJ reads to filter out lowly supported BSJs. 4. Combine all tool-specific BSJ calls per sample into a single file. -5. Filter out BSJs that are not supported by at least `tool_filter` tools. +5. Filter out BSJs that are not supported by at least as many tools as specified by`tool_filter`. 6. Merge all samples into a single file. This now represents the "circular transcriptome" ### Per tool From ff1d11a9bb760f97e2f26dd8c7b823d4acd489ad Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:30:45 +0200 Subject: [PATCH 399/491] Update docs/output.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- docs/output.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/output.md b/docs/output.md index 1c9e2dbf..4f751c34 100644 --- a/docs/output.md +++ b/docs/output.md @@ -332,7 +332,7 @@ STAR in 2-pass mode is used to identify novel splice junctions in RNA-Seq data.
      -`nf-core/circrna` produces a sample-specific set of BSJ calls. The BSJ calls are filtered for BSJs with at least `tool_filter` supporting tools. The filtered BSJ calls are then annotated with the reference GTF file and the database BED file. An upset plot is generated to visualise the overlap of BSJ calls across tools. +nf-core/circrna produces a sample-specific set of BSJ calls. The BSJ calls are filtered for BSJs with at least `tool_filter` supporting tools. The filtered BSJ calls are then annotated with the reference GTF file and the database BED file. An upset plot is generated to visualise the overlap of BSJ calls across tools. ### Combined From e3844bb4e85764ced9a22e922509131ba7187fdc Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:31:01 +0200 Subject: [PATCH 400/491] Update docs/output.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- docs/output.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/output.md b/docs/output.md index 4f751c34..d31355ff 100644 --- a/docs/output.md +++ b/docs/output.md @@ -350,7 +350,7 @@ nf-core/circrna produces a sample-specific set of BSJ calls. The BSJ calls are f
      -`nf-core/circrna` combines the sample-specific BSJ calls into a single file. The filtered BSJ calls are then annotated with the reference GTF file and the database BED file. An upset plot is generated to visualise the overlap of BSJ calls across tools. +nf-core/circrna combines the sample-specific BSJ calls into a single file. The filtered BSJ calls are then annotated with the reference GTF file and the database BED file. An upset plot is generated to visualise the overlap of BSJ calls across tools. ## Quantification From cce50cb6457fb3a8dbbd1035061bbda57f5b7bab Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:31:15 +0200 Subject: [PATCH 401/491] Update docs/output.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- docs/output.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/output.md b/docs/output.md index d31355ff..e4e8c323 100644 --- a/docs/output.md +++ b/docs/output.md @@ -395,7 +395,7 @@ The quantification is performed using psirc-quant, which is a wrapper around `ka
      -`nf-core/circrna` performs quantification of linear and circular transcripts using `psirc-quant`. The quantification results are stored in HDF5 and TSV format. The pipeline also generates a `tximeta` RDS file containing the sample-specific transcript quantification data. The `tximport` directory contains gene and transcript counts, lengths and TPM values. +nf-core/circrna performs quantification of linear and circular transcripts using `psirc-quant`. The quantification results are stored in HDF5 and TSV format. The pipeline also generates a `tximeta` RDS file containing the sample-specific transcript quantification data. The `tximport` directory contains gene and transcript counts, lengths and TPM values. ### Combined From af15e96bfda741aaa8556fe586da81dd70da23c4 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 6 Aug 2024 14:34:24 +0200 Subject: [PATCH 402/491] Fix syntax error in nextflow_schema.json --- nextflow_schema.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index 9c952c23..69d123e6 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -65,10 +65,9 @@ "type": "string", "fa_icon": "fas fa-wrench", "description": "Comma separated list of circRNA quantification tools to use. Supported tools: ciriquant, circexplorer2, find_circ, circrna_finder, mapsplice, dcc, segemehl", - "pattern": "^(ciriquant|circexplorer2|find_circ|circrna_finder|mapsplice|dcc|segemehl)(,(ciriquant|circexplorer2|find_circ|circrna_finder|mapsplice|dcc|segemehl))*$" + "pattern": "^(ciriquant|circexplorer2|find_circ|circrna_finder|mapsplice|dcc|segemehl)(,(ciriquant|circexplorer2|find_circ|circrna_finder|mapsplice|dcc|segemehl))*$", "help_text": "Select one or a combination of circRNA quantification tools for the pipeline e.g:\n--tool 'circexplorer2, ciriquant, find_circ'\n\nN.B: Selecting more than one circRNA quantification tool will trigger the circRNA filtering parameter --tool_filter", - "default": "circexplorer2", - "pattern": "^((circexplorer2|circrna_finder|ciriquant|dcc|find_circ|mapsplice|segemehl)?,?)*[^,]+$" + "default": "circexplorer2" }, "bsj_reads": { "type": "integer", From 237bf49b7a639758b4dadfb7e24940c36c1aa6c3 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 6 Aug 2024 14:37:16 +0200 Subject: [PATCH 403/491] Write pipeline name in standard formatting in output docs --- docs/output.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/output.md b/docs/output.md index e4e8c323..7c00df20 100644 --- a/docs/output.md +++ b/docs/output.md @@ -118,7 +118,7 @@ The FastQC plots in this directory are generated relative to the raw, input read
      -`nf-core/circrna` will add the reference files to the output directory if `save_reference` is set to `true`. The resulting files, especially the aligner indices, can be used for speeding up future runs (if the `resume` option cannot be used). In order to achieve this, copy the indices to a location outside of the pipeline's output directory and provide the path to the indices via the corresponding aligner flags (check the [parameters documentation](https://nf-co.re/circrna/parameters/#reference-genome-options) for more information). +nf-core/circrna will add the reference files to the output directory if `save_reference` is set to `true`. The resulting files, especially the aligner indices, can be used for speeding up future runs (if the `resume` option cannot be used). In order to achieve this, copy the indices to a location outside of the pipeline's output directory and provide the path to the indices via the corresponding aligner flags (check the [parameters documentation](https://nf-co.re/circrna/parameters/#reference-genome-options) for more information). ## Pipeline info @@ -223,7 +223,7 @@ An exemption of the above is `star`, which is not used as a standalone BSJ detec `DCC` then performs a series of filtering steps on candidate circular reads: 1. Mapping of mates must be consistent with a circular RNA template i.e align to the back-splice junction. -2. Filtering by a minimum number of junction reads per replicate (`nf-core/circrna` has set this parameter to`-Nr 1 1` allowing all reads). +2. Filtering by a minimum number of junction reads per replicate (nf-core/circrna has set this parameter to`-Nr 1 1` allowing all reads). 3. Circular reads are not allowed span more than one gene. 4. Circular reads aligning to mitochondrial genome are removed. 5. Circular reads that lack a canonical (GT/AG) splicing signal at the circRNA junction borders are removed. @@ -413,7 +413,7 @@ nf-core/circrna performs quantification of linear and circular transcripts using
      -`nf-core/circrna` combines the sample-specific quantification results into proper count matrices. It also generates an RDS file containing a SummarizedExperiment with the merged transcript quantification data. +nf-core/circrna combines the sample-specific quantification results into proper count matrices. It also generates an RDS file containing a SummarizedExperiment with the merged transcript quantification data. ## miRNA Prediction @@ -454,7 +454,7 @@ nf-core/circrna performs quantification of linear and circular transcripts using
      -`nf-core/circrna` performs miRNA target filtering on `miRanda` and `TargetScan` predictions: +nf-core/circrna performs miRNA target filtering on `miRanda` and `TargetScan` predictions: 1. miRNA must be called by both `miRanda` and `TargetScan`. 2. If a site within the circRNA mature sequence shares duplicate miRNA ID's overlapping the same coordinates, the miRNA with the highest score is kept. From 90172a00bd369bf3f90f65e3f829d2a641f49c62 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Tue, 6 Aug 2024 14:38:32 +0200 Subject: [PATCH 404/491] Update bsj_reads help text --- nextflow_schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index 69d123e6..f881e277 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -73,7 +73,7 @@ "type": "integer", "fa_icon": "fas fa-circle-notch", "description": "Minimum number of reads spanning circRNA back-splice junction required for circRNA to be output by workflow.", - "help_text": "Filter low confidence circRNAs by removing circRNAs with read counts below a specified value. To disable, set the value to 0 (default).", + "help_text": "Filter low confidence circRNAs by removing circRNAs with read counts below a specified value. To disable, set the value to 1 (default).", "default": 1, "minimum": 1 }, From 9a4ece6f3e7d458b306ecc4fceb606b0eb198e1b Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Fri, 26 Apr 2024 10:17:56 +0200 Subject: [PATCH 405/491] Adding mirna_expression param to subworkflow mirna_prediction --- main.nf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 23b4c9c0..192ac42e 100644 --- a/main.nf +++ b/main.nf @@ -57,8 +57,10 @@ workflow NFCORE_CIRCRNA { ch_samplesheet = Channel.fromSamplesheet("input") ch_fasta = Channel.value([[id: "fasta"], file(params.fasta, checkIfExists:true)]) ch_gtf = Channel.value([[id: "gtf"], file(params.gtf, checkIfExists:true)]) - ch_mature = params.mature ? Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) : Channel.empty() + ch_mature = params.module.split(',').contains('mirna_prediction') ? Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) : Channel.empty() ch_phenotype = params.phenotype ? Channel.value([[id: "phenotype"], file(params.phenotype, checkIfExists:true)]) : Channel.empty() + ch_species = params.phenotype ? Channel.value(params.species_id) : Channel.empty() + ch_mirna = params.module.split(',').contains('mirna_prediction') ? Channel.value(params.mirna_expression) : Channel.empty() ch_annotation = params.annotation ? Channel.fromSamplesheet("annotation") : Channel.empty() CIRCRNA ( From ea567a3f58f99db60d8a824b763fd7dad3fedbac Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Fri, 26 Apr 2024 10:18:22 +0200 Subject: [PATCH 406/491] Adding mirna_expression param to config --- nextflow.config | 1 + 1 file changed, 1 insertion(+) diff --git a/nextflow.config b/nextflow.config index d693ca69..ec8da623 100644 --- a/nextflow.config +++ b/nextflow.config @@ -14,6 +14,7 @@ params { outdir = null phenotype = null annotation = null + mirna_expression = null // workflow options tools = 'circexplorer2' From b800bdb7c254acc31bfaaf4aecd8e4696395f447 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Fri, 26 Apr 2024 10:18:51 +0200 Subject: [PATCH 407/491] Adding mirna_expression param to nextflow_schema.json --- nextflow_schema.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/nextflow_schema.json b/nextflow_schema.json index f881e277..b884688e 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -51,6 +51,16 @@ "description": "Path to a CSV file containing BED files that should be used for annotation.", "help_text": "The annotation file should be a CSV file with the following columns: `name`, `file` and `min_overlap`. The `name` column should contain a unique identifier for the annotation, the `file` column should contain the path to the BED file and the `min_overlap` column should contain the minimum overlap required for a circRNA to be considered as overlapping with the annotation. The `min_overlap` column is optional and defaults to 0.9 if not provided.", "fa_icon": "fas fa-file-csv" + }, + "mirna_expression": { + "type": "string", + "format": "file-path", + "exists": true, + "schema": "assets/schema_input.json", + "mimetype": "text/tsv", + "pattern": "^\\S+\\.tsv$", + "description": "Path to tab-separated file providing the expression counts of miRNAs, which are created in pipeline 'smrnaseq'. \n\n\t sample1 \t sample2 \t sample3 \t\nid1\t count_sample1 \t count_sample2 \t count_sample3 \t\nid2 \t ... \t ... \t ... \t \n", + "fa_icon": "fas fa-file-tsv" } } }, From 0aa5c0f3de69cd633847319f50a02dd5363b185e Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Mon, 29 Apr 2024 22:04:17 +0200 Subject: [PATCH 408/491] adding process DESEQ2_NORMALIZATION --- main.nf | 6 +- .../deseq2/normalization/environment.yml | 8 +++ modules/local/deseq2/normalization/main.nf | 32 ++++++++++ .../templates/deseq_normalization.R | 58 +++++++++++++++++++ nextflow_schema.json | 3 +- subworkflows/local/mirna_prediction.nf | 19 ++++-- workflows/circrna/main.nf | 3 + 7 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 modules/local/deseq2/normalization/environment.yml create mode 100644 modules/local/deseq2/normalization/main.nf create mode 100644 modules/local/deseq2/normalization/templates/deseq_normalization.R diff --git a/main.nf b/main.nf index 192ac42e..94437354 100644 --- a/main.nf +++ b/main.nf @@ -60,8 +60,8 @@ workflow NFCORE_CIRCRNA { ch_mature = params.module.split(',').contains('mirna_prediction') ? Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) : Channel.empty() ch_phenotype = params.phenotype ? Channel.value([[id: "phenotype"], file(params.phenotype, checkIfExists:true)]) : Channel.empty() ch_species = params.phenotype ? Channel.value(params.species_id) : Channel.empty() - ch_mirna = params.module.split(',').contains('mirna_prediction') ? Channel.value(params.mirna_expression) : Channel.empty() ch_annotation = params.annotation ? Channel.fromSamplesheet("annotation") : Channel.empty() + ch_mirna = params.mature ? Channel.value([[id: "mirna"], file(params.mirna_expression, checkIfExists:true)]) : Channel.empty() CIRCRNA ( ch_samplesheet, @@ -70,7 +70,9 @@ workflow NFCORE_CIRCRNA { ch_gtf, ch_mature, ch_annotation, - ch_versions + ch_species, + ch_versions, + ch_mirna ) emit: diff --git a/modules/local/deseq2/normalization/environment.yml b/modules/local/deseq2/normalization/environment.yml new file mode 100644 index 00000000..8bd70ac0 --- /dev/null +++ b/modules/local/deseq2/normalization/environment.yml @@ -0,0 +1,8 @@ +name: deseq2_normalization +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::bioconductor-deseq2=1.34.0 + - conda-forge::r-data.table=1.15.2 diff --git a/modules/local/deseq2/normalization/main.nf b/modules/local/deseq2/normalization/main.nf new file mode 100644 index 00000000..97b13efa --- /dev/null +++ b/modules/local/deseq2/normalization/main.nf @@ -0,0 +1,32 @@ +process DESEQ2_NORMALIZATION { + tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/bioconductor-deseq2:1.34.0--r41hc247a5b_3' : + 'biocontainers/bioconductor-deseq2:1.34.0--r41hc247a5b_3' }" + + input: + tuple val(meta), path(counts) + + output: + tuple val(meta), path("${meta.id}.normalized_counts.tsv"), emit: normalized + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + template 'deseq_normalization.R' + + stub: + """ + touch ${meta.id}.normalized_counts.tsv + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + bioconductor-deseq2: \$(Rscript -e "library(DESeq2); cat(as.character(packageVersion('DESeq2')))") + END_VERSIONS + """ +} diff --git a/modules/local/deseq2/normalization/templates/deseq_normalization.R b/modules/local/deseq2/normalization/templates/deseq_normalization.R new file mode 100644 index 00000000..daada9f6 --- /dev/null +++ b/modules/local/deseq2/normalization/templates/deseq_normalization.R @@ -0,0 +1,58 @@ +#!/usr/bin/env Rscript + +library(DESeq2) + +raw_counts <- read.table("$counts", sep = "\\t", + header = TRUE, + stringsAsFactors = FALSE, + check.names = FALSE) +samples <- colnames(raw_counts)[-c(1)] + +row.names(raw_counts) <- raw_counts\$miRNA +data <- raw_counts[, -1] +mirna_names <- data.frame(miRNA = raw_counts\$miRNA, + order = seq_len(nrow(raw_counts))) + +# normalize using DeSeq2, Library Size Estimation +meta_data <- data.frame(samples) +row.names(meta_data) <- meta_data\$samples +all(colnames(data) %in% rownames(meta_data)) +all(colnames(data) == rownames(meta_data)) + +dds <- DESeqDataSetFromMatrix(countData = data, + colData = meta_data, + design = ~ 1) +dds <- estimateSizeFactors(dds) +sizeFactors(dds) +normalized_counts <- DESeq2::counts(dds, normalized = TRUE) + +# add miRNA IDs back to counts table +merged_data <- merge(mirna_names, normalized_counts, + by.x = "miRNA", by.y = "row.names") +merged_data <- merged_data[order(merged_data\$order), ] + +norm_data <- subset(merged_data, select = -c(order)) + +write.table(norm_data, paste0("${meta.id}.normalized_counts.tsv"), + quote = FALSE, sep = "\\t", row.names = FALSE) + +# TODO: Perform normalization and save as "${meta.id}.normalized_counts.tsv" +# TODO: (Can be done later) Add support for Samplesheet so that we can eliminate batch effects + + +################################################ +################################################ +## VERSIONS FILE ## +################################################ +################################################ + +r.version <- strsplit(version[['version.string']], ' ')[[1]][3] +deseq2.version <- as.character(packageVersion('DESeq2')) + +writeLines( + c( + '"${task.process}":', + paste(' r-base:', r.version), + paste(' bioconductor-deseq2:', deseq2.version) + ), +'versions.yml') diff --git a/nextflow_schema.json b/nextflow_schema.json index b884688e..7397a535 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -56,10 +56,9 @@ "type": "string", "format": "file-path", "exists": true, - "schema": "assets/schema_input.json", "mimetype": "text/tsv", "pattern": "^\\S+\\.tsv$", - "description": "Path to tab-separated file providing the expression counts of miRNAs, which are created in pipeline 'smrnaseq'. \n\n\t sample1 \t sample2 \t sample3 \t\nid1\t count_sample1 \t count_sample2 \t count_sample3 \t\nid2 \t ... \t ... \t ... \t \n", + "description": "Path to tab-separated file providing the expression counts of miRNAs, which are created in pipeline 'smrnaseq'. \n\nmirna \t sample1 \t sample2 \t sample3 \t\nid1\t count_sample1 \t count_sample2 \t count_sample3 \t\nid2 \t ... \t ... \t ... \t \n", "fa_icon": "fas fa-file-tsv" } } diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index 1bf7623f..b58b14fe 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -1,8 +1,8 @@ -include { GAWK as ADD_BACKSPLICE } from '../../modules/nf-core/gawk' -include { TARGETSCAN_DATABASE } from '../../modules/local/targetscan/database/main' -include { TARGETSCAN } from '../../modules/local/targetscan/predict/main' -include { MIRANDA } from '../../modules/nf-core/miranda/main' -include { MIRNA_TARGETS } from '../../modules/local/mirna_targets/main' +include { TARGETSCAN_DATABASE } from '../../modules/local/targetscan/database' +include { TARGETSCAN } from '../../modules/local/targetscan/predict' +include { MIRANDA } from '../../modules/nf-core/miranda' +include { MIRNA_TARGETS } from '../../modules/local/mirna_targets' +include { DESEQ2_NORMALIZATION } from '../../modules/local/deseq2/normalization' workflow MIRNA_PREDICTION{ @@ -10,6 +10,7 @@ workflow MIRNA_PREDICTION{ circrna_fasta circrna_bed12 ch_mature + ch_mirna main: ch_versions = Channel.empty() @@ -17,6 +18,14 @@ workflow MIRNA_PREDICTION{ ADD_BACKSPLICE( circrna_fasta, [] ) ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) + // + // MIRNA QUANTIFICATION WORKFLOW: + // + + ch_mirna_normalized = DESEQ2_NORMALIZATION( ch_mirna ).normalized + + ch_versions = ch_versions.mix(DESEQ2_NORMALIZATION.out.versions) + // // TARGETSCAN WORKFLOW: // diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 4c1e76ea..b82646f7 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -61,6 +61,7 @@ workflow CIRCRNA { ch_mature ch_annotation ch_versions + ch_mirna main: @@ -173,11 +174,13 @@ workflow CIRCRNA { // // 4. miRNA prediction // + if (params.mature) { MIRNA_PREDICTION( BSJ_DETECTION.out.fasta, BSJ_DETECTION.out.bed, ch_mature + ch_mirna ) ch_versions = ch_versions.mix(MIRNA_PREDICTION.out.versions) } From 4a90115a73393d6a21d850b5bcb8a8746f950ef2 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Fri, 10 May 2024 12:13:24 +0200 Subject: [PATCH 409/491] Adding deseq2 module and mirna normalization module (including params) --- .../deseq2/normalization/environment.yml | 1 - modules/local/deseq2/normalization/main.nf | 2 +- modules/local/mirna_filtering/environment.yml | 4 ++ modules/local/mirna_filtering/main.nf | 24 +++++++++ .../templates/mirna_filtering.R | 51 +++++++++++++++++++ nextflow.config | 7 +++ nextflow_schema.json | 44 +++++++++++++++- 7 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 modules/local/mirna_filtering/environment.yml create mode 100644 modules/local/mirna_filtering/main.nf create mode 100644 modules/local/mirna_filtering/templates/mirna_filtering.R diff --git a/modules/local/deseq2/normalization/environment.yml b/modules/local/deseq2/normalization/environment.yml index 8bd70ac0..8eb117c3 100644 --- a/modules/local/deseq2/normalization/environment.yml +++ b/modules/local/deseq2/normalization/environment.yml @@ -5,4 +5,3 @@ channels: - defaults dependencies: - bioconda::bioconductor-deseq2=1.34.0 - - conda-forge::r-data.table=1.15.2 diff --git a/modules/local/deseq2/normalization/main.nf b/modules/local/deseq2/normalization/main.nf index 97b13efa..74cb8b5a 100644 --- a/modules/local/deseq2/normalization/main.nf +++ b/modules/local/deseq2/normalization/main.nf @@ -12,7 +12,7 @@ process DESEQ2_NORMALIZATION { output: tuple val(meta), path("${meta.id}.normalized_counts.tsv"), emit: normalized - path "versions.yml" , emit: versions + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/mirna_filtering/environment.yml b/modules/local/mirna_filtering/environment.yml new file mode 100644 index 00000000..1aa60c3d --- /dev/null +++ b/modules/local/mirna_filtering/environment.yml @@ -0,0 +1,4 @@ +name: mirna_filtering +channels: + - conda-forge + - defaults diff --git a/modules/local/mirna_filtering/main.nf b/modules/local/mirna_filtering/main.nf new file mode 100644 index 00000000..035354d1 --- /dev/null +++ b/modules/local/mirna_filtering/main.nf @@ -0,0 +1,24 @@ +process MIRNA_FILTERING { + tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/r-base:4.2.1' : + 'biocontainers/r-base:4.2.1' }" + + input: + tuple val(meta), path(normalized_counts) + val(mirna_min_sample_percentage) + val(mirna_min_reads) + + output: + tuple val(meta), path("${meta.id}.normalized_counts_filtered.tsv"), emit: filtered + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + template 'mirna_filtering.R' +} diff --git a/modules/local/mirna_filtering/templates/mirna_filtering.R b/modules/local/mirna_filtering/templates/mirna_filtering.R new file mode 100644 index 00000000..32521c8e --- /dev/null +++ b/modules/local/mirna_filtering/templates/mirna_filtering.R @@ -0,0 +1,51 @@ +#!/usr/bin/env Rscript + +expression_norm <- read.table("$normalized_counts", + sep = "\\t", + header = TRUE, + stringsAsFactors = FALSE, + check.names = FALSE +) + +samples <- colnames(expression_norm)[-c(1)] + +# filter data: counts > 5 in at least 20% of samples +if (length(samples) < 5) { + stop("Cannot perform filtering on less than 5 samples") +} + +sample_nr_cutoff <- ceiling($mirna_min_sample_percentage * length(samples)) +rows_to_keep <- c() + +for (i in seq_len(nrow(expression_norm))) { + mirna_per_sample <- 0 + for (j in 5:ncol(expression_norm)) { + if (expression_norm[i, j] >= $mirna_min_reads) { + mirna_per_sample <- mirna_per_sample + 1 + } + } + if (mirna_per_sample >= sample_nr_cutoff) { + rows_to_keep <- append(rows_to_keep, i) + } +} + +filtered_data <- expression_norm[rows_to_keep, ] + +write.table(filtered_data, paste0("${meta.id}.normalized_counts_filtered.tsv"), + quote = FALSE, sep = "\\t", + row.names = FALSE) + +################################################ +################################################ +## VERSIONS FILE ## +################################################ +################################################ + +r.version <- strsplit(version[['version.string']], ' ')[[1]][3] + +writeLines( + c( + '"${task.process}":', + paste(' r-base:', r.version) + ), +'versions.yml') diff --git a/nextflow.config b/nextflow.config index ec8da623..3790a3bb 100644 --- a/nextflow.config +++ b/nextflow.config @@ -65,6 +65,13 @@ params { //> Quantification bootstrap_samples = 30 + //> MIRNA processing + mirna_expression = null + mirna_min_reads = 5 + mirna_min_sample_percentage = 0.2 + mirna_tools = 'miranda, targetscan' + mirna_vote = 1 + //> MISC save_unaligned = false seq_center = null diff --git a/nextflow_schema.json b/nextflow_schema.json index 7397a535..e266c70a 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -51,7 +51,16 @@ "description": "Path to a CSV file containing BED files that should be used for annotation.", "help_text": "The annotation file should be a CSV file with the following columns: `name`, `file` and `min_overlap`. The `name` column should contain a unique identifier for the annotation, the `file` column should contain the path to the BED file and the `min_overlap` column should contain the minimum overlap required for a circRNA to be considered as overlapping with the annotation. The `min_overlap` column is optional and defaults to 0.9 if not provided.", "fa_icon": "fas fa-file-csv" - }, + } + } + }, + "mirna_processing_options": { + "title": "miRNA options", + "type": "object", + "fa_icon": "fas fa-terminal", + "description": "Define paths and threasholds for miRNA analysis.", + "required": ["mirna_expression"], + "properties": { "mirna_expression": { "type": "string", "format": "file-path", @@ -60,6 +69,22 @@ "pattern": "^\\S+\\.tsv$", "description": "Path to tab-separated file providing the expression counts of miRNAs, which are created in pipeline 'smrnaseq'. \n\nmirna \t sample1 \t sample2 \t sample3 \t\nid1\t count_sample1 \t count_sample2 \t count_sample3 \t\nid2 \t ... \t ... \t ... \t \n", "fa_icon": "fas fa-file-tsv" + }, + "mirna_min_sample_percentage": { + "type": "number", + "fa_icon": "fas fa-circle-notch", + "description": "Minimum percentage of samples, a miRNA has to be expressed in to pass filtering.", + "help_text": "The mirna_min_percentage parameter sets the minimum percentage of samples in which a miRNA must be expressed to pass filtering. The default value is 0.2, which means a miRNA must be detected in at least 20% of the samples to be included in the analysis.", + "default": 0.2, + "minimum": 0 + }, + "mirna_min_reads": { + "type": "integer", + "fa_icon": "fas fa-circle-notch", + "description": "Minimum number of reads, a miRNA is required to have to pass filtering.", + "help_text": "This parameter determines the minimum number of reads that a miRNA must have to pass filtering. The default is 5, meaning a miRNA must have at least 5 reads across the samples to be considered for analysis.", + "default": 5, + "minimum": 0 } } }, @@ -106,6 +131,23 @@ "description": "Specify the distance at which the annotation script decides if a candidate is a circRNA or EI-circRNA.", "help_text": "During annotation, if one of the start or end position of a circular candidate imperfectly overlaps an exon boundary, the script will consider positions within 'exon_boundary' (default 0bp) to be an exonic circRNA. If they fall outside of this range, the candidate is assumed to be an exonic-intronic circRNA, and the entire underlying sequence is taken for miRNA analysis, as opposed to just the exonic sequences for canonical exonic circRNAs. ", "default": 0 + }, + "mirna_tools": { + "type": "string", + "fa_icon": "fas fa-wrench", + "description": "Comma separated list of miRNA bindingsite prediction tools to use. Supported tools: miranda, targetscan.", + "help_text": "Select one or a combination of miRNA bindingsite prediction tools for the pipeline e.g:\n--tool 'miranda, targetscan'", + "default": "miranda, targetscan", + "pattern": "^((miranda|targetscan|pita|tarpmir)?,?)*[^,]+$" + }, + "mirna_vote": { + "type": "integer", + "fa_icon": "fas fa-intersection", + "description": "Specify the number of votes required for a miRNA to be further considered in downstream analysis.'", + "help_text": "Controls the number of votes required for a binding site prediction to be considered valid. If a miRNA binding site was predicted by two different tools (e.g., miRanda and TargetScan), it receives two votes. By specifying additional tools for miRNA binding site prediction (using the 'mirna_tools' parameter), you can adjust the number of votes required for a binding site to be considered valid.", + "default": 1, + "minimum": 1, + "maximum": 4 } } }, From 3617290865b07035dc44841c0ae44d4b4305e56f Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Fri, 10 May 2024 12:14:25 +0200 Subject: [PATCH 410/491] Adding formatting of mirna prediction output --- conf/modules.config | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/conf/modules.config b/conf/modules.config index fac43d45..722660a3 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -804,6 +804,30 @@ process { ] } + withName: COUNTS_COMBINED { + ext.when = { params.module.split(',').contains('circrna_discovery') } + } + + withName: COUNTS_TO_BED { + ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3, \".\", \".\" }'" + ext.suffix = "bed" + } + + withName: MIRANDA_TO_MAJORITY { + ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$1, \$2, \$7, \$8, \"miranda\" }'" + ext.suffix = "tsv" + } + + withName: TARGETSCAN_TO_MAJORITY { + ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$2, \$1, \$6, \$7, \"targetscan\" }'" + ext.suffix = "tsv" + } + + withName: UNIQUE_REGIONS { + ext.args = "-k 1,1 -k2,2n -k3,3n -u" + ext.suffix = "unique.bed" + } + withName: COMBINE_TRANSCRIPTOME_GTFS { ext.args = "-k 1,1 -k4,4n -k5,5n" ext.suffix = "combined.gtf" From e7a8f73575ea3313473ac44a15a15e9c55e817ab Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Fri, 10 May 2024 12:17:10 +0200 Subject: [PATCH 411/491] embedding mirna filtering and output formatting in mirna_prediction subworkflow --- subworkflows/local/mirna_prediction.nf | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index b58b14fe..3a0eb0ab 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -1,8 +1,11 @@ -include { TARGETSCAN_DATABASE } from '../../modules/local/targetscan/database' -include { TARGETSCAN } from '../../modules/local/targetscan/predict' -include { MIRANDA } from '../../modules/nf-core/miranda' -include { MIRNA_TARGETS } from '../../modules/local/mirna_targets' -include { DESEQ2_NORMALIZATION } from '../../modules/local/deseq2/normalization' +include { TARGETSCAN_DATABASE } from '../../modules/local/targetscan/database' +include { TARGETSCAN } from '../../modules/local/targetscan/predict' +include { MIRANDA } from '../../modules/nf-core/miranda' +include { MIRNA_TARGETS } from '../../modules/local/mirna_targets' +include { DESEQ2_NORMALIZATION } from '../../modules/local/deseq2/normalization' +include { MIRNA_FILTERING } from '../../modules/local/mirna_filtering' +include { GAWK as MIRANDA_TO_MAJORITY } from '../../modules/nf-core/gawk' +include { GAWK as TARGETSCAN_TO_MAJORITY } from '../../modules/nf-core/gawk' workflow MIRNA_PREDICTION{ @@ -26,12 +29,18 @@ workflow MIRNA_PREDICTION{ ch_versions = ch_versions.mix(DESEQ2_NORMALIZATION.out.versions) + ch_mirna_filtered = MIRNA_FILTERING( ch_mirna_normalized, + params.mirna_min_sample_percentage, + params.mirna_min_reads + ).filtered + ch_versions = ch_versions.mix(MIRNA_FILTERING.out.versions) // // TARGETSCAN WORKFLOW: // TARGETSCAN_DATABASE( ch_mature ) TARGETSCAN( circrna_fasta, TARGETSCAN_DATABASE.out.mature_txt ) + TARGETSCAN_TO_MAJORITY( TARGETSCAN.out.txt, [] ) ch_versions = ch_versions.mix(TARGETSCAN_DATABASE.out.versions) ch_versions = ch_versions.mix(TARGETSCAN.out.versions) @@ -41,8 +50,9 @@ workflow MIRNA_PREDICTION{ // MIRANDA( circrna_fasta, ch_mature.map{meta, mature -> mature} ) + MIRANDA_TO_MAJORITY( MIRANDA.out.txt, [] ) + ch_versions = ch_versions.mix(MIRANDA.out.versions) - ch_versions = ch_versions.mix(MIRANDA.out.versions) // // CONSOLIDATE PREDICTIONS WORKFLOW: From 3596c5f41ee190a8608614579c941ad57d97b4f0 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Sat, 11 May 2024 17:30:07 +0200 Subject: [PATCH 412/491] extending miranda output formatting to ignore unwanted prefix --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 722660a3..90211131 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -814,7 +814,7 @@ process { } withName: MIRANDA_TO_MAJORITY { - ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$1, \$2, \$7, \$8, \"miranda\" }'" + ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { sub(/^${params.species_id}-/, \"\", \$1); print \$1, \$2, \$7, \$8, \"miranda\" }'" ext.suffix = "tsv" } From 2715dfa40fd2956ffa6cbefc7135986cbaafb492 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Wed, 15 May 2024 19:28:55 +0200 Subject: [PATCH 413/491] implementing concatenation of mirna predictions, work in progress --- conf/modules.config | 10 +++++-- subworkflows/local/mirna_prediction.nf | 39 ++++++++++++++++++++------ 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 90211131..50a4553d 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -815,12 +815,16 @@ process { withName: MIRANDA_TO_MAJORITY { ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { sub(/^${params.species_id}-/, \"\", \$1); print \$1, \$2, \$7, \$8, \"miranda\" }'" - ext.suffix = "tsv" + ext.suffix = "miranda.tsv" } - + withName: TARGETSCAN_TO_MAJORITY { ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$2, \$1, \$6, \$7, \"targetscan\" }'" - ext.suffix = "tsv" + ext.suffix = "targetscan.tsv" + } + + withName: COMBINE_BINDINGSITES { + ext.prefix = "bindingsites.tsv" } withName: UNIQUE_REGIONS { diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index 3a0eb0ab..ce1e1b3d 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -1,11 +1,14 @@ -include { TARGETSCAN_DATABASE } from '../../modules/local/targetscan/database' -include { TARGETSCAN } from '../../modules/local/targetscan/predict' -include { MIRANDA } from '../../modules/nf-core/miranda' -include { MIRNA_TARGETS } from '../../modules/local/mirna_targets' -include { DESEQ2_NORMALIZATION } from '../../modules/local/deseq2/normalization' -include { MIRNA_FILTERING } from '../../modules/local/mirna_filtering' -include { GAWK as MIRANDA_TO_MAJORITY } from '../../modules/nf-core/gawk' -include { GAWK as TARGETSCAN_TO_MAJORITY } from '../../modules/nf-core/gawk' +include { TARGETSCAN_DATABASE } from '../../modules/local/targetscan/database' +include { TARGETSCAN } from '../../modules/local/targetscan/predict' +include { MIRANDA } from '../../modules/nf-core/miranda' +include { MIRNA_TARGETS } from '../../modules/local/mirna_targets' +include { DESEQ2_NORMALIZATION } from '../../modules/local/deseq2/normalization' +include { MIRNA_FILTERING } from '../../modules/local/mirna_filtering' +include { GAWK as MIRANDA_TO_MAJORITY } from '../../modules/nf-core/gawk' +include { GAWK as TARGETSCAN_TO_MAJORITY } from '../../modules/nf-core/gawk' +include { CAT_CAT as COMBINE_BINDINGSITES } from '../../modules/nf-core/cat/cat' + +// include { MAJORITY_VOTE } from '../../modules/local/majority_vote' workflow MIRNA_PREDICTION{ @@ -17,6 +20,7 @@ workflow MIRNA_PREDICTION{ main: ch_versions = Channel.empty() + ch_predictions = Channel.empty() ADD_BACKSPLICE( circrna_fasta, [] ) ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) @@ -33,7 +37,9 @@ workflow MIRNA_PREDICTION{ params.mirna_min_sample_percentage, params.mirna_min_reads ).filtered + ch_versions = ch_versions.mix(MIRNA_FILTERING.out.versions) + // // TARGETSCAN WORKFLOW: // @@ -44,6 +50,8 @@ workflow MIRNA_PREDICTION{ ch_versions = ch_versions.mix(TARGETSCAN_DATABASE.out.versions) ch_versions = ch_versions.mix(TARGETSCAN.out.versions) + + ch_predictions = ch_predictions.mix(TARGETSCAN_TO_MAJORITY.out.output) // // MIRANDA WORKFLOW: @@ -51,7 +59,9 @@ workflow MIRNA_PREDICTION{ MIRANDA( circrna_fasta, ch_mature.map{meta, mature -> mature} ) MIRANDA_TO_MAJORITY( MIRANDA.out.txt, [] ) + ch_versions = ch_versions.mix(MIRANDA.out.versions) + ch_predictions = ch_predictions.mix(MIRANDA_TO_MAJORITY.out.output) // @@ -63,6 +73,19 @@ workflow MIRNA_PREDICTION{ ch_versions = ch_versions.mix(MIRNA_TARGETS.out.versions) + + // + // UNIFICATION OF PREDICTIONS + // + + ch_predictions.map{meta, file -> file}.collect().map{[[id: "mirna"], it]} + + COMBINE_BINDINGSITES ( ch_predictions ) + + // + // MAJORITY VOTE: TODO + // + emit: versions = ch_versions } From 60fe2a8b34113e8d6538d371da3c48bb15e8f43b Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Fri, 17 May 2024 16:50:05 +0200 Subject: [PATCH 414/491] preparing majority vote --- modules/local/majority_vote/main.nf | 23 +++++++++++++++++ .../local/majority_vote/templates/majority.py | 25 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 modules/local/majority_vote/main.nf create mode 100644 modules/local/majority_vote/templates/majority.py diff --git a/modules/local/majority_vote/main.nf b/modules/local/majority_vote/main.nf new file mode 100644 index 00000000..76442d1f --- /dev/null +++ b/modules/local/majority_vote/main.nf @@ -0,0 +1,23 @@ +process MAJORITY_VOTE { + tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/r-base:4.2.1' : + 'biocontainers/r-base:4.2.1' }" + + input: + tuple val(meta), path(miranda_data) + path(targetscan_data) + + output: + tuple val(meta), path("${meta.id}.majority.tsv.gz") , emit: tsv + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + template 'majority.R' +} diff --git a/modules/local/majority_vote/templates/majority.py b/modules/local/majority_vote/templates/majority.py new file mode 100644 index 00000000..58a356fc --- /dev/null +++ b/modules/local/majority_vote/templates/majority.py @@ -0,0 +1,25 @@ +import pandas as pd + + +if __name__ == "__main__": + predictions = pd.read_csv("/home/malte/projects/refactorring/majority_test/main.tsv", + sep="\\t", header=0, names=['mirna', 'target', 'start', 'end', 'tool' ]) + + start = False + end = True + complete = False # TODO: Ask if this means an exact match or an "either ..., or ..." + majority = 2 + + if start: # group by start indices + predictions = predictions.groupby(['mirna', 'target', 'start'])['tool'].apply(set).reset_index() + elif end: # group by end indices + predictions = predictions.groupby(['mirna', 'target', 'end'])['tool'].apply(set).reset_index() + elif complete: # group by both indices + predictions = predictions.groupby(['mirna', 'target', 'start', 'end'])['tool'].apply(set).reset_index() + + # performing majority vote keeping only mirna binding sites that meet the required number of votes + post_vote_predictions = predictions[predictions['tool'].apply(len) >= majority].copy() + post_vote_predictions = post_vote_predictions.drop('tool', axis=1) + + + predictions_out.to_csv('filtered_bindingsites.tsv', sep='\\t', index=False) From 8a7772dce85501116fc3f486dfca19b2bc4d8354 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Fri, 17 May 2024 16:51:49 +0200 Subject: [PATCH 415/491] fixing channel structure of predictions for cat cat --- subworkflows/local/mirna_prediction.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index ce1e1b3d..160e569f 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -8,7 +8,7 @@ include { GAWK as MIRANDA_TO_MAJORITY } from '../../modules/nf-core/gawk' include { GAWK as TARGETSCAN_TO_MAJORITY } from '../../modules/nf-core/gawk' include { CAT_CAT as COMBINE_BINDINGSITES } from '../../modules/nf-core/cat/cat' -// include { MAJORITY_VOTE } from '../../modules/local/majority_vote' +// include { MAJORITY_VOTE } from '../../modules/local/majority_vote' workflow MIRNA_PREDICTION{ @@ -78,9 +78,9 @@ workflow MIRNA_PREDICTION{ // UNIFICATION OF PREDICTIONS // - ch_predictions.map{meta, file -> file}.collect().map{[[id: "mirna"], it]} + ch_combined = ch_predictions.map{meta, file -> file}.collect().map{[[id: "mirna"], it]} - COMBINE_BINDINGSITES ( ch_predictions ) + COMBINE_BINDINGSITES ( ch_combined ) // // MAJORITY VOTE: TODO From c7a82da25a8e1ae5611924d711d1fc7e9dd55752 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Sat, 18 May 2024 18:00:58 +0200 Subject: [PATCH 416/491] Embedding majority vote for mirna predictions --- modules/local/majority_vote/main.nf | 29 +++++--- .../local/majority_vote/templates/majority.py | 68 ++++++++++++++----- subworkflows/local/mirna_prediction.nf | 11 ++- 3 files changed, 79 insertions(+), 29 deletions(-) diff --git a/modules/local/majority_vote/main.nf b/modules/local/majority_vote/main.nf index 76442d1f..5cd86ae3 100644 --- a/modules/local/majority_vote/main.nf +++ b/modules/local/majority_vote/main.nf @@ -2,22 +2,33 @@ process MAJORITY_VOTE { tag "$meta.id" label 'process_single' - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/r-base:4.2.1' : - 'biocontainers/r-base:4.2.1' }" + conda "bioconda::pandas=1.5.2" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : + 'biocontainers/pandas:1.5.2' }" input: - tuple val(meta), path(miranda_data) - path(targetscan_data) + tuple val(meta), path(bindingsites) + output: - tuple val(meta), path("${meta.id}.majority.tsv.gz") , emit: tsv - path "versions.yml" , emit: versions + tuple val(meta), path("${meta.id}.majority.tsv") , emit: tsv + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when script: - template 'majority.R' + template 'majority.py' + + stub: + """ + touch ${meta.id}.majority.tsv + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + python: \$(python --version | sed 's/Python //g') + pandas: \$(python -c "import pandas; print(pandas.__version__)") + END_VERSIONS + """ } diff --git a/modules/local/majority_vote/templates/majority.py b/modules/local/majority_vote/templates/majority.py index 58a356fc..6c362dc4 100644 --- a/modules/local/majority_vote/templates/majority.py +++ b/modules/local/majority_vote/templates/majority.py @@ -1,25 +1,59 @@ +#!/usr/bin/env python3 import pandas as pd +import platform -if __name__ == "__main__": - predictions = pd.read_csv("/home/malte/projects/refactorring/majority_test/main.tsv", - sep="\\t", header=0, names=['mirna', 'target', 'start', 'end', 'tool' ]) +def format_yaml_like(data: dict, indent: int = 0) -> str: + """Formats a dictionary to a YAML-like string. - start = False - end = True - complete = False # TODO: Ask if this means an exact match or an "either ..., or ..." - majority = 2 + Args: + data (dict): The dictionary to format. + indent (int): The current indentation level. - if start: # group by start indices - predictions = predictions.groupby(['mirna', 'target', 'start'])['tool'].apply(set).reset_index() - elif end: # group by end indices - predictions = predictions.groupby(['mirna', 'target', 'end'])['tool'].apply(set).reset_index() - elif complete: # group by both indices - predictions = predictions.groupby(['mirna', 'target', 'start', 'end'])['tool'].apply(set).reset_index() + Returns: + str: A string formatted as YAML. + """ + yaml_str = "" + for key, value in data.items(): + spaces = " " * indent + if isinstance(value, dict): + yaml_str += f"{spaces}{key}:\\n{format_yaml_like(value, indent + 1)}" + else: + yaml_str += f"{spaces}{key}: {value}\\n" + return yaml_str - # performing majority vote keeping only mirna binding sites that meet the required number of votes - post_vote_predictions = predictions[predictions['tool'].apply(len) >= majority].copy() - post_vote_predictions = post_vote_predictions.drop('tool', axis=1) +predictions = pd.read_csv("$bindingsites", + sep="\\t", header=0, names=['mirna', 'target', 'start', 'end', 'tool' ]) - predictions_out.to_csv('filtered_bindingsites.tsv', sep='\\t', index=False) +# start = False # TODO: Probably needs to be removed +# end = False +complete = True # TODO: Ask if this means an exact match or an "either ..., or ..." +majority = ${params.mirna_vote} + +# if start: # group by start indices +# predictions = predictions.groupby(['mirna', 'target', 'start'])['tool'].apply(set).reset_index() +# elif end: # group by end indices +# predictions = predictions.groupby(['mirna', 'target', 'end'])['tool'].apply(set).reset_index() +# elif complete: # group by both indices +# predictions = predictions.groupby(['mirna', 'target', 'start', 'end'])['tool'].apply(set).reset_index() + +predictions = predictions.groupby(['mirna', 'target', 'start', 'end'])['tool'].apply(set).reset_index() + +# performing majority vote keeping only mirna binding sites that meet the required number of votes +post_vote_predictions = predictions[predictions['tool'].apply(len) >= majority].copy() +post_vote_predictions = post_vote_predictions.drop('tool', axis=1) + + +post_vote_predictions.to_csv('${meta.id}.majority.tsv', sep='\\t', index=False) + +# Create version file +versions = { + "${task.process}" : { + "python": platform.python_version(), + "pandas": pd.__version__, + } +} + +with open("versions.yml", "w") as f: + f.write(format_yaml_like(versions)) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index 160e569f..d5529933 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -8,7 +8,7 @@ include { GAWK as MIRANDA_TO_MAJORITY } from '../../modules/nf-core/gawk' include { GAWK as TARGETSCAN_TO_MAJORITY } from '../../modules/nf-core/gawk' include { CAT_CAT as COMBINE_BINDINGSITES } from '../../modules/nf-core/cat/cat' -// include { MAJORITY_VOTE } from '../../modules/local/majority_vote' +include { MAJORITY_VOTE } from '../../modules/local/majority_vote' workflow MIRNA_PREDICTION{ @@ -21,6 +21,7 @@ workflow MIRNA_PREDICTION{ main: ch_versions = Channel.empty() ch_predictions = Channel.empty() + ch_votings = Channel.empty() ADD_BACKSPLICE( circrna_fasta, [] ) ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) @@ -81,11 +82,15 @@ workflow MIRNA_PREDICTION{ ch_combined = ch_predictions.map{meta, file -> file}.collect().map{[[id: "mirna"], it]} COMBINE_BINDINGSITES ( ch_combined ) - + ch_votings = ch_votings.mix(COMBINE_BINDINGSITES.out.file_out) + ch_votings.view() + // - // MAJORITY VOTE: TODO + // MAJORITY VOTE: // + MAJORITY_VOTE( ch_votings ) + emit: versions = ch_versions } From bb5d520bfb00296e6500553cb5e48ee36f14acd3 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Sat, 1 Jun 2024 11:07:48 +0200 Subject: [PATCH 417/491] updating miranda to majority gawk --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 50a4553d..42e5a0f9 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -814,7 +814,7 @@ process { } withName: MIRANDA_TO_MAJORITY { - ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { sub(/^${params.species_id}-/, \"\", \$1); print \$1, \$2, \$7, \$8, \"miranda\" }'" + ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$1, \$2, \$7, \$8, \"miranda\" }'" ext.suffix = "miranda.tsv" } From d9dea25c721f4a533ddcb914c98ed1868d154fd5 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Sat, 1 Jun 2024 11:10:14 +0200 Subject: [PATCH 418/491] adding compute correlations module --- .../compute_correlations/environment.yml | 4 + modules/local/compute_correlations/main.nf | 30 ++++ .../templates/compute_correlations.R | 142 ++++++++++++++++++ subworkflows/local/mirna_prediction.nf | 68 ++++++++- workflows/circrna/main.nf | 1 + 5 files changed, 237 insertions(+), 8 deletions(-) create mode 100644 modules/local/compute_correlations/environment.yml create mode 100644 modules/local/compute_correlations/main.nf create mode 100644 modules/local/compute_correlations/templates/compute_correlations.R diff --git a/modules/local/compute_correlations/environment.yml b/modules/local/compute_correlations/environment.yml new file mode 100644 index 00000000..d0903bfd --- /dev/null +++ b/modules/local/compute_correlations/environment.yml @@ -0,0 +1,4 @@ +name: compute_correlations +channels: + - conda-forge + - defaults diff --git a/modules/local/compute_correlations/main.nf b/modules/local/compute_correlations/main.nf new file mode 100644 index 00000000..eae4add2 --- /dev/null +++ b/modules/local/compute_correlations/main.nf @@ -0,0 +1,30 @@ +process COMPUTE_CORRELATIONS { + tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/r-base:4.2.1' : + 'biocontainers/r-base:4.2.1' }" + + input: + tuple val(meta), path(bindingsites) + path(filtered_mirnas) + path(filtered_circrnas) + + + output: + tuple val(meta), path("${meta.id}.circrna_correlation.tsv") , emit: correlation + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + template 'compute_correlations.R' + + stub: + """ + touch ${meta.id}.circrna_correlation.tsv + """ +} diff --git a/modules/local/compute_correlations/templates/compute_correlations.R b/modules/local/compute_correlations/templates/compute_correlations.R new file mode 100644 index 00000000..add9a221 --- /dev/null +++ b/modules/local/compute_correlations/templates/compute_correlations.R @@ -0,0 +1,142 @@ +#!/usr/bin/env Rscript + +dataset <- read.table('${params.input}', sep = ",", header=T, stringsAsFactors = F, check.names = F) +samples <- dataset\$sample + +pairBindSites <- read.table('$bindingsites', header = F, sep = "\\t", stringsAsFactors = F, check.names = F) +pairBindSites <- as.data.frame.matrix(table(pairBindSites[,2], pairBindSites[,1])) + +if (!nrow(pairBindSites) > 1) { # check if there are samples that survived majority vote + stop("\\nMajority vote resulted in no bindingsites! Check majority.tsv and adjust the parameter 'mirn_vote' in your nextflow.config to a lower number.") +} + +miRNA_expression <- read.table('$filtered_mirnas', header = T, stringsAsFactors = F, check.names = F, sep = "\\t") + + +if(length(samples) < 5){ + stop("Cannot perform correlation on less than 5 samples") +} + +circRNA_expression <- read.table('$filtered_circrnas', header = T, stringsAsFactors = F, check.names = F, sep="\\t") + +circRNA_expression\$tx <- sub("^circ_", "", circRNA_expression\$tx) +rownames(circRNA_expression) <- circRNA_expression\$tx + + +# filter expression for miRNA binding pairs +valid_circRNAs <- intersect(circRNA_expression\$tx, rownames(pairBindSites)) +valid_miRNAs <- intersect(miRNA_expression\$miRNA, colnames(pairBindSites)) + +circRNA_expression <- circRNA_expression[valid_circRNAs,] +miRNA_expression <- miRNA_expression[miRNA_expression\$miRNA %in% valid_miRNAs,] + +# check for annotation +annotation <- "circBaseID" %in% colnames(circRNA_expression) #TODO Do we need this? + +header <- "circRNA\\tmiRNA\\tcircRNA_miRNA_ratio\\tmiRNA_binding_sites\\tpearson_R\\tcorr_pval\\tRSS_norm\\tintercept\\tintercept_pval\\tslope\\tslope_pval\\tadj_r_squared" +#write(header, file=paste0("filtered_circRNA_miRNA_correlation_libSizeEstNorm_directwritten.tsv"), append = F) + +miRNA_for_row <- function(miRNA_expr_line, circRNA, circRNA_counts){ + + mirna <- as.character(miRNA_expr_line[1]) + # get sample counts for current miRNA + miRNA_counts <- miRNA_expr_line[-1] + + miRNA_counts <- data.frame(sample = as.character(names(miRNA_counts)), "miRNA_counts" = as.numeric(unname(miRNA_counts))) + # compute circRNA expression vs. miRNA expression + joined_counts <- merge(miRNA_counts, circRNA_counts, by="sample") + + # analyse circRNA/miRNA ratio + mean_circRNA_counts <- mean(joined_counts\$circRNA_counts) + mean_miRNA_counts <- mean(joined_counts\$miRNA_counts) + circRNA_miRNA_ratio <- mean_circRNA_counts/mean_miRNA_counts + + binding_sites <- pairBindSites[circRNA, mirna] + + # compute circRNA-miRNA correlation for all samples + cor_res <- cor.test(joined_counts\$miRNA_counts, joined_counts\$circRNA_counts, method = "pearson", use = "complete.obs") + corr_R <- as.numeric(as.character(cor_res\$estimate)) + corr_pval <- as.numeric(as.character(cor_res\$p.value)) + + # compute linear regression + regression_model <- lm(miRNA_counts~circRNA_counts, data = joined_counts) + intercept <- summary(regression_model)\$coefficients[1,1] + intercept_pval <- summary(regression_model)\$coefficients[1,4] + slope <- summary(regression_model)\$coefficients[2,1] + slope_pval <- summary(regression_model)\$coefficients[2,4] + adj_r_squared <- summary(regression_model)\$adj.r.squared + + # compute residuals sum of squares + # normalize counts for residuals sum of squares + normalized_counts <- joined_counts[,c("circRNA_counts", "miRNA_counts")] + min_circRNA_counts <- min(normalized_counts\$circRNA_counts) + max_circRNA_counts <- max(normalized_counts\$circRNA_counts) + normalized_counts[,"circRNA_counts"] <- (normalized_counts[,"circRNA_counts"] - min_circRNA_counts)/(max_circRNA_counts - min_circRNA_counts) + min_miRNA_counts <- min(normalized_counts\$miRNA_counts) + max_miRNA_counts <- max(normalized_counts\$miRNA_counts) + normalized_counts[,"miRNA_counts"] <- (normalized_counts[,"miRNA_counts"] - min_miRNA_counts)/(max_miRNA_counts - min_miRNA_counts) + norm_reg_model <- lm(miRNA_counts~circRNA_counts, data = normalized_counts) + RSS_norm <- sum(norm_reg_model\$residuals^2) + + res <- data.frame(circRNA = as.character(circRNA), miRNA = as.character(mirna), + circRNA_miRNA_ratio = as.numeric(circRNA_miRNA_ratio), + miRNA_binding_sites = as.numeric(binding_sites), + pearson_R = as.numeric(corr_R), corr_pval = as.numeric(corr_pval), + RSS_norm = RSS_norm, intercept = intercept, + intercept_pval = intercept_pval, slope = slope, + slope_pval = slope_pval, adj_r_squared = adj_r_squared) + + return(res) +} + +circRNA_for_row <- function(circRNA_expr_line){ + # get coordinations of current circRNA + circRNA <- as.character(circRNA_expr_line[1]) + + # annotate if possible + if (annotation){ + an = circRNA_expression[circRNA,"circBaseID"] + if (an != "None") { + message("processing: ", circRNA, " (", an, ")") + circRNA = an + } + + } else { + message("processing: ", circRNA) + } + + # extract pure counts only + circRNA_counts <- circRNA_expr_line[samples] # passt + + # get sample counts for current circRNA + circRNA_counts <- data.frame(sample = as.character(names(circRNA_counts)), "circRNA_counts" = as.numeric(unname(circRNA_counts))) + + if (all(circRNA_counts\$circRNA_counts != 0)) { + res_list <- apply(miRNA_expression, 1, FUN = miRNA_for_row, circRNA, circRNA_counts) + res_df <- do.call(rbind, res_list) + return(res_df) + } + +} + +correlations_list <- apply(circRNA_expression, MARGIN = 1, circRNA_for_row) +correlations_df <- do.call(rbind, correlations_list) +correlations_df\$adj_pval <- p.adjust(correlations_df\$corr_pval, method = "BH") + +write.table(correlations_df, file=paste0("${meta.id}.circrna_correlation.tsv"), sep = "\\t", quote = F, row.names = F, col.names = T) + + +################################################ +################################################ +## VERSIONS FILE ## +################################################ +################################################ + +r.version <- strsplit(version[['version.string']], ' ')[[1]][3] + +writeLines( + c( + '"${task.process}":', + paste(' r-base:', r.version) + ), +'versions.yml') diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index d5529933..0dd3e01a 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -7,8 +7,8 @@ include { MIRNA_FILTERING } from '../../modules/local/mirna_filt include { GAWK as MIRANDA_TO_MAJORITY } from '../../modules/nf-core/gawk' include { GAWK as TARGETSCAN_TO_MAJORITY } from '../../modules/nf-core/gawk' include { CAT_CAT as COMBINE_BINDINGSITES } from '../../modules/nf-core/cat/cat' - include { MAJORITY_VOTE } from '../../modules/local/majority_vote' +include { COMPUTE_CORRELATIONS } from '../../modules/local/compute_correlations' workflow MIRNA_PREDICTION{ @@ -17,11 +17,13 @@ workflow MIRNA_PREDICTION{ circrna_bed12 ch_mature ch_mirna + circrna_counts main: ch_versions = Channel.empty() ch_predictions = Channel.empty() ch_votings = Channel.empty() + ch_targetscan_meta_formatted = Channel.empty() ADD_BACKSPLICE( circrna_fasta, [] ) ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) @@ -45,13 +47,12 @@ workflow MIRNA_PREDICTION{ // TARGETSCAN WORKFLOW: // - TARGETSCAN_DATABASE( ch_mature ) - TARGETSCAN( circrna_fasta, TARGETSCAN_DATABASE.out.mature_txt ) + ch_targetscan_meta_formatted = ch_targetscan_meta_formatted.mix(formatMiRNAForTargetScan( ch_mature )).collect() + + TARGETSCAN( circrna_fasta, ch_targetscan_meta_formatted ) TARGETSCAN_TO_MAJORITY( TARGETSCAN.out.txt, [] ) - ch_versions = ch_versions.mix(TARGETSCAN_DATABASE.out.versions) ch_versions = ch_versions.mix(TARGETSCAN.out.versions) - ch_predictions = ch_predictions.mix(TARGETSCAN_TO_MAJORITY.out.output) // @@ -82,15 +83,66 @@ workflow MIRNA_PREDICTION{ ch_combined = ch_predictions.map{meta, file -> file}.collect().map{[[id: "mirna"], it]} COMBINE_BINDINGSITES ( ch_combined ) - ch_votings = ch_votings.mix(COMBINE_BINDINGSITES.out.file_out) - ch_votings.view() + + ch_votings = ch_votings.mix(COMBINE_BINDINGSITES.out.file_out) + ch_versions.mix(COMBINE_BINDINGSITES.out.versions) // // MAJORITY VOTE: // - MAJORITY_VOTE( ch_votings ) + ch_bindingsites = Channel.empty() + MAJORITY_VOTE( ch_votings ) + + ch_bindingsites = ch_bindingsites.mix(MAJORITY_VOTE.output.tsv) + ch_versions = ch_versions.mix(MAJORITY_VOTE.output.versions) + + // + // COMPUTE CORREALTION: + // + + COMPUTE_CORRELATIONS( ch_bindingsites, + ch_mirna_filtered.map{meta, file -> file}.collect(), + circrna_counts.map{meta, file -> file}.collect() + ) + + ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) + emit: versions = ch_versions } + +/* +======================================================================================== + FUNCTIONS +======================================================================================== +*/ +// Fromatting miRNA input for taretscan +// takes mature.fa, iterates over entries (id, seq) and generates a new file +// writing: +// 1. miR ID +// 2. miR (7bp) seed sequence from mature seq +// 3. Species ID (set to 0000, not important for output). +// to new file +def formatMiRNAForTargetScan(ch_mature) { + + def ch_targetscan_meta_formatted = ch_mature + .map { meta, mature -> mature } + .splitFasta(by: 1) + .map { entry -> + def lines = entry.readLines() + def id = lines[0] + def seq = lines[1..-1].join() + return [id, seq] + } + .map { id, seq -> + def newSeq = seq[1..7] // Extract sub-sequence (2) + return [id, newSeq, '0000'] // Add species ID (3) + } + .map { id, newSeq, s_id -> "$id\t$newSeq\t$s_id\n" } + .collectFile(name: 'mature.txt') + + ch_targetscan_meta_formatted = ch_targetscan_meta_formatted.map { [[id: "mature_targetscan"], it] } + return ch_targetscan_meta_formatted +} diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index b82646f7..47642d7b 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -181,6 +181,7 @@ workflow CIRCRNA { BSJ_DETECTION.out.bed, ch_mature ch_mirna + QUANTIFICATION.out.circular_tx_counts ) ch_versions = ch_versions.mix(MIRNA_PREDICTION.out.versions) } From f51de26fea4e4d4401e95f02cca990ddcf939723 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Sat, 1 Jun 2024 11:10:31 +0200 Subject: [PATCH 419/491] todos --- .../deseq2/normalization/templates/deseq_normalization.R | 1 - modules/local/majority_vote/templates/majority.py | 9 +++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/local/deseq2/normalization/templates/deseq_normalization.R b/modules/local/deseq2/normalization/templates/deseq_normalization.R index daada9f6..131bfd54 100644 --- a/modules/local/deseq2/normalization/templates/deseq_normalization.R +++ b/modules/local/deseq2/normalization/templates/deseq_normalization.R @@ -36,7 +36,6 @@ norm_data <- subset(merged_data, select = -c(order)) write.table(norm_data, paste0("${meta.id}.normalized_counts.tsv"), quote = FALSE, sep = "\\t", row.names = FALSE) -# TODO: Perform normalization and save as "${meta.id}.normalized_counts.tsv" # TODO: (Can be done later) Add support for Samplesheet so that we can eliminate batch effects diff --git a/modules/local/majority_vote/templates/majority.py b/modules/local/majority_vote/templates/majority.py index 6c362dc4..b172591d 100644 --- a/modules/local/majority_vote/templates/majority.py +++ b/modules/local/majority_vote/templates/majority.py @@ -26,9 +26,10 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: predictions = pd.read_csv("$bindingsites", sep="\\t", header=0, names=['mirna', 'target', 'start', 'end', 'tool' ]) -# start = False # TODO: Probably needs to be removed +# start = False # end = False -complete = True # TODO: Ask if this means an exact match or an "either ..., or ..." +# TODO: Ask if this means an exact match or an "either ..., or ..." +complete = True majority = ${params.mirna_vote} # if start: # group by start indices @@ -42,10 +43,10 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: # performing majority vote keeping only mirna binding sites that meet the required number of votes post_vote_predictions = predictions[predictions['tool'].apply(len) >= majority].copy() -post_vote_predictions = post_vote_predictions.drop('tool', axis=1) +out = post_vote_predictions.drop('tool', axis=1) -post_vote_predictions.to_csv('${meta.id}.majority.tsv', sep='\\t', index=False) +out.to_csv('${meta.id}.majority.tsv', sep='\\t', index=False) # Create version file versions = { From c31d3d9efa4624462d0c73e67b1a4ccfb376bdaa Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 11:21:28 +0200 Subject: [PATCH 420/491] Replace tabs with spaces --- subworkflows/local/mirna_prediction.nf | 104 ++++++++++++------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index 0dd3e01a..ed7f3ebc 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -17,13 +17,13 @@ workflow MIRNA_PREDICTION{ circrna_bed12 ch_mature ch_mirna - circrna_counts + circrna_counts main: ch_versions = Channel.empty() ch_predictions = Channel.empty() - ch_votings = Channel.empty() - ch_targetscan_meta_formatted = Channel.empty() + ch_votings = Channel.empty() + ch_targetscan_meta_formatted = Channel.empty() ADD_BACKSPLICE( circrna_fasta, [] ) ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) @@ -37,11 +37,11 @@ workflow MIRNA_PREDICTION{ ch_versions = ch_versions.mix(DESEQ2_NORMALIZATION.out.versions) ch_mirna_filtered = MIRNA_FILTERING( ch_mirna_normalized, - params.mirna_min_sample_percentage, - params.mirna_min_reads - ).filtered + params.mirna_min_sample_percentage, + params.mirna_min_reads + ).filtered - ch_versions = ch_versions.mix(MIRNA_FILTERING.out.versions) + ch_versions = ch_versions.mix(MIRNA_FILTERING.out.versions) // // TARGETSCAN WORKFLOW: @@ -50,20 +50,20 @@ workflow MIRNA_PREDICTION{ ch_targetscan_meta_formatted = ch_targetscan_meta_formatted.mix(formatMiRNAForTargetScan( ch_mature )).collect() TARGETSCAN( circrna_fasta, ch_targetscan_meta_formatted ) - TARGETSCAN_TO_MAJORITY( TARGETSCAN.out.txt, [] ) + TARGETSCAN_TO_MAJORITY( TARGETSCAN.out.txt, [] ) ch_versions = ch_versions.mix(TARGETSCAN.out.versions) - ch_predictions = ch_predictions.mix(TARGETSCAN_TO_MAJORITY.out.output) + ch_predictions = ch_predictions.mix(TARGETSCAN_TO_MAJORITY.out.output) // // MIRANDA WORKFLOW: // MIRANDA( circrna_fasta, ch_mature.map{meta, mature -> mature} ) - MIRANDA_TO_MAJORITY( MIRANDA.out.txt, [] ) + MIRANDA_TO_MAJORITY( MIRANDA.out.txt, [] ) - ch_versions = ch_versions.mix(MIRANDA.out.versions) - ch_predictions = ch_predictions.mix(MIRANDA_TO_MAJORITY.out.output) + ch_versions = ch_versions.mix(MIRANDA.out.versions) + ch_predictions = ch_predictions.mix(MIRANDA_TO_MAJORITY.out.output) // @@ -76,39 +76,39 @@ workflow MIRNA_PREDICTION{ ch_versions = ch_versions.mix(MIRNA_TARGETS.out.versions) - // - // UNIFICATION OF PREDICTIONS - // + // + // UNIFICATION OF PREDICTIONS + // ch_combined = ch_predictions.map{meta, file -> file}.collect().map{[[id: "mirna"], it]} - - COMBINE_BINDINGSITES ( ch_combined ) - ch_votings = ch_votings.mix(COMBINE_BINDINGSITES.out.file_out) - ch_versions.mix(COMBINE_BINDINGSITES.out.versions) + COMBINE_BINDINGSITES ( ch_combined ) + + ch_votings = ch_votings.mix(COMBINE_BINDINGSITES.out.file_out) + ch_versions.mix(COMBINE_BINDINGSITES.out.versions) - // - // MAJORITY VOTE: - // + // + // MAJORITY VOTE: + // - ch_bindingsites = Channel.empty() + ch_bindingsites = Channel.empty() MAJORITY_VOTE( ch_votings ) - ch_bindingsites = ch_bindingsites.mix(MAJORITY_VOTE.output.tsv) - ch_versions = ch_versions.mix(MAJORITY_VOTE.output.versions) + ch_bindingsites = ch_bindingsites.mix(MAJORITY_VOTE.output.tsv) + ch_versions = ch_versions.mix(MAJORITY_VOTE.output.versions) - // - // COMPUTE CORREALTION: - // + // + // COMPUTE CORREALTION: + // - COMPUTE_CORRELATIONS( ch_bindingsites, - ch_mirna_filtered.map{meta, file -> file}.collect(), - circrna_counts.map{meta, file -> file}.collect() - ) + COMPUTE_CORRELATIONS( ch_bindingsites, + ch_mirna_filtered.map{meta, file -> file}.collect(), + circrna_counts.map{meta, file -> file}.collect() + ) - ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) - + ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) + emit: versions = ch_versions } @@ -127,22 +127,22 @@ workflow MIRNA_PREDICTION{ // to new file def formatMiRNAForTargetScan(ch_mature) { - def ch_targetscan_meta_formatted = ch_mature - .map { meta, mature -> mature } - .splitFasta(by: 1) - .map { entry -> - def lines = entry.readLines() - def id = lines[0] - def seq = lines[1..-1].join() - return [id, seq] - } - .map { id, seq -> - def newSeq = seq[1..7] // Extract sub-sequence (2) - return [id, newSeq, '0000'] // Add species ID (3) - } - .map { id, newSeq, s_id -> "$id\t$newSeq\t$s_id\n" } - .collectFile(name: 'mature.txt') - - ch_targetscan_meta_formatted = ch_targetscan_meta_formatted.map { [[id: "mature_targetscan"], it] } - return ch_targetscan_meta_formatted + def ch_targetscan_meta_formatted = ch_mature + .map { meta, mature -> mature } + .splitFasta(by: 1) + .map { entry -> + def lines = entry.readLines() + def id = lines[0] + def seq = lines[1..-1].join() + return [id, seq] + } + .map { id, seq -> + def newSeq = seq[1..7] // Extract sub-sequence (2) + return [id, newSeq, '0000'] // Add species ID (3) + } + .map { id, newSeq, s_id -> "$id\t$newSeq\t$s_id\n" } + .collectFile(name: 'mature.txt') + + ch_targetscan_meta_formatted = ch_targetscan_meta_formatted.map { [[id: "mature_targetscan"], it] } + return ch_targetscan_meta_formatted } From eb03b026cc3e4a2ffac88b6f4c7a29020e5d7f8e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 11:49:33 +0200 Subject: [PATCH 421/491] Implement MIRNA_BINDINGSITES subworkflow --- conf/modules.config | 4 +- .../local/mirna/mirna_bindingsites.nf | 97 +++++++++++++++ subworkflows/local/mirna_prediction.nf | 116 ++---------------- 3 files changed, 110 insertions(+), 107 deletions(-) create mode 100644 subworkflows/local/mirna/mirna_bindingsites.nf diff --git a/conf/modules.config b/conf/modules.config index 42e5a0f9..6126cc11 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -813,12 +813,12 @@ process { ext.suffix = "bed" } - withName: MIRANDA_TO_MAJORITY { + withName: UNIFY_MIRANDA { ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$1, \$2, \$7, \$8, \"miranda\" }'" ext.suffix = "miranda.tsv" } - withName: TARGETSCAN_TO_MAJORITY { + withName: UNIFY_TARGETSCAN { ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$2, \$1, \$6, \$7, \"targetscan\" }'" ext.suffix = "targetscan.tsv" } diff --git a/subworkflows/local/mirna/mirna_bindingsites.nf b/subworkflows/local/mirna/mirna_bindingsites.nf new file mode 100644 index 00000000..780bde22 --- /dev/null +++ b/subworkflows/local/mirna/mirna_bindingsites.nf @@ -0,0 +1,97 @@ +include { MIRANDA } from '../../../modules/nf-core/miranda' +include { GAWK as UNIFY_MIRANDA } from '../../../modules/nf-core/gawk' +include { TARGETSCAN } from '../../../modules/local/targetscan/predict' +include { GAWK as UNIFY_TARGETSCAN } from '../../../modules/nf-core/gawk' +include { MIRNA_TARGETS } from '../../../modules/local/mirna_targets' +include { CAT_CAT as COMBINE_BINDINGSITES } from '../../../modules/nf-core/cat/cat' +include { MAJORITY_VOTE } from '../../../modules/local/majority_vote' + +workflow MIRNA_BINDINGSITES { + take: + circrna_fasta + circrna_bed12 + mirna_fasta + + main: + ch_versions = Channel.empty() + ch_predictions = Channel.empty() + + // + // TARGETSCAN WORKFLOW: + // + TARGETSCAN( circrna_fasta, formatMiRNAForTargetScan( mirna_fasta ).collect() ) + UNIFY_TARGETSCAN( TARGETSCAN.out.txt, [] ) + + ch_versions = ch_versions.mix(TARGETSCAN.out.versions) + ch_versions = ch_versions.mix(UNIFY_TARGETSCAN.out.versions) + ch_predictions = ch_predictions.mix(UNIFY_TARGETSCAN.out.output) + + // + // MIRANDA WORKFLOW: + // + + MIRANDA( circrna_fasta, mirna_fasta.map{meta, mature -> mature} ) + UNIFY_MIRANDA( MIRANDA.out.txt, [] ) + + ch_versions = ch_versions.mix(MIRANDA.out.versions) + ch_versions = ch_versions.mix(UNIFY_MIRANDA.out.versions) + ch_predictions = ch_predictions.mix(UNIFY_MIRANDA.out.output) + + // + // CONSOLIDATE PREDICTIONS WORKFLOW: + // + // TODO: This is an artifact and should be removed if we have a replacement + + consolidate_targets = TARGETSCAN.out.txt.join(MIRANDA.out.txt).join(circrna_bed12) + MIRNA_TARGETS( consolidate_targets ) + + ch_versions = ch_versions.mix(MIRNA_TARGETS.out.versions) + + // + // MAJORITY VOTING: + // + COMBINE_BINDINGSITES ( ch_predictions.map{meta, file -> file}.collect().map{[[id: "mirna"], it]} ) + MAJORITY_VOTE( COMBINE_BINDINGSITES.out.file_out ) + + ch_versions = ch_versions.mix(COMBINE_BINDINGSITES.out.versions) + ch_versions = ch_versions.mix(MAJORITY_VOTE.out.versions) + + emit: + binding_sites = MAJORITY_VOTE.out.tsv + + versions = ch_versions +} + +/* +======================================================================================== + FUNCTIONS +======================================================================================== +*/ +// Formatting miRNA input for targetscan +// takes mature.fa, iterates over entries (id, seq) and generates a new file +// writing: +// 1. miR ID +// 2. miR (7bp) seed sequence from mature seq +// 3. Species ID (set to 0000, not important for output). +// to new file +def formatMiRNAForTargetScan(ch_mature) { + + def ch_targetscan_meta_formatted = ch_mature + .map { meta, mature -> mature } + .splitFasta(by: 1) + .map { entry -> + def lines = entry.readLines() + def id = lines[0] + def seq = lines[1..-1].join() + return [id, seq] + } + .map { id, seq -> + def newSeq = seq[1..7] // Extract sub-sequence (2) + return [id, newSeq, '0000'] // Add species ID (3) + } + .map { id, newSeq, s_id -> "$id\t$newSeq\t$s_id\n" } + .collectFile(name: 'mature.txt') + + ch_targetscan_meta_formatted = ch_targetscan_meta_formatted.map { [[id: "mature_targetscan"], it] } + return ch_targetscan_meta_formatted +} diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index ed7f3ebc..45ee0a1d 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -1,16 +1,12 @@ -include { TARGETSCAN_DATABASE } from '../../modules/local/targetscan/database' -include { TARGETSCAN } from '../../modules/local/targetscan/predict' -include { MIRANDA } from '../../modules/nf-core/miranda' -include { MIRNA_TARGETS } from '../../modules/local/mirna_targets' +// MODULES include { DESEQ2_NORMALIZATION } from '../../modules/local/deseq2/normalization' include { MIRNA_FILTERING } from '../../modules/local/mirna_filtering' -include { GAWK as MIRANDA_TO_MAJORITY } from '../../modules/nf-core/gawk' -include { GAWK as TARGETSCAN_TO_MAJORITY } from '../../modules/nf-core/gawk' -include { CAT_CAT as COMBINE_BINDINGSITES } from '../../modules/nf-core/cat/cat' -include { MAJORITY_VOTE } from '../../modules/local/majority_vote' -include { COMPUTE_CORRELATIONS } from '../../modules/local/compute_correlations' +include { COMPUTE_CORRELATIONS } from '../../modules/local/compute_correlations' -workflow MIRNA_PREDICTION{ +// SUBWORKFLOWS +include { MIRNA_BINDINGSITES } from './mirna/mirna_bindingsites' + +workflow MIRNA_PREDICTION { take: circrna_fasta @@ -21,15 +17,14 @@ workflow MIRNA_PREDICTION{ main: ch_versions = Channel.empty() - ch_predictions = Channel.empty() - ch_votings = Channel.empty() - ch_targetscan_meta_formatted = Channel.empty() + + MIRNA_BINDINGSITES( circrna_fasta, circrna_bed12, ch_mature ) ADD_BACKSPLICE( circrna_fasta, [] ) ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) // - // MIRNA QUANTIFICATION WORKFLOW: + // MIRNA NORMALIZATION WORKFLOW: // ch_mirna_normalized = DESEQ2_NORMALIZATION( ch_mirna ).normalized @@ -43,106 +38,17 @@ workflow MIRNA_PREDICTION{ ch_versions = ch_versions.mix(MIRNA_FILTERING.out.versions) - // - // TARGETSCAN WORKFLOW: - // - - ch_targetscan_meta_formatted = ch_targetscan_meta_formatted.mix(formatMiRNAForTargetScan( ch_mature )).collect() - - TARGETSCAN( circrna_fasta, ch_targetscan_meta_formatted ) - TARGETSCAN_TO_MAJORITY( TARGETSCAN.out.txt, [] ) - - ch_versions = ch_versions.mix(TARGETSCAN.out.versions) - ch_predictions = ch_predictions.mix(TARGETSCAN_TO_MAJORITY.out.output) - - // - // MIRANDA WORKFLOW: - // - - MIRANDA( circrna_fasta, ch_mature.map{meta, mature -> mature} ) - MIRANDA_TO_MAJORITY( MIRANDA.out.txt, [] ) - - ch_versions = ch_versions.mix(MIRANDA.out.versions) - ch_predictions = ch_predictions.mix(MIRANDA_TO_MAJORITY.out.output) - - - // - // CONSOLIDATE PREDICTIONS WORKFLOW: - // - - consolidate_targets = TARGETSCAN.out.txt.join(MIRANDA.out.txt).join(circrna_bed12) - MIRNA_TARGETS( consolidate_targets ) - - ch_versions = ch_versions.mix(MIRNA_TARGETS.out.versions) - - - // - // UNIFICATION OF PREDICTIONS - // - - ch_combined = ch_predictions.map{meta, file -> file}.collect().map{[[id: "mirna"], it]} - - COMBINE_BINDINGSITES ( ch_combined ) - - ch_votings = ch_votings.mix(COMBINE_BINDINGSITES.out.file_out) - ch_versions.mix(COMBINE_BINDINGSITES.out.versions) - - // - // MAJORITY VOTE: - // - - ch_bindingsites = Channel.empty() - - MAJORITY_VOTE( ch_votings ) - - ch_bindingsites = ch_bindingsites.mix(MAJORITY_VOTE.output.tsv) - ch_versions = ch_versions.mix(MAJORITY_VOTE.output.versions) - // // COMPUTE CORREALTION: // - COMPUTE_CORRELATIONS( ch_bindingsites, + COMPUTE_CORRELATIONS( MIRNA_BINDINGSITES.out.binding_sites, ch_mirna_filtered.map{meta, file -> file}.collect(), circrna_counts.map{meta, file -> file}.collect() ) - ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) + ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) emit: versions = ch_versions } - -/* -======================================================================================== - FUNCTIONS -======================================================================================== -*/ -// Fromatting miRNA input for taretscan -// takes mature.fa, iterates over entries (id, seq) and generates a new file -// writing: -// 1. miR ID -// 2. miR (7bp) seed sequence from mature seq -// 3. Species ID (set to 0000, not important for output). -// to new file -def formatMiRNAForTargetScan(ch_mature) { - - def ch_targetscan_meta_formatted = ch_mature - .map { meta, mature -> mature } - .splitFasta(by: 1) - .map { entry -> - def lines = entry.readLines() - def id = lines[0] - def seq = lines[1..-1].join() - return [id, seq] - } - .map { id, seq -> - def newSeq = seq[1..7] // Extract sub-sequence (2) - return [id, newSeq, '0000'] // Add species ID (3) - } - .map { id, newSeq, s_id -> "$id\t$newSeq\t$s_id\n" } - .collectFile(name: 'mature.txt') - - ch_targetscan_meta_formatted = ch_targetscan_meta_formatted.map { [[id: "mature_targetscan"], it] } - return ch_targetscan_meta_formatted -} From a8128573893d497bf4e8c3179cf48851712d89a7 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 11:49:58 +0200 Subject: [PATCH 422/491] Add versions capture for MIRNA_BINDINGSITES --- subworkflows/local/mirna_prediction.nf | 1 + 1 file changed, 1 insertion(+) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index 45ee0a1d..d0c1b929 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -19,6 +19,7 @@ workflow MIRNA_PREDICTION { ch_versions = Channel.empty() MIRNA_BINDINGSITES( circrna_fasta, circrna_bed12, ch_mature ) + ch_versions = ch_versions.mix(MIRNA_BINDINGSITES.out.versions) ADD_BACKSPLICE( circrna_fasta, [] ) ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) From d0360e21f5245cb19b2d3b820736921d4dfc1f63 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 12:09:53 +0200 Subject: [PATCH 423/491] Use full transcriptome in miRNA binding site detection --- subworkflows/local/mirna/mirna_bindingsites.nf | 13 ++++++++++--- subworkflows/local/mirna_prediction.nf | 14 +++++++------- subworkflows/local/quantification.nf | 1 + 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/subworkflows/local/mirna/mirna_bindingsites.nf b/subworkflows/local/mirna/mirna_bindingsites.nf index 780bde22..34cb1a48 100644 --- a/subworkflows/local/mirna/mirna_bindingsites.nf +++ b/subworkflows/local/mirna/mirna_bindingsites.nf @@ -1,3 +1,4 @@ +include { GAWK as ADD_BACKSPLICE } from '../../../modules/nf-core/gawk' include { MIRANDA } from '../../../modules/nf-core/miranda' include { GAWK as UNIFY_MIRANDA } from '../../../modules/nf-core/gawk' include { TARGETSCAN } from '../../../modules/local/targetscan/predict' @@ -8,7 +9,7 @@ include { MAJORITY_VOTE } from '../../../modules/local/majorit workflow MIRNA_BINDINGSITES { take: - circrna_fasta + transcriptome_fasta circrna_bed12 mirna_fasta @@ -16,10 +17,16 @@ workflow MIRNA_BINDINGSITES { ch_versions = Channel.empty() ch_predictions = Channel.empty() + // miRNAs can potentially bind to circRNAs right at the backsplice site + // In this case, the miRNA binding sequence would partially overlap with start and end of the circRNA + // To account for this, the first 25bp of the circRNA are added to the end of the circRNA sequence + ADD_BACKSPLICE( transcriptome_fasta, []) + ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) + // // TARGETSCAN WORKFLOW: // - TARGETSCAN( circrna_fasta, formatMiRNAForTargetScan( mirna_fasta ).collect() ) + TARGETSCAN( transcriptome_fasta, formatMiRNAForTargetScan( mirna_fasta ).collect() ) UNIFY_TARGETSCAN( TARGETSCAN.out.txt, [] ) ch_versions = ch_versions.mix(TARGETSCAN.out.versions) @@ -30,7 +37,7 @@ workflow MIRNA_BINDINGSITES { // MIRANDA WORKFLOW: // - MIRANDA( circrna_fasta, mirna_fasta.map{meta, mature -> mature} ) + MIRANDA( transcriptome_fasta, mirna_fasta.map{meta, mature -> mature} ) UNIFY_MIRANDA( MIRANDA.out.txt, [] ) ch_versions = ch_versions.mix(MIRANDA.out.versions) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index d0c1b929..e59adac8 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -9,7 +9,7 @@ include { MIRNA_BINDINGSITES } from './mirna/mirna_bindingsites' workflow MIRNA_PREDICTION { take: - circrna_fasta + transcriptome_fasta circrna_bed12 ch_mature ch_mirna @@ -18,7 +18,7 @@ workflow MIRNA_PREDICTION { main: ch_versions = Channel.empty() - MIRNA_BINDINGSITES( circrna_fasta, circrna_bed12, ch_mature ) + MIRNA_BINDINGSITES( transcriptome_fasta, circrna_bed12, ch_mature ) ch_versions = ch_versions.mix(MIRNA_BINDINGSITES.out.versions) ADD_BACKSPLICE( circrna_fasta, [] ) @@ -43,12 +43,12 @@ workflow MIRNA_PREDICTION { // COMPUTE CORREALTION: // - COMPUTE_CORRELATIONS( MIRNA_BINDINGSITES.out.binding_sites, - ch_mirna_filtered.map{meta, file -> file}.collect(), - circrna_counts.map{meta, file -> file}.collect() - ) + //COMPUTE_CORRELATIONS( MIRNA_BINDINGSITES.out.binding_sites, + // ch_mirna_filtered.map{meta, file -> file}.collect(), + // circrna_counts.map{meta, file -> file}.collect() + // ) - ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) + //ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) emit: versions = ch_versions diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index 695fd524..5c5bf48e 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -121,6 +121,7 @@ workflow QUANTIFICATION { emit: se = MERGE_EXPERIMENTS.out.merged + transcriptome = TRANSCRIPTOME.out.transcriptome gene_counts = JOIN_GENE_COUNTS.out.csv gene_tpm = JOIN_GENE_TPM.out.csv tx_counts = JOIN_TX_COUNTS.out.csv From 282ddc61b14ff40c7a6d2925c6ea6cb81cdf95f9 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 12:56:14 +0200 Subject: [PATCH 424/491] Use BIOAWK for ADD_BACKSPLICE --- conf/modules.config | 2 +- modules.json | 205 +++++++++++++----- modules/nf-core/bioawk/bioawk.diff | 24 ++ modules/nf-core/bioawk/environment.yml | 7 + modules/nf-core/bioawk/main.nf | 37 ++++ modules/nf-core/bioawk/meta.yml | 46 ++++ .../local/mirna/mirna_bindingsites.nf | 8 +- 7 files changed, 270 insertions(+), 59 deletions(-) create mode 100644 modules/nf-core/bioawk/bioawk.diff create mode 100644 modules/nf-core/bioawk/environment.yml create mode 100644 modules/nf-core/bioawk/main.nf create mode 100644 modules/nf-core/bioawk/meta.yml diff --git a/conf/modules.config b/conf/modules.config index 6126cc11..61492e6a 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -795,7 +795,7 @@ process { } withName: ADD_BACKSPLICE { - ext.args = "'{ if (/^>/) { print \$0 } else { start = substr(\$0, 1, 25); print \$0 start } }'" + ext.args = "-c fastx '{ if (\$name ~ /^circ_/) { \$seq = \$seq substr(\$seq, 1, 25) } print \">\" \$name; print \$seq }'" ext.suffix = "backspliced.fa" publishDir = [ path: { "${params.outdir}/mirna_prediction" }, diff --git a/modules.json b/modules.json index 36315754..b0cd0057 100644 --- a/modules.json +++ b/modules.json @@ -8,7 +8,9 @@ "bedtools/getfasta": { "branch": "master", "git_sha": "cdcdd5e3d806f0ff3983c40c69e0b07bb44ec299", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "bedtools/groupby": { "branch": "master", @@ -18,72 +20,108 @@ "bedtools/intersect": { "branch": "master", "git_sha": "575e1bc54b083fb15e7dd8b5fcc40bea60e8ce83", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "bedtools/sort": { "branch": "master", "git_sha": "571a5feac4c9ce0a8df0bc15b94230e7f3e8db47", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] + }, + "bioawk": { + "branch": "master", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "installed_by": [ + "modules" + ], + "patch": "modules/nf-core/bioawk/bioawk.diff" }, "bowtie/align": { "branch": "master", "git_sha": "3c77ca9aac783e76c3614a06db3bfe4fef619bde", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "bowtie/build": { "branch": "master", "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "bowtie2/align": { "branch": "master", "git_sha": "e4bad511789f16d0df39ee306b2cd50418365048", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "bowtie2/build": { "branch": "master", "git_sha": "1fea64f5132a813ec97c1c6d3a74e0aee7142b6d", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "bwa/index": { "branch": "master", - "git_sha": "e0ff65e1fb313677de09f5f477ae3da30ce19b7b", - "installed_by": ["modules"] + "git_sha": "086fa66260595e123b0ea47a6512539b72a9afa3", + "installed_by": [ + "modules" + ] }, "cat/cat": { "branch": "master", "git_sha": "9437e6053dccf4aafa022bfd6e7e9de67e625af8", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "cat/fastq": { "branch": "master", "git_sha": "4fc983ad0b30e6e32696fa7d980c76c7bfe1c03e", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "circexplorer2/annotate": { "branch": "master", "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "circexplorer2/parse": { "branch": "master", "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "csvtk/join": { "branch": "master", "git_sha": "614abbf126f287a3068dc86997b2e1b6a93abe20", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "csvtk/split": { "branch": "master", "git_sha": "614abbf126f287a3068dc86997b2e1b6a93abe20", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "custom/dumpsoftwareversions": { "branch": "master", "git_sha": "de45447d060b8c8b98575bc637a4a575fd0638e1", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "custom/gtffilter": { "branch": "master", @@ -93,117 +131,165 @@ "custom/tx2gene": { "branch": "master", "git_sha": "ec155021a9104441bf6a9bae3b55d1b5b0bfdb3a", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "fastqc": { "branch": "master", "git_sha": "285a50500f9e02578d90b3ce6382ea3c30216acd", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "gawk": { "branch": "master", "git_sha": "cf3ed075695639b0a0924eb0901146df1996dc08", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "gnu/sort": { "branch": "master", - "git_sha": "a3cc42943548378b726610f45bb5a79ab3f0b633", - "installed_by": ["modules"] + "git_sha": "ca199cfe5aa4f1ea3c41302158f0af2cfaa58957", + "installed_by": [ + "modules" + ] }, "hisat2/align": { "branch": "master", "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "hisat2/build": { "branch": "master", "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "hisat2/extractsplicesites": { "branch": "master", "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "miranda": { "branch": "master", "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "multiqc": { "branch": "master", "git_sha": "b7ebe95761cd389603f9cc0e0dc384c0f663815a", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "samtools/faidx": { "branch": "master", - "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", - "installed_by": ["modules"] + "git_sha": "f153f1f10e1083c49935565844cccb7453021682", + "installed_by": [ + "modules" + ] }, "samtools/flagstat": { "branch": "master", - "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", - "installed_by": ["bam_stats_samtools"] + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "installed_by": [ + "bam_stats_samtools" + ] }, "samtools/idxstats": { "branch": "master", - "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", - "installed_by": ["bam_stats_samtools"] + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "installed_by": [ + "bam_stats_samtools" + ] }, "samtools/index": { "branch": "master", - "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", - "installed_by": ["bam_sort_stats_samtools", "modules"] + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "installed_by": [ + "bam_sort_stats_samtools", + "modules" + ] }, "samtools/sort": { "branch": "master", - "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", - "installed_by": ["bam_sort_stats_samtools", "modules"] + "git_sha": "4352dbdb09ec40db71e9b172b97a01dcf5622c26", + "installed_by": [ + "bam_sort_stats_samtools", + "modules" + ] }, "samtools/stats": { "branch": "master", - "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", - "installed_by": ["bam_stats_samtools"] + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "installed_by": [ + "bam_stats_samtools" + ] }, "samtools/view": { "branch": "master", - "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", - "installed_by": ["modules"] + "git_sha": "0bd7d2333a88483aa0476acea172e9f5f6dd83bb", + "installed_by": [ + "modules" + ] }, "segemehl/align": { "branch": "master", "git_sha": "9a6b0745dbb5359286d36dee2183ffab240abba0", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "segemehl/index": { "branch": "master", "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "star/align": { "branch": "master", "git_sha": "a21faa6a3481af92a343a10926f59c189a2c16c9", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "star/genomegenerate": { "branch": "master", "git_sha": "a21faa6a3481af92a343a10926f59c189a2c16c9", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "stringtie/stringtie": { "branch": "master", "git_sha": "b1b959609bda44341120aed1766329909f54b8d0", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "trimgalore": { "branch": "master", "git_sha": "a98418419ae6c9df3cf6cf108d1e1aba71037d5a", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "tximeta/tximport": { "branch": "master", "git_sha": "5d095e8413da1f4c72b7d07ce87f75c09482486f", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] } } }, @@ -211,28 +297,39 @@ "nf-core": { "bam_sort_stats_samtools": { "branch": "master", - "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", - "installed_by": ["subworkflows"] + "git_sha": "4352dbdb09ec40db71e9b172b97a01dcf5622c26", + "installed_by": [ + "subworkflows" + ] }, "bam_stats_samtools": { "branch": "master", - "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", - "installed_by": ["bam_sort_stats_samtools", "subworkflows"] + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "installed_by": [ + "bam_sort_stats_samtools", + "subworkflows" + ] }, "utils_nextflow_pipeline": { "branch": "master", "git_sha": "5caf7640a9ef1d18d765d55339be751bb0969dfa", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "utils_nfcore_pipeline": { "branch": "master", "git_sha": "92de218a329bfc9a9033116eb5f65fd270e72ba3", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "utils_nfvalidation_plugin": { "branch": "master", "git_sha": "5caf7640a9ef1d18d765d55339be751bb0969dfa", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] } } } diff --git a/modules/nf-core/bioawk/bioawk.diff b/modules/nf-core/bioawk/bioawk.diff new file mode 100644 index 00000000..1303738f --- /dev/null +++ b/modules/nf-core/bioawk/bioawk.diff @@ -0,0 +1,24 @@ +Changes in module 'nf-core/bioawk' +--- modules/nf-core/bioawk/main.nf ++++ modules/nf-core/bioawk/main.nf +@@ -20,15 +20,15 @@ + script: + def args = task.ext.args ?: '' // args is used for the main arguments of the tool + prefix = task.ext.prefix ?: "${meta.id}" ++ suffix = task.ext.suffix ?: input.extension ++ file_name = "${prefix}.${suffix}" + + def VERSION = '1.0' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. + """ + bioawk \\ + $args \\ + $input \\ +- > ${prefix} +- +- gzip ${prefix} ++ > ${file_name} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + +************************************************************ diff --git a/modules/nf-core/bioawk/environment.yml b/modules/nf-core/bioawk/environment.yml new file mode 100644 index 00000000..5fdfd417 --- /dev/null +++ b/modules/nf-core/bioawk/environment.yml @@ -0,0 +1,7 @@ +name: bioawk +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::bioawk=1.0 diff --git a/modules/nf-core/bioawk/main.nf b/modules/nf-core/bioawk/main.nf new file mode 100644 index 00000000..0fded517 --- /dev/null +++ b/modules/nf-core/bioawk/main.nf @@ -0,0 +1,37 @@ +process BIOAWK { + tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/bioawk:1.0--h5bf99c6_6': + 'biocontainers/bioawk:1.0--h5bf99c6_6' }" + + input: + tuple val(meta), path(input) + + output: + tuple val(meta), path("${prefix}.${suffix}"), emit: output + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' // args is used for the main arguments of the tool + prefix = task.ext.prefix ?: "${meta.id}" + suffix = task.ext.suffix ?: input.extension + + def VERSION = '1.0' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. + """ + bioawk \\ + $args \\ + $input \\ + > ${prefix}.${suffix} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + bioawk: $VERSION + END_VERSIONS + """ +} diff --git a/modules/nf-core/bioawk/meta.yml b/modules/nf-core/bioawk/meta.yml new file mode 100644 index 00000000..c9d00111 --- /dev/null +++ b/modules/nf-core/bioawk/meta.yml @@ -0,0 +1,46 @@ +name: "bioawk" +description: Bioawk is an extension to Brian Kernighan's awk, adding the support of several common biological data formats. +keywords: + - bioawk + - fastq + - fasta + - sam + - file manipulation + - awk +tools: + - "bioawk": + description: "BWK awk modified for biological data" + homepage: "https://github.com/lh3/bioawk" + documentation: "https://github.com/lh3/bioawk" + tool_dev_url: "https://github.com/lh3/bioawk" + licence: "['Free software license (https://github.com/lh3/bioawk/blob/master/README.awk#L1)']" +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - input: + type: file + description: Input sequence biological sequence file (optionally gzipped) to be manipulated via program specified in `$args`. + pattern: "*.{bed,gff,sam,vcf,fastq,fasta,tab,bed.gz,gff.gz,sam.gz,vcf.gz,fastq.gz,fasta.gz,tab.gz}" +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + - output: + type: file + description: | + Manipulated and gzipped version of input sequence file following program specified in `args`. + File name will be what is specified in `$prefix`. Do not include `.gz` suffix in `$prefix`! Output files` will be gzipped for you! + pattern: "*.gz" +authors: + - "@jfy133" +maintainers: + - "@jfy133" diff --git a/subworkflows/local/mirna/mirna_bindingsites.nf b/subworkflows/local/mirna/mirna_bindingsites.nf index 34cb1a48..4c68c800 100644 --- a/subworkflows/local/mirna/mirna_bindingsites.nf +++ b/subworkflows/local/mirna/mirna_bindingsites.nf @@ -1,4 +1,4 @@ -include { GAWK as ADD_BACKSPLICE } from '../../../modules/nf-core/gawk' +include { BIOAWK as ADD_BACKSPLICE } from '../../../modules/nf-core/bioawk' include { MIRANDA } from '../../../modules/nf-core/miranda' include { GAWK as UNIFY_MIRANDA } from '../../../modules/nf-core/gawk' include { TARGETSCAN } from '../../../modules/local/targetscan/predict' @@ -20,13 +20,13 @@ workflow MIRNA_BINDINGSITES { // miRNAs can potentially bind to circRNAs right at the backsplice site // In this case, the miRNA binding sequence would partially overlap with start and end of the circRNA // To account for this, the first 25bp of the circRNA are added to the end of the circRNA sequence - ADD_BACKSPLICE( transcriptome_fasta, []) + ADD_BACKSPLICE( transcriptome_fasta) ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) // // TARGETSCAN WORKFLOW: // - TARGETSCAN( transcriptome_fasta, formatMiRNAForTargetScan( mirna_fasta ).collect() ) + TARGETSCAN( ADD_BACKSPLICE.out.output, formatMiRNAForTargetScan( mirna_fasta ).collect() ) UNIFY_TARGETSCAN( TARGETSCAN.out.txt, [] ) ch_versions = ch_versions.mix(TARGETSCAN.out.versions) @@ -37,7 +37,7 @@ workflow MIRNA_BINDINGSITES { // MIRANDA WORKFLOW: // - MIRANDA( transcriptome_fasta, mirna_fasta.map{meta, mature -> mature} ) + MIRANDA( ADD_BACKSPLICE.out.output, mirna_fasta.map{meta, mature -> mature} ) UNIFY_MIRANDA( MIRANDA.out.txt, [] ) ch_versions = ch_versions.mix(MIRANDA.out.versions) From 91436e32403350ba4a7626177a3a41e2cca8e998 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 13:13:09 +0200 Subject: [PATCH 425/491] Pass correct count info to mirna_prediction --- subworkflows/local/mirna_prediction.nf | 5 +++-- subworkflows/local/quantification.nf | 1 + workflows/circrna/main.nf | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index e59adac8..3428df6a 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -13,7 +13,8 @@ workflow MIRNA_PREDICTION { circrna_bed12 ch_mature ch_mirna - circrna_counts + transcript_counts + quantification_rds main: ch_versions = Channel.empty() @@ -45,7 +46,7 @@ workflow MIRNA_PREDICTION { //COMPUTE_CORRELATIONS( MIRNA_BINDINGSITES.out.binding_sites, // ch_mirna_filtered.map{meta, file -> file}.collect(), - // circrna_counts.map{meta, file -> file}.collect() + // transcript_counts.map{meta, file -> file}.collect() // ) //ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) diff --git a/subworkflows/local/quantification.nf b/subworkflows/local/quantification.nf index 5c5bf48e..62abc16a 100644 --- a/subworkflows/local/quantification.nf +++ b/subworkflows/local/quantification.nf @@ -122,6 +122,7 @@ workflow QUANTIFICATION { emit: se = MERGE_EXPERIMENTS.out.merged transcriptome = TRANSCRIPTOME.out.transcriptome + rds = MERGE_EXPERIMENTS.out.merged gene_counts = JOIN_GENE_COUNTS.out.csv gene_tpm = JOIN_GENE_TPM.out.csv tx_counts = JOIN_TX_COUNTS.out.csv diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index 47642d7b..cf2abf1e 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -182,6 +182,7 @@ workflow CIRCRNA { ch_mature ch_mirna QUANTIFICATION.out.circular_tx_counts + QUANTIFICATION.out.rds ) ch_versions = ch_versions.mix(MIRNA_PREDICTION.out.versions) } From 05f588fb8b61e856cd5e6ca8b387f6d409ae0b11 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 13:38:56 +0200 Subject: [PATCH 426/491] Implement transcriptome batch splitting in MIRNA_BINDINGSITES --- subworkflows/local/mirna/mirna_bindingsites.nf | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/subworkflows/local/mirna/mirna_bindingsites.nf b/subworkflows/local/mirna/mirna_bindingsites.nf index 4c68c800..61bd0964 100644 --- a/subworkflows/local/mirna/mirna_bindingsites.nf +++ b/subworkflows/local/mirna/mirna_bindingsites.nf @@ -23,10 +23,14 @@ workflow MIRNA_BINDINGSITES { ADD_BACKSPLICE( transcriptome_fasta) ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) + ch_transcriptome_batches = ADD_BACKSPLICE.out.output + .splitFasta(by: 100, file: true) + .map{ meta, file -> [[id: "batch_" + file.baseName.split("\\.").last()], file]} + // // TARGETSCAN WORKFLOW: // - TARGETSCAN( ADD_BACKSPLICE.out.output, formatMiRNAForTargetScan( mirna_fasta ).collect() ) + TARGETSCAN( ch_transcriptome_batches, formatMiRNAForTargetScan( mirna_fasta ).collect() ) UNIFY_TARGETSCAN( TARGETSCAN.out.txt, [] ) ch_versions = ch_versions.mix(TARGETSCAN.out.versions) @@ -37,7 +41,7 @@ workflow MIRNA_BINDINGSITES { // MIRANDA WORKFLOW: // - MIRANDA( ADD_BACKSPLICE.out.output, mirna_fasta.map{meta, mature -> mature} ) + MIRANDA( ch_transcriptome_batches, mirna_fasta.map{meta, mature -> mature} ) UNIFY_MIRANDA( MIRANDA.out.txt, [] ) ch_versions = ch_versions.mix(MIRANDA.out.versions) From 7a097fea4f562ed521a42e23e976eb74965df9f2 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 14:16:04 +0200 Subject: [PATCH 427/491] Improve targetscan input preparation --- subworkflows/local/mirna/mirna_bindingsites.nf | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/subworkflows/local/mirna/mirna_bindingsites.nf b/subworkflows/local/mirna/mirna_bindingsites.nf index 61bd0964..ba204bf3 100644 --- a/subworkflows/local/mirna/mirna_bindingsites.nf +++ b/subworkflows/local/mirna/mirna_bindingsites.nf @@ -89,18 +89,10 @@ def formatMiRNAForTargetScan(ch_mature) { def ch_targetscan_meta_formatted = ch_mature .map { meta, mature -> mature } - .splitFasta(by: 1) - .map { entry -> - def lines = entry.readLines() - def id = lines[0] - def seq = lines[1..-1].join() - return [id, seq] + .splitFasta(record: [id: true, seqString: true]) + .map { record -> + return "${record.id}\t${record.seqString[1..7]}\t0000\n" } - .map { id, seq -> - def newSeq = seq[1..7] // Extract sub-sequence (2) - return [id, newSeq, '0000'] // Add species ID (3) - } - .map { id, newSeq, s_id -> "$id\t$newSeq\t$s_id\n" } .collectFile(name: 'mature.txt') ch_targetscan_meta_formatted = ch_targetscan_meta_formatted.map { [[id: "mature_targetscan"], it] } From 4683f79b5a7012fa2f54ffdc0482a44f0a953a1c Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 14:37:37 +0200 Subject: [PATCH 428/491] Improve majority vote script --- .../local/majority_vote/templates/majority.py | 26 +++++-------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/modules/local/majority_vote/templates/majority.py b/modules/local/majority_vote/templates/majority.py index b172591d..3c60dc2f 100644 --- a/modules/local/majority_vote/templates/majority.py +++ b/modules/local/majority_vote/templates/majority.py @@ -23,30 +23,16 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: return yaml_str -predictions = pd.read_csv("$bindingsites", +df = pd.read_csv("$bindingsites", sep="\\t", header=0, names=['mirna', 'target', 'start', 'end', 'tool' ]) - -# start = False -# end = False -# TODO: Ask if this means an exact match or an "either ..., or ..." -complete = True -majority = ${params.mirna_vote} - -# if start: # group by start indices -# predictions = predictions.groupby(['mirna', 'target', 'start'])['tool'].apply(set).reset_index() -# elif end: # group by end indices -# predictions = predictions.groupby(['mirna', 'target', 'end'])['tool'].apply(set).reset_index() -# elif complete: # group by both indices -# predictions = predictions.groupby(['mirna', 'target', 'start', 'end'])['tool'].apply(set).reset_index() - -predictions = predictions.groupby(['mirna', 'target', 'start', 'end'])['tool'].apply(set).reset_index() +df = df.groupby(['mirna', 'target'])['tool'].apply(set).reset_index() # performing majority vote keeping only mirna binding sites that meet the required number of votes -post_vote_predictions = predictions[predictions['tool'].apply(len) >= majority].copy() -out = post_vote_predictions.drop('tool', axis=1) - +min_tools = int("${params.mirna_vote}") +df = df[df['tool'].apply(len) >= min_tools].copy() +df = df.drop('tool', axis=1) -out.to_csv('${meta.id}.majority.tsv', sep='\\t', index=False) +df.to_csv('${meta.id}.majority.tsv', sep='\\t', index=False) # Create version file versions = { From 5852fe94283fa2bc5ba5b427ddfaf1b104173b7e Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 14:50:32 +0200 Subject: [PATCH 429/491] Improve styling --- modules/local/compute_correlations/main.nf | 23 +++++++++++----------- subworkflows/local/mirna_prediction.nf | 16 +++++++-------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/modules/local/compute_correlations/main.nf b/modules/local/compute_correlations/main.nf index eae4add2..df6e7823 100644 --- a/modules/local/compute_correlations/main.nf +++ b/modules/local/compute_correlations/main.nf @@ -5,26 +5,25 @@ process COMPUTE_CORRELATIONS { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/r-base:4.2.1' : - 'biocontainers/r-base:4.2.1' }" + 'biocontainers/r-base:4.2.1' }" input: - tuple val(meta), path(bindingsites) - path(filtered_mirnas) - path(filtered_circrnas) - + tuple val(meta), path(bindingsites) + tuple val(meta2), path(mirna_expression) + tuple val(meta3), path(transcript_rds) output: - tuple val(meta), path("${meta.id}.circrna_correlation.tsv") , emit: correlation - path "versions.yml" , emit: versions + tuple val(meta), path("${meta.id}.circrna_correlation.tsv"), emit: correlation + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when script: template 'compute_correlations.R' - - stub: - """ - touch ${meta.id}.circrna_correlation.tsv - """ + + stub: + """ + touch ${meta.id}.circrna_correlation.tsv + """ } diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index 3428df6a..86858033 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -33,10 +33,10 @@ workflow MIRNA_PREDICTION { ch_versions = ch_versions.mix(DESEQ2_NORMALIZATION.out.versions) - ch_mirna_filtered = MIRNA_FILTERING( ch_mirna_normalized, - params.mirna_min_sample_percentage, - params.mirna_min_reads - ).filtered + ch_mirna_filtered = MIRNA_FILTERING(ch_mirna_normalized, + params.mirna_min_sample_percentage, + params.mirna_min_reads + ).filtered ch_versions = ch_versions.mix(MIRNA_FILTERING.out.versions) @@ -44,10 +44,10 @@ workflow MIRNA_PREDICTION { // COMPUTE CORREALTION: // - //COMPUTE_CORRELATIONS( MIRNA_BINDINGSITES.out.binding_sites, - // ch_mirna_filtered.map{meta, file -> file}.collect(), - // transcript_counts.map{meta, file -> file}.collect() - // ) + COMPUTE_CORRELATIONS( MIRNA_BINDINGSITES.out.binding_sites, + ch_mirna_filtered, + quantification_rds + ) //ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) From 8d2c151cdcb0fac8d437cba044c742d654b03145 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 14:52:57 +0200 Subject: [PATCH 430/491] Add majority targets output --- modules/local/majority_vote/main.nf | 5 +++-- modules/local/majority_vote/templates/majority.py | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/local/majority_vote/main.nf b/modules/local/majority_vote/main.nf index 5cd86ae3..6f965262 100644 --- a/modules/local/majority_vote/main.nf +++ b/modules/local/majority_vote/main.nf @@ -12,8 +12,9 @@ process MAJORITY_VOTE { output: - tuple val(meta), path("${meta.id}.majority.tsv") , emit: tsv - path "versions.yml" , emit: versions + tuple val(meta), path("${meta.id}.majority.tsv"), emit: tsv + tuple val(meta), path("${meta.id}.targets.tsv") , emit: targets + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/majority_vote/templates/majority.py b/modules/local/majority_vote/templates/majority.py index 3c60dc2f..786fdb8c 100644 --- a/modules/local/majority_vote/templates/majority.py +++ b/modules/local/majority_vote/templates/majority.py @@ -34,6 +34,9 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: df.to_csv('${meta.id}.majority.tsv', sep='\\t', index=False) +df = df.groupby('target')['mirna'].apply(lambda x: ','.join(x)).reset_index() +df.to_csv('${meta.id}.targets.tsv', sep='\\t', index=False, header=False) + # Create version file versions = { "${task.process}" : { From 56007a751c6c9fa35aa4fee5f0aadd0f080a9283 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 15:03:33 +0200 Subject: [PATCH 431/491] Transpose binding site output --- modules/local/majority_vote/main.nf | 20 +++++++++---------- .../local/majority_vote/templates/majority.py | 2 +- .../local/mirna/mirna_bindingsites.nf | 2 +- subworkflows/local/mirna_prediction.nf | 12 +++++++---- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/modules/local/majority_vote/main.nf b/modules/local/majority_vote/main.nf index 6f965262..8ed51f0a 100644 --- a/modules/local/majority_vote/main.nf +++ b/modules/local/majority_vote/main.nf @@ -2,14 +2,14 @@ process MAJORITY_VOTE { tag "$meta.id" label 'process_single' - conda "bioconda::pandas=1.5.2" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : - 'biocontainers/pandas:1.5.2' }" + conda "bioconda::pandas=1.5.2" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : + 'biocontainers/pandas:1.5.2' }" input: tuple val(meta), path(bindingsites) - + output: tuple val(meta), path("${meta.id}.majority.tsv"), emit: tsv @@ -21,15 +21,15 @@ process MAJORITY_VOTE { script: template 'majority.py' - - stub: - """ - touch ${meta.id}.majority.tsv + + stub: + """ + touch ${meta.id}.majority.tsv cat <<-END_VERSIONS > versions.yml "${task.process}": python: \$(python --version | sed 's/Python //g') pandas: \$(python -c "import pandas; print(pandas.__version__)") END_VERSIONS - """ + """ } diff --git a/modules/local/majority_vote/templates/majority.py b/modules/local/majority_vote/templates/majority.py index 786fdb8c..2969ce54 100644 --- a/modules/local/majority_vote/templates/majority.py +++ b/modules/local/majority_vote/templates/majority.py @@ -34,7 +34,7 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: df.to_csv('${meta.id}.majority.tsv', sep='\\t', index=False) -df = df.groupby('target')['mirna'].apply(lambda x: ','.join(x)).reset_index() +df = df.groupby('mirna')['target'].apply(lambda x: ','.join(x)).reset_index() df.to_csv('${meta.id}.targets.tsv', sep='\\t', index=False, header=False) # Create version file diff --git a/subworkflows/local/mirna/mirna_bindingsites.nf b/subworkflows/local/mirna/mirna_bindingsites.nf index ba204bf3..e46233f4 100644 --- a/subworkflows/local/mirna/mirna_bindingsites.nf +++ b/subworkflows/local/mirna/mirna_bindingsites.nf @@ -68,7 +68,7 @@ workflow MIRNA_BINDINGSITES { ch_versions = ch_versions.mix(MAJORITY_VOTE.out.versions) emit: - binding_sites = MAJORITY_VOTE.out.tsv + binding_sites = MAJORITY_VOTE.out.targets versions = ch_versions } diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index 86858033..ff75a8fe 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -44,10 +44,14 @@ workflow MIRNA_PREDICTION { // COMPUTE CORREALTION: // - COMPUTE_CORRELATIONS( MIRNA_BINDINGSITES.out.binding_sites, - ch_mirna_filtered, - quantification_rds - ) + ch_binding_site_batches = MIRNA_BINDINGSITES.out.binding_sites + .splitText(by: 100, file: true) + .map{ meta, file -> [[id: "batch_" + file.baseName.split("\\.").last()], file]} + .view() + + // COMPUTE_CORRELATIONS( ch_binding_site_batches, + // ch_mirna_filtered, + // quantification_rds) //ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) From 825f0d1bb85efc30893efd2885e41d56615054f3 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 15:16:01 +0200 Subject: [PATCH 432/491] Start refactoring correlation --- .../compute_correlations/environment.yml | 5 +- modules/local/compute_correlations/main.nf | 6 +- .../templates/compute_correlations.R | 128 +----------------- subworkflows/local/mirna_prediction.nf | 7 +- 4 files changed, 14 insertions(+), 132 deletions(-) diff --git a/modules/local/compute_correlations/environment.yml b/modules/local/compute_correlations/environment.yml index d0903bfd..efe72834 100644 --- a/modules/local/compute_correlations/environment.yml +++ b/modules/local/compute_correlations/environment.yml @@ -1,4 +1,7 @@ -name: compute_correlations +name: "compute_correlations" channels: - conda-forge - defaults + - bioconda +dependencies: + - "bioconda::bioconductor-fishpond=2.8.0--r43hdfd78af_0" diff --git a/modules/local/compute_correlations/main.nf b/modules/local/compute_correlations/main.nf index df6e7823..dd8d48b3 100644 --- a/modules/local/compute_correlations/main.nf +++ b/modules/local/compute_correlations/main.nf @@ -4,8 +4,8 @@ process COMPUTE_CORRELATIONS { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/r-base:4.2.1' : - 'biocontainers/r-base:4.2.1' }" + 'https://depot.galaxyproject.org/singularity/bioconductor-fishpond:2.8.0--r43hdfd78af_0' : + 'biocontainers/bioconductor-fishpond:2.8.0--r43hdfd78af_0' }" input: tuple val(meta), path(bindingsites) @@ -13,7 +13,7 @@ process COMPUTE_CORRELATIONS { tuple val(meta3), path(transcript_rds) output: - tuple val(meta), path("${meta.id}.circrna_correlation.tsv"), emit: correlation + //tuple val(meta), path("${meta.id}.circrna_correlation.tsv"), emit: correlation path "versions.yml" , emit: versions when: diff --git a/modules/local/compute_correlations/templates/compute_correlations.R b/modules/local/compute_correlations/templates/compute_correlations.R index add9a221..4640b0a0 100644 --- a/modules/local/compute_correlations/templates/compute_correlations.R +++ b/modules/local/compute_correlations/templates/compute_correlations.R @@ -1,130 +1,10 @@ #!/usr/bin/env Rscript -dataset <- read.table('${params.input}', sep = ",", header=T, stringsAsFactors = F, check.names = F) -samples <- dataset\$sample - -pairBindSites <- read.table('$bindingsites', header = F, sep = "\\t", stringsAsFactors = F, check.names = F) -pairBindSites <- as.data.frame.matrix(table(pairBindSites[,2], pairBindSites[,1])) - -if (!nrow(pairBindSites) > 1) { # check if there are samples that survived majority vote - stop("\\nMajority vote resulted in no bindingsites! Check majority.tsv and adjust the parameter 'mirn_vote' in your nextflow.config to a lower number.") -} - -miRNA_expression <- read.table('$filtered_mirnas', header = T, stringsAsFactors = F, check.names = F, sep = "\\t") - - -if(length(samples) < 5){ - stop("Cannot perform correlation on less than 5 samples") -} - -circRNA_expression <- read.table('$filtered_circrnas', header = T, stringsAsFactors = F, check.names = F, sep="\\t") - -circRNA_expression\$tx <- sub("^circ_", "", circRNA_expression\$tx) -rownames(circRNA_expression) <- circRNA_expression\$tx - - -# filter expression for miRNA binding pairs -valid_circRNAs <- intersect(circRNA_expression\$tx, rownames(pairBindSites)) -valid_miRNAs <- intersect(miRNA_expression\$miRNA, colnames(pairBindSites)) - -circRNA_expression <- circRNA_expression[valid_circRNAs,] -miRNA_expression <- miRNA_expression[miRNA_expression\$miRNA %in% valid_miRNAs,] - -# check for annotation -annotation <- "circBaseID" %in% colnames(circRNA_expression) #TODO Do we need this? - -header <- "circRNA\\tmiRNA\\tcircRNA_miRNA_ratio\\tmiRNA_binding_sites\\tpearson_R\\tcorr_pval\\tRSS_norm\\tintercept\\tintercept_pval\\tslope\\tslope_pval\\tadj_r_squared" -#write(header, file=paste0("filtered_circRNA_miRNA_correlation_libSizeEstNorm_directwritten.tsv"), append = F) - -miRNA_for_row <- function(miRNA_expr_line, circRNA, circRNA_counts){ - - mirna <- as.character(miRNA_expr_line[1]) - # get sample counts for current miRNA - miRNA_counts <- miRNA_expr_line[-1] - - miRNA_counts <- data.frame(sample = as.character(names(miRNA_counts)), "miRNA_counts" = as.numeric(unname(miRNA_counts))) - # compute circRNA expression vs. miRNA expression - joined_counts <- merge(miRNA_counts, circRNA_counts, by="sample") - - # analyse circRNA/miRNA ratio - mean_circRNA_counts <- mean(joined_counts\$circRNA_counts) - mean_miRNA_counts <- mean(joined_counts\$miRNA_counts) - circRNA_miRNA_ratio <- mean_circRNA_counts/mean_miRNA_counts - - binding_sites <- pairBindSites[circRNA, mirna] - - # compute circRNA-miRNA correlation for all samples - cor_res <- cor.test(joined_counts\$miRNA_counts, joined_counts\$circRNA_counts, method = "pearson", use = "complete.obs") - corr_R <- as.numeric(as.character(cor_res\$estimate)) - corr_pval <- as.numeric(as.character(cor_res\$p.value)) - - # compute linear regression - regression_model <- lm(miRNA_counts~circRNA_counts, data = joined_counts) - intercept <- summary(regression_model)\$coefficients[1,1] - intercept_pval <- summary(regression_model)\$coefficients[1,4] - slope <- summary(regression_model)\$coefficients[2,1] - slope_pval <- summary(regression_model)\$coefficients[2,4] - adj_r_squared <- summary(regression_model)\$adj.r.squared - - # compute residuals sum of squares - # normalize counts for residuals sum of squares - normalized_counts <- joined_counts[,c("circRNA_counts", "miRNA_counts")] - min_circRNA_counts <- min(normalized_counts\$circRNA_counts) - max_circRNA_counts <- max(normalized_counts\$circRNA_counts) - normalized_counts[,"circRNA_counts"] <- (normalized_counts[,"circRNA_counts"] - min_circRNA_counts)/(max_circRNA_counts - min_circRNA_counts) - min_miRNA_counts <- min(normalized_counts\$miRNA_counts) - max_miRNA_counts <- max(normalized_counts\$miRNA_counts) - normalized_counts[,"miRNA_counts"] <- (normalized_counts[,"miRNA_counts"] - min_miRNA_counts)/(max_miRNA_counts - min_miRNA_counts) - norm_reg_model <- lm(miRNA_counts~circRNA_counts, data = normalized_counts) - RSS_norm <- sum(norm_reg_model\$residuals^2) - - res <- data.frame(circRNA = as.character(circRNA), miRNA = as.character(mirna), - circRNA_miRNA_ratio = as.numeric(circRNA_miRNA_ratio), - miRNA_binding_sites = as.numeric(binding_sites), - pearson_R = as.numeric(corr_R), corr_pval = as.numeric(corr_pval), - RSS_norm = RSS_norm, intercept = intercept, - intercept_pval = intercept_pval, slope = slope, - slope_pval = slope_pval, adj_r_squared = adj_r_squared) - - return(res) -} - -circRNA_for_row <- function(circRNA_expr_line){ - # get coordinations of current circRNA - circRNA <- as.character(circRNA_expr_line[1]) - - # annotate if possible - if (annotation){ - an = circRNA_expression[circRNA,"circBaseID"] - if (an != "None") { - message("processing: ", circRNA, " (", an, ")") - circRNA = an - } - - } else { - message("processing: ", circRNA) - } - - # extract pure counts only - circRNA_counts <- circRNA_expr_line[samples] # passt - - # get sample counts for current circRNA - circRNA_counts <- data.frame(sample = as.character(names(circRNA_counts)), "circRNA_counts" = as.numeric(unname(circRNA_counts))) - - if (all(circRNA_counts\$circRNA_counts != 0)) { - res_list <- apply(miRNA_expression, 1, FUN = miRNA_for_row, circRNA, circRNA_counts) - res_df <- do.call(rbind, res_list) - return(res_df) - } - -} - -correlations_list <- apply(circRNA_expression, MARGIN = 1, circRNA_for_row) -correlations_df <- do.call(rbind, correlations_list) -correlations_df\$adj_pval <- p.adjust(correlations_df\$corr_pval, method = "BH") - -write.table(correlations_df, file=paste0("${meta.id}.circrna_correlation.tsv"), sep = "\\t", quote = F, row.names = F, col.names = T) +library(fishpond) +tx_expression <- readRDS('${transcript_rds}') +mi_expression <- read.table('${mirna_expression}', header=TRUE, row.names=1, sep='\\t') +interactions <- read.table('${bindingsites}', sep='\\t') ################################################ ################################################ diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index ff75a8fe..88aa08e8 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -47,11 +47,10 @@ workflow MIRNA_PREDICTION { ch_binding_site_batches = MIRNA_BINDINGSITES.out.binding_sites .splitText(by: 100, file: true) .map{ meta, file -> [[id: "batch_" + file.baseName.split("\\.").last()], file]} - .view() - // COMPUTE_CORRELATIONS( ch_binding_site_batches, - // ch_mirna_filtered, - // quantification_rds) + COMPUTE_CORRELATIONS( ch_binding_site_batches, + ch_mirna_filtered, + quantification_rds) //ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) From 4317c98a72089b9ff4e45f4c7f04c9b73861d068 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 15:55:50 +0200 Subject: [PATCH 433/491] Implement first draft of correlation analysis --- .../templates/compute_correlations.R | 27 +++++++++++++++++++ .../templates/merge_experiments.r | 5 +++- subworkflows/local/mirna_prediction.nf | 9 ++++++- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/modules/local/compute_correlations/templates/compute_correlations.R b/modules/local/compute_correlations/templates/compute_correlations.R index 4640b0a0..57837c40 100644 --- a/modules/local/compute_correlations/templates/compute_correlations.R +++ b/modules/local/compute_correlations/templates/compute_correlations.R @@ -1,11 +1,38 @@ #!/usr/bin/env Rscript library(fishpond) +suppressMessages(library(SummarizedExperiment)) tx_expression <- readRDS('${transcript_rds}') mi_expression <- read.table('${mirna_expression}', header=TRUE, row.names=1, sep='\\t') interactions <- read.table('${bindingsites}', sep='\\t') +# Iterate rows of interactions +for (i in 1:nrow(interactions)) { + # Get miRNA and target gene + miRNA <- interactions[i, 1] + targets <- unlist(strsplit(interactions[i, 2], ',')) + + # TODO: Remove this check after making sure that lowly expressed miRNAs + # are filtered out before binding site detection + if (!miRNA %in% rownames(mi_expression)) { + print(paste('miRNA', miRNA, 'not found')) + next + } + + mirna_expression <- mi_expression[miRNA,] + transcript_expression <- tx_expression[targets,] + + # Add miRNA expression to colData so that it can be used for correlation + colData(transcript_expression) <- cbind( + colData(transcript_expression), + t(mirna_expression[, rownames(colData(transcript_expression))]) + ) + + result <- rowData(swish(transcript_expression, miRNA, cor = "pearson")) + print(colnames(result)) +} + ################################################ ################################################ ## VERSIONS FILE ## diff --git a/modules/local/quantification/merge_experiments/templates/merge_experiments.r b/modules/local/quantification/merge_experiments/templates/merge_experiments.r index 12d1f6b5..4e82e57d 100644 --- a/modules/local/quantification/merge_experiments/templates/merge_experiments.r +++ b/modules/local/quantification/merge_experiments/templates/merge_experiments.r @@ -42,12 +42,15 @@ for (col in colnames(colData(se))) { } } +rownames(colData(se)) <- colData(se)\$names +colData(se)\$names <- NULL + # Add transcript annotation annotation <- annotation[match(rownames(se), annotation\$transcript_id),] rowData(se) <- annotation # Add TPM -assay(se, "tpm", withDimnames = FALSE) <- tpm[rownames(se), colData(se)\$names] +assay(se, "tpm", withDimnames = FALSE) <- tpm[rownames(se), rownames(colData(se))] saveRDS(se, '${meta.id}.merged.rds') diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index 88aa08e8..b176aacc 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -41,7 +41,14 @@ workflow MIRNA_PREDICTION { ch_versions = ch_versions.mix(MIRNA_FILTERING.out.versions) // - // COMPUTE CORREALTION: + // MIRNA BINDING SITES: + // + // TODO: Implement filtering of miRNAs from ch_mature if they are not present in ch_mirna_filtered + MIRNA_BINDINGSITES( transcriptome_fasta, circrna_bed12, ch_mature ) + ch_versions = ch_versions.mix(MIRNA_BINDINGSITES.out.versions) + + // + // COMPUTE CORRELATION: // ch_binding_site_batches = MIRNA_BINDINGSITES.out.binding_sites From 2bdabcc675aa9d2fc708edfae3056fbe3131f113 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 16:02:43 +0200 Subject: [PATCH 434/491] Save correlation results --- modules/local/compute_correlations/main.nf | 4 ++-- .../compute_correlations/templates/compute_correlations.R | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/modules/local/compute_correlations/main.nf b/modules/local/compute_correlations/main.nf index dd8d48b3..25172c7a 100644 --- a/modules/local/compute_correlations/main.nf +++ b/modules/local/compute_correlations/main.nf @@ -13,8 +13,8 @@ process COMPUTE_CORRELATIONS { tuple val(meta3), path(transcript_rds) output: - //tuple val(meta), path("${meta.id}.circrna_correlation.tsv"), emit: correlation - path "versions.yml" , emit: versions + tuple val(meta), path("*.tsv"), emit: correlations + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/compute_correlations/templates/compute_correlations.R b/modules/local/compute_correlations/templates/compute_correlations.R index 57837c40..b4f0d02a 100644 --- a/modules/local/compute_correlations/templates/compute_correlations.R +++ b/modules/local/compute_correlations/templates/compute_correlations.R @@ -7,6 +7,8 @@ tx_expression <- readRDS('${transcript_rds}') mi_expression <- read.table('${mirna_expression}', header=TRUE, row.names=1, sep='\\t') interactions <- read.table('${bindingsites}', sep='\\t') +result_cols <- c('stat', 'log2FC', 'pvalue', 'locfdr', 'qvalue') + # Iterate rows of interactions for (i in 1:nrow(interactions)) { # Get miRNA and target gene @@ -29,8 +31,9 @@ for (i in 1:nrow(interactions)) { t(mirna_expression[, rownames(colData(transcript_expression))]) ) - result <- rowData(swish(transcript_expression, miRNA, cor = "pearson")) - print(colnames(result)) + # TODO: Allow setting "spearman" + result <- rowData(swish(transcript_expression, miRNA, cor = "pearson"))[, result_cols] + write.table(result, paste0(miRNA, '.tsv')) } ################################################ From bb0a858066fde0747ee9ad1bdab568547a3c5fed Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 16:09:21 +0200 Subject: [PATCH 435/491] Switch correlation output to TSV --- .../compute_correlations/templates/compute_correlations.R | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/local/compute_correlations/templates/compute_correlations.R b/modules/local/compute_correlations/templates/compute_correlations.R index b4f0d02a..5f0d8db0 100644 --- a/modules/local/compute_correlations/templates/compute_correlations.R +++ b/modules/local/compute_correlations/templates/compute_correlations.R @@ -33,7 +33,9 @@ for (i in 1:nrow(interactions)) { # TODO: Allow setting "spearman" result <- rowData(swish(transcript_expression, miRNA, cor = "pearson"))[, result_cols] - write.table(result, paste0(miRNA, '.tsv')) + # TODO: Find out why NaN rows occur + result <- result[complete.cases(result), ] + write.table(result, paste0(miRNA, '.tsv'), sep = '\\t') } ################################################ From 8c2ae5560b348f644fc4597a51f46c7c32361b1f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sat, 1 Jun 2024 16:16:21 +0200 Subject: [PATCH 436/491] Handle correlation output channels --- subworkflows/local/mirna_prediction.nf | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index b176aacc..d8ffb157 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -58,8 +58,13 @@ workflow MIRNA_PREDICTION { COMPUTE_CORRELATIONS( ch_binding_site_batches, ch_mirna_filtered, quantification_rds) + + ch_correlation_results = COMPUTE_CORRELATIONS.out.correlations + .map{meta, results -> results} + .flatten().collect() + .map{results -> [[id: 'correlation'], results]} - //ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) + ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) emit: versions = ch_versions From 9e97abb9cc2956f5aad015dd5ffcee1a5ed9f8e7 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Fri, 7 Jun 2024 17:28:09 +0200 Subject: [PATCH 437/491] fixing MIRNA_TARGETS --- modules/local/mirna_targets/main.nf | 8 +-- .../local/mirna/mirna_bindingsites.nf | 56 ++++++++++++------- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/modules/local/mirna_targets/main.nf b/modules/local/mirna_targets/main.nf index 94b31eeb..e525a9f5 100644 --- a/modules/local/mirna_targets/main.nf +++ b/modules/local/mirna_targets/main.nf @@ -8,7 +8,7 @@ process MIRNA_TARGETS { 'biocontainers/bedtools:2.30.0--h7d7f7ad_2' }" input: - tuple val(meta), path(targetscan), path(miranda), path(bed12) + tuple val(meta), path(targetscan), path(miranda) output: tuple val(meta), path("${prefix}.mirna_targets.txt"), emit: results @@ -22,8 +22,8 @@ process MIRNA_TARGETS { prefix = task.ext.prefix ?: "${meta.id}" """ ## reformat and sort miRanda, TargetScan outputs, convert to BED for overlaps. - tail -n +2 $targetscan | sort -k1,1 -k4n | awk -v OFS="\\t" '{print \$1, \$2, \$4, \$5, \$9}' | awk -v OFS="\t" '{print \$2, \$3, \$4, \$1, "0", \$5}' > targetscan.bed - tail -n +2 $miranda | sort -k2,2 -k7n | awk -v OFS="\\t" '{print \$2, \$1, \$3, \$4, \$7, \$8}' | awk -v OFS="\t" '{print \$2, \$5, \$6, \$1, \$3, \$4}' | sed 's/^[^-]*-//g' > miranda.bed + tail -n +2 $targetscan | sort -k1,1 -k4n | awk -v OFS="\\t" '{print \$1, \$2, \$4, \$5, \$9}' | awk -v OFS="\\t" '{print \$2, \$3, \$4, \$1, "0", \$5}' > targetscan.bed + tail -n +2 $miranda | sort -k2,2 -k7n | awk -v OFS="\\t" '{print \$2, \$1, \$3, \$4, \$7, \$8}' | awk -v OFS="\\t" '{print \$2, \$5, \$6, \$1, \$3, \$4}' > miranda.bed ## intersect, consolidate miRanda, TargetScan information about miRs. ## -wa to output miRanda hits - targetscan makes it difficult to resolve duplicate miRNAs at MRE sites. @@ -32,7 +32,7 @@ process MIRNA_TARGETS { ## remove duplicate miRNA entries at MRE sites. ## strategy: sory by circs, sort by start position, sort by site type - the goal is to take the best site type (i.e rank site type found at MRE site). - paste ${prefix}.mirnas.tmp mirna_type | sort -k3,3 -k2n -k7r | awk -v OFS="\\t" '{print \$4,\$1,\$2,\$3,\$5,\$6,\$7}' | awk -F "\\t" '{if (!seen[\$1,\$2,\$3,\$4,\$5,\$6]++)print}' | sort -k1,1 -k3n > ${prefix}.mirna_targets.tmp + paste ${prefix}.mirnas.tmp mirna_type | sort -k3n -k2n -k7r | awk -v OFS="\\t" '{print \$4,\$1,\$2,\$3,\$5,\$6,\$7}' | awk -F "\\t" '{if (!seen[\$1,\$2,\$3,\$4,\$5,\$6]++)print}' | sort -k1,1 -k3n > ${prefix}.mirna_targets.tmp echo -e "circRNA\\tmiRNA\\tStart\\tEnd\\tScore\\tEnergy_KcalMol\\tSite_type" | cat - ${prefix}.mirna_targets.tmp > ${prefix}.mirna_targets.txt cat <<-END_VERSIONS > versions.yml diff --git a/subworkflows/local/mirna/mirna_bindingsites.nf b/subworkflows/local/mirna/mirna_bindingsites.nf index e46233f4..e0755b5e 100644 --- a/subworkflows/local/mirna/mirna_bindingsites.nf +++ b/subworkflows/local/mirna/mirna_bindingsites.nf @@ -7,7 +7,7 @@ include { MIRNA_TARGETS } from '../../../modules/local/mirna_t include { CAT_CAT as COMBINE_BINDINGSITES } from '../../../modules/nf-core/cat/cat' include { MAJORITY_VOTE } from '../../../modules/local/majority_vote' -workflow MIRNA_BINDINGSITES { +workflow MIRNA_BINDINGSITES { take: transcriptome_fasta circrna_bed12 @@ -20,7 +20,7 @@ workflow MIRNA_BINDINGSITES { // miRNAs can potentially bind to circRNAs right at the backsplice site // In this case, the miRNA binding sequence would partially overlap with start and end of the circRNA // To account for this, the first 25bp of the circRNA are added to the end of the circRNA sequence - ADD_BACKSPLICE( transcriptome_fasta) + ADD_BACKSPLICE( transcriptome_fasta ) ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) ch_transcriptome_batches = ADD_BACKSPLICE.out.output @@ -28,32 +28,46 @@ workflow MIRNA_BINDINGSITES { .map{ meta, file -> [[id: "batch_" + file.baseName.split("\\.").last()], file]} // - // TARGETSCAN WORKFLOW: + // MIRNA PREDICTION TOOLS: // - TARGETSCAN( ch_transcriptome_batches, formatMiRNAForTargetScan( mirna_fasta ).collect() ) - UNIFY_TARGETSCAN( TARGETSCAN.out.txt, [] ) - - ch_versions = ch_versions.mix(TARGETSCAN.out.versions) - ch_versions = ch_versions.mix(UNIFY_TARGETSCAN.out.versions) - ch_predictions = ch_predictions.mix(UNIFY_TARGETSCAN.out.output) - - // - // MIRANDA WORKFLOW: - // - - MIRANDA( ch_transcriptome_batches, mirna_fasta.map{meta, mature -> mature} ) - UNIFY_MIRANDA( MIRANDA.out.txt, [] ) - - ch_versions = ch_versions.mix(MIRANDA.out.versions) - ch_versions = ch_versions.mix(UNIFY_MIRANDA.out.versions) - ch_predictions = ch_predictions.mix(UNIFY_MIRANDA.out.output) + tools_selected = params.mirna_tools.split(',').collect{it.trim().toLowerCase()} + + if (tools_selected.size() == 0) { + error 'No tools selected for miRNA discovery.' + } + + if (tools_selected.contains('targetscan')) { + // + // TARGETSCAN WORKFLOW: + // + TARGETSCAN( ch_transcriptome_batches, formatMiRNAForTargetScan( mirna_fasta ).collect() ) + UNIFY_TARGETSCAN( TARGETSCAN.out.txt, [] ) + + ch_versions = ch_versions.mix(TARGETSCAN.out.versions) + ch_versions = ch_versions.mix(UNIFY_TARGETSCAN.out.versions) + ch_predictions = ch_predictions.mix(UNIFY_TARGETSCAN.out.output) + } + + if (tools_selected.contains('miranda')) { + // + // MIRANDA WORKFLOW: + // + MIRANDA( ch_transcriptome_batches, mirna_fasta.map{meta, mature -> mature} ) + UNIFY_MIRANDA( MIRANDA.out.txt, [] ) + + ch_versions = ch_versions.mix(MIRANDA.out.versions) + ch_versions = ch_versions.mix(UNIFY_MIRANDA.out.versions) + ch_predictions = ch_predictions.mix(UNIFY_MIRANDA.out.output) + } // // CONSOLIDATE PREDICTIONS WORKFLOW: // // TODO: This is an artifact and should be removed if we have a replacement - consolidate_targets = TARGETSCAN.out.txt.join(MIRANDA.out.txt).join(circrna_bed12) + // consolidate_targets = TARGETSCAN.out.txt.join(MIRANDA.out.txt).join(circrna_bed12) + consolidate_targets = TARGETSCAN.out.txt.join(MIRANDA.out.txt) + MIRNA_TARGETS( consolidate_targets ) ch_versions = ch_versions.mix(MIRNA_TARGETS.out.versions) From 2be8d5efd8db56fa0bc5491e7357819c6dd2bbbf Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Mon, 17 Jun 2024 16:37:24 +0200 Subject: [PATCH 438/491] Filtering mature based on filtered mirnas --- subworkflows/local/mirna_prediction.nf | 28 ++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index d8ffb157..1121bb26 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -8,7 +8,7 @@ include { MIRNA_BINDINGSITES } from './mirna/mirna_bindingsites' workflow MIRNA_PREDICTION { - take: + take: transcriptome_fasta circrna_bed12 ch_mature @@ -43,8 +43,24 @@ workflow MIRNA_PREDICTION { // // MIRNA BINDING SITES: // - // TODO: Implement filtering of miRNAs from ch_mature if they are not present in ch_mirna_filtered - MIRNA_BINDINGSITES( transcriptome_fasta, circrna_bed12, ch_mature ) + + // Filtering miRNAs from ch_mature if they are not in ch_mirna_filtered. + ch_uniq_mirnas = ch_mirna_filtered.map{ meta, path -> path }.splitCsv( sep: '\t' ).map{ it[0] }.unique().collect() + ch_mature_filtered = ch_mature + .map{ meta, path -> + path + } + .splitFasta( record: [id:true, seqString:true] ) + .combine(ch_uniq_mirnas.map{ it -> [it]}) // Not sure why this mapping is necessary but I think it is + .filter{ record, mirnas -> + ch_uniq_mirnas.contains(record.id) + }.map{ record, mirnas -> + ">${record.id}\n${record.seqString}" + } + .collectFile( name: 'mature_filtered.fa', newLine: true) + ch_mature_filtered = ch_mature_filtered.map{ it -> [[id: 'mature_filtered'], it]} + + MIRNA_BINDINGSITES( transcriptome_fasta, circrna_bed12, ch_mature_filtered ) ch_versions = ch_versions.mix(MIRNA_BINDINGSITES.out.versions) // @@ -55,9 +71,9 @@ workflow MIRNA_PREDICTION { .splitText(by: 100, file: true) .map{ meta, file -> [[id: "batch_" + file.baseName.split("\\.").last()], file]} - COMPUTE_CORRELATIONS( ch_binding_site_batches, - ch_mirna_filtered, - quantification_rds) + COMPUTE_CORRELATIONS( ch_binding_site_batches, + ch_mirna_filtered, + quantification_rds ) ch_correlation_results = COMPUTE_CORRELATIONS.out.correlations .map{meta, results -> results} From 0f6313d11ea939beddb6ec4709be3a27eb22a4a4 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Fri, 21 Jun 2024 23:12:27 +0200 Subject: [PATCH 439/491] Adding missing .collect() to MIRANDA process --- subworkflows/local/mirna/mirna_bindingsites.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subworkflows/local/mirna/mirna_bindingsites.nf b/subworkflows/local/mirna/mirna_bindingsites.nf index e0755b5e..7683524f 100644 --- a/subworkflows/local/mirna/mirna_bindingsites.nf +++ b/subworkflows/local/mirna/mirna_bindingsites.nf @@ -52,7 +52,7 @@ workflow MIRNA_BINDINGSITES { // // MIRANDA WORKFLOW: // - MIRANDA( ch_transcriptome_batches, mirna_fasta.map{meta, mature -> mature} ) + MIRANDA( ch_transcriptome_batches, mirna_fasta.map{meta, mature -> mature}.collect() ) UNIFY_MIRANDA( MIRANDA.out.txt, [] ) ch_versions = ch_versions.mix(MIRANDA.out.versions) From 3d8b9eff13ea544ea3450089e30dcbc315c33285 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Sat, 22 Jun 2024 20:39:22 +0200 Subject: [PATCH 440/491] fixing filtering of mature --- subworkflows/local/mirna_prediction.nf | 101 +++++++++++++------------ 1 file changed, 54 insertions(+), 47 deletions(-) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index 1121bb26..0ca665ac 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -29,58 +29,65 @@ workflow MIRNA_PREDICTION { // MIRNA NORMALIZATION WORKFLOW: // - ch_mirna_normalized = DESEQ2_NORMALIZATION( ch_mirna ).normalized + if (params.mirna_expression) { + + ch_mirna_normalized = DESEQ2_NORMALIZATION( ch_mirna ).normalized + + ch_versions = ch_versions.mix(DESEQ2_NORMALIZATION.out.versions) + + ch_mirna_filtered = MIRNA_FILTERING(ch_mirna_normalized, + params.mirna_min_sample_percentage, + params.mirna_min_reads + ).filtered + + ch_versions = ch_versions.mix(MIRNA_FILTERING.out.versions) + + // + // MIRNA BINDING SITES: + // + + // Filtering miRNAs from ch_mature if they are not in ch_mirna_filtered. + ch_uniq_mirnas = ch_mirna_filtered.map{ meta, path -> path }.splitCsv( sep: '\t' ).map{ it[0] }.unique().collect() + + ch_mature = ch_mature + .map{ meta, path -> + path + } + .splitFasta( record: [id:true, seqString:true] ) + .combine(ch_uniq_mirnas.map{ it -> [it]}) // Not sure why this mapping is necessary but I think it is + .filter{ record, mirnas -> + ch_uniq_mirnas.contains(record.id).value + }.map{ record, mirnas -> + ">${record.id}\n${record.seqString}" + } + .collectFile( name: 'mature_filtered.fa', newLine: true) + ch_mature = ch_mature.map{ it -> [[id: 'mature_filtered'], it]} + } - ch_versions = ch_versions.mix(DESEQ2_NORMALIZATION.out.versions) - ch_mirna_filtered = MIRNA_FILTERING(ch_mirna_normalized, - params.mirna_min_sample_percentage, - params.mirna_min_reads - ).filtered - - ch_versions = ch_versions.mix(MIRNA_FILTERING.out.versions) - - // - // MIRNA BINDING SITES: - // - - // Filtering miRNAs from ch_mature if they are not in ch_mirna_filtered. - ch_uniq_mirnas = ch_mirna_filtered.map{ meta, path -> path }.splitCsv( sep: '\t' ).map{ it[0] }.unique().collect() - ch_mature_filtered = ch_mature - .map{ meta, path -> - path - } - .splitFasta( record: [id:true, seqString:true] ) - .combine(ch_uniq_mirnas.map{ it -> [it]}) // Not sure why this mapping is necessary but I think it is - .filter{ record, mirnas -> - ch_uniq_mirnas.contains(record.id) - }.map{ record, mirnas -> - ">${record.id}\n${record.seqString}" - } - .collectFile( name: 'mature_filtered.fa', newLine: true) - ch_mature_filtered = ch_mature_filtered.map{ it -> [[id: 'mature_filtered'], it]} - - MIRNA_BINDINGSITES( transcriptome_fasta, circrna_bed12, ch_mature_filtered ) + MIRNA_BINDINGSITES( transcriptome_fasta, circrna_bed12, ch_mature ) ch_versions = ch_versions.mix(MIRNA_BINDINGSITES.out.versions) - // - // COMPUTE CORRELATION: - // - - ch_binding_site_batches = MIRNA_BINDINGSITES.out.binding_sites - .splitText(by: 100, file: true) - .map{ meta, file -> [[id: "batch_" + file.baseName.split("\\.").last()], file]} - - COMPUTE_CORRELATIONS( ch_binding_site_batches, - ch_mirna_filtered, - quantification_rds ) - - ch_correlation_results = COMPUTE_CORRELATIONS.out.correlations - .map{meta, results -> results} - .flatten().collect() - .map{results -> [[id: 'correlation'], results]} + if (params.mirna_expression) { + // + // COMPUTE CORRELATION: + // + ch_binding_site_batches = MIRNA_BINDINGSITES.out.binding_sites + .splitText(by: 100, file: true) + .map{ meta, file -> [[id: "batch_" + file.baseName.split("\\.").last()], file]} + + COMPUTE_CORRELATIONS( ch_binding_site_batches, + ch_mirna_filtered, + quantification_rds ) + + ch_correlation_results = COMPUTE_CORRELATIONS.out.correlations + .map{meta, results -> results} + .flatten().collect() + .map{results -> [[id: 'correlation'], results]} + + ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) + } - ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) emit: versions = ch_versions From d9619dc27ae942aede7a4114cfa692d129f7c4db Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Sat, 22 Jun 2024 20:39:54 +0200 Subject: [PATCH 441/491] Cleaning up --- nextflow.config | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nextflow.config b/nextflow.config index 3790a3bb..152873f7 100644 --- a/nextflow.config +++ b/nextflow.config @@ -65,12 +65,12 @@ params { //> Quantification bootstrap_samples = 30 - //> MIRNA processing + //> MIRNA processing mirna_expression = null - mirna_min_reads = 5 + mirna_min_reads = 1 mirna_min_sample_percentage = 0.2 - mirna_tools = 'miranda, targetscan' - mirna_vote = 1 + mirna_tools = 'miranda, targetscan' + mirna_vote = 1 //> MISC save_unaligned = false From d87def8a6eb099b548308576cbae47a66df4f01d Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Sat, 22 Jun 2024 21:12:21 +0200 Subject: [PATCH 442/491] Adding param to switch between spearman and pearson correlation --- .../templates/compute_correlations.R | 23 ++++++++++++------- nextflow.config | 2 ++ nextflow_schema.json | 12 ++++++++-- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/modules/local/compute_correlations/templates/compute_correlations.R b/modules/local/compute_correlations/templates/compute_correlations.R index 5f0d8db0..78c05e53 100644 --- a/modules/local/compute_correlations/templates/compute_correlations.R +++ b/modules/local/compute_correlations/templates/compute_correlations.R @@ -7,6 +7,13 @@ tx_expression <- readRDS('${transcript_rds}') mi_expression <- read.table('${mirna_expression}', header=TRUE, row.names=1, sep='\\t') interactions <- read.table('${bindingsites}', sep='\\t') +tx_expression <- scaleInfReps(tx_expression) +tx_expression <- labelKeep(tx_expression) # Here one can perform custom filtering + +if (!any(mcols(tx_expression)\$keep)) { + stop('No transcripts left after filtering') +} + result_cols <- c('stat', 'log2FC', 'pvalue', 'locfdr', 'qvalue') # Iterate rows of interactions @@ -15,16 +22,14 @@ for (i in 1:nrow(interactions)) { miRNA <- interactions[i, 1] targets <- unlist(strsplit(interactions[i, 2], ',')) - # TODO: Remove this check after making sure that lowly expressed miRNAs - # are filtered out before binding site detection - if (!miRNA %in% rownames(mi_expression)) { - print(paste('miRNA', miRNA, 'not found')) - next - } - mirna_expression <- mi_expression[miRNA,] transcript_expression <- tx_expression[targets,] + if (!any(mcols(transcript_expression)\$keep)) { + print(paste('No transcripts left after filtering for miRNA', miRNA)) + next + } + # Add miRNA expression to colData so that it can be used for correlation colData(transcript_expression) <- cbind( colData(transcript_expression), @@ -32,8 +37,10 @@ for (i in 1:nrow(interactions)) { ) # TODO: Allow setting "spearman" - result <- rowData(swish(transcript_expression, miRNA, cor = "pearson"))[, result_cols] + result <- rowData(swish(transcript_expression, miRNA, cor = "${params.mirna_correlation}"))[, result_cols] # TODO: Find out why NaN rows occur + # NaNs occur whenever mcols(transcript_expression)\$keep is false + # Because in this case the corresponding entry is ignored result <- result[complete.cases(result), ] write.table(result, paste0(miRNA, '.tsv'), sep = '\\t') } diff --git a/nextflow.config b/nextflow.config index 152873f7..d4062a9e 100644 --- a/nextflow.config +++ b/nextflow.config @@ -71,6 +71,8 @@ params { mirna_min_sample_percentage = 0.2 mirna_tools = 'miranda, targetscan' mirna_vote = 1 + mirna_correlation = 'pearson' + //> MISC save_unaligned = false diff --git a/nextflow_schema.json b/nextflow_schema.json index e266c70a..10d9ca4e 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -66,8 +66,8 @@ "format": "file-path", "exists": true, "mimetype": "text/tsv", - "pattern": "^\\S+\\.tsv$", - "description": "Path to tab-separated file providing the expression counts of miRNAs, which are created in pipeline 'smrnaseq'. \n\nmirna \t sample1 \t sample2 \t sample3 \t\nid1\t count_sample1 \t count_sample2 \t count_sample3 \t\nid2 \t ... \t ... \t ... \t \n", + "pattern": "^\\s+\\.tsv$", + "description": "path to tab-separated file providing the expression counts of mirnas, which are created in pipeline 'smrnaseq'. \n\nmirna \t sample1 \t sample2 \t sample3 \t\nid1\t count_sample1 \t count_sample2 \t count_sample3 \t\nid2 \t ... \t ... \t ... \t \n", "fa_icon": "fas fa-file-tsv" }, "mirna_min_sample_percentage": { @@ -85,6 +85,14 @@ "help_text": "This parameter determines the minimum number of reads that a miRNA must have to pass filtering. The default is 5, meaning a miRNA must have at least 5 reads across the samples to be considered for analysis.", "default": 5, "minimum": 0 + }, + "mirna_correlation": { + "type": "string", + "fa_icon": "fas fa-wrench", + "description": "Specifies the type of correlation to be used when analyzing the relationship between miRNA and transcript expression levels. Valid options are 'pearson' or 'spearman'.", + "help_text": "Select the correlation method to be applied in the correlation analysis of miRNAs.", + "default": "pearson", + "pattern": "^(pearson|spearman)$" } } }, From bd5345ecefb27a26e9099575b1edfbc03a1e7175 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Sun, 23 Jun 2024 18:22:42 +0200 Subject: [PATCH 443/491] More resources for MAJORITY_VOTE --- modules/local/majority_vote/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/majority_vote/main.nf b/modules/local/majority_vote/main.nf index 8ed51f0a..7b58a67f 100644 --- a/modules/local/majority_vote/main.nf +++ b/modules/local/majority_vote/main.nf @@ -1,6 +1,6 @@ process MAJORITY_VOTE { tag "$meta.id" - label 'process_single' + label 'process_medium' conda "bioconda::pandas=1.5.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? From fbc094a40ac69839c7396caae8ba2d34f5bb8ecd Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Sun, 23 Jun 2024 18:23:12 +0200 Subject: [PATCH 444/491] removing todo comment --- .../local/compute_correlations/templates/compute_correlations.R | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/local/compute_correlations/templates/compute_correlations.R b/modules/local/compute_correlations/templates/compute_correlations.R index 78c05e53..c3cb8ec6 100644 --- a/modules/local/compute_correlations/templates/compute_correlations.R +++ b/modules/local/compute_correlations/templates/compute_correlations.R @@ -36,7 +36,6 @@ for (i in 1:nrow(interactions)) { t(mirna_expression[, rownames(colData(transcript_expression))]) ) - # TODO: Allow setting "spearman" result <- rowData(swish(transcript_expression, miRNA, cor = "${params.mirna_correlation}"))[, result_cols] # TODO: Find out why NaN rows occur # NaNs occur whenever mcols(transcript_expression)\$keep is false From b5adea20851c3dffc190a136729ee65ec5cd5203 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Tue, 25 Jun 2024 22:44:00 +0200 Subject: [PATCH 445/491] removing TODO comment --- .../compute_correlations/templates/compute_correlations.R | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/local/compute_correlations/templates/compute_correlations.R b/modules/local/compute_correlations/templates/compute_correlations.R index c3cb8ec6..e60ccc73 100644 --- a/modules/local/compute_correlations/templates/compute_correlations.R +++ b/modules/local/compute_correlations/templates/compute_correlations.R @@ -37,9 +37,6 @@ for (i in 1:nrow(interactions)) { ) result <- rowData(swish(transcript_expression, miRNA, cor = "${params.mirna_correlation}"))[, result_cols] - # TODO: Find out why NaN rows occur - # NaNs occur whenever mcols(transcript_expression)\$keep is false - # Because in this case the corresponding entry is ignored result <- result[complete.cases(result), ] write.table(result, paste0(miRNA, '.tsv'), sep = '\\t') } From ff1edcfffc1762c3ecc5d2f45e5fa8c0a5a29a4f Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Tue, 25 Jun 2024 22:44:37 +0200 Subject: [PATCH 446/491] correlations output set to optional --- modules/local/compute_correlations/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/compute_correlations/main.nf b/modules/local/compute_correlations/main.nf index 25172c7a..773fddae 100644 --- a/modules/local/compute_correlations/main.nf +++ b/modules/local/compute_correlations/main.nf @@ -13,7 +13,7 @@ process COMPUTE_CORRELATIONS { tuple val(meta3), path(transcript_rds) output: - tuple val(meta), path("*.tsv"), emit: correlations + tuple val(meta), path("*.tsv"), emit: correlations, optional: true path "versions.yml" , emit: versions when: From 1e8b04f9f9bf44be8fc7ad4502063b994d92b567 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sun, 4 Aug 2024 22:43:46 +0200 Subject: [PATCH 447/491] Fix major rebase problems --- main.nf | 4 +--- subworkflows/local/mirna_prediction.nf | 10 ++++------ workflows/circrna/main.nf | 10 +++++----- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/main.nf b/main.nf index 94437354..b5a47b01 100644 --- a/main.nf +++ b/main.nf @@ -57,9 +57,8 @@ workflow NFCORE_CIRCRNA { ch_samplesheet = Channel.fromSamplesheet("input") ch_fasta = Channel.value([[id: "fasta"], file(params.fasta, checkIfExists:true)]) ch_gtf = Channel.value([[id: "gtf"], file(params.gtf, checkIfExists:true)]) - ch_mature = params.module.split(',').contains('mirna_prediction') ? Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) : Channel.empty() + ch_mature = params.mature ? Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) : Channel.empty() ch_phenotype = params.phenotype ? Channel.value([[id: "phenotype"], file(params.phenotype, checkIfExists:true)]) : Channel.empty() - ch_species = params.phenotype ? Channel.value(params.species_id) : Channel.empty() ch_annotation = params.annotation ? Channel.fromSamplesheet("annotation") : Channel.empty() ch_mirna = params.mature ? Channel.value([[id: "mirna"], file(params.mirna_expression, checkIfExists:true)]) : Channel.empty() @@ -70,7 +69,6 @@ workflow NFCORE_CIRCRNA { ch_gtf, ch_mature, ch_annotation, - ch_species, ch_versions, ch_mirna ) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index 0ca665ac..9f8425d1 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -1,4 +1,5 @@ // MODULES +include { BIOAWK as ADD_BACKSPLICE } from '../../modules/nf-core/bioawk' include { DESEQ2_NORMALIZATION } from '../../modules/local/deseq2/normalization' include { MIRNA_FILTERING } from '../../modules/local/mirna_filtering' include { COMPUTE_CORRELATIONS } from '../../modules/local/compute_correlations' @@ -10,7 +11,7 @@ workflow MIRNA_PREDICTION { take: transcriptome_fasta - circrna_bed12 + circrna_annotation ch_mature ch_mirna transcript_counts @@ -19,10 +20,7 @@ workflow MIRNA_PREDICTION { main: ch_versions = Channel.empty() - MIRNA_BINDINGSITES( transcriptome_fasta, circrna_bed12, ch_mature ) - ch_versions = ch_versions.mix(MIRNA_BINDINGSITES.out.versions) - - ADD_BACKSPLICE( circrna_fasta, [] ) + ADD_BACKSPLICE( transcriptome_fasta, [] ) ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) // @@ -65,7 +63,7 @@ workflow MIRNA_PREDICTION { } - MIRNA_BINDINGSITES( transcriptome_fasta, circrna_bed12, ch_mature ) + MIRNA_BINDINGSITES( transcriptome_fasta, circrna_annotation, ch_mature ) ch_versions = ch_versions.mix(MIRNA_BINDINGSITES.out.versions) if (params.mirna_expression) { diff --git a/workflows/circrna/main.nf b/workflows/circrna/main.nf index cf2abf1e..048b4da3 100644 --- a/workflows/circrna/main.nf +++ b/workflows/circrna/main.nf @@ -177,11 +177,11 @@ workflow CIRCRNA { if (params.mature) { MIRNA_PREDICTION( - BSJ_DETECTION.out.fasta, - BSJ_DETECTION.out.bed, - ch_mature - ch_mirna - QUANTIFICATION.out.circular_tx_counts + QUANTIFICATION.out.transcriptome, + BSJ_DETECTION.out.bed12, + ch_mature, + ch_mirna, + QUANTIFICATION.out.circular_tx_counts, QUANTIFICATION.out.rds ) ch_versions = ch_versions.mix(MIRNA_PREDICTION.out.versions) From cdb265ef5b5dc67890f054a820a3a307f2e387f8 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sun, 4 Aug 2024 22:57:19 +0200 Subject: [PATCH 448/491] Fix small bug with backsplice junction adding --- subworkflows/local/mirna_prediction.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index 9f8425d1..be598045 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -20,7 +20,7 @@ workflow MIRNA_PREDICTION { main: ch_versions = Channel.empty() - ADD_BACKSPLICE( transcriptome_fasta, [] ) + ADD_BACKSPLICE( transcriptome_fasta ) ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) // From abac8e292a2e6ef2c2b13982e0c9cc3ddfe8c059 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sun, 4 Aug 2024 23:17:57 +0200 Subject: [PATCH 449/491] Improve mirna prediction formatting --- subworkflows/local/mirna_prediction.nf | 28 +++++++++++--------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index be598045..117701c8 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -20,9 +20,6 @@ workflow MIRNA_PREDICTION { main: ch_versions = Channel.empty() - ADD_BACKSPLICE( transcriptome_fasta ) - ch_versions = ch_versions.mix(ADD_BACKSPLICE.out.versions) - // // MIRNA NORMALIZATION WORKFLOW: // @@ -48,21 +45,20 @@ workflow MIRNA_PREDICTION { ch_uniq_mirnas = ch_mirna_filtered.map{ meta, path -> path }.splitCsv( sep: '\t' ).map{ it[0] }.unique().collect() ch_mature = ch_mature - .map{ meta, path -> - path - } - .splitFasta( record: [id:true, seqString:true] ) - .combine(ch_uniq_mirnas.map{ it -> [it]}) // Not sure why this mapping is necessary but I think it is - .filter{ record, mirnas -> - ch_uniq_mirnas.contains(record.id).value - }.map{ record, mirnas -> - ">${record.id}\n${record.seqString}" - } - .collectFile( name: 'mature_filtered.fa', newLine: true) - ch_mature = ch_mature.map{ it -> [[id: 'mature_filtered'], it]} + .map{ meta, path -> + path + } + .splitFasta( record: [id:true, seqString:true] ) + .combine(ch_uniq_mirnas.map{ it -> [it]}) // Not sure why this mapping is necessary but I think it is + .filter{ record, mirnas -> + ch_uniq_mirnas.contains(record.id).value + }.map{ record, mirnas -> + ">${record.id}\n${record.seqString}" + } + .collectFile( name: 'mature_filtered.fa', newLine: true) + .map{ it -> [[id: 'mature_filtered'], it]} } - MIRNA_BINDINGSITES( transcriptome_fasta, circrna_annotation, ch_mature ) ch_versions = ch_versions.mix(MIRNA_BINDINGSITES.out.versions) From f3a6233cb93b33da62e39076b90276e89451d9b1 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Sun, 4 Aug 2024 23:58:38 +0200 Subject: [PATCH 450/491] Improve output structure for mirna prediction --- conf/modules.config | 56 ++++++++++++++++++++++++-- subworkflows/local/mirna_prediction.nf | 1 - 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 61492e6a..9f09196f 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -816,11 +816,21 @@ process { withName: UNIFY_MIRANDA { ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$1, \$2, \$7, \$8, \"miranda\" }'" ext.suffix = "miranda.tsv" + publishDir = [ + path: { "${params.outdir}/mirna_prediction/binding_sites/tools/miranda/unified" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + ] } withName: UNIFY_TARGETSCAN { ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$2, \$1, \$6, \$7, \"targetscan\" }'" ext.suffix = "targetscan.tsv" + publishDir = [ + path: { "${params.outdir}/mirna_prediction/binding_sites/tools/targetscan/unified" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + ] } withName: COMBINE_BINDINGSITES { @@ -940,6 +950,22 @@ process { ] } + withName: '.*:MIRNA_PREDICTION:DESEQ2_NORMALIZATION' { + publishDir = [ + path: { "${params.outdir}/mirna_prediction/mirna_expression" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + ] + } + + withName: '.*:MIRNA_PREDICTION:MIRNA_FILTERING' { + publishDir = [ + path: { "${params.outdir}/mirna_prediction/mirna_expression" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + ] + } + withName: TARGETSCAN_DATABASE { publishDir = [ path: { "${params.outdir}/references/mirna_prediction/targetscan" }, @@ -952,7 +978,7 @@ process { withName: TARGETSCAN { ext.prefix = { "${meta.id}.targetscan" } publishDir = [ - path: { "${params.outdir}/mirna_prediction/targetscan" }, + path: { "${params.outdir}/mirna_prediction/binding_sites/tools/targetscan/output" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.txt" @@ -963,7 +989,7 @@ process { ext.prefix = { "${meta.id}.miranda" } ext.args = "-strict" publishDir = [ - path: { "${params.outdir}/mirna_prediction/miranda" }, + path: { "${params.outdir}/mirna_prediction/binding_sites/tools/miranda/output" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.txt" @@ -972,13 +998,37 @@ process { withName: MIRNA_TARGETS { publishDir = [ - path: { "${params.outdir}/mirna_prediction/combined" }, + path: { "${params.outdir}/mirna_prediction/binding_sites/targets" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, pattern: "*.txt" ] } + withName: COMBINE_BINDINGSITES { + publishDir = [ + path: { "${params.outdir}/mirna_prediction/binding_sites/majority_vote" }, + mode: params.publish_dir_mode, + saveAs: { filename -> ( filename != 'versions.yml' && params.save_intermediates ) ? filename : null } + ] + } + + withName: MAJORITY_VOTE { + publishDir = [ + path: { "${params.outdir}/mirna_prediction/binding_sites/majority_vote" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + ] + } + + withName: '.*:MIRNA_PREDICTION:COMPUTE_CORRELATIONS' { + publishDir = [ + path: { "${params.outdir}/mirna_prediction/correlation" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + ] + } + withName: CIRCTEST_PREPARE { publishDir = [ path: { "${params.outdir}/statistical_tests/circtest" }, diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index 117701c8..48c64fbe 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -82,7 +82,6 @@ workflow MIRNA_PREDICTION { ch_versions = ch_versions.mix(COMPUTE_CORRELATIONS.out.versions) } - emit: versions = ch_versions } From 2b28c808ab864165cd6d0b93e48bdfb18b0b850d Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Tue, 6 Aug 2024 16:41:36 +0200 Subject: [PATCH 451/491] fixing formatting in modules --- modules.json | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/modules.json b/modules.json index b0cd0057..35714771 100644 --- a/modules.json +++ b/modules.json @@ -15,7 +15,9 @@ "bedtools/groupby": { "branch": "master", "git_sha": "3b248b84694d1939ac4bb33df84bf6233a34d668", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "bedtools/intersect": { "branch": "master", @@ -126,7 +128,9 @@ "custom/gtffilter": { "branch": "master", "git_sha": "a0aee18374b7f072aa0f89f4d66f5a3a9f8176d2", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "custom/tx2gene": { "branch": "master", @@ -335,4 +339,4 @@ } } } -} +} \ No newline at end of file From 86c7958a30da3ac08b09bb0d330230c124935bc9 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Tue, 6 Aug 2024 16:41:54 +0200 Subject: [PATCH 452/491] adjusting mirna_min_reads to match nextflow_schema --- nextflow.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index d4062a9e..21270121 100644 --- a/nextflow.config +++ b/nextflow.config @@ -67,7 +67,7 @@ params { //> MIRNA processing mirna_expression = null - mirna_min_reads = 1 + mirna_min_reads = 5 mirna_min_sample_percentage = 0.2 mirna_tools = 'miranda, targetscan' mirna_vote = 1 From 3ddfe3e56c1e3924111bc5a8330714679ca89080 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Tue, 6 Aug 2024 16:45:00 +0200 Subject: [PATCH 453/491] fixing formatting and adding missing allOf field for mirna_processing_options --- nextflow_schema.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index 10d9ca4e..21f3dfb1 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -151,7 +151,7 @@ "mirna_vote": { "type": "integer", "fa_icon": "fas fa-intersection", - "description": "Specify the number of votes required for a miRNA to be further considered in downstream analysis.'", + "description": "Specify the number of votes required for a miRNA to be further considered in downstream analysis.'", "help_text": "Controls the number of votes required for a binding site prediction to be considered valid. If a miRNA binding site was predicted by two different tools (e.g., miRanda and TargetScan), it receives two votes. By specifying additional tools for miRNA binding site prediction (using the 'mirna_tools' parameter), you can adjust the number of votes required for a binding site to be considered valid.", "default": 1, "minimum": 1, @@ -614,6 +614,9 @@ { "$ref": "#/definitions/discovery_options" }, + { + "$ref": "#/definitions/mirna_processing_options" + }, { "$ref": "#/definitions/institutional_config_options" }, From 45dd40741c855e53259ef4397d85feb7673c2242 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Tue, 6 Aug 2024 17:03:55 +0200 Subject: [PATCH 454/491] removing non used configs in modules.config --- conf/modules.config | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 9f09196f..4f6fea71 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -804,15 +804,6 @@ process { ] } - withName: COUNTS_COMBINED { - ext.when = { params.module.split(',').contains('circrna_discovery') } - } - - withName: COUNTS_TO_BED { - ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$1, \$2, \$3, \$1 \":\" \$2 \"-\" \$3, \".\", \".\" }'" - ext.suffix = "bed" - } - withName: UNIFY_MIRANDA { ext.args = "-v FS='\\t' -v OFS='\\t' 'NR>1 { print \$1, \$2, \$7, \$8, \"miranda\" }'" ext.suffix = "miranda.tsv" @@ -837,11 +828,6 @@ process { ext.prefix = "bindingsites.tsv" } - withName: UNIQUE_REGIONS { - ext.args = "-k 1,1 -k2,2n -k3,3n -u" - ext.suffix = "unique.bed" - } - withName: COMBINE_TRANSCRIPTOME_GTFS { ext.args = "-k 1,1 -k4,4n -k5,5n" ext.suffix = "combined.gtf" From 4cbb345872ab8777f5b26f351f6982a201b680ed Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Tue, 6 Aug 2024 17:16:28 +0200 Subject: [PATCH 455/491] updating nf-core modules --- modules.json | 56 +- modules/nf-core/bioawk/main.nf | 11 +- modules/nf-core/bowtie/align/environment.yml | 1 + modules/nf-core/bowtie/align/main.nf | 35 +- modules/nf-core/bowtie/align/meta.yml | 21 +- .../nf-core/bowtie/align/tests/main.nf.test | 129 + .../bowtie/align/tests/main.nf.test.snap | 192 ++ modules/nf-core/bowtie/align/tests/tags.yml | 2 + modules/nf-core/bowtie/build/main.nf | 32 +- modules/nf-core/bowtie/build/meta.yml | 12 +- .../nf-core/bowtie/build/tests/main.nf.test | 57 + .../bowtie/build/tests/main.nf.test.snap | 96 + modules/nf-core/bowtie/build/tests/tags.yml | 2 + .../nf-core/bowtie2/align/tests/main.nf.test | 90 +- modules/nf-core/cat/cat/main.nf | 1 - modules/nf-core/cat/cat/tests/main.nf.test | 27 +- .../nf-core/cat/cat/tests/main.nf.test.snap | 74 +- modules/nf-core/cat/fastq/main.nf | 10 +- modules/nf-core/cat/fastq/tests/main.nf.test | 136 +- .../nf-core/cat/fastq/tests/main.nf.test.snap | 207 ++ .../templates/dumpsoftwareversions.py | 1 - .../custom/tx2gene/templates/tx2gene.py | 24 +- .../nf-core/custom/tx2gene/tests/main.nf.test | 45 +- .../custom/tx2gene/tests/main.nf.test.snap | 96 +- modules/nf-core/fastqc/tests/main.nf.test | 225 +- .../nf-core/fastqc/tests/main.nf.test.snap | 370 ++- modules/nf-core/hisat2/align/main.nf | 19 + .../nf-core/hisat2/align/tests/main.nf.test | 202 ++ .../hisat2/align/tests/main.nf.test.snap | 338 ++- modules/nf-core/hisat2/build/main.nf | 11 + .../nf-core/hisat2/build/tests/main.nf.test | 47 +- .../hisat2/build/tests/main.nf.test.snap | 66 +- .../nf-core/hisat2/extractsplicesites/main.nf | 11 + .../extractsplicesites/tests/main.nf.test | 26 + .../tests/main.nf.test.snap | 37 + modules/nf-core/multiqc/environment.yml | 2 +- modules/nf-core/multiqc/main.nf | 10 +- modules/nf-core/multiqc/meta.yml | 13 + modules/nf-core/multiqc/tests/main.nf.test | 6 + .../nf-core/multiqc/tests/main.nf.test.snap | 18 +- .../samtools/flagstat/tests/main.nf.test | 28 +- .../samtools/flagstat/tests/main.nf.test.snap | 78 +- .../samtools/idxstats/tests/main.nf.test | 29 +- .../samtools/idxstats/tests/main.nf.test.snap | 78 +- modules/nf-core/samtools/index/main.nf | 7 +- .../nf-core/samtools/index/tests/main.nf.test | 87 +- .../samtools/index/tests/main.nf.test.snap | 264 +- modules/nf-core/samtools/sort/main.nf | 14 +- .../nf-core/samtools/sort/tests/main.nf.test | 54 +- .../samtools/sort/tests/main.nf.test.snap | 202 +- .../samtools/sort/tests/nextflow_cram.config | 8 + .../nf-core/samtools/stats/tests/main.nf.test | 57 +- .../samtools/stats/tests/main.nf.test.snap | 82 +- modules/nf-core/samtools/view/main.nf | 40 +- modules/nf-core/samtools/view/meta.yml | 9 + .../nf-core/samtools/view/tests/main.nf.test | 2 + .../samtools/view/tests/main.nf.test.snap | 22 +- modules/nf-core/star/align/main.nf | 4 +- modules/nf-core/star/align/tests/main.nf.test | 523 +++- .../star/align/tests/main.nf.test.snap | 2288 +++++++++++++---- .../star/genomegenerate/tests/main.nf.test | 39 +- .../genomegenerate/tests/main.nf.test.snap | 182 +- .../stringtie/stringtie/tests/main.nf.test | 139 +- .../stringtie/tests/main.nf.test.snap | 504 +++- modules/nf-core/trimgalore/main.nf | 21 + modules/nf-core/trimgalore/tests/main.nf.test | 47 + .../trimgalore/tests/main.nf.test.snap | 154 ++ 67 files changed, 6315 insertions(+), 1405 deletions(-) create mode 100644 modules/nf-core/bowtie/align/tests/main.nf.test create mode 100644 modules/nf-core/bowtie/align/tests/main.nf.test.snap create mode 100644 modules/nf-core/bowtie/align/tests/tags.yml create mode 100644 modules/nf-core/bowtie/build/tests/main.nf.test create mode 100644 modules/nf-core/bowtie/build/tests/main.nf.test.snap create mode 100644 modules/nf-core/bowtie/build/tests/tags.yml create mode 100644 modules/nf-core/samtools/sort/tests/nextflow_cram.config diff --git a/modules.json b/modules.json index 35714771..6b2ae568 100644 --- a/modules.json +++ b/modules.json @@ -35,7 +35,7 @@ }, "bioawk": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "dee3479f3b4a828df6052d318403d2b6a87b2d2e", "installed_by": [ "modules" ], @@ -43,21 +43,21 @@ }, "bowtie/align": { "branch": "master", - "git_sha": "3c77ca9aac783e76c3614a06db3bfe4fef619bde", + "git_sha": "54381508775905f1ecd4fc0dea3fc2f07c78d1c6", "installed_by": [ "modules" ] }, "bowtie/build": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "54381508775905f1ecd4fc0dea3fc2f07c78d1c6", "installed_by": [ "modules" ] }, "bowtie2/align": { "branch": "master", - "git_sha": "e4bad511789f16d0df39ee306b2cd50418365048", + "git_sha": "9bfc81874554e87740bcb3e5e07acf0a153c9ecb", "installed_by": [ "modules" ] @@ -71,21 +71,21 @@ }, "bwa/index": { "branch": "master", - "git_sha": "086fa66260595e123b0ea47a6512539b72a9afa3", + "git_sha": "e0ff65e1fb313677de09f5f477ae3da30ce19b7b", "installed_by": [ "modules" ] }, "cat/cat": { "branch": "master", - "git_sha": "9437e6053dccf4aafa022bfd6e7e9de67e625af8", + "git_sha": "5bb8ca085e17549e185e1823495ab8d20727a805", "installed_by": [ "modules" ] }, "cat/fastq": { "branch": "master", - "git_sha": "4fc983ad0b30e6e32696fa7d980c76c7bfe1c03e", + "git_sha": "1ceaa8ba4d0fd886dbca0e545815d905b7407de7", "installed_by": [ "modules" ] @@ -120,7 +120,7 @@ }, "custom/dumpsoftwareversions": { "branch": "master", - "git_sha": "de45447d060b8c8b98575bc637a4a575fd0638e1", + "git_sha": "82024cf6325d2ee194e7f056d841ecad2f6856e9", "installed_by": [ "modules" ] @@ -134,14 +134,14 @@ }, "custom/tx2gene": { "branch": "master", - "git_sha": "ec155021a9104441bf6a9bae3b55d1b5b0bfdb3a", + "git_sha": "4e5f4687318f24ba944a13609d3ea6ebd890737d", "installed_by": [ "modules" ] }, "fastqc": { "branch": "master", - "git_sha": "285a50500f9e02578d90b3ce6382ea3c30216acd", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "modules" ] @@ -155,28 +155,28 @@ }, "gnu/sort": { "branch": "master", - "git_sha": "ca199cfe5aa4f1ea3c41302158f0af2cfaa58957", + "git_sha": "a3cc42943548378b726610f45bb5a79ab3f0b633", "installed_by": [ "modules" ] }, "hisat2/align": { "branch": "master", - "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", + "git_sha": "2c6b1144ed58b6184ad58fc4e6b6a90219b4bf4f", "installed_by": [ "modules" ] }, "hisat2/build": { "branch": "master", - "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", + "git_sha": "2c6b1144ed58b6184ad58fc4e6b6a90219b4bf4f", "installed_by": [ "modules" ] }, "hisat2/extractsplicesites": { "branch": "master", - "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", + "git_sha": "2c6b1144ed58b6184ad58fc4e6b6a90219b4bf4f", "installed_by": [ "modules" ] @@ -190,35 +190,35 @@ }, "multiqc": { "branch": "master", - "git_sha": "b7ebe95761cd389603f9cc0e0dc384c0f663815a", + "git_sha": "b80f5fd12ff7c43938f424dd76392a2704fa2396", "installed_by": [ "modules" ] }, "samtools/faidx": { "branch": "master", - "git_sha": "f153f1f10e1083c49935565844cccb7453021682", + "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", "installed_by": [ "modules" ] }, "samtools/flagstat": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "bam_stats_samtools" ] }, "samtools/idxstats": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "bam_stats_samtools" ] }, "samtools/index": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "bam_sort_stats_samtools", "modules" @@ -226,7 +226,7 @@ }, "samtools/sort": { "branch": "master", - "git_sha": "4352dbdb09ec40db71e9b172b97a01dcf5622c26", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "bam_sort_stats_samtools", "modules" @@ -234,14 +234,14 @@ }, "samtools/stats": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "bam_stats_samtools" ] }, "samtools/view": { "branch": "master", - "git_sha": "0bd7d2333a88483aa0476acea172e9f5f6dd83bb", + "git_sha": "6c2309aaec566c0d44a6cf14d4b2d0c51afe2e91", "installed_by": [ "modules" ] @@ -262,28 +262,28 @@ }, "star/align": { "branch": "master", - "git_sha": "a21faa6a3481af92a343a10926f59c189a2c16c9", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "modules" ] }, "star/genomegenerate": { "branch": "master", - "git_sha": "a21faa6a3481af92a343a10926f59c189a2c16c9", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "modules" ] }, "stringtie/stringtie": { "branch": "master", - "git_sha": "b1b959609bda44341120aed1766329909f54b8d0", + "git_sha": "c789476080a150f87066ca3ed42a622339a26c0b", "installed_by": [ "modules" ] }, "trimgalore": { "branch": "master", - "git_sha": "a98418419ae6c9df3cf6cf108d1e1aba71037d5a", + "git_sha": "b4919e9a2b4d8b71061e601633db4600a3858fa1", "installed_by": [ "modules" ] @@ -301,14 +301,14 @@ "nf-core": { "bam_sort_stats_samtools": { "branch": "master", - "git_sha": "4352dbdb09ec40db71e9b172b97a01dcf5622c26", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "subworkflows" ] }, "bam_stats_samtools": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "0eacd714effe5aac1c1de26593873960b3346cab", "installed_by": [ "bam_sort_stats_samtools", "subworkflows" diff --git a/modules/nf-core/bioawk/main.nf b/modules/nf-core/bioawk/main.nf index 0fded517..a537dcf4 100644 --- a/modules/nf-core/bioawk/main.nf +++ b/modules/nf-core/bioawk/main.nf @@ -11,8 +11,8 @@ process BIOAWK { tuple val(meta), path(input) output: - tuple val(meta), path("${prefix}.${suffix}"), emit: output - path "versions.yml" , emit: versions + tuple val(meta), path("*.gz"), emit: output + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -20,14 +20,15 @@ process BIOAWK { script: def args = task.ext.args ?: '' // args is used for the main arguments of the tool prefix = task.ext.prefix ?: "${meta.id}" - suffix = task.ext.suffix ?: input.extension - + if ("${input}" == "${prefix}") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" def VERSION = '1.0' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. """ bioawk \\ $args \\ $input \\ - > ${prefix}.${suffix} + > ${prefix} + + gzip ${prefix} cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/bowtie/align/environment.yml b/modules/nf-core/bowtie/align/environment.yml index 2617e6f0..fb5d7c1e 100644 --- a/modules/nf-core/bowtie/align/environment.yml +++ b/modules/nf-core/bowtie/align/environment.yml @@ -5,3 +5,4 @@ channels: - defaults dependencies: - bioconda::bowtie=1.3.0 + - bioconda::samtools=1.16.1 diff --git a/modules/nf-core/bowtie/align/main.nf b/modules/nf-core/bowtie/align/main.nf index 29e9cd53..5e72b02a 100644 --- a/modules/nf-core/bowtie/align/main.nf +++ b/modules/nf-core/bowtie/align/main.nf @@ -9,13 +9,14 @@ process BOWTIE_ALIGN { input: tuple val(meta), path(reads) - path index + tuple val(meta2), path(index) + val (save_unaligned) output: - tuple val(meta), path('*.bam'), emit: bam - tuple val(meta), path('*.out'), emit: log - path "versions.yml" , emit: versions - tuple val(meta), path('*fastq.gz'), optional:true, emit: fastq + tuple val(meta), path('*.bam') , emit: bam + tuple val(meta), path('*.out') , emit: log + tuple val(meta), path('*fastq.gz') , emit: fastq, optional : true + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -24,10 +25,10 @@ process BOWTIE_ALIGN { def args = task.ext.args ?: '' def args2 = task.ext.args2 ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - def unaligned = params.save_unaligned ? "--un ${prefix}.unmapped.fastq" : '' + def unaligned = save_unaligned ? "--un ${prefix}.unmapped.fastq" : '' def endedness = meta.single_end ? "$reads" : "-1 ${reads[0]} -2 ${reads[1]}" """ - INDEX=`find -L ./ -name "*.3.ebwt" | sed 's/\\.3.ebwt\$//'` + INDEX=\$(find -L ./ -name "*.3.ebwt" | sed 's/\\.3.ebwt\$//') bowtie \\ --threads $task.cpus \\ --sam \\ @@ -53,4 +54,24 @@ process BOWTIE_ALIGN { samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') END_VERSIONS """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + def unaligned = save_unaligned ? + meta.single_end ? "echo '' | gzip > ${prefix}.unmapped.fastq.gz" : + "echo '' | gzip > ${prefix}.unmapped_1.fastq.gz; echo '' | gzip > ${prefix}.unmapped_2.fastq.gz" + : '' + """ + touch ${prefix}.bam + touch ${prefix}.out + $unaligned + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + bowtie: \$(echo \$(bowtie --version 2>&1) | sed 's/^.*bowtie-align-s version //; s/ .*\$//') + samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') + END_VERSIONS + """ + + } diff --git a/modules/nf-core/bowtie/align/meta.yml b/modules/nf-core/bowtie/align/meta.yml index 89eaedd6..7c7e8237 100644 --- a/modules/nf-core/bowtie/align/meta.yml +++ b/modules/nf-core/bowtie/align/meta.yml @@ -27,23 +27,36 @@ input: description: | List of input FastQ files of size 1 and 2 for single-end and paired-end data, respectively. + - meta2: + type: map + description: | + Groovy Map containing genome information + e.g. [ id:'sarscov2' ] - index: type: file description: Bowtie genome index files pattern: "*.ebwt" + - save_unaligned: + type: boolean + description: Whether to save fastq files containing the reads which did not align. output: - bam: type: file description: Output BAM file containing read alignments pattern: "*.{bam}" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" - fastq: type: file description: Unaligned FastQ files pattern: "*.fastq.gz" + - log: + type: file + description: Log file + pattern: "*.log" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + authors: - "@kevinmenden" maintainers: diff --git a/modules/nf-core/bowtie/align/tests/main.nf.test b/modules/nf-core/bowtie/align/tests/main.nf.test new file mode 100644 index 00000000..3403ae22 --- /dev/null +++ b/modules/nf-core/bowtie/align/tests/main.nf.test @@ -0,0 +1,129 @@ +nextflow_process { + + name "Test Process BOWTIE_ALIGN" + script "../main.nf" + process "BOWTIE_ALIGN" + + tag "modules" + tag "modules_nfcore" + tag "bowtie" + tag "bowtie/align" + tag "bowtie/build" + + + setup { + run("BOWTIE_BUILD") { + script "../../../bowtie/build/main.nf" + process { + """ + input[0] = [[ id:'sarscov2' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] + """ + } + } + } + + test("sarscov2 - single_end") { + + when { + process { + """ + input[0] = [ [id:"test", single_end:true], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ] + input[1] = BOWTIE_BUILD.out.index + input[2] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.versions, + process.out.bam.collect { bam(it[1]).getReadsMD5() }, + process.out.fastq, + process.out.log + ).match() } + ) + } + + } + + test("sarscov2 - single_end - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ [id:"test", single_end:true], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ] + input[1] = BOWTIE_BUILD.out.index + input[2] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("sarscov2 - paired_end") { + + when { + process { + """ + input[0] = [ [id:"test", single_end:false], + [file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)] + ] + input[1] = BOWTIE_BUILD.out.index + input[2] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.versions, + process.out.bam.collect { bam(it[1]).getReads(2) }, + process.out.log + ).match() } + ) + } + + } + + test("sarscov2 - paired_end - stub") { + + options "-stub" + when { + process { + """ + input[0] = [ [id:"test", single_end:false], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ] + input[1] = BOWTIE_BUILD.out.index + input[2] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/nf-core/bowtie/align/tests/main.nf.test.snap b/modules/nf-core/bowtie/align/tests/main.nf.test.snap new file mode 100644 index 00000000..de95bb81 --- /dev/null +++ b/modules/nf-core/bowtie/align/tests/main.nf.test.snap @@ -0,0 +1,192 @@ +{ + "sarscov2 - single_end": { + "content": [ + [ + "versions.yml:md5,96e36b0b99c80da0be8239d03db30ecc" + ], + [ + "7bdcfc6f54ae6e8f4570395cc85db9a3" + ], + [ + [ + { + "id": "test", + "single_end": true + }, + "test.unmapped.fastq.gz:md5,5729a694abd09657da3b9101861090c4" + ] + ], + [ + [ + { + "id": "test", + "single_end": true + }, + "test.out:md5,4b9140ceadb8a18ae9330885370f8a0b" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-26T09:25:24.60746041" + }, + "sarscov2 - single_end - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": true + }, + "test.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "single_end": true + }, + "test.unmapped.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "3": [ + "versions.yml:md5,96e36b0b99c80da0be8239d03db30ecc" + ], + "bam": [ + [ + { + "id": "test", + "single_end": true + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "fastq": [ + [ + { + "id": "test", + "single_end": true + }, + "test.unmapped.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "log": [ + [ + { + "id": "test", + "single_end": true + }, + "test.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,96e36b0b99c80da0be8239d03db30ecc" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-25T10:00:28.666281812" + }, + "sarscov2 - paired_end": { + "content": [ + [ + "versions.yml:md5,96e36b0b99c80da0be8239d03db30ecc" + ], + [ + [ + "ATGTGTACATTGGCGACCCTGCTCAATTACCTGCACCACGCACATTGCTAACTAAGGGCACACTAGAACCAGAATATTTCAATTCAGTGTGTAGACTTATGAAAACTATAGGTCCAGACATGTTCCTCGGAACTTGTCGGCGTTGTCCTG", + "ACGCACATTGCTAACTAAGGGCACACTAGAACCAGAATATTTCAATTCAGTGTGTAGACTTATGAAAACTATAGGTCCAGACATGTTCCTCGGAACTTGTCGGCGTTGTCCTGCTGAAATTGTTGACACTGTGAGTGCTTTGGTTTATGA" + ] + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.out:md5,5e13272d112cef8faeedcdbd7c602de0" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-26T11:57:56.604464368" + }, + "sarscov2 - paired_end - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,96e36b0b99c80da0be8239d03db30ecc" + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "fastq": [ + + ], + "log": [ + [ + { + "id": "test", + "single_end": false + }, + "test.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,96e36b0b99c80da0be8239d03db30ecc" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-25T10:01:02.043164876" + } +} \ No newline at end of file diff --git a/modules/nf-core/bowtie/align/tests/tags.yml b/modules/nf-core/bowtie/align/tests/tags.yml new file mode 100644 index 00000000..a5753d58 --- /dev/null +++ b/modules/nf-core/bowtie/align/tests/tags.yml @@ -0,0 +1,2 @@ +bowtie/align: + - "modules/nf-core/bowtie/align/**" diff --git a/modules/nf-core/bowtie/build/main.nf b/modules/nf-core/bowtie/build/main.nf index 05e22fe8..d5b4c690 100644 --- a/modules/nf-core/bowtie/build/main.nf +++ b/modules/nf-core/bowtie/build/main.nf @@ -1,5 +1,5 @@ process BOWTIE_BUILD { - tag "$fasta" + tag "${meta.id}" label 'process_high' conda "${moduleDir}/environment.yml" @@ -8,23 +8,43 @@ process BOWTIE_BUILD { 'biocontainers/bowtie:1.3.0--py38hed8969a_1' }" input: - path fasta + tuple val(meta), path(fasta) output: - path 'bowtie' , emit: index - path "versions.yml" , emit: versions + tuple val(meta), path('bowtie') , emit: index + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when script: def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" """ - mkdir bowtie - bowtie-build --threads $task.cpus $fasta bowtie/${fasta.baseName} + mkdir -p bowtie + bowtie-build --threads $task.cpus $fasta bowtie/${prefix} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + bowtie: \$(echo \$(bowtie --version 2>&1) | sed 's/^.*bowtie-align-s version //; s/ .*\$//') + END_VERSIONS + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + mkdir -p bowtie + touch bowtie/${prefix}.1.ebwt + touch bowtie/${prefix}.2.ebwt + touch bowtie/${prefix}.3.ebwt + touch bowtie/${prefix}.4.ebwt + touch bowtie/${prefix}.rev.1.ebwt + touch bowtie/${prefix}.rev.2.ebwt + cat <<-END_VERSIONS > versions.yml "${task.process}": bowtie: \$(echo \$(bowtie --version 2>&1) | sed 's/^.*bowtie-align-s version //; s/ .*\$//') END_VERSIONS """ + } diff --git a/modules/nf-core/bowtie/build/meta.yml b/modules/nf-core/bowtie/build/meta.yml index 262855f4..dd48004f 100644 --- a/modules/nf-core/bowtie/build/meta.yml +++ b/modules/nf-core/bowtie/build/meta.yml @@ -15,13 +15,23 @@ tools: arxiv: arXiv:1303.3997 licence: ["Artistic-2.0"] input: + - meta: + type: map + description: | + Groovy Map containing information about the genome fasta + e.g. [ id:'test' ] - fasta: type: file description: Input genome fasta file output: + - meta: + type: map + description: | + Groovy Map containing nformation about the genome fasta + e.g. [ id:'test' ] - index: type: file - description: Bowtie genome index files + description: Folder containing bowtie genome index files pattern: "*.ebwt" - versions: type: file diff --git a/modules/nf-core/bowtie/build/tests/main.nf.test b/modules/nf-core/bowtie/build/tests/main.nf.test new file mode 100644 index 00000000..2a1e0dc0 --- /dev/null +++ b/modules/nf-core/bowtie/build/tests/main.nf.test @@ -0,0 +1,57 @@ +nextflow_process { + + name "Test Process BOWTIE_BUILD" + script "../main.nf" + process "BOWTIE_BUILD" + + tag "modules" + tag "modules_nfcore" + tag "bowtie" + tag "bowtie/build" + + test("sarscov2 - fasta") { + + when { + process { + """ + input[0] = [ + [id: 'sarscov2'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("sarscov2 - fasta - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [[id: 'sarscov2'], + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/nf-core/bowtie/build/tests/main.nf.test.snap b/modules/nf-core/bowtie/build/tests/main.nf.test.snap new file mode 100644 index 00000000..e8061756 --- /dev/null +++ b/modules/nf-core/bowtie/build/tests/main.nf.test.snap @@ -0,0 +1,96 @@ +{ + "sarscov2 - fasta - stub": { + "content": [ + { + "0": [ + [ + { + "id": "sarscov2" + }, + [ + "sarscov2.1.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", + "sarscov2.2.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", + "sarscov2.3.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", + "sarscov2.4.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", + "sarscov2.rev.1.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", + "sarscov2.rev.2.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "1": [ + "versions.yml:md5,afbd066e1dd5ae4a30b21c49149ea09a" + ], + "index": [ + [ + { + "id": "sarscov2" + }, + [ + "sarscov2.1.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", + "sarscov2.2.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", + "sarscov2.3.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", + "sarscov2.4.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", + "sarscov2.rev.1.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", + "sarscov2.rev.2.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions": [ + "versions.yml:md5,afbd066e1dd5ae4a30b21c49149ea09a" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-18T08:38:14.852528155" + }, + "sarscov2 - fasta": { + "content": [ + { + "0": [ + [ + { + "id": "sarscov2" + }, + [ + "sarscov2.1.ebwt:md5,d9b76ecf9fd0413240173273b38d8199", + "sarscov2.2.ebwt:md5,02b44af9f94c62ecd3c583048e25d4cf", + "sarscov2.3.ebwt:md5,4ed93abba181d8dfab2e303e33114777", + "sarscov2.4.ebwt:md5,c25be5f8b0378abf7a58c8a880b87626", + "sarscov2.rev.1.ebwt:md5,b37aaf11853e65a3b13561f27a912b06", + "sarscov2.rev.2.ebwt:md5,9e6b0c4c1ddb99ae71ff8a4fe5ec6459" + ] + ] + ], + "1": [ + "versions.yml:md5,afbd066e1dd5ae4a30b21c49149ea09a" + ], + "index": [ + [ + { + "id": "sarscov2" + }, + [ + "sarscov2.1.ebwt:md5,d9b76ecf9fd0413240173273b38d8199", + "sarscov2.2.ebwt:md5,02b44af9f94c62ecd3c583048e25d4cf", + "sarscov2.3.ebwt:md5,4ed93abba181d8dfab2e303e33114777", + "sarscov2.4.ebwt:md5,c25be5f8b0378abf7a58c8a880b87626", + "sarscov2.rev.1.ebwt:md5,b37aaf11853e65a3b13561f27a912b06", + "sarscov2.rev.2.ebwt:md5,9e6b0c4c1ddb99ae71ff8a4fe5ec6459" + ] + ] + ], + "versions": [ + "versions.yml:md5,afbd066e1dd5ae4a30b21c49149ea09a" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-18T08:37:53.65689025" + } +} \ No newline at end of file diff --git a/modules/nf-core/bowtie/build/tests/tags.yml b/modules/nf-core/bowtie/build/tests/tags.yml new file mode 100644 index 00000000..1ccfa30c --- /dev/null +++ b/modules/nf-core/bowtie/build/tests/tags.yml @@ -0,0 +1,2 @@ +bowtie/build: + - "modules/nf-core/bowtie/build/**" diff --git a/modules/nf-core/bowtie2/align/tests/main.nf.test b/modules/nf-core/bowtie2/align/tests/main.nf.test index 03aeaf9e..0de5950f 100644 --- a/modules/nf-core/bowtie2/align/tests/main.nf.test +++ b/modules/nf-core/bowtie2/align/tests/main.nf.test @@ -18,7 +18,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -30,10 +30,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -64,7 +64,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -76,10 +76,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -110,7 +110,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -122,10 +122,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -155,7 +155,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -167,10 +167,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -200,7 +200,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -213,12 +213,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -248,7 +248,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -261,12 +261,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -297,7 +297,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -309,10 +309,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -343,7 +343,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -356,12 +356,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -391,7 +391,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -404,12 +404,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -439,7 +439,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -451,10 +451,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -486,7 +486,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -499,12 +499,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = true //sort """ @@ -533,7 +533,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -546,12 +546,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), - file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -583,7 +583,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -595,10 +595,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ diff --git a/modules/nf-core/cat/cat/main.nf b/modules/nf-core/cat/cat/main.nf index adbdbd7b..2862c64c 100644 --- a/modules/nf-core/cat/cat/main.nf +++ b/modules/nf-core/cat/cat/main.nf @@ -76,4 +76,3 @@ def getFileSuffix(filename) { def match = filename =~ /^.*?((\.\w{1,5})?(\.\w{1,5}\.gz$))/ return match ? match[0][1] : filename.substring(filename.lastIndexOf('.')) } - diff --git a/modules/nf-core/cat/cat/tests/main.nf.test b/modules/nf-core/cat/cat/tests/main.nf.test index fcee2d19..9cb16178 100644 --- a/modules/nf-core/cat/cat/tests/main.nf.test +++ b/modules/nf-core/cat/cat/tests/main.nf.test @@ -29,7 +29,8 @@ nextflow_process { then { assertAll( { assert !process.success }, - { assert process.stdout.toString().contains("The name of the input file can't be the same as for the output prefix") } + { assert process.stdout.toString().contains("The name of the input file can't be the same as for the output prefix") }, + { assert snapshot(process.out.versions).match() } ) } } @@ -83,8 +84,12 @@ nextflow_process { def lines = path(process.out.file_out.get(0).get(1)).linesGzip assertAll( { assert process.success }, - { assert snapshot(lines[0..5]).match("test_cat_zipped_zipped_lines") }, - { assert snapshot(lines.size()).match("test_cat_zipped_zipped_size")} + { assert snapshot( + lines[0..5], + lines.size(), + process.out.versions + ).match() + } ) } } @@ -142,8 +147,12 @@ nextflow_process { def lines = path(process.out.file_out.get(0).get(1)).linesGzip assertAll( { assert process.success }, - { assert snapshot(lines[0..5]).match("test_cat_unzipped_zipped_lines") }, - { assert snapshot(lines.size()).match("test_cat_unzipped_zipped_size")} + { assert snapshot( + lines[0..5], + lines.size(), + process.out.versions + ).match() + } ) } } @@ -170,8 +179,12 @@ nextflow_process { def lines = path(process.out.file_out.get(0).get(1)).linesGzip assertAll( { assert process.success }, - { assert snapshot(lines[0..5]).match("test_cat_one_file_unzipped_zipped_lines") }, - { assert snapshot(lines.size()).match("test_cat_one_file_unzipped_zipped_size")} + { assert snapshot( + lines[0..5], + lines.size(), + process.out.versions + ).match() + } ) } } diff --git a/modules/nf-core/cat/cat/tests/main.nf.test.snap b/modules/nf-core/cat/cat/tests/main.nf.test.snap index 423571ba..b7623ee6 100644 --- a/modules/nf-core/cat/cat/tests/main.nf.test.snap +++ b/modules/nf-core/cat/cat/tests/main.nf.test.snap @@ -1,10 +1,4 @@ { - "test_cat_unzipped_zipped_size": { - "content": [ - 375 - ], - "timestamp": "2023-10-16T14:33:08.049445686" - }, "test_cat_unzipped_unzipped": { "content": [ { @@ -34,6 +28,10 @@ ] } ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.3" + }, "timestamp": "2023-10-16T14:32:18.500464399" }, "test_cat_zipped_unzipped": { @@ -65,9 +63,13 @@ ] } ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.3" + }, "timestamp": "2023-10-16T14:32:49.642741302" }, - "test_cat_zipped_zipped_lines": { + "test_cat_zipped_zipped": { "content": [ [ "MT192765.1\tGenbank\ttranscript\t259\t29667\t.\t+\t.\tID=unknown_transcript_1;geneID=orf1ab;gene_name=orf1ab", @@ -76,11 +78,31 @@ "MT192765.1\tGenbank\tCDS\t13461\t21548\t.\t+\t0\tParent=unknown_transcript_1;exception=\"ribosomal slippage\";gbkey=CDS;gene=orf1ab;note=\"pp1ab;translated=by -1 ribosomal frameshift\";product=\"orf1ab polyprotein\";protein_id=QIK50426.1", "MT192765.1\tGenbank\tCDS\t21556\t25377\t.\t+\t0\tParent=unknown_transcript_1;gbkey=CDS;gene=S;note=\"structural protein\";product=\"surface glycoprotein\";protein_id=QIK50427.1", "MT192765.1\tGenbank\tgene\t21556\t25377\t.\t+\t.\tParent=unknown_transcript_1" + ], + 78, + [ + "versions.yml:md5,115ed6177ebcff24eb99d503fa5ef894" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:51:46.802978" + }, + "test_cat_name_conflict": { + "content": [ + [ + ] ], - "timestamp": "2023-10-16T14:32:33.629048645" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:51:29.45394" }, - "test_cat_unzipped_zipped_lines": { + "test_cat_one_file_unzipped_zipped": { "content": [ [ ">MT192765.1 Severe acute respiratory syndrome coronavirus 2 isolate SARS-CoV-2/human/USA/PC00101P/2020, complete genome", @@ -89,11 +111,19 @@ "TAACTCGTCTATCTTCTGCAGGCTGCTTACGGTTTCGTCCGTGTTGCAGCCGATCATCAGCACATCTAGGTTTTGTCCGG", "GTGTGACCGAAAGGTAAGATGGAGAGCCTTGTCCCTGGTTTCAACGAGAAAACACACGTCCAACTCAGTTTGCCTGTTTT", "ACAGGTTCGCGACGTGCTCGTACGTGGCTTTGGAGACTCCGTGGAGGAGGTCTTATCAGAGGCACGTCAACATCTTAAAG" + ], + 374, + [ + "versions.yml:md5,115ed6177ebcff24eb99d503fa5ef894" ] ], - "timestamp": "2023-10-16T14:33:08.038830506" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:52:02.774016" }, - "test_cat_one_file_unzipped_zipped_lines": { + "test_cat_unzipped_zipped": { "content": [ [ ">MT192765.1 Severe acute respiratory syndrome coronavirus 2 isolate SARS-CoV-2/human/USA/PC00101P/2020, complete genome", @@ -102,20 +132,16 @@ "TAACTCGTCTATCTTCTGCAGGCTGCTTACGGTTTCGTCCGTGTTGCAGCCGATCATCAGCACATCTAGGTTTTGTCCGG", "GTGTGACCGAAAGGTAAGATGGAGAGCCTTGTCCCTGGTTTCAACGAGAAAACACACGTCCAACTCAGTTTGCCTGTTTT", "ACAGGTTCGCGACGTGCTCGTACGTGGCTTTGGAGACTCCGTGGAGGAGGTCTTATCAGAGGCACGTCAACATCTTAAAG" + ], + 375, + [ + "versions.yml:md5,115ed6177ebcff24eb99d503fa5ef894" ] ], - "timestamp": "2023-10-16T14:33:21.39642399" - }, - "test_cat_zipped_zipped_size": { - "content": [ - 78 - ], - "timestamp": "2023-10-16T14:32:33.641869244" - }, - "test_cat_one_file_unzipped_zipped_size": { - "content": [ - 374 - ], - "timestamp": "2023-10-16T14:33:21.4094373" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:51:57.581523" } } \ No newline at end of file diff --git a/modules/nf-core/cat/fastq/main.nf b/modules/nf-core/cat/fastq/main.nf index f132b2ad..b68e5f91 100644 --- a/modules/nf-core/cat/fastq/main.nf +++ b/modules/nf-core/cat/fastq/main.nf @@ -53,9 +53,9 @@ process CAT_FASTQ { def prefix = task.ext.prefix ?: "${meta.id}" def readList = reads instanceof List ? reads.collect{ it.toString() } : [reads.toString()] if (meta.single_end) { - if (readList.size > 1) { + if (readList.size >= 1) { """ - touch ${prefix}.merged.fastq.gz + echo '' | gzip > ${prefix}.merged.fastq.gz cat <<-END_VERSIONS > versions.yml "${task.process}": @@ -64,10 +64,10 @@ process CAT_FASTQ { """ } } else { - if (readList.size > 2) { + if (readList.size >= 2) { """ - touch ${prefix}_1.merged.fastq.gz - touch ${prefix}_2.merged.fastq.gz + echo '' | gzip > ${prefix}_1.merged.fastq.gz + echo '' | gzip > ${prefix}_2.merged.fastq.gz cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/cat/fastq/tests/main.nf.test b/modules/nf-core/cat/fastq/tests/main.nf.test index a71dcb8d..f88a78b6 100644 --- a/modules/nf-core/cat/fastq/tests/main.nf.test +++ b/modules/nf-core/cat/fastq/tests/main.nf.test @@ -13,9 +13,6 @@ nextflow_process { test("test_cat_fastq_single_end") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -38,9 +35,6 @@ nextflow_process { test("test_cat_fastq_paired_end") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -65,9 +59,6 @@ nextflow_process { test("test_cat_fastq_single_end_same_name") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -90,9 +81,6 @@ nextflow_process { test("test_cat_fastq_paired_end_same_name") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -117,9 +105,129 @@ nextflow_process { test("test_cat_fastq_single_end_single_file") { when { - params { - outdir = "$outputDir" + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_single_end - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_paired_end - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_single_end_same_name - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_paired_end_same_name - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)] + ]) + """ } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_single_end_single_file - stub") { + + options "-stub" + + when { process { """ input[0] = Channel.of([ diff --git a/modules/nf-core/cat/fastq/tests/main.nf.test.snap b/modules/nf-core/cat/fastq/tests/main.nf.test.snap index 43dfe28f..aec119a9 100644 --- a/modules/nf-core/cat/fastq/tests/main.nf.test.snap +++ b/modules/nf-core/cat/fastq/tests/main.nf.test.snap @@ -28,6 +28,10 @@ ] } ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, "timestamp": "2024-01-17T17:30:39.816981" }, "test_cat_fastq_single_end_same_name": { @@ -59,6 +63,10 @@ ] } ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, "timestamp": "2024-01-17T17:32:35.229332" }, "test_cat_fastq_single_end_single_file": { @@ -90,6 +98,10 @@ ] } ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, "timestamp": "2024-01-17T17:34:00.058829" }, "test_cat_fastq_paired_end_same_name": { @@ -127,8 +139,123 @@ ] } ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, "timestamp": "2024-01-17T17:33:33.031555" }, + "test_cat_fastq_single_end - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-07-05T12:07:28.244999" + }, + "test_cat_fastq_paired_end_same_name - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "1": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ], + "reads": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "versions": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-07-05T12:07:57.070911" + }, + "test_cat_fastq_single_end_same_name - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-07-05T12:07:46.796254" + }, "test_cat_fastq_paired_end": { "content": [ { @@ -164,6 +291,86 @@ ] } ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, "timestamp": "2024-01-17T17:32:02.270935" + }, + "test_cat_fastq_paired_end - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "1": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ], + "reads": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "versions": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-07-05T12:07:37.807553" + }, + "test_cat_fastq_single_end_single_file - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions": [ + "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-07-05T12:14:51.861264" } } \ No newline at end of file diff --git a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py index da033408..9a493ace 100755 --- a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py +++ b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py @@ -3,7 +3,6 @@ """Provide functions to merge multiple versions.yml files.""" - import yaml import platform from textwrap import dedent diff --git a/modules/nf-core/custom/tx2gene/templates/tx2gene.py b/modules/nf-core/custom/tx2gene/templates/tx2gene.py index 7fd0de64..8c2e3b1f 100755 --- a/modules/nf-core/custom/tx2gene/templates/tx2gene.py +++ b/modules/nf-core/custom/tx2gene/templates/tx2gene.py @@ -17,6 +17,7 @@ logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) + def format_yaml_like(data: dict, indent: int = 0) -> str: """Formats a dictionary to a YAML-like string. @@ -36,6 +37,7 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: yaml_str += f"{spaces}{key}: {value}\\n" return yaml_str + def read_top_transcripts(quant_dir: str, file_pattern: str) -> Set[str]: """ Read the top 100 transcripts from the quantification file. @@ -123,7 +125,12 @@ def parse_attributes(attributes_text: str) -> Dict[str, str]: def map_transcripts_to_gene( - quant_type: str, gtf_file: str, quant_dir: str, gene_id: str, extra_id_field: str, output_file: str + quant_type: str, + gtf_file: str, + quant_dir: str, + gene_id: str, + extra_id_field: str, + output_file: str, ) -> bool: """ Map transcripts to gene names and write the output to a file. @@ -156,7 +163,10 @@ def map_transcripts_to_gene( attr_dict = parse_attributes(cols[8]) if gene_id in attr_dict and transcript_attribute in attr_dict: # Create a unique identifier for the transcript-gene combination - transcript_gene_pair = (attr_dict[transcript_attribute], attr_dict[gene_id]) + transcript_gene_pair = ( + attr_dict[transcript_attribute], + attr_dict[gene_id], + ) # Check if the combination has already been seen if transcript_gene_pair not in seen: @@ -170,14 +180,14 @@ def map_transcripts_to_gene( # Main function to parse arguments and call the mapping function if __name__ == "__main__": - if '${task.ext.prefix}' != "null": + if "${task.ext.prefix}" != "null": prefix = "${task.ext.prefix}." - elif '$meta.id' != "null": - prefix = '${meta.id}.' + elif "$meta.id" != "null": + prefix = "${meta.id}." else: - prefix = '' + prefix = "" - if not map_transcripts_to_gene('$quant_type', '$gtf', 'quants', '$id', '$extra', f"{prefix}tx2gene.tsv"): + if not map_transcripts_to_gene("$quant_type", "$gtf", "quants", "$id", "$extra", f"{prefix}tx2gene.tsv"): logger.error("Failed to map transcripts to genes.") # Write the versions diff --git a/modules/nf-core/custom/tx2gene/tests/main.nf.test b/modules/nf-core/custom/tx2gene/tests/main.nf.test index b1559279..4cbb8d4e 100644 --- a/modules/nf-core/custom/tx2gene/tests/main.nf.test +++ b/modules/nf-core/custom/tx2gene/tests/main.nf.test @@ -10,22 +10,21 @@ nextflow_process { tag "custom/tx2gene" tag "untar" - setup { + test("saccharomyces_cerevisiae - gtf") { - run("UNTAR") { - script "../../../untar/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test'], // meta map - file(params.modules_testdata_base_path + 'genomics/eukaryotes/saccharomyces_cerevisiae/kallisto_results.tar.gz', checkIfExists: true) - ]) - """ + setup { + run("UNTAR") { + script "../../../untar/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test'], // meta map + file(params.modules_testdata_base_path + 'genomics/eukaryotes/saccharomyces_cerevisiae/kallisto_results.tar.gz', checkIfExists: true) + ]) + """ + } } } - } - - test("saccharomyces_cerevisiae - gtf") { when { process { @@ -45,8 +44,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.tx2gene).match('tx2gene') }, - { assert snapshot(process.out.versions).match('versions') } + { assert snapshot(process.out).match() } ) } } @@ -55,6 +53,20 @@ nextflow_process { options "-stub" + setup { + run("UNTAR") { + script "../../../untar/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test'], // meta map + file(params.modules_testdata_base_path + 'genomics/eukaryotes/saccharomyces_cerevisiae/kallisto_results.tar.gz', checkIfExists: true) + ]) + """ + } + } + } + when { process { """ @@ -73,8 +85,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.tx2gene).match('tx2gene - stub') }, - { assert snapshot(process.out.versions).match('versions - stub') } + { assert snapshot(process.out).match() } ) } } diff --git a/modules/nf-core/custom/tx2gene/tests/main.nf.test.snap b/modules/nf-core/custom/tx2gene/tests/main.nf.test.snap index 1e76e10d..c19f10f7 100644 --- a/modules/nf-core/custom/tx2gene/tests/main.nf.test.snap +++ b/modules/nf-core/custom/tx2gene/tests/main.nf.test.snap @@ -1,60 +1,68 @@ { - "versions": { + "saccharomyces_cerevisiae - gtf": { "content": [ - [ - "versions.yml:md5,fb8145d7fbc6043ba031249b23ecda50" - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.01.0" - }, - "timestamp": "2024-02-26T13:14:18.218251" - }, - "tx2gene": { - "content": [ - [ - [ - { - "id": "test" - }, - "test.tx2gene.tsv:md5,0e2418a69d2eba45097ebffc2f700bfe" + { + "0": [ + [ + { + "id": "test" + }, + "test.tx2gene.tsv:md5,0e2418a69d2eba45097ebffc2f700bfe" + ] + ], + "1": [ + "versions.yml:md5,fb8145d7fbc6043ba031249b23ecda50" + ], + "tx2gene": [ + [ + { + "id": "test" + }, + "test.tx2gene.tsv:md5,0e2418a69d2eba45097ebffc2f700bfe" + ] + ], + "versions": [ + "versions.yml:md5,fb8145d7fbc6043ba031249b23ecda50" ] - ] + } ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "24.04.2" }, - "timestamp": "2024-02-26T13:14:18.21054" + "timestamp": "2024-07-05T13:13:11.305047" }, - "tx2gene - stub": { + "saccharomyces_cerevisiae - gtf - stub": { "content": [ - [ - [ - { - "id": "test" - }, - "test.tx2gene.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + { + "0": [ + [ + { + "id": "test" + }, + "test.tx2gene.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,5613eefbca41377128f1d8dc09b9fb60" + ], + "tx2gene": [ + [ + { + "id": "test" + }, + "test.tx2gene.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,5613eefbca41377128f1d8dc09b9fb60" ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.01.0" - }, - "timestamp": "2024-02-26T13:14:25.915434" - }, - "versions - stub": { - "content": [ - [ - "versions.yml:md5,5613eefbca41377128f1d8dc09b9fb60" - ] + } ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nextflow": "24.04.3" }, - "timestamp": "2024-02-26T13:14:25.919243" + "timestamp": "2024-07-10T15:15:34.064489" } } \ No newline at end of file diff --git a/modules/nf-core/fastqc/tests/main.nf.test b/modules/nf-core/fastqc/tests/main.nf.test index 70edae4d..e9d79a07 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test +++ b/modules/nf-core/fastqc/tests/main.nf.test @@ -23,17 +23,14 @@ nextflow_process { then { assertAll ( - { assert process.success }, - - // NOTE The report contains the date inside it, which means that the md5sum is stable per day, but not longer than that. So you can't md5sum it. - // looks like this:
      Mon 2 Oct 2023
      test.gz
      - // https://github.com/nf-core/modules/pull/3903#issuecomment-1743620039 - - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("
    ") }, - - { assert snapshot(process.out.versions).match("fastqc_versions_single") } + { assert process.success }, + // NOTE The report contains the date inside it, which means that the md5sum is stable per day, but not longer than that. So you can't md5sum it. + // looks like this:
    Mon 2 Oct 2023
    test.gz
    + // https://github.com/nf-core/modules/pull/3903#issuecomment-1743620039 + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("
    ") }, + { assert snapshot(process.out.versions).match() } ) } } @@ -54,16 +51,14 @@ nextflow_process { then { assertAll ( - { assert process.success }, - - { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, - { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, - { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, - { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, - { assert path(process.out.html[0][1][0]).text.contains("") }, - { assert path(process.out.html[0][1][1]).text.contains("") }, - - { assert snapshot(process.out.versions).match("fastqc_versions_paired") } + { assert process.success }, + { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, + { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, + { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, + { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, + { assert path(process.out.html[0][1][0]).text.contains("") }, + { assert path(process.out.html[0][1][1]).text.contains("") }, + { assert snapshot(process.out.versions).match() } ) } } @@ -83,13 +78,11 @@ nextflow_process { then { assertAll ( - { assert process.success }, - - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("") }, - - { assert snapshot(process.out.versions).match("fastqc_versions_interleaved") } + { assert process.success }, + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("") }, + { assert snapshot(process.out.versions).match() } ) } } @@ -109,13 +102,11 @@ nextflow_process { then { assertAll ( - { assert process.success }, - - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("") }, - - { assert snapshot(process.out.versions).match("fastqc_versions_bam") } + { assert process.success }, + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("") }, + { assert snapshot(process.out.versions).match() } ) } } @@ -138,22 +129,20 @@ nextflow_process { then { assertAll ( - { assert process.success }, - - { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, - { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, - { assert process.out.html[0][1][2] ==~ ".*/test_3_fastqc.html" }, - { assert process.out.html[0][1][3] ==~ ".*/test_4_fastqc.html" }, - { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, - { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, - { assert process.out.zip[0][1][2] ==~ ".*/test_3_fastqc.zip" }, - { assert process.out.zip[0][1][3] ==~ ".*/test_4_fastqc.zip" }, - { assert path(process.out.html[0][1][0]).text.contains("") }, - { assert path(process.out.html[0][1][1]).text.contains("") }, - { assert path(process.out.html[0][1][2]).text.contains("") }, - { assert path(process.out.html[0][1][3]).text.contains("") }, - - { assert snapshot(process.out.versions).match("fastqc_versions_multiple") } + { assert process.success }, + { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, + { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, + { assert process.out.html[0][1][2] ==~ ".*/test_3_fastqc.html" }, + { assert process.out.html[0][1][3] ==~ ".*/test_4_fastqc.html" }, + { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, + { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, + { assert process.out.zip[0][1][2] ==~ ".*/test_3_fastqc.zip" }, + { assert process.out.zip[0][1][3] ==~ ".*/test_4_fastqc.zip" }, + { assert path(process.out.html[0][1][0]).text.contains("") }, + { assert path(process.out.html[0][1][1]).text.contains("") }, + { assert path(process.out.html[0][1][2]).text.contains("") }, + { assert path(process.out.html[0][1][3]).text.contains("") }, + { assert snapshot(process.out.versions).match() } ) } } @@ -173,21 +162,18 @@ nextflow_process { then { assertAll ( - { assert process.success }, - - { assert process.out.html[0][1] ==~ ".*/mysample_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/mysample_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("") }, - - { assert snapshot(process.out.versions).match("fastqc_versions_custom_prefix") } + { assert process.success }, + { assert process.out.html[0][1] ==~ ".*/mysample_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/mysample_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("") }, + { assert snapshot(process.out.versions).match() } ) } } test("sarscov2 single-end [fastq] - stub") { - options "-stub" - + options "-stub" when { process { """ @@ -201,12 +187,123 @@ nextflow_process { then { assertAll ( - { assert process.success }, - { assert snapshot(process.out.html.collect { file(it[1]).getName() } + - process.out.zip.collect { file(it[1]).getName() } + - process.out.versions ).match("fastqc_stub") } + { assert process.success }, + { assert snapshot(process.out).match() } ) } } + test("sarscov2 paired-end [fastq] - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 interleaved [fastq] - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 paired-end [bam] - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 multiple [fastq] - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) ] + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 custom_prefix - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [ id:'mysample', single_end:true ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } } diff --git a/modules/nf-core/fastqc/tests/main.nf.test.snap b/modules/nf-core/fastqc/tests/main.nf.test.snap index 86f7c311..d5db3092 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test.snap +++ b/modules/nf-core/fastqc/tests/main.nf.test.snap @@ -1,88 +1,392 @@ { - "fastqc_versions_interleaved": { + "sarscov2 custom_prefix": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-31T17:40:07.293713" + "timestamp": "2024-07-22T11:02:16.374038" }, - "fastqc_stub": { + "sarscov2 single-end [fastq] - stub": { "content": [ - [ - "test.html", - "test.zip", - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": true + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": true + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": true + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:02:24.993809" + }, + "sarscov2 custom_prefix - stub": { + "content": [ + { + "0": [ + [ + { + "id": "mysample", + "single_end": true + }, + "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "mysample", + "single_end": true + }, + "mysample.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "mysample", + "single_end": true + }, + "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "mysample", + "single_end": true + }, + "mysample.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-31T17:31:01.425198" + "timestamp": "2024-07-22T11:03:10.93942" }, - "fastqc_versions_multiple": { + "sarscov2 interleaved [fastq]": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-31T17:40:55.797907" + "timestamp": "2024-07-22T11:01:42.355718" }, - "fastqc_versions_bam": { + "sarscov2 paired-end [bam]": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-31T17:40:26.795862" + "timestamp": "2024-07-22T11:01:53.276274" }, - "fastqc_versions_single": { + "sarscov2 multiple [fastq]": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-31T17:39:27.043675" + "timestamp": "2024-07-22T11:02:05.527626" }, - "fastqc_versions_paired": { + "sarscov2 paired-end [fastq]": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:01:31.188871" + }, + "sarscov2 paired-end [fastq] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:02:34.273566" + }, + "sarscov2 multiple [fastq] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-31T17:39:47.584191" + "timestamp": "2024-07-22T11:03:02.304411" }, - "fastqc_versions_custom_prefix": { + "sarscov2 single-end [fastq]": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:01:19.095607" + }, + "sarscov2 interleaved [fastq] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:02:44.640184" + }, + "sarscov2 paired-end [bam] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-31T17:41:14.576531" + "timestamp": "2024-07-22T11:02:53.550742" } } \ No newline at end of file diff --git a/modules/nf-core/hisat2/align/main.nf b/modules/nf-core/hisat2/align/main.nf index 2289a9fc..ea186f62 100644 --- a/modules/nf-core/hisat2/align/main.nf +++ b/modules/nf-core/hisat2/align/main.nf @@ -90,4 +90,23 @@ process HISAT2_ALIGN { END_VERSIONS """ } + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + def unaligned = params.save_unaligned ? "echo '' | gzip > ${prefix}.unmapped_1.fastq.gz \n echo '' | gzip > ${prefix}.unmapped_2.fastq.gz" : '' + def VERSION = '2.2.1' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. + """ + ${unaligned} + + touch ${prefix}.hisat2.summary.log + touch ${prefix}.bam + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + hisat2: $VERSION + samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') + END_VERSIONS + """ + + } diff --git a/modules/nf-core/hisat2/align/tests/main.nf.test b/modules/nf-core/hisat2/align/tests/main.nf.test index 3a520e9a..396757d7 100644 --- a/modules/nf-core/hisat2/align/tests/main.nf.test +++ b/modules/nf-core/hisat2/align/tests/main.nf.test @@ -68,6 +68,63 @@ nextflow_process { } } + test("Single-End - stub") { + options "-stub" + + setup { + run("HISAT2_EXTRACTSPLICESITES") { + script "../../extractsplicesites/main.nf" + process { + """ + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ]) + """ + } + } + + run("HISAT2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + input[1] = Channel.of([ [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ]) + input[2] = HISAT2_EXTRACTSPLICESITES.out.txt + """ + } + } + } + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)] + ]) + input[1] = HISAT2_BUILD.out.index + input[2] = HISAT2_EXTRACTSPLICESITES.out.txt + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + test("Paired-End") { setup { @@ -127,6 +184,64 @@ nextflow_process { } } + test("Paired-End - stub") { + options "-stub" + + setup { + run("HISAT2_EXTRACTSPLICESITES") { + script "../../extractsplicesites/main.nf" + process { + """ + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ]) + """ + } + } + + run("HISAT2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + input[1] = Channel.of([ [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ]) + input[2] = HISAT2_EXTRACTSPLICESITES.out.txt + """ + } + } + } + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] + ]) + input[1] = HISAT2_BUILD.out.index + input[2] = HISAT2_EXTRACTSPLICESITES.out.txt + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + test("Single-End No Splice Sites") { setup { @@ -171,6 +286,49 @@ nextflow_process { } } + test("Single-End No Splice Sites - stub") { + options "-stub" + + setup { + run("HISAT2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + input[1] = [[:],[]] + input[2] = [[:],[]] + """ + } + } + } + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] + ]) + input[1] = HISAT2_BUILD.out.index + input[2] = [[:],[]] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + test("Paired-End No Splice Sites") { setup { @@ -215,4 +373,48 @@ nextflow_process { ) } } + + test("Paired-End No Splice Sites - stub") { + options "-stub" + + setup { + run("HISAT2_BUILD") { + script "../../build/main.nf" + process { + """ + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + input[1] = [[:],[]] + input[2] = [[:],[]] + """ + } + } + } + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] + ]) + input[1] = HISAT2_BUILD.out.index + input[2] = [[:],[]] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } } diff --git a/modules/nf-core/hisat2/align/tests/main.nf.test.snap b/modules/nf-core/hisat2/align/tests/main.nf.test.snap index a80fa3c5..ff670d45 100644 --- a/modules/nf-core/hisat2/align/tests/main.nf.test.snap +++ b/modules/nf-core/hisat2/align/tests/main.nf.test.snap @@ -5,21 +5,129 @@ "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" ] ], - "timestamp": "2023-10-16T15:14:50.269895296" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:08:33.735489" }, - "se_no_ss_summary": { + "Paired-End - stub": { "content": [ - [ - [ - { - "id": "test", - "single_end": true - }, - "test.hisat2.summary.log:md5,7b8a9e61b7646da1089b041333c41a87" + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "fastq": [ + + ], + "summary": [ + [ + { + "id": "test", + "single_end": false + }, + "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" ] - ] + } ], - "timestamp": "2023-10-16T15:15:22.897386626" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:09:14.35626" + }, + "Single-End - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": true + }, + "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" + ], + "bam": [ + [ + { + "id": "test", + "single_end": true + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "fastq": [ + + ], + "summary": [ + [ + { + "id": "test", + "single_end": true + }, + "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:08:47.404885" }, "pe_no_ss_versions": { "content": [ @@ -27,15 +135,70 @@ "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" ] ], - "timestamp": "2023-10-16T15:15:42.583699978" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:09:52.076955" }, - "se_no_ss_versions": { + "Paired-End No Splice Sites - stub": { "content": [ - [ - "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" - ] + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "fastq": [ + + ], + "summary": [ + [ + { + "id": "test", + "single_end": false + }, + "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" + ] + } ], - "timestamp": "2023-10-16T15:15:22.909407356" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:10:03.739697" }, "pe_no_ss_summary": { "content": [ @@ -49,7 +212,11 @@ ] ] ], - "timestamp": "2023-10-16T15:15:42.569775538" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:09:52.068244" }, "pe_no_ss_fastq": { "content": [ @@ -57,7 +224,11 @@ ] ], - "timestamp": "2023-10-16T15:15:42.576881608" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:09:52.072985" }, "se_summary": { "content": [ @@ -71,7 +242,11 @@ ] ] ], - "timestamp": "2023-10-16T15:14:50.252466896" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:08:33.727355" }, "pe_summary": { "content": [ @@ -85,7 +260,11 @@ ] ] ], - "timestamp": "2023-10-16T15:15:09.881690889" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:09:01.495439" }, "pe_fastq": { "content": [ @@ -93,23 +272,124 @@ ] ], - "timestamp": "2023-10-16T15:15:09.888696129" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:09:01.500755" }, - "se_no_ss_fastq": { + "se_fastq": { "content": [ [ ] ], - "timestamp": "2023-10-16T15:15:22.904010016" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:08:33.732523" }, - "se_fastq": { + "se_no_ss_summary": { + "content": [ + [ + [ + { + "id": "test", + "single_end": true + }, + "test.hisat2.summary.log:md5,7b8a9e61b7646da1089b041333c41a87" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:09:26.851884" + }, + "se_no_ss_versions": { + "content": [ + [ + "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:09:26.89234" + }, + "se_no_ss_fastq": { "content": [ [ ] ], - "timestamp": "2023-10-16T15:14:50.264366105" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:09:26.871369" + }, + "Single-End No Splice Sites - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": true + }, + "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" + ], + "bam": [ + [ + { + "id": "test", + "single_end": true + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "fastq": [ + + ], + "summary": [ + [ + { + "id": "test", + "single_end": true + }, + "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:09:39.544807" }, "pe_versions": { "content": [ @@ -117,6 +397,10 @@ "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" ] ], - "timestamp": "2023-10-16T15:15:09.894683308" + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T09:09:01.506346" } } \ No newline at end of file diff --git a/modules/nf-core/hisat2/build/main.nf b/modules/nf-core/hisat2/build/main.nf index 766e8731..17d8fdd5 100644 --- a/modules/nf-core/hisat2/build/main.nf +++ b/modules/nf-core/hisat2/build/main.nf @@ -61,4 +61,15 @@ process HISAT2_BUILD { hisat2: $VERSION END_VERSIONS """ + + stub: + def VERSION = '2.2.1' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. + """ + mkdir hisat2 + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + hisat2: $VERSION + END_VERSIONS + """ } diff --git a/modules/nf-core/hisat2/build/tests/main.nf.test b/modules/nf-core/hisat2/build/tests/main.nf.test index 5b31debc..e19692c4 100644 --- a/modules/nf-core/hisat2/build/tests/main.nf.test +++ b/modules/nf-core/hisat2/build/tests/main.nf.test @@ -50,4 +50,49 @@ nextflow_process { ) } } -} + + test("Should run without failures - stub") { + + options "-stub" + + setup { + run("HISAT2_EXTRACTSPLICESITES") { + script "../../extractsplicesites/main.nf" + process { + """ + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ]) + """ + } + } + } + + when { + params { + outdir = "$outputDir" + } + + process { + """ + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + input[1] = Channel.of([ [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ]) + input[2] = HISAT2_EXTRACTSPLICESITES.out.txt + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } +} \ No newline at end of file diff --git a/modules/nf-core/hisat2/build/tests/main.nf.test.snap b/modules/nf-core/hisat2/build/tests/main.nf.test.snap index c7d364db..0e3b5c57 100644 --- a/modules/nf-core/hisat2/build/tests/main.nf.test.snap +++ b/modules/nf-core/hisat2/build/tests/main.nf.test.snap @@ -1,4 +1,64 @@ { + "test - stub": { + "content": [ + { + "0": [ + + ], + "1": [ + + ], + "index": [ + + ], + "versions": [ + + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-20T17:29:31.567024" + }, + "Should run without failures - stub": { + "content": [ + { + "0": [ + [ + { + "id": "genome" + }, + [ + + ] + ] + ], + "1": [ + "versions.yml:md5,e36ef3cd73d19ccf2378c9358fe942c0" + ], + "index": [ + [ + { + "id": "genome" + }, + [ + + ] + ] + ], + "versions": [ + "versions.yml:md5,e36ef3cd73d19ccf2378c9358fe942c0" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-20T18:18:08.896422" + }, "Should run without failures": { "content": [ { @@ -44,6 +104,10 @@ ] } ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, "timestamp": "2023-10-16T14:42:22.381609786" } -} \ No newline at end of file +} diff --git a/modules/nf-core/hisat2/extractsplicesites/main.nf b/modules/nf-core/hisat2/extractsplicesites/main.nf index b0c8513a..588a9947 100644 --- a/modules/nf-core/hisat2/extractsplicesites/main.nf +++ b/modules/nf-core/hisat2/extractsplicesites/main.nf @@ -28,4 +28,15 @@ process HISAT2_EXTRACTSPLICESITES { hisat2: $VERSION END_VERSIONS """ + + stub: + def VERSION = '2.2.1' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. + """ + touch ${gtf.baseName}.splice_sites.txt + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + hisat2: $VERSION + END_VERSIONS + """ } diff --git a/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test b/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test index 72eb6d53..14129cff 100644 --- a/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test +++ b/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test @@ -32,4 +32,30 @@ nextflow_process { ) } } + + test("test - stub") { + + options "-stub" + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } } diff --git a/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test.snap b/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test.snap index 17f1c8eb..1dcd8af2 100644 --- a/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test.snap +++ b/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test.snap @@ -1,10 +1,47 @@ { + "test - stub": { + "content": [ + { + "0": [ + [ + { + "id": "genome" + }, + "genome.splice_sites.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,eeea7231fe197810659b8bad4133aff2" + ], + "txt": [ + [ + { + "id": "genome" + }, + "genome.splice_sites.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,eeea7231fe197810659b8bad4133aff2" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-20T17:34:13.229903" + }, "Should run without failures": { "content": [ [ "versions.yml:md5,eeea7231fe197810659b8bad4133aff2" ] ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, "timestamp": "2024-01-18T20:56:30.71763" } } \ No newline at end of file diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index ca39fb67..2121492d 100644 --- a/modules/nf-core/multiqc/environment.yml +++ b/modules/nf-core/multiqc/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - bioconda::multiqc=1.21 + - bioconda::multiqc=1.23 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 47ac352f..459dfea5 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -3,14 +3,16 @@ process MULTIQC { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.21--pyhdfd78af_0' : - 'biocontainers/multiqc:1.21--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.23--pyhdfd78af_0' : + 'biocontainers/multiqc:1.23--pyhdfd78af_0' }" input: path multiqc_files, stageAs: "?/*" path(multiqc_config) path(extra_multiqc_config) path(multiqc_logo) + path(replace_names) + path(sample_names) output: path "*multiqc_report.html", emit: report @@ -26,6 +28,8 @@ process MULTIQC { def config = multiqc_config ? "--config $multiqc_config" : '' def extra_config = extra_multiqc_config ? "--config $extra_multiqc_config" : '' def logo = multiqc_logo ? /--cl-config 'custom_logo: "${multiqc_logo}"'/ : '' + def replace = replace_names ? "--replace-names ${replace_names}" : '' + def samples = sample_names ? "--sample-names ${sample_names}" : '' """ multiqc \\ --force \\ @@ -33,6 +37,8 @@ process MULTIQC { $config \\ $extra_config \\ $logo \\ + $replace \\ + $samples \\ . cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index 45a9bc35..382c08cb 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -29,6 +29,19 @@ input: type: file description: Optional logo file for MultiQC pattern: "*.{png}" + - replace_names: + type: file + description: | + Optional two-column sample renaming file. First column a set of + patterns, second column a set of corresponding replacements. Passed via + MultiQC's `--replace-names` option. + pattern: "*.{tsv}" + - sample_names: + type: file + description: | + Optional TSV file with headers, passed to the MultiQC --sample_names + argument. + pattern: "*.{tsv}" output: - report: type: file diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test index f1c4242e..6aa27f4c 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -17,6 +17,8 @@ nextflow_process { input[1] = [] input[2] = [] input[3] = [] + input[4] = [] + input[5] = [] """ } } @@ -41,6 +43,8 @@ nextflow_process { input[1] = Channel.of(file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true)) input[2] = [] input[3] = [] + input[4] = [] + input[5] = [] """ } } @@ -66,6 +70,8 @@ nextflow_process { input[1] = [] input[2] = [] input[3] = [] + input[4] = [] + input[5] = [] """ } } diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap index bfebd802..45e95e5d 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -2,14 +2,14 @@ "multiqc_versions_single": { "content": [ [ - "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" + "versions.yml:md5,87904cd321df21fac35d18f0fc01bb19" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nextflow": "24.04.2" }, - "timestamp": "2024-02-29T08:48:55.657331" + "timestamp": "2024-07-10T12:41:34.562023" }, "multiqc_stub": { "content": [ @@ -17,25 +17,25 @@ "multiqc_report.html", "multiqc_data", "multiqc_plots", - "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" + "versions.yml:md5,87904cd321df21fac35d18f0fc01bb19" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nextflow": "24.04.2" }, - "timestamp": "2024-02-29T08:49:49.071937" + "timestamp": "2024-07-10T11:27:11.933869532" }, "multiqc_versions_config": { "content": [ [ - "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" + "versions.yml:md5,87904cd321df21fac35d18f0fc01bb19" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nextflow": "24.04.2" }, - "timestamp": "2024-02-29T08:49:25.457567" + "timestamp": "2024-07-10T11:26:56.709849369" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test b/modules/nf-core/samtools/flagstat/tests/main.nf.test index 24c3c04b..3b648a37 100644 --- a/modules/nf-core/samtools/flagstat/tests/main.nf.test +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test @@ -11,9 +11,30 @@ nextflow_process { test("BAM") { when { - params { - outdir = "$outputDir" + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + 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) + ]) + """ } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("BAM - stub") { + + options "-stub" + + when { process { """ input[0] = Channel.of([ @@ -28,8 +49,7 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out.flagstat).match("flagstat") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out).match() } ) } } diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap index e9f85efa..23989c61 100644 --- a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap @@ -1,32 +1,72 @@ { - "flagstat": { + "BAM - stub": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" + ], + "flagstat": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" ] - ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-02-12T18:31:37.783927" + "timestamp": "2024-07-22T14:17:28.002887" }, - "versions": { + "BAM": { "content": [ - [ - "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" - ] + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" + ] + ], + "1": [ + "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" + ], + "flagstat": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" + ] + ], + "versions": [ + "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-28T15:41:52.516253882" + "timestamp": "2024-07-22T14:17:13.330971" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test b/modules/nf-core/samtools/idxstats/tests/main.nf.test index a2dcb27c..5fd1fc78 100644 --- a/modules/nf-core/samtools/idxstats/tests/main.nf.test +++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test @@ -11,9 +11,6 @@ nextflow_process { test("bam") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -28,9 +25,29 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out.idxstats).match("idxstats") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out).match() } ) } } -} + + test("bam - stub") { + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + 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) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + }} diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap index 4eacdb90..a5ac8104 100644 --- a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap @@ -1,32 +1,72 @@ { - "versions": { + "bam - stub": { "content": [ - [ - "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" - ] + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" + ], + "idxstats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-28T15:46:46.617989517" + "timestamp": "2024-07-22T14:17:56.180093" }, - "idxstats": { + "bam": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" + ] + ], + "1": [ + "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" + ], + "idxstats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" + ] + ], + "versions": [ + "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" ] - ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-02-12T18:36:41.561026" + "timestamp": "2024-07-22T14:17:41.408704" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/index/main.nf b/modules/nf-core/samtools/index/main.nf index b523c21b..e002585b 100644 --- a/modules/nf-core/samtools/index/main.nf +++ b/modules/nf-core/samtools/index/main.nf @@ -35,10 +35,11 @@ process SAMTOOLS_INDEX { """ stub: + def args = task.ext.args ?: '' + def extension = file(input).getExtension() == 'cram' ? + "crai" : args.contains("-c") ? "csi" : "bai" """ - touch ${input}.bai - touch ${input}.crai - touch ${input}.csi + touch ${input}.${extension} cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/samtools/index/tests/main.nf.test b/modules/nf-core/samtools/index/tests/main.nf.test index bb7756d1..ca34fb5c 100644 --- a/modules/nf-core/samtools/index/tests/main.nf.test +++ b/modules/nf-core/samtools/index/tests/main.nf.test @@ -9,11 +9,7 @@ nextflow_process { tag "samtools/index" test("bai") { - when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -27,18 +23,13 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out.bai).match("bai") }, - { assert snapshot(process.out.versions).match("bai_versions") } + { assert snapshot(process.out).match() } ) } } test("crai") { - when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -52,20 +43,83 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out.crai).match("crai") }, - { assert snapshot(process.out.versions).match("crai_versions") } + { assert snapshot(process.out).match() } ) } } test("csi") { - config "./csi.nextflow.config" when { - params { - outdir = "$outputDir" + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.csi[0][1]).name, + process.out.versions + ).match() } + ) + } + } + + test("bai - stub") { + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("crai - stub") { + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram', checkIfExists: true) + ]) + """ } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("csi - stub") { + options "-stub" + config "./csi.nextflow.config" + + when { process { """ input[0] = Channel.of([ @@ -79,8 +133,7 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert path(process.out.csi.get(0).get(1)).exists() }, - { assert snapshot(process.out.versions).match("csi_versions") } + { assert snapshot(process.out).match() } ) } } diff --git a/modules/nf-core/samtools/index/tests/main.nf.test.snap b/modules/nf-core/samtools/index/tests/main.nf.test.snap index 52756e85..799d199c 100644 --- a/modules/nf-core/samtools/index/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/index/tests/main.nf.test.snap @@ -1,74 +1,250 @@ { - "crai_versions": { + "csi - stub": { "content": [ - [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ] + { + "0": [ + + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ], + "bai": [ + + ], + "crai": [ + + ], + "csi": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-28T15:42:04.203740976" + "timestamp": "2024-07-22T16:51:53.9057" }, - "csi_versions": { + "crai - stub": { "content": [ - [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ] + { + "0": [ + + ], + "1": [ + + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ], + "bai": [ + + ], + "crai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "csi": [ + + ], + "versions": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-28T15:42:09.57475878" + "timestamp": "2024-07-22T16:51:45.931558" }, - "crai": { + "bai - stub": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ], + "bai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "crai": [ + + ], + "csi": [ + + ], + "versions": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" ] - ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-02-12T18:41:38.446424" + "timestamp": "2024-07-22T16:51:34.807525" }, - "bai": { + "csi": { "content": [ + "test.paired_end.sorted.bam.csi", [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" - ] + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-02-12T18:40:46.579747" + "timestamp": "2024-07-22T16:52:55.688799" }, - "bai_versions": { + "crai": { "content": [ - [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ] + { + "0": [ + + ], + "1": [ + + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" + ] + ], + "3": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ], + "bai": [ + + ], + "crai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" + ] + ], + "csi": [ + + ], + "versions": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T16:51:17.609533" + }, + "bai": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ], + "bai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" + ] + ], + "crai": [ + + ], + "csi": [ + + ], + "versions": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-28T15:41:57.929287369" + "timestamp": "2024-07-22T16:51:04.16585" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/sort/main.nf b/modules/nf-core/samtools/sort/main.nf index 596c6f7e..8e019099 100644 --- a/modules/nf-core/samtools/sort/main.nf +++ b/modules/nf-core/samtools/sort/main.nf @@ -50,10 +50,20 @@ process SAMTOOLS_SORT { """ stub: + def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" + def extension = args.contains("--output-fmt sam") ? "sam" : + args.contains("--output-fmt cram") ? "cram" : + "bam" """ - touch ${prefix}.bam - touch ${prefix}.bam.csi + touch ${prefix}.${extension} + if [ "${extension}" == "bam" ]; + then + touch ${prefix}.${extension}.csi + elif [ "${extension}" == "cram" ]; + then + touch ${prefix}.${extension}.crai + fi cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test b/modules/nf-core/samtools/sort/tests/main.nf.test index fb38ed9b..c2ea9c72 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test +++ b/modules/nf-core/samtools/sort/tests/main.nf.test @@ -32,16 +32,16 @@ nextflow_process { { assert process.success }, { assert snapshot( process.out.bam, - process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } } - ).match("test_bam") - } + process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } }, + process.out.versions + ).match()} ) } } test("cram") { - config "./nextflow.config" + config "./nextflow_cram.config" when { process { @@ -62,23 +62,20 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - process.out.bam, - process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } } - ).match("test_cram") - } + process.out.cram.collect { it.collect { it instanceof Map ? it : file(it).name } }, + process.out.crai.collect { it.collect { it instanceof Map ? it : file(it).name } }, + process.out.versions + ).match()} ) } } - test("bam_stub") { + test("bam - stub") { - config "./nextflow.config" options "-stub" + config "./nextflow.config" when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -96,8 +93,35 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(file(process.out.bam[0][1]).name).match("bam_stub_bam") }, - { assert snapshot(process.out.versions).match("bam_stub_versions") } + { assert snapshot(process.out).match() } + ) + } + } + + test("cram - stub") { + + options "-stub" + config "./nextflow_cram.config" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true) + ]) + input[1] = Channel.of([ + [ id:'fasta' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } ) } } diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test.snap b/modules/nf-core/samtools/sort/tests/main.nf.test.snap index 5a27de1d..da38d5d1 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/sort/tests/main.nf.test.snap @@ -7,54 +7,159 @@ "id": "test", "single_end": false }, - "test.sorted.bam:md5,21c992d59615936b99f2ad008aa54400" + "test.sorted.cram" ] + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.cram.crai" + ] + ], + [ + "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-31T08:13:54.512837189" + "timestamp": "2024-07-22T17:19:37.196205" }, - "bam_stub_bam": { + "bam - stub": { "content": [ - "test.sorted.bam" + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "crai": [ + + ], + "cram": [ + + ], + "csi": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-31T07:29:00.761845507" + "timestamp": "2024-07-22T15:54:46.580756" }, - "test_cram": { + "cram - stub": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,22b2093be34a7637f5fbc84272b89d06" - ] - ], - [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam.csi" + { + "0": [ + + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.cram:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + + ], + "4": [ + "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" + ], + "bam": [ + + ], + "crai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "cram": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.cram:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "csi": [ + + ], + "versions": [ + "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" ] - ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-31T09:16:51.924951855" + "timestamp": "2024-07-22T15:57:30.505698" }, - "test_bam": { + "bam": { "content": [ [ [ @@ -73,42 +178,15 @@ }, "test.sorted.bam.csi" ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-05-31T08:28:12.15952312" - }, - "bam_stub_versions": { - "content": [ + ], [ "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-05-31T07:29:00.765038811" - }, - "bam": { - "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,21c992d59615936b99f2ad008aa54400" - ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-31T08:13:48.538030517" + "timestamp": "2024-07-22T15:54:25.872954" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/sort/tests/nextflow_cram.config b/modules/nf-core/samtools/sort/tests/nextflow_cram.config new file mode 100644 index 00000000..3a8c0188 --- /dev/null +++ b/modules/nf-core/samtools/sort/tests/nextflow_cram.config @@ -0,0 +1,8 @@ +process { + + withName: SAMTOOLS_SORT { + ext.prefix = { "${meta.id}.sorted" } + ext.args = "--write-index --output-fmt cram" + } + +} diff --git a/modules/nf-core/samtools/stats/tests/main.nf.test b/modules/nf-core/samtools/stats/tests/main.nf.test index e3d5cb14..28a77db2 100644 --- a/modules/nf-core/samtools/stats/tests/main.nf.test +++ b/modules/nf-core/samtools/stats/tests/main.nf.test @@ -11,9 +11,6 @@ nextflow_process { test("bam") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -37,9 +34,59 @@ nextflow_process { test("cram") { when { - params { - outdir = "$outputDir" + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram.crai', checkIfExists: true) + ]) + input[1] = Channel.of([ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) + """ } + } + + then { + assertAll( + {assert process.success}, + {assert snapshot(process.out).match()} + ) + } + } + + test("bam - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + 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] = [[],[]] + """ + } + } + + then { + assertAll( + {assert process.success}, + {assert snapshot(process.out).match()} + ) + } + } + + test("cram - stub") { + + options "-stub" + + when { process { """ input[0] = Channel.of([ diff --git a/modules/nf-core/samtools/stats/tests/main.nf.test.snap b/modules/nf-core/samtools/stats/tests/main.nf.test.snap index 2747fd6c..3828f378 100644 --- a/modules/nf-core/samtools/stats/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/stats/tests/main.nf.test.snap @@ -29,10 +29,80 @@ } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-28T15:45:24.403941966" + "timestamp": "2024-07-22T14:20:24.885816" + }, + "bam - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" + ], + "stats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T14:20:39.310713" + }, + "cram - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" + ], + "stats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T14:21:04.771199" }, "bam": { "content": [ @@ -64,9 +134,9 @@ } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-28T15:45:06.711251947" + "timestamp": "2024-07-22T14:19:06.645466" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/view/main.nf b/modules/nf-core/samtools/view/main.nf index 38df8576..dc611448 100644 --- a/modules/nf-core/samtools/view/main.nf +++ b/modules/nf-core/samtools/view/main.nf @@ -13,13 +13,15 @@ process SAMTOOLS_VIEW { path qname output: - tuple val(meta), path("*.bam"), emit: bam, optional: true - tuple val(meta), path("*.cram"), emit: cram, optional: true - tuple val(meta), path("*.sam"), emit: sam, optional: true - tuple val(meta), path("*.bai"), emit: bai, optional: true - tuple val(meta), path("*.csi"), emit: csi, optional: true - tuple val(meta), path("*.crai"), emit: crai, optional: true - path "versions.yml", emit: versions + tuple val(meta), path("${prefix}.bam"), emit: bam, optional: true + tuple val(meta), path("${prefix}.cram"), emit: cram, optional: true + tuple val(meta), path("${prefix}.sam"), emit: sam, optional: true + tuple val(meta), path("${prefix}.${file_type}.bai"), emit: bai, optional: true + tuple val(meta), path("${prefix}.${file_type}.csi"), emit: csi, optional: true + tuple val(meta), path("${prefix}.${file_type}.crai"), emit: crai, optional: true + tuple val(meta), path("${prefix}.unselected.${file_type}"), emit: unselected, optional: true + tuple val(meta), path("${prefix}.unselected.${file_type}.{bai,csi,crsi}"), emit: unselected_index, optional: true + path "versions.yml", emit: versions when: task.ext.when == null || task.ext.when @@ -27,13 +29,13 @@ process SAMTOOLS_VIEW { script: def args = task.ext.args ?: '' def args2 = task.ext.args2 ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" def reference = fasta ? "--reference ${fasta}" : "" - def readnames = qname ? "--qname-file ${qname}": "" - def file_type = args.contains("--output-fmt sam") ? "sam" : - args.contains("--output-fmt bam") ? "bam" : - args.contains("--output-fmt cram") ? "cram" : - input.getExtension() + file_type = args.contains("--output-fmt sam") ? "sam" : + args.contains("--output-fmt bam") ? "bam" : + args.contains("--output-fmt cram") ? "cram" : + input.getExtension() + readnames = qname ? "--qname-file ${qname} --output-unselected ${prefix}.unselected.${file_type}": "" if ("$input" == "${prefix}.${file_type}") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" """ samtools \\ @@ -54,14 +56,14 @@ process SAMTOOLS_VIEW { stub: def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" - def file_type = args.contains("--output-fmt sam") ? "sam" : - args.contains("--output-fmt bam") ? "bam" : - args.contains("--output-fmt cram") ? "cram" : - input.getExtension() + prefix = task.ext.prefix ?: "${meta.id}" + file_type = args.contains("--output-fmt sam") ? "sam" : + args.contains("--output-fmt bam") ? "bam" : + args.contains("--output-fmt cram") ? "cram" : + input.getExtension() if ("$input" == "${prefix}.${file_type}") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" - def index = args.contains("--write-index") ? "touch ${prefix}.csi" : "" + def index = args.contains("--write-index") ? "touch ${prefix}.${file_type}.csi" : "" """ touch ${prefix}.${file_type} diff --git a/modules/nf-core/samtools/view/meta.yml b/modules/nf-core/samtools/view/meta.yml index 3dadafae..27be60d0 100644 --- a/modules/nf-core/samtools/view/meta.yml +++ b/modules/nf-core/samtools/view/meta.yml @@ -73,6 +73,15 @@ output: type: file description: optional CRAM file index pattern: "*.{crai}" + # unselected and unselected_index are created when passing a qname + - unselected: + type: file + description: optional file with unselected alignments + pattern: "*.unselected.{bam,cram,sam}" + - unselected_index: + type: file + description: index for the "unselected" file + pattern: "*.unselected.{bai,csi,crai}" - versions: type: file description: File containing software versions diff --git a/modules/nf-core/samtools/view/tests/main.nf.test b/modules/nf-core/samtools/view/tests/main.nf.test index 45a0defb..37b81a91 100644 --- a/modules/nf-core/samtools/view/tests/main.nf.test +++ b/modules/nf-core/samtools/view/tests/main.nf.test @@ -172,6 +172,8 @@ nextflow_process { { assert snapshot(process.out.crai).match("cram_to_bam_index_qname_crai") }, { assert snapshot(process.out.cram).match("cram_to_bam_index_qname_cram") }, { assert snapshot(process.out.sam).match("cram_to_bam_index_qname_sam") }, + { assert snapshot(file(process.out.unselected[0][1]).name).match("cram_to_bam_index_qname_unselected") }, + { assert snapshot(file(process.out.unselected_index[0][1]).name).match("cram_to_bam_index_qname_unselected_csi") }, { assert snapshot(process.out.versions).match("cram_to_bam_index_qname_versions") } ) } diff --git a/modules/nf-core/samtools/view/tests/main.nf.test.snap b/modules/nf-core/samtools/view/tests/main.nf.test.snap index eb0c577c..6bcce9fe 100644 --- a/modules/nf-core/samtools/view/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/view/tests/main.nf.test.snap @@ -355,6 +355,26 @@ }, "timestamp": "2024-02-12T19:38:23.322874" }, + "cram_to_bam_index_qname_unselected": { + "content": [ + "test.unselected.bam" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:23.322874" + }, + "cram_to_bam_index_qname_unselected_csi": { + "content": [ + "test.unselected.bam.csi" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:23.328458" + }, "bam_versions": { "content": [ [ @@ -477,7 +497,7 @@ }, "bam_stub_csi": { "content": [ - "test.csi" + "test.bam.csi" ], "meta": { "nf-test": "0.8.4", diff --git a/modules/nf-core/star/align/main.nf b/modules/nf-core/star/align/main.nf index 8e9c48b1..ae67e004 100644 --- a/modules/nf-core/star/align/main.nf +++ b/modules/nf-core/star/align/main.nf @@ -81,6 +81,8 @@ process STAR_ALIGN { stub: def prefix = task.ext.prefix ?: "${meta.id}" """ + echo "" | gzip > ${prefix}.unmapped_1.fastq.gz + echo "" | gzip > ${prefix}.unmapped_2.fastq.gz touch ${prefix}Xd.out.bam touch ${prefix}.Log.final.out touch ${prefix}.Log.out @@ -89,8 +91,6 @@ process STAR_ALIGN { touch ${prefix}.toTranscriptome.out.bam touch ${prefix}.Aligned.unsort.out.bam touch ${prefix}.Aligned.sortedByCoord.out.bam - touch ${prefix}.unmapped_1.fastq.gz - touch ${prefix}.unmapped_2.fastq.gz touch ${prefix}.tab touch ${prefix}.SJ.out.tab touch ${prefix}.ReadsPerGene.out.tab diff --git a/modules/nf-core/star/align/tests/main.nf.test b/modules/nf-core/star/align/tests/main.nf.test index 6ecd7786..2d9f72dd 100644 --- a/modules/nf-core/star/align/tests/main.nf.test +++ b/modules/nf-core/star/align/tests/main.nf.test @@ -9,27 +9,367 @@ nextflow_process { tag "star/align" tag "star/genomegenerate" - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" + test("homo_sapiens - single_end") { + config "./nextflow.config" + + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + """ + } + } + } + + when { process { """ input[0] = Channel.of([ - [ id:'test_fasta' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true) ] ]) - input[1] = Channel.of([ + input[1] = STAR_GENOMEGENERATE.out.index + input[2] = Channel.of([ [ id:'test_gtf' ], [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) + input[3] = false + input[4] = 'illumina' + input[5] = false """ } } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + file(process.out.log_final[0][1]).name, + file(process.out.log_out[0][1]).name, + file(process.out.log_progress[0][1]).name, + process.out.bam, + process.out.bam_sorted, + process.out.bam_transcript, + process.out.bam_unsorted, + process.out.bedgraph, + process.out.fastq, + process.out.junction, + process.out.read_per_gene_tab, + process.out.sam, + process.out.spl_junc_tab, + process.out.tab, + process.out.wig, + process.out.versions + ).match() } + ) + } } - test("homo_sapiens - single_end") { + test("homo_sapiens - paired_end") { + config "./nextflow.config" + + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + """ + } + } + } + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true) + ] + ]) + input[1] = STAR_GENOMEGENERATE.out.index + input[2] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + input[3] = false + input[4] = 'illumina' + input[5] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + file(process.out.log_final[0][1]).name, + file(process.out.log_out[0][1]).name, + file(process.out.log_progress[0][1]).name, + process.out.bam, + process.out.bam_sorted, + process.out.bam_transcript, + process.out.bam_unsorted, + process.out.bedgraph, + process.out.fastq, + process.out.junction, + process.out.read_per_gene_tab, + process.out.sam, + process.out.spl_junc_tab, + process.out.tab, + process.out.wig, + process.out.versions + ).match() } + ) + } + } + + test("homo_sapiens - paired_end - arriba") { + config "./nextflow.arriba.config" + + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + """ + } + } + } + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true) + ] + ]) + input[1] = STAR_GENOMEGENERATE.out.index + input[2] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + input[3] = false + input[4] = 'illumina' + input[5] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + file(process.out.log_final[0][1]).name, + file(process.out.log_out[0][1]).name, + file(process.out.log_progress[0][1]).name, + process.out.bam, + process.out.bam_sorted, + process.out.bam_transcript, + process.out.bam_unsorted, + process.out.bedgraph, + process.out.fastq, + process.out.junction, + process.out.read_per_gene_tab, + process.out.sam, + process.out.spl_junc_tab, + process.out.tab, + process.out.wig, + process.out.versions + ).match() } + ) + } + } + + test("homo_sapiens - paired_end - starfusion") { + config "./nextflow.starfusion.config" + + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + """ + } + } + } + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true) + ] + ]) + input[1] = STAR_GENOMEGENERATE.out.index + input[2] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + input[3] = false + input[4] = 'illumina' + input[5] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + file(process.out.log_final[0][1]).name, + file(process.out.log_out[0][1]).name, + file(process.out.log_progress[0][1]).name, + process.out.bam, + process.out.bam_sorted, + process.out.bam_transcript, + process.out.bam_unsorted, + process.out.bedgraph, + process.out.fastq, + process.out.junction, + process.out.read_per_gene_tab, + process.out.sam, + process.out.spl_junc_tab, + process.out.tab, + process.out.wig, + process.out.versions + ).match() } + ) + } + } + + test("homo_sapiens - paired_end - multiple") { config "./nextflow.config" + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + """ + } + } + } + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true) + ] + ]) + input[1] = STAR_GENOMEGENERATE.out.index + input[2] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + input[3] = false + input[4] = 'illumina' + input[5] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + file(process.out.log_final[0][1]).name, + file(process.out.log_out[0][1]).name, + file(process.out.log_progress[0][1]).name, + process.out.bam, + process.out.bam_sorted, + process.out.bam_transcript, + process.out.bam_unsorted, + process.out.bedgraph, + process.out.fastq, + process.out.junction, + process.out.read_per_gene_tab, + process.out.sam, + process.out.spl_junc_tab, + process.out.tab, + process.out.wig, + process.out.versions + ).match() } + ) + } + } + + test("homo_sapiens - single_end - stub") { + options "-stub" + config "./nextflow.config" + + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + """ + } + } + } + when { process { """ @@ -52,29 +392,33 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - single_end - log_final") }, - { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - single_end - log_out") }, - { assert snapshot(process.out.bam).match("homo_sapiens - single_end - bam") }, - { assert snapshot(process.out.bam_sorted).match("homo_sapiens - single_end - bam_sorted") }, - { assert snapshot(process.out.bam_transcript).match("homo_sapiens - single_end - bam_transcript") }, - { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - single_end - bam_unsorted") }, - { assert snapshot(process.out.bedgraph).match("homo_sapiens - single_end - bedgraph") }, - { assert snapshot(process.out.fastq).match("homo_sapiens - single_end - fastq") }, - { assert snapshot(process.out.junction).match("homo_sapiens - single_end - junction") }, - { assert snapshot(process.out.log_progress).match("homo_sapiens - single_end - log_progress") }, - { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - single_end - read_per_gene_tab") }, - { assert snapshot(process.out.sam).match("homo_sapiens - single_end - sam") }, - { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - single_end - spl_junc_tab") }, - { assert snapshot(process.out.tab).match("homo_sapiens - single_end - tab") }, - { assert snapshot(process.out.wig).match("homo_sapiens - single_end - wig") }, - { assert snapshot(process.out.versions).match("homo_sapiens - single_end - versions") } + { assert snapshot(process.out).match() } ) } } - test("homo_sapiens - paired_end") { + test("homo_sapiens - paired_end - stub") { + options "-stub" config "./nextflow.config" + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + """ + } + } + } + when { process { """ @@ -100,29 +444,33 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - paired_end - log_final") }, - { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - paired_end - log_out") }, - { assert snapshot(process.out.bam).match("homo_sapiens - paired_end - bam") }, - { assert snapshot(process.out.bam_sorted).match("homo_sapiens - paired_end - bam_sorted") }, - { assert snapshot(process.out.bam_transcript).match("homo_sapiens - paired_end - bam_transcript") }, - { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - paired_end - bam_unsorted") }, - { assert snapshot(process.out.bedgraph).match("homo_sapiens - paired_end - bedgraph") }, - { assert snapshot(process.out.fastq).match("homo_sapiens - paired_end - fastq") }, - { assert snapshot(process.out.junction).match("homo_sapiens - paired_end - junction") }, - { assert snapshot(process.out.log_progress).match("homo_sapiens - paired_end - log_progress") }, - { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - paired_end - read_per_gene_tab") }, - { assert snapshot(process.out.sam).match("homo_sapiens - paired_end - sam") }, - { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - paired_end - spl_junc_tab") }, - { assert snapshot(process.out.tab).match("homo_sapiens - paired_end - tab") }, - { assert snapshot(process.out.wig).match("homo_sapiens - paired_end - wig") }, - { assert snapshot(process.out.versions).match("homo_sapiens - paired_end - versions") } + { assert snapshot(process.out).match() } ) } } - test("homo_sapiens - paired_end - arriba") { + test("homo_sapiens - paired_end - arriba - stub") { + options "-stub" config "./nextflow.arriba.config" + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + """ + } + } + } + when { process { """ @@ -148,29 +496,33 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - paired_end - arriba - log_final") }, - { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - paired_end - arriba - log_out") }, - { assert snapshot(file(process.out.log_progress[0][1]).name).match("homo_sapiens - paired_end - arriba - log_progress") }, - { assert snapshot(process.out.bam).match("homo_sapiens - paired_end - arriba - bam") }, - { assert snapshot(process.out.bam_sorted).match("homo_sapiens - paired_end - arriba - bam_sorted") }, - { assert snapshot(process.out.bam_transcript).match("homo_sapiens - paired_end - arriba - bam_transcript") }, - { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - paired_end - arriba - bam_unsorted") }, - { assert snapshot(process.out.bedgraph).match("homo_sapiens - paired_end - arriba - bedgraph") }, - { assert snapshot(process.out.fastq).match("homo_sapiens - paired_end - arriba - fastq") }, - { assert snapshot(process.out.junction).match("homo_sapiens - paired_end - arriba - junction") }, - { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - paired_end - arriba - read_per_gene_tab") }, - { assert snapshot(process.out.sam).match("homo_sapiens - paired_end - arriba - sam") }, - { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - paired_end - arriba - spl_junc_tab") }, - { assert snapshot(process.out.tab).match("homo_sapiens - paired_end - arriba - tab") }, - { assert snapshot(process.out.wig).match("homo_sapiens - paired_end - arriba - wig") }, - { assert snapshot(process.out.versions).match("homo_sapiens - paired_end - arriba - versions") } + { assert snapshot(process.out).match() } ) } } - test("homo_sapiens - paired_end - starfusion") { + test("homo_sapiens - paired_end - starfusion - stub") { + options "-stub" config "./nextflow.starfusion.config" + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + """ + } + } + } + when { process { """ @@ -196,29 +548,33 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - paired_end - starfusion - log_final") }, - { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - paired_end - starfusion - log_out") }, - { assert snapshot(file(process.out.log_progress[0][1]).name).match("homo_sapiens - paired_end - starfusion - log_progress") }, - { assert snapshot(process.out.bam).match("homo_sapiens - paired_end - starfusion - bam") }, - { assert snapshot(process.out.bam_sorted).match("homo_sapiens - paired_end - starfusion - bam_sorted") }, - { assert snapshot(process.out.bam_transcript).match("homo_sapiens - paired_end - starfusion - bam_transcript") }, - { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - paired_end - starfusion - bam_unsorted") }, - { assert snapshot(process.out.bedgraph).match("homo_sapiens - paired_end - starfusion - bedgraph") }, - { assert snapshot(process.out.fastq).match("homo_sapiens - paired_end - starfusion - fastq") }, - { assert snapshot(process.out.junction).match("homo_sapiens - paired_end - starfusion - junction") }, - { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - paired_end - starfusion - read_per_gene_tab") }, - { assert snapshot(process.out.sam).match("homo_sapiens - paired_end - starfusion - sam") }, - { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - paired_end - starfusion - spl_junc_tab") }, - { assert snapshot(process.out.tab).match("homo_sapiens - paired_end - starfusion - tab") }, - { assert snapshot(process.out.wig).match("homo_sapiens - paired_end - starfusion - wig") }, - { assert snapshot(process.out.versions).match("homo_sapiens - paired_end - starfusion - versions") } + { assert snapshot(process.out).match() } ) } } - test("homo_sapiens - paired_end - multiple") { + test("homo_sapiens - paired_end - multiple - stub") { + options "-stub" config "./nextflow.config" + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test_fasta' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] + ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) + """ + } + } + } + when { process { """ @@ -246,22 +602,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - paired_end - multiple - log_final") }, - { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - paired_end - multiple - log_out") }, - { assert snapshot(file(process.out.log_progress[0][1]).name).match("homo_sapiens - paired_end - multiple - log_progress") }, - { assert snapshot(process.out.bam).match("homo_sapiens - paired_end - multiple - bam") }, - { assert snapshot(process.out.bam_sorted).match("homo_sapiens - paired_end - multiple - bam_sorted") }, - { assert snapshot(process.out.bam_transcript).match("homo_sapiens - paired_end - multiple - bam_transcript") }, - { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - paired_end - multiple - bam_unsorted") }, - { assert snapshot(process.out.bedgraph).match("homo_sapiens - paired_end - multiple - bedgraph") }, - { assert snapshot(process.out.fastq).match("homo_sapiens - paired_end - multiple - fastq") }, - { assert snapshot(process.out.junction).match("homo_sapiens - paired_end - multiple - junction") }, - { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - paired_end - multiple - read_per_gene_tab") }, - { assert snapshot(process.out.sam).match("homo_sapiens - paired_end - multiple - sam") }, - { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - paired_end - multiple - spl_junc_tab") }, - { assert snapshot(process.out.tab).match("homo_sapiens - paired_end - multiple - tab") }, - { assert snapshot(process.out.wig).match("homo_sapiens - paired_end - multiple - wig") }, - { assert snapshot(process.out.versions).match("homo_sapiens - paired_end - multiple - versions") } + { assert snapshot(process.out).match() } ) } } diff --git a/modules/nf-core/star/align/tests/main.nf.test.snap b/modules/nf-core/star/align/tests/main.nf.test.snap index 08edb914..c814eb56 100644 --- a/modules/nf-core/star/align/tests/main.nf.test.snap +++ b/modules/nf-core/star/align/tests/main.nf.test.snap @@ -1,382 +1,1170 @@ { - "homo_sapiens - paired_end - multiple - bam_sorted": { + "homo_sapiens - single_end - stub": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.Aligned.sortedByCoord.out.bam:md5,ab07c21d63ab0a6c07d171d213c81d5a" + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "10": [ + [ + { + "id": "test", + "single_end": true + }, + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "11": [ + [ + { + "id": "test", + "single_end": true + }, + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "12": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "13": [ + [ + { + "id": "test", + "single_end": true + }, + "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "14": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "15": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ], + "4": [ + [ + { + "id": "test", + "single_end": true + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "5": [ + [ + { + "id": "test", + "single_end": true + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "6": [ + [ + { + "id": "test", + "single_end": true + }, + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "7": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "8": [ + [ + { + "id": "test", + "single_end": true + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "9": [ + [ + { + "id": "test", + "single_end": true + }, + [ + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam": [ + [ + { + "id": "test", + "single_end": true + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam_sorted": [ + [ + { + "id": "test", + "single_end": true + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam_transcript": [ + [ + { + "id": "test", + "single_end": true + }, + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "bam_unsorted": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "bedgraph": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "fastq": [ + [ + { + "id": "test", + "single_end": true + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "junction": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_final": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_out": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_progress": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "read_per_gene_tab": [ + [ + { + "id": "test", + "single_end": true + }, + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "sam": [ + [ + { + "id": "test", + "single_end": true + }, + "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "spl_junc_tab": [ + [ + { + "id": "test", + "single_end": true + }, + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "tab": [ + [ + { + "id": "test", + "single_end": true + }, + [ + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions": [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ], + "wig": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ] - ] + } ], - "timestamp": "2023-12-04T18:01:19.968225733" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T15:16:04.712114" }, - "homo_sapiens - paired_end - multiple - wig": { + "homo_sapiens - paired_end - arriba - stub": { "content": [ - [ - - ] + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "10": [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "11": [ + [ + { + "id": "test", + "single_end": false + }, + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "12": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "13": [ + [ + { + "id": "test", + "single_end": false + }, + "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "14": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "15": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ], + "4": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "5": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "6": [ + [ + { + "id": "test", + "single_end": false + }, + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "7": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "8": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "9": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam_sorted": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam_transcript": [ + [ + { + "id": "test", + "single_end": false + }, + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "bam_unsorted": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "bedgraph": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "fastq": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "junction": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_final": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_out": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_progress": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "read_per_gene_tab": [ + [ + { + "id": "test", + "single_end": false + }, + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "sam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "spl_junc_tab": [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "tab": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions": [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ], + "wig": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } ], - "timestamp": "2023-11-23T13:29:01.857804" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T15:16:28.874293" }, - "homo_sapiens - paired_end - arriba - tab": { + "homo_sapiens - single_end": { "content": [ + "test.Log.final.out", + "test.Log.out", + "test.Log.progress.out", [ [ { "id": "test", - "single_end": false + "single_end": true }, - "test.SJ.out.tab:md5,5155c9fd1f787ad6d7d80987fb06219c" + "test.Aligned.sortedByCoord.out.bam:md5,c6cfaccaf91bc7fdabed3cfe236d4535" ] - ] - ], - "timestamp": "2023-12-04T17:56:12.347549723" - }, - "homo_sapiens - single_end - wig": { - "content": [ + ], [ - - ] - ], - "timestamp": "2023-11-23T13:22:55.24701" - }, - "homo_sapiens - paired_end - sam": { - "content": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Aligned.sortedByCoord.out.bam:md5,c6cfaccaf91bc7fdabed3cfe236d4535" + ] + ], [ - ] - ], - "timestamp": "2023-11-23T13:23:33.383818" - }, - "homo_sapiens - paired_end - arriba - versions": { - "content": [ + ], [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" - ] - ], - "timestamp": "2023-12-04T17:56:12.431212643" - }, - "homo_sapiens - paired_end - multiple - bedgraph": { - "content": [ + + ], [ [ { "id": "test", - "single_end": false + "single_end": true }, [ - "test.Signal.Unique.str1.out.bg:md5,d7bf8b70b436ca048a62513e1d0ece3a", - "test.Signal.UniqueMultiple.str1.out.bg:md5,686d58493b9eb445b56ace4d67f76ef6" + "test.Signal.Unique.str1.out.bg:md5,c56fc1472776fb927eaf62d973da5f9a", + "test.Signal.UniqueMultiple.str1.out.bg:md5,e93373cf6f2a2a9506e2efdb260cdd4f" ] ] - ] - ], - "timestamp": "2023-12-04T18:01:20.07119229" - }, - "homo_sapiens - paired_end - read_per_gene_tab": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:23:33.368841" - }, - "homo_sapiens - paired_end - arriba - bedgraph": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:25:07.102537" - }, - "homo_sapiens - single_end - junction": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:22:55.185369" - }, - "homo_sapiens - paired_end - arriba - spl_junc_tab": { - "content": [ + ], + [ + + ], [ [ { "id": "test", - "single_end": false + "single_end": true }, - "test.SJ.out.tab:md5,5155c9fd1f787ad6d7d80987fb06219c" + "test.SJ.out.tab:md5,75a516ab950fb958f40b29996474949c" ] - ] - ], - "timestamp": "2023-12-04T17:56:12.268388251" - }, - "homo_sapiens - single_end - sam": { - "content": [ + ], [ - - ] - ], - "timestamp": "2023-11-23T13:22:55.216183" - }, - "homo_sapiens - paired_end - fastq": { - "content": [ + [ + { + "id": "test", + "single_end": true + }, + "test.SJ.out.tab:md5,75a516ab950fb958f40b29996474949c" + ] + ], [ - ] - ], - "timestamp": "2023-11-23T13:23:33.327236" - }, - "homo_sapiens - single_end - versions": { - "content": [ + ], [ "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" ] ], - "timestamp": "2023-12-04T17:53:26.664210196" - }, - "homo_sapiens - paired_end - multiple - log_out": { - "content": [ - "test.Log.out" - ], - "timestamp": "2023-11-23T13:29:01.022176" - }, - "homo_sapiens - paired_end - arriba - fastq": { - "content": [ - [ - - ] - ], - "timestamp": "2023-11-23T13:25:07.15277" - }, - "homo_sapiens - paired_end - multiple - junction": { - "content": [ - [ - - ] - ], - "timestamp": "2023-11-23T13:29:01.52923" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T18:02:34.35338" }, - "homo_sapiens - paired_end - multiple - spl_junc_tab": { + "homo_sapiens - paired_end": { "content": [ + "test.Log.final.out", + "test.Log.out", + "test.Log.progress.out", [ [ { "id": "test", "single_end": false }, - "test.SJ.out.tab:md5,069877e053714e23010fe4e1c003b4a2" + "test.Aligned.sortedByCoord.out.bam:md5,b9ee1c607e07323bc1652ef3babb543f" ] - ] - ], - "timestamp": "2023-12-04T18:01:20.189486201" - }, - "homo_sapiens - paired_end - starfusion - log_final": { - "content": [ - "test.Log.final.out" - ], - "timestamp": "2023-11-23T13:27:55.905883" - }, - "homo_sapiens - paired_end - starfusion - fastq": { - "content": [ - [ - - ] - ], - "timestamp": "2023-11-23T13:27:56.192302" - }, - "homo_sapiens - paired_end - multiple - sam": { - "content": [ - [ - - ] - ], - "timestamp": "2023-11-23T13:29:01.661837" - }, - "homo_sapiens - paired_end - multiple - log_final": { - "content": [ - "test.Log.final.out" - ], - "timestamp": "2023-11-23T13:29:00.966417" - }, - "homo_sapiens - paired_end - starfusion - bam": { - "content": [ + ], [ [ { "id": "test", "single_end": false }, - "test.Aligned.out.bam:md5,bcad07b838f6762fc01eea52b5cd3f84" + "test.Aligned.sortedByCoord.out.bam:md5,b9ee1c607e07323bc1652ef3babb543f" ] - ] - ], - "timestamp": "2023-12-04T17:59:58.53235164" - }, - "homo_sapiens - paired_end - arriba - junction": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:25:07.202776" - }, - "homo_sapiens - single_end - bedgraph": { - "content": [ + ], + [ + + ], [ [ { "id": "test", - "single_end": true + "single_end": false }, [ - "test.Signal.Unique.str1.out.bg:md5,c56fc1472776fb927eaf62d973da5f9a", - "test.Signal.UniqueMultiple.str1.out.bg:md5,e93373cf6f2a2a9506e2efdb260cdd4f" + "test.Signal.Unique.str1.out.bg:md5,d7bf8b70b436ca048a62513e1d0ece3a", + "test.Signal.UniqueMultiple.str1.out.bg:md5,686d58493b9eb445b56ace4d67f76ef6" ] ] - ] - ], - "timestamp": "2023-12-04T17:53:26.394863748" - }, - "homo_sapiens - paired_end - arriba - read_per_gene_tab": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:25:07.251962" - }, - "homo_sapiens - paired_end - starfusion - bam_sorted": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:27:56.040843" - }, - "homo_sapiens - single_end - bam_unsorted": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:22:55.154172" - }, - "homo_sapiens - paired_end - bam": { - "content": [ + ], + [ + + ], [ [ { "id": "test", "single_end": false }, - "test.Aligned.sortedByCoord.out.bam:md5,b9ee1c607e07323bc1652ef3babb543f" + "test.SJ.out.tab:md5,844af19ab0fc8cd9a3f75228445aca0d" ] - ] - ], - "timestamp": "2023-12-04T17:54:11.934832258" - }, - "homo_sapiens - paired_end - arriba - bam_transcript": { - "content": [ + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,844af19ab0fc8cd9a3f75228445aca0d" + ] + ], [ - ] - ], - "timestamp": "2023-11-23T13:25:06.998817" - }, - "homo_sapiens - paired_end - log_out": { - "content": [ - "test.Log.out" - ], - "timestamp": "2023-11-23T13:23:33.259699" - }, - "homo_sapiens - paired_end - arriba - log_out": { - "content": [ - "test.Log.out" - ], - "timestamp": "2023-11-23T13:25:06.849451" - }, - "homo_sapiens - paired_end - multiple - versions": { - "content": [ + ], [ "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" ] ], - "timestamp": "2023-12-04T18:01:20.393705142" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T18:03:16.701923" }, - "homo_sapiens - paired_end - starfusion - bam_transcript": { + "homo_sapiens - paired_end - multiple - stub": { "content": [ - [ - - ] + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "10": [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "11": [ + [ + { + "id": "test", + "single_end": false + }, + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "12": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "13": [ + [ + { + "id": "test", + "single_end": false + }, + "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "14": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "15": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ], + "4": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "5": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "6": [ + [ + { + "id": "test", + "single_end": false + }, + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "7": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "8": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "9": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam_sorted": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam_transcript": [ + [ + { + "id": "test", + "single_end": false + }, + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "bam_unsorted": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "bedgraph": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "fastq": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "junction": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_final": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_out": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_progress": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "read_per_gene_tab": [ + [ + { + "id": "test", + "single_end": false + }, + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "sam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "spl_junc_tab": [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "tab": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions": [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ], + "wig": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } ], - "timestamp": "2023-11-23T13:27:56.082408" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T15:16:51.360287" }, - "homo_sapiens - paired_end - starfusion - tab": { + "homo_sapiens - paired_end - multiple": { "content": [ + "test.Log.final.out", + "test.Log.out", + "test.Log.progress.out", [ [ { "id": "test", "single_end": false }, - "test.SJ.out.tab:md5,19c3faa1bfa9a0cc5e4c45f17065b53a" + "test.Aligned.sortedByCoord.out.bam:md5,ab07c21d63ab0a6c07d171d213c81d5a" ] - ] - ], - "timestamp": "2023-12-04T17:59:58.818041322" - }, - "homo_sapiens - single_end - fastq": { - "content": [ + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.sortedByCoord.out.bam:md5,ab07c21d63ab0a6c07d171d213c81d5a" + ] + ], [ - ] - ], - "timestamp": "2023-11-23T13:22:55.175307" - }, - "homo_sapiens - paired_end - tab": { - "content": [ + ], + [ + + ], [ [ { "id": "test", "single_end": false }, - "test.SJ.out.tab:md5,844af19ab0fc8cd9a3f75228445aca0d" + [ + "test.Signal.Unique.str1.out.bg:md5,d7bf8b70b436ca048a62513e1d0ece3a", + "test.Signal.UniqueMultiple.str1.out.bg:md5,686d58493b9eb445b56ace4d67f76ef6" + ] ] - ] - ], - "timestamp": "2023-12-04T17:54:12.255481058" - }, - "homo_sapiens - paired_end - starfusion - bedgraph": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:27:56.155413" - }, - "homo_sapiens - single_end - bam_transcript": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:22:55.144852" - }, - "homo_sapiens - paired_end - versions": { - "content": [ + ], [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" - ] - ], - "timestamp": "2023-12-04T17:54:12.343840482" - }, - "homo_sapiens - paired_end - multiple - tab": { - "content": [ + + ], + [ + + ], [ [ { @@ -385,385 +1173,801 @@ }, "test.SJ.out.tab:md5,069877e053714e23010fe4e1c003b4a2" ] - ] - ], - "timestamp": "2023-12-04T18:01:20.291692062" - }, - "homo_sapiens - single_end - bam": { - "content": [ + ], [ [ { "id": "test", - "single_end": true + "single_end": false }, - "test.Aligned.sortedByCoord.out.bam:md5,c6cfaccaf91bc7fdabed3cfe236d4535" + "test.SJ.out.tab:md5,069877e053714e23010fe4e1c003b4a2" ] - ] - ], - "timestamp": "2023-12-04T17:53:26.265642675" - }, - "homo_sapiens - paired_end - arriba - wig": { - "content": [ + ], [ + ], + [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" ] ], - "timestamp": "2023-11-23T13:25:07.444214" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T13:13:28.987438" }, - "homo_sapiens - paired_end - log_progress": { + "homo_sapiens - paired_end - stub": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.progress.out:md5,b2bd061d6cbaaf3d6d3b1fed547f69b8" + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "10": [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "11": [ + [ + { + "id": "test", + "single_end": false + }, + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "12": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "13": [ + [ + { + "id": "test", + "single_end": false + }, + "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "14": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "15": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ], + "4": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "5": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "6": [ + [ + { + "id": "test", + "single_end": false + }, + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "7": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "8": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "9": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam_sorted": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam_transcript": [ + [ + { + "id": "test", + "single_end": false + }, + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "bam_unsorted": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "bedgraph": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "fastq": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "junction": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_final": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_out": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_progress": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "read_per_gene_tab": [ + [ + { + "id": "test", + "single_end": false + }, + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "sam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "spl_junc_tab": [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "tab": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions": [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ], + "wig": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ] - ] - ], - "timestamp": "2023-12-04T17:54:12.126063825" - }, - "homo_sapiens - paired_end - arriba - log_final": { - "content": [ - "test.Log.final.out" - ], - "timestamp": "2023-11-23T13:25:06.829799" - }, - "homo_sapiens - paired_end - bam_unsorted": { - "content": [ - [ - - ] - ], - "timestamp": "2023-11-23T13:23:33.300509" - }, - "homo_sapiens - paired_end - arriba - sam": { - "content": [ - [ - - ] + } ], - "timestamp": "2023-11-23T13:25:07.300383" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T15:16:16.798018" }, - "homo_sapiens - paired_end - multiple - bam": { + "homo_sapiens - paired_end - starfusion": { "content": [ + "test.Log.final.out", + "test.Log.out", + "test.Log.progress.out", [ [ { "id": "test", "single_end": false }, - "test.Aligned.sortedByCoord.out.bam:md5,ab07c21d63ab0a6c07d171d213c81d5a" + "test.Aligned.out.bam:md5,bcad07b838f6762fc01eea52b5cd3f84" ] - ] - ], - "timestamp": "2023-12-04T18:01:19.851247126" - }, - "homo_sapiens - paired_end - multiple - fastq": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:29:01.462257" - }, - "homo_sapiens - single_end - bam_sorted": { - "content": [ - [ - [ - { - "id": "test", - "single_end": true - }, - "test.Aligned.sortedByCoord.out.bam:md5,c6cfaccaf91bc7fdabed3cfe236d4535" - ] - ] - ], - "timestamp": "2023-12-04T17:53:26.335457371" - }, - "homo_sapiens - paired_end - arriba - bam_sorted": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:25:06.94699" - }, - "homo_sapiens - paired_end - starfusion - junction": { - "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.Chimeric.out.junction:md5,c10ef219f4a30e83711b995bc5e40dba" - ] - ] - ], - "timestamp": "2023-12-04T17:59:58.641115828" - }, - "homo_sapiens - single_end - tab": { - "content": [ + ], [ - [ - { - "id": "test", - "single_end": true - }, - "test.SJ.out.tab:md5,75a516ab950fb958f40b29996474949c" - ] - ] - ], - "timestamp": "2023-12-04T17:53:26.580593434" - }, - "homo_sapiens - paired_end - starfusion - versions": { - "content": [ + + ], [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" - ] - ], - "timestamp": "2023-12-04T17:59:58.907317103" - }, - "homo_sapiens - paired_end - multiple - bam_unsorted": { - "content": [ + + ], [ - ] - ], - "timestamp": "2023-11-23T13:29:01.330463" - }, - "homo_sapiens - paired_end - arriba - log_progress": { - "content": [ - "test.Log.progress.out" - ], - "timestamp": "2023-11-23T13:25:06.86866" - }, - "homo_sapiens - paired_end - bedgraph": { - "content": [ + ], [ [ { "id": "test", "single_end": false }, - [ - "test.Signal.Unique.str1.out.bg:md5,d7bf8b70b436ca048a62513e1d0ece3a", - "test.Signal.UniqueMultiple.str1.out.bg:md5,686d58493b9eb445b56ace4d67f76ef6" - ] + "test.Chimeric.out.junction:md5,c10ef219f4a30e83711b995bc5e40dba" ] - ] - ], - "timestamp": "2023-12-04T17:54:12.064121304" - }, - "homo_sapiens - paired_end - starfusion - bam_unsorted": { - "content": [ - [ - - ] - ], - "timestamp": "2023-11-23T13:27:56.118974" - }, - "homo_sapiens - paired_end - starfusion - read_per_gene_tab": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:27:56.264699" - }, - "homo_sapiens - paired_end - multiple - log_progress": { - "content": [ - "test.Log.progress.out" - ], - "timestamp": "2023-11-23T13:29:01.076947" - }, - "homo_sapiens - paired_end - arriba - bam_unsorted": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:25:07.050409" - }, - "homo_sapiens - paired_end - bam_sorted": { - "content": [ + ], [ [ { "id": "test", "single_end": false }, - "test.Aligned.sortedByCoord.out.bam:md5,b9ee1c607e07323bc1652ef3babb543f" + "test.SJ.out.tab:md5,19c3faa1bfa9a0cc5e4c45f17065b53a" ] - ] - ], - "timestamp": "2023-12-04T17:54:12.002180537" - }, - "homo_sapiens - single_end - spl_junc_tab": { - "content": [ + ], [ [ { "id": "test", - "single_end": true + "single_end": false }, - "test.SJ.out.tab:md5,75a516ab950fb958f40b29996474949c" + "test.SJ.out.tab:md5,19c3faa1bfa9a0cc5e4c45f17065b53a" ] + ], + [ + + ], + [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" ] ], - "timestamp": "2023-12-04T17:53:26.50932751" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T13:10:55.371956" }, - "homo_sapiens - paired_end - starfusion - spl_junc_tab": { + "homo_sapiens - paired_end - arriba": { "content": [ + "test.Log.final.out", + "test.Log.out", + "test.Log.progress.out", [ [ { "id": "test", "single_end": false }, - "test.SJ.out.tab:md5,19c3faa1bfa9a0cc5e4c45f17065b53a" + "test.Aligned.out.bam:md5,c1b1747f5873f2d17762725636e891d5" ] - ] - ], - "timestamp": "2023-12-04T17:59:58.731699486" - }, - "homo_sapiens - single_end - log_out": { - "content": [ - "test.Log.out" - ], - "timestamp": "2023-11-23T13:22:55.126286" - }, - "homo_sapiens - paired_end - log_final": { - "content": [ - "test.Log.final.out" - ], - "timestamp": "2023-11-23T13:23:33.253884" - }, - "homo_sapiens - single_end - log_final": { - "content": [ - "test.Log.final.out" - ], - "timestamp": "2023-11-23T13:22:55.11799" - }, - "homo_sapiens - paired_end - bam_transcript": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:23:33.287684" - }, - "homo_sapiens - paired_end - starfusion - log_progress": { - "content": [ - "test.Log.progress.out" - ], - "timestamp": "2023-11-23T13:27:55.971484" - }, - "homo_sapiens - paired_end - multiple - bam_transcript": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:29:01.264176" - }, - "homo_sapiens - paired_end - multiple - read_per_gene_tab": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:29:01.596406" - }, - "homo_sapiens - single_end - read_per_gene_tab": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:22:55.205936" - }, - "homo_sapiens - paired_end - junction": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:23:33.340653" - }, - "homo_sapiens - paired_end - spl_junc_tab": { - "content": [ + ], [ - [ - { - "id": "test", - "single_end": false - }, - "test.SJ.out.tab:md5,844af19ab0fc8cd9a3f75228445aca0d" - ] - ] - ], - "timestamp": "2023-12-04T17:54:12.185730856" - }, - "homo_sapiens - paired_end - starfusion - sam": { - "content": [ + + ], [ - ] - ], - "timestamp": "2023-11-23T13:27:56.300637" - }, - "homo_sapiens - paired_end - arriba - bam": { - "content": [ + ], + [ + + ], [ [ { "id": "test", "single_end": false }, - "test.Aligned.out.bam:md5,c1b1747f5873f2d17762725636e891d5" + "test.SJ.out.tab:md5,5155c9fd1f787ad6d7d80987fb06219c" ] - ] - ], - "timestamp": "2023-12-04T17:56:12.190560178" - }, - "homo_sapiens - single_end - log_progress": { - "content": [ + ], [ [ { "id": "test", - "single_end": true + "single_end": false }, - "test.Log.progress.out:md5,b2bd061d6cbaaf3d6d3b1fed547f69b8" + "test.SJ.out.tab:md5,5155c9fd1f787ad6d7d80987fb06219c" ] - ] - ], - "timestamp": "2023-12-04T17:53:26.450352138" - }, - "homo_sapiens - paired_end - starfusion - wig": { - "content": [ + ], [ - ] - ], - "timestamp": "2023-11-23T13:27:56.422018" - }, - "homo_sapiens - paired_end - wig": { - "content": [ + ], [ - + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" ] ], - "timestamp": "2023-11-23T13:23:33.429457" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T13:05:10.7534" }, - "homo_sapiens - paired_end - starfusion - log_out": { + "homo_sapiens - paired_end - starfusion - stub": { "content": [ - "test.Log.out" + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "10": [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "11": [ + [ + { + "id": "test", + "single_end": false + }, + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "12": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "13": [ + [ + { + "id": "test", + "single_end": false + }, + "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "14": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "15": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ], + "4": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "5": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "6": [ + [ + { + "id": "test", + "single_end": false + }, + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "7": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "8": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "9": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam_sorted": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "bam_transcript": [ + [ + { + "id": "test", + "single_end": false + }, + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "bam_unsorted": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "bedgraph": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "fastq": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "junction": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_final": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_out": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log_progress": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "read_per_gene_tab": [ + [ + { + "id": "test", + "single_end": false + }, + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "sam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "spl_junc_tab": [ + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "tab": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions": [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ], + "wig": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } ], - "timestamp": "2023-11-23T13:27:55.93945" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T15:16:40.64399" } } \ No newline at end of file diff --git a/modules/nf-core/star/genomegenerate/tests/main.nf.test b/modules/nf-core/star/genomegenerate/tests/main.nf.test index c17c8ba4..4d619c47 100644 --- a/modules/nf-core/star/genomegenerate/tests/main.nf.test +++ b/modules/nf-core/star/genomegenerate/tests/main.nf.test @@ -28,15 +28,15 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("fasta_gtf_index") }, - { assert snapshot(process.out.versions).match("fasta_gtf_versions") } + { assert snapshot( + file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString(), + process.out.versions) + .match() } ) } } - test("fasta_gtf_stub") { - - options '-stub' + test("fasta") { when { process { @@ -45,10 +45,7 @@ nextflow_process { [ id:'test_fasta' ], [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) + input[1] = Channel.of([ [], [] ]) """ } } @@ -56,13 +53,17 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("fasta_gtf_stub_index") }, - { assert snapshot(process.out.versions).match("fasta_gtf_stub_versions") } + { assert snapshot( + file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString(), + process.out.versions + ).match() } ) } } - test("fasta") { + test("fasta_gtf_stub") { + + options '-stub' when { process { @@ -71,7 +72,10 @@ nextflow_process { [ id:'test_fasta' ], [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] ]) - input[1] = Channel.of([ [], [] ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) """ } } @@ -79,11 +83,9 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("fasta_index") }, - { assert snapshot(process.out.versions).match("fasta_versions") } + { assert snapshot(process.out).match() } ) } - } test("fasta_stub") { @@ -105,11 +107,8 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("fasta_stub_index") }, - { assert snapshot(process.out.versions).match("fasta_stub_versions") } + { assert snapshot(process.out).match() } ) } - } - } diff --git a/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap b/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap index 5653d6e6..207f4b4f 100644 --- a/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap +++ b/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap @@ -1,90 +1,148 @@ { - "fasta_gtf_versions": { + "fasta_gtf": { "content": [ + "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, exonGeTrInfo.tab, exonInfo.tab, geneInfo.tab, genomeParameters.txt, sjdbInfo.txt, sjdbList.fromGTF.out.tab, sjdbList.out.tab, transcriptInfo.tab]", [ "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-02-01T15:54:31.798555" + "timestamp": "2024-07-22T14:55:35.478401" }, - "fasta_stub_versions": { + "fasta_gtf_stub": { "content": [ - [ - "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" - }, - "timestamp": "2024-02-01T15:55:07.521209" - }, - "fasta_gtf_stub_index": { - "content": [ - "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, exonGeTrInfo.tab, exonInfo.tab, geneInfo.tab, genomeParameters.txt, sjdbInfo.txt, sjdbList.fromGTF.out.tab, sjdbList.out.tab, transcriptInfo.tab]" - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" - }, - "timestamp": "2024-02-01T15:54:46.478098" - }, - "fasta_gtf_stub_versions": { - "content": [ - [ - "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" - ] + { + "0": [ + [ + { + "id": "test_fasta" + }, + [ + "Genome:md5,d41d8cd98f00b204e9800998ecf8427e", + "Log.out:md5,d41d8cd98f00b204e9800998ecf8427e", + "SA:md5,d41d8cd98f00b204e9800998ecf8427e", + "SAindex:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrName.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrNameLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrStart.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "exonGeTrInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "exonInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "geneInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "genomeParameters.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "sjdbInfo.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "sjdbList.fromGTF.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "sjdbList.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "transcriptInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "1": [ + "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" + ], + "index": [ + [ + { + "id": "test_fasta" + }, + [ + "Genome:md5,d41d8cd98f00b204e9800998ecf8427e", + "Log.out:md5,d41d8cd98f00b204e9800998ecf8427e", + "SA:md5,d41d8cd98f00b204e9800998ecf8427e", + "SAindex:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrName.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrNameLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrStart.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "exonGeTrInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "exonInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "geneInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "genomeParameters.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "sjdbInfo.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "sjdbList.fromGTF.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "sjdbList.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", + "transcriptInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions": [ + "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-02-01T15:54:46.491657" + "timestamp": "2024-07-22T14:55:57.247585" }, - "fasta_index": { + "fasta_stub": { "content": [ - "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, genomeParameters.txt]" + { + "0": [ + [ + { + "id": "test_fasta" + }, + [ + "Genome:md5,d41d8cd98f00b204e9800998ecf8427e", + "Log.out:md5,d41d8cd98f00b204e9800998ecf8427e", + "SA:md5,d41d8cd98f00b204e9800998ecf8427e", + "SAindex:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrName.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrNameLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrStart.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "genomeParameters.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "1": [ + "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" + ], + "index": [ + [ + { + "id": "test_fasta" + }, + [ + "Genome:md5,d41d8cd98f00b204e9800998ecf8427e", + "Log.out:md5,d41d8cd98f00b204e9800998ecf8427e", + "SA:md5,d41d8cd98f00b204e9800998ecf8427e", + "SAindex:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrName.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrNameLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "chrStart.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "genomeParameters.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions": [ + "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-02-01T15:54:57.552329" + "timestamp": "2024-07-22T14:56:07.01742" }, - "fasta_versions": { + "fasta": { "content": [ + "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, genomeParameters.txt]", [ "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" - }, - "timestamp": "2024-02-01T15:54:57.560541" - }, - "fasta_gtf_index": { - "content": [ - "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, exonGeTrInfo.tab, exonInfo.tab, geneInfo.tab, genomeParameters.txt, sjdbInfo.txt, sjdbList.fromGTF.out.tab, sjdbList.out.tab, transcriptInfo.tab]" - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" - }, - "timestamp": "2024-02-01T15:54:31.786814" - }, - "fasta_stub_index": { - "content": [ - "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, genomeParameters.txt]" - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-02-01T15:55:07.517472" + "timestamp": "2024-07-22T14:55:45.48784" } } \ No newline at end of file diff --git a/modules/nf-core/stringtie/stringtie/tests/main.nf.test b/modules/nf-core/stringtie/stringtie/tests/main.nf.test index 00efe8f1..2204e849 100644 --- a/modules/nf-core/stringtie/stringtie/tests/main.nf.test +++ b/modules/nf-core/stringtie/stringtie/tests/main.nf.test @@ -3,6 +3,7 @@ nextflow_process { name "Test Process STRINGTIE_STRINGTIE" script "../main.nf" process "STRINGTIE_STRINGTIE" + config "./nextflow.config" tag "modules" tag "modules_nfcore" tag "stringtie" @@ -10,8 +11,6 @@ nextflow_process { test("sarscov2 [bam] - forward strandedness") { - config "./nextflow.config" - when { process { """ @@ -27,17 +26,17 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.transcript_gtf).match("fs_transcript_gtf") }, - { assert snapshot(process.out.abundance).match("fs_abundance") }, - { assert snapshot(process.out.versions).match("fs_versions") } + { assert snapshot( + process.out.abundance, + process.out.transcript_gtf, + process.out.versions + ).match() } ) } } test("sarscov2 [bam] - forward strandedness + reference annotation") { - config "./nextflow.config" - when { process { """ @@ -53,18 +52,18 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.transcript_gtf).match("fs_gtf_transcript_gtf") }, - { assert snapshot(process.out.abundance).match("fs_gtf_abundance") }, - { assert snapshot(process.out.ballgown).match("fs_gtf_ballgown") }, - { assert snapshot(process.out.versions).match("fs_gtf_versions") } + { assert snapshot( + process.out.abundance, + process.out.ballgown, + process.out.transcript_gtf, + process.out.versions + ).match() } ) } } test("sarscov2 [bam] - reverse strandedness") { - config "./nextflow.config" - when { process { """ @@ -80,16 +79,117 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.transcript_gtf).match("rs_transcript_gtf") }, - { assert snapshot(process.out.abundance).match("rs_abundance") }, - { assert snapshot(process.out.versions).match("rs_versions") } + { assert snapshot( + process.out.abundance, + process.out.transcript_gtf, + process.out.versions + ).match() } ) } } test("sarscov2 [bam] - reverse strandedness + reference annotation") { - config "./nextflow.config" + when { + process { + """ + input[0] = [ + [ id:'test', strandedness:'reverse' ], // meta map + [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam", checkIfExists: true) ] + ] + input[1] = file(params.modules_testdata_base_path + "genomics/sarscov2/genome/genome.gtf", checkIfExists: true) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.abundance, + process.out.ballgown, + process.out.transcript_gtf, + process.out.versions + ).match() } + ) + } + } + + test("sarscov2 [bam] - forward strandedness - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test', strandedness:'forward' ], // meta map + [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam", checkIfExists: true) ] + ] + input[1] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 [bam] - forward strandedness + reference annotation - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test', strandedness:'forward' ], // meta map + [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam", checkIfExists: true) ] + ] + input[1] = file(params.modules_testdata_base_path + "genomics/sarscov2/genome/genome.gtf", checkIfExists: true) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 [bam] - reverse strandedness - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test', strandedness:'reverse' ], // meta map + [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam", checkIfExists: true) ] + ] + input[1] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 [bam] - reverse strandedness + reference annotation - stub") { + + options "-stub" when { process { @@ -106,10 +206,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.transcript_gtf).match("rs_gtf_transcript_gtf") }, - { assert snapshot(process.out.abundance).match("rs_gtf_abundance") }, - { assert snapshot(process.out.ballgown).match("rs_gtf_ballgown") }, - { assert snapshot(process.out.versions).match("rs_gtf_versions") } + { assert snapshot(process.out).match() } ) } } diff --git a/modules/nf-core/stringtie/stringtie/tests/main.nf.test.snap b/modules/nf-core/stringtie/stringtie/tests/main.nf.test.snap index bf751636..124dd4cb 100644 --- a/modules/nf-core/stringtie/stringtie/tests/main.nf.test.snap +++ b/modules/nf-core/stringtie/stringtie/tests/main.nf.test.snap @@ -1,5 +1,5 @@ { - "fs_abundance": { + "sarscov2 [bam] - forward strandedness + reference annotation": { "content": [ [ [ @@ -7,49 +7,44 @@ "id": "test", "strandedness": "forward" }, - "test.gene.abundance.txt:md5,d6f5c8cadb8458f1df0427cf790246e3" + "test.gene.abundance.txt:md5,7d8bce7f2a922e367cedccae7267c22e" ] - ] - ], - "timestamp": "2023-11-23T13:55:41.032044613" - }, - "fs_transcript_gtf": { - "content": [ + ], [ [ { "id": "test", "strandedness": "forward" }, - "test.transcripts.gtf:md5,569137af5be452413086b50653a97203" + [ + "e2t.ctab:md5,e981c0038295ae54b63cedb1083f1540", + "e_data.ctab:md5,6b4cf69bc03f3f69890f972a0e8b7471", + "i2t.ctab:md5,8a117c8aa4334b4c2d4711932b006fb4", + "i_data.ctab:md5,be3abe09740603213f83d50dcf81427f", + "t_data.ctab:md5,3b66c065da73ae0dd41cc332eff6a818" + ] ] - ] - ], - "timestamp": "2023-11-23T13:55:41.017978904" - }, - "rs_abundance": { - "content": [ + ], [ [ { "id": "test", - "strandedness": "reverse" + "strandedness": "forward" }, - "test.gene.abundance.txt:md5,d6f5c8cadb8458f1df0427cf790246e3" + "test.transcripts.gtf:md5,f56cf8aba2c4a5673bc7963ba5f12d04" ] - ] - ], - "timestamp": "2023-11-23T13:56:13.601112933" - }, - "fs_gtf_versions": { - "content": [ + ], [ "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" ] ], - "timestamp": "2023-11-23T13:56:00.523797974" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T12:33:44.299962" }, - "fs_gtf_transcript_gtf": { + "sarscov2 [bam] - forward strandedness": { "content": [ [ [ @@ -57,50 +52,395 @@ "id": "test", "strandedness": "forward" }, - "test.transcripts.gtf:md5,f56cf8aba2c4a5673bc7963ba5f12d04" + "test.gene.abundance.txt:md5,d6f5c8cadb8458f1df0427cf790246e3" + ] + ], + [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.transcripts.gtf:md5,569137af5be452413086b50653a97203" ] + ], + [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" ] ], - "timestamp": "2023-11-23T13:56:00.475164879" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T12:33:35.177738" }, - "rs_versions": { + "sarscov2 [bam] - forward strandedness - stub": { "content": [ - [ - "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" - ] + { + "0": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" + ], + "abundance": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "ballgown": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "coverage_gtf": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "transcript_gtf": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" + ] + } ], - "timestamp": "2023-11-23T13:56:13.623892691" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T12:36:32.885078" }, - "rs_gtf_transcript_gtf": { + "sarscov2 [bam] - forward strandedness + reference annotation - stub": { "content": [ - [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.transcripts.gtf:md5,bb346053a8c156b803b055133376c7fa" + { + "0": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" + ], + "abundance": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "ballgown": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "coverage_gtf": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "transcript_gtf": [ + [ + { + "id": "test", + "strandedness": "forward" + }, + "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" ] - ] + } ], - "timestamp": "2023-11-23T13:56:22.693599559" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T12:36:43.325777" }, - "fs_gtf_abundance": { + "sarscov2 [bam] - reverse strandedness + reference annotation - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" + ], + "abundance": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "ballgown": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "coverage_gtf": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "transcript_gtf": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T12:37:06.085936" + }, + "sarscov2 [bam] - reverse strandedness - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" + ], + "abundance": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "ballgown": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "coverage_gtf": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "transcript_gtf": [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T12:36:53.837578" + }, + "sarscov2 [bam] - reverse strandedness + reference annotation": { "content": [ [ [ { "id": "test", - "strandedness": "forward" + "strandedness": "reverse" }, - "test.gene.abundance.txt:md5,7d8bce7f2a922e367cedccae7267c22e" + "test.gene.abundance.txt:md5,7385b870b955dae2c2ab78a70cf05cce" ] - ] - ], - "timestamp": "2023-11-23T13:56:00.482135418" - }, - "rs_gtf_ballgown": { - "content": [ + ], [ [ { @@ -115,72 +455,54 @@ "t_data.ctab:md5,3b66c065da73ae0dd41cc332eff6a818" ] ] - ] - ], - "timestamp": "2023-11-23T13:56:22.715698347" - }, - "rs_transcript_gtf": { - "content": [ + ], [ [ { "id": "test", "strandedness": "reverse" }, - "test.transcripts.gtf:md5,31c34aec2bf36bb0ea3c16c2afeeeb1f" + "test.transcripts.gtf:md5,bb346053a8c156b803b055133376c7fa" ] - ] - ], - "timestamp": "2023-11-23T13:56:13.590054035" - }, - "rs_gtf_versions": { - "content": [ + ], [ "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" ] ], - "timestamp": "2023-11-23T13:56:22.725513476" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T12:34:03.114695" }, - "fs_gtf_ballgown": { + "sarscov2 [bam] - reverse strandedness": { "content": [ [ [ { "id": "test", - "strandedness": "forward" + "strandedness": "reverse" }, - [ - "e2t.ctab:md5,e981c0038295ae54b63cedb1083f1540", - "e_data.ctab:md5,6b4cf69bc03f3f69890f972a0e8b7471", - "i2t.ctab:md5,8a117c8aa4334b4c2d4711932b006fb4", - "i_data.ctab:md5,be3abe09740603213f83d50dcf81427f", - "t_data.ctab:md5,3b66c065da73ae0dd41cc332eff6a818" - ] + "test.gene.abundance.txt:md5,d6f5c8cadb8458f1df0427cf790246e3" ] - ] - ], - "timestamp": "2023-11-23T13:56:00.494299817" - }, - "fs_versions": { - "content": [ - [ - "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" - ] - ], - "timestamp": "2023-11-23T13:55:41.049417582" - }, - "rs_gtf_abundance": { - "content": [ + ], [ [ { "id": "test", "strandedness": "reverse" }, - "test.gene.abundance.txt:md5,7385b870b955dae2c2ab78a70cf05cce" + "test.transcripts.gtf:md5,31c34aec2bf36bb0ea3c16c2afeeeb1f" ] + ], + [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" ] ], - "timestamp": "2023-11-23T13:56:22.701059059" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T12:33:52.874479" } -} +} \ No newline at end of file diff --git a/modules/nf-core/trimgalore/main.nf b/modules/nf-core/trimgalore/main.nf index 24ead871..0e2f3290 100644 --- a/modules/nf-core/trimgalore/main.nf +++ b/modules/nf-core/trimgalore/main.nf @@ -72,4 +72,25 @@ process TRIMGALORE { END_VERSIONS """ } + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + if (meta.single_end) { + output_command = "echo '' | gzip > ${prefix}_trimmed.fq.gz ;" + output_command += "touch ${prefix}.fastq.gz_trimming_report.txt" + } else { + output_command = "echo '' | gzip > ${prefix}_1_trimmed.fq.gz ;" + output_command += "touch ${prefix}_1.fastq.gz_trimming_report.txt ;" + output_command += "echo '' | gzip > ${prefix}_2_trimmed.fq.gz ;" + output_command += "touch ${prefix}_2.fastq.gz_trimming_report.txt" + } + """ + ${output_command} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + trimgalore: \$(echo \$(trim_galore --version 2>&1) | sed 's/^.*version //; s/Last.*\$//') + cutadapt: \$(cutadapt --version) + END_VERSIONS + """ } diff --git a/modules/nf-core/trimgalore/tests/main.nf.test b/modules/nf-core/trimgalore/tests/main.nf.test index 43904ac3..2a3dbbb0 100644 --- a/modules/nf-core/trimgalore/tests/main.nf.test +++ b/modules/nf-core/trimgalore/tests/main.nf.test @@ -44,6 +44,28 @@ nextflow_process { } } + test("test_trimgalore_single_end - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/fastq/test_1.fastq.gz", checkIfExists: true) ] + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + test("test_trimgalore_paired_end") { when { @@ -100,4 +122,29 @@ nextflow_process { ) } } + + test("test_trimgalore_paired_end - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/fastq/test_1.fastq.gz", checkIfExists: true), + file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/fastq/test_2.fastq.gz", checkIfExists: true) + ] + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } } diff --git a/modules/nf-core/trimgalore/tests/main.nf.test.snap b/modules/nf-core/trimgalore/tests/main.nf.test.snap index 082c5500..6cb31c9f 100644 --- a/modules/nf-core/trimgalore/tests/main.nf.test.snap +++ b/modules/nf-core/trimgalore/tests/main.nf.test.snap @@ -11,6 +11,160 @@ }, "timestamp": "2024-02-29T16:33:20.401347" }, + "test_trimgalore_single_end - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": true + }, + "test.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + + ], + "3": [ + + ], + "4": [ + + ], + "5": [ + "versions.yml:md5,47d966cbb31c80eb8f7fe860d55659b7" + ], + "html": [ + + ], + "log": [ + [ + { + "id": "test", + "single_end": true + }, + "test.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "unpaired": [ + + ], + "versions": [ + "versions.yml:md5,47d966cbb31c80eb8f7fe860d55659b7" + ], + "zip": [ + + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T10:27:44.964166" + }, + "test_trimgalore_paired_end - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "test_2.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "2": [ + + ], + "3": [ + + ], + "4": [ + + ], + "5": [ + "versions.yml:md5,47d966cbb31c80eb8f7fe860d55659b7" + ], + "html": [ + + ], + "log": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "test_2.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "reads": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "unpaired": [ + + ], + "versions": [ + "versions.yml:md5,47d966cbb31c80eb8f7fe860d55659b7" + ], + "zip": [ + + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-21T10:28:07.611496" + }, "test_trimgalore_paired_end": { "content": [ [ From 802768638db5ea81aec179a46d35fff17f8dd9a8 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Tue, 6 Aug 2024 17:43:44 +0200 Subject: [PATCH 456/491] Revert "updating nf-core modules" This reverts commit 4cbb345872ab8777f5b26f351f6982a201b680ed. --- modules.json | 56 +- modules/nf-core/bioawk/main.nf | 11 +- modules/nf-core/bowtie/align/environment.yml | 1 - modules/nf-core/bowtie/align/main.nf | 35 +- modules/nf-core/bowtie/align/meta.yml | 21 +- .../nf-core/bowtie/align/tests/main.nf.test | 129 - .../bowtie/align/tests/main.nf.test.snap | 192 -- modules/nf-core/bowtie/align/tests/tags.yml | 2 - modules/nf-core/bowtie/build/main.nf | 32 +- modules/nf-core/bowtie/build/meta.yml | 12 +- .../nf-core/bowtie/build/tests/main.nf.test | 57 - .../bowtie/build/tests/main.nf.test.snap | 96 - modules/nf-core/bowtie/build/tests/tags.yml | 2 - .../nf-core/bowtie2/align/tests/main.nf.test | 90 +- modules/nf-core/cat/cat/main.nf | 1 + modules/nf-core/cat/cat/tests/main.nf.test | 27 +- .../nf-core/cat/cat/tests/main.nf.test.snap | 74 +- modules/nf-core/cat/fastq/main.nf | 10 +- modules/nf-core/cat/fastq/tests/main.nf.test | 136 +- .../nf-core/cat/fastq/tests/main.nf.test.snap | 207 -- .../templates/dumpsoftwareversions.py | 1 + .../custom/tx2gene/templates/tx2gene.py | 24 +- .../nf-core/custom/tx2gene/tests/main.nf.test | 45 +- .../custom/tx2gene/tests/main.nf.test.snap | 96 +- modules/nf-core/fastqc/tests/main.nf.test | 225 +- .../nf-core/fastqc/tests/main.nf.test.snap | 370 +-- modules/nf-core/hisat2/align/main.nf | 19 - .../nf-core/hisat2/align/tests/main.nf.test | 202 -- .../hisat2/align/tests/main.nf.test.snap | 338 +-- modules/nf-core/hisat2/build/main.nf | 11 - .../nf-core/hisat2/build/tests/main.nf.test | 47 +- .../hisat2/build/tests/main.nf.test.snap | 66 +- .../nf-core/hisat2/extractsplicesites/main.nf | 11 - .../extractsplicesites/tests/main.nf.test | 26 - .../tests/main.nf.test.snap | 37 - modules/nf-core/multiqc/environment.yml | 2 +- modules/nf-core/multiqc/main.nf | 10 +- modules/nf-core/multiqc/meta.yml | 13 - modules/nf-core/multiqc/tests/main.nf.test | 6 - .../nf-core/multiqc/tests/main.nf.test.snap | 18 +- .../samtools/flagstat/tests/main.nf.test | 28 +- .../samtools/flagstat/tests/main.nf.test.snap | 78 +- .../samtools/idxstats/tests/main.nf.test | 29 +- .../samtools/idxstats/tests/main.nf.test.snap | 78 +- modules/nf-core/samtools/index/main.nf | 7 +- .../nf-core/samtools/index/tests/main.nf.test | 87 +- .../samtools/index/tests/main.nf.test.snap | 264 +- modules/nf-core/samtools/sort/main.nf | 14 +- .../nf-core/samtools/sort/tests/main.nf.test | 54 +- .../samtools/sort/tests/main.nf.test.snap | 202 +- .../samtools/sort/tests/nextflow_cram.config | 8 - .../nf-core/samtools/stats/tests/main.nf.test | 57 +- .../samtools/stats/tests/main.nf.test.snap | 82 +- modules/nf-core/samtools/view/main.nf | 40 +- modules/nf-core/samtools/view/meta.yml | 9 - .../nf-core/samtools/view/tests/main.nf.test | 2 - .../samtools/view/tests/main.nf.test.snap | 22 +- modules/nf-core/star/align/main.nf | 4 +- modules/nf-core/star/align/tests/main.nf.test | 523 +--- .../star/align/tests/main.nf.test.snap | 2288 ++++------------- .../star/genomegenerate/tests/main.nf.test | 39 +- .../genomegenerate/tests/main.nf.test.snap | 182 +- .../stringtie/stringtie/tests/main.nf.test | 139 +- .../stringtie/tests/main.nf.test.snap | 504 +--- modules/nf-core/trimgalore/main.nf | 21 - modules/nf-core/trimgalore/tests/main.nf.test | 47 - .../trimgalore/tests/main.nf.test.snap | 154 -- 67 files changed, 1405 insertions(+), 6315 deletions(-) delete mode 100644 modules/nf-core/bowtie/align/tests/main.nf.test delete mode 100644 modules/nf-core/bowtie/align/tests/main.nf.test.snap delete mode 100644 modules/nf-core/bowtie/align/tests/tags.yml delete mode 100644 modules/nf-core/bowtie/build/tests/main.nf.test delete mode 100644 modules/nf-core/bowtie/build/tests/main.nf.test.snap delete mode 100644 modules/nf-core/bowtie/build/tests/tags.yml delete mode 100644 modules/nf-core/samtools/sort/tests/nextflow_cram.config diff --git a/modules.json b/modules.json index 6b2ae568..35714771 100644 --- a/modules.json +++ b/modules.json @@ -35,7 +35,7 @@ }, "bioawk": { "branch": "master", - "git_sha": "dee3479f3b4a828df6052d318403d2b6a87b2d2e", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": [ "modules" ], @@ -43,21 +43,21 @@ }, "bowtie/align": { "branch": "master", - "git_sha": "54381508775905f1ecd4fc0dea3fc2f07c78d1c6", + "git_sha": "3c77ca9aac783e76c3614a06db3bfe4fef619bde", "installed_by": [ "modules" ] }, "bowtie/build": { "branch": "master", - "git_sha": "54381508775905f1ecd4fc0dea3fc2f07c78d1c6", + "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", "installed_by": [ "modules" ] }, "bowtie2/align": { "branch": "master", - "git_sha": "9bfc81874554e87740bcb3e5e07acf0a153c9ecb", + "git_sha": "e4bad511789f16d0df39ee306b2cd50418365048", "installed_by": [ "modules" ] @@ -71,21 +71,21 @@ }, "bwa/index": { "branch": "master", - "git_sha": "e0ff65e1fb313677de09f5f477ae3da30ce19b7b", + "git_sha": "086fa66260595e123b0ea47a6512539b72a9afa3", "installed_by": [ "modules" ] }, "cat/cat": { "branch": "master", - "git_sha": "5bb8ca085e17549e185e1823495ab8d20727a805", + "git_sha": "9437e6053dccf4aafa022bfd6e7e9de67e625af8", "installed_by": [ "modules" ] }, "cat/fastq": { "branch": "master", - "git_sha": "1ceaa8ba4d0fd886dbca0e545815d905b7407de7", + "git_sha": "4fc983ad0b30e6e32696fa7d980c76c7bfe1c03e", "installed_by": [ "modules" ] @@ -120,7 +120,7 @@ }, "custom/dumpsoftwareversions": { "branch": "master", - "git_sha": "82024cf6325d2ee194e7f056d841ecad2f6856e9", + "git_sha": "de45447d060b8c8b98575bc637a4a575fd0638e1", "installed_by": [ "modules" ] @@ -134,14 +134,14 @@ }, "custom/tx2gene": { "branch": "master", - "git_sha": "4e5f4687318f24ba944a13609d3ea6ebd890737d", + "git_sha": "ec155021a9104441bf6a9bae3b55d1b5b0bfdb3a", "installed_by": [ "modules" ] }, "fastqc": { "branch": "master", - "git_sha": "46eca555142d6e597729fcb682adcc791796f514", + "git_sha": "285a50500f9e02578d90b3ce6382ea3c30216acd", "installed_by": [ "modules" ] @@ -155,28 +155,28 @@ }, "gnu/sort": { "branch": "master", - "git_sha": "a3cc42943548378b726610f45bb5a79ab3f0b633", + "git_sha": "ca199cfe5aa4f1ea3c41302158f0af2cfaa58957", "installed_by": [ "modules" ] }, "hisat2/align": { "branch": "master", - "git_sha": "2c6b1144ed58b6184ad58fc4e6b6a90219b4bf4f", + "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", "installed_by": [ "modules" ] }, "hisat2/build": { "branch": "master", - "git_sha": "2c6b1144ed58b6184ad58fc4e6b6a90219b4bf4f", + "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", "installed_by": [ "modules" ] }, "hisat2/extractsplicesites": { "branch": "master", - "git_sha": "2c6b1144ed58b6184ad58fc4e6b6a90219b4bf4f", + "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", "installed_by": [ "modules" ] @@ -190,35 +190,35 @@ }, "multiqc": { "branch": "master", - "git_sha": "b80f5fd12ff7c43938f424dd76392a2704fa2396", + "git_sha": "b7ebe95761cd389603f9cc0e0dc384c0f663815a", "installed_by": [ "modules" ] }, "samtools/faidx": { "branch": "master", - "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", + "git_sha": "f153f1f10e1083c49935565844cccb7453021682", "installed_by": [ "modules" ] }, "samtools/flagstat": { "branch": "master", - "git_sha": "46eca555142d6e597729fcb682adcc791796f514", + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", "installed_by": [ "bam_stats_samtools" ] }, "samtools/idxstats": { "branch": "master", - "git_sha": "46eca555142d6e597729fcb682adcc791796f514", + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", "installed_by": [ "bam_stats_samtools" ] }, "samtools/index": { "branch": "master", - "git_sha": "46eca555142d6e597729fcb682adcc791796f514", + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", "installed_by": [ "bam_sort_stats_samtools", "modules" @@ -226,7 +226,7 @@ }, "samtools/sort": { "branch": "master", - "git_sha": "46eca555142d6e597729fcb682adcc791796f514", + "git_sha": "4352dbdb09ec40db71e9b172b97a01dcf5622c26", "installed_by": [ "bam_sort_stats_samtools", "modules" @@ -234,14 +234,14 @@ }, "samtools/stats": { "branch": "master", - "git_sha": "46eca555142d6e597729fcb682adcc791796f514", + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", "installed_by": [ "bam_stats_samtools" ] }, "samtools/view": { "branch": "master", - "git_sha": "6c2309aaec566c0d44a6cf14d4b2d0c51afe2e91", + "git_sha": "0bd7d2333a88483aa0476acea172e9f5f6dd83bb", "installed_by": [ "modules" ] @@ -262,28 +262,28 @@ }, "star/align": { "branch": "master", - "git_sha": "46eca555142d6e597729fcb682adcc791796f514", + "git_sha": "a21faa6a3481af92a343a10926f59c189a2c16c9", "installed_by": [ "modules" ] }, "star/genomegenerate": { "branch": "master", - "git_sha": "46eca555142d6e597729fcb682adcc791796f514", + "git_sha": "a21faa6a3481af92a343a10926f59c189a2c16c9", "installed_by": [ "modules" ] }, "stringtie/stringtie": { "branch": "master", - "git_sha": "c789476080a150f87066ca3ed42a622339a26c0b", + "git_sha": "b1b959609bda44341120aed1766329909f54b8d0", "installed_by": [ "modules" ] }, "trimgalore": { "branch": "master", - "git_sha": "b4919e9a2b4d8b71061e601633db4600a3858fa1", + "git_sha": "a98418419ae6c9df3cf6cf108d1e1aba71037d5a", "installed_by": [ "modules" ] @@ -301,14 +301,14 @@ "nf-core": { "bam_sort_stats_samtools": { "branch": "master", - "git_sha": "46eca555142d6e597729fcb682adcc791796f514", + "git_sha": "4352dbdb09ec40db71e9b172b97a01dcf5622c26", "installed_by": [ "subworkflows" ] }, "bam_stats_samtools": { "branch": "master", - "git_sha": "0eacd714effe5aac1c1de26593873960b3346cab", + "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", "installed_by": [ "bam_sort_stats_samtools", "subworkflows" diff --git a/modules/nf-core/bioawk/main.nf b/modules/nf-core/bioawk/main.nf index a537dcf4..0fded517 100644 --- a/modules/nf-core/bioawk/main.nf +++ b/modules/nf-core/bioawk/main.nf @@ -11,8 +11,8 @@ process BIOAWK { tuple val(meta), path(input) output: - tuple val(meta), path("*.gz"), emit: output - path "versions.yml" , emit: versions + tuple val(meta), path("${prefix}.${suffix}"), emit: output + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -20,15 +20,14 @@ process BIOAWK { script: def args = task.ext.args ?: '' // args is used for the main arguments of the tool prefix = task.ext.prefix ?: "${meta.id}" - if ("${input}" == "${prefix}") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" + suffix = task.ext.suffix ?: input.extension + def VERSION = '1.0' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. """ bioawk \\ $args \\ $input \\ - > ${prefix} - - gzip ${prefix} + > ${prefix}.${suffix} cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/bowtie/align/environment.yml b/modules/nf-core/bowtie/align/environment.yml index fb5d7c1e..2617e6f0 100644 --- a/modules/nf-core/bowtie/align/environment.yml +++ b/modules/nf-core/bowtie/align/environment.yml @@ -5,4 +5,3 @@ channels: - defaults dependencies: - bioconda::bowtie=1.3.0 - - bioconda::samtools=1.16.1 diff --git a/modules/nf-core/bowtie/align/main.nf b/modules/nf-core/bowtie/align/main.nf index 5e72b02a..29e9cd53 100644 --- a/modules/nf-core/bowtie/align/main.nf +++ b/modules/nf-core/bowtie/align/main.nf @@ -9,14 +9,13 @@ process BOWTIE_ALIGN { input: tuple val(meta), path(reads) - tuple val(meta2), path(index) - val (save_unaligned) + path index output: - tuple val(meta), path('*.bam') , emit: bam - tuple val(meta), path('*.out') , emit: log - tuple val(meta), path('*fastq.gz') , emit: fastq, optional : true - path "versions.yml" , emit: versions + tuple val(meta), path('*.bam'), emit: bam + tuple val(meta), path('*.out'), emit: log + path "versions.yml" , emit: versions + tuple val(meta), path('*fastq.gz'), optional:true, emit: fastq when: task.ext.when == null || task.ext.when @@ -25,10 +24,10 @@ process BOWTIE_ALIGN { def args = task.ext.args ?: '' def args2 = task.ext.args2 ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - def unaligned = save_unaligned ? "--un ${prefix}.unmapped.fastq" : '' + def unaligned = params.save_unaligned ? "--un ${prefix}.unmapped.fastq" : '' def endedness = meta.single_end ? "$reads" : "-1 ${reads[0]} -2 ${reads[1]}" """ - INDEX=\$(find -L ./ -name "*.3.ebwt" | sed 's/\\.3.ebwt\$//') + INDEX=`find -L ./ -name "*.3.ebwt" | sed 's/\\.3.ebwt\$//'` bowtie \\ --threads $task.cpus \\ --sam \\ @@ -54,24 +53,4 @@ process BOWTIE_ALIGN { samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') END_VERSIONS """ - - stub: - def prefix = task.ext.prefix ?: "${meta.id}" - def unaligned = save_unaligned ? - meta.single_end ? "echo '' | gzip > ${prefix}.unmapped.fastq.gz" : - "echo '' | gzip > ${prefix}.unmapped_1.fastq.gz; echo '' | gzip > ${prefix}.unmapped_2.fastq.gz" - : '' - """ - touch ${prefix}.bam - touch ${prefix}.out - $unaligned - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bowtie: \$(echo \$(bowtie --version 2>&1) | sed 's/^.*bowtie-align-s version //; s/ .*\$//') - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS - """ - - } diff --git a/modules/nf-core/bowtie/align/meta.yml b/modules/nf-core/bowtie/align/meta.yml index 7c7e8237..89eaedd6 100644 --- a/modules/nf-core/bowtie/align/meta.yml +++ b/modules/nf-core/bowtie/align/meta.yml @@ -27,36 +27,23 @@ input: description: | List of input FastQ files of size 1 and 2 for single-end and paired-end data, respectively. - - meta2: - type: map - description: | - Groovy Map containing genome information - e.g. [ id:'sarscov2' ] - index: type: file description: Bowtie genome index files pattern: "*.ebwt" - - save_unaligned: - type: boolean - description: Whether to save fastq files containing the reads which did not align. output: - bam: type: file description: Output BAM file containing read alignments pattern: "*.{bam}" - - fastq: - type: file - description: Unaligned FastQ files - pattern: "*.fastq.gz" - - log: - type: file - description: Log file - pattern: "*.log" - versions: type: file description: File containing software versions pattern: "versions.yml" - + - fastq: + type: file + description: Unaligned FastQ files + pattern: "*.fastq.gz" authors: - "@kevinmenden" maintainers: diff --git a/modules/nf-core/bowtie/align/tests/main.nf.test b/modules/nf-core/bowtie/align/tests/main.nf.test deleted file mode 100644 index 3403ae22..00000000 --- a/modules/nf-core/bowtie/align/tests/main.nf.test +++ /dev/null @@ -1,129 +0,0 @@ -nextflow_process { - - name "Test Process BOWTIE_ALIGN" - script "../main.nf" - process "BOWTIE_ALIGN" - - tag "modules" - tag "modules_nfcore" - tag "bowtie" - tag "bowtie/align" - tag "bowtie/build" - - - setup { - run("BOWTIE_BUILD") { - script "../../../bowtie/build/main.nf" - process { - """ - input[0] = [[ id:'sarscov2' ], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] - """ - } - } - } - - test("sarscov2 - single_end") { - - when { - process { - """ - input[0] = [ [id:"test", single_end:true], - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) - ] - input[1] = BOWTIE_BUILD.out.index - input[2] = true - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out.versions, - process.out.bam.collect { bam(it[1]).getReadsMD5() }, - process.out.fastq, - process.out.log - ).match() } - ) - } - - } - - test("sarscov2 - single_end - stub") { - - options "-stub" - - when { - process { - """ - input[0] = [ [id:"test", single_end:true], - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) - ] - input[1] = BOWTIE_BUILD.out.index - input[2] = true - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - - } - - test("sarscov2 - paired_end") { - - when { - process { - """ - input[0] = [ [id:"test", single_end:false], - [file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)] - ] - input[1] = BOWTIE_BUILD.out.index - input[2] = false - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out.versions, - process.out.bam.collect { bam(it[1]).getReads(2) }, - process.out.log - ).match() } - ) - } - - } - - test("sarscov2 - paired_end - stub") { - - options "-stub" - when { - process { - """ - input[0] = [ [id:"test", single_end:false], - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) - ] - input[1] = BOWTIE_BUILD.out.index - input[2] = false - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - - } - -} diff --git a/modules/nf-core/bowtie/align/tests/main.nf.test.snap b/modules/nf-core/bowtie/align/tests/main.nf.test.snap deleted file mode 100644 index de95bb81..00000000 --- a/modules/nf-core/bowtie/align/tests/main.nf.test.snap +++ /dev/null @@ -1,192 +0,0 @@ -{ - "sarscov2 - single_end": { - "content": [ - [ - "versions.yml:md5,96e36b0b99c80da0be8239d03db30ecc" - ], - [ - "7bdcfc6f54ae6e8f4570395cc85db9a3" - ], - [ - [ - { - "id": "test", - "single_end": true - }, - "test.unmapped.fastq.gz:md5,5729a694abd09657da3b9101861090c4" - ] - ], - [ - [ - { - "id": "test", - "single_end": true - }, - "test.out:md5,4b9140ceadb8a18ae9330885370f8a0b" - ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-26T09:25:24.60746041" - }, - "sarscov2 - single_end - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": true - }, - "test.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test", - "single_end": true - }, - "test.unmapped.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ], - "3": [ - "versions.yml:md5,96e36b0b99c80da0be8239d03db30ecc" - ], - "bam": [ - [ - { - "id": "test", - "single_end": true - }, - "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "fastq": [ - [ - { - "id": "test", - "single_end": true - }, - "test.unmapped.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ], - "log": [ - [ - { - "id": "test", - "single_end": true - }, - "test.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,96e36b0b99c80da0be8239d03db30ecc" - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-25T10:00:28.666281812" - }, - "sarscov2 - paired_end": { - "content": [ - [ - "versions.yml:md5,96e36b0b99c80da0be8239d03db30ecc" - ], - [ - [ - "ATGTGTACATTGGCGACCCTGCTCAATTACCTGCACCACGCACATTGCTAACTAAGGGCACACTAGAACCAGAATATTTCAATTCAGTGTGTAGACTTATGAAAACTATAGGTCCAGACATGTTCCTCGGAACTTGTCGGCGTTGTCCTG", - "ACGCACATTGCTAACTAAGGGCACACTAGAACCAGAATATTTCAATTCAGTGTGTAGACTTATGAAAACTATAGGTCCAGACATGTTCCTCGGAACTTGTCGGCGTTGTCCTGCTGAAATTGTTGACACTGTGAGTGCTTTGGTTTATGA" - ] - ], - [ - [ - { - "id": "test", - "single_end": false - }, - "test.out:md5,5e13272d112cef8faeedcdbd7c602de0" - ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-26T11:57:56.604464368" - }, - "sarscov2 - paired_end - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - - ], - "3": [ - "versions.yml:md5,96e36b0b99c80da0be8239d03db30ecc" - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "fastq": [ - - ], - "log": [ - [ - { - "id": "test", - "single_end": false - }, - "test.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,96e36b0b99c80da0be8239d03db30ecc" - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-25T10:01:02.043164876" - } -} \ No newline at end of file diff --git a/modules/nf-core/bowtie/align/tests/tags.yml b/modules/nf-core/bowtie/align/tests/tags.yml deleted file mode 100644 index a5753d58..00000000 --- a/modules/nf-core/bowtie/align/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -bowtie/align: - - "modules/nf-core/bowtie/align/**" diff --git a/modules/nf-core/bowtie/build/main.nf b/modules/nf-core/bowtie/build/main.nf index d5b4c690..05e22fe8 100644 --- a/modules/nf-core/bowtie/build/main.nf +++ b/modules/nf-core/bowtie/build/main.nf @@ -1,5 +1,5 @@ process BOWTIE_BUILD { - tag "${meta.id}" + tag "$fasta" label 'process_high' conda "${moduleDir}/environment.yml" @@ -8,43 +8,23 @@ process BOWTIE_BUILD { 'biocontainers/bowtie:1.3.0--py38hed8969a_1' }" input: - tuple val(meta), path(fasta) + path fasta output: - tuple val(meta), path('bowtie') , emit: index - path "versions.yml" , emit: versions + path 'bowtie' , emit: index + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when script: def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" """ - mkdir -p bowtie - bowtie-build --threads $task.cpus $fasta bowtie/${prefix} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bowtie: \$(echo \$(bowtie --version 2>&1) | sed 's/^.*bowtie-align-s version //; s/ .*\$//') - END_VERSIONS - """ - - stub: - def prefix = task.ext.prefix ?: "${meta.id}" - """ - mkdir -p bowtie - touch bowtie/${prefix}.1.ebwt - touch bowtie/${prefix}.2.ebwt - touch bowtie/${prefix}.3.ebwt - touch bowtie/${prefix}.4.ebwt - touch bowtie/${prefix}.rev.1.ebwt - touch bowtie/${prefix}.rev.2.ebwt - + mkdir bowtie + bowtie-build --threads $task.cpus $fasta bowtie/${fasta.baseName} cat <<-END_VERSIONS > versions.yml "${task.process}": bowtie: \$(echo \$(bowtie --version 2>&1) | sed 's/^.*bowtie-align-s version //; s/ .*\$//') END_VERSIONS """ - } diff --git a/modules/nf-core/bowtie/build/meta.yml b/modules/nf-core/bowtie/build/meta.yml index dd48004f..262855f4 100644 --- a/modules/nf-core/bowtie/build/meta.yml +++ b/modules/nf-core/bowtie/build/meta.yml @@ -15,23 +15,13 @@ tools: arxiv: arXiv:1303.3997 licence: ["Artistic-2.0"] input: - - meta: - type: map - description: | - Groovy Map containing information about the genome fasta - e.g. [ id:'test' ] - fasta: type: file description: Input genome fasta file output: - - meta: - type: map - description: | - Groovy Map containing nformation about the genome fasta - e.g. [ id:'test' ] - index: type: file - description: Folder containing bowtie genome index files + description: Bowtie genome index files pattern: "*.ebwt" - versions: type: file diff --git a/modules/nf-core/bowtie/build/tests/main.nf.test b/modules/nf-core/bowtie/build/tests/main.nf.test deleted file mode 100644 index 2a1e0dc0..00000000 --- a/modules/nf-core/bowtie/build/tests/main.nf.test +++ /dev/null @@ -1,57 +0,0 @@ -nextflow_process { - - name "Test Process BOWTIE_BUILD" - script "../main.nf" - process "BOWTIE_BUILD" - - tag "modules" - tag "modules_nfcore" - tag "bowtie" - tag "bowtie/build" - - test("sarscov2 - fasta") { - - when { - process { - """ - input[0] = [ - [id: 'sarscov2'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) - ] - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - - } - - test("sarscov2 - fasta - stub") { - - options "-stub" - - when { - process { - """ - input[0] = [[id: 'sarscov2'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) - ] - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - - } - -} diff --git a/modules/nf-core/bowtie/build/tests/main.nf.test.snap b/modules/nf-core/bowtie/build/tests/main.nf.test.snap deleted file mode 100644 index e8061756..00000000 --- a/modules/nf-core/bowtie/build/tests/main.nf.test.snap +++ /dev/null @@ -1,96 +0,0 @@ -{ - "sarscov2 - fasta - stub": { - "content": [ - { - "0": [ - [ - { - "id": "sarscov2" - }, - [ - "sarscov2.1.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", - "sarscov2.2.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", - "sarscov2.3.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", - "sarscov2.4.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", - "sarscov2.rev.1.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", - "sarscov2.rev.2.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "1": [ - "versions.yml:md5,afbd066e1dd5ae4a30b21c49149ea09a" - ], - "index": [ - [ - { - "id": "sarscov2" - }, - [ - "sarscov2.1.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", - "sarscov2.2.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", - "sarscov2.3.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", - "sarscov2.4.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", - "sarscov2.rev.1.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e", - "sarscov2.rev.2.ebwt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "versions": [ - "versions.yml:md5,afbd066e1dd5ae4a30b21c49149ea09a" - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-18T08:38:14.852528155" - }, - "sarscov2 - fasta": { - "content": [ - { - "0": [ - [ - { - "id": "sarscov2" - }, - [ - "sarscov2.1.ebwt:md5,d9b76ecf9fd0413240173273b38d8199", - "sarscov2.2.ebwt:md5,02b44af9f94c62ecd3c583048e25d4cf", - "sarscov2.3.ebwt:md5,4ed93abba181d8dfab2e303e33114777", - "sarscov2.4.ebwt:md5,c25be5f8b0378abf7a58c8a880b87626", - "sarscov2.rev.1.ebwt:md5,b37aaf11853e65a3b13561f27a912b06", - "sarscov2.rev.2.ebwt:md5,9e6b0c4c1ddb99ae71ff8a4fe5ec6459" - ] - ] - ], - "1": [ - "versions.yml:md5,afbd066e1dd5ae4a30b21c49149ea09a" - ], - "index": [ - [ - { - "id": "sarscov2" - }, - [ - "sarscov2.1.ebwt:md5,d9b76ecf9fd0413240173273b38d8199", - "sarscov2.2.ebwt:md5,02b44af9f94c62ecd3c583048e25d4cf", - "sarscov2.3.ebwt:md5,4ed93abba181d8dfab2e303e33114777", - "sarscov2.4.ebwt:md5,c25be5f8b0378abf7a58c8a880b87626", - "sarscov2.rev.1.ebwt:md5,b37aaf11853e65a3b13561f27a912b06", - "sarscov2.rev.2.ebwt:md5,9e6b0c4c1ddb99ae71ff8a4fe5ec6459" - ] - ] - ], - "versions": [ - "versions.yml:md5,afbd066e1dd5ae4a30b21c49149ea09a" - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-18T08:37:53.65689025" - } -} \ No newline at end of file diff --git a/modules/nf-core/bowtie/build/tests/tags.yml b/modules/nf-core/bowtie/build/tests/tags.yml deleted file mode 100644 index 1ccfa30c..00000000 --- a/modules/nf-core/bowtie/build/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -bowtie/build: - - "modules/nf-core/bowtie/build/**" diff --git a/modules/nf-core/bowtie2/align/tests/main.nf.test b/modules/nf-core/bowtie2/align/tests/main.nf.test index 0de5950f..03aeaf9e 100644 --- a/modules/nf-core/bowtie2/align/tests/main.nf.test +++ b/modules/nf-core/bowtie2/align/tests/main.nf.test @@ -18,7 +18,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) ] """ } @@ -30,10 +30,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -64,7 +64,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) ] """ } @@ -76,10 +76,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -110,7 +110,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) ] """ } @@ -122,10 +122,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -155,7 +155,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) ] """ } @@ -167,10 +167,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -200,7 +200,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) ] """ } @@ -213,12 +213,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -248,7 +248,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) ] """ } @@ -261,12 +261,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -297,7 +297,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) ] """ } @@ -309,10 +309,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -343,7 +343,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) ] """ } @@ -356,12 +356,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -391,7 +391,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) ] """ } @@ -404,12 +404,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -439,7 +439,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) ] """ } @@ -451,10 +451,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -486,7 +486,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) ] """ } @@ -499,12 +499,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] input[3] = false //save_unaligned input[4] = true //sort """ @@ -533,7 +533,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) ] """ } @@ -546,12 +546,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true), + file(params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], checkIfExists: true) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -583,7 +583,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) ] """ } @@ -595,10 +595,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], checkIfExists: true) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] + input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ diff --git a/modules/nf-core/cat/cat/main.nf b/modules/nf-core/cat/cat/main.nf index 2862c64c..adbdbd7b 100644 --- a/modules/nf-core/cat/cat/main.nf +++ b/modules/nf-core/cat/cat/main.nf @@ -76,3 +76,4 @@ def getFileSuffix(filename) { def match = filename =~ /^.*?((\.\w{1,5})?(\.\w{1,5}\.gz$))/ return match ? match[0][1] : filename.substring(filename.lastIndexOf('.')) } + diff --git a/modules/nf-core/cat/cat/tests/main.nf.test b/modules/nf-core/cat/cat/tests/main.nf.test index 9cb16178..fcee2d19 100644 --- a/modules/nf-core/cat/cat/tests/main.nf.test +++ b/modules/nf-core/cat/cat/tests/main.nf.test @@ -29,8 +29,7 @@ nextflow_process { then { assertAll( { assert !process.success }, - { assert process.stdout.toString().contains("The name of the input file can't be the same as for the output prefix") }, - { assert snapshot(process.out.versions).match() } + { assert process.stdout.toString().contains("The name of the input file can't be the same as for the output prefix") } ) } } @@ -84,12 +83,8 @@ nextflow_process { def lines = path(process.out.file_out.get(0).get(1)).linesGzip assertAll( { assert process.success }, - { assert snapshot( - lines[0..5], - lines.size(), - process.out.versions - ).match() - } + { assert snapshot(lines[0..5]).match("test_cat_zipped_zipped_lines") }, + { assert snapshot(lines.size()).match("test_cat_zipped_zipped_size")} ) } } @@ -147,12 +142,8 @@ nextflow_process { def lines = path(process.out.file_out.get(0).get(1)).linesGzip assertAll( { assert process.success }, - { assert snapshot( - lines[0..5], - lines.size(), - process.out.versions - ).match() - } + { assert snapshot(lines[0..5]).match("test_cat_unzipped_zipped_lines") }, + { assert snapshot(lines.size()).match("test_cat_unzipped_zipped_size")} ) } } @@ -179,12 +170,8 @@ nextflow_process { def lines = path(process.out.file_out.get(0).get(1)).linesGzip assertAll( { assert process.success }, - { assert snapshot( - lines[0..5], - lines.size(), - process.out.versions - ).match() - } + { assert snapshot(lines[0..5]).match("test_cat_one_file_unzipped_zipped_lines") }, + { assert snapshot(lines.size()).match("test_cat_one_file_unzipped_zipped_size")} ) } } diff --git a/modules/nf-core/cat/cat/tests/main.nf.test.snap b/modules/nf-core/cat/cat/tests/main.nf.test.snap index b7623ee6..423571ba 100644 --- a/modules/nf-core/cat/cat/tests/main.nf.test.snap +++ b/modules/nf-core/cat/cat/tests/main.nf.test.snap @@ -1,4 +1,10 @@ { + "test_cat_unzipped_zipped_size": { + "content": [ + 375 + ], + "timestamp": "2023-10-16T14:33:08.049445686" + }, "test_cat_unzipped_unzipped": { "content": [ { @@ -28,10 +34,6 @@ ] } ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.3" - }, "timestamp": "2023-10-16T14:32:18.500464399" }, "test_cat_zipped_unzipped": { @@ -63,13 +65,9 @@ ] } ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.3" - }, "timestamp": "2023-10-16T14:32:49.642741302" }, - "test_cat_zipped_zipped": { + "test_cat_zipped_zipped_lines": { "content": [ [ "MT192765.1\tGenbank\ttranscript\t259\t29667\t.\t+\t.\tID=unknown_transcript_1;geneID=orf1ab;gene_name=orf1ab", @@ -78,31 +76,11 @@ "MT192765.1\tGenbank\tCDS\t13461\t21548\t.\t+\t0\tParent=unknown_transcript_1;exception=\"ribosomal slippage\";gbkey=CDS;gene=orf1ab;note=\"pp1ab;translated=by -1 ribosomal frameshift\";product=\"orf1ab polyprotein\";protein_id=QIK50426.1", "MT192765.1\tGenbank\tCDS\t21556\t25377\t.\t+\t0\tParent=unknown_transcript_1;gbkey=CDS;gene=S;note=\"structural protein\";product=\"surface glycoprotein\";protein_id=QIK50427.1", "MT192765.1\tGenbank\tgene\t21556\t25377\t.\t+\t.\tParent=unknown_transcript_1" - ], - 78, - [ - "versions.yml:md5,115ed6177ebcff24eb99d503fa5ef894" - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:51:46.802978" - }, - "test_cat_name_conflict": { - "content": [ - [ - ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:51:29.45394" + "timestamp": "2023-10-16T14:32:33.629048645" }, - "test_cat_one_file_unzipped_zipped": { + "test_cat_unzipped_zipped_lines": { "content": [ [ ">MT192765.1 Severe acute respiratory syndrome coronavirus 2 isolate SARS-CoV-2/human/USA/PC00101P/2020, complete genome", @@ -111,19 +89,11 @@ "TAACTCGTCTATCTTCTGCAGGCTGCTTACGGTTTCGTCCGTGTTGCAGCCGATCATCAGCACATCTAGGTTTTGTCCGG", "GTGTGACCGAAAGGTAAGATGGAGAGCCTTGTCCCTGGTTTCAACGAGAAAACACACGTCCAACTCAGTTTGCCTGTTTT", "ACAGGTTCGCGACGTGCTCGTACGTGGCTTTGGAGACTCCGTGGAGGAGGTCTTATCAGAGGCACGTCAACATCTTAAAG" - ], - 374, - [ - "versions.yml:md5,115ed6177ebcff24eb99d503fa5ef894" ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:52:02.774016" + "timestamp": "2023-10-16T14:33:08.038830506" }, - "test_cat_unzipped_zipped": { + "test_cat_one_file_unzipped_zipped_lines": { "content": [ [ ">MT192765.1 Severe acute respiratory syndrome coronavirus 2 isolate SARS-CoV-2/human/USA/PC00101P/2020, complete genome", @@ -132,16 +102,20 @@ "TAACTCGTCTATCTTCTGCAGGCTGCTTACGGTTTCGTCCGTGTTGCAGCCGATCATCAGCACATCTAGGTTTTGTCCGG", "GTGTGACCGAAAGGTAAGATGGAGAGCCTTGTCCCTGGTTTCAACGAGAAAACACACGTCCAACTCAGTTTGCCTGTTTT", "ACAGGTTCGCGACGTGCTCGTACGTGGCTTTGGAGACTCCGTGGAGGAGGTCTTATCAGAGGCACGTCAACATCTTAAAG" - ], - 375, - [ - "versions.yml:md5,115ed6177ebcff24eb99d503fa5ef894" ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:51:57.581523" + "timestamp": "2023-10-16T14:33:21.39642399" + }, + "test_cat_zipped_zipped_size": { + "content": [ + 78 + ], + "timestamp": "2023-10-16T14:32:33.641869244" + }, + "test_cat_one_file_unzipped_zipped_size": { + "content": [ + 374 + ], + "timestamp": "2023-10-16T14:33:21.4094373" } } \ No newline at end of file diff --git a/modules/nf-core/cat/fastq/main.nf b/modules/nf-core/cat/fastq/main.nf index b68e5f91..f132b2ad 100644 --- a/modules/nf-core/cat/fastq/main.nf +++ b/modules/nf-core/cat/fastq/main.nf @@ -53,9 +53,9 @@ process CAT_FASTQ { def prefix = task.ext.prefix ?: "${meta.id}" def readList = reads instanceof List ? reads.collect{ it.toString() } : [reads.toString()] if (meta.single_end) { - if (readList.size >= 1) { + if (readList.size > 1) { """ - echo '' | gzip > ${prefix}.merged.fastq.gz + touch ${prefix}.merged.fastq.gz cat <<-END_VERSIONS > versions.yml "${task.process}": @@ -64,10 +64,10 @@ process CAT_FASTQ { """ } } else { - if (readList.size >= 2) { + if (readList.size > 2) { """ - echo '' | gzip > ${prefix}_1.merged.fastq.gz - echo '' | gzip > ${prefix}_2.merged.fastq.gz + touch ${prefix}_1.merged.fastq.gz + touch ${prefix}_2.merged.fastq.gz cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/cat/fastq/tests/main.nf.test b/modules/nf-core/cat/fastq/tests/main.nf.test index f88a78b6..a71dcb8d 100644 --- a/modules/nf-core/cat/fastq/tests/main.nf.test +++ b/modules/nf-core/cat/fastq/tests/main.nf.test @@ -13,6 +13,9 @@ nextflow_process { test("test_cat_fastq_single_end") { when { + params { + outdir = "$outputDir" + } process { """ input[0] = Channel.of([ @@ -35,6 +38,9 @@ nextflow_process { test("test_cat_fastq_paired_end") { when { + params { + outdir = "$outputDir" + } process { """ input[0] = Channel.of([ @@ -59,6 +65,9 @@ nextflow_process { test("test_cat_fastq_single_end_same_name") { when { + params { + outdir = "$outputDir" + } process { """ input[0] = Channel.of([ @@ -81,6 +90,9 @@ nextflow_process { test("test_cat_fastq_paired_end_same_name") { when { + params { + outdir = "$outputDir" + } process { """ input[0] = Channel.of([ @@ -105,129 +117,9 @@ nextflow_process { test("test_cat_fastq_single_end_single_file") { when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:true ], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)] - ]) - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("test_cat_fastq_single_end - stub") { - - options "-stub" - - when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:true ], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)] - ]) - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("test_cat_fastq_paired_end - stub") { - - options "-stub" - - when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true)] - ]) - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("test_cat_fastq_single_end_same_name - stub") { - - options "-stub" - - when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:true ], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)] - ]) - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("test_cat_fastq_paired_end_same_name - stub") { - - options "-stub" - - when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)] - ]) - """ + params { + outdir = "$outputDir" } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("test_cat_fastq_single_end_single_file - stub") { - - options "-stub" - - when { process { """ input[0] = Channel.of([ diff --git a/modules/nf-core/cat/fastq/tests/main.nf.test.snap b/modules/nf-core/cat/fastq/tests/main.nf.test.snap index aec119a9..43dfe28f 100644 --- a/modules/nf-core/cat/fastq/tests/main.nf.test.snap +++ b/modules/nf-core/cat/fastq/tests/main.nf.test.snap @@ -28,10 +28,6 @@ ] } ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, "timestamp": "2024-01-17T17:30:39.816981" }, "test_cat_fastq_single_end_same_name": { @@ -63,10 +59,6 @@ ] } ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, "timestamp": "2024-01-17T17:32:35.229332" }, "test_cat_fastq_single_end_single_file": { @@ -98,10 +90,6 @@ ] } ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, "timestamp": "2024-01-17T17:34:00.058829" }, "test_cat_fastq_paired_end_same_name": { @@ -139,123 +127,8 @@ ] } ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, "timestamp": "2024-01-17T17:33:33.031555" }, - "test_cat_fastq_single_end - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ], - "1": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" - ], - "reads": [ - [ - { - "id": "test", - "single_end": true - }, - "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ], - "versions": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-07-05T12:07:28.244999" - }, - "test_cat_fastq_paired_end_same_name - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test_1.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "1": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" - ], - "reads": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test_1.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "versions": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-07-05T12:07:57.070911" - }, - "test_cat_fastq_single_end_same_name - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ], - "1": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" - ], - "reads": [ - [ - { - "id": "test", - "single_end": true - }, - "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ], - "versions": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-07-05T12:07:46.796254" - }, "test_cat_fastq_paired_end": { "content": [ { @@ -291,86 +164,6 @@ ] } ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, "timestamp": "2024-01-17T17:32:02.270935" - }, - "test_cat_fastq_paired_end - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test_1.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "1": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" - ], - "reads": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test_1.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "versions": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-07-05T12:07:37.807553" - }, - "test_cat_fastq_single_end_single_file - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ], - "1": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" - ], - "reads": [ - [ - { - "id": "test", - "single_end": true - }, - "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ], - "versions": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-07-05T12:14:51.861264" } } \ No newline at end of file diff --git a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py index 9a493ace..da033408 100755 --- a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py +++ b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py @@ -3,6 +3,7 @@ """Provide functions to merge multiple versions.yml files.""" + import yaml import platform from textwrap import dedent diff --git a/modules/nf-core/custom/tx2gene/templates/tx2gene.py b/modules/nf-core/custom/tx2gene/templates/tx2gene.py index 8c2e3b1f..7fd0de64 100755 --- a/modules/nf-core/custom/tx2gene/templates/tx2gene.py +++ b/modules/nf-core/custom/tx2gene/templates/tx2gene.py @@ -17,7 +17,6 @@ logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) - def format_yaml_like(data: dict, indent: int = 0) -> str: """Formats a dictionary to a YAML-like string. @@ -37,7 +36,6 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: yaml_str += f"{spaces}{key}: {value}\\n" return yaml_str - def read_top_transcripts(quant_dir: str, file_pattern: str) -> Set[str]: """ Read the top 100 transcripts from the quantification file. @@ -125,12 +123,7 @@ def parse_attributes(attributes_text: str) -> Dict[str, str]: def map_transcripts_to_gene( - quant_type: str, - gtf_file: str, - quant_dir: str, - gene_id: str, - extra_id_field: str, - output_file: str, + quant_type: str, gtf_file: str, quant_dir: str, gene_id: str, extra_id_field: str, output_file: str ) -> bool: """ Map transcripts to gene names and write the output to a file. @@ -163,10 +156,7 @@ def map_transcripts_to_gene( attr_dict = parse_attributes(cols[8]) if gene_id in attr_dict and transcript_attribute in attr_dict: # Create a unique identifier for the transcript-gene combination - transcript_gene_pair = ( - attr_dict[transcript_attribute], - attr_dict[gene_id], - ) + transcript_gene_pair = (attr_dict[transcript_attribute], attr_dict[gene_id]) # Check if the combination has already been seen if transcript_gene_pair not in seen: @@ -180,14 +170,14 @@ def map_transcripts_to_gene( # Main function to parse arguments and call the mapping function if __name__ == "__main__": - if "${task.ext.prefix}" != "null": + if '${task.ext.prefix}' != "null": prefix = "${task.ext.prefix}." - elif "$meta.id" != "null": - prefix = "${meta.id}." + elif '$meta.id' != "null": + prefix = '${meta.id}.' else: - prefix = "" + prefix = '' - if not map_transcripts_to_gene("$quant_type", "$gtf", "quants", "$id", "$extra", f"{prefix}tx2gene.tsv"): + if not map_transcripts_to_gene('$quant_type', '$gtf', 'quants', '$id', '$extra', f"{prefix}tx2gene.tsv"): logger.error("Failed to map transcripts to genes.") # Write the versions diff --git a/modules/nf-core/custom/tx2gene/tests/main.nf.test b/modules/nf-core/custom/tx2gene/tests/main.nf.test index 4cbb8d4e..b1559279 100644 --- a/modules/nf-core/custom/tx2gene/tests/main.nf.test +++ b/modules/nf-core/custom/tx2gene/tests/main.nf.test @@ -10,21 +10,22 @@ nextflow_process { tag "custom/tx2gene" tag "untar" - test("saccharomyces_cerevisiae - gtf") { + setup { - setup { - run("UNTAR") { - script "../../../untar/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test'], // meta map - file(params.modules_testdata_base_path + 'genomics/eukaryotes/saccharomyces_cerevisiae/kallisto_results.tar.gz', checkIfExists: true) - ]) - """ - } + run("UNTAR") { + script "../../../untar/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test'], // meta map + file(params.modules_testdata_base_path + 'genomics/eukaryotes/saccharomyces_cerevisiae/kallisto_results.tar.gz', checkIfExists: true) + ]) + """ } } + } + + test("saccharomyces_cerevisiae - gtf") { when { process { @@ -44,7 +45,8 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out.tx2gene).match('tx2gene') }, + { assert snapshot(process.out.versions).match('versions') } ) } } @@ -53,20 +55,6 @@ nextflow_process { options "-stub" - setup { - run("UNTAR") { - script "../../../untar/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test'], // meta map - file(params.modules_testdata_base_path + 'genomics/eukaryotes/saccharomyces_cerevisiae/kallisto_results.tar.gz', checkIfExists: true) - ]) - """ - } - } - } - when { process { """ @@ -85,7 +73,8 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out.tx2gene).match('tx2gene - stub') }, + { assert snapshot(process.out.versions).match('versions - stub') } ) } } diff --git a/modules/nf-core/custom/tx2gene/tests/main.nf.test.snap b/modules/nf-core/custom/tx2gene/tests/main.nf.test.snap index c19f10f7..1e76e10d 100644 --- a/modules/nf-core/custom/tx2gene/tests/main.nf.test.snap +++ b/modules/nf-core/custom/tx2gene/tests/main.nf.test.snap @@ -1,68 +1,60 @@ { - "saccharomyces_cerevisiae - gtf": { + "versions": { "content": [ - { - "0": [ - [ - { - "id": "test" - }, - "test.tx2gene.tsv:md5,0e2418a69d2eba45097ebffc2f700bfe" - ] - ], - "1": [ - "versions.yml:md5,fb8145d7fbc6043ba031249b23ecda50" - ], - "tx2gene": [ - [ - { - "id": "test" - }, - "test.tx2gene.tsv:md5,0e2418a69d2eba45097ebffc2f700bfe" - ] - ], - "versions": [ - "versions.yml:md5,fb8145d7fbc6043ba031249b23ecda50" + [ + "versions.yml:md5,fb8145d7fbc6043ba031249b23ecda50" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-26T13:14:18.218251" + }, + "tx2gene": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.tx2gene.tsv:md5,0e2418a69d2eba45097ebffc2f700bfe" ] - } + ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nextflow": "24.01.0" }, - "timestamp": "2024-07-05T13:13:11.305047" + "timestamp": "2024-02-26T13:14:18.21054" }, - "saccharomyces_cerevisiae - gtf - stub": { + "tx2gene - stub": { "content": [ - { - "0": [ - [ - { - "id": "test" - }, - "test.tx2gene.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - "versions.yml:md5,5613eefbca41377128f1d8dc09b9fb60" - ], - "tx2gene": [ - [ - { - "id": "test" - }, - "test.tx2gene.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,5613eefbca41377128f1d8dc09b9fb60" + [ + [ + { + "id": "test" + }, + "test.tx2gene.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" ] - } + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-26T13:14:25.915434" + }, + "versions - stub": { + "content": [ + [ + "versions.yml:md5,5613eefbca41377128f1d8dc09b9fb60" + ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.04.3" + "nextflow": "24.01.0" }, - "timestamp": "2024-07-10T15:15:34.064489" + "timestamp": "2024-02-26T13:14:25.919243" } } \ No newline at end of file diff --git a/modules/nf-core/fastqc/tests/main.nf.test b/modules/nf-core/fastqc/tests/main.nf.test index e9d79a07..70edae4d 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test +++ b/modules/nf-core/fastqc/tests/main.nf.test @@ -23,14 +23,17 @@ nextflow_process { then { assertAll ( - { assert process.success }, - // NOTE The report contains the date inside it, which means that the md5sum is stable per day, but not longer than that. So you can't md5sum it. - // looks like this:
    Mon 2 Oct 2023
    test.gz
    - // https://github.com/nf-core/modules/pull/3903#issuecomment-1743620039 - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("
    ") }, - { assert snapshot(process.out.versions).match() } + { assert process.success }, + + // NOTE The report contains the date inside it, which means that the md5sum is stable per day, but not longer than that. So you can't md5sum it. + // looks like this:
    Mon 2 Oct 2023
    test.gz
    + // https://github.com/nf-core/modules/pull/3903#issuecomment-1743620039 + + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("
    ") }, + + { assert snapshot(process.out.versions).match("fastqc_versions_single") } ) } } @@ -51,14 +54,16 @@ nextflow_process { then { assertAll ( - { assert process.success }, - { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, - { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, - { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, - { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, - { assert path(process.out.html[0][1][0]).text.contains("") }, - { assert path(process.out.html[0][1][1]).text.contains("") }, - { assert snapshot(process.out.versions).match() } + { assert process.success }, + + { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, + { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, + { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, + { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, + { assert path(process.out.html[0][1][0]).text.contains("") }, + { assert path(process.out.html[0][1][1]).text.contains("") }, + + { assert snapshot(process.out.versions).match("fastqc_versions_paired") } ) } } @@ -78,11 +83,13 @@ nextflow_process { then { assertAll ( - { assert process.success }, - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("") }, - { assert snapshot(process.out.versions).match() } + { assert process.success }, + + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("") }, + + { assert snapshot(process.out.versions).match("fastqc_versions_interleaved") } ) } } @@ -102,11 +109,13 @@ nextflow_process { then { assertAll ( - { assert process.success }, - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("") }, - { assert snapshot(process.out.versions).match() } + { assert process.success }, + + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("") }, + + { assert snapshot(process.out.versions).match("fastqc_versions_bam") } ) } } @@ -129,20 +138,22 @@ nextflow_process { then { assertAll ( - { assert process.success }, - { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, - { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, - { assert process.out.html[0][1][2] ==~ ".*/test_3_fastqc.html" }, - { assert process.out.html[0][1][3] ==~ ".*/test_4_fastqc.html" }, - { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, - { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, - { assert process.out.zip[0][1][2] ==~ ".*/test_3_fastqc.zip" }, - { assert process.out.zip[0][1][3] ==~ ".*/test_4_fastqc.zip" }, - { assert path(process.out.html[0][1][0]).text.contains("") }, - { assert path(process.out.html[0][1][1]).text.contains("") }, - { assert path(process.out.html[0][1][2]).text.contains("") }, - { assert path(process.out.html[0][1][3]).text.contains("") }, - { assert snapshot(process.out.versions).match() } + { assert process.success }, + + { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, + { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, + { assert process.out.html[0][1][2] ==~ ".*/test_3_fastqc.html" }, + { assert process.out.html[0][1][3] ==~ ".*/test_4_fastqc.html" }, + { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, + { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, + { assert process.out.zip[0][1][2] ==~ ".*/test_3_fastqc.zip" }, + { assert process.out.zip[0][1][3] ==~ ".*/test_4_fastqc.zip" }, + { assert path(process.out.html[0][1][0]).text.contains("") }, + { assert path(process.out.html[0][1][1]).text.contains("") }, + { assert path(process.out.html[0][1][2]).text.contains("") }, + { assert path(process.out.html[0][1][3]).text.contains("") }, + + { assert snapshot(process.out.versions).match("fastqc_versions_multiple") } ) } } @@ -162,116 +173,27 @@ nextflow_process { then { assertAll ( - { assert process.success }, - { assert process.out.html[0][1] ==~ ".*/mysample_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/mysample_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("") }, - { assert snapshot(process.out.versions).match() } - ) - } - } + { assert process.success }, - test("sarscov2 single-end [fastq] - stub") { + { assert process.out.html[0][1] ==~ ".*/mysample_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/mysample_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("") }, - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [ id: 'test', single_end:true ], - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out.versions).match("fastqc_versions_custom_prefix") } ) } } - test("sarscov2 paired-end [fastq] - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 interleaved [fastq] - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 paired-end [bam] - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } + test("sarscov2 single-end [fastq] - stub") { - test("sarscov2 multiple [fastq] - stub") { + options "-stub" - options "-stub" when { process { """ input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) ] + [ id: 'test', single_end:true ], + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] ]) """ } @@ -279,31 +201,12 @@ nextflow_process { then { assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert process.success }, + { assert snapshot(process.out.html.collect { file(it[1]).getName() } + + process.out.zip.collect { file(it[1]).getName() } + + process.out.versions ).match("fastqc_stub") } ) } } - test("sarscov2 custom_prefix - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [ id:'mysample', single_end:true ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } } diff --git a/modules/nf-core/fastqc/tests/main.nf.test.snap b/modules/nf-core/fastqc/tests/main.nf.test.snap index d5db3092..86f7c311 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test.snap +++ b/modules/nf-core/fastqc/tests/main.nf.test.snap @@ -1,392 +1,88 @@ { - "sarscov2 custom_prefix": { + "fastqc_versions_interleaved": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.10.1" }, - "timestamp": "2024-07-22T11:02:16.374038" + "timestamp": "2024-01-31T17:40:07.293713" }, - "sarscov2 single-end [fastq] - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": true - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": true - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": true - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:24.993809" - }, - "sarscov2 custom_prefix - stub": { - "content": [ - { - "0": [ - [ - { - "id": "mysample", - "single_end": true - }, - "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "mysample", - "single_end": true - }, - "mysample.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "mysample", - "single_end": true - }, - "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "mysample", - "single_end": true - }, - "mysample.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:03:10.93942" - }, - "sarscov2 interleaved [fastq]": { + "fastqc_stub": { "content": [ [ + "test.html", + "test.zip", "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.10.1" }, - "timestamp": "2024-07-22T11:01:42.355718" + "timestamp": "2024-01-31T17:31:01.425198" }, - "sarscov2 paired-end [bam]": { + "fastqc_versions_multiple": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.10.1" }, - "timestamp": "2024-07-22T11:01:53.276274" + "timestamp": "2024-01-31T17:40:55.797907" }, - "sarscov2 multiple [fastq]": { + "fastqc_versions_bam": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.10.1" }, - "timestamp": "2024-07-22T11:02:05.527626" + "timestamp": "2024-01-31T17:40:26.795862" }, - "sarscov2 paired-end [fastq]": { + "fastqc_versions_single": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:01:31.188871" - }, - "sarscov2 paired-end [fastq] - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.10.1" }, - "timestamp": "2024-07-22T11:02:34.273566" + "timestamp": "2024-01-31T17:39:27.043675" }, - "sarscov2 multiple [fastq] - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:03:02.304411" - }, - "sarscov2 single-end [fastq]": { + "fastqc_versions_paired": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:01:19.095607" - }, - "sarscov2 interleaved [fastq] - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.10.1" }, - "timestamp": "2024-07-22T11:02:44.640184" + "timestamp": "2024-01-31T17:39:47.584191" }, - "sarscov2 paired-end [bam] - stub": { + "fastqc_versions_custom_prefix": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.10.1" }, - "timestamp": "2024-07-22T11:02:53.550742" + "timestamp": "2024-01-31T17:41:14.576531" } } \ No newline at end of file diff --git a/modules/nf-core/hisat2/align/main.nf b/modules/nf-core/hisat2/align/main.nf index ea186f62..2289a9fc 100644 --- a/modules/nf-core/hisat2/align/main.nf +++ b/modules/nf-core/hisat2/align/main.nf @@ -90,23 +90,4 @@ process HISAT2_ALIGN { END_VERSIONS """ } - - stub: - def prefix = task.ext.prefix ?: "${meta.id}" - def unaligned = params.save_unaligned ? "echo '' | gzip > ${prefix}.unmapped_1.fastq.gz \n echo '' | gzip > ${prefix}.unmapped_2.fastq.gz" : '' - def VERSION = '2.2.1' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. - """ - ${unaligned} - - touch ${prefix}.hisat2.summary.log - touch ${prefix}.bam - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - hisat2: $VERSION - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS - """ - - } diff --git a/modules/nf-core/hisat2/align/tests/main.nf.test b/modules/nf-core/hisat2/align/tests/main.nf.test index 396757d7..3a520e9a 100644 --- a/modules/nf-core/hisat2/align/tests/main.nf.test +++ b/modules/nf-core/hisat2/align/tests/main.nf.test @@ -68,63 +68,6 @@ nextflow_process { } } - test("Single-End - stub") { - options "-stub" - - setup { - run("HISAT2_EXTRACTSPLICESITES") { - script "../../extractsplicesites/main.nf" - process { - """ - input[0] = Channel.of([ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) - ]) - """ - } - } - - run("HISAT2_BUILD") { - script "../../build/main.nf" - process { - """ - input[0] = Channel.of([ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) - input[1] = Channel.of([ [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) - ]) - input[2] = HISAT2_EXTRACTSPLICESITES.out.txt - """ - } - } - } - - when { - params { - outdir = "$outputDir" - } - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:true ], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)] - ]) - input[1] = HISAT2_BUILD.out.index - input[2] = HISAT2_EXTRACTSPLICESITES.out.txt - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - test("Paired-End") { setup { @@ -184,64 +127,6 @@ nextflow_process { } } - test("Paired-End - stub") { - options "-stub" - - setup { - run("HISAT2_EXTRACTSPLICESITES") { - script "../../extractsplicesites/main.nf" - process { - """ - input[0] = Channel.of([ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) - ]) - """ - } - } - - run("HISAT2_BUILD") { - script "../../build/main.nf" - process { - """ - input[0] = Channel.of([ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) - input[1] = Channel.of([ [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) - ]) - input[2] = HISAT2_EXTRACTSPLICESITES.out.txt - """ - } - } - } - - when { - params { - outdir = "$outputDir" - } - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] - ]) - input[1] = HISAT2_BUILD.out.index - input[2] = HISAT2_EXTRACTSPLICESITES.out.txt - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - test("Single-End No Splice Sites") { setup { @@ -286,49 +171,6 @@ nextflow_process { } } - test("Single-End No Splice Sites - stub") { - options "-stub" - - setup { - run("HISAT2_BUILD") { - script "../../build/main.nf" - process { - """ - input[0] = Channel.of([ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) - input[1] = [[:],[]] - input[2] = [[:],[]] - """ - } - } - } - - when { - params { - outdir = "$outputDir" - } - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:true ], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] - ]) - input[1] = HISAT2_BUILD.out.index - input[2] = [[:],[]] - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - test("Paired-End No Splice Sites") { setup { @@ -373,48 +215,4 @@ nextflow_process { ) } } - - test("Paired-End No Splice Sites - stub") { - options "-stub" - - setup { - run("HISAT2_BUILD") { - script "../../build/main.nf" - process { - """ - input[0] = Channel.of([ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) - input[1] = [[:],[]] - input[2] = [[:],[]] - """ - } - } - } - - when { - params { - outdir = "$outputDir" - } - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] - ]) - input[1] = HISAT2_BUILD.out.index - input[2] = [[:],[]] - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } } diff --git a/modules/nf-core/hisat2/align/tests/main.nf.test.snap b/modules/nf-core/hisat2/align/tests/main.nf.test.snap index ff670d45..a80fa3c5 100644 --- a/modules/nf-core/hisat2/align/tests/main.nf.test.snap +++ b/modules/nf-core/hisat2/align/tests/main.nf.test.snap @@ -5,129 +5,21 @@ "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:08:33.735489" + "timestamp": "2023-10-16T15:14:50.269895296" }, - "Paired-End - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - - ], - "3": [ - "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "fastq": [ - - ], - "summary": [ - [ - { - "id": "test", - "single_end": false - }, - "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:09:14.35626" - }, - "Single-End - stub": { + "se_no_ss_summary": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": true - }, - "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - - ], - "3": [ - "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" - ], - "bam": [ - [ - { - "id": "test", - "single_end": true - }, - "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "fastq": [ - - ], - "summary": [ - [ - { - "id": "test", - "single_end": true - }, - "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" + [ + [ + { + "id": "test", + "single_end": true + }, + "test.hisat2.summary.log:md5,7b8a9e61b7646da1089b041333c41a87" ] - } + ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:08:47.404885" + "timestamp": "2023-10-16T15:15:22.897386626" }, "pe_no_ss_versions": { "content": [ @@ -135,70 +27,15 @@ "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:09:52.076955" + "timestamp": "2023-10-16T15:15:42.583699978" }, - "Paired-End No Splice Sites - stub": { + "se_no_ss_versions": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - - ], - "3": [ - "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "fastq": [ - - ], - "summary": [ - [ - { - "id": "test", - "single_end": false - }, - "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" - ] - } + [ + "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" + ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:10:03.739697" + "timestamp": "2023-10-16T15:15:22.909407356" }, "pe_no_ss_summary": { "content": [ @@ -212,11 +49,7 @@ ] ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:09:52.068244" + "timestamp": "2023-10-16T15:15:42.569775538" }, "pe_no_ss_fastq": { "content": [ @@ -224,11 +57,7 @@ ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:09:52.072985" + "timestamp": "2023-10-16T15:15:42.576881608" }, "se_summary": { "content": [ @@ -242,11 +71,7 @@ ] ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:08:33.727355" + "timestamp": "2023-10-16T15:14:50.252466896" }, "pe_summary": { "content": [ @@ -260,11 +85,7 @@ ] ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:09:01.495439" + "timestamp": "2023-10-16T15:15:09.881690889" }, "pe_fastq": { "content": [ @@ -272,124 +93,23 @@ ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:09:01.500755" + "timestamp": "2023-10-16T15:15:09.888696129" }, - "se_fastq": { + "se_no_ss_fastq": { "content": [ [ ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:08:33.732523" - }, - "se_no_ss_summary": { - "content": [ - [ - [ - { - "id": "test", - "single_end": true - }, - "test.hisat2.summary.log:md5,7b8a9e61b7646da1089b041333c41a87" - ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:09:26.851884" + "timestamp": "2023-10-16T15:15:22.904010016" }, - "se_no_ss_versions": { - "content": [ - [ - "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:09:26.89234" - }, - "se_no_ss_fastq": { + "se_fastq": { "content": [ [ ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:09:26.871369" - }, - "Single-End No Splice Sites - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": true - }, - "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - - ], - "3": [ - "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" - ], - "bam": [ - [ - { - "id": "test", - "single_end": true - }, - "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "fastq": [ - - ], - "summary": [ - [ - { - "id": "test", - "single_end": true - }, - "test.hisat2.summary.log:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:09:39.544807" + "timestamp": "2023-10-16T15:14:50.264366105" }, "pe_versions": { "content": [ @@ -397,10 +117,6 @@ "versions.yml:md5,ceb638f44ebdaf09ba1f5c5c409585e2" ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T09:09:01.506346" + "timestamp": "2023-10-16T15:15:09.894683308" } } \ No newline at end of file diff --git a/modules/nf-core/hisat2/build/main.nf b/modules/nf-core/hisat2/build/main.nf index 17d8fdd5..766e8731 100644 --- a/modules/nf-core/hisat2/build/main.nf +++ b/modules/nf-core/hisat2/build/main.nf @@ -61,15 +61,4 @@ process HISAT2_BUILD { hisat2: $VERSION END_VERSIONS """ - - stub: - def VERSION = '2.2.1' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. - """ - mkdir hisat2 - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - hisat2: $VERSION - END_VERSIONS - """ } diff --git a/modules/nf-core/hisat2/build/tests/main.nf.test b/modules/nf-core/hisat2/build/tests/main.nf.test index e19692c4..5b31debc 100644 --- a/modules/nf-core/hisat2/build/tests/main.nf.test +++ b/modules/nf-core/hisat2/build/tests/main.nf.test @@ -50,49 +50,4 @@ nextflow_process { ) } } - - test("Should run without failures - stub") { - - options "-stub" - - setup { - run("HISAT2_EXTRACTSPLICESITES") { - script "../../extractsplicesites/main.nf" - process { - """ - input[0] = Channel.of([ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) - ]) - """ - } - } - } - - when { - params { - outdir = "$outputDir" - } - - process { - """ - input[0] = Channel.of([ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) - input[1] = Channel.of([ [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) - ]) - input[2] = HISAT2_EXTRACTSPLICESITES.out.txt - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } -} \ No newline at end of file +} diff --git a/modules/nf-core/hisat2/build/tests/main.nf.test.snap b/modules/nf-core/hisat2/build/tests/main.nf.test.snap index 0e3b5c57..c7d364db 100644 --- a/modules/nf-core/hisat2/build/tests/main.nf.test.snap +++ b/modules/nf-core/hisat2/build/tests/main.nf.test.snap @@ -1,64 +1,4 @@ { - "test - stub": { - "content": [ - { - "0": [ - - ], - "1": [ - - ], - "index": [ - - ], - "versions": [ - - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-20T17:29:31.567024" - }, - "Should run without failures - stub": { - "content": [ - { - "0": [ - [ - { - "id": "genome" - }, - [ - - ] - ] - ], - "1": [ - "versions.yml:md5,e36ef3cd73d19ccf2378c9358fe942c0" - ], - "index": [ - [ - { - "id": "genome" - }, - [ - - ] - ] - ], - "versions": [ - "versions.yml:md5,e36ef3cd73d19ccf2378c9358fe942c0" - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-20T18:18:08.896422" - }, "Should run without failures": { "content": [ { @@ -104,10 +44,6 @@ ] } ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, "timestamp": "2023-10-16T14:42:22.381609786" } -} +} \ No newline at end of file diff --git a/modules/nf-core/hisat2/extractsplicesites/main.nf b/modules/nf-core/hisat2/extractsplicesites/main.nf index 588a9947..b0c8513a 100644 --- a/modules/nf-core/hisat2/extractsplicesites/main.nf +++ b/modules/nf-core/hisat2/extractsplicesites/main.nf @@ -28,15 +28,4 @@ process HISAT2_EXTRACTSPLICESITES { hisat2: $VERSION END_VERSIONS """ - - stub: - def VERSION = '2.2.1' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. - """ - touch ${gtf.baseName}.splice_sites.txt - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - hisat2: $VERSION - END_VERSIONS - """ } diff --git a/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test b/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test index 14129cff..72eb6d53 100644 --- a/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test +++ b/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test @@ -32,30 +32,4 @@ nextflow_process { ) } } - - test("test - stub") { - - options "-stub" - - when { - params { - outdir = "$outputDir" - } - process { - """ - input[0] = Channel.of([ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gtf', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } } diff --git a/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test.snap b/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test.snap index 1dcd8af2..17f1c8eb 100644 --- a/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test.snap +++ b/modules/nf-core/hisat2/extractsplicesites/tests/main.nf.test.snap @@ -1,47 +1,10 @@ { - "test - stub": { - "content": [ - { - "0": [ - [ - { - "id": "genome" - }, - "genome.splice_sites.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - "versions.yml:md5,eeea7231fe197810659b8bad4133aff2" - ], - "txt": [ - [ - { - "id": "genome" - }, - "genome.splice_sites.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,eeea7231fe197810659b8bad4133aff2" - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-20T17:34:13.229903" - }, "Should run without failures": { "content": [ [ "versions.yml:md5,eeea7231fe197810659b8bad4133aff2" ] ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, "timestamp": "2024-01-18T20:56:30.71763" } } \ No newline at end of file diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index 2121492d..ca39fb67 100644 --- a/modules/nf-core/multiqc/environment.yml +++ b/modules/nf-core/multiqc/environment.yml @@ -4,4 +4,4 @@ channels: - bioconda - defaults dependencies: - - bioconda::multiqc=1.23 + - bioconda::multiqc=1.21 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 459dfea5..47ac352f 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -3,16 +3,14 @@ process MULTIQC { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.23--pyhdfd78af_0' : - 'biocontainers/multiqc:1.23--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.21--pyhdfd78af_0' : + 'biocontainers/multiqc:1.21--pyhdfd78af_0' }" input: path multiqc_files, stageAs: "?/*" path(multiqc_config) path(extra_multiqc_config) path(multiqc_logo) - path(replace_names) - path(sample_names) output: path "*multiqc_report.html", emit: report @@ -28,8 +26,6 @@ process MULTIQC { def config = multiqc_config ? "--config $multiqc_config" : '' def extra_config = extra_multiqc_config ? "--config $extra_multiqc_config" : '' def logo = multiqc_logo ? /--cl-config 'custom_logo: "${multiqc_logo}"'/ : '' - def replace = replace_names ? "--replace-names ${replace_names}" : '' - def samples = sample_names ? "--sample-names ${sample_names}" : '' """ multiqc \\ --force \\ @@ -37,8 +33,6 @@ process MULTIQC { $config \\ $extra_config \\ $logo \\ - $replace \\ - $samples \\ . cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index 382c08cb..45a9bc35 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -29,19 +29,6 @@ input: type: file description: Optional logo file for MultiQC pattern: "*.{png}" - - replace_names: - type: file - description: | - Optional two-column sample renaming file. First column a set of - patterns, second column a set of corresponding replacements. Passed via - MultiQC's `--replace-names` option. - pattern: "*.{tsv}" - - sample_names: - type: file - description: | - Optional TSV file with headers, passed to the MultiQC --sample_names - argument. - pattern: "*.{tsv}" output: - report: type: file diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test index 6aa27f4c..f1c4242e 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -17,8 +17,6 @@ nextflow_process { input[1] = [] input[2] = [] input[3] = [] - input[4] = [] - input[5] = [] """ } } @@ -43,8 +41,6 @@ nextflow_process { input[1] = Channel.of(file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true)) input[2] = [] input[3] = [] - input[4] = [] - input[5] = [] """ } } @@ -70,8 +66,6 @@ nextflow_process { input[1] = [] input[2] = [] input[3] = [] - input[4] = [] - input[5] = [] """ } } diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap index 45e95e5d..bfebd802 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -2,14 +2,14 @@ "multiqc_versions_single": { "content": [ [ - "versions.yml:md5,87904cd321df21fac35d18f0fc01bb19" + "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nextflow": "23.10.1" }, - "timestamp": "2024-07-10T12:41:34.562023" + "timestamp": "2024-02-29T08:48:55.657331" }, "multiqc_stub": { "content": [ @@ -17,25 +17,25 @@ "multiqc_report.html", "multiqc_data", "multiqc_plots", - "versions.yml:md5,87904cd321df21fac35d18f0fc01bb19" + "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nextflow": "23.10.1" }, - "timestamp": "2024-07-10T11:27:11.933869532" + "timestamp": "2024-02-29T08:49:49.071937" }, "multiqc_versions_config": { "content": [ [ - "versions.yml:md5,87904cd321df21fac35d18f0fc01bb19" + "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" ] ], "meta": { "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nextflow": "23.10.1" }, - "timestamp": "2024-07-10T11:26:56.709849369" + "timestamp": "2024-02-29T08:49:25.457567" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test b/modules/nf-core/samtools/flagstat/tests/main.nf.test index 3b648a37..24c3c04b 100644 --- a/modules/nf-core/samtools/flagstat/tests/main.nf.test +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test @@ -11,30 +11,9 @@ nextflow_process { test("BAM") { when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - 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) - ]) - """ + params { + outdir = "$outputDir" } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("BAM - stub") { - - options "-stub" - - when { process { """ input[0] = Channel.of([ @@ -49,7 +28,8 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out.flagstat).match("flagstat") }, + { assert snapshot(process.out.versions).match("versions") } ) } } diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap index 23989c61..e9f85efa 100644 --- a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap @@ -1,72 +1,32 @@ { - "BAM - stub": { + "flagstat": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.flagstat:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" - ], - "flagstat": [ - [ - { - "id": "test", - "single_end": false - }, - "test.flagstat:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" + [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" ] - } + ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.04.3" }, - "timestamp": "2024-07-22T14:17:28.002887" + "timestamp": "2024-02-12T18:31:37.783927" }, - "BAM": { + "versions": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" - ] - ], - "1": [ - "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" - ], - "flagstat": [ - [ - { - "id": "test", - "single_end": false - }, - "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" - ] - ], - "versions": [ - "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" - ] - } + [ + "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" + ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.10.1" }, - "timestamp": "2024-07-22T14:17:13.330971" + "timestamp": "2024-05-28T15:41:52.516253882" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test b/modules/nf-core/samtools/idxstats/tests/main.nf.test index 5fd1fc78..a2dcb27c 100644 --- a/modules/nf-core/samtools/idxstats/tests/main.nf.test +++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test @@ -11,28 +11,9 @@ nextflow_process { test("bam") { when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - 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) - ]) - """ + params { + outdir = "$outputDir" } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("bam - stub") { - options "-stub" - when { process { """ input[0] = Channel.of([ @@ -47,7 +28,9 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out.idxstats).match("idxstats") }, + { assert snapshot(process.out.versions).match("versions") } ) } - }} + } +} diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap index a5ac8104..4eacdb90 100644 --- a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap @@ -1,72 +1,32 @@ { - "bam - stub": { + "versions": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" - ], - "idxstats": [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" - ] - } + [ + "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" + ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.10.1" }, - "timestamp": "2024-07-22T14:17:56.180093" + "timestamp": "2024-05-28T15:46:46.617989517" }, - "bam": { + "idxstats": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" - ] - ], - "1": [ - "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" - ], - "idxstats": [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" - ] - ], - "versions": [ - "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" + [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" ] - } + ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.04.3" }, - "timestamp": "2024-07-22T14:17:41.408704" + "timestamp": "2024-02-12T18:36:41.561026" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/index/main.nf b/modules/nf-core/samtools/index/main.nf index e002585b..b523c21b 100644 --- a/modules/nf-core/samtools/index/main.nf +++ b/modules/nf-core/samtools/index/main.nf @@ -35,11 +35,10 @@ process SAMTOOLS_INDEX { """ stub: - def args = task.ext.args ?: '' - def extension = file(input).getExtension() == 'cram' ? - "crai" : args.contains("-c") ? "csi" : "bai" """ - touch ${input}.${extension} + touch ${input}.bai + touch ${input}.crai + touch ${input}.csi cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/samtools/index/tests/main.nf.test b/modules/nf-core/samtools/index/tests/main.nf.test index ca34fb5c..bb7756d1 100644 --- a/modules/nf-core/samtools/index/tests/main.nf.test +++ b/modules/nf-core/samtools/index/tests/main.nf.test @@ -9,49 +9,11 @@ nextflow_process { tag "samtools/index" test("bai") { - when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - test("crai") { when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram', checkIfExists: true) - ]) - """ + params { + outdir = "$outputDir" } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("csi") { - config "./csi.nextflow.config" - - when { process { """ input[0] = Channel.of([ @@ -65,38 +27,18 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot( - file(process.out.csi[0][1]).name, - process.out.versions - ).match() } + { assert snapshot(process.out.bai).match("bai") }, + { assert snapshot(process.out.versions).match("bai_versions") } ) } } - test("bai - stub") { - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } + test("crai") { - test("crai - stub") { - options "-stub" when { + params { + outdir = "$outputDir" + } process { """ input[0] = Channel.of([ @@ -110,16 +52,20 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out.crai).match("crai") }, + { assert snapshot(process.out.versions).match("crai_versions") } ) } } - test("csi - stub") { - options "-stub" + test("csi") { + config "./csi.nextflow.config" when { + params { + outdir = "$outputDir" + } process { """ input[0] = Channel.of([ @@ -133,7 +79,8 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert path(process.out.csi.get(0).get(1)).exists() }, + { assert snapshot(process.out.versions).match("csi_versions") } ) } } diff --git a/modules/nf-core/samtools/index/tests/main.nf.test.snap b/modules/nf-core/samtools/index/tests/main.nf.test.snap index 799d199c..52756e85 100644 --- a/modules/nf-core/samtools/index/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/index/tests/main.nf.test.snap @@ -1,250 +1,74 @@ { - "csi - stub": { + "crai_versions": { "content": [ - { - "0": [ - - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - - ], - "3": [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ], - "bai": [ - - ], - "crai": [ - - ], - "csi": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T16:51:53.9057" - }, - "crai - stub": { - "content": [ - { - "0": [ - - ], - "1": [ - - ], - "2": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.recalibrated.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ], - "bai": [ - - ], - "crai": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.recalibrated.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "csi": [ - - ], - "versions": [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ] - } + [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.10.1" }, - "timestamp": "2024-07-22T16:51:45.931558" + "timestamp": "2024-05-28T15:42:04.203740976" }, - "bai - stub": { + "csi_versions": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ], - "bai": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "crai": [ - - ], - "csi": [ - - ], - "versions": [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ] - } + [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.10.1" }, - "timestamp": "2024-07-22T16:51:34.807525" + "timestamp": "2024-05-28T15:42:09.57475878" }, - "csi": { + "crai": { "content": [ - "test.paired_end.sorted.bam.csi", [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" + ] ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.04.3" }, - "timestamp": "2024-07-22T16:52:55.688799" + "timestamp": "2024-02-12T18:41:38.446424" }, - "crai": { + "bai": { "content": [ - { - "0": [ - - ], - "1": [ - - ], - "2": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" - ] - ], - "3": [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ], - "bai": [ - - ], - "crai": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" - ] - ], - "csi": [ - - ], - "versions": [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" ] - } + ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.04.3" }, - "timestamp": "2024-07-22T16:51:17.609533" + "timestamp": "2024-02-12T18:40:46.579747" }, - "bai": { + "bai_versions": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" - ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ], - "bai": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" - ] - ], - "crai": [ - - ], - "csi": [ - - ], - "versions": [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ] - } + [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.10.1" }, - "timestamp": "2024-07-22T16:51:04.16585" + "timestamp": "2024-05-28T15:41:57.929287369" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/sort/main.nf b/modules/nf-core/samtools/sort/main.nf index 8e019099..596c6f7e 100644 --- a/modules/nf-core/samtools/sort/main.nf +++ b/modules/nf-core/samtools/sort/main.nf @@ -50,20 +50,10 @@ process SAMTOOLS_SORT { """ stub: - def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - def extension = args.contains("--output-fmt sam") ? "sam" : - args.contains("--output-fmt cram") ? "cram" : - "bam" """ - touch ${prefix}.${extension} - if [ "${extension}" == "bam" ]; - then - touch ${prefix}.${extension}.csi - elif [ "${extension}" == "cram" ]; - then - touch ${prefix}.${extension}.crai - fi + touch ${prefix}.bam + touch ${prefix}.bam.csi cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test b/modules/nf-core/samtools/sort/tests/main.nf.test index c2ea9c72..fb38ed9b 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test +++ b/modules/nf-core/samtools/sort/tests/main.nf.test @@ -32,16 +32,16 @@ nextflow_process { { assert process.success }, { assert snapshot( process.out.bam, - process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } }, - process.out.versions - ).match()} + process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } } + ).match("test_bam") + } ) } } test("cram") { - config "./nextflow_cram.config" + config "./nextflow.config" when { process { @@ -62,20 +62,23 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - process.out.cram.collect { it.collect { it instanceof Map ? it : file(it).name } }, - process.out.crai.collect { it.collect { it instanceof Map ? it : file(it).name } }, - process.out.versions - ).match()} + process.out.bam, + process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } } + ).match("test_cram") + } ) } } - test("bam - stub") { + test("bam_stub") { - options "-stub" config "./nextflow.config" + options "-stub" when { + params { + outdir = "$outputDir" + } process { """ input[0] = Channel.of([ @@ -93,35 +96,8 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("cram - stub") { - - options "-stub" - config "./nextflow_cram.config" - - when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true) - ]) - input[1] = Channel.of([ - [ id:'fasta' ], // meta map - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(file(process.out.bam[0][1]).name).match("bam_stub_bam") }, + { assert snapshot(process.out.versions).match("bam_stub_versions") } ) } } diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test.snap b/modules/nf-core/samtools/sort/tests/main.nf.test.snap index da38d5d1..5a27de1d 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/sort/tests/main.nf.test.snap @@ -7,159 +7,54 @@ "id": "test", "single_end": false }, - "test.sorted.cram" - ] - ], - [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.cram.crai" + "test.sorted.bam:md5,21c992d59615936b99f2ad008aa54400" ] - ], - [ - "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "24.04.2" }, - "timestamp": "2024-07-22T17:19:37.196205" + "timestamp": "2024-05-31T08:13:54.512837189" }, - "bam - stub": { + "bam_stub_bam": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "4": [ - "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "crai": [ - - ], - "cram": [ - - ], - "csi": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" - ] - } + "test.sorted.bam" ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "24.04.2" }, - "timestamp": "2024-07-22T15:54:46.580756" + "timestamp": "2024-05-31T07:29:00.761845507" }, - "cram - stub": { + "test_cram": { "content": [ - { - "0": [ - - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.cram:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - - ], - "4": [ - "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" - ], - "bam": [ - - ], - "crai": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "cram": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.cram:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "csi": [ - - ], - "versions": [ - "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,22b2093be34a7637f5fbc84272b89d06" + ] + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.csi" ] - } + ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "24.04.2" }, - "timestamp": "2024-07-22T15:57:30.505698" + "timestamp": "2024-05-31T09:16:51.924951855" }, - "bam": { + "test_bam": { "content": [ [ [ @@ -178,15 +73,42 @@ }, "test.sorted.bam.csi" ] - ], + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-05-31T08:28:12.15952312" + }, + "bam_stub_versions": { + "content": [ [ "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-05-31T07:29:00.765038811" + }, + "bam": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,21c992d59615936b99f2ad008aa54400" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" }, - "timestamp": "2024-07-22T15:54:25.872954" + "timestamp": "2024-05-31T08:13:48.538030517" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/sort/tests/nextflow_cram.config b/modules/nf-core/samtools/sort/tests/nextflow_cram.config deleted file mode 100644 index 3a8c0188..00000000 --- a/modules/nf-core/samtools/sort/tests/nextflow_cram.config +++ /dev/null @@ -1,8 +0,0 @@ -process { - - withName: SAMTOOLS_SORT { - ext.prefix = { "${meta.id}.sorted" } - ext.args = "--write-index --output-fmt cram" - } - -} diff --git a/modules/nf-core/samtools/stats/tests/main.nf.test b/modules/nf-core/samtools/stats/tests/main.nf.test index 28a77db2..e3d5cb14 100644 --- a/modules/nf-core/samtools/stats/tests/main.nf.test +++ b/modules/nf-core/samtools/stats/tests/main.nf.test @@ -11,6 +11,9 @@ nextflow_process { test("bam") { when { + params { + outdir = "$outputDir" + } process { """ input[0] = Channel.of([ @@ -34,59 +37,9 @@ nextflow_process { test("cram") { when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram.crai', checkIfExists: true) - ]) - input[1] = Channel.of([ - [ id:'genome' ], // meta map - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) - ]) - """ + params { + outdir = "$outputDir" } - } - - then { - assertAll( - {assert process.success}, - {assert snapshot(process.out).match()} - ) - } - } - - test("bam - stub") { - - options "-stub" - - when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - 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] = [[],[]] - """ - } - } - - then { - assertAll( - {assert process.success}, - {assert snapshot(process.out).match()} - ) - } - } - - test("cram - stub") { - - options "-stub" - - when { process { """ input[0] = Channel.of([ diff --git a/modules/nf-core/samtools/stats/tests/main.nf.test.snap b/modules/nf-core/samtools/stats/tests/main.nf.test.snap index 3828f378..2747fd6c 100644 --- a/modules/nf-core/samtools/stats/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/stats/tests/main.nf.test.snap @@ -29,80 +29,10 @@ } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.10.1" }, - "timestamp": "2024-07-22T14:20:24.885816" - }, - "bam - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" - ], - "stats": [ - [ - { - "id": "test", - "single_end": false - }, - "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T14:20:39.310713" - }, - "cram - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" - ], - "stats": [ - [ - { - "id": "test", - "single_end": false - }, - "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T14:21:04.771199" + "timestamp": "2024-05-28T15:45:24.403941966" }, "bam": { "content": [ @@ -134,9 +64,9 @@ } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.10.1" }, - "timestamp": "2024-07-22T14:19:06.645466" + "timestamp": "2024-05-28T15:45:06.711251947" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/view/main.nf b/modules/nf-core/samtools/view/main.nf index dc611448..38df8576 100644 --- a/modules/nf-core/samtools/view/main.nf +++ b/modules/nf-core/samtools/view/main.nf @@ -13,15 +13,13 @@ process SAMTOOLS_VIEW { path qname output: - tuple val(meta), path("${prefix}.bam"), emit: bam, optional: true - tuple val(meta), path("${prefix}.cram"), emit: cram, optional: true - tuple val(meta), path("${prefix}.sam"), emit: sam, optional: true - tuple val(meta), path("${prefix}.${file_type}.bai"), emit: bai, optional: true - tuple val(meta), path("${prefix}.${file_type}.csi"), emit: csi, optional: true - tuple val(meta), path("${prefix}.${file_type}.crai"), emit: crai, optional: true - tuple val(meta), path("${prefix}.unselected.${file_type}"), emit: unselected, optional: true - tuple val(meta), path("${prefix}.unselected.${file_type}.{bai,csi,crsi}"), emit: unselected_index, optional: true - path "versions.yml", emit: versions + tuple val(meta), path("*.bam"), emit: bam, optional: true + tuple val(meta), path("*.cram"), emit: cram, optional: true + tuple val(meta), path("*.sam"), emit: sam, optional: true + tuple val(meta), path("*.bai"), emit: bai, optional: true + tuple val(meta), path("*.csi"), emit: csi, optional: true + tuple val(meta), path("*.crai"), emit: crai, optional: true + path "versions.yml", emit: versions when: task.ext.when == null || task.ext.when @@ -29,13 +27,13 @@ process SAMTOOLS_VIEW { script: def args = task.ext.args ?: '' def args2 = task.ext.args2 ?: '' - prefix = task.ext.prefix ?: "${meta.id}" + def prefix = task.ext.prefix ?: "${meta.id}" def reference = fasta ? "--reference ${fasta}" : "" - file_type = args.contains("--output-fmt sam") ? "sam" : - args.contains("--output-fmt bam") ? "bam" : - args.contains("--output-fmt cram") ? "cram" : - input.getExtension() - readnames = qname ? "--qname-file ${qname} --output-unselected ${prefix}.unselected.${file_type}": "" + def readnames = qname ? "--qname-file ${qname}": "" + def file_type = args.contains("--output-fmt sam") ? "sam" : + args.contains("--output-fmt bam") ? "bam" : + args.contains("--output-fmt cram") ? "cram" : + input.getExtension() if ("$input" == "${prefix}.${file_type}") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" """ samtools \\ @@ -56,14 +54,14 @@ process SAMTOOLS_VIEW { stub: def args = task.ext.args ?: '' - prefix = task.ext.prefix ?: "${meta.id}" - file_type = args.contains("--output-fmt sam") ? "sam" : - args.contains("--output-fmt bam") ? "bam" : - args.contains("--output-fmt cram") ? "cram" : - input.getExtension() + def prefix = task.ext.prefix ?: "${meta.id}" + def file_type = args.contains("--output-fmt sam") ? "sam" : + args.contains("--output-fmt bam") ? "bam" : + args.contains("--output-fmt cram") ? "cram" : + input.getExtension() if ("$input" == "${prefix}.${file_type}") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" - def index = args.contains("--write-index") ? "touch ${prefix}.${file_type}.csi" : "" + def index = args.contains("--write-index") ? "touch ${prefix}.csi" : "" """ touch ${prefix}.${file_type} diff --git a/modules/nf-core/samtools/view/meta.yml b/modules/nf-core/samtools/view/meta.yml index 27be60d0..3dadafae 100644 --- a/modules/nf-core/samtools/view/meta.yml +++ b/modules/nf-core/samtools/view/meta.yml @@ -73,15 +73,6 @@ output: type: file description: optional CRAM file index pattern: "*.{crai}" - # unselected and unselected_index are created when passing a qname - - unselected: - type: file - description: optional file with unselected alignments - pattern: "*.unselected.{bam,cram,sam}" - - unselected_index: - type: file - description: index for the "unselected" file - pattern: "*.unselected.{bai,csi,crai}" - versions: type: file description: File containing software versions diff --git a/modules/nf-core/samtools/view/tests/main.nf.test b/modules/nf-core/samtools/view/tests/main.nf.test index 37b81a91..45a0defb 100644 --- a/modules/nf-core/samtools/view/tests/main.nf.test +++ b/modules/nf-core/samtools/view/tests/main.nf.test @@ -172,8 +172,6 @@ nextflow_process { { assert snapshot(process.out.crai).match("cram_to_bam_index_qname_crai") }, { assert snapshot(process.out.cram).match("cram_to_bam_index_qname_cram") }, { assert snapshot(process.out.sam).match("cram_to_bam_index_qname_sam") }, - { assert snapshot(file(process.out.unselected[0][1]).name).match("cram_to_bam_index_qname_unselected") }, - { assert snapshot(file(process.out.unselected_index[0][1]).name).match("cram_to_bam_index_qname_unselected_csi") }, { assert snapshot(process.out.versions).match("cram_to_bam_index_qname_versions") } ) } diff --git a/modules/nf-core/samtools/view/tests/main.nf.test.snap b/modules/nf-core/samtools/view/tests/main.nf.test.snap index 6bcce9fe..eb0c577c 100644 --- a/modules/nf-core/samtools/view/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/view/tests/main.nf.test.snap @@ -355,26 +355,6 @@ }, "timestamp": "2024-02-12T19:38:23.322874" }, - "cram_to_bam_index_qname_unselected": { - "content": [ - "test.unselected.bam" - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" - }, - "timestamp": "2024-02-12T19:38:23.322874" - }, - "cram_to_bam_index_qname_unselected_csi": { - "content": [ - "test.unselected.bam.csi" - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" - }, - "timestamp": "2024-02-12T19:38:23.328458" - }, "bam_versions": { "content": [ [ @@ -497,7 +477,7 @@ }, "bam_stub_csi": { "content": [ - "test.bam.csi" + "test.csi" ], "meta": { "nf-test": "0.8.4", diff --git a/modules/nf-core/star/align/main.nf b/modules/nf-core/star/align/main.nf index ae67e004..8e9c48b1 100644 --- a/modules/nf-core/star/align/main.nf +++ b/modules/nf-core/star/align/main.nf @@ -81,8 +81,6 @@ process STAR_ALIGN { stub: def prefix = task.ext.prefix ?: "${meta.id}" """ - echo "" | gzip > ${prefix}.unmapped_1.fastq.gz - echo "" | gzip > ${prefix}.unmapped_2.fastq.gz touch ${prefix}Xd.out.bam touch ${prefix}.Log.final.out touch ${prefix}.Log.out @@ -91,6 +89,8 @@ process STAR_ALIGN { touch ${prefix}.toTranscriptome.out.bam touch ${prefix}.Aligned.unsort.out.bam touch ${prefix}.Aligned.sortedByCoord.out.bam + touch ${prefix}.unmapped_1.fastq.gz + touch ${prefix}.unmapped_2.fastq.gz touch ${prefix}.tab touch ${prefix}.SJ.out.tab touch ${prefix}.ReadsPerGene.out.tab diff --git a/modules/nf-core/star/align/tests/main.nf.test b/modules/nf-core/star/align/tests/main.nf.test index 2d9f72dd..6ecd7786 100644 --- a/modules/nf-core/star/align/tests/main.nf.test +++ b/modules/nf-core/star/align/tests/main.nf.test @@ -9,367 +9,27 @@ nextflow_process { tag "star/align" tag "star/genomegenerate" - test("homo_sapiens - single_end") { - config "./nextflow.config" - - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) - """ - } - } - } - - when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:true ], // meta map - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true) ] - ]) - input[1] = STAR_GENOMEGENERATE.out.index - input[2] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) - input[3] = false - input[4] = 'illumina' - input[5] = false - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot( - file(process.out.log_final[0][1]).name, - file(process.out.log_out[0][1]).name, - file(process.out.log_progress[0][1]).name, - process.out.bam, - process.out.bam_sorted, - process.out.bam_transcript, - process.out.bam_unsorted, - process.out.bedgraph, - process.out.fastq, - process.out.junction, - process.out.read_per_gene_tab, - process.out.sam, - process.out.spl_junc_tab, - process.out.tab, - process.out.wig, - process.out.versions - ).match() } - ) - } - } - - test("homo_sapiens - paired_end") { - config "./nextflow.config" - - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) - """ - } - } - } - - when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - [ - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true) - ] - ]) - input[1] = STAR_GENOMEGENERATE.out.index - input[2] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) - input[3] = false - input[4] = 'illumina' - input[5] = false - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot( - file(process.out.log_final[0][1]).name, - file(process.out.log_out[0][1]).name, - file(process.out.log_progress[0][1]).name, - process.out.bam, - process.out.bam_sorted, - process.out.bam_transcript, - process.out.bam_unsorted, - process.out.bedgraph, - process.out.fastq, - process.out.junction, - process.out.read_per_gene_tab, - process.out.sam, - process.out.spl_junc_tab, - process.out.tab, - process.out.wig, - process.out.versions - ).match() } - ) - } - } - - test("homo_sapiens - paired_end - arriba") { - config "./nextflow.arriba.config" - - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) - """ - } - } - } - - when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - [ - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true) - ] - ]) - input[1] = STAR_GENOMEGENERATE.out.index - input[2] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) - input[3] = false - input[4] = 'illumina' - input[5] = false - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot( - file(process.out.log_final[0][1]).name, - file(process.out.log_out[0][1]).name, - file(process.out.log_progress[0][1]).name, - process.out.bam, - process.out.bam_sorted, - process.out.bam_transcript, - process.out.bam_unsorted, - process.out.bedgraph, - process.out.fastq, - process.out.junction, - process.out.read_per_gene_tab, - process.out.sam, - process.out.spl_junc_tab, - process.out.tab, - process.out.wig, - process.out.versions - ).match() } - ) - } - } - - test("homo_sapiens - paired_end - starfusion") { - config "./nextflow.starfusion.config" - - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) - """ - } - } - } - - when { + setup { + run("STAR_GENOMEGENERATE") { + script "../../../star/genomegenerate/main.nf" process { """ input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - [ - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true) - ] + [ id:'test_fasta' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] ]) - input[1] = STAR_GENOMEGENERATE.out.index - input[2] = Channel.of([ + input[1] = Channel.of([ [ id:'test_gtf' ], [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) - input[3] = false - input[4] = 'illumina' - input[5] = false """ } } - - then { - assertAll( - { assert process.success }, - { assert snapshot( - file(process.out.log_final[0][1]).name, - file(process.out.log_out[0][1]).name, - file(process.out.log_progress[0][1]).name, - process.out.bam, - process.out.bam_sorted, - process.out.bam_transcript, - process.out.bam_unsorted, - process.out.bedgraph, - process.out.fastq, - process.out.junction, - process.out.read_per_gene_tab, - process.out.sam, - process.out.spl_junc_tab, - process.out.tab, - process.out.wig, - process.out.versions - ).match() } - ) - } } - test("homo_sapiens - paired_end - multiple") { - config "./nextflow.config" - - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) - """ - } - } - } - - when { - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - [ - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_rnaseq_2.fastq.gz', checkIfExists: true) - ] - ]) - input[1] = STAR_GENOMEGENERATE.out.index - input[2] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) - input[3] = false - input[4] = 'illumina' - input[5] = false - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot( - file(process.out.log_final[0][1]).name, - file(process.out.log_out[0][1]).name, - file(process.out.log_progress[0][1]).name, - process.out.bam, - process.out.bam_sorted, - process.out.bam_transcript, - process.out.bam_unsorted, - process.out.bedgraph, - process.out.fastq, - process.out.junction, - process.out.read_per_gene_tab, - process.out.sam, - process.out.spl_junc_tab, - process.out.tab, - process.out.wig, - process.out.versions - ).match() } - ) - } - } - - test("homo_sapiens - single_end - stub") { - options "-stub" + test("homo_sapiens - single_end") { config "./nextflow.config" - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) - """ - } - } - } - when { process { """ @@ -392,33 +52,29 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - single_end - log_final") }, + { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - single_end - log_out") }, + { assert snapshot(process.out.bam).match("homo_sapiens - single_end - bam") }, + { assert snapshot(process.out.bam_sorted).match("homo_sapiens - single_end - bam_sorted") }, + { assert snapshot(process.out.bam_transcript).match("homo_sapiens - single_end - bam_transcript") }, + { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - single_end - bam_unsorted") }, + { assert snapshot(process.out.bedgraph).match("homo_sapiens - single_end - bedgraph") }, + { assert snapshot(process.out.fastq).match("homo_sapiens - single_end - fastq") }, + { assert snapshot(process.out.junction).match("homo_sapiens - single_end - junction") }, + { assert snapshot(process.out.log_progress).match("homo_sapiens - single_end - log_progress") }, + { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - single_end - read_per_gene_tab") }, + { assert snapshot(process.out.sam).match("homo_sapiens - single_end - sam") }, + { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - single_end - spl_junc_tab") }, + { assert snapshot(process.out.tab).match("homo_sapiens - single_end - tab") }, + { assert snapshot(process.out.wig).match("homo_sapiens - single_end - wig") }, + { assert snapshot(process.out.versions).match("homo_sapiens - single_end - versions") } ) } } - test("homo_sapiens - paired_end - stub") { - options "-stub" + test("homo_sapiens - paired_end") { config "./nextflow.config" - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) - """ - } - } - } - when { process { """ @@ -444,33 +100,29 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - paired_end - log_final") }, + { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - paired_end - log_out") }, + { assert snapshot(process.out.bam).match("homo_sapiens - paired_end - bam") }, + { assert snapshot(process.out.bam_sorted).match("homo_sapiens - paired_end - bam_sorted") }, + { assert snapshot(process.out.bam_transcript).match("homo_sapiens - paired_end - bam_transcript") }, + { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - paired_end - bam_unsorted") }, + { assert snapshot(process.out.bedgraph).match("homo_sapiens - paired_end - bedgraph") }, + { assert snapshot(process.out.fastq).match("homo_sapiens - paired_end - fastq") }, + { assert snapshot(process.out.junction).match("homo_sapiens - paired_end - junction") }, + { assert snapshot(process.out.log_progress).match("homo_sapiens - paired_end - log_progress") }, + { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - paired_end - read_per_gene_tab") }, + { assert snapshot(process.out.sam).match("homo_sapiens - paired_end - sam") }, + { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - paired_end - spl_junc_tab") }, + { assert snapshot(process.out.tab).match("homo_sapiens - paired_end - tab") }, + { assert snapshot(process.out.wig).match("homo_sapiens - paired_end - wig") }, + { assert snapshot(process.out.versions).match("homo_sapiens - paired_end - versions") } ) } } - test("homo_sapiens - paired_end - arriba - stub") { - options "-stub" + test("homo_sapiens - paired_end - arriba") { config "./nextflow.arriba.config" - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) - """ - } - } - } - when { process { """ @@ -496,33 +148,29 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - paired_end - arriba - log_final") }, + { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - paired_end - arriba - log_out") }, + { assert snapshot(file(process.out.log_progress[0][1]).name).match("homo_sapiens - paired_end - arriba - log_progress") }, + { assert snapshot(process.out.bam).match("homo_sapiens - paired_end - arriba - bam") }, + { assert snapshot(process.out.bam_sorted).match("homo_sapiens - paired_end - arriba - bam_sorted") }, + { assert snapshot(process.out.bam_transcript).match("homo_sapiens - paired_end - arriba - bam_transcript") }, + { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - paired_end - arriba - bam_unsorted") }, + { assert snapshot(process.out.bedgraph).match("homo_sapiens - paired_end - arriba - bedgraph") }, + { assert snapshot(process.out.fastq).match("homo_sapiens - paired_end - arriba - fastq") }, + { assert snapshot(process.out.junction).match("homo_sapiens - paired_end - arriba - junction") }, + { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - paired_end - arriba - read_per_gene_tab") }, + { assert snapshot(process.out.sam).match("homo_sapiens - paired_end - arriba - sam") }, + { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - paired_end - arriba - spl_junc_tab") }, + { assert snapshot(process.out.tab).match("homo_sapiens - paired_end - arriba - tab") }, + { assert snapshot(process.out.wig).match("homo_sapiens - paired_end - arriba - wig") }, + { assert snapshot(process.out.versions).match("homo_sapiens - paired_end - arriba - versions") } ) } } - test("homo_sapiens - paired_end - starfusion - stub") { - options "-stub" + test("homo_sapiens - paired_end - starfusion") { config "./nextflow.starfusion.config" - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) - """ - } - } - } - when { process { """ @@ -548,33 +196,29 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - paired_end - starfusion - log_final") }, + { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - paired_end - starfusion - log_out") }, + { assert snapshot(file(process.out.log_progress[0][1]).name).match("homo_sapiens - paired_end - starfusion - log_progress") }, + { assert snapshot(process.out.bam).match("homo_sapiens - paired_end - starfusion - bam") }, + { assert snapshot(process.out.bam_sorted).match("homo_sapiens - paired_end - starfusion - bam_sorted") }, + { assert snapshot(process.out.bam_transcript).match("homo_sapiens - paired_end - starfusion - bam_transcript") }, + { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - paired_end - starfusion - bam_unsorted") }, + { assert snapshot(process.out.bedgraph).match("homo_sapiens - paired_end - starfusion - bedgraph") }, + { assert snapshot(process.out.fastq).match("homo_sapiens - paired_end - starfusion - fastq") }, + { assert snapshot(process.out.junction).match("homo_sapiens - paired_end - starfusion - junction") }, + { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - paired_end - starfusion - read_per_gene_tab") }, + { assert snapshot(process.out.sam).match("homo_sapiens - paired_end - starfusion - sam") }, + { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - paired_end - starfusion - spl_junc_tab") }, + { assert snapshot(process.out.tab).match("homo_sapiens - paired_end - starfusion - tab") }, + { assert snapshot(process.out.wig).match("homo_sapiens - paired_end - starfusion - wig") }, + { assert snapshot(process.out.versions).match("homo_sapiens - paired_end - starfusion - versions") } ) } } - test("homo_sapiens - paired_end - multiple - stub") { - options "-stub" + test("homo_sapiens - paired_end - multiple") { config "./nextflow.config" - setup { - run("STAR_GENOMEGENERATE") { - script "../../../star/genomegenerate/main.nf" - process { - """ - input[0] = Channel.of([ - [ id:'test_fasta' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] - ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) - """ - } - } - } - when { process { """ @@ -602,7 +246,22 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(file(process.out.log_final[0][1]).name).match("homo_sapiens - paired_end - multiple - log_final") }, + { assert snapshot(file(process.out.log_out[0][1]).name).match("homo_sapiens - paired_end - multiple - log_out") }, + { assert snapshot(file(process.out.log_progress[0][1]).name).match("homo_sapiens - paired_end - multiple - log_progress") }, + { assert snapshot(process.out.bam).match("homo_sapiens - paired_end - multiple - bam") }, + { assert snapshot(process.out.bam_sorted).match("homo_sapiens - paired_end - multiple - bam_sorted") }, + { assert snapshot(process.out.bam_transcript).match("homo_sapiens - paired_end - multiple - bam_transcript") }, + { assert snapshot(process.out.bam_unsorted).match("homo_sapiens - paired_end - multiple - bam_unsorted") }, + { assert snapshot(process.out.bedgraph).match("homo_sapiens - paired_end - multiple - bedgraph") }, + { assert snapshot(process.out.fastq).match("homo_sapiens - paired_end - multiple - fastq") }, + { assert snapshot(process.out.junction).match("homo_sapiens - paired_end - multiple - junction") }, + { assert snapshot(process.out.read_per_gene_tab).match("homo_sapiens - paired_end - multiple - read_per_gene_tab") }, + { assert snapshot(process.out.sam).match("homo_sapiens - paired_end - multiple - sam") }, + { assert snapshot(process.out.spl_junc_tab).match("homo_sapiens - paired_end - multiple - spl_junc_tab") }, + { assert snapshot(process.out.tab).match("homo_sapiens - paired_end - multiple - tab") }, + { assert snapshot(process.out.wig).match("homo_sapiens - paired_end - multiple - wig") }, + { assert snapshot(process.out.versions).match("homo_sapiens - paired_end - multiple - versions") } ) } } diff --git a/modules/nf-core/star/align/tests/main.nf.test.snap b/modules/nf-core/star/align/tests/main.nf.test.snap index c814eb56..08edb914 100644 --- a/modules/nf-core/star/align/tests/main.nf.test.snap +++ b/modules/nf-core/star/align/tests/main.nf.test.snap @@ -1,1170 +1,382 @@ { - "homo_sapiens - single_end - stub": { + "homo_sapiens - paired_end - multiple - bam_sorted": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": true - }, - "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "10": [ - [ - { - "id": "test", - "single_end": true - }, - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "11": [ - [ - { - "id": "test", - "single_end": true - }, - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "12": [ - [ - { - "id": "test", - "single_end": true - }, - "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "13": [ - [ - { - "id": "test", - "single_end": true - }, - "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "14": [ - [ - { - "id": "test", - "single_end": true - }, - "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "15": [ - [ - { - "id": "test", - "single_end": true - }, - "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test", - "single_end": true - }, - "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" - ], - "4": [ - [ - { - "id": "test", - "single_end": true - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "5": [ - [ - { - "id": "test", - "single_end": true - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "6": [ - [ - { - "id": "test", - "single_end": true - }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "7": [ - [ - { - "id": "test", - "single_end": true - }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "8": [ - [ - { - "id": "test", - "single_end": true - }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "9": [ - [ - { - "id": "test", - "single_end": true - }, - [ - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam": [ - [ - { - "id": "test", - "single_end": true - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam_sorted": [ - [ - { - "id": "test", - "single_end": true - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam_transcript": [ - [ - { - "id": "test", - "single_end": true - }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "bam_unsorted": [ - [ - { - "id": "test", - "single_end": true - }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "bedgraph": [ - [ - { - "id": "test", - "single_end": true - }, - "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "fastq": [ - [ - { - "id": "test", - "single_end": true - }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "junction": [ - [ - { - "id": "test", - "single_end": true - }, - "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_final": [ - [ - { - "id": "test", - "single_end": true - }, - "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_out": [ - [ - { - "id": "test", - "single_end": true - }, - "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_progress": [ - [ - { - "id": "test", - "single_end": true - }, - "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "read_per_gene_tab": [ - [ - { - "id": "test", - "single_end": true - }, - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "sam": [ - [ - { - "id": "test", - "single_end": true - }, - "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "spl_junc_tab": [ - [ - { - "id": "test", - "single_end": true - }, - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "tab": [ - [ - { - "id": "test", - "single_end": true - }, - [ - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "versions": [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" - ], - "wig": [ - [ - { - "id": "test", - "single_end": true - }, - "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" - ] + [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.sortedByCoord.out.bam:md5,ab07c21d63ab0a6c07d171d213c81d5a" ] - } + ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T15:16:04.712114" + "timestamp": "2023-12-04T18:01:19.968225733" }, - "homo_sapiens - paired_end - arriba - stub": { + "homo_sapiens - paired_end - multiple - wig": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "10": [ - [ - { - "id": "test", - "single_end": false - }, - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "11": [ - [ - { - "id": "test", - "single_end": false - }, - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "12": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "13": [ - [ - { - "id": "test", - "single_end": false - }, - "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "14": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "15": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" - ], - "4": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "5": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "6": [ - [ - { - "id": "test", - "single_end": false - }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "7": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "8": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "9": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam_sorted": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam_transcript": [ - [ - { - "id": "test", - "single_end": false - }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "bam_unsorted": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "bedgraph": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "fastq": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "junction": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_final": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_out": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_progress": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "read_per_gene_tab": [ - [ - { - "id": "test", - "single_end": false - }, - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "sam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "spl_junc_tab": [ - [ - { - "id": "test", - "single_end": false - }, - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "tab": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "versions": [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" - ], - "wig": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } + [ + + ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T15:16:28.874293" + "timestamp": "2023-11-23T13:29:01.857804" }, - "homo_sapiens - single_end": { + "homo_sapiens - paired_end - arriba - tab": { "content": [ - "test.Log.final.out", - "test.Log.out", - "test.Log.progress.out", - [ - [ - { - "id": "test", - "single_end": true - }, - "test.Aligned.sortedByCoord.out.bam:md5,c6cfaccaf91bc7fdabed3cfe236d4535" - ] - ], [ [ { "id": "test", - "single_end": true + "single_end": false }, - "test.Aligned.sortedByCoord.out.bam:md5,c6cfaccaf91bc7fdabed3cfe236d4535" + "test.SJ.out.tab:md5,5155c9fd1f787ad6d7d80987fb06219c" ] - ], + ] + ], + "timestamp": "2023-12-04T17:56:12.347549723" + }, + "homo_sapiens - single_end - wig": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:22:55.24701" + }, + "homo_sapiens - paired_end - sam": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:23:33.383818" + }, + "homo_sapiens - paired_end - arriba - versions": { + "content": [ + [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ] + ], + "timestamp": "2023-12-04T17:56:12.431212643" + }, + "homo_sapiens - paired_end - multiple - bedgraph": { + "content": [ [ [ { "id": "test", - "single_end": true + "single_end": false }, [ - "test.Signal.Unique.str1.out.bg:md5,c56fc1472776fb927eaf62d973da5f9a", - "test.Signal.UniqueMultiple.str1.out.bg:md5,e93373cf6f2a2a9506e2efdb260cdd4f" + "test.Signal.Unique.str1.out.bg:md5,d7bf8b70b436ca048a62513e1d0ece3a", + "test.Signal.UniqueMultiple.str1.out.bg:md5,686d58493b9eb445b56ace4d67f76ef6" ] ] - ], - [ - - ], + ] + ], + "timestamp": "2023-12-04T18:01:20.07119229" + }, + "homo_sapiens - paired_end - read_per_gene_tab": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:23:33.368841" + }, + "homo_sapiens - paired_end - arriba - bedgraph": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:25:07.102537" + }, + "homo_sapiens - single_end - junction": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:22:55.185369" + }, + "homo_sapiens - paired_end - arriba - spl_junc_tab": { + "content": [ [ [ { "id": "test", - "single_end": true + "single_end": false }, - "test.SJ.out.tab:md5,75a516ab950fb958f40b29996474949c" + "test.SJ.out.tab:md5,5155c9fd1f787ad6d7d80987fb06219c" ] - ], + ] + ], + "timestamp": "2023-12-04T17:56:12.268388251" + }, + "homo_sapiens - single_end - sam": { + "content": [ [ - [ - { - "id": "test", - "single_end": true - }, - "test.SJ.out.tab:md5,75a516ab950fb958f40b29996474949c" - ] - ], + + ] + ], + "timestamp": "2023-11-23T13:22:55.216183" + }, + "homo_sapiens - paired_end - fastq": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:23:33.327236" + }, + "homo_sapiens - single_end - versions": { + "content": [ [ "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T18:02:34.35338" + "timestamp": "2023-12-04T17:53:26.664210196" + }, + "homo_sapiens - paired_end - multiple - log_out": { + "content": [ + "test.Log.out" + ], + "timestamp": "2023-11-23T13:29:01.022176" + }, + "homo_sapiens - paired_end - arriba - fastq": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:25:07.15277" + }, + "homo_sapiens - paired_end - multiple - junction": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:29:01.52923" }, - "homo_sapiens - paired_end": { + "homo_sapiens - paired_end - multiple - spl_junc_tab": { "content": [ - "test.Log.final.out", - "test.Log.out", - "test.Log.progress.out", [ [ { "id": "test", "single_end": false }, - "test.Aligned.sortedByCoord.out.bam:md5,b9ee1c607e07323bc1652ef3babb543f" + "test.SJ.out.tab:md5,069877e053714e23010fe4e1c003b4a2" ] - ], + ] + ], + "timestamp": "2023-12-04T18:01:20.189486201" + }, + "homo_sapiens - paired_end - starfusion - log_final": { + "content": [ + "test.Log.final.out" + ], + "timestamp": "2023-11-23T13:27:55.905883" + }, + "homo_sapiens - paired_end - starfusion - fastq": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:27:56.192302" + }, + "homo_sapiens - paired_end - multiple - sam": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:29:01.661837" + }, + "homo_sapiens - paired_end - multiple - log_final": { + "content": [ + "test.Log.final.out" + ], + "timestamp": "2023-11-23T13:29:00.966417" + }, + "homo_sapiens - paired_end - starfusion - bam": { + "content": [ [ [ { "id": "test", "single_end": false }, - "test.Aligned.sortedByCoord.out.bam:md5,b9ee1c607e07323bc1652ef3babb543f" + "test.Aligned.out.bam:md5,bcad07b838f6762fc01eea52b5cd3f84" ] - ], - [ - - ], + ] + ], + "timestamp": "2023-12-04T17:59:58.53235164" + }, + "homo_sapiens - paired_end - arriba - junction": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:25:07.202776" + }, + "homo_sapiens - single_end - bedgraph": { + "content": [ [ [ { "id": "test", - "single_end": false + "single_end": true }, [ - "test.Signal.Unique.str1.out.bg:md5,d7bf8b70b436ca048a62513e1d0ece3a", - "test.Signal.UniqueMultiple.str1.out.bg:md5,686d58493b9eb445b56ace4d67f76ef6" + "test.Signal.Unique.str1.out.bg:md5,c56fc1472776fb927eaf62d973da5f9a", + "test.Signal.UniqueMultiple.str1.out.bg:md5,e93373cf6f2a2a9506e2efdb260cdd4f" ] ] - ], - [ - - ], + ] + ], + "timestamp": "2023-12-04T17:53:26.394863748" + }, + "homo_sapiens - paired_end - arriba - read_per_gene_tab": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:25:07.251962" + }, + "homo_sapiens - paired_end - starfusion - bam_sorted": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:27:56.040843" + }, + "homo_sapiens - single_end - bam_unsorted": { + "content": [ [ - ], - [ - [ - { - "id": "test", - "single_end": false - }, - "test.SJ.out.tab:md5,844af19ab0fc8cd9a3f75228445aca0d" - ] - ], + ] + ], + "timestamp": "2023-11-23T13:22:55.154172" + }, + "homo_sapiens - paired_end - bam": { + "content": [ [ [ { "id": "test", "single_end": false }, - "test.SJ.out.tab:md5,844af19ab0fc8cd9a3f75228445aca0d" + "test.Aligned.sortedByCoord.out.bam:md5,b9ee1c607e07323bc1652ef3babb543f" ] - ], + ] + ], + "timestamp": "2023-12-04T17:54:11.934832258" + }, + "homo_sapiens - paired_end - arriba - bam_transcript": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:25:06.998817" + }, + "homo_sapiens - paired_end - log_out": { + "content": [ + "test.Log.out" + ], + "timestamp": "2023-11-23T13:23:33.259699" + }, + "homo_sapiens - paired_end - arriba - log_out": { + "content": [ + "test.Log.out" + ], + "timestamp": "2023-11-23T13:25:06.849451" + }, + "homo_sapiens - paired_end - multiple - versions": { + "content": [ [ "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T18:03:16.701923" + "timestamp": "2023-12-04T18:01:20.393705142" }, - "homo_sapiens - paired_end - multiple - stub": { + "homo_sapiens - paired_end - starfusion - bam_transcript": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "10": [ - [ - { - "id": "test", - "single_end": false - }, - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "11": [ - [ - { - "id": "test", - "single_end": false - }, - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "12": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "13": [ - [ - { - "id": "test", - "single_end": false - }, - "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "14": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "15": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" - ], - "4": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "5": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "6": [ - [ - { - "id": "test", - "single_end": false - }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "7": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "8": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "9": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam_sorted": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam_transcript": [ - [ - { - "id": "test", - "single_end": false - }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "bam_unsorted": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "bedgraph": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "fastq": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "junction": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_final": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_out": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_progress": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "read_per_gene_tab": [ - [ - { - "id": "test", - "single_end": false - }, - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "sam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "spl_junc_tab": [ - [ - { - "id": "test", - "single_end": false - }, - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "tab": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "versions": [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" - ], - "wig": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } + [ + + ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T15:16:51.360287" + "timestamp": "2023-11-23T13:27:56.082408" }, - "homo_sapiens - paired_end - multiple": { + "homo_sapiens - paired_end - starfusion - tab": { "content": [ - "test.Log.final.out", - "test.Log.out", - "test.Log.progress.out", [ [ { "id": "test", "single_end": false }, - "test.Aligned.sortedByCoord.out.bam:md5,ab07c21d63ab0a6c07d171d213c81d5a" - ] - ], - [ - [ - { - "id": "test", - "single_end": false - }, - "test.Aligned.sortedByCoord.out.bam:md5,ab07c21d63ab0a6c07d171d213c81d5a" + "test.SJ.out.tab:md5,19c3faa1bfa9a0cc5e4c45f17065b53a" ] - ], - [ - - ], + ] + ], + "timestamp": "2023-12-04T17:59:58.818041322" + }, + "homo_sapiens - single_end - fastq": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:22:55.175307" + }, + "homo_sapiens - paired_end - tab": { + "content": [ [ [ { "id": "test", "single_end": false }, - [ - "test.Signal.Unique.str1.out.bg:md5,d7bf8b70b436ca048a62513e1d0ece3a", - "test.Signal.UniqueMultiple.str1.out.bg:md5,686d58493b9eb445b56ace4d67f76ef6" - ] + "test.SJ.out.tab:md5,844af19ab0fc8cd9a3f75228445aca0d" ] - ], - [ - - ], + ] + ], + "timestamp": "2023-12-04T17:54:12.255481058" + }, + "homo_sapiens - paired_end - starfusion - bedgraph": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:27:56.155413" + }, + "homo_sapiens - single_end - bam_transcript": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:22:55.144852" + }, + "homo_sapiens - paired_end - versions": { + "content": [ [ - - ], + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ] + ], + "timestamp": "2023-12-04T17:54:12.343840482" + }, + "homo_sapiens - paired_end - multiple - tab": { + "content": [ [ [ { @@ -1173,801 +385,385 @@ }, "test.SJ.out.tab:md5,069877e053714e23010fe4e1c003b4a2" ] - ], + ] + ], + "timestamp": "2023-12-04T18:01:20.291692062" + }, + "homo_sapiens - single_end - bam": { + "content": [ [ [ { "id": "test", - "single_end": false + "single_end": true }, - "test.SJ.out.tab:md5,069877e053714e23010fe4e1c003b4a2" + "test.Aligned.sortedByCoord.out.bam:md5,c6cfaccaf91bc7fdabed3cfe236d4535" ] - ], + ] + ], + "timestamp": "2023-12-04T17:53:26.265642675" + }, + "homo_sapiens - paired_end - arriba - wig": { + "content": [ [ - ], - [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T13:13:28.987438" + "timestamp": "2023-11-23T13:25:07.444214" }, - "homo_sapiens - paired_end - stub": { + "homo_sapiens - paired_end - log_progress": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "10": [ - [ - { - "id": "test", - "single_end": false - }, - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "11": [ - [ - { - "id": "test", - "single_end": false - }, - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "12": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "13": [ - [ - { - "id": "test", - "single_end": false - }, - "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "14": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "15": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" - ], - "4": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "5": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "6": [ - [ - { - "id": "test", - "single_end": false - }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "7": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "8": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "9": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam_sorted": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam_transcript": [ - [ - { - "id": "test", - "single_end": false - }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "bam_unsorted": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "bedgraph": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "fastq": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "junction": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_final": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_out": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_progress": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "read_per_gene_tab": [ - [ - { - "id": "test", - "single_end": false - }, - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "sam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "spl_junc_tab": [ - [ - { - "id": "test", - "single_end": false - }, - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "tab": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "versions": [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" - ], - "wig": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" - ] + [ + [ + { + "id": "test", + "single_end": false + }, + "test.Log.progress.out:md5,b2bd061d6cbaaf3d6d3b1fed547f69b8" ] - } + ] + ], + "timestamp": "2023-12-04T17:54:12.126063825" + }, + "homo_sapiens - paired_end - arriba - log_final": { + "content": [ + "test.Log.final.out" + ], + "timestamp": "2023-11-23T13:25:06.829799" + }, + "homo_sapiens - paired_end - bam_unsorted": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:23:33.300509" + }, + "homo_sapiens - paired_end - arriba - sam": { + "content": [ + [ + + ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T15:16:16.798018" + "timestamp": "2023-11-23T13:25:07.300383" }, - "homo_sapiens - paired_end - starfusion": { + "homo_sapiens - paired_end - multiple - bam": { "content": [ - "test.Log.final.out", - "test.Log.out", - "test.Log.progress.out", [ [ { "id": "test", "single_end": false }, - "test.Aligned.out.bam:md5,bcad07b838f6762fc01eea52b5cd3f84" + "test.Aligned.sortedByCoord.out.bam:md5,ab07c21d63ab0a6c07d171d213c81d5a" ] - ], + ] + ], + "timestamp": "2023-12-04T18:01:19.851247126" + }, + "homo_sapiens - paired_end - multiple - fastq": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:29:01.462257" + }, + "homo_sapiens - single_end - bam_sorted": { + "content": [ [ - - ], + [ + { + "id": "test", + "single_end": true + }, + "test.Aligned.sortedByCoord.out.bam:md5,c6cfaccaf91bc7fdabed3cfe236d4535" + ] + ] + ], + "timestamp": "2023-12-04T17:53:26.335457371" + }, + "homo_sapiens - paired_end - arriba - bam_sorted": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:25:06.94699" + }, + "homo_sapiens - paired_end - starfusion - junction": { + "content": [ [ - - ], + [ + { + "id": "test", + "single_end": false + }, + "test.Chimeric.out.junction:md5,c10ef219f4a30e83711b995bc5e40dba" + ] + ] + ], + "timestamp": "2023-12-04T17:59:58.641115828" + }, + "homo_sapiens - single_end - tab": { + "content": [ + [ + [ + { + "id": "test", + "single_end": true + }, + "test.SJ.out.tab:md5,75a516ab950fb958f40b29996474949c" + ] + ] + ], + "timestamp": "2023-12-04T17:53:26.580593434" + }, + "homo_sapiens - paired_end - starfusion - versions": { + "content": [ + [ + "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ] + ], + "timestamp": "2023-12-04T17:59:58.907317103" + }, + "homo_sapiens - paired_end - multiple - bam_unsorted": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:29:01.330463" + }, + "homo_sapiens - paired_end - arriba - log_progress": { + "content": [ + "test.Log.progress.out" + ], + "timestamp": "2023-11-23T13:25:06.86866" + }, + "homo_sapiens - paired_end - bedgraph": { + "content": [ [ [ { "id": "test", "single_end": false }, - "test.Chimeric.out.junction:md5,c10ef219f4a30e83711b995bc5e40dba" + [ + "test.Signal.Unique.str1.out.bg:md5,d7bf8b70b436ca048a62513e1d0ece3a", + "test.Signal.UniqueMultiple.str1.out.bg:md5,686d58493b9eb445b56ace4d67f76ef6" + ] ] - ], + ] + ], + "timestamp": "2023-12-04T17:54:12.064121304" + }, + "homo_sapiens - paired_end - starfusion - bam_unsorted": { + "content": [ + [ + + ] + ], + "timestamp": "2023-11-23T13:27:56.118974" + }, + "homo_sapiens - paired_end - starfusion - read_per_gene_tab": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:27:56.264699" + }, + "homo_sapiens - paired_end - multiple - log_progress": { + "content": [ + "test.Log.progress.out" + ], + "timestamp": "2023-11-23T13:29:01.076947" + }, + "homo_sapiens - paired_end - arriba - bam_unsorted": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:25:07.050409" + }, + "homo_sapiens - paired_end - bam_sorted": { + "content": [ [ [ { "id": "test", "single_end": false }, - "test.SJ.out.tab:md5,19c3faa1bfa9a0cc5e4c45f17065b53a" + "test.Aligned.sortedByCoord.out.bam:md5,b9ee1c607e07323bc1652ef3babb543f" ] - ], + ] + ], + "timestamp": "2023-12-04T17:54:12.002180537" + }, + "homo_sapiens - single_end - spl_junc_tab": { + "content": [ [ [ { "id": "test", - "single_end": false + "single_end": true }, - "test.SJ.out.tab:md5,19c3faa1bfa9a0cc5e4c45f17065b53a" + "test.SJ.out.tab:md5,75a516ab950fb958f40b29996474949c" ] - ], - [ - - ], - [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T13:10:55.371956" + "timestamp": "2023-12-04T17:53:26.50932751" }, - "homo_sapiens - paired_end - arriba": { + "homo_sapiens - paired_end - starfusion - spl_junc_tab": { "content": [ - "test.Log.final.out", - "test.Log.out", - "test.Log.progress.out", [ [ { "id": "test", "single_end": false }, - "test.Aligned.out.bam:md5,c1b1747f5873f2d17762725636e891d5" + "test.SJ.out.tab:md5,19c3faa1bfa9a0cc5e4c45f17065b53a" ] - ], - [ - - ], + ] + ], + "timestamp": "2023-12-04T17:59:58.731699486" + }, + "homo_sapiens - single_end - log_out": { + "content": [ + "test.Log.out" + ], + "timestamp": "2023-11-23T13:22:55.126286" + }, + "homo_sapiens - paired_end - log_final": { + "content": [ + "test.Log.final.out" + ], + "timestamp": "2023-11-23T13:23:33.253884" + }, + "homo_sapiens - single_end - log_final": { + "content": [ + "test.Log.final.out" + ], + "timestamp": "2023-11-23T13:22:55.11799" + }, + "homo_sapiens - paired_end - bam_transcript": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:23:33.287684" + }, + "homo_sapiens - paired_end - starfusion - log_progress": { + "content": [ + "test.Log.progress.out" + ], + "timestamp": "2023-11-23T13:27:55.971484" + }, + "homo_sapiens - paired_end - multiple - bam_transcript": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:29:01.264176" + }, + "homo_sapiens - paired_end - multiple - read_per_gene_tab": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:29:01.596406" + }, + "homo_sapiens - single_end - read_per_gene_tab": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:22:55.205936" + }, + "homo_sapiens - paired_end - junction": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:23:33.340653" + }, + "homo_sapiens - paired_end - spl_junc_tab": { + "content": [ [ - - ], + [ + { + "id": "test", + "single_end": false + }, + "test.SJ.out.tab:md5,844af19ab0fc8cd9a3f75228445aca0d" + ] + ] + ], + "timestamp": "2023-12-04T17:54:12.185730856" + }, + "homo_sapiens - paired_end - starfusion - sam": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:27:56.300637" + }, + "homo_sapiens - paired_end - arriba - bam": { + "content": [ [ [ { "id": "test", "single_end": false }, - "test.SJ.out.tab:md5,5155c9fd1f787ad6d7d80987fb06219c" + "test.Aligned.out.bam:md5,c1b1747f5873f2d17762725636e891d5" ] - ], + ] + ], + "timestamp": "2023-12-04T17:56:12.190560178" + }, + "homo_sapiens - single_end - log_progress": { + "content": [ [ [ { "id": "test", - "single_end": false + "single_end": true }, - "test.SJ.out.tab:md5,5155c9fd1f787ad6d7d80987fb06219c" + "test.Log.progress.out:md5,b2bd061d6cbaaf3d6d3b1fed547f69b8" ] - ], + ] + ], + "timestamp": "2023-12-04T17:53:26.450352138" + }, + "homo_sapiens - paired_end - starfusion - wig": { + "content": [ [ - ], + ] + ], + "timestamp": "2023-11-23T13:27:56.422018" + }, + "homo_sapiens - paired_end - wig": { + "content": [ [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" + ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T13:05:10.7534" + "timestamp": "2023-11-23T13:23:33.429457" }, - "homo_sapiens - paired_end - starfusion - stub": { + "homo_sapiens - paired_end - starfusion - log_out": { "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "10": [ - [ - { - "id": "test", - "single_end": false - }, - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "11": [ - [ - { - "id": "test", - "single_end": false - }, - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "12": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "13": [ - [ - { - "id": "test", - "single_end": false - }, - "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "14": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "15": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" - ], - "4": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "5": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "6": [ - [ - { - "id": "test", - "single_end": false - }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "7": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "8": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "9": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam_sorted": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "bam_transcript": [ - [ - { - "id": "test", - "single_end": false - }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "bam_unsorted": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "bedgraph": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.bg:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "fastq": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "junction": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_final": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.final.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_out": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "log_progress": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Log.progress.out:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "read_per_gene_tab": [ - [ - { - "id": "test", - "single_end": false - }, - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "sam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "spl_junc_tab": [ - [ - { - "id": "test", - "single_end": false - }, - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "tab": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "versions": [ - "versions.yml:md5,2e6b6d8809f5a17f38f4d27c45dcb22f" - ], - "wig": [ - [ - { - "id": "test", - "single_end": false - }, - "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } + "test.Log.out" ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T15:16:40.64399" + "timestamp": "2023-11-23T13:27:55.93945" } } \ No newline at end of file diff --git a/modules/nf-core/star/genomegenerate/tests/main.nf.test b/modules/nf-core/star/genomegenerate/tests/main.nf.test index 4d619c47..c17c8ba4 100644 --- a/modules/nf-core/star/genomegenerate/tests/main.nf.test +++ b/modules/nf-core/star/genomegenerate/tests/main.nf.test @@ -28,15 +28,15 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString(), - process.out.versions) - .match() } + { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("fasta_gtf_index") }, + { assert snapshot(process.out.versions).match("fasta_gtf_versions") } ) } } - test("fasta") { + test("fasta_gtf_stub") { + + options '-stub' when { process { @@ -45,7 +45,10 @@ nextflow_process { [ id:'test_fasta' ], [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] ]) - input[1] = Channel.of([ [], [] ]) + input[1] = Channel.of([ + [ id:'test_gtf' ], + [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] + ]) """ } } @@ -53,17 +56,13 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString(), - process.out.versions - ).match() } + { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("fasta_gtf_stub_index") }, + { assert snapshot(process.out.versions).match("fasta_gtf_stub_versions") } ) } } - test("fasta_gtf_stub") { - - options '-stub' + test("fasta") { when { process { @@ -72,10 +71,7 @@ nextflow_process { [ id:'test_fasta' ], [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ] ]) - input[1] = Channel.of([ - [ id:'test_gtf' ], - [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] - ]) + input[1] = Channel.of([ [], [] ]) """ } } @@ -83,9 +79,11 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("fasta_index") }, + { assert snapshot(process.out.versions).match("fasta_versions") } ) } + } test("fasta_stub") { @@ -107,8 +105,11 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(file(process.out.index[0][1]).listFiles().collect { it.getName() }.sort().toString()).match("fasta_stub_index") }, + { assert snapshot(process.out.versions).match("fasta_stub_versions") } ) } + } + } diff --git a/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap b/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap index 207f4b4f..5653d6e6 100644 --- a/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap +++ b/modules/nf-core/star/genomegenerate/tests/main.nf.test.snap @@ -1,148 +1,90 @@ { - "fasta_gtf": { + "fasta_gtf_versions": { "content": [ - "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, exonGeTrInfo.tab, exonInfo.tab, geneInfo.tab, genomeParameters.txt, sjdbInfo.txt, sjdbList.fromGTF.out.tab, sjdbList.out.tab, transcriptInfo.tab]", [ "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.04.3" }, - "timestamp": "2024-07-22T14:55:35.478401" + "timestamp": "2024-02-01T15:54:31.798555" }, - "fasta_gtf_stub": { + "fasta_stub_versions": { "content": [ - { - "0": [ - [ - { - "id": "test_fasta" - }, - [ - "Genome:md5,d41d8cd98f00b204e9800998ecf8427e", - "Log.out:md5,d41d8cd98f00b204e9800998ecf8427e", - "SA:md5,d41d8cd98f00b204e9800998ecf8427e", - "SAindex:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrName.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrNameLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrStart.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "exonGeTrInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "exonInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "geneInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "genomeParameters.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "sjdbInfo.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "sjdbList.fromGTF.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "sjdbList.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "transcriptInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "1": [ - "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" - ], - "index": [ - [ - { - "id": "test_fasta" - }, - [ - "Genome:md5,d41d8cd98f00b204e9800998ecf8427e", - "Log.out:md5,d41d8cd98f00b204e9800998ecf8427e", - "SA:md5,d41d8cd98f00b204e9800998ecf8427e", - "SAindex:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrName.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrNameLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrStart.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "exonGeTrInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "exonInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "geneInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "genomeParameters.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "sjdbInfo.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "sjdbList.fromGTF.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "sjdbList.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e", - "transcriptInfo.tab:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "versions": [ - "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" - ] - } + [ + "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-01T15:55:07.521209" + }, + "fasta_gtf_stub_index": { + "content": [ + "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, exonGeTrInfo.tab, exonInfo.tab, geneInfo.tab, genomeParameters.txt, sjdbInfo.txt, sjdbList.fromGTF.out.tab, sjdbList.out.tab, transcriptInfo.tab]" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-01T15:54:46.478098" + }, + "fasta_gtf_stub_versions": { + "content": [ + [ + "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" + ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.04.3" }, - "timestamp": "2024-07-22T14:55:57.247585" + "timestamp": "2024-02-01T15:54:46.491657" }, - "fasta_stub": { + "fasta_index": { "content": [ - { - "0": [ - [ - { - "id": "test_fasta" - }, - [ - "Genome:md5,d41d8cd98f00b204e9800998ecf8427e", - "Log.out:md5,d41d8cd98f00b204e9800998ecf8427e", - "SA:md5,d41d8cd98f00b204e9800998ecf8427e", - "SAindex:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrName.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrNameLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrStart.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "genomeParameters.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "1": [ - "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" - ], - "index": [ - [ - { - "id": "test_fasta" - }, - [ - "Genome:md5,d41d8cd98f00b204e9800998ecf8427e", - "Log.out:md5,d41d8cd98f00b204e9800998ecf8427e", - "SA:md5,d41d8cd98f00b204e9800998ecf8427e", - "SAindex:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrName.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrNameLength.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "chrStart.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "genomeParameters.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "versions": [ - "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" - ] - } + "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, genomeParameters.txt]" ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.04.3" }, - "timestamp": "2024-07-22T14:56:07.01742" + "timestamp": "2024-02-01T15:54:57.552329" }, - "fasta": { + "fasta_versions": { "content": [ - "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, genomeParameters.txt]", [ "versions.yml:md5,46b8f1f34bb7f23892cd1eb249ed4d7f" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-01T15:54:57.560541" + }, + "fasta_gtf_index": { + "content": [ + "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, exonGeTrInfo.tab, exonInfo.tab, geneInfo.tab, genomeParameters.txt, sjdbInfo.txt, sjdbList.fromGTF.out.tab, sjdbList.out.tab, transcriptInfo.tab]" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-01T15:54:31.786814" + }, + "fasta_stub_index": { + "content": [ + "[Genome, Log.out, SA, SAindex, chrLength.txt, chrName.txt, chrNameLength.txt, chrStart.txt, genomeParameters.txt]" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" }, - "timestamp": "2024-07-22T14:55:45.48784" + "timestamp": "2024-02-01T15:55:07.517472" } } \ No newline at end of file diff --git a/modules/nf-core/stringtie/stringtie/tests/main.nf.test b/modules/nf-core/stringtie/stringtie/tests/main.nf.test index 2204e849..00efe8f1 100644 --- a/modules/nf-core/stringtie/stringtie/tests/main.nf.test +++ b/modules/nf-core/stringtie/stringtie/tests/main.nf.test @@ -3,7 +3,6 @@ nextflow_process { name "Test Process STRINGTIE_STRINGTIE" script "../main.nf" process "STRINGTIE_STRINGTIE" - config "./nextflow.config" tag "modules" tag "modules_nfcore" tag "stringtie" @@ -11,6 +10,8 @@ nextflow_process { test("sarscov2 [bam] - forward strandedness") { + config "./nextflow.config" + when { process { """ @@ -26,17 +27,17 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - process.out.abundance, - process.out.transcript_gtf, - process.out.versions - ).match() } + { assert snapshot(process.out.transcript_gtf).match("fs_transcript_gtf") }, + { assert snapshot(process.out.abundance).match("fs_abundance") }, + { assert snapshot(process.out.versions).match("fs_versions") } ) } } test("sarscov2 [bam] - forward strandedness + reference annotation") { + config "./nextflow.config" + when { process { """ @@ -52,120 +53,17 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - process.out.abundance, - process.out.ballgown, - process.out.transcript_gtf, - process.out.versions - ).match() } + { assert snapshot(process.out.transcript_gtf).match("fs_gtf_transcript_gtf") }, + { assert snapshot(process.out.abundance).match("fs_gtf_abundance") }, + { assert snapshot(process.out.ballgown).match("fs_gtf_ballgown") }, + { assert snapshot(process.out.versions).match("fs_gtf_versions") } ) } } test("sarscov2 [bam] - reverse strandedness") { - when { - process { - """ - input[0] = [ - [ id:'test', strandedness:'reverse' ], // meta map - [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam", checkIfExists: true) ] - ] - input[1] = [] - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot( - process.out.abundance, - process.out.transcript_gtf, - process.out.versions - ).match() } - ) - } - } - - test("sarscov2 [bam] - reverse strandedness + reference annotation") { - - when { - process { - """ - input[0] = [ - [ id:'test', strandedness:'reverse' ], // meta map - [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam", checkIfExists: true) ] - ] - input[1] = file(params.modules_testdata_base_path + "genomics/sarscov2/genome/genome.gtf", checkIfExists: true) - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot( - process.out.abundance, - process.out.ballgown, - process.out.transcript_gtf, - process.out.versions - ).match() } - ) - } - } - - test("sarscov2 [bam] - forward strandedness - stub") { - - options "-stub" - - when { - process { - """ - input[0] = [ - [ id:'test', strandedness:'forward' ], // meta map - [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam", checkIfExists: true) ] - ] - input[1] = [] - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 [bam] - forward strandedness + reference annotation - stub") { - - options "-stub" - - when { - process { - """ - input[0] = [ - [ id:'test', strandedness:'forward' ], // meta map - [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam", checkIfExists: true) ] - ] - input[1] = file(params.modules_testdata_base_path + "genomics/sarscov2/genome/genome.gtf", checkIfExists: true) - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 [bam] - reverse strandedness - stub") { - - options "-stub" + config "./nextflow.config" when { process { @@ -182,14 +80,16 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out.transcript_gtf).match("rs_transcript_gtf") }, + { assert snapshot(process.out.abundance).match("rs_abundance") }, + { assert snapshot(process.out.versions).match("rs_versions") } ) } } - test("sarscov2 [bam] - reverse strandedness + reference annotation - stub") { + test("sarscov2 [bam] - reverse strandedness + reference annotation") { - options "-stub" + config "./nextflow.config" when { process { @@ -206,7 +106,10 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out.transcript_gtf).match("rs_gtf_transcript_gtf") }, + { assert snapshot(process.out.abundance).match("rs_gtf_abundance") }, + { assert snapshot(process.out.ballgown).match("rs_gtf_ballgown") }, + { assert snapshot(process.out.versions).match("rs_gtf_versions") } ) } } diff --git a/modules/nf-core/stringtie/stringtie/tests/main.nf.test.snap b/modules/nf-core/stringtie/stringtie/tests/main.nf.test.snap index 124dd4cb..bf751636 100644 --- a/modules/nf-core/stringtie/stringtie/tests/main.nf.test.snap +++ b/modules/nf-core/stringtie/stringtie/tests/main.nf.test.snap @@ -1,5 +1,5 @@ { - "sarscov2 [bam] - forward strandedness + reference annotation": { + "fs_abundance": { "content": [ [ [ @@ -7,44 +7,49 @@ "id": "test", "strandedness": "forward" }, - "test.gene.abundance.txt:md5,7d8bce7f2a922e367cedccae7267c22e" + "test.gene.abundance.txt:md5,d6f5c8cadb8458f1df0427cf790246e3" ] - ], + ] + ], + "timestamp": "2023-11-23T13:55:41.032044613" + }, + "fs_transcript_gtf": { + "content": [ [ [ { "id": "test", "strandedness": "forward" }, - [ - "e2t.ctab:md5,e981c0038295ae54b63cedb1083f1540", - "e_data.ctab:md5,6b4cf69bc03f3f69890f972a0e8b7471", - "i2t.ctab:md5,8a117c8aa4334b4c2d4711932b006fb4", - "i_data.ctab:md5,be3abe09740603213f83d50dcf81427f", - "t_data.ctab:md5,3b66c065da73ae0dd41cc332eff6a818" - ] + "test.transcripts.gtf:md5,569137af5be452413086b50653a97203" ] - ], + ] + ], + "timestamp": "2023-11-23T13:55:41.017978904" + }, + "rs_abundance": { + "content": [ [ [ { "id": "test", - "strandedness": "forward" + "strandedness": "reverse" }, - "test.transcripts.gtf:md5,f56cf8aba2c4a5673bc7963ba5f12d04" + "test.gene.abundance.txt:md5,d6f5c8cadb8458f1df0427cf790246e3" ] - ], + ] + ], + "timestamp": "2023-11-23T13:56:13.601112933" + }, + "fs_gtf_versions": { + "content": [ [ "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T12:33:44.299962" + "timestamp": "2023-11-23T13:56:00.523797974" }, - "sarscov2 [bam] - forward strandedness": { + "fs_gtf_transcript_gtf": { "content": [ [ [ @@ -52,395 +57,50 @@ "id": "test", "strandedness": "forward" }, - "test.gene.abundance.txt:md5,d6f5c8cadb8458f1df0427cf790246e3" - ] - ], - [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.transcripts.gtf:md5,569137af5be452413086b50653a97203" + "test.transcripts.gtf:md5,f56cf8aba2c4a5673bc7963ba5f12d04" ] - ], - [ - "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T12:33:35.177738" - }, - "sarscov2 [bam] - forward strandedness - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "4": [ - "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" - ], - "abundance": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "ballgown": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "coverage_gtf": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "transcript_gtf": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T12:36:32.885078" + "timestamp": "2023-11-23T13:56:00.475164879" }, - "sarscov2 [bam] - forward strandedness + reference annotation - stub": { + "rs_versions": { "content": [ - { - "0": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "4": [ - "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" - ], - "abundance": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "ballgown": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "coverage_gtf": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "transcript_gtf": [ - [ - { - "id": "test", - "strandedness": "forward" - }, - "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T12:36:43.325777" - }, - "sarscov2 [bam] - reverse strandedness + reference annotation - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "4": [ - "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" - ], - "abundance": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "ballgown": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "coverage_gtf": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "transcript_gtf": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" - ] - } + [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" + ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T12:37:06.085936" + "timestamp": "2023-11-23T13:56:13.623892691" }, - "sarscov2 [bam] - reverse strandedness - stub": { + "rs_gtf_transcript_gtf": { "content": [ - { - "0": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "4": [ - "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" - ], - "abundance": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.gene.abundance.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "ballgown": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.ballgown:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "coverage_gtf": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.coverage.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "transcript_gtf": [ - [ - { - "id": "test", - "strandedness": "reverse" - }, - "test.transcripts.gtf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" + [ + [ + { + "id": "test", + "strandedness": "reverse" + }, + "test.transcripts.gtf:md5,bb346053a8c156b803b055133376c7fa" ] - } + ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T12:36:53.837578" + "timestamp": "2023-11-23T13:56:22.693599559" }, - "sarscov2 [bam] - reverse strandedness + reference annotation": { + "fs_gtf_abundance": { "content": [ [ [ { "id": "test", - "strandedness": "reverse" + "strandedness": "forward" }, - "test.gene.abundance.txt:md5,7385b870b955dae2c2ab78a70cf05cce" + "test.gene.abundance.txt:md5,7d8bce7f2a922e367cedccae7267c22e" ] - ], + ] + ], + "timestamp": "2023-11-23T13:56:00.482135418" + }, + "rs_gtf_ballgown": { + "content": [ [ [ { @@ -455,54 +115,72 @@ "t_data.ctab:md5,3b66c065da73ae0dd41cc332eff6a818" ] ] - ], + ] + ], + "timestamp": "2023-11-23T13:56:22.715698347" + }, + "rs_transcript_gtf": { + "content": [ [ [ { "id": "test", "strandedness": "reverse" }, - "test.transcripts.gtf:md5,bb346053a8c156b803b055133376c7fa" + "test.transcripts.gtf:md5,31c34aec2bf36bb0ea3c16c2afeeeb1f" ] - ], + ] + ], + "timestamp": "2023-11-23T13:56:13.590054035" + }, + "rs_gtf_versions": { + "content": [ [ "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T12:34:03.114695" + "timestamp": "2023-11-23T13:56:22.725513476" }, - "sarscov2 [bam] - reverse strandedness": { + "fs_gtf_ballgown": { "content": [ [ [ { "id": "test", - "strandedness": "reverse" + "strandedness": "forward" }, - "test.gene.abundance.txt:md5,d6f5c8cadb8458f1df0427cf790246e3" + [ + "e2t.ctab:md5,e981c0038295ae54b63cedb1083f1540", + "e_data.ctab:md5,6b4cf69bc03f3f69890f972a0e8b7471", + "i2t.ctab:md5,8a117c8aa4334b4c2d4711932b006fb4", + "i_data.ctab:md5,be3abe09740603213f83d50dcf81427f", + "t_data.ctab:md5,3b66c065da73ae0dd41cc332eff6a818" + ] ] - ], + ] + ], + "timestamp": "2023-11-23T13:56:00.494299817" + }, + "fs_versions": { + "content": [ + [ + "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" + ] + ], + "timestamp": "2023-11-23T13:55:41.049417582" + }, + "rs_gtf_abundance": { + "content": [ [ [ { "id": "test", "strandedness": "reverse" }, - "test.transcripts.gtf:md5,31c34aec2bf36bb0ea3c16c2afeeeb1f" + "test.gene.abundance.txt:md5,7385b870b955dae2c2ab78a70cf05cce" ] - ], - [ - "versions.yml:md5,3410e8ac349d18c85ddee89337851d38" ] ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T12:33:52.874479" + "timestamp": "2023-11-23T13:56:22.701059059" } -} \ No newline at end of file +} diff --git a/modules/nf-core/trimgalore/main.nf b/modules/nf-core/trimgalore/main.nf index 0e2f3290..24ead871 100644 --- a/modules/nf-core/trimgalore/main.nf +++ b/modules/nf-core/trimgalore/main.nf @@ -72,25 +72,4 @@ process TRIMGALORE { END_VERSIONS """ } - - stub: - def prefix = task.ext.prefix ?: "${meta.id}" - if (meta.single_end) { - output_command = "echo '' | gzip > ${prefix}_trimmed.fq.gz ;" - output_command += "touch ${prefix}.fastq.gz_trimming_report.txt" - } else { - output_command = "echo '' | gzip > ${prefix}_1_trimmed.fq.gz ;" - output_command += "touch ${prefix}_1.fastq.gz_trimming_report.txt ;" - output_command += "echo '' | gzip > ${prefix}_2_trimmed.fq.gz ;" - output_command += "touch ${prefix}_2.fastq.gz_trimming_report.txt" - } - """ - ${output_command} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - trimgalore: \$(echo \$(trim_galore --version 2>&1) | sed 's/^.*version //; s/Last.*\$//') - cutadapt: \$(cutadapt --version) - END_VERSIONS - """ } diff --git a/modules/nf-core/trimgalore/tests/main.nf.test b/modules/nf-core/trimgalore/tests/main.nf.test index 2a3dbbb0..43904ac3 100644 --- a/modules/nf-core/trimgalore/tests/main.nf.test +++ b/modules/nf-core/trimgalore/tests/main.nf.test @@ -44,28 +44,6 @@ nextflow_process { } } - test("test_trimgalore_single_end - stub") { - - options "-stub" - - when { - process { - """ - input[0] = [ [ id:'test', single_end:true ], // meta map - [ file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/fastq/test_1.fastq.gz", checkIfExists: true) ] - ] - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - test("test_trimgalore_paired_end") { when { @@ -122,29 +100,4 @@ nextflow_process { ) } } - - test("test_trimgalore_paired_end - stub") { - - options "-stub" - - when { - process { - """ - input[0] = [ [ id:'test', single_end:false ], // meta map - [ - file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/fastq/test_1.fastq.gz", checkIfExists: true), - file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/fastq/test_2.fastq.gz", checkIfExists: true) - ] - ] - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } } diff --git a/modules/nf-core/trimgalore/tests/main.nf.test.snap b/modules/nf-core/trimgalore/tests/main.nf.test.snap index 6cb31c9f..082c5500 100644 --- a/modules/nf-core/trimgalore/tests/main.nf.test.snap +++ b/modules/nf-core/trimgalore/tests/main.nf.test.snap @@ -11,160 +11,6 @@ }, "timestamp": "2024-02-29T16:33:20.401347" }, - "test_trimgalore_single_end - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": true - }, - "test.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - - ], - "3": [ - - ], - "4": [ - - ], - "5": [ - "versions.yml:md5,47d966cbb31c80eb8f7fe860d55659b7" - ], - "html": [ - - ], - "log": [ - [ - { - "id": "test", - "single_end": true - }, - "test.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "reads": [ - [ - { - "id": "test", - "single_end": true - }, - "test_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ], - "unpaired": [ - - ], - "versions": [ - "versions.yml:md5,47d966cbb31c80eb8f7fe860d55659b7" - ], - "zip": [ - - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T10:27:44.964166" - }, - "test_trimgalore_paired_end - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test_1_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test_1.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "test_2.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "2": [ - - ], - "3": [ - - ], - "4": [ - - ], - "5": [ - "versions.yml:md5,47d966cbb31c80eb8f7fe860d55659b7" - ], - "html": [ - - ], - "log": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test_1.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "test_2.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "reads": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test_1_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ] - ], - "unpaired": [ - - ], - "versions": [ - "versions.yml:md5,47d966cbb31c80eb8f7fe860d55659b7" - ], - "zip": [ - - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-06-21T10:28:07.611496" - }, "test_trimgalore_paired_end": { "content": [ [ From b3c1ffd47d87a3d94fcd1bfac2b9d1aba187c7bc Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Tue, 6 Aug 2024 18:01:56 +0200 Subject: [PATCH 457/491] only updating necessary modules --- modules.json | 22 +- .../samtools/flagstat/tests/main.nf.test | 28 +- .../samtools/flagstat/tests/main.nf.test.snap | 78 ++++- .../samtools/idxstats/tests/main.nf.test | 29 +- .../samtools/idxstats/tests/main.nf.test.snap | 78 ++++- modules/nf-core/samtools/index/main.nf | 7 +- .../nf-core/samtools/index/tests/main.nf.test | 87 ++++- .../samtools/index/tests/main.nf.test.snap | 264 +++++++++++--- modules/nf-core/samtools/sort/main.nf | 14 +- .../nf-core/samtools/sort/tests/main.nf.test | 54 ++- .../samtools/sort/tests/main.nf.test.snap | 202 +++++++---- .../samtools/sort/tests/nextflow_cram.config | 8 + .../nf-core/samtools/stats/tests/main.nf.test | 57 ++- .../samtools/stats/tests/main.nf.test.snap | 82 ++++- modules/nf-core/samtools/view/main.nf | 40 ++- modules/nf-core/samtools/view/meta.yml | 9 + .../nf-core/samtools/view/tests/main.nf.test | 2 + .../samtools/view/tests/main.nf.test.snap | 22 +- .../tests/main.nf.test | 76 +++- .../tests/main.nf.test.snap | 326 +++++++++++++++--- 20 files changed, 1187 insertions(+), 298 deletions(-) create mode 100644 modules/nf-core/samtools/sort/tests/nextflow_cram.config diff --git a/modules.json b/modules.json index 35714771..abfb70e0 100644 --- a/modules.json +++ b/modules.json @@ -71,7 +71,7 @@ }, "bwa/index": { "branch": "master", - "git_sha": "086fa66260595e123b0ea47a6512539b72a9afa3", + "git_sha": "e0ff65e1fb313677de09f5f477ae3da30ce19b7b", "installed_by": [ "modules" ] @@ -155,7 +155,7 @@ }, "gnu/sort": { "branch": "master", - "git_sha": "ca199cfe5aa4f1ea3c41302158f0af2cfaa58957", + "git_sha": "a3cc42943548378b726610f45bb5a79ab3f0b633", "installed_by": [ "modules" ] @@ -197,28 +197,28 @@ }, "samtools/faidx": { "branch": "master", - "git_sha": "f153f1f10e1083c49935565844cccb7453021682", + "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", "installed_by": [ "modules" ] }, "samtools/flagstat": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "bam_stats_samtools" ] }, "samtools/idxstats": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "bam_stats_samtools" ] }, "samtools/index": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "bam_sort_stats_samtools", "modules" @@ -226,7 +226,7 @@ }, "samtools/sort": { "branch": "master", - "git_sha": "4352dbdb09ec40db71e9b172b97a01dcf5622c26", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "bam_sort_stats_samtools", "modules" @@ -234,14 +234,14 @@ }, "samtools/stats": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "bam_stats_samtools" ] }, "samtools/view": { "branch": "master", - "git_sha": "0bd7d2333a88483aa0476acea172e9f5f6dd83bb", + "git_sha": "6c2309aaec566c0d44a6cf14d4b2d0c51afe2e91", "installed_by": [ "modules" ] @@ -301,14 +301,14 @@ "nf-core": { "bam_sort_stats_samtools": { "branch": "master", - "git_sha": "4352dbdb09ec40db71e9b172b97a01dcf5622c26", + "git_sha": "46eca555142d6e597729fcb682adcc791796f514", "installed_by": [ "subworkflows" ] }, "bam_stats_samtools": { "branch": "master", - "git_sha": "f4596fe0bdc096cf53ec4497e83defdb3a94ff62", + "git_sha": "0eacd714effe5aac1c1de26593873960b3346cab", "installed_by": [ "bam_sort_stats_samtools", "subworkflows" diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test b/modules/nf-core/samtools/flagstat/tests/main.nf.test index 24c3c04b..3b648a37 100644 --- a/modules/nf-core/samtools/flagstat/tests/main.nf.test +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test @@ -11,9 +11,30 @@ nextflow_process { test("BAM") { when { - params { - outdir = "$outputDir" + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + 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) + ]) + """ } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("BAM - stub") { + + options "-stub" + + when { process { """ input[0] = Channel.of([ @@ -28,8 +49,7 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out.flagstat).match("flagstat") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out).match() } ) } } diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap index e9f85efa..23989c61 100644 --- a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap @@ -1,32 +1,72 @@ { - "flagstat": { + "BAM - stub": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" + ], + "flagstat": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" ] - ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-02-12T18:31:37.783927" + "timestamp": "2024-07-22T14:17:28.002887" }, - "versions": { + "BAM": { "content": [ - [ - "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" - ] + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" + ] + ], + "1": [ + "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" + ], + "flagstat": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" + ] + ], + "versions": [ + "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-28T15:41:52.516253882" + "timestamp": "2024-07-22T14:17:13.330971" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test b/modules/nf-core/samtools/idxstats/tests/main.nf.test index a2dcb27c..5fd1fc78 100644 --- a/modules/nf-core/samtools/idxstats/tests/main.nf.test +++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test @@ -11,9 +11,6 @@ nextflow_process { test("bam") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -28,9 +25,29 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out.idxstats).match("idxstats") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out).match() } ) } } -} + + test("bam - stub") { + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + 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) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + }} diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap index 4eacdb90..a5ac8104 100644 --- a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap @@ -1,32 +1,72 @@ { - "versions": { + "bam - stub": { "content": [ - [ - "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" - ] + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" + ], + "idxstats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-28T15:46:46.617989517" + "timestamp": "2024-07-22T14:17:56.180093" }, - "idxstats": { + "bam": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" + ] + ], + "1": [ + "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" + ], + "idxstats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" + ] + ], + "versions": [ + "versions.yml:md5,7acbcb2a8ec6436ba7b2916d3ff13351" ] - ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-02-12T18:36:41.561026" + "timestamp": "2024-07-22T14:17:41.408704" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/index/main.nf b/modules/nf-core/samtools/index/main.nf index b523c21b..e002585b 100644 --- a/modules/nf-core/samtools/index/main.nf +++ b/modules/nf-core/samtools/index/main.nf @@ -35,10 +35,11 @@ process SAMTOOLS_INDEX { """ stub: + def args = task.ext.args ?: '' + def extension = file(input).getExtension() == 'cram' ? + "crai" : args.contains("-c") ? "csi" : "bai" """ - touch ${input}.bai - touch ${input}.crai - touch ${input}.csi + touch ${input}.${extension} cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/samtools/index/tests/main.nf.test b/modules/nf-core/samtools/index/tests/main.nf.test index bb7756d1..ca34fb5c 100644 --- a/modules/nf-core/samtools/index/tests/main.nf.test +++ b/modules/nf-core/samtools/index/tests/main.nf.test @@ -9,11 +9,7 @@ nextflow_process { tag "samtools/index" test("bai") { - when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -27,18 +23,13 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out.bai).match("bai") }, - { assert snapshot(process.out.versions).match("bai_versions") } + { assert snapshot(process.out).match() } ) } } test("crai") { - when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -52,20 +43,83 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out.crai).match("crai") }, - { assert snapshot(process.out.versions).match("crai_versions") } + { assert snapshot(process.out).match() } ) } } test("csi") { - config "./csi.nextflow.config" when { - params { - outdir = "$outputDir" + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.csi[0][1]).name, + process.out.versions + ).match() } + ) + } + } + + test("bai - stub") { + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("crai - stub") { + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram', checkIfExists: true) + ]) + """ } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("csi - stub") { + options "-stub" + config "./csi.nextflow.config" + + when { process { """ input[0] = Channel.of([ @@ -79,8 +133,7 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert path(process.out.csi.get(0).get(1)).exists() }, - { assert snapshot(process.out.versions).match("csi_versions") } + { assert snapshot(process.out).match() } ) } } diff --git a/modules/nf-core/samtools/index/tests/main.nf.test.snap b/modules/nf-core/samtools/index/tests/main.nf.test.snap index 52756e85..799d199c 100644 --- a/modules/nf-core/samtools/index/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/index/tests/main.nf.test.snap @@ -1,74 +1,250 @@ { - "crai_versions": { + "csi - stub": { "content": [ - [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ] + { + "0": [ + + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ], + "bai": [ + + ], + "crai": [ + + ], + "csi": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-28T15:42:04.203740976" + "timestamp": "2024-07-22T16:51:53.9057" }, - "csi_versions": { + "crai - stub": { "content": [ - [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ] + { + "0": [ + + ], + "1": [ + + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ], + "bai": [ + + ], + "crai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "csi": [ + + ], + "versions": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-28T15:42:09.57475878" + "timestamp": "2024-07-22T16:51:45.931558" }, - "crai": { + "bai - stub": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ], + "bai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "crai": [ + + ], + "csi": [ + + ], + "versions": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" ] - ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-02-12T18:41:38.446424" + "timestamp": "2024-07-22T16:51:34.807525" }, - "bai": { + "csi": { "content": [ + "test.paired_end.sorted.bam.csi", [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" - ] + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-02-12T18:40:46.579747" + "timestamp": "2024-07-22T16:52:55.688799" }, - "bai_versions": { + "crai": { "content": [ - [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ] + { + "0": [ + + ], + "1": [ + + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" + ] + ], + "3": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ], + "bai": [ + + ], + "crai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" + ] + ], + "csi": [ + + ], + "versions": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T16:51:17.609533" + }, + "bai": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ], + "bai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" + ] + ], + "crai": [ + + ], + "csi": [ + + ], + "versions": [ + "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-28T15:41:57.929287369" + "timestamp": "2024-07-22T16:51:04.16585" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/sort/main.nf b/modules/nf-core/samtools/sort/main.nf index 596c6f7e..8e019099 100644 --- a/modules/nf-core/samtools/sort/main.nf +++ b/modules/nf-core/samtools/sort/main.nf @@ -50,10 +50,20 @@ process SAMTOOLS_SORT { """ stub: + def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" + def extension = args.contains("--output-fmt sam") ? "sam" : + args.contains("--output-fmt cram") ? "cram" : + "bam" """ - touch ${prefix}.bam - touch ${prefix}.bam.csi + touch ${prefix}.${extension} + if [ "${extension}" == "bam" ]; + then + touch ${prefix}.${extension}.csi + elif [ "${extension}" == "cram" ]; + then + touch ${prefix}.${extension}.crai + fi cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test b/modules/nf-core/samtools/sort/tests/main.nf.test index fb38ed9b..c2ea9c72 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test +++ b/modules/nf-core/samtools/sort/tests/main.nf.test @@ -32,16 +32,16 @@ nextflow_process { { assert process.success }, { assert snapshot( process.out.bam, - process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } } - ).match("test_bam") - } + process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } }, + process.out.versions + ).match()} ) } } test("cram") { - config "./nextflow.config" + config "./nextflow_cram.config" when { process { @@ -62,23 +62,20 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - process.out.bam, - process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } } - ).match("test_cram") - } + process.out.cram.collect { it.collect { it instanceof Map ? it : file(it).name } }, + process.out.crai.collect { it.collect { it instanceof Map ? it : file(it).name } }, + process.out.versions + ).match()} ) } } - test("bam_stub") { + test("bam - stub") { - config "./nextflow.config" options "-stub" + config "./nextflow.config" when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -96,8 +93,35 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(file(process.out.bam[0][1]).name).match("bam_stub_bam") }, - { assert snapshot(process.out.versions).match("bam_stub_versions") } + { assert snapshot(process.out).match() } + ) + } + } + + test("cram - stub") { + + options "-stub" + config "./nextflow_cram.config" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true) + ]) + input[1] = Channel.of([ + [ id:'fasta' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } ) } } diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test.snap b/modules/nf-core/samtools/sort/tests/main.nf.test.snap index 5a27de1d..da38d5d1 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/sort/tests/main.nf.test.snap @@ -7,54 +7,159 @@ "id": "test", "single_end": false }, - "test.sorted.bam:md5,21c992d59615936b99f2ad008aa54400" + "test.sorted.cram" ] + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.cram.crai" + ] + ], + [ + "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-31T08:13:54.512837189" + "timestamp": "2024-07-22T17:19:37.196205" }, - "bam_stub_bam": { + "bam - stub": { "content": [ - "test.sorted.bam" + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "crai": [ + + ], + "cram": [ + + ], + "csi": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-31T07:29:00.761845507" + "timestamp": "2024-07-22T15:54:46.580756" }, - "test_cram": { + "cram - stub": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,22b2093be34a7637f5fbc84272b89d06" - ] - ], - [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam.csi" + { + "0": [ + + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.cram:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + + ], + "4": [ + "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" + ], + "bam": [ + + ], + "crai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "cram": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.cram:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "csi": [ + + ], + "versions": [ + "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" ] - ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-31T09:16:51.924951855" + "timestamp": "2024-07-22T15:57:30.505698" }, - "test_bam": { + "bam": { "content": [ [ [ @@ -73,42 +178,15 @@ }, "test.sorted.bam.csi" ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-05-31T08:28:12.15952312" - }, - "bam_stub_versions": { - "content": [ + ], [ "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-05-31T07:29:00.765038811" - }, - "bam": { - "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,21c992d59615936b99f2ad008aa54400" - ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-31T08:13:48.538030517" + "timestamp": "2024-07-22T15:54:25.872954" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/sort/tests/nextflow_cram.config b/modules/nf-core/samtools/sort/tests/nextflow_cram.config new file mode 100644 index 00000000..3a8c0188 --- /dev/null +++ b/modules/nf-core/samtools/sort/tests/nextflow_cram.config @@ -0,0 +1,8 @@ +process { + + withName: SAMTOOLS_SORT { + ext.prefix = { "${meta.id}.sorted" } + ext.args = "--write-index --output-fmt cram" + } + +} diff --git a/modules/nf-core/samtools/stats/tests/main.nf.test b/modules/nf-core/samtools/stats/tests/main.nf.test index e3d5cb14..28a77db2 100644 --- a/modules/nf-core/samtools/stats/tests/main.nf.test +++ b/modules/nf-core/samtools/stats/tests/main.nf.test @@ -11,9 +11,6 @@ nextflow_process { test("bam") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -37,9 +34,59 @@ nextflow_process { test("cram") { when { - params { - outdir = "$outputDir" + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram.crai', checkIfExists: true) + ]) + input[1] = Channel.of([ + [ id:'genome' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) + """ } + } + + then { + assertAll( + {assert process.success}, + {assert snapshot(process.out).match()} + ) + } + } + + test("bam - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + 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] = [[],[]] + """ + } + } + + then { + assertAll( + {assert process.success}, + {assert snapshot(process.out).match()} + ) + } + } + + test("cram - stub") { + + options "-stub" + + when { process { """ input[0] = Channel.of([ diff --git a/modules/nf-core/samtools/stats/tests/main.nf.test.snap b/modules/nf-core/samtools/stats/tests/main.nf.test.snap index 2747fd6c..3828f378 100644 --- a/modules/nf-core/samtools/stats/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/stats/tests/main.nf.test.snap @@ -29,10 +29,80 @@ } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-28T15:45:24.403941966" + "timestamp": "2024-07-22T14:20:24.885816" + }, + "bam - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" + ], + "stats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T14:20:39.310713" + }, + "cram - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" + ], + "stats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,b3b70b126f867fdbb7dcea5e36e49d4a" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T14:21:04.771199" }, "bam": { "content": [ @@ -64,9 +134,9 @@ } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-28T15:45:06.711251947" + "timestamp": "2024-07-22T14:19:06.645466" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/view/main.nf b/modules/nf-core/samtools/view/main.nf index 38df8576..dc611448 100644 --- a/modules/nf-core/samtools/view/main.nf +++ b/modules/nf-core/samtools/view/main.nf @@ -13,13 +13,15 @@ process SAMTOOLS_VIEW { path qname output: - tuple val(meta), path("*.bam"), emit: bam, optional: true - tuple val(meta), path("*.cram"), emit: cram, optional: true - tuple val(meta), path("*.sam"), emit: sam, optional: true - tuple val(meta), path("*.bai"), emit: bai, optional: true - tuple val(meta), path("*.csi"), emit: csi, optional: true - tuple val(meta), path("*.crai"), emit: crai, optional: true - path "versions.yml", emit: versions + tuple val(meta), path("${prefix}.bam"), emit: bam, optional: true + tuple val(meta), path("${prefix}.cram"), emit: cram, optional: true + tuple val(meta), path("${prefix}.sam"), emit: sam, optional: true + tuple val(meta), path("${prefix}.${file_type}.bai"), emit: bai, optional: true + tuple val(meta), path("${prefix}.${file_type}.csi"), emit: csi, optional: true + tuple val(meta), path("${prefix}.${file_type}.crai"), emit: crai, optional: true + tuple val(meta), path("${prefix}.unselected.${file_type}"), emit: unselected, optional: true + tuple val(meta), path("${prefix}.unselected.${file_type}.{bai,csi,crsi}"), emit: unselected_index, optional: true + path "versions.yml", emit: versions when: task.ext.when == null || task.ext.when @@ -27,13 +29,13 @@ process SAMTOOLS_VIEW { script: def args = task.ext.args ?: '' def args2 = task.ext.args2 ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" def reference = fasta ? "--reference ${fasta}" : "" - def readnames = qname ? "--qname-file ${qname}": "" - def file_type = args.contains("--output-fmt sam") ? "sam" : - args.contains("--output-fmt bam") ? "bam" : - args.contains("--output-fmt cram") ? "cram" : - input.getExtension() + file_type = args.contains("--output-fmt sam") ? "sam" : + args.contains("--output-fmt bam") ? "bam" : + args.contains("--output-fmt cram") ? "cram" : + input.getExtension() + readnames = qname ? "--qname-file ${qname} --output-unselected ${prefix}.unselected.${file_type}": "" if ("$input" == "${prefix}.${file_type}") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" """ samtools \\ @@ -54,14 +56,14 @@ process SAMTOOLS_VIEW { stub: def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" - def file_type = args.contains("--output-fmt sam") ? "sam" : - args.contains("--output-fmt bam") ? "bam" : - args.contains("--output-fmt cram") ? "cram" : - input.getExtension() + prefix = task.ext.prefix ?: "${meta.id}" + file_type = args.contains("--output-fmt sam") ? "sam" : + args.contains("--output-fmt bam") ? "bam" : + args.contains("--output-fmt cram") ? "cram" : + input.getExtension() if ("$input" == "${prefix}.${file_type}") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" - def index = args.contains("--write-index") ? "touch ${prefix}.csi" : "" + def index = args.contains("--write-index") ? "touch ${prefix}.${file_type}.csi" : "" """ touch ${prefix}.${file_type} diff --git a/modules/nf-core/samtools/view/meta.yml b/modules/nf-core/samtools/view/meta.yml index 3dadafae..27be60d0 100644 --- a/modules/nf-core/samtools/view/meta.yml +++ b/modules/nf-core/samtools/view/meta.yml @@ -73,6 +73,15 @@ output: type: file description: optional CRAM file index pattern: "*.{crai}" + # unselected and unselected_index are created when passing a qname + - unselected: + type: file + description: optional file with unselected alignments + pattern: "*.unselected.{bam,cram,sam}" + - unselected_index: + type: file + description: index for the "unselected" file + pattern: "*.unselected.{bai,csi,crai}" - versions: type: file description: File containing software versions diff --git a/modules/nf-core/samtools/view/tests/main.nf.test b/modules/nf-core/samtools/view/tests/main.nf.test index 45a0defb..37b81a91 100644 --- a/modules/nf-core/samtools/view/tests/main.nf.test +++ b/modules/nf-core/samtools/view/tests/main.nf.test @@ -172,6 +172,8 @@ nextflow_process { { assert snapshot(process.out.crai).match("cram_to_bam_index_qname_crai") }, { assert snapshot(process.out.cram).match("cram_to_bam_index_qname_cram") }, { assert snapshot(process.out.sam).match("cram_to_bam_index_qname_sam") }, + { assert snapshot(file(process.out.unselected[0][1]).name).match("cram_to_bam_index_qname_unselected") }, + { assert snapshot(file(process.out.unselected_index[0][1]).name).match("cram_to_bam_index_qname_unselected_csi") }, { assert snapshot(process.out.versions).match("cram_to_bam_index_qname_versions") } ) } diff --git a/modules/nf-core/samtools/view/tests/main.nf.test.snap b/modules/nf-core/samtools/view/tests/main.nf.test.snap index eb0c577c..6bcce9fe 100644 --- a/modules/nf-core/samtools/view/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/view/tests/main.nf.test.snap @@ -355,6 +355,26 @@ }, "timestamp": "2024-02-12T19:38:23.322874" }, + "cram_to_bam_index_qname_unselected": { + "content": [ + "test.unselected.bam" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:23.322874" + }, + "cram_to_bam_index_qname_unselected_csi": { + "content": [ + "test.unselected.bam.csi" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.04.3" + }, + "timestamp": "2024-02-12T19:38:23.328458" + }, "bam_versions": { "content": [ [ @@ -477,7 +497,7 @@ }, "bam_stub_csi": { "content": [ - "test.csi" + "test.bam.csi" ], "meta": { "nf-test": "0.8.4", diff --git a/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test b/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test index 75b5b934..821a3cf5 100644 --- a/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test +++ b/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test @@ -19,9 +19,6 @@ nextflow_workflow { test("test_bam_sort_stats_samtools_single_end") { when { - params { - outdir = "$outputDir" - } workflow { """ input[0] = Channel.of([ @@ -41,9 +38,11 @@ nextflow_workflow { { assert workflow.success}, { assert workflow.out.bam.get(0).get(1) ==~ ".*.bam"}, { assert workflow.out.bai.get(0).get(1) ==~ ".*.bai"}, - { assert snapshot(workflow.out.stats).match("test_bam_sort_stats_samtools_single_end_stats") }, - { assert snapshot(workflow.out.flagstat).match("test_bam_sort_stats_samtools_single_end_flagstats") }, - { assert snapshot(workflow.out.idxstats).match("test_bam_sort_stats_samtools_single_end_idxstats") } + { assert snapshot( + workflow.out.flagstat, + workflow.out.idxstats, + workflow.out.stats, + workflow.out.versions).match() } ) } } @@ -51,9 +50,6 @@ nextflow_workflow { test("test_bam_sort_stats_samtools_paired_end") { when { - params { - outdir = "$outputDir" - } workflow { """ input[0] = Channel.of([ @@ -73,9 +69,65 @@ nextflow_workflow { { assert workflow.success}, { assert workflow.out.bam.get(0).get(1) ==~ ".*.bam"}, { assert workflow.out.bai.get(0).get(1) ==~ ".*.bai"}, - { assert snapshot(workflow.out.stats).match("test_bam_sort_stats_samtools_paired_end_stats") }, - { assert snapshot(workflow.out.flagstat).match("test_bam_sort_stats_samtools_paired_end_flagstats") }, - { assert snapshot(workflow.out.idxstats).match("test_bam_sort_stats_samtools_paired_end_idxstats") } + { assert snapshot( + workflow.out.flagstat, + workflow.out.idxstats, + workflow.out.stats, + workflow.out.versions).match() } + ) + } + } + + test("test_bam_sort_stats_samtools_single_end - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.single_end.bam', checkIfExists: true) + ]) + input[1] = Channel.of([ + [ id:'genome' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll( + { assert workflow.success}, + { assert snapshot(workflow.out).match() } + ) + } + } + + test("test_bam_sort_stats_samtools_paired_end - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true) + ]) + input[1] = Channel.of([ + [ id:'genome' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll( + { assert workflow.success}, + { assert snapshot(workflow.out).match() } ) } } diff --git a/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap b/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap index db063837..b7f4da17 100644 --- a/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap +++ b/subworkflows/nf-core/bam_sort_stats_samtools/tests/main.nf.test.snap @@ -1,5 +1,5 @@ { - "test_bam_sort_stats_samtools_paired_end_flagstats": { + "test_bam_sort_stats_samtools_single_end": { "content": [ [ [ @@ -7,36 +7,18 @@ "id": "test", "single_end": false }, - "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" + "test.flagstat:md5,2191911d72575a2358b08b1df64ccb53" ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.01.0" - }, - "timestamp": "2023-10-22T20:25:03.687121177" - }, - "test_bam_sort_stats_samtools_paired_end_idxstats": { - "content": [ + ], [ [ { "id": "test", "single_end": false }, - "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" + "test.idxstats:md5,613e048487662c694aa4a2f73ca96a20" ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.01.0" - }, - "timestamp": "2023-10-22T20:25:03.709648916" - }, - "test_bam_sort_stats_samtools_single_end_stats": { - "content": [ + ], [ [ { @@ -45,15 +27,22 @@ }, "test.stats:md5,d32de3b3716a11039cef2367c3c1a56e" ] + ], + [ + "versions.yml:md5,494b5530a1aa29fd5867cf655bebbfe1", + "versions.yml:md5,9fcb0cd845bfb1f89d83201bb20649b4", + "versions.yml:md5,bacc323ec4055d6f69f07a09089772d1", + "versions.yml:md5,ce946e97097c6a9ccf834a3f91f6da30", + "versions.yml:md5,d6c8dae685f1b7d050165fc15c7a20b5" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-05-29T07:47:44.044172487" + "timestamp": "2024-07-22T17:02:44.34964" }, - "test_bam_sort_stats_samtools_paired_end_stats": { + "test_bam_sort_stats_samtools_paired_end": { "content": [ [ [ @@ -61,50 +50,281 @@ "id": "test", "single_end": false }, - "test.stats:md5,cca83e4fc9406fc3875b5e60055d6574" + "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - }, - "timestamp": "2024-05-29T07:47:51.426232891" - }, - "test_bam_sort_stats_samtools_single_end_idxstats": { - "content": [ + ], [ [ { "id": "test", "single_end": false }, - "test.idxstats:md5,613e048487662c694aa4a2f73ca96a20" + "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.01.0" - }, - "timestamp": "2024-01-18T17:10:02.84631" - }, - "test_bam_sort_stats_samtools_single_end_flagstats": { - "content": [ + ], [ [ { "id": "test", "single_end": false }, - "test.flagstat:md5,2191911d72575a2358b08b1df64ccb53" + "test.stats:md5,cca83e4fc9406fc3875b5e60055d6574" ] + ], + [ + "versions.yml:md5,494b5530a1aa29fd5867cf655bebbfe1", + "versions.yml:md5,9fcb0cd845bfb1f89d83201bb20649b4", + "versions.yml:md5,bacc323ec4055d6f69f07a09089772d1", + "versions.yml:md5,ce946e97097c6a9ccf834a3f91f6da30", + "versions.yml:md5,d6c8dae685f1b7d050165fc15c7a20b5" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.01.0" + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T17:03:02.583095" + }, + "test_bam_sort_stats_samtools_single_end - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + + ], + "3": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "5": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "6": [ + "versions.yml:md5,494b5530a1aa29fd5867cf655bebbfe1", + "versions.yml:md5,9fcb0cd845bfb1f89d83201bb20649b4", + "versions.yml:md5,bacc323ec4055d6f69f07a09089772d1", + "versions.yml:md5,ce946e97097c6a9ccf834a3f91f6da30", + "versions.yml:md5,d6c8dae685f1b7d050165fc15c7a20b5" + ], + "bai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "csi": [ + + ], + "flagstat": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "idxstats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "stats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,494b5530a1aa29fd5867cf655bebbfe1", + "versions.yml:md5,9fcb0cd845bfb1f89d83201bb20649b4", + "versions.yml:md5,bacc323ec4055d6f69f07a09089772d1", + "versions.yml:md5,ce946e97097c6a9ccf834a3f91f6da30", + "versions.yml:md5,d6c8dae685f1b7d050165fc15c7a20b5" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T17:03:22.328703" + }, + "test_bam_sort_stats_samtools_paired_end - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + + ], + "3": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "5": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "6": [ + "versions.yml:md5,494b5530a1aa29fd5867cf655bebbfe1", + "versions.yml:md5,9fcb0cd845bfb1f89d83201bb20649b4", + "versions.yml:md5,bacc323ec4055d6f69f07a09089772d1", + "versions.yml:md5,ce946e97097c6a9ccf834a3f91f6da30", + "versions.yml:md5,d6c8dae685f1b7d050165fc15c7a20b5" + ], + "bai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "csi": [ + + ], + "flagstat": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "idxstats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "stats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,494b5530a1aa29fd5867cf655bebbfe1", + "versions.yml:md5,9fcb0cd845bfb1f89d83201bb20649b4", + "versions.yml:md5,bacc323ec4055d6f69f07a09089772d1", + "versions.yml:md5,ce946e97097c6a9ccf834a3f91f6da30", + "versions.yml:md5,d6c8dae685f1b7d050165fc15c7a20b5" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-18T17:10:02.829756" + "timestamp": "2024-07-22T17:03:38.833662" } } \ No newline at end of file From 35ebe7575bab3920311bd518fa04a1acf8ad5bfb Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Tue, 6 Aug 2024 18:07:06 +0200 Subject: [PATCH 458/491] fixing pattern for input file of mirna_expression --- nextflow_schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index 21f3dfb1..ef992d4e 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -66,7 +66,7 @@ "format": "file-path", "exists": true, "mimetype": "text/tsv", - "pattern": "^\\s+\\.tsv$", + "pattern": "^\\S+\\.tsv$", "description": "path to tab-separated file providing the expression counts of mirnas, which are created in pipeline 'smrnaseq'. \n\nmirna \t sample1 \t sample2 \t sample3 \t\nid1\t count_sample1 \t count_sample2 \t count_sample3 \t\nid2 \t ... \t ... \t ... \t \n", "fa_icon": "fas fa-file-tsv" }, From 399a16d3379c332b198142fc956af8fda591c991 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Wed, 7 Aug 2024 21:04:00 +0200 Subject: [PATCH 459/491] Adding missing html tag in output.md --- docs/output.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/output.md b/docs/output.md index 7c00df20..d706517c 100644 --- a/docs/output.md +++ b/docs/output.md @@ -369,6 +369,7 @@ The quantification is performed using psirc-quant, which is a wrapper around `ka - `*.marked.fasta`: Transcript sequences in FASTA format with the circRNA sequences marked with a `C` field in the header. - `*.tx2gene.tsv`: Transcript to gene mapping file. + ### Per sample
    From e550ec22544a86492b541ba004888069c207ba1b Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Wed, 7 Aug 2024 21:05:57 +0200 Subject: [PATCH 460/491] updating output.md in docs Updating the mirna_prediction section --- docs/output.md | 74 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/docs/output.md b/docs/output.md index d706517c..ea926cb2 100644 --- a/docs/output.md +++ b/docs/output.md @@ -24,9 +24,9 @@ The directories listed below will be created in the results directory after the - samples: Per sample quantification results - transcriptome: Combined linear and circular transcriptome, based on GTF file and detected BSJs - mirna_prediction - - miranda - - targetscan - - combined + - binding_sites + - correlation + - mirna_expression - statistical_tests - circtest - multiqc @@ -370,6 +370,7 @@ The quantification is performed using psirc-quant, which is a wrapper around `ka - `*.tx2gene.tsv`: Transcript to gene mapping file.
    + ### Per sample
    @@ -418,13 +419,22 @@ nf-core/circrna combines the sample-specific quantification results into proper ## miRNA Prediction -### miRanda +### Binding Sites + +#### Tools + +This section contains predicted binding sites for miRNA-target interactions generated by various computational tools. +Each tool utilizes unique algorithms and criteria to identify potential miRNA binding sites on target genomic sequences, providing complementary insights into miRNA regulatory networks. + +##### miRanda
    Output files -- `mirna_prediction/miranda/` - - `*.miRanda.txt`: Raw outputs from `miRanda`. +- `mirna_prediction/bindingsites/tools/miranda/output` + - `*.miranda.txt`: Raw predictions from `miRanda`. +- `mirna_prediction/bindingsites/tools/miranda/unified` + - `*.miranda.tsv`: Unified predictions from `miRanda`.
    @@ -433,24 +443,27 @@ nf-core/circrna combines the sample-specific quantification results into proper 1. First a dynamic programming local alignment is carried out between the query miRNA sequence and the reference sequence. This alignment procedure scores based on sequence complementarity and not on sequence identity. 2. Secondly, the algorithm takes high-scoring alignments detected from phase 1 and estimates the thermodynamic stability of RNA duplexes based on these alignments. This second phase of the method utilises folding routines from the `RNAlib` library, part of the [ViennaRNA](https://www.tbi.univie.ac.at/RNA/) package. -### TargetScan +##### TargetScan
    Output files -- `mirna_prediction/targetscan/` - - `*.targetscan.txt`: Raw outputs from `TargetScan`. +- `mirna_prediction/bindingsites/tools/targetscan/output` + - `*.targetscan.txt`: Raw predictions from `TargetScan`. +- `mirna_prediction/bindingsites/tools/targetscan/unified` + - `*.targetscan.tsv`: Unified predictions from `TargetScan`.
    [TargetScan](http://www.targetscan.org/vert_72/) predicts biological targets of miRNAs by searching for the presence of conserved 8mer, 7mer, and 6mer sites within the circRNA mature sequence that match the seed region of each miRNA. -### Combined + +#### Targets
    Output files -- `mirna_prediction/combined/` +- `mirna_prediction/binding_sites/targets` - `*_miRNA_targets.txt`: Filtered target miRNAs of circRNAs called by quantification tools. Columns are self explanatory: miRNA, Score, Energy_KcalMol, Start, End, Site_type.
    @@ -459,3 +472,42 @@ nf-core/circrna performs miRNA target filtering on `miRanda` and `TargetScan` pr 1. miRNA must be called by both `miRanda` and `TargetScan`. 2. If a site within the circRNA mature sequence shares duplicate miRNA ID's overlapping the same coordinates, the miRNA with the highest score is kept. + +#### Majority Vote + +
    +Output files + +- `mirna_prediction/binding_sites/majority_vote` + - `mirna.targets.tsv`: Stores miRNA-target mappings with all targets listed per miRNA, making it compact and suitable for bulk analyses. + - `mirna.majority.tsv`: Lists each miRNA-target interaction on a separate line, which is helpful for detailed analysis of each interaction independently. + +
    + +nf-core/circrna performs a majority vote on the predicted miRNA targets from [TargetScan](http://www.targetscan.org/vert_72/) and [miRanda](http://cbio.mskcc.org/miRNA2003/miranda.html) based on a +threshold specified by the user. + +### miRNA Expression + +
    +Output files + +- `mirna_prediction/mirna_expression/` + - `mirna.normalized_counts.tsv`: Contains normalized miRNA expression of all samples. + - `mirna.normalized_counts_filtered.tsv`: Contains miRNA expression after filtering. + +
    + +nf-core/circrna processes miRNA expression data by normalizing and filtering it for further analysis. + +### Correlation + +
    +Output files + +- `mirna_prediction/correlation` + - `*.tsv`: Files named after the specific miRNA containing correlation results for that miRNA with its target transcripts. + +
    + +nf-core/circrna computes correlations between miRNA and transcript expression levels and writes the results to individual tsv files for each miRNA-target interaction specified in the input binding sites file. From 8fef0f7cb7501a14b71af1c60da7181fd759994f Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Wed, 7 Aug 2024 21:17:44 +0200 Subject: [PATCH 461/491] capitalizing 'tsv' to TSV --- docs/output.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/output.md b/docs/output.md index ea926cb2..64599ac0 100644 --- a/docs/output.md +++ b/docs/output.md @@ -510,4 +510,4 @@ nf-core/circrna processes miRNA expression data by normalizing and filtering it
    -nf-core/circrna computes correlations between miRNA and transcript expression levels and writes the results to individual tsv files for each miRNA-target interaction specified in the input binding sites file. +nf-core/circrna computes correlations between miRNA and transcript expression levels and writes the results to individual TSV files for each miRNA-target interaction specified in the input binding sites file. From 740cc4372214078e59e159f927656ec018398add Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Wed, 7 Aug 2024 21:24:25 +0200 Subject: [PATCH 462/491] updating usage.md --- docs/usage.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 13a1b410..a8cbfcae 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -94,12 +94,15 @@ The output of the annotation step will be bundled with the outputs of the BSJ de ## miRNA prediction -This section allows looking for miRNA binding sites in the circRNAs. The following tools are currently supported: +This section allows looking for miRNA binding sites in the circRNAs. +The following tools are currently supported: - `miRanda` - `TargetScan` -This section will only be executed if the `mature` parameter is provided. The parameter should point to a FASTA file containing mature miRNA sequences. +This section will only be executed if the `mature` and `mirna_expression` parameters are provided. +The parameter `mature` should point to a FASTA file containing mature miRNA sequences. +The `mirna_expression` parameter should reference a TSV file containing the miRNA expression for each sample in your samplesheet. To view the outputs of the module, please see the output [documentation](https://nf-co.re/circrna/dev/output#mirna-prediction). From 5f9a7f98a425911fa31a16c87af2cb3a381a0dd2 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Wed, 7 Aug 2024 21:24:36 +0200 Subject: [PATCH 463/491] updating README.md --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6e8bb401..3f8b368f 100644 --- a/README.md +++ b/README.md @@ -54,9 +54,13 @@ If you want to contribute, feel free to create an issue or pull request on the [ - Merge circular transcriptome with linear transcriptome derived from provided GTF - Quantification of combined circular and linear transcriptome - [`psirc-quant`](https://github.com/Christina-hshi/psirc) -- miRNA binding affinity analysis (only if the `mature` parameter is provided) - - [`miRanda`](http://cbio.mskcc.org/miRNA2003/miranda.html) - - [`TargetScan`](http://www.targetscan.org/cgi-bin/targetscan/data_download.vert72.cgi) +- miRNA binding affinity analysis (only if the `mature` and `mirna_expression` parameter is provided) + - Normalizes miRNA expression + - Binding site prediction + - [`miRanda`](http://cbio.mskcc.org/miRNA2003/miranda.html) + - [`TargetScan`](http://www.targetscan.org/cgi-bin/targetscan/data_download.vert72.cgi) + - Perform majority vote on binding sites + - Compute correlations between miRNA and transcript expression levels - Statistical tests (only if the `phenotype` parameter is provided) - [`CircTest`](https://github.com/dieterich-lab/CircTest) - MultiQC report [`MultiQC`](http://multiqc.info/) From 596df450ca784369be156821bab66c5bdc0bf65b Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Wed, 7 Aug 2024 21:51:31 +0200 Subject: [PATCH 464/491] making mirna_expression parameter optional --- nextflow_schema.json | 1 - 1 file changed, 1 deletion(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index ef992d4e..bce90b44 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -59,7 +59,6 @@ "type": "object", "fa_icon": "fas fa-terminal", "description": "Define paths and threasholds for miRNA analysis.", - "required": ["mirna_expression"], "properties": { "mirna_expression": { "type": "string", From 6479a534f927fa92667aa7c598ae734918a89113 Mon Sep 17 00:00:00 2001 From: mweyrich28 <120316140+mweyrich28@users.noreply.github.com> Date: Wed, 7 Aug 2024 22:09:09 +0200 Subject: [PATCH 465/491] Apply suggestions from code review Co-authored-by: Nico Trummer <52698566+nictru@users.noreply.github.com> --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3f8b368f..d856c31d 100644 --- a/README.md +++ b/README.md @@ -54,13 +54,13 @@ If you want to contribute, feel free to create an issue or pull request on the [ - Merge circular transcriptome with linear transcriptome derived from provided GTF - Quantification of combined circular and linear transcriptome - [`psirc-quant`](https://github.com/Christina-hshi/psirc) -- miRNA binding affinity analysis (only if the `mature` and `mirna_expression` parameter is provided) - - Normalizes miRNA expression +- miRNA binding affinity analysis (only if the `mature` parameter is provided) + - Normalizes miRNA expression (only if the `mirna_expression` parameter is provided) - Binding site prediction - [`miRanda`](http://cbio.mskcc.org/miRNA2003/miranda.html) - [`TargetScan`](http://www.targetscan.org/cgi-bin/targetscan/data_download.vert72.cgi) - Perform majority vote on binding sites - - Compute correlations between miRNA and transcript expression levels + - Compute correlations between miRNA and transcript expression levels (only if the `mirna_expression` parameter is provided) - Statistical tests (only if the `phenotype` parameter is provided) - [`CircTest`](https://github.com/dieterich-lab/CircTest) - MultiQC report [`MultiQC`](http://multiqc.info/) From e52e401b181b30c214cd65e6ee11902af5c43d6f Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Wed, 7 Aug 2024 22:25:04 +0200 Subject: [PATCH 466/491] renaming mirna_vote to mirna_tool_filter --- modules/local/majority_vote/templates/majority.py | 2 +- nextflow_schema.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/local/majority_vote/templates/majority.py b/modules/local/majority_vote/templates/majority.py index 2969ce54..b08d9c25 100644 --- a/modules/local/majority_vote/templates/majority.py +++ b/modules/local/majority_vote/templates/majority.py @@ -28,7 +28,7 @@ def format_yaml_like(data: dict, indent: int = 0) -> str: df = df.groupby(['mirna', 'target'])['tool'].apply(set).reset_index() # performing majority vote keeping only mirna binding sites that meet the required number of votes -min_tools = int("${params.mirna_vote}") +min_tools = int("${params.mirna_tool_filter}") df = df[df['tool'].apply(len) >= min_tools].copy() df = df.drop('tool', axis=1) diff --git a/nextflow_schema.json b/nextflow_schema.json index bce90b44..8ab9ecdc 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -147,7 +147,7 @@ "default": "miranda, targetscan", "pattern": "^((miranda|targetscan|pita|tarpmir)?,?)*[^,]+$" }, - "mirna_vote": { + "mirna_tool_filter": { "type": "integer", "fa_icon": "fas fa-intersection", "description": "Specify the number of votes required for a miRNA to be further considered in downstream analysis.'", From e49b9477abf910aaddd2427784e9a186d436f8c6 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 09:21:16 +0200 Subject: [PATCH 467/491] applying prettier --- README.md | 2 +- docs/output.md | 1 - modules.json | 189 +++++------------- modules/local/mirna_filtering/environment.yml | 2 +- 4 files changed, 49 insertions(+), 145 deletions(-) diff --git a/README.md b/README.md index d856c31d..5ea93d2c 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ If you want to contribute, feel free to create an issue or pull request on the [ - Binding site prediction - [`miRanda`](http://cbio.mskcc.org/miRNA2003/miranda.html) - [`TargetScan`](http://www.targetscan.org/cgi-bin/targetscan/data_download.vert72.cgi) - - Perform majority vote on binding sites + - Perform majority vote on binding sites - Compute correlations between miRNA and transcript expression levels (only if the `mirna_expression` parameter is provided) - Statistical tests (only if the `phenotype` parameter is provided) - [`CircTest`](https://github.com/dieterich-lab/CircTest) diff --git a/docs/output.md b/docs/output.md index 64599ac0..f7016c8b 100644 --- a/docs/output.md +++ b/docs/output.md @@ -457,7 +457,6 @@ Each tool utilizes unique algorithms and criteria to identify potential miRNA bi [TargetScan](http://www.targetscan.org/vert_72/) predicts biological targets of miRNAs by searching for the presence of conserved 8mer, 7mer, and 6mer sites within the circRNA mature sequence that match the seed region of each miRNA. - #### Targets
    diff --git a/modules.json b/modules.json index abfb70e0..c1bed414 100644 --- a/modules.json +++ b/modules.json @@ -8,292 +8,208 @@ "bedtools/getfasta": { "branch": "master", "git_sha": "cdcdd5e3d806f0ff3983c40c69e0b07bb44ec299", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "bedtools/groupby": { "branch": "master", "git_sha": "3b248b84694d1939ac4bb33df84bf6233a34d668", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "bedtools/intersect": { "branch": "master", "git_sha": "575e1bc54b083fb15e7dd8b5fcc40bea60e8ce83", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "bedtools/sort": { "branch": "master", "git_sha": "571a5feac4c9ce0a8df0bc15b94230e7f3e8db47", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "bioawk": { "branch": "master", "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/bioawk/bioawk.diff" }, "bowtie/align": { "branch": "master", "git_sha": "3c77ca9aac783e76c3614a06db3bfe4fef619bde", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "bowtie/build": { "branch": "master", "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "bowtie2/align": { "branch": "master", "git_sha": "e4bad511789f16d0df39ee306b2cd50418365048", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "bowtie2/build": { "branch": "master", "git_sha": "1fea64f5132a813ec97c1c6d3a74e0aee7142b6d", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "bwa/index": { "branch": "master", "git_sha": "e0ff65e1fb313677de09f5f477ae3da30ce19b7b", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "cat/cat": { "branch": "master", "git_sha": "9437e6053dccf4aafa022bfd6e7e9de67e625af8", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "cat/fastq": { "branch": "master", "git_sha": "4fc983ad0b30e6e32696fa7d980c76c7bfe1c03e", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "circexplorer2/annotate": { "branch": "master", "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "circexplorer2/parse": { "branch": "master", "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "csvtk/join": { "branch": "master", "git_sha": "614abbf126f287a3068dc86997b2e1b6a93abe20", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "csvtk/split": { "branch": "master", "git_sha": "614abbf126f287a3068dc86997b2e1b6a93abe20", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "custom/dumpsoftwareversions": { "branch": "master", "git_sha": "de45447d060b8c8b98575bc637a4a575fd0638e1", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "custom/gtffilter": { "branch": "master", "git_sha": "a0aee18374b7f072aa0f89f4d66f5a3a9f8176d2", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "custom/tx2gene": { "branch": "master", "git_sha": "ec155021a9104441bf6a9bae3b55d1b5b0bfdb3a", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "fastqc": { "branch": "master", "git_sha": "285a50500f9e02578d90b3ce6382ea3c30216acd", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "gawk": { "branch": "master", "git_sha": "cf3ed075695639b0a0924eb0901146df1996dc08", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "gnu/sort": { "branch": "master", "git_sha": "a3cc42943548378b726610f45bb5a79ab3f0b633", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "hisat2/align": { "branch": "master", "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "hisat2/build": { "branch": "master", "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "hisat2/extractsplicesites": { "branch": "master", "git_sha": "400037f54de4b0c42712ec5a499d9fd9e66250d1", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "miranda": { "branch": "master", "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "multiqc": { "branch": "master", "git_sha": "b7ebe95761cd389603f9cc0e0dc384c0f663815a", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "samtools/faidx": { "branch": "master", "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "samtools/flagstat": { "branch": "master", "git_sha": "46eca555142d6e597729fcb682adcc791796f514", - "installed_by": [ - "bam_stats_samtools" - ] + "installed_by": ["bam_stats_samtools"] }, "samtools/idxstats": { "branch": "master", "git_sha": "46eca555142d6e597729fcb682adcc791796f514", - "installed_by": [ - "bam_stats_samtools" - ] + "installed_by": ["bam_stats_samtools"] }, "samtools/index": { "branch": "master", "git_sha": "46eca555142d6e597729fcb682adcc791796f514", - "installed_by": [ - "bam_sort_stats_samtools", - "modules" - ] + "installed_by": ["bam_sort_stats_samtools", "modules"] }, "samtools/sort": { "branch": "master", "git_sha": "46eca555142d6e597729fcb682adcc791796f514", - "installed_by": [ - "bam_sort_stats_samtools", - "modules" - ] + "installed_by": ["bam_sort_stats_samtools", "modules"] }, "samtools/stats": { "branch": "master", "git_sha": "46eca555142d6e597729fcb682adcc791796f514", - "installed_by": [ - "bam_stats_samtools" - ] + "installed_by": ["bam_stats_samtools"] }, "samtools/view": { "branch": "master", "git_sha": "6c2309aaec566c0d44a6cf14d4b2d0c51afe2e91", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "segemehl/align": { "branch": "master", "git_sha": "9a6b0745dbb5359286d36dee2183ffab240abba0", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "segemehl/index": { "branch": "master", "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "star/align": { "branch": "master", "git_sha": "a21faa6a3481af92a343a10926f59c189a2c16c9", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "star/genomegenerate": { "branch": "master", "git_sha": "a21faa6a3481af92a343a10926f59c189a2c16c9", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "stringtie/stringtie": { "branch": "master", "git_sha": "b1b959609bda44341120aed1766329909f54b8d0", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "trimgalore": { "branch": "master", "git_sha": "a98418419ae6c9df3cf6cf108d1e1aba71037d5a", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "tximeta/tximport": { "branch": "master", "git_sha": "5d095e8413da1f4c72b7d07ce87f75c09482486f", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] } } }, @@ -302,41 +218,30 @@ "bam_sort_stats_samtools": { "branch": "master", "git_sha": "46eca555142d6e597729fcb682adcc791796f514", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] }, "bam_stats_samtools": { "branch": "master", "git_sha": "0eacd714effe5aac1c1de26593873960b3346cab", - "installed_by": [ - "bam_sort_stats_samtools", - "subworkflows" - ] + "installed_by": ["bam_sort_stats_samtools", "subworkflows"] }, "utils_nextflow_pipeline": { "branch": "master", "git_sha": "5caf7640a9ef1d18d765d55339be751bb0969dfa", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { "branch": "master", "git_sha": "92de218a329bfc9a9033116eb5f65fd270e72ba3", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] }, "utils_nfvalidation_plugin": { "branch": "master", "git_sha": "5caf7640a9ef1d18d765d55339be751bb0969dfa", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] } } } } } -} \ No newline at end of file +} diff --git a/modules/local/mirna_filtering/environment.yml b/modules/local/mirna_filtering/environment.yml index 1aa60c3d..ddeffa11 100644 --- a/modules/local/mirna_filtering/environment.yml +++ b/modules/local/mirna_filtering/environment.yml @@ -1,4 +1,4 @@ -name: mirna_filtering +name: mirna_filtering channels: - conda-forge - defaults From edafce4825c5b541196d74ab4b86c063b4c7551f Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 09:23:53 +0200 Subject: [PATCH 468/491] renaming mirna_tools in nextflow.config --- nextflow.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index 21270121..f79cdd5b 100644 --- a/nextflow.config +++ b/nextflow.config @@ -69,7 +69,7 @@ params { mirna_expression = null mirna_min_reads = 5 mirna_min_sample_percentage = 0.2 - mirna_tools = 'miranda, targetscan' + mirna_tool_filter = 'miranda, targetscan' mirna_vote = 1 mirna_correlation = 'pearson' From 4d514b405c8f758c9e395fe3347a091b4c6a7f53 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 09:25:34 +0200 Subject: [PATCH 469/491] fixing indent --- modules/local/mirna_filtering/main.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/local/mirna_filtering/main.nf b/modules/local/mirna_filtering/main.nf index 035354d1..03efeea4 100644 --- a/modules/local/mirna_filtering/main.nf +++ b/modules/local/mirna_filtering/main.nf @@ -5,12 +5,12 @@ process MIRNA_FILTERING { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/r-base:4.2.1' : - 'biocontainers/r-base:4.2.1' }" + 'biocontainers/r-base:4.2.1' }" input: tuple val(meta), path(normalized_counts) - val(mirna_min_sample_percentage) - val(mirna_min_reads) + val(mirna_min_sample_percentage) + val(mirna_min_reads) output: tuple val(meta), path("${meta.id}.normalized_counts_filtered.tsv"), emit: filtered From 737da8027e5c14563cafd261a17a4454a1816dbb Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 09:28:10 +0200 Subject: [PATCH 470/491] deleting redundant file --- modules/local/mirna_filtering/environment.yml | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 modules/local/mirna_filtering/environment.yml diff --git a/modules/local/mirna_filtering/environment.yml b/modules/local/mirna_filtering/environment.yml deleted file mode 100644 index ddeffa11..00000000 --- a/modules/local/mirna_filtering/environment.yml +++ /dev/null @@ -1,4 +0,0 @@ -name: mirna_filtering -channels: - - conda-forge - - defaults From b112f0c9ec6314623123114096cfbbb1f3a6ee00 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 09:35:36 +0200 Subject: [PATCH 471/491] rewording usage --- docs/usage.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index a8cbfcae..2dbeda74 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -100,9 +100,11 @@ The following tools are currently supported: - `miRanda` - `TargetScan` -This section will only be executed if the `mature` and `mirna_expression` parameters are provided. +This section will only be executed if the `mature` parameter is provided. The parameter `mature` should point to a FASTA file containing mature miRNA sequences. -The `mirna_expression` parameter should reference a TSV file containing the miRNA expression for each sample in your samplesheet. +By providing a TSV file containing the miRNA expression of all samples via `mirna_expression`, this +subworkflow will perform additional normalization and filtering of `mirna_expression` and `mature` before +executing the miRNA binding size prediction. To view the outputs of the module, please see the output [documentation](https://nf-co.re/circrna/dev/output#mirna-prediction). From bd7cd3690f64c588f1d2e101def8f100079a9397 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 09:40:59 +0200 Subject: [PATCH 472/491] rewording usage --- docs/usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage.md b/docs/usage.md index 2dbeda74..2f3b2166 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -103,7 +103,7 @@ The following tools are currently supported: This section will only be executed if the `mature` parameter is provided. The parameter `mature` should point to a FASTA file containing mature miRNA sequences. By providing a TSV file containing the miRNA expression of all samples via `mirna_expression`, this -subworkflow will perform additional normalization and filtering of `mirna_expression` and `mature` before +sub-workflow will perform additional normalization and filtering of `mirna_expression` and `mature` before executing the miRNA binding size prediction. To view the outputs of the module, please see the output [documentation](https://nf-co.re/circrna/dev/output#mirna-prediction). From 7f165bafe3166625887587170b62bd6fc7afba59 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 09:52:29 +0200 Subject: [PATCH 473/491] reformatting compute correlations --- modules/local/compute_correlations/main.nf | 2 +- .../templates/compute_correlations.R | 51 ++++++++++--------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/modules/local/compute_correlations/main.nf b/modules/local/compute_correlations/main.nf index 773fddae..4a72b5eb 100644 --- a/modules/local/compute_correlations/main.nf +++ b/modules/local/compute_correlations/main.nf @@ -21,7 +21,7 @@ process COMPUTE_CORRELATIONS { script: template 'compute_correlations.R' - + stub: """ touch ${meta.id}.circrna_correlation.tsv diff --git a/modules/local/compute_correlations/templates/compute_correlations.R b/modules/local/compute_correlations/templates/compute_correlations.R index e60ccc73..d9976226 100644 --- a/modules/local/compute_correlations/templates/compute_correlations.R +++ b/modules/local/compute_correlations/templates/compute_correlations.R @@ -11,34 +11,34 @@ tx_expression <- scaleInfReps(tx_expression) tx_expression <- labelKeep(tx_expression) # Here one can perform custom filtering if (!any(mcols(tx_expression)\$keep)) { - stop('No transcripts left after filtering') + stop('No transcripts left after filtering') } result_cols <- c('stat', 'log2FC', 'pvalue', 'locfdr', 'qvalue') # Iterate rows of interactions for (i in 1:nrow(interactions)) { - # Get miRNA and target gene - miRNA <- interactions[i, 1] - targets <- unlist(strsplit(interactions[i, 2], ',')) - - mirna_expression <- mi_expression[miRNA,] - transcript_expression <- tx_expression[targets,] - - if (!any(mcols(transcript_expression)\$keep)) { - print(paste('No transcripts left after filtering for miRNA', miRNA)) - next - } - - # Add miRNA expression to colData so that it can be used for correlation - colData(transcript_expression) <- cbind( - colData(transcript_expression), - t(mirna_expression[, rownames(colData(transcript_expression))]) - ) - - result <- rowData(swish(transcript_expression, miRNA, cor = "${params.mirna_correlation}"))[, result_cols] - result <- result[complete.cases(result), ] - write.table(result, paste0(miRNA, '.tsv'), sep = '\\t') + # Get miRNA and target gene + miRNA <- interactions[i, 1] + targets <- unlist(strsplit(interactions[i, 2], ',')) + + mirna_expression <- mi_expression[miRNA,] + transcript_expression <- tx_expression[targets,] + + if (!any(mcols(transcript_expression)\$keep)) { + print(paste('No transcripts left after filtering for miRNA', miRNA)) + next + } + + # Add miRNA expression to colData so that it can be used for correlation + colData(transcript_expression) <- cbind( + colData(transcript_expression), + t(mirna_expression[, rownames(colData(transcript_expression))]) + ) + + result <- rowData(swish(transcript_expression, miRNA, cor = "${params.mirna_correlation}"))[, result_cols] + result <- result[complete.cases(result), ] + write.table(result, paste0(miRNA, '.tsv'), sep = '\\t') } ################################################ @@ -53,5 +53,10 @@ writeLines( c( '"${task.process}":', paste(' r-base:', r.version) - ), + ), 'versions.yml') + +################################################ +################################################ +################################################ +################################################ From 5708f75696627954ee666743521a1f2f2c0eed95 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 09:52:48 +0200 Subject: [PATCH 474/491] reformatting normalization --- .../templates/deseq_normalization.R | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/modules/local/deseq2/normalization/templates/deseq_normalization.R b/modules/local/deseq2/normalization/templates/deseq_normalization.R index 131bfd54..91b366dc 100644 --- a/modules/local/deseq2/normalization/templates/deseq_normalization.R +++ b/modules/local/deseq2/normalization/templates/deseq_normalization.R @@ -2,16 +2,12 @@ library(DESeq2) -raw_counts <- read.table("$counts", sep = "\\t", - header = TRUE, - stringsAsFactors = FALSE, - check.names = FALSE) +raw_counts <- read.table("$counts", sep = "\\t", header = TRUE, stringsAsFactors = FALSE, check.names = FALSE) samples <- colnames(raw_counts)[-c(1)] row.names(raw_counts) <- raw_counts\$miRNA data <- raw_counts[, -1] -mirna_names <- data.frame(miRNA = raw_counts\$miRNA, - order = seq_len(nrow(raw_counts))) +mirna_names <- data.frame(miRNA = raw_counts\$miRNA, order = seq_len(nrow(raw_counts))) # normalize using DeSeq2, Library Size Estimation meta_data <- data.frame(samples) @@ -19,22 +15,19 @@ row.names(meta_data) <- meta_data\$samples all(colnames(data) %in% rownames(meta_data)) all(colnames(data) == rownames(meta_data)) -dds <- DESeqDataSetFromMatrix(countData = data, - colData = meta_data, - design = ~ 1) +dds <- DESeqDataSetFromMatrix(countData = data, colData = meta_data, design = ~ 1) dds <- estimateSizeFactors(dds) sizeFactors(dds) normalized_counts <- DESeq2::counts(dds, normalized = TRUE) # add miRNA IDs back to counts table merged_data <- merge(mirna_names, normalized_counts, - by.x = "miRNA", by.y = "row.names") + by.x = "miRNA", by.y = "row.names") merged_data <- merged_data[order(merged_data\$order), ] norm_data <- subset(merged_data, select = -c(order)) -write.table(norm_data, paste0("${meta.id}.normalized_counts.tsv"), - quote = FALSE, sep = "\\t", row.names = FALSE) +write.table(norm_data, paste0("${meta.id}.normalized_counts.tsv"), quote = FALSE, sep = "\\t", row.names = FALSE) # TODO: (Can be done later) Add support for Samplesheet so that we can eliminate batch effects From 3b7074d556dcd976e40aae62bf6a0e42f72a08b5 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 09:54:11 +0200 Subject: [PATCH 475/491] reformatting majority vote --- modules/local/majority_vote/main.nf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/local/majority_vote/main.nf b/modules/local/majority_vote/main.nf index 7b58a67f..5161ca6d 100644 --- a/modules/local/majority_vote/main.nf +++ b/modules/local/majority_vote/main.nf @@ -4,12 +4,12 @@ process MAJORITY_VOTE { conda "bioconda::pandas=1.5.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : + 'https://depot.galaxyproject.org/singularity/pandas:1.5.2' : 'biocontainers/pandas:1.5.2' }" input: tuple val(meta), path(bindingsites) - + output: tuple val(meta), path("${meta.id}.majority.tsv"), emit: tsv From 6ac49fd1284f4202ef765b8d41de5ec8d35dfe0a Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 09:54:58 +0200 Subject: [PATCH 476/491] reformatting majority vote py --- modules/local/majority_vote/templates/majority.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/local/majority_vote/templates/majority.py b/modules/local/majority_vote/templates/majority.py index b08d9c25..70c5dd91 100644 --- a/modules/local/majority_vote/templates/majority.py +++ b/modules/local/majority_vote/templates/majority.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python3 import pandas as pd import platform From 26e75994c2c73df08f529a181f3ffa651723d068 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 09:56:00 +0200 Subject: [PATCH 477/491] reformatting mirna filtering R --- .../mirna_filtering/templates/mirna_filtering.R | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/local/mirna_filtering/templates/mirna_filtering.R b/modules/local/mirna_filtering/templates/mirna_filtering.R index 32521c8e..588eb260 100644 --- a/modules/local/mirna_filtering/templates/mirna_filtering.R +++ b/modules/local/mirna_filtering/templates/mirna_filtering.R @@ -18,15 +18,15 @@ sample_nr_cutoff <- ceiling($mirna_min_sample_percentage * length(samples)) rows_to_keep <- c() for (i in seq_len(nrow(expression_norm))) { - mirna_per_sample <- 0 - for (j in 5:ncol(expression_norm)) { - if (expression_norm[i, j] >= $mirna_min_reads) { - mirna_per_sample <- mirna_per_sample + 1 + mirna_per_sample <- 0 + for (j in 5:ncol(expression_norm)) { + if (expression_norm[i, j] >= $mirna_min_reads) { + mirna_per_sample <- mirna_per_sample + 1 + } + } + if (mirna_per_sample >= sample_nr_cutoff) { + rows_to_keep <- append(rows_to_keep, i) } - } - if (mirna_per_sample >= sample_nr_cutoff) { - rows_to_keep <- append(rows_to_keep, i) - } } filtered_data <- expression_norm[rows_to_keep, ] From 050bb4d6db9ce0129695e2aea5a198dbf9e1e3af Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 09:58:23 +0200 Subject: [PATCH 478/491] reformatting mirna bindingsites --- subworkflows/local/mirna/mirna_bindingsites.nf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/subworkflows/local/mirna/mirna_bindingsites.nf b/subworkflows/local/mirna/mirna_bindingsites.nf index 7683524f..d81abae5 100644 --- a/subworkflows/local/mirna/mirna_bindingsites.nf +++ b/subworkflows/local/mirna/mirna_bindingsites.nf @@ -7,7 +7,7 @@ include { MIRNA_TARGETS } from '../../../modules/local/mirna_t include { CAT_CAT as COMBINE_BINDINGSITES } from '../../../modules/nf-core/cat/cat' include { MAJORITY_VOTE } from '../../../modules/local/majority_vote' -workflow MIRNA_BINDINGSITES { +workflow MIRNA_BINDINGSITES { take: transcriptome_fasta circrna_bed12 @@ -35,26 +35,26 @@ workflow MIRNA_BINDINGSITES { if (tools_selected.size() == 0) { error 'No tools selected for miRNA discovery.' } - + if (tools_selected.contains('targetscan')) { // // TARGETSCAN WORKFLOW: // TARGETSCAN( ch_transcriptome_batches, formatMiRNAForTargetScan( mirna_fasta ).collect() ) UNIFY_TARGETSCAN( TARGETSCAN.out.txt, [] ) - + ch_versions = ch_versions.mix(TARGETSCAN.out.versions) ch_versions = ch_versions.mix(UNIFY_TARGETSCAN.out.versions) ch_predictions = ch_predictions.mix(UNIFY_TARGETSCAN.out.output) } - + if (tools_selected.contains('miranda')) { // // MIRANDA WORKFLOW: // MIRANDA( ch_transcriptome_batches, mirna_fasta.map{meta, mature -> mature}.collect() ) UNIFY_MIRANDA( MIRANDA.out.txt, [] ) - + ch_versions = ch_versions.mix(MIRANDA.out.versions) ch_versions = ch_versions.mix(UNIFY_MIRANDA.out.versions) ch_predictions = ch_predictions.mix(UNIFY_MIRANDA.out.output) @@ -67,7 +67,7 @@ workflow MIRNA_BINDINGSITES { // consolidate_targets = TARGETSCAN.out.txt.join(MIRANDA.out.txt).join(circrna_bed12) consolidate_targets = TARGETSCAN.out.txt.join(MIRANDA.out.txt) - + MIRNA_TARGETS( consolidate_targets ) ch_versions = ch_versions.mix(MIRNA_TARGETS.out.versions) From 1cd2841e076db4e651340f9f2bcab74cab32cc26 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 10:02:41 +0200 Subject: [PATCH 479/491] reformatting mirna prediction --- subworkflows/local/mirna_prediction.nf | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/subworkflows/local/mirna_prediction.nf b/subworkflows/local/mirna_prediction.nf index 48c64fbe..b3fc46cc 100644 --- a/subworkflows/local/mirna_prediction.nf +++ b/subworkflows/local/mirna_prediction.nf @@ -9,7 +9,7 @@ include { MIRNA_BINDINGSITES } from './mirna/mirna_bindingsites' workflow MIRNA_PREDICTION { - take: + take: transcriptome_fasta circrna_annotation ch_mature @@ -25,16 +25,16 @@ workflow MIRNA_PREDICTION { // if (params.mirna_expression) { - + ch_mirna_normalized = DESEQ2_NORMALIZATION( ch_mirna ).normalized ch_versions = ch_versions.mix(DESEQ2_NORMALIZATION.out.versions) - ch_mirna_filtered = MIRNA_FILTERING(ch_mirna_normalized, - params.mirna_min_sample_percentage, + ch_mirna_filtered = MIRNA_FILTERING(ch_mirna_normalized, + params.mirna_min_sample_percentage, params.mirna_min_reads ).filtered - + ch_versions = ch_versions.mix(MIRNA_FILTERING.out.versions) // @@ -52,8 +52,8 @@ workflow MIRNA_PREDICTION { .combine(ch_uniq_mirnas.map{ it -> [it]}) // Not sure why this mapping is necessary but I think it is .filter{ record, mirnas -> ch_uniq_mirnas.contains(record.id).value - }.map{ record, mirnas -> - ">${record.id}\n${record.seqString}" + }.map{ record, mirnas -> + ">${record.id}\n${record.seqString}" } .collectFile( name: 'mature_filtered.fa', newLine: true) .map{ it -> [[id: 'mature_filtered'], it]} @@ -70,10 +70,8 @@ workflow MIRNA_PREDICTION { .splitText(by: 100, file: true) .map{ meta, file -> [[id: "batch_" + file.baseName.split("\\.").last()], file]} - COMPUTE_CORRELATIONS( ch_binding_site_batches, - ch_mirna_filtered, - quantification_rds ) - + COMPUTE_CORRELATIONS(ch_binding_site_batches, ch_mirna_filtered, quantification_rds) + ch_correlation_results = COMPUTE_CORRELATIONS.out.correlations .map{meta, results -> results} .flatten().collect() From 80edcc51b2b8ad91a74857b325e7c1120f7f9be4 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 10:06:44 +0200 Subject: [PATCH 480/491] fixing param mirna_tool_filter --- nextflow.config | 4 ++-- nextflow_schema.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nextflow.config b/nextflow.config index f79cdd5b..3d2aa173 100644 --- a/nextflow.config +++ b/nextflow.config @@ -69,8 +69,8 @@ params { mirna_expression = null mirna_min_reads = 5 mirna_min_sample_percentage = 0.2 - mirna_tool_filter = 'miranda, targetscan' - mirna_vote = 1 + mirna_tools = 'miranda, targetscan' + mirna_tool_filter = 1 mirna_correlation = 'pearson' diff --git a/nextflow_schema.json b/nextflow_schema.json index 8ab9ecdc..d62d2493 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -151,7 +151,7 @@ "type": "integer", "fa_icon": "fas fa-intersection", "description": "Specify the number of votes required for a miRNA to be further considered in downstream analysis.'", - "help_text": "Controls the number of votes required for a binding site prediction to be considered valid. If a miRNA binding site was predicted by two different tools (e.g., miRanda and TargetScan), it receives two votes. By specifying additional tools for miRNA binding site prediction (using the 'mirna_tools' parameter), you can adjust the number of votes required for a binding site to be considered valid.", + "help_text": "Controls the number of votes required for a binding site prediction to be considered valid. If a miRNA binding site was predicted by two different tools (e.g., miRanda and TargetScan), it receives two votes. By specifying additional tools for miRNA binding site prediction (using the 'mirna_tool_filter' parameter), you can adjust the number of votes required for a binding site to be considered valid.", "default": 1, "minimum": 1, "maximum": 4 From 0106c3a59717200322518dffabf3664a8591aace Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 10:16:15 +0200 Subject: [PATCH 481/491] checking if mirna_expression is null before passing it to file() --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index b5a47b01..9be3219c 100644 --- a/main.nf +++ b/main.nf @@ -60,7 +60,7 @@ workflow NFCORE_CIRCRNA { ch_mature = params.mature ? Channel.value([[id: "mature"], file(params.mature, checkIfExists:true)]) : Channel.empty() ch_phenotype = params.phenotype ? Channel.value([[id: "phenotype"], file(params.phenotype, checkIfExists:true)]) : Channel.empty() ch_annotation = params.annotation ? Channel.fromSamplesheet("annotation") : Channel.empty() - ch_mirna = params.mature ? Channel.value([[id: "mirna"], file(params.mirna_expression, checkIfExists:true)]) : Channel.empty() + ch_mirna = params.mature && params.mirna_expression ? Channel.value([[id: "mirna"], file(params.mirna_expression, checkIfExists:true)]) : Channel.empty() CIRCRNA ( ch_samplesheet, From 2be53ee11605ae70e54a1057aa938b4208cdfc0b Mon Sep 17 00:00:00 2001 From: mweyrich28 <120316140+mweyrich28@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:25:57 +0200 Subject: [PATCH 482/491] Apply suggestions from code review Co-authored-by: Nico Trummer <52698566+nictru@users.noreply.github.com> --- nextflow_schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index d62d2493..64c63c17 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -143,9 +143,9 @@ "type": "string", "fa_icon": "fas fa-wrench", "description": "Comma separated list of miRNA bindingsite prediction tools to use. Supported tools: miranda, targetscan.", - "help_text": "Select one or a combination of miRNA bindingsite prediction tools for the pipeline e.g:\n--tool 'miranda, targetscan'", + "help_text": "Select one or a combination of miRNA bindingsite prediction tools for the pipeline e.g:\n--mirna_tools 'miranda,targetscan'", "default": "miranda, targetscan", - "pattern": "^((miranda|targetscan|pita|tarpmir)?,?)*[^,]+$" + "pattern": "^((miranda|targetscan)?,?)*[^,]+$" }, "mirna_tool_filter": { "type": "integer", From e0afb0a42aaae49a7c85e9402dcea5e0df9478ba Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 10:28:23 +0200 Subject: [PATCH 483/491] applying correct format to mirna_tools --- nextflow.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index 3d2aa173..ff6b0bbc 100644 --- a/nextflow.config +++ b/nextflow.config @@ -69,7 +69,7 @@ params { mirna_expression = null mirna_min_reads = 5 mirna_min_sample_percentage = 0.2 - mirna_tools = 'miranda, targetscan' + mirna_tools = 'miranda,targetscan' mirna_tool_filter = 1 mirna_correlation = 'pearson' From 5082d4fad8e3d8b6bb51729c2f9c752b1df7b3f5 Mon Sep 17 00:00:00 2001 From: Malte Weyrich Date: Thu, 8 Aug 2024 10:37:20 +0200 Subject: [PATCH 484/491] updating default format of mirna_tools --- nextflow_schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index 64c63c17..ee8ea89c 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -144,7 +144,7 @@ "fa_icon": "fas fa-wrench", "description": "Comma separated list of miRNA bindingsite prediction tools to use. Supported tools: miranda, targetscan.", "help_text": "Select one or a combination of miRNA bindingsite prediction tools for the pipeline e.g:\n--mirna_tools 'miranda,targetscan'", - "default": "miranda, targetscan", + "default": "miranda,targetscan", "pattern": "^((miranda|targetscan)?,?)*[^,]+$" }, "mirna_tool_filter": { From 6f69c930706939f7677eab9d21427244c416b453 Mon Sep 17 00:00:00 2001 From: Nico Trummer <52698566+nictru@users.noreply.github.com> Date: Thu, 8 Aug 2024 09:43:10 +0000 Subject: [PATCH 485/491] Add credits for mweyrich --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5ea93d2c..a1e288e1 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,7 @@ We thank the following people for their extensive assistance in the development - [Alexander Peltzer](https://github.com/apeltzer) - [Ben Whittle](https://github.com/bj-w) - [Kevin Menden](https://github.com/KevinMenden) +- [Malte Weyrich](https://github.com/mweyrich28) - [Marieke Vromman](https://github.com/MariekeVromman) - [Maxime Garcia](https://github.com/maxulysse) - [Phil Ewels](https://github.com/ewels) From 2977ef0b39aee0ee3cad6af18377c25c425ae162 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 8 Aug 2024 23:00:54 +0200 Subject: [PATCH 486/491] Implement count extraction --- conf/modules.config | 10 ++++++++++ subworkflows/local/bsj_detection.nf | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/conf/modules.config b/conf/modules.config index 4f6fea71..68008694 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -652,6 +652,16 @@ process { ] } + withName: 'EXTRACT_COUNTS' { + // Add meta.id as header + // Keep columns 4,5 + ext.args = { "-v FS='\\t' -v OFS='\\t' 'BEGIN { print \"id\", \"${meta.id}\" } { print \$4, \$5 }'" } + ext.suffix = {"counts.tsv"} + publishDir = [ + enabled: false + ] + } + withName: UPSET_SAMPLES { ext.when = { params.tools.split(',').length > 1 } publishDir = [ diff --git a/subworkflows/local/bsj_detection.nf b/subworkflows/local/bsj_detection.nf index 5da9899f..f0e5187f 100644 --- a/subworkflows/local/bsj_detection.nf +++ b/subworkflows/local/bsj_detection.nf @@ -5,6 +5,7 @@ include { GNU_SORT as CONCAT_TOOLS_PER_SAMPLE } from '../../modules/nf-co include { BEDTOOLS_GROUPBY as COUNT_TOOLS } from '../../modules/nf-core/bedtools/groupby' include { GAWK as FILTER_MIN_TOOLS } from '../../modules/nf-core/gawk' include { GNU_SORT as CONCAT_SAMPLES } from '../../modules/nf-core/gnu/sort' +include { GAWK as EXTRACT_COUNTS } from '../../modules/nf-core/gawk' include { UPSET as UPSET_SAMPLES } from '../../modules/local/upset' include { UPSET as UPSET_ALL } from '../../modules/local/upset' include { BEDTOOLS_GETFASTA as FASTA_COMBINED } from '../../modules/nf-core/bedtools/getfasta' @@ -140,6 +141,16 @@ workflow BSJ_DETECTION { ch_versions = ch_versions.mix(CONCAT_SAMPLES.out.versions) ch_bsj_bed_combined = CONCAT_SAMPLES.out.sorted + // + // QUANTIFY BSJs PER TOOL + // + EXTRACT_COUNTS( ch_bsj_bed_per_sample_tool, [] ) + ch_versions = ch_versions.mix(EXTRACT_COUNTS.out.versions) + + EXTRACT_COUNTS.out.output.map{ meta, bed -> [[id: meta.tool], meta.id, bed]} + .groupTuple() + .view() + // // UPSET PLOTS // From 16695dae224ee87e7597883cee91dd69d11bfd38 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 8 Aug 2024 23:08:20 +0200 Subject: [PATCH 487/491] Implement per-tool count combination across samples --- conf/modules.config | 9 +++++++++ subworkflows/local/bsj_detection.nf | 8 +++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 68008694..1fc279cd 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -662,6 +662,15 @@ process { ] } + withName: 'COMBINE_COUNTS_PER_TOOL' { + ext.args = "-f 1 -t" + publishDir = [ + path: { "${params.outdir}/bsj_detection/tools/${meta.id}" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + withName: UPSET_SAMPLES { ext.when = { params.tools.split(',').length > 1 } publishDir = [ diff --git a/subworkflows/local/bsj_detection.nf b/subworkflows/local/bsj_detection.nf index f0e5187f..4eac9741 100644 --- a/subworkflows/local/bsj_detection.nf +++ b/subworkflows/local/bsj_detection.nf @@ -6,6 +6,7 @@ include { BEDTOOLS_GROUPBY as COUNT_TOOLS } from '../../modules/nf-co include { GAWK as FILTER_MIN_TOOLS } from '../../modules/nf-core/gawk' include { GNU_SORT as CONCAT_SAMPLES } from '../../modules/nf-core/gnu/sort' include { GAWK as EXTRACT_COUNTS } from '../../modules/nf-core/gawk' +include { CSVTK_JOIN as COMBINE_COUNTS_PER_TOOL } from '../../modules/nf-core/csvtk/join' include { UPSET as UPSET_SAMPLES } from '../../modules/local/upset' include { UPSET as UPSET_ALL } from '../../modules/local/upset' include { BEDTOOLS_GETFASTA as FASTA_COMBINED } from '../../modules/nf-core/bedtools/getfasta' @@ -147,9 +148,10 @@ workflow BSJ_DETECTION { EXTRACT_COUNTS( ch_bsj_bed_per_sample_tool, [] ) ch_versions = ch_versions.mix(EXTRACT_COUNTS.out.versions) - EXTRACT_COUNTS.out.output.map{ meta, bed -> [[id: meta.tool], meta.id, bed]} - .groupTuple() - .view() + COMBINE_COUNTS_PER_TOOL( EXTRACT_COUNTS.out.output + .map{ meta, bed -> [[id: meta.tool], bed]} + .groupTuple() ) + ch_versions = ch_versions.mix(COMBINE_COUNTS_PER_TOOL.out.versions) // // UPSET PLOTS From 38c2e495ef752637f6b4a6cd42a4a09c7bfc667f Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 8 Aug 2024 23:19:28 +0200 Subject: [PATCH 488/491] Restructure BSJ detection workflow --- subworkflows/local/bsj_detection.nf | 69 +++++++++++++++-------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/subworkflows/local/bsj_detection.nf b/subworkflows/local/bsj_detection.nf index 4eac9741..fdcb8027 100644 --- a/subworkflows/local/bsj_detection.nf +++ b/subworkflows/local/bsj_detection.nf @@ -45,7 +45,7 @@ workflow BSJ_DETECTION { main: ch_versions = Channel.empty() - ch_bed = Channel.empty() + ch_bsj_bed_per_sample_tool = Channel.empty() ch_multiqc_files = Channel.empty() fasta = ch_fasta.map{meta, fasta -> fasta} gtf = ch_gtf.map{meta, gtf -> gtf} @@ -68,59 +68,71 @@ workflow BSJ_DETECTION { if (tools_selected.contains('segemehl')) { SEGEMEHL( reads, fasta, params.segemehl ) - ch_versions = ch_versions.mix(SEGEMEHL.out.versions) - ch_bed = ch_bed .mix(SEGEMEHL.out.bed) + ch_versions = ch_versions.mix(SEGEMEHL.out.versions) + ch_bsj_bed_per_sample_tool = ch_bsj_bed_per_sample_tool.mix(SEGEMEHL.out.bed) } if (tools_selected.contains('circexplorer2')) { CIRCEXPLORER2( gtf, fasta, STAR2PASS.out.junction ) - ch_versions = ch_versions.mix(CIRCEXPLORER2.out.versions) - ch_bed = ch_bed .mix(CIRCEXPLORER2.out.bed) + ch_versions = ch_versions.mix(CIRCEXPLORER2.out.versions) + ch_bsj_bed_per_sample_tool = ch_bsj_bed_per_sample_tool.mix(CIRCEXPLORER2.out.bed) } if (tools_selected.contains('circrna_finder')) { CIRCRNA_FINDER( fasta, STAR2PASS.out.sam, STAR2PASS.out.junction, STAR2PASS.out.tab ) - ch_versions = ch_versions.mix(CIRCRNA_FINDER.out.versions) - ch_bed = ch_bed .mix(CIRCRNA_FINDER.out.bed) + ch_versions = ch_versions.mix(CIRCRNA_FINDER.out.versions) + ch_bsj_bed_per_sample_tool = ch_bsj_bed_per_sample_tool.mix(CIRCRNA_FINDER.out.bed) } if (tools_selected.contains('find_circ')) { FIND_CIRC( reads, bowtie2_index, ch_fasta ) - ch_versions = ch_versions.mix(FIND_CIRC.out.versions) - ch_bed = ch_bed .mix(FIND_CIRC.out.bed) + ch_versions = ch_versions.mix(FIND_CIRC.out.versions) + ch_bsj_bed_per_sample_tool = ch_bsj_bed_per_sample_tool.mix(FIND_CIRC.out.bed) } if (tools_selected.contains('ciriquant')) { CIRIQUANT( reads, ch_gtf, ch_fasta, bwa_index, hisat2_index ) - ch_versions = ch_versions.mix(CIRIQUANT.out.versions) - ch_bed = ch_bed .mix(CIRIQUANT.out.bed) + ch_versions = ch_versions.mix(CIRIQUANT.out.versions) + ch_bsj_bed_per_sample_tool = ch_bsj_bed_per_sample_tool.mix(CIRIQUANT.out.bed) } if (tools_selected.contains('dcc')) { DCC( reads, ch_fasta, ch_gtf, star_index, STAR2PASS.out.junction, star_ignore_sjdbgtf, seq_platform, seq_center, bsj_reads ) - ch_versions = ch_versions.mix(DCC.out.versions) - ch_bed = ch_bed .mix(DCC.out.bed) + ch_versions = ch_versions.mix(DCC.out.versions) + ch_bsj_bed_per_sample_tool = ch_bsj_bed_per_sample_tool.mix(DCC.out.bed) } if (tools_selected.contains('mapsplice')) { MAPSPLICE( reads, gtf, fasta, bowtie_index, chromosomes, STAR2PASS.out.junction ) - ch_versions = ch_versions.mix(MAPSPLICE.out.versions) - ch_bed = ch_bed .mix(MAPSPLICE.out.bed) + ch_versions = ch_versions.mix(MAPSPLICE.out.versions) + ch_bsj_bed_per_sample_tool = ch_bsj_bed_per_sample_tool.mix(MAPSPLICE.out.bed) } - ch_bed = FILTER_BSJS( ch_bed, [] ).output - ch_versions = ch_versions.mix(FILTER_BSJS.out.versions) + ch_bsj_bed_per_sample_tool = FILTER_BSJS( ch_bsj_bed_per_sample_tool, [] ).output + ch_versions = ch_versions.mix(FILTER_BSJS.out.versions) + + // + // QUANTIFY BSJs PER TOOL + // + + EXTRACT_COUNTS( ch_bsj_bed_per_sample_tool, [] ) + ch_versions = ch_versions.mix(EXTRACT_COUNTS.out.versions) + + COMBINE_COUNTS_PER_TOOL( EXTRACT_COUNTS.out.output + .map{ meta, bed -> [[id: meta.tool], bed]} + .groupTuple() ) + ch_versions = ch_versions.mix(COMBINE_COUNTS_PER_TOOL.out.versions) // // MERGE BED FILES // - MASK_SCORES( ch_bed, [] ) + MASK_SCORES( ch_bsj_bed_per_sample_tool, [] ) ch_versions = ch_versions.mix(MASK_SCORES.out.versions) - ch_bsj_bed_per_sample_tool = MASK_SCORES.out.output + ch_bsj_bed_per_sample_tool_masked = MASK_SCORES.out.output .filter{ meta, bed -> !bed.empty } CONCAT_TOOLS_PER_SAMPLE( @@ -142,29 +154,18 @@ workflow BSJ_DETECTION { ch_versions = ch_versions.mix(CONCAT_SAMPLES.out.versions) ch_bsj_bed_combined = CONCAT_SAMPLES.out.sorted - // - // QUANTIFY BSJs PER TOOL - // - EXTRACT_COUNTS( ch_bsj_bed_per_sample_tool, [] ) - ch_versions = ch_versions.mix(EXTRACT_COUNTS.out.versions) - - COMBINE_COUNTS_PER_TOOL( EXTRACT_COUNTS.out.output - .map{ meta, bed -> [[id: meta.tool], bed]} - .groupTuple() ) - ch_versions = ch_versions.mix(COMBINE_COUNTS_PER_TOOL.out.versions) - // // UPSET PLOTS // - UPSET_SAMPLES( ch_bsj_bed_per_sample_tool + UPSET_SAMPLES( ch_bsj_bed_per_sample_tool_masked .map{ meta, bed -> [meta.id, meta.tool, bed]} .groupTuple() .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) ch_multiqc_files = ch_multiqc_files.mix(UPSET_SAMPLES.out.multiqc) ch_versions = ch_versions.mix(UPSET_SAMPLES.out.versions) - UPSET_ALL( ch_bsj_bed_per_sample_tool + UPSET_ALL( ch_bsj_bed_per_sample_tool_masked .map{ meta, bed -> ["all", meta.tool, bed] } .groupTuple() .map{ sample, tools, beds -> [[id: sample], tools, beds]} ) @@ -185,7 +186,7 @@ workflow BSJ_DETECTION { ch_bsj_bed12_per_sample = ANNOTATE_PER_SAMPLE.out.bed ch_bsj_gtf_per_sample = ANNOTATE_PER_SAMPLE.out.gtf - ANNOTATE_PER_SAMPLE_TOOL( ch_bsj_bed_per_sample_tool, ch_gtf, exon_boundary, ch_annotation ) + ANNOTATE_PER_SAMPLE_TOOL( ch_bsj_bed_per_sample_tool_masked, ch_gtf, exon_boundary, ch_annotation ) ch_versions = ch_versions.mix(ANNOTATE_PER_SAMPLE_TOOL.out.versions) ch_bsj_bed12_per_sample_tool = ANNOTATE_PER_SAMPLE_TOOL.out.bed ch_bsj_gtf_per_sample_tool = ANNOTATE_PER_SAMPLE_TOOL.out.gtf @@ -202,7 +203,7 @@ workflow BSJ_DETECTION { ch_versions = ch_versions.mix(FASTA_PER_SAMPLE.out.versions) ch_bsj_fasta_per_sample = FASTA_PER_SAMPLE.out.fasta - FASTA_PER_SAMPLE_TOOL( ch_bsj_bed_per_sample_tool, fasta ) + FASTA_PER_SAMPLE_TOOL( ch_bsj_bed_per_sample_tool_masked, fasta ) ch_versions = ch_versions.mix(FASTA_PER_SAMPLE_TOOL.out.versions) ch_bsj_fasta_per_sample_tool = FASTA_PER_SAMPLE_TOOL.out.fasta From a1acac7b2557ed9514f589fdd32743d61f2696b3 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 8 Aug 2024 23:44:03 +0200 Subject: [PATCH 489/491] Update docs --- docs/output.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/output.md b/docs/output.md index f7016c8b..f60c28a0 100644 --- a/docs/output.md +++ b/docs/output.md @@ -154,6 +154,7 @@ The rough workflow for the BSJ detection looks like this: - `annotated`: Based on `masked`, but with additional columns for the circRNA type, the host gene(s), host transcript(s) and potential database hits. Contains a BED and a GTF file for each sample. - `fasta`: Extracted sequences of the circRNAs in FASTA format. Based on `masked`. - `intermediates`: Contains intermediate files generated by the BSJ detection tools, as explained below. +- `${tool}.csv`: Number of reads that the tool found supporting the BSJ.
    From d0f7cfeed6e86c3f6a76cc5e53b46605c8777cb5 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 8 Aug 2024 23:56:24 +0200 Subject: [PATCH 490/491] Perform outer join on counts --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 1fc279cd..b23ea157 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -663,7 +663,7 @@ process { } withName: 'COMBINE_COUNTS_PER_TOOL' { - ext.args = "-f 1 -t" + ext.args = "-f 1 -t -O" publishDir = [ path: { "${params.outdir}/bsj_detection/tools/${meta.id}" }, mode: params.publish_dir_mode, From 7ac747efcd42c0c0e9df9c53b0d975e78aa4e2f1 Mon Sep 17 00:00:00 2001 From: Nico Trummer Date: Thu, 8 Aug 2024 23:56:45 +0200 Subject: [PATCH 491/491] Imporve BSJ_DETECTION order --- subworkflows/local/bsj_detection.nf | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/subworkflows/local/bsj_detection.nf b/subworkflows/local/bsj_detection.nf index fdcb8027..89ddec4e 100644 --- a/subworkflows/local/bsj_detection.nf +++ b/subworkflows/local/bsj_detection.nf @@ -111,9 +111,6 @@ workflow BSJ_DETECTION { ch_bsj_bed_per_sample_tool = ch_bsj_bed_per_sample_tool.mix(MAPSPLICE.out.bed) } - ch_bsj_bed_per_sample_tool = FILTER_BSJS( ch_bsj_bed_per_sample_tool, [] ).output - ch_versions = ch_versions.mix(FILTER_BSJS.out.versions) - // // QUANTIFY BSJs PER TOOL // @@ -126,11 +123,19 @@ workflow BSJ_DETECTION { .groupTuple() ) ch_versions = ch_versions.mix(COMBINE_COUNTS_PER_TOOL.out.versions) + // + // APPLY bsj_reads FILTER + // + + ch_bsj_bed_per_sample_tool_filtered = FILTER_BSJS( ch_bsj_bed_per_sample_tool, [] ).output + ch_versions = ch_versions.mix(FILTER_BSJS.out.versions) + + // // MERGE BED FILES // - MASK_SCORES( ch_bsj_bed_per_sample_tool, [] ) + MASK_SCORES( ch_bsj_bed_per_sample_tool_filtered, [] ) ch_versions = ch_versions.mix(MASK_SCORES.out.versions) ch_bsj_bed_per_sample_tool_masked = MASK_SCORES.out.output .filter{ meta, bed -> !bed.empty }
    Process Name \\", + " \\ Software Version
    CUSTOM_DUMPSOFTWAREVERSIONSpython3.11.7
    yaml5.4.1
    TOOL1tool10.11.9
    TOOL2tool21.9
    WorkflowNextflow
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls
    File typeConventional base calls