From 858d41563dd5a26a19f3327f245d4c5034af4fc6 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Tue, 8 Oct 2024 12:31:41 +0000 Subject: [PATCH 01/70] Template update for nf-core/tools version 3.0.0 --- .editorconfig | 4 + .github/CONTRIBUTING.md | 10 +- .github/PULL_REQUEST_TEMPLATE.md | 2 +- .github/workflows/awsfulltest.yml | 23 +- .github/workflows/ci.yml | 17 +- .github/workflows/download_pipeline.yml | 53 ++- .github/workflows/linting.yml | 23 +- .github/workflows/linting_comment.yml | 2 +- .github/workflows/release-announcements.yml | 2 +- .../workflows/template_version_comment.yml | 43 ++ .gitpod.yml | 7 +- .nf-core.yml | 20 +- .pre-commit-config.yaml | 2 +- .prettierignore | 1 + CHANGELOG.md | 2 +- CITATIONS.md | 4 +- README.md | 5 +- assets/multiqc_config.yml | 6 +- assets/schema_input.json | 2 +- conf/base.config | 34 +- conf/igenomes_ignored.config | 9 + conf/modules.config | 1 - conf/test.config | 13 +- docs/images/mqc_fastqc_adapter.png | Bin 23458 -> 0 bytes docs/images/mqc_fastqc_counts.png | Bin 33918 -> 0 bytes docs/images/mqc_fastqc_quality.png | Bin 55769 -> 0 bytes docs/output.md | 11 +- docs/usage.md | 12 +- main.nf | 10 +- modules.json | 12 +- modules/nf-core/fastqc/environment.yml | 2 - modules/nf-core/fastqc/main.nf | 5 +- modules/nf-core/fastqc/meta.yml | 57 +-- modules/nf-core/fastqc/tests/main.nf.test | 225 ++++++++--- .../nf-core/fastqc/tests/main.nf.test.snap | 370 ++++++++++++++++-- modules/nf-core/multiqc/environment.yml | 4 +- modules/nf-core/multiqc/main.nf | 14 +- modules/nf-core/multiqc/meta.yml | 78 ++-- modules/nf-core/multiqc/tests/main.nf.test | 8 + .../nf-core/multiqc/tests/main.nf.test.snap | 20 +- modules/nf-core/multiqc/tests/nextflow.config | 5 + nextflow.config | 148 ++++--- nextflow_schema.json | 85 +--- .../utils_nfcore_pixelator_pipeline/main.nf | 56 +-- .../nf-core/utils_nextflow_pipeline/main.nf | 24 +- .../tests/nextflow.config | 2 +- .../nf-core/utils_nfcore_pipeline/main.nf | 45 ++- .../nf-core/utils_nfschema_plugin/main.nf | 46 +++ .../nf-core/utils_nfschema_plugin/meta.yml | 35 ++ .../utils_nfschema_plugin/tests/main.nf.test | 117 ++++++ .../tests/nextflow.config | 8 + .../tests/nextflow_schema.json | 8 +- .../nf-core/utils_nfvalidation_plugin/main.nf | 62 --- .../utils_nfvalidation_plugin/meta.yml | 44 --- .../tests/main.nf.test | 200 ---------- .../utils_nfvalidation_plugin/tests/tags.yml | 2 - workflows/pixelator.nf | 23 +- 57 files changed, 1211 insertions(+), 812 deletions(-) create mode 100644 .github/workflows/template_version_comment.yml create mode 100644 conf/igenomes_ignored.config delete mode 100755 docs/images/mqc_fastqc_adapter.png delete mode 100755 docs/images/mqc_fastqc_counts.png delete mode 100755 docs/images/mqc_fastqc_quality.png create mode 100644 modules/nf-core/multiqc/tests/nextflow.config create mode 100644 subworkflows/nf-core/utils_nfschema_plugin/main.nf create mode 100644 subworkflows/nf-core/utils_nfschema_plugin/meta.yml create mode 100644 subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test create mode 100644 subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config rename subworkflows/nf-core/{utils_nfvalidation_plugin => utils_nfschema_plugin}/tests/nextflow_schema.json (95%) delete mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/main.nf delete mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/meta.yml delete mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test delete mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml diff --git a/.editorconfig b/.editorconfig index 72dda289..e1058815 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,7 @@ indent_style = space [*.{md,yml,yaml,html,css,scss,js}] indent_size = 2 + # These files are edited and tested upstream in nf-core/modules [/modules/nf-core/**] charset = unset @@ -25,9 +26,12 @@ insert_final_newline = unset trim_trailing_whitespace = unset indent_style = unset + + [/assets/email*] indent_size = unset + # ignore python and markdown [*.{py,md}] indent_style = unset diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 3542d8d5..a61a2a48 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -19,7 +19,7 @@ If you'd like to write some code for nf-core/pixelator, the standard workflow is 1. Check that there isn't already an issue about your idea in the [nf-core/pixelator issues](https://github.com/nf-core/pixelator/issues) to avoid duplicating work. If there isn't one already, please create one so that others know you're working on this 2. [Fork](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) the [nf-core/pixelator repository](https://github.com/nf-core/pixelator) to your GitHub account 3. Make the necessary changes / additions within your forked repository following [Pipeline conventions](#pipeline-contribution-conventions) -4. Use `nf-core schema build` and add any new parameters to the pipeline JSON schema (requires [nf-core tools](https://github.com/nf-core/tools) >= 1.10). +4. Use `nf-core pipelines schema build` and add any new parameters to the pipeline JSON schema (requires [nf-core tools](https://github.com/nf-core/tools) >= 1.10). 5. Submit a Pull Request against the `dev` branch and wait for the code to be reviewed and merged If you're not used to this workflow with git, you can start with some [docs from GitHub](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests) or even their [excellent `git` resources](https://try.github.io/). @@ -40,7 +40,7 @@ There are typically two types of tests that run: ### Lint tests `nf-core` has a [set of guidelines](https://nf-co.re/developers/guidelines) which all pipelines must adhere to. -To enforce these and ensure that all pipelines stay in sync, we have developed a helper tool which runs checks on the pipeline code. This is in the [nf-core/tools repository](https://github.com/nf-core/tools) and once installed can be run locally with the `nf-core lint ` command. +To enforce these and ensure that all pipelines stay in sync, we have developed a helper tool which runs checks on the pipeline code. This is in the [nf-core/tools repository](https://github.com/nf-core/tools) and once installed can be run locally with the `nf-core pipelines lint ` command. If any failures or warnings are encountered, please follow the listed URL for more documentation. @@ -75,7 +75,7 @@ If you wish to contribute a new step, please use the following coding standards: 2. Write the process block (see below). 3. Define the output channel if needed (see below). 4. Add any new parameters to `nextflow.config` with a default (see below). -5. Add any new parameters to `nextflow_schema.json` with help text (via the `nf-core schema build` tool). +5. Add any new parameters to `nextflow_schema.json` with help text (via the `nf-core pipelines schema build` tool). 6. Add sanity checks and validation for all relevant parameters. 7. Perform local tests to validate that the new code works as expected. 8. If applicable, add a new test command in `.github/workflow/ci.yml`. @@ -86,7 +86,7 @@ If you wish to contribute a new step, please use the following coding standards: Parameters should be initialised / defined with default values in `nextflow.config` under the `params` scope. -Once there, use `nf-core schema build` to add to `nextflow_schema.json`. +Once there, use `nf-core pipelines schema build` to add to `nextflow_schema.json`. ### Default processes resource requirements @@ -103,7 +103,7 @@ Please use the following naming schemes, to make it easy to understand what is g ### Nextflow version bumping -If you are using a new feature from core Nextflow, you may bump the minimum required version of nextflow in the pipeline with: `nf-core bump-version --nextflow . [min-nf-version]` +If you are using a new feature from core Nextflow, you may bump the minimum required version of nextflow in the pipeline with: `nf-core pipelines bump-version --nextflow . [min-nf-version]` ### Images and figures diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9d93ee87..3e33e429 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -17,7 +17,7 @@ Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/pixe - [ ] 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/pixelator/tree/master/.github/CONTRIBUTING.md) - [ ] If necessary, also make a PR on the nf-core/pixelator _branch_ on the [nf-core/test-datasets](https://github.com/nf-core/test-datasets) repository. -- [ ] Make sure your code lints (`nf-core lint`). +- [ ] Make sure your code lints (`nf-core pipelines lint`). - [ ] 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. diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index bd9c15db..5980d4d7 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -1,18 +1,33 @@ name: nf-core AWS full size tests -# This workflow is triggered on published releases. +# This workflow is triggered on PRs opened against the master branch. # It can be additionally triggered manually with GitHub actions workflow dispatch button. # It runs the -profile 'test_full' on AWS batch on: - release: - types: [published] + pull_request: + branches: + - master workflow_dispatch: + pull_request_review: + types: [submitted] + jobs: run-platform: name: Run AWS full tests - if: github.repository == 'nf-core/pixelator' + if: github.repository == 'nf-core/pixelator' && github.event.review.state == 'approved' runs-on: ubuntu-latest steps: + - uses: octokit/request-action@v2.x + id: check_approvals + with: + route: GET /repos/${{ github.repository }}/pulls/${{ github.event.review.number }}/reviews + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - id: test_variables + run: | + JSON_RESPONSE='${{ steps.check_approvals.outputs.data }}' + CURRENT_APPROVALS_COUNT=$(echo $JSON_RESPONSE | jq -c '[.[] | select(.state | contains("APPROVED")) ] | length') + test $CURRENT_APPROVALS_COUNT -ge 2 || exit 1 # At least 2 approvals are required - name: Launch workflow via Seqera Platform uses: seqeralabs/action-tower-launch@v2 # TODO nf-core: You can customise AWS full pipeline tests as required diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7db22d2..232946a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,7 @@ on: pull_request: release: types: [published] + workflow_dispatch: env: NXF_ANSI_LOG: false @@ -24,7 +25,7 @@ jobs: strategy: matrix: NXF_VER: - - "23.04.0" + - "24.04.2" - "latest-everything" steps: - name: Check out pipeline code @@ -38,9 +39,21 @@ jobs: - name: Disk space cleanup uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 - - name: Run pipeline with test data + - name: Run pipeline with test data (docker) # 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: | nextflow run ${GITHUB_WORKSPACE} -profile test,docker --outdir ./results + + - name: Run pipeline with test data (singularity) + # TODO nf-core: You can customise CI pipeline run tests as required + run: | + nextflow run ${GITHUB_WORKSPACE} -profile test,singularity --outdir ./results + if: "${{ github.base_ref == 'master' }}" + + - name: Run pipeline with test data (conda) + # TODO nf-core: You can customise CI pipeline run tests as required + run: | + nextflow run ${GITHUB_WORKSPACE} -profile test,conda --outdir ./results + if: "${{ github.base_ref == 'master' }}" diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml index 2d20d644..713dc3e7 100644 --- a/.github/workflows/download_pipeline.yml +++ b/.github/workflows/download_pipeline.yml @@ -1,4 +1,4 @@ -name: Test successful pipeline download with 'nf-core download' +name: Test successful pipeline download with 'nf-core pipelines download' # Run the workflow when: # - dispatched manually @@ -8,7 +8,7 @@ on: workflow_dispatch: inputs: testbranch: - description: "The specific branch you wish to utilize for the test execution of nf-core download." + description: "The specific branch you wish to utilize for the test execution of nf-core pipelines download." required: true default: "dev" pull_request: @@ -39,9 +39,11 @@ jobs: with: python-version: "3.12" architecture: "x64" - - uses: eWaterCycle/setup-singularity@931d4e31109e875b13309ae1d07c70ca8fbc8537 # v7 + + - name: Setup Apptainer + uses: eWaterCycle/setup-apptainer@4bb22c52d4f63406c49e94c804632975787312b3 # v2.0.0 with: - singularity-version: 3.8.3 + apptainer-version: 1.3.4 - name: Install dependencies run: | @@ -54,33 +56,64 @@ jobs: echo "REPOTITLE_LOWERCASE=$(basename ${GITHUB_REPOSITORY,,})" >> ${GITHUB_ENV} echo "REPO_BRANCH=${{ github.event.inputs.testbranch || 'dev' }}" >> ${GITHUB_ENV} + - name: Make a cache directory for the container images + run: | + mkdir -p ./singularity_container_images + - name: Download the pipeline env: - NXF_SINGULARITY_CACHEDIR: ./ + NXF_SINGULARITY_CACHEDIR: ./singularity_container_images run: | - nf-core download ${{ env.REPO_LOWERCASE }} \ + nf-core pipelines 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-library "quay.io" -l "docker.io" -l "community.wave.seqera.io" \ --container-cache-utilisation 'amend' \ - --download-configuration + --download-configuration 'yes' - name: Inspect download run: tree ./${{ env.REPOTITLE_LOWERCASE }} + - name: Count the downloaded number of container images + id: count_initial + run: | + image_count=$(ls -1 ./singularity_container_images | wc -l | xargs) + echo "Initial container image count: $image_count" + echo "IMAGE_COUNT_INITIAL=$image_count" >> ${GITHUB_ENV} + - name: Run the downloaded pipeline (stub) id: stub_run_pipeline continue-on-error: true env: - NXF_SINGULARITY_CACHEDIR: ./ + NXF_SINGULARITY_CACHEDIR: ./singularity_container_images 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_CACHEDIR: ./singularity_container_images NXF_SINGULARITY_HOME_MOUNT: true run: nextflow run ./${{ env.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ env.REPO_BRANCH }}) -profile test,singularity --outdir ./results + + - name: Count the downloaded number of container images + id: count_afterwards + run: | + image_count=$(ls -1 ./singularity_container_images | wc -l | xargs) + echo "Post-pipeline run container image count: $image_count" + echo "IMAGE_COUNT_AFTER=$image_count" >> ${GITHUB_ENV} + + - name: Compare container image counts + run: | + if [ "${{ env.IMAGE_COUNT_INITIAL }}" -ne "${{ env.IMAGE_COUNT_AFTER }}" ]; then + initial_count=${{ env.IMAGE_COUNT_INITIAL }} + final_count=${{ env.IMAGE_COUNT_AFTER }} + difference=$((final_count - initial_count)) + echo "$difference additional container images were \n downloaded at runtime . The pipeline has no support for offline runs!" + tree ./singularity_container_images + exit 1 + else + echo "The pipeline can be downloaded successfully!" + fi diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 1fcafe88..b882838a 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -1,6 +1,6 @@ name: nf-core linting # This workflow is triggered on pushes and PRs to the repository. -# It runs the `nf-core lint` and markdown lint tests to ensure +# It runs the `nf-core pipelines lint` and markdown lint tests to ensure # that the code meets the nf-core guidelines. on: push: @@ -41,17 +41,32 @@ jobs: python-version: "3.12" architecture: "x64" + - name: read .nf-core.yml + uses: pietrobolcato/action-read-yaml@1.0.0 + id: read_yml + with: + config: ${{ github.workspace }}/.nf-core.yaml + - name: Install dependencies run: | python -m pip install --upgrade pip - pip install nf-core + pip install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} + + - name: Run nf-core pipelines lint + if: ${{ github.base_ref != 'master' }} + env: + GITHUB_COMMENTS_URL: ${{ github.event.pull_request.comments_url }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_PR_COMMIT: ${{ github.event.pull_request.head.sha }} + run: nf-core -l lint_log.txt pipelines lint --dir ${GITHUB_WORKSPACE} --markdown lint_results.md - - name: Run nf-core lint + - name: Run nf-core pipelines lint --release + if: ${{ github.base_ref == 'master' }} env: GITHUB_COMMENTS_URL: ${{ github.event.pull_request.comments_url }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_PR_COMMIT: ${{ github.event.pull_request.head.sha }} - run: nf-core -l lint_log.txt lint --dir ${GITHUB_WORKSPACE} --markdown lint_results.md + run: nf-core -l lint_log.txt pipelines lint --release --dir ${GITHUB_WORKSPACE} --markdown lint_results.md - name: Save PR number if: ${{ always() }} diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index 40acc23f..42e519bf 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@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3 + uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6 with: workflow: linting.yml workflow_conclusion: completed diff --git a/.github/workflows/release-announcements.yml b/.github/workflows/release-announcements.yml index 03ecfcf7..c6ba35df 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: | - 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 + 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' ' ')" | sed 's/-//g' >> $GITHUB_OUTPUT - uses: rzr/fediverse-action@master with: diff --git a/.github/workflows/template_version_comment.yml b/.github/workflows/template_version_comment.yml new file mode 100644 index 00000000..9dea41f0 --- /dev/null +++ b/.github/workflows/template_version_comment.yml @@ -0,0 +1,43 @@ +name: nf-core template version comment +# This workflow is triggered on PRs to check if the pipeline template version matches the latest nf-core version. +# It posts a comment to the PR, even if it comes from a fork. + +on: pull_request_target + +jobs: + template_version: + runs-on: ubuntu-latest + steps: + - name: Check out pipeline code + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 + + - name: Read template version from .nf-core.yml + uses: pietrobolcato/action-read-yaml@1.0.0 + id: read_yml + with: + config: ${{ github.workspace }}/.nf-core.yml + + - name: Install nf-core + run: | + python -m pip install --upgrade pip + pip install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} + + - name: Check nf-core outdated + id: nf_core_outdated + run: pip list --outdated | grep nf-core + + - name: Post nf-core template version comment + uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 + if: | + ${{ steps.nf_core_outdated.outputs.stdout }} =~ 'nf-core' + with: + repo-token: ${{ secrets.NF_CORE_BOT_AUTH_TOKEN }} + allow-repeats: false + message: | + ## :warning: Newer version of the nf-core template is available. + + Your pipeline is using an old version of the nf-core template: ${{ steps.read_yml.outputs['nf_core_version'] }}. + Please update your pipeline to the latest version. + + For more documentation on how to update your pipeline, please see the [nf-core documentation](https://github.com/nf-core/tools?tab=readme-ov-file#sync-a-pipeline-with-the-template) and [Synchronisation documentation](https://nf-co.re/docs/contributing/sync). + # diff --git a/.gitpod.yml b/.gitpod.yml index 105a1821..46118637 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -4,17 +4,14 @@ tasks: command: | pre-commit install --install-hooks nextflow self-update - - name: unset JAVA_TOOL_OPTIONS - command: | - unset JAVA_TOOL_OPTIONS vscode: extensions: # based on nf-core.nf-core-extensionpack - - esbenp.prettier-vscode # Markdown/CommonMark linting and style checking for Visual Studio Code + #- esbenp.prettier-vscode # Markdown/CommonMark linting and style checking for Visual Studio Code - 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/.nf-core.yml b/.nf-core.yml index e0b85a77..3faeceae 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -1,2 +1,20 @@ +bump_version: null +lint: + files_exist: + - assets/multiqc_config.yml + - conf/igenomes.config + multiqc_config: false +nf_core_version: 3.0.0 +org_path: null repository_type: pipeline -nf_core_version: "2.14.1" +template: + author: Pixelgen Technologies AB + description: Pipeline for analysis of Molecular Pixelation assays + force: false + is_nfcore: true + name: pixelator + org: nf-core + outdir: . + skip_features: null + version: 1.3.1 +update: null diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4dc0f1dc..9e9f0e1c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: - prettier@3.2.5 - repo: https://github.com/editorconfig-checker/editorconfig-checker.python - rev: "2.7.3" + rev: "3.0.3" hooks: - id: editorconfig-checker alias: ec diff --git a/.prettierignore b/.prettierignore index 437d763d..610e5069 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,4 @@ + email_template.html adaptivecard.json slackreport.json diff --git a/CHANGELOG.md b/CHANGELOG.md index f7f10319..d577935c 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.1.0 - [date] +## v1.3.1 - [date] Initial release of nf-core/pixelator, created with the [nf-core](https://nf-co.re/) template. diff --git a/CITATIONS.md b/CITATIONS.md index ca3444ff..d2fcc108 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -12,11 +12,11 @@ - [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) - > Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. +> Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. - [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. +> 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 diff --git a/README.md b/README.md index fdbb131a..ed807c37 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![GitHub Actions Linting Status](https://github.com/nf-core/pixelator/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/pixelator/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/pixelator/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/) +[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A524.04.2-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/) @@ -67,8 +67,7 @@ nextflow run nf-core/pixelator \ ``` > [!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). +> 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/docs/usage/getting_started/configuration#custom-configuration-files). For more details and further functionality, please refer to the [usage documentation](https://nf-co.re/pixelator/usage) and the [parameter documentation](https://nf-co.re/pixelator/parameters). diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index a67694de..adefdf6c 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/pixelator + This report has been generated by the nf-core/pixelator analysis pipeline. For information about how to interpret these results, please see the - documentation. - + documentation. report_section_order: "nf-core-pixelator-methods-description": order: -1000 diff --git a/assets/schema_input.json b/assets/schema_input.json index 0b6b7dd1..148fd766 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-07/schema", + "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/nf-core/pixelator/master/assets/schema_input.json", "title": "nf-core/pixelator pipeline - params.input schema", "description": "Schema for the file provided with params.input", diff --git a/conf/base.config b/conf/base.config index 4d00103e..11eeb9e5 100644 --- a/conf/base.config +++ b/conf/base.config @@ -11,9 +11,9 @@ process { // TODO nf-core: Check the defaults for all processes - cpus = { check_max( 1 * task.attempt, 'cpus' ) } - memory = { check_max( 6.GB * task.attempt, 'memory' ) } - time = { check_max( 4.h * task.attempt, 'time' ) } + cpus = { 1 * task.attempt } + memory = { 6.GB * task.attempt } + time = { 4.h * task.attempt } errorStrategy = { task.exitStatus in ((130..145) + 104) ? 'retry' : 'finish' } maxRetries = 1 @@ -27,30 +27,30 @@ process { // TODO nf-core: Customise requirements for specific processes. // See https://www.nextflow.io/docs/latest/config.html#config-process-selectors withLabel:process_single { - cpus = { check_max( 1 , 'cpus' ) } - memory = { check_max( 6.GB * task.attempt, 'memory' ) } - time = { check_max( 4.h * task.attempt, 'time' ) } + cpus = { 1 } + memory = { 6.GB * task.attempt } + time = { 4.h * task.attempt } } withLabel:process_low { - cpus = { check_max( 2 * task.attempt, 'cpus' ) } - memory = { check_max( 12.GB * task.attempt, 'memory' ) } - time = { check_max( 4.h * task.attempt, 'time' ) } + cpus = { 2 * task.attempt } + memory = { 12.GB * task.attempt } + time = { 4.h * task.attempt } } withLabel:process_medium { - cpus = { check_max( 6 * task.attempt, 'cpus' ) } - memory = { check_max( 36.GB * task.attempt, 'memory' ) } - time = { check_max( 8.h * task.attempt, 'time' ) } + cpus = { 6 * task.attempt } + memory = { 36.GB * task.attempt } + time = { 8.h * task.attempt } } withLabel:process_high { - cpus = { check_max( 12 * task.attempt, 'cpus' ) } - memory = { check_max( 72.GB * task.attempt, 'memory' ) } - time = { check_max( 16.h * task.attempt, 'time' ) } + cpus = { 12 * task.attempt } + memory = { 72.GB * task.attempt } + time = { 16.h * task.attempt } } withLabel:process_long { - time = { check_max( 20.h * task.attempt, 'time' ) } + time = { 20.h * task.attempt } } withLabel:process_high_memory { - memory = { check_max( 200.GB * task.attempt, 'memory' ) } + memory = { 200.GB * task.attempt } } withLabel:error_ignore { errorStrategy = 'ignore' diff --git a/conf/igenomes_ignored.config b/conf/igenomes_ignored.config new file mode 100644 index 00000000..b4034d82 --- /dev/null +++ b/conf/igenomes_ignored.config @@ -0,0 +1,9 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for iGenomes paths +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Empty genomes dictionary to use when igenomes is ignored. +---------------------------------------------------------------------------------------- +*/ + +params.genomes = [:] diff --git a/conf/modules.config b/conf/modules.config index d203d2b6..d266a387 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -21,7 +21,6 @@ process { withName: FASTQC { ext.args = '--quiet' } - withName: 'MULTIQC' { ext.args = { params.multiqc_title ? "--title \"$params.multiqc_title\"" : '' } publishDir = [ diff --git a/conf/test.config b/conf/test.config index 8f96a616..e2f55d9a 100644 --- a/conf/test.config +++ b/conf/test.config @@ -10,15 +10,18 @@ ---------------------------------------------------------------------------------------- */ +process { + resourceLimits = [ + cpus: 4, + memory: '15.GB', + time: '1.h' + ] +} + 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' - // 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 diff --git a/docs/images/mqc_fastqc_adapter.png b/docs/images/mqc_fastqc_adapter.png deleted file mode 100755 index 361d0e47acfb424dea1f326590d1eb2f6dfa26b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23458 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 diff --git a/docs/images/mqc_fastqc_quality.png b/docs/images/mqc_fastqc_quality.png deleted file mode 100755 index a4b89bf56ab2ba88cab87841916eb680a816deae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55769 zcmeFZRal$t)-Fn+z*nS{Vx>rm6qiDAOL2F1cMtAuDNvx0;#Q!zyE_zjcbDMqmSlzR zn{)pEI@tSUUwdu2)&Y>bJb7fuJ?=5a1EER^lGqq;F_4guu%)HMRFIHRN0E?_z5hZ+ zJaJ}X&O!Wm=At4gf>b&}x`%l4+)`Lx7zwEYjQMDcig^FRNlM!V3F)=#)7P^V3xFpQ z(!7JTn6R3s!6EcTteK|QPPjx@DDOv5T2*CXB}Z%z@|SP-DsObzPh`FaVcdV&m0)j; zcZ>LN@}*RhsyUw6to^1IV&KrBgSL*D84<+V=b92tLUGmkCzrla{Dr!*h^X~IGAQjM zyD9lfz=>mTe@ql{QdCq_QdAt=(BA&2YBUsY=dfzD{{p(Xxaz)h;YCF8?Ul%1e}5}@ zO@0yZuh)nND%kn8|Na%lH#NLM=KqYOnC|MbCw}whr}=*yP7H-Y`-r9qwQ2rq9Dz|0 zBdN65Kl4A$DgS>m=QkV7|7=EzGh^Yu&HaDh$NCi3wnS$c$@$FVUp#HFss7?l0LJ~{ z!`SL7tNPPP=8^Kq8)3(i@(qbit!IaRj$Duu3h(VXaI4Sdu3~_@H&ak|A1shtFJP;$ z&Ff|ziaT$FS{aiU@Te#m;Cp!+I*IbJ@XxAqIeeeH<$>FQ&-YdyTH@a_&X?%>7*prF zp2!e%;=M(CLssc(k6U1h(+Z6N7fk4b1$pU zx+k}@k}uu*?&UWT+g}Y#gV?3_XQkIe!hs%Suq9Q))|Tlh`Wr-J#)v6)bNt9IQZ-?zd%Hw*=ZrCzD^f-D3r^0KBi$+ip$`A6Mk<3rtrZFNxAf zKk90T99Gb#t7ndaGJ(*jcpaOR-2zFV|0MH`0H4>cX|8kH-A>yB@PzO5QPgAAeG<9~ z(7IdVikhJ^RFhx&6*~Cd*30U>;FKs>ES%nYuI$%8RM=1({ChUX}X7!Wu zAA=&In$O5ezi+pM8LtJ8`oW`oa28+E!&*f>9{W97;k4XXkIS^H4+UAGvZx7D{UOIK zH$}ZEkpj2NC%)GxA>My-R{)`xdTyO1fcg{J)!T^@lJhkw=vrQzj&$^Qa(I7Cu2xl- zg5af(2k=sEQGeBmBNF1c9B_MFCIG7eR|`T^)>Jws({-d$>S9rNoIs$o1qKW1U(s7gPai5(qrX(&Um zwy;AI@AZ}{%d9#&PBP>zwc8=%jgWWGH2jQp`DWYPw4k^T`^Nvelzg_m4tOygvshAx zSic)*_56B2$iwR{sdtKA-$NW8Cffewvz4#abf1JwCg*y2X*Lu~6edkmydt&um&!Yh;0Fgz!I z8S zXW#cIlDgIR7Kgd*mV>IL1+VdR*KujmVe6Bnrwi2`nyj5h(N`umHB#h26X zt}BBFa)TAfq5C^R?mPC5nk4!GljuO$+PG#|*B4a_2>^!?m-qb{I`I10^!40&Ah?Xo z5pt;rAZdrM_}>Q86li@(J8)D#f?(9Br`@U}FA1>Jx%%}~}bmH|q8K|Y!jaNAu?dYM~6 zRZJc^eBV;Y!Mnx?kn&2<<#2q|Pp)+P>ZBPmqA2KkX?Et2s&9LqBzZimIWVsmGYatA zRXt~RY=fjB;A5x~rSrZ2e#S!_7>vCGqC{9lj*|V8LTb}g!H@mpp{+Rn_v>x&(6H+J z7}nKf@B4Ld%Z-a7|M0=og<;D>XSx@Y&lV$4Ekin}o2SXK^<>^M{r+%K-I&?XE$nJSn(xJK4qrH|bnqfPU>4jm=e=x!oc#?Jke&g(g- zUucQtw<$SVY?d~P}!t-c2Lo8mx6d`@70 zvP5TBSUX%%C7-WOwciMN4WbKqP5B%ow3f{Z-jx6kgNKYV|^tpbL^<*qZ-A^30n?FBY*Hn_q~jp%0Mg-<>UCF!!;rL{!Y{b z*3Cv>f1?;licgf`G`bG-zLl-3R|wc#Q538g0z$S#C86oCbHSjNy?ANChiOIVH2rMI zG5nGlT3Axtm$CYA3AoOV^jpuMy|ROZ?T(T^1UI_*!$t2I@DM>^@!2%tQ*2Px;zGGh z02fo5-BK-N3cz|cST76mXYkO_egPK}#MwY7cUixalk{5k7n=LGIBj3hTJKhyeXzl~ zGo3fkBcT7$3Q6oSx65M@pbZ+YC;(b=HY>1%!!mZp6Fqznq0rpI#0pXZU|dVnIlk9-%u>~`h}VhYjz zmPod{6t5ndj-zKD=!WOo(!>9dq!*2ld8_8dca!LG1x9m|yPCUXkoxbbV)V`B^QlP* z2QLUMxOI2m3%(x6c>7K);Oa-%C(!K#N~N9Ef%3qRq9J)~x4KpV>itdW?%7A43LDIa z8X^^jrZk!ojDyDSMXww70zLApJntoe%=xcBD#D>RDy64nfaU_M6Z)d7V4v3O7+UfM zI23&xL2-PqOi$oj<6nQBorePGYWBHH+x}3PF;m>1({p~`Te}(*tYP8JcKw|ZaIa3W z5|KeaW+a1}*~V9jOh9(L$~YKYYcNd}*`l$FOU6yA(HR-(cSZ&9*~&v1R}oErionDF zkmE|SIb~(H=VJ$DZ4b&-CQ)fO@a_a4)*zSnmv493+6k&S(%z0p_QJ>psX^O_V9lhrb>BAr9 z#!w93wGILaXkvaRP39@H;n)|GB8ih{1e-l>kB{FBn1qGHL%+#NzbvY3$Xf&5Ir5z2 zPG9!I*3-qPiSN%$8O#PHBV)1VD}P1)O~7Dhj2?72@pBcduzphsN8H)`k=p3Wh%;_$ zOeXLMp7o@Qaw@rwstN}`?{)X08s5C`DQlRw*eDrX7{@P}7d8#NUz6uvKJSkcQF?Ne z6pViyWiT|=e=Doa?LjcWpUG)555Bnx)chgcgWJ97&2EQZf!xal z)p2nI02nbGF^RF>u>$hlk&33=WQ-^JoI>Si0u8 zV07Zbz#>r^qAXD{lBu!00RKml^p=Cv64=~UMF`M+kogAK za9tvbFb_5Czmu~*!Wcf7X4}nlOhFn>z@2UYs5e8zXiDYQ=Ox))S3>&zy2o(u2h5!JvYvSsLq$lAJ%%c;J%Lb@e5mEkCW z?eZ|Dux0i&Si?wGLD+e^#G`KKbCx{u6gsr?6jUM?pE*3wAGiPuHc1MIvY4|WVosn|)%172v_ zuJ9qyLTdW=-$|n#8!G@V$$7Z3oifYzxs!m`vv;S}RV*&e|L#YrvkJalcR(jP&|ivp zdX?VXKmoSP&tSH<4&P*Xc=vJz77}8-1B8!d0cW#BxWLd8o=iJfUfU`0+(QVsx$4{8 zM%dD+!cq1`U^-K(q~!|)T~eLAZia5FB+I+)`mCM=ATeKEa>FyeeU0P0N(2$?H5_a% z1c?1K;t}s!d86fx%Dsml&FIN>)%>u!tJSay-_BD*KV3b8rOY0MRDF}8&W3rMO8Cvd zq4No{`UQOiAyeW&=;8TZg&{D6<%2^Z z!|qE6iY8+BPguq9y#O>n~H+h-giBAsF%%~f&;2z zHSJ9+elB|j$&@GebI=dtreMMQ&ghri{%!G?7SS%=%2G0KqHH#RkD(za3ny=Hi$(=p zLGvS3B|d!WGOoC}J8#If=~Y0uQMxBB0Dao47Ri8W79ysyRyY66Fcmx+Tm-DB zhy25cx=95+#qc?ToUlOnSSf2{HM2o=*VzYQSjU+-RrVoQq-g{FF4Zg zE~D2d*8doXY~?Q)$%+d%R^R5T*Ja|j(efj$qMbfNU$|`D4f(?#^kdi{t)k*vJRUdL zlxcwb4m#}66CTp`2n9CPSQhv#x;!Mn5l~6yO6GGaT9+UCvj-#Cg^PfUgy(9?6bFXL zpNb`ZMW&HB#=RloUUl{4T*WAYN0#{>9S=giO>#Fy+5dV^K*r~FnE~_`y9;cG`R|Z< zoOm=C`0i!|j9q)!?A~%82Uz7BM!4{L-9s2&lDz;lp6G%f*Hh2|EjuF*ZTdWkb~fij z6_P^E5528|&KH1y9o-vpP$5xCn_I}+iK{MC;6&BY+8Fs=m!-n;b%SD?b{UHjMD=vl z=|HehRp36=l!l{Nb=j)%E)c-p>$yu+7f<0NCv?~F0Cqtaf)`7bVV&u>BhZse9N&i(A3$x{)K4e9C)`q;|M{`52%Ol-Fg#F@RhIVC{{nI!7gqddBASWD!btp-(BBw zy3b`l5s_nR2<)6q^Y+vd*eWbZ{zSIO{;S}l*pU8|lJn$|PvBuKUqx7+=-R09e`&ej zfx{|HP3Z%AGj5jsR!`dCO19@yQ~>yvW;*!(X7#4zWHpB}1(BEfJf?t!{10!5-z-JJ zQX-eGqE>l9_7%!}cZXT{YORv&H@6?!P^VBI%uu6V6=U2bfK z-nUhXzIRgAtSRD^1sRqBr@J>`*yP8cp7G0o-9a4q`1%ZFqkHR25(W(nc!>F8Rev?+ z2p#E#0X>$-*t{U__3WWm|LRC(^ku5R)_I#q+`)twhDXu$zH2tK)}SV;F#zE0@2 zg?0JR?v@D90Hrb{11&%10Dztc$r&o2>~^QX>Hg!vk;( z#!o$oW+d2aJ3E!HTRLmi#ku04&fiTkl>~TQ=DSMO6nU&V@0^f&T|`G#xX*^A`Jd~q zJ}%Ne)$q(Ccl0IwAN0|Wt_{zb<)PfG{R#-xbxpIXTB^TSg|zin6u zSh5q{v1O+fzBxjo@#?QW1SARF$04v2_)CFv*=aWK_yOuc#x(QJ=Ett;&FUqs;sfxq zCIB|&O^N=5HrZJJV02Sr(xjsQLk19jeTIiI@V|PQ~{$B-zwT*x3pGviT$60%8 zCF!>divF-$D){m87X$&aRcy6G_WdbycC+L(o9?%>1B5-W24q|AHU&J)RiTV0+o^D# zT@WW6EHpXfOd)pp&5q{s?`;3C`S)0Y*FJT?+vbC9;6s04-B?QK(}F_(bAgv9`a9z3 z6M28iWc~@r|2+7AU-9?vZT>GSHUD2*%^6Xwe{?i5`rX!MSZEWDhZAtQj+cwo7%6a? zSLc=zv`#AoZy(3i_dRGaga;nDKI!IPS|BN(j!XSr`)E`qYOKB0Wf*X2oba7V#{I5) zk=%1laIo%)G5j-l9>dPfyf>2it=GmbYZG{h1;(^o*K*Rh-V5gQHTu_th|#qnsfD#z z@N=S0eaEKKL8ivW8}}v!0nvu1qUJx#E)FXw=}JTjohk=?^dIb7E2n>IU)7z^yXKN5>F_agCUG}=!;#J&CZeBX*c`T6-#zh=YC zndemokzv74zo3(!G~OKC6xP?%!8h!~ZNg_vh8nM8JRn4`F)hCQXDep(R~_D}48xI{ zy4B6+;dRhGlsf5MLde2Kp_-kt&0xj4>3R zhquhEz2pj?@1^q#2>W9fj)Lo|e>Qu;f1NoyY^u>Q{MwRUOwH>_4=8z=h;cgr9=^=* z?xGoVzo&BQKig6XySlGE%#IRELH|3M`R8%$1||7_>z7ob{BH;Pi(>l!kOxD5aw~vz80WD^z{{}CSKKBaMsdz*X zg6)>mlPEl1p-B3iKpQu{PzB-uPdhWO{u5Cs7TY70bf2c^q^bito#+l%nrww;wH*q9 z9^AY$9%^s&xgT$p@9X{}TC>IZXEuYUIBot@Zd+L=dt8Ib>xM9s`UCq}w*sdfH-c>$0J>4`lZ*J!KJWf!Y{KJ18 zO*eu+eRMMb1qB7s`&Lme!UCS%p^vnj9Q2HvZ-t@@!T%j}87W(a>}+UdXigJcB$4Fw!o$e+tk>*3^i~SJOF4C(3^hQo`+k zUHc7b-*l>D~O}$@DWtwNsB+WB=I-1wY3B z)aL(26^f6bcMLQ!gU#$v8OoT`dO;}%ZkQ@+oL)F*{Gtk~zA0_h*@O(Wo!zyFkK)04I`B2uMsXC_I zU!z7c!RhYhJk8D~`gE!0=iP>pQ1&?a zB!)_?vR+2ekCH#{3X(;%F)T=$KuNw;e-z^P__rCKy7~zHo4Nd6PA>hsiCK;Rkg$~!x* z1oZ}mhF_&o*#{n_Gl6O4`E5MaZ`8*?L(y-2KH65;x&P}1M}c~Nt(r)Z&EUbuGWgb` zq7h*-WJ2sQ%Gao%mg#yU&%gCFZGLyHw3wSiqxS1=ra7 zhfVM<(E_q=xL(ERoMH|F6v6KtK8Lk~#`=qi2h8)gZN zpyUxJ+PA&F!GFW~&t>#~6y)_7(HpW8GA#0Jj)JnO8cp|o$d$>=w7`eLBf~3W4w@?I z3W{(h>8dd`6ru&FGa6{(H&J8WF#<6i9@Pa!~XE?j?N_|er(s~ zoQnPL+2qvYPfp!VWX_=|XJ`LT_K`)B)Hpg6`5Jj1h*XuWGaakV^^5GAL8 z1<+W`_)7+Y9;rgWz7UMAb3^H0$qF~P}9YX$|(l68N)eOTs+-Qe#c_pox#H>9Hd=PVCb?037 zc_zYv+uwJQsXssy&e|r6osX(3gtZO%F+;}1ED_{DN(OKVGEW(OEgOHy`z;Y7edqUg zys_WA|GWh3p==edvj;U(>@0s)K za$RXeodzH`gT9(d)4eY`^}kKtGx+twpn!(!VK&>E+`yXpuh(v|Wpi(xTH=d7h;v5M zR!OVLI0!YPL@|EdV)~92GWb13R$pt`GEOT?Qb3x8FL#*Qs?^3PjDp30bwiH;|K&TnmI{XS_VTuIA^Xnk) zsnw>~BEwGBj$xwjGp_8r=GxpTbLY>4v$JC!E~~?Hz8N?^Ndu^6cq%-o7f>+JKkXTPIu#nTp1%Bf8oJEn+~#k zN$lGfo=h(}gTm<=NmRx#HWubhurWa9!z_j0mirhQKozcX)o-MCKS+U+)JmbYr=O&@ zqxm_+j`#c2m5$2FzBZCB1j*|si#Xvy3^!Fg04#vUxMh?he_JB87X1Pu^@Js}Al%lvRC}tTS?07wM`*eC|2fyacbu0nu1^PZ>k4AuS6p2pa8h}3!lXb z7r_gjW1#8@siJi4P7|_X)OLVfrXKQ1D=O4MjItz#=B=8o?40SD-1vq-P6EOgSr>U~Z9S?C>u(HvJCbLw4qC ztop8mY8GXcZ~_~n((s%NJy11JVUEbad`sQH;>i#eZ%GutbswFi`1%Pt)KH$zcr%DNDbV>DfG#DbOi8HOuFJpN&gT2;Iw>eOv}O#o z4R?4w{O&%K5Vb8@eB}{yeS>?T6RABQWkJM`{;QZIfGnGhyGq@IV*-6knvpw|-p9>L z8_Al3s`00QS`2aOB3S!KJ6PoClJHk*^e<9Ad|2h$i@?&-W7MU;?%kal^yz-r<+G^1 z3ePEaFu4kt4B8S>_b4Tog*3~bz8YIp2aKD9eM`&~kMoKBWiRy9>3*ex{3JikcJ}Fb z%F|>X-1Il#2ykyN?PknmKS5VQ>R)oG6|@i!HKt@e_*{`e6InENts%!y^}F{k;`8W< zOrqN3znhy>Y9D=`Y^b~%VAL%YTfa)04G_FL@T75=u?EDHHkKYcahGyN8oqe$#fkN- zL8ZX;gEHG~1>0NUj1-Y$rY3Fo=O%*5W=W@_?&iwRXu`HWXo{>Xyp@Hhxe!iZ?z&aD z4#nffwZ_Qzzrns#X;7I)Zjo{zoMhLa+xqy$Lg_DE<4d}V4`)a2&!Cd8UrIb`$7hQ~ z=rk3pL_>uShe-#nDQLLow4nimpL(^LXX95){J{Vs+#}lAx7hhMZKMAmM z@F@}Uj3|<`r$;{V-DHE@vA-qpGrh)EZ5nLHWL(KsXXqLi6M2tSeldQ*-*^A#+2(TN zh$e0D&p8p<0o2}CZ?Hhg*9_EEM8poNPOG1Aa2MN4ah2O+F;TTtw>uGr!H)Gh>J2rH zXFLlZh85r9yE4=+UxGnHePi3;6^A7(&UUa7E_@yVU?4Y_-Fl<@d%Quv-C`T%DQ|3``&(L^MPUn-q&sCZ zIsW1CvgOQcUB>3?@6N76^$4n~f@AH|@$r9Ikk}0E6n$%+>4bIhw}NC?o0k^zHGQCq zxp%a2gBW2V&eD+hK-KcNgv_rD{9j9$3M3nTudV&qOyVhqdTQ*bNTlgAZR#YREPi=I zfkqQU1+uZ!r~ zapTZw$fVK7r9vJg-B@Ml62+w5DO-4xdbOHw%~CT+&0R2hKK6+*aN;}#xCcXC8`-rj z#;6lm-Bt>#;*zI)V_WakvCNkFRBe|M;i6nIt8_Sqf)GD$y4Ebet;_EQ-h36+-}Hwi z*G}Fgdp~G<3==(#xp-|EIBy&Mupf-xtXVY1eM0f9a^eqffibJ*| zFeh(6S1byR5ldEw}h82UX3!s5W0g3eUd%q+f2x+?Q9?AJ$OF(NzRM^O0ul)+F&srRw4rpP9NNM zC+6g5Exi}AgJU;t`_6WH(mrCoZ3b*c%ri})d9Ihd2^NoS7gwNk za5jd{cQ*6X&O$wBl|Mpu%G zfG|V3AiCEMp;(0hIdu;xI$DRF-Q+5CzoEklgGPL8%wa`qXo-C(ae{e2;oprIn(;Y@Rg$=FML#BVB8#k+Rsl+tItuyeq~L*%@f2v&d2@{8TD zM4U=vKs?;y0D1T4AlMAjt@pZ4y~b5b@2%c%N=e{S-}#nshr*)&pdIT`hWpYx&!zQe zjQd!}?*!y1TmKrsOhSFkV0&vQpSUeJ3^??Yn_vhJE!C@OqdrT8p(8U?oK zh4%j8J@{vmM&n5g*a{t_Z9=H#&%@^O?8k?dY_{BgDp+AGs7eel>=}gdqYj%0RVi$( zsT+LAc6Q%axVf$PzQhzC+57B3hfK@;tUU~41cfVo{!Kj}NUffe)J3ZeQ!*z(w z>Yf&dPaI1$fq6}(4-q#NuR(Tjuk+8QT?>!Z%}?WO-j#B?w@`gzPQ`$y$X_?XzFGTR zq4hP-)!S%(Z9A9kK-iSIk7=8q-+i=TuFWi-ym*_>eUoPt=U@$W&Du0xolIbxFcuds z4|Sb9PnETL$71WkID^fx}bZ->Qs>AzZ!# z)c%0bGRnt2(({R^w`7S zQ7`JPVihS~JElzLcg&Jdd}{iZFO;O*+4PfZg117qLHd0iCL@#g)Gf`g%DXKUr@=Yy zaQwqceMb;fi5;K|T|B z`ANT$P7xM#`E`EtzTje-z>i*~rOcq&w0y=+5+UNB=7_ZR+xavh$!gMiy9+D2V)I5) zXmTO4S339dDqho((|)vpY7L~`^o1fNL?K(C>SAW7+0tP}5O6WnD~RdrArPuwYBrFn z0t9YDTYbmUanM0m#&K`|H1tT-76<{b^1V|*ZWLDqsJ;U0k+kIi?txp3rqAApczcKB zo-dSweIHV#%4W#2=aTn${B1Sv+UK<<0kN}qKR$ZB4bCuBx0k6_9x~vVoKV+ z&(}WQ=Jfd5nXXxN3SCvQlpXd}JoI-|b2eC!WgJd}PGeu$0!A_7d^#zIInYxi2_?*Ae@&^G z$PDnH`PPs*7BM*M79tWQTA8;<+CjnjahNS z)TAw}dr@;mwFV9luiSC7%1XKG3xtoE5sB2~ygqfPHmK?D`3S&-UbuAZDCpu%&f(5$ zZ=tm6>C+h!4NRlD7~_9!xK|Rw7kh7$EdN8&O|Q*;*ZCaD z4jJd=S~Xv{DiBm!zi9n!b0}i$`%OoeZgb9z_M07f<{%w$=I`(F7_&6GM`$zITB8MB8N6Ln8`vU|&v^H% zzlI7CK3Iehb#r8caRv?DU*F)1A3F@2*T^{A{zQd`>S=|uUQsZ&KA$%6(}JuU$Osz{88r^rp+Wi2e{`0T9QV1?p4 za~L#5T~1-Vhe|5^Tiu~ICc2J`73V*Tefm#B~4=bveHUwyMjMBL|;cX%8)=8 zoFo#i&)!T+)w-21=sR3;km9s1*flcnP%RDC*F=Tm+O94aEg_pD%leF8vta2*Az+P5 zADCIRacf?WQ5yN&B7R1q%5=w5DPM1NI*8FkNSjOkOD-biO1n=>Yb5tgEnr6RP3U8p z5Y3K}dS=;@c)-P$KCeSaK>{xIyvtA`@hFg}FUHmS*FTS48)2aw_y`Ge$ znPdOp^4YsOOpB;eHiXpO*`L}sIyT{J3b~>{{`Hm*>q&-6fwqLN*}Hm*SJZr0npYDr z?=PMOu;BO2GP-?w@jR;0&XjsqFWugHNL(Ya_7gUH7>j4_c5%P9E#H1=OZjV-#{l0u_)~I>-0fUVyiYkdf9XWUa zM1Xd3e6i;hJ1jx+30m4J7u2Est`0T%J8*(f$K%%KjgCZsHvMO3bvqCnPh3H|?xQma z4rSbdWu=z(`9a-Vy*y?Xf&ekh=h1@{dte9L4d-_~uQ60YMb*`Oc8Afv+%Yp?VF6=U zBVxaZSM8}7nHB{T5Ec5;B(df4+%q?_-G3OE5S=3EkUl8VV4L_ckv;LF(c9jrKJ0u# zcUAY~BU|YBk+VVlfiscRFj_~_Mj8R6yWmfL^BTYEytrmUr|}&luY{yq2gBhj`^c5Z z^S(cSkrU0?2?&(}>)0c{^rSVWrQMSY%$yc?UR!hrcSNmq+0&B!svJ0?5C~GA8}c>6 zj3N{*t4OCfKpu_^evK+tV7fprL3p;sL9(|iBI7Pia)v6MwpCc}&x=Mz?g403Xl<e;viOll%5G z0F13z2bFa2Hzg%Djq*8s(f={4DAR z_VYbC*mT3k8^YwXI%jshm2GBx>{5ieUdx1_gq9OvdT$5b@dmgLq=((RU{ZK6<-f+T zm}DK>i(S6*_7hf2xOTX|1-7HO4%Lop@E&^79{! z@9zg?%&B$Nbb{u$4&`iUl7ECne{W^Zt*<`qAxIkdiPu5@9OKNSobC�)v~C(0C)c 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 M)78&qol`;+0Fu7JivR!s diff --git a/docs/output.md b/docs/output.md index dc8682df..ddf2c98a 100644 --- a/docs/output.md +++ b/docs/output.md @@ -14,6 +14,7 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d - [FastQC](#fastqc) - Raw read QC - [MultiQC](#multiqc) - Aggregate report describing results and QC from the whole pipeline + - [Pipeline information](#pipeline-information) - Report metrics generated during the workflow execution ### FastQC @@ -29,16 +30,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d [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) - -:::note -The FastQC plots displayed in the MultiQC report shows _untrimmed_ reads. They may contain adapter sequence and potentially regions with low quality. -::: - ### MultiQC
diff --git a/docs/usage.md b/docs/usage.md index 20bcc59d..938053d7 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -85,9 +85,9 @@ The above pipeline run specified with a params file in yaml format: nextflow run nf-core/pixelator -profile docker -params-file params.yaml ``` -with `params.yaml` containing: +with: -```yaml +```yaml title="params.yaml" input: './samplesheet.csv' outdir: './results/' genome: 'GRCh37' @@ -199,14 +199,6 @@ See the main [Nextflow documentation](https://www.nextflow.io/docs/latest/config If you have any questions or issues please send us a message on [Slack](https://nf-co.re/join/slack) on the [`#configs` channel](https://nfcore.slack.com/channels/configs). -## Azure Resource Requests - -To be used with the `azurebatch` profile by specifying the `-profile azurebatch`. -We recommend providing a compute `params.vm_type` of `Standard_D16_v3` VMs by default but these options can be changed if required. - -Note that the choice of VM size depends on your quota and the overall workload during the analysis. -For a thorough list, please refer the [Azure Sizes for virtual machines in Azure](https://docs.microsoft.com/en-us/azure/virtual-machines/sizes). - ## Running in the background Nextflow handles job submissions and supervises the running jobs. The Nextflow process must run until the pipeline is finished. diff --git a/main.nf b/main.nf index 268be7c8..349e8d79 100644 --- a/main.nf +++ b/main.nf @@ -9,8 +9,6 @@ ---------------------------------------------------------------------------------------- */ -nextflow.enable.dsl = 2 - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT FUNCTIONS / MODULES / SUBWORKFLOWS / WORKFLOWS @@ -20,7 +18,6 @@ nextflow.enable.dsl = 2 include { PIXELATOR } from './workflows/pixelator' include { PIPELINE_INITIALISATION } from './subworkflows/local/utils_nfcore_pixelator_pipeline' include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_pixelator_pipeline' - include { getGenomeAttribute } from './subworkflows/local/utils_nfcore_pixelator_pipeline' /* @@ -56,10 +53,8 @@ workflow NFCORE_PIXELATOR { PIXELATOR ( samplesheet ) - emit: multiqc_report = PIXELATOR.out.multiqc_report // channel: /path/to/multiqc_report.html - } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -70,27 +65,24 @@ workflow NFCORE_PIXELATOR { workflow { 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_PIXELATOR ( PIPELINE_INITIALISATION.out.samplesheet ) - // // SUBWORKFLOW: Run completion tasks // diff --git a/modules.json b/modules.json index 6cb9bbd1..170c12d4 100644 --- a/modules.json +++ b/modules.json @@ -7,12 +7,12 @@ "nf-core": { "fastqc": { "branch": "master", - "git_sha": "285a50500f9e02578d90b3ce6382ea3c30216acd", + "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", "installed_by": ["modules"] }, "multiqc": { "branch": "master", - "git_sha": "b7ebe95761cd389603f9cc0e0dc384c0f663815a", + "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", "installed_by": ["modules"] } } @@ -21,17 +21,17 @@ "nf-core": { "utils_nextflow_pipeline": { "branch": "master", - "git_sha": "5caf7640a9ef1d18d765d55339be751bb0969dfa", + "git_sha": "d20fb2a9cc3e2835e9d067d1046a63252eb17352", "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "92de218a329bfc9a9033116eb5f65fd270e72ba3", + "git_sha": "2fdce49d30c0254f76bc0f13c55c17455c1251ab", "installed_by": ["subworkflows"] }, - "utils_nfvalidation_plugin": { + "utils_nfschema_plugin": { "branch": "master", - "git_sha": "5caf7640a9ef1d18d765d55339be751bb0969dfa", + "git_sha": "bbd5a41f4535a8defafe6080e00ea74c45f4f96c", "installed_by": ["subworkflows"] } } diff --git a/modules/nf-core/fastqc/environment.yml b/modules/nf-core/fastqc/environment.yml index 1787b38a..691d4c76 100644 --- a/modules/nf-core/fastqc/environment.yml +++ b/modules/nf-core/fastqc/environment.yml @@ -1,7 +1,5 @@ -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 d79f1c86..d8989f48 100644 --- a/modules/nf-core/fastqc/main.nf +++ b/modules/nf-core/fastqc/main.nf @@ -26,7 +26,10 @@ process FASTQC { 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') + // The total amount of allocated RAM by FastQC is equal to the number of threads defined (--threads) time the amount of RAM defined (--memory) + // https://github.com/s-andrews/FastQC/blob/1faeea0412093224d7f6a07f777fad60a5650795/fastqc#L211-L222 + // Dividing the task.memory by task.cpu allows to stick to requested amount of RAM in the label + def memory_in_mb = MemoryUnit.of("${task.memory}").toUnit('MB') / task.cpus // FastQC memory value allowed range (100 - 10000) def fastqc_memory = memory_in_mb > 10000 ? 10000 : (memory_in_mb < 100 ? 100 : memory_in_mb) diff --git a/modules/nf-core/fastqc/meta.yml b/modules/nf-core/fastqc/meta.yml index ee5507e0..4827da7a 100644 --- a/modules/nf-core/fastqc/meta.yml +++ b/modules/nf-core/fastqc/meta.yml @@ -16,35 +16,44 @@ tools: homepage: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/ documentation: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/ licence: ["GPL-2.0-only"] + identifier: biotools:fastqc input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - reads: - type: file - description: | - List of input FastQ files of size 1 and 2 for single-end and paired-end data, - respectively. + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - reads: + type: file + description: | + List of input FastQ files of size 1 and 2 for single-end and paired-end data, + respectively. output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - html: - type: file - description: FastQC report - pattern: "*_{fastqc.html}" + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.html": + type: file + description: FastQC report + pattern: "*_{fastqc.html}" - zip: - type: file - description: FastQC report archive - pattern: "*_{fastqc.zip}" + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.zip": + type: file + description: FastQC report archive + pattern: "*_{fastqc.zip}" - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" authors: - "@drpatelh" - "@grst" 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("File typeConventional base calls") }, - - { 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("File typeConventional base calls") }, + { 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("File typeConventional base calls") }, - { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, - - { 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("File typeConventional base calls") }, + { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, + { 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("File typeConventional base calls") }, - - { 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("File typeConventional base calls") }, + { 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("File typeConventional base calls") }, - - { 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("File typeConventional base calls") }, + { 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("File typeConventional base calls") }, - { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][2]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][3]).text.contains("File typeConventional base calls") }, - - { 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("File typeConventional base calls") }, + { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, + { assert path(process.out.html[0][1][2]).text.contains("File typeConventional base calls") }, + { assert path(process.out.html[0][1][3]).text.contains("File typeConventional base calls") }, + { 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("File typeConventional base calls") }, - - { 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("File typeConventional base calls") }, + { 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/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index ca39fb67..f1cd99b0 100644 --- a/modules/nf-core/multiqc/environment.yml +++ b/modules/nf-core/multiqc/environment.yml @@ -1,7 +1,5 @@ -name: multiqc channels: - conda-forge - bioconda - - defaults dependencies: - - bioconda::multiqc=1.21 + - bioconda::multiqc=1.24.1 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 47ac352f..b9ccebdb 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.25--pyhdfd78af_0' : + 'biocontainers/multiqc:1.25--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 @@ -23,16 +25,22 @@ process MULTIQC { script: def args = task.ext.args ?: '' + def prefix = task.ext.prefix ? "--filename ${task.ext.prefix}.html" : '' 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 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 \\ $args \\ $config \\ + $prefix \\ $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..b16c1879 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -1,5 +1,6 @@ name: multiqc -description: Aggregate results from bioinformatics analyses across many samples into a single report +description: Aggregate results from bioinformatics analyses across many samples into + a single report keywords: - QC - bioinformatics tools @@ -12,40 +13,59 @@ tools: homepage: https://multiqc.info/ documentation: https://multiqc.info/docs/ licence: ["GPL-3.0-or-later"] + identifier: biotools:multiqc input: - - multiqc_files: - type: file - description: | - List of reports / files recognised by MultiQC, for example the html and zip output of FastQC - - multiqc_config: - type: file - description: Optional config yml for MultiQC - pattern: "*.{yml,yaml}" - - extra_multiqc_config: - type: file - description: Second optional config yml for MultiQC. Will override common sections in multiqc_config. - pattern: "*.{yml,yaml}" - - multiqc_logo: - type: file - description: Optional logo file for MultiQC - pattern: "*.{png}" + - - multiqc_files: + type: file + description: | + List of reports / files recognised by MultiQC, for example the html and zip output of FastQC + - - multiqc_config: + type: file + description: Optional config yml for MultiQC + pattern: "*.{yml,yaml}" + - - extra_multiqc_config: + type: file + description: Second optional config yml for MultiQC. Will override common sections + in multiqc_config. + pattern: "*.{yml,yaml}" + - - multiqc_logo: + 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 - description: MultiQC report file - pattern: "multiqc_report.html" + - "*multiqc_report.html": + type: file + description: MultiQC report file + pattern: "multiqc_report.html" - data: - type: directory - description: MultiQC data dir - pattern: "multiqc_data" + - "*_data": + type: directory + description: MultiQC data dir + pattern: "multiqc_data" - plots: - type: file - description: Plots created by MultiQC - pattern: "*_data" + - "*_plots": + type: file + description: Plots created by MultiQC + pattern: "*_data" - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" authors: - "@abhi18av" - "@bunop" diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test index f1c4242e..33316a7d 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -8,6 +8,8 @@ nextflow_process { tag "modules_nfcore" tag "multiqc" + config "./nextflow.config" + test("sarscov2 single-end [fastqc]") { when { @@ -17,6 +19,8 @@ nextflow_process { input[1] = [] input[2] = [] input[3] = [] + input[4] = [] + input[5] = [] """ } } @@ -41,6 +45,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 +72,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..b779e469 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,8c8724363a5efe0c6f43ab34faa57efd" ] ], "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,8c8724363a5efe0c6f43ab34faa57efd" ] ], "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,8c8724363a5efe0c6f43ab34faa57efd" ] ], "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/multiqc/tests/nextflow.config b/modules/nf-core/multiqc/tests/nextflow.config new file mode 100644 index 00000000..c537a6a3 --- /dev/null +++ b/modules/nf-core/multiqc/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: 'MULTIQC' { + ext.prefix = null + } +} diff --git a/nextflow.config b/nextflow.config index ebfdbf55..99c13ada 100644 --- a/nextflow.config +++ b/nextflow.config @@ -16,7 +16,6 @@ params { genome = null igenomes_base = 's3://ngi-igenomes/igenomes/' igenomes_ignore = false - // MultiQC options multiqc_config = null multiqc_title = null @@ -33,48 +32,26 @@ params { monochrome_logs = false hook_url = null help = false + help_full = false + show_hidden = false version = false pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' - // 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_contact = null config_profile_url = null - - // Max resource options - // Defaults only, expecting to be overwritten - max_memory = '128.GB' - max_cpus = 16 - max_time = '240.h' - // Schema validation default options - validationFailUnrecognisedParams = false - validationLenientMode = false - validationSchemaIgnoreParams = 'genomes,igenomes_base' - validationShowHiddenParams = false - validate_params = true - + validate_params = true + } // Load base.config by default for all pipelines includeConfig 'conf/base.config' -// Load nf-core custom profiles from different Institutions -try { - includeConfig "${params.custom_config_base}/nfcore_custom.config" -} catch (Exception e) { - System.err.println("WARNING: Could not load nf-core/config profiles: ${params.custom_config_base}/nfcore_custom.config") -} - -// Load nf-core/pixelator custom profiles from different institutions. -try { - includeConfig "${params.custom_config_base}/pipeline/pixelator.config" -} catch (Exception e) { - System.err.println("WARNING: Could not load nf-core/config/pixelator profiles: ${params.custom_config_base}/pipeline/pixelator.config") -} profiles { debug { dumpHashes = true @@ -89,7 +66,7 @@ profiles { podman.enabled = false shifter.enabled = false charliecloud.enabled = false - conda.channels = ['conda-forge', 'bioconda', 'defaults'] + conda.channels = ['conda-forge', 'bioconda'] apptainer.enabled = false } mamba { @@ -178,25 +155,23 @@ 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' +// Load nf-core custom profiles from different Institutions +includeConfig !System.getenv('NXF_OFFLINE') && params.custom_config_base ? "${params.custom_config_base}/nfcore_custom.config" : "/dev/null" -// Nextflow plugins -plugins { - id 'nf-validation@1.1.3' // Validation of pipeline parameters and creation of an input channel from a sample sheet -} +// Load nf-core/pixelator custom profiles from different institutions. +// TODO nf-core: Optionally, you can add a pipeline-specific nf-core config at https://github.com/nf-core/configs +// includeConfig !System.getenv('NXF_OFFLINE') && params.custom_config_base ? "${params.custom_config_base}/pipeline/pixelator.config" : "/dev/null" +// Set default registry for Apptainer, Docker, Podman, Charliecloud and Singularity independent of -profile +// Will not be used unless Apptainer / Docker / Podman / Charliecloud / 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' +charliecloud.registry = 'quay.io' // Load igenomes.config if required -if (!params.igenomes_ignore) { - includeConfig 'conf/igenomes.config' -} else { - params.genomes = [:] -} +includeConfig !params.igenomes_ignore ? 'conf/igenomes.config' : 'conf/igenomes_ignored.config' // 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. @@ -208,8 +183,15 @@ env { JULIA_DEPOT_PATH = "/usr/local/share/julia" } -// Capture exit codes from upstream processes when piping -process.shell = ['/bin/bash', '-euo', 'pipefail'] +// Set bash options +process.shell = """\ +bash + +set -e # Exit if a tool returns a non-zero status/exit code +set -u # Treat unset variables and parameters as an error +set -o pipefail # Returns the status of the last command to exit with a non-zero status or zero if all successfully execute +set -C # No clobber - prevent output redirection from overwriting files. +""" // Disable process selector warnings by default. Use debug profile to enable warnings. nextflow.enable.configProcessNamesValidation = false @@ -238,43 +220,47 @@ manifest { homePage = 'https://github.com/nf-core/pixelator' description = """Pipeline for analysis of Molecular Pixelation assays""" mainScript = 'main.nf' - nextflowVersion = '!>=23.04.0' - version = '1.1.0' + nextflowVersion = '!>=24.04.2' + version = '1.3.1' doi = '' } -// Load modules.config for DSL2 module specific options -includeConfig 'conf/modules.config' +// Nextflow plugins +plugins { + id 'nf-schema@2.1.1' // Validation of pipeline parameters and creation of an input channel from a sample sheet +} + +validation { + defaultIgnoreParams = ["genomes"] + help { + enabled = true + command = "nextflow run $manifest.name -profile --input samplesheet.csv --outdir " + fullParameter = "help_full" + showHiddenParameter = "show_hidden" + beforeText = """ +-\033[2m----------------------------------------------------\033[0m- + \033[0;32m,--.\033[0;30m/\033[0;32m,-.\033[0m +\033[0;34m ___ __ __ __ ___ \033[0;32m/,-._.--~\'\033[0m +\033[0;34m |\\ | |__ __ / ` / \\ |__) |__ \033[0;33m} {\033[0m +\033[0;34m | \\| | \\__, \\__/ | \\ |___ \033[0;32m\\`-._,-`-,\033[0m + \033[0;32m`._,._,\'\033[0m +\033[0;35m ${manifest.name} ${manifest.version}\033[0m +-\033[2m----------------------------------------------------\033[0m- +""" + afterText = """${manifest.doi ? "* The pipeline\n" : ""}${manifest.doi.tokenize(",").collect { " https://doi.org/${it.trim().replace('https://doi.org/','')}"}.join("\n")}${manifest.doi ? "\n" : ""} +* The nf-core framework + https://doi.org/10.1038/s41587-020-0439-x -// Function to ensure that resource requirements don't go beyond -// a maximum limit -def check_max(obj, type) { - if (type == 'memory') { - try { - if (obj.compareTo(params.max_memory as nextflow.util.MemoryUnit) == 1) - return params.max_memory as nextflow.util.MemoryUnit - else - return obj - } catch (all) { - println " ### ERROR ### Max memory '${params.max_memory}' is not valid! Using default value: $obj" - return obj - } - } else if (type == 'time') { - try { - if (obj.compareTo(params.max_time as nextflow.util.Duration) == 1) - return params.max_time as nextflow.util.Duration - else - return obj - } catch (all) { - println " ### ERROR ### Max time '${params.max_time}' is not valid! Using default value: $obj" - return obj - } - } else if (type == 'cpus') { - try { - return Math.min( obj, params.max_cpus as int ) - } catch (all) { - println " ### ERROR ### Max cpus '${params.max_cpus}' is not valid! Using default value: $obj" - return obj - } +* Software dependencies + https://github.com/${manifest.name}/blob/master/CITATIONS.md +""" + } + summary { + beforeText = validation.help.beforeText + afterText = validation.help.afterText } } + +// Load modules.config for DSL2 module specific options +includeConfig 'conf/modules.config' + diff --git a/nextflow_schema.json b/nextflow_schema.json index 77b2a8e1..694bac27 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -1,10 +1,10 @@ { - "$schema": "http://json-schema.org/draft-07/schema", + "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/nf-core/pixelator/master/nextflow_schema.json", "title": "nf-core/pixelator pipeline parameters", "description": "Pipeline for analysis of Molecular Pixelation assays", "type": "object", - "definitions": { + "$defs": { "input_output_options": { "title": "Input/output options", "type": "object", @@ -71,6 +71,14 @@ "fa_icon": "fas fa-ban", "hidden": true, "help_text": "Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`." + }, + "igenomes_base": { + "type": "string", + "format": "directory-path", + "description": "The base path to the igenomes reference files", + "fa_icon": "fas fa-ban", + "hidden": true, + "default": "s3://ngi-igenomes/igenomes/" } } }, @@ -122,41 +130,6 @@ } } }, - "max_job_request_options": { - "title": "Max job request options", - "type": "object", - "fa_icon": "fab fa-acquisitions-incorporated", - "description": "Set the top limit for requested resources for any single job.", - "help_text": "If you are running on a smaller system, a pipeline step requesting more resources than are available may cause the Nextflow to stop the run with an error. These options allow you to cap the maximum resources requested by any single job so that the pipeline will run on your system.\n\nNote that you can not _increase_ the resources requested by any job using these options. For that you will need your own configuration file. See [the nf-core website](https://nf-co.re/usage/configuration) for details.", - "properties": { - "max_cpus": { - "type": "integer", - "description": "Maximum number of CPUs that can be requested for any single job.", - "default": 16, - "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`" - }, - "max_memory": { - "type": "string", - "description": "Maximum amount of memory that can be requested for any single job.", - "default": "128.GB", - "fa_icon": "fas fa-memory", - "pattern": "^\\d+(\\.\\d+)?\\.?\\s*(K|M|G|T)?B$", - "hidden": true, - "help_text": "Use to set an upper-limit for the memory requirement for each process. Should be a string in the format integer-unit e.g. `--max_memory '8.GB'`" - }, - "max_time": { - "type": "string", - "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|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'`" - } - } - }, "generic_options": { "title": "Generic options", "type": "object", @@ -164,12 +137,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": { - "help": { - "type": "boolean", - "description": "Display help text.", - "fa_icon": "fas fa-question-circle", - "hidden": true - }, "version": { "type": "boolean", "description": "Display version and exit.", @@ -245,27 +212,6 @@ "fa_icon": "fas fa-check-square", "hidden": true }, - "validationShowHiddenParams": { - "type": "boolean", - "fa_icon": "far fa-eye-slash", - "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)." - }, "pipelines_testdata_base_path": { "type": "string", "fa_icon": "far fa-check-circle", @@ -278,19 +224,16 @@ }, "allOf": [ { - "$ref": "#/definitions/input_output_options" - }, - { - "$ref": "#/definitions/reference_genome_options" + "$ref": "#/$defs/input_output_options" }, { - "$ref": "#/definitions/institutional_config_options" + "$ref": "#/$defs/reference_genome_options" }, { - "$ref": "#/definitions/max_job_request_options" + "$ref": "#/$defs/institutional_config_options" }, { - "$ref": "#/definitions/generic_options" + "$ref": "#/$defs/generic_options" } ] } diff --git a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf index 5d96f1f8..7ae96c12 100644 --- a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf @@ -8,17 +8,14 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -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 { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { samplesheetToList } from 'plugin/nf-schema' 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' +include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' /* ======================================================================================== @@ -30,7 +27,6 @@ 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 @@ -51,20 +47,16 @@ workflow PIPELINE_INITIALISATION { 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, + UTILS_NFSCHEMA_PLUGIN ( + workflow, validate_params, - "nextflow_schema.json" + null ) + // // Check config provided to the pipeline @@ -80,8 +72,9 @@ workflow PIPELINE_INITIALISATION { // // Create channel from input file provided through params.input // + Channel - .fromSamplesheet("input") + .fromList(samplesheetToList(params.input, "${projectDir}/assets/schema_input.json")) .map { meta, fastq_1, fastq_2 -> if (!fastq_2) { @@ -91,8 +84,8 @@ workflow PIPELINE_INITIALISATION { } } .groupTuple() - .map { - validateInputSamplesheet(it) + .map { samplesheet -> + validateInputSamplesheet(samplesheet) } .map { meta, fastqs -> @@ -117,13 +110,13 @@ workflow PIPELINE_COMPLETION { 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") // @@ -131,11 +124,18 @@ workflow PIPELINE_COMPLETION { // workflow.onComplete { if (email || email_on_fail) { - completionEmail(summary_params, email, email_on_fail, plaintext_email, outdir, monochrome_logs, multiqc_report.toList()) + 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) } @@ -165,7 +165,7 @@ 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 + def endedness_ok = metas.collect{ meta -> meta.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}") } @@ -197,7 +197,6 @@ def genomeExistsError() { error(error_string) } } - // // Generate methods description for MultiQC // @@ -239,8 +238,10 @@ def methodsDescriptionText(mqc_methods_yaml) { // 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(" ", "")}), " + def manifest_doi = meta.manifest_map.doi.tokenize(",") + manifest_doi.each { doi_ref -> + 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.
  • " @@ -261,3 +262,4 @@ def methodsDescriptionText(mqc_methods_yaml) { return description_html.toString() } + diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf index ac31f28f..28e32b20 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf @@ -2,10 +2,6 @@ // 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 @@ -58,7 +54,7 @@ workflow UTILS_NEXTFLOW_PIPELINE { // Generate version string // def getWorkflowVersion() { - String version_string = "" + def version_string = "" as String if (workflow.manifest.version) { def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : '' version_string += "${prefix_v}${workflow.manifest.version}" @@ -79,10 +75,10 @@ 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) + def jsonStr = groovy.json.JsonOutput.toJson(params) + temp_pf.text = groovy.json.JsonOutput.prettyPrint(jsonStr) - FilesEx.copyTo(temp_pf.toPath(), "${outdir}/pipeline_info/params_${timestamp}.json") + nextflow.extension.FilesEx.copyTo(temp_pf.toPath(), "${outdir}/pipeline_info/params_${timestamp}.json") temp_pf.delete() } @@ -90,7 +86,7 @@ def dumpParametersToJSON(outdir) { // When running with -profile conda, warn if channels have not been set-up appropriately // def checkCondaChannels() { - Yaml parser = new Yaml() + def parser = new org.yaml.snakeyaml.Yaml() def channels = [] try { def config = parser.load("conda config --show channels".execute().text) @@ -102,14 +98,16 @@ def checkCondaChannels() { // 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 required_channels_in_order = ['conda-forge', 'bioconda'] 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])) + + required_channels_in_order.eachWithIndex { channel, index -> + if (index < required_channels_in_order.size() - 1) { + channel_priority_violation |= !(channels.indexOf(channel) < channels.indexOf(required_channels_in_order[index+1])) + } } if (channels_missing | channel_priority_violation) { diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config b/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config index d0a926bf..a09572e5 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config @@ -3,7 +3,7 @@ manifest { author = """nf-core""" homePage = 'https://127.0.0.1' description = """Dummy pipeline""" - nextflowVersion = '!>=23.04.0' + 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/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index 14558c39..cbd8495b 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -2,9 +2,6 @@ // Subworkflow with utility functions specific to the nf-core pipeline template // -import org.yaml.snakeyaml.Yaml -import nextflow.extension.FilesEx - /* ======================================================================================== SUBWORKFLOW DEFINITION @@ -34,7 +31,7 @@ workflow UTILS_NFCORE_PIPELINE { // Warn if a -profile or Nextflow config has not been provided to run the pipeline // def checkConfigProvided() { - valid_config = true + def valid_config = true as Boolean 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" + @@ -66,11 +63,13 @@ def checkProfileProvided(nextflow_cli_args) { // def workflowCitation() { def temp_doi_ref = "" - String[] manifest_doi = workflow.manifest.doi.tokenize(",") + def 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" + manifest_doi.each { doi_ref -> + 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" + temp_doi_ref + "\n" + @@ -84,7 +83,7 @@ def workflowCitation() { // Generate workflow version string // def getWorkflowVersion() { - String version_string = "" + def version_string = "" as String if (workflow.manifest.version) { def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : '' version_string += "${prefix_v}${workflow.manifest.version}" @@ -102,8 +101,8 @@ def getWorkflowVersion() { // 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 ] } + def yaml = new org.yaml.snakeyaml.Yaml() + def versions = yaml.load(yaml_file).collectEntries { k, v -> [ k.tokenize(':')[-1], v ] } return yaml.dumpAsMap(versions).trim() } @@ -124,7 +123,7 @@ def workflowVersionToYAML() { def softwareVersionsToYAML(ch_versions) { return ch_versions .unique() - .map { processVersionsFromYAML(it) } + .map { version -> processVersionsFromYAML(version) } .unique() .mix(Channel.of(workflowVersionToYAML())) } @@ -134,19 +133,19 @@ def softwareVersionsToYAML(ch_versions) { // def paramsSummaryMultiqc(summary_params) { def summary_section = '' - for (group in summary_params.keySet()) { + summary_params.keySet().each { group -> 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()) { + group_params.keySet().sort().each { param -> summary_section += "
    $param
    ${group_params.get(param) ?: 'N/A'}
    \n" } summary_section += "
    \n" } } - String yaml_file_text = "id: '${workflow.manifest.name.replace('/','-')}-summary'\n" + def yaml_file_text = "id: '${workflow.manifest.name.replace('/','-')}-summary'\n" as String 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" @@ -161,7 +160,7 @@ def paramsSummaryMultiqc(summary_params) { // nf-core logo // def nfCoreLogo(monochrome_logs=true) { - Map colors = logColours(monochrome_logs) + def colors = logColours(monochrome_logs) as Map String.format( """\n ${dashedLine(monochrome_logs)} @@ -180,7 +179,7 @@ def nfCoreLogo(monochrome_logs=true) { // Return dashed line // def dashedLine(monochrome_logs=true) { - Map colors = logColours(monochrome_logs) + def colors = logColours(monochrome_logs) as Map return "-${colors.dim}----------------------------------------------------${colors.reset}-" } @@ -188,7 +187,7 @@ def dashedLine(monochrome_logs=true) { // ANSII colours used for terminal logging // def logColours(monochrome_logs=true) { - Map colorcodes = [:] + def colorcodes = [:] as Map // Reset / Meta colorcodes['reset'] = monochrome_logs ? '' : "\033[0m" @@ -287,7 +286,7 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi } def summary = [:] - for (group in summary_params.keySet()) { + summary_params.keySet().sort().each { group -> summary << summary_params[group] } @@ -344,10 +343,10 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi def sendmail_html = sendmail_template.toString() // Send the HTML e-mail - Map colors = logColours(monochrome_logs) + def colors = logColours(monochrome_logs) as Map if (email_address) { try { - if (plaintext_email) { throw GroovyException('Send plaintext e-mail, not HTML') } + if (plaintext_email) { throw new org.codehaus.groovy.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 } @@ -364,13 +363,13 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi // 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"); + nextflow.extension.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"); + nextflow.extension.FilesEx.copyTo(output_tf.toPath(), "${outdir}/pipeline_info/pipeline_report.txt"); output_tf.delete() } @@ -378,7 +377,7 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi // Print pipeline summary on completion // def completionSummary(monochrome_logs=true) { - Map colors = logColours(monochrome_logs) + def colors = logColours(monochrome_logs) as Map if (workflow.success) { if (workflow.stats.ignoredCount == 0) { log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Pipeline completed successfully${colors.reset}-" @@ -395,7 +394,7 @@ def completionSummary(monochrome_logs=true) { // def imNotification(summary_params, hook_url) { def summary = [:] - for (group in summary_params.keySet()) { + summary_params.keySet().sort().each { group -> summary << summary_params[group] } diff --git a/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/subworkflows/nf-core/utils_nfschema_plugin/main.nf new file mode 100644 index 00000000..4994303e --- /dev/null +++ b/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -0,0 +1,46 @@ +// +// Subworkflow that uses the nf-schema plugin to validate parameters and render the parameter summary +// + +include { paramsSummaryLog } from 'plugin/nf-schema' +include { validateParameters } from 'plugin/nf-schema' + +workflow UTILS_NFSCHEMA_PLUGIN { + + take: + input_workflow // workflow: the workflow object used by nf-schema to get metadata from the workflow + validate_params // boolean: validate the parameters + parameters_schema // string: path to the parameters JSON schema. + // this has to be the same as the schema given to `validation.parametersSchema` + // when this input is empty it will automatically use the configured schema or + // "${projectDir}/nextflow_schema.json" as default. This input should not be empty + // for meta pipelines + + main: + + // + // Print parameter summary to stdout. This will display the parameters + // that differ from the default given in the JSON schema + // + if(parameters_schema) { + log.info paramsSummaryLog(input_workflow, parameters_schema:parameters_schema) + } else { + log.info paramsSummaryLog(input_workflow) + } + + // + // Validate the parameters using nextflow_schema.json or the schema + // given via the validation.parametersSchema configuration option + // + if(validate_params) { + if(parameters_schema) { + validateParameters(parameters_schema:parameters_schema) + } else { + validateParameters() + } + } + + emit: + dummy_emit = true +} + diff --git a/subworkflows/nf-core/utils_nfschema_plugin/meta.yml b/subworkflows/nf-core/utils_nfschema_plugin/meta.yml new file mode 100644 index 00000000..f7d9f028 --- /dev/null +++ b/subworkflows/nf-core/utils_nfschema_plugin/meta.yml @@ -0,0 +1,35 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "utils_nfschema_plugin" +description: Run nf-schema to validate parameters and create a summary of changed parameters +keywords: + - validation + - JSON schema + - plugin + - parameters + - summary +components: [] +input: + - input_workflow: + type: object + description: | + The workflow object of the used pipeline. + This object contains meta data used to create the params summary log + - validate_params: + type: boolean + description: Validate the parameters and error if invalid. + - parameters_schema: + type: string + description: | + Path to the parameters JSON schema. + This has to be the same as the schema given to the `validation.parametersSchema` config + option. When this input is empty it will automatically use the configured schema or + "${projectDir}/nextflow_schema.json" as default. The schema should not be given in this way + for meta pipelines. +output: + - dummy_emit: + type: boolean + description: Dummy emit to make nf-core subworkflows lint happy +authors: + - "@nvnieuwk" +maintainers: + - "@nvnieuwk" diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test b/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test new file mode 100644 index 00000000..842dc432 --- /dev/null +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test @@ -0,0 +1,117 @@ +nextflow_workflow { + + name "Test Subworkflow UTILS_NFSCHEMA_PLUGIN" + script "../main.nf" + workflow "UTILS_NFSCHEMA_PLUGIN" + + tag "subworkflows" + tag "subworkflows_nfcore" + tag "subworkflows/utils_nfschema_plugin" + tag "plugin/nf-schema" + + config "./nextflow.config" + + test("Should run nothing") { + + when { + + params { + test_data = '' + } + + workflow { + """ + validate_params = false + input[0] = workflow + input[1] = validate_params + input[2] = "" + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } + + test("Should validate params") { + + when { + + params { + test_data = '' + outdir = 1 + } + + workflow { + """ + validate_params = true + input[0] = workflow + input[1] = validate_params + input[2] = "" + """ + } + } + + then { + assertAll( + { assert workflow.failed }, + { assert workflow.stdout.any { it.contains('ERROR ~ Validation of pipeline parameters failed!') } } + ) + } + } + + test("Should run nothing - custom schema") { + + when { + + params { + test_data = '' + } + + workflow { + """ + validate_params = false + input[0] = workflow + input[1] = validate_params + input[2] = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } + + test("Should validate params - custom schema") { + + when { + + params { + test_data = '' + outdir = 1 + } + + workflow { + """ + validate_params = true + input[0] = workflow + input[1] = validate_params + input[2] = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" + """ + } + } + + then { + assertAll( + { assert workflow.failed }, + { assert workflow.stdout.any { it.contains('ERROR ~ Validation of pipeline parameters failed!') } } + ) + } + } +} diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config new file mode 100644 index 00000000..0907ac58 --- /dev/null +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config @@ -0,0 +1,8 @@ +plugins { + id "nf-schema@2.1.0" +} + +validation { + parametersSchema = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" + monochromeLogs = true +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json similarity index 95% rename from subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json rename to subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json index 7626c1c9..331e0d2f 100644 --- a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json @@ -1,10 +1,10 @@ { - "$schema": "http://json-schema.org/draft-07/schema", + "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/./master/nextflow_schema.json", "title": ". pipeline parameters", "description": "", "type": "object", - "definitions": { + "$defs": { "input_output_options": { "title": "Input/output options", "type": "object", @@ -87,10 +87,10 @@ }, "allOf": [ { - "$ref": "#/definitions/input_output_options" + "$ref": "#/$defs/input_output_options" }, { - "$ref": "#/definitions/generic_options" + "$ref": "#/$defs/generic_options" } ] } diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/main.nf b/subworkflows/nf-core/utils_nfvalidation_plugin/main.nf deleted file mode 100644 index 2585b65d..00000000 --- a/subworkflows/nf-core/utils_nfvalidation_plugin/main.nf +++ /dev/null @@ -1,62 +0,0 @@ -// -// 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 deleted file mode 100644 index 3d4a6b04..00000000 --- a/subworkflows/nf-core/utils_nfvalidation_plugin/meta.yml +++ /dev/null @@ -1,44 +0,0 @@ -# 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 deleted file mode 100644 index 5784a33f..00000000 --- a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test +++ /dev/null @@ -1,200 +0,0 @@ -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!') } } - ) - } - } -} diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml deleted file mode 100644 index 60b1cfff..00000000 --- a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -subworkflows/utils_nfvalidation_plugin: - - subworkflows/nf-core/utils_nfvalidation_plugin/** diff --git a/workflows/pixelator.nf b/workflows/pixelator.nf index afb6838b..d9263cc1 100644 --- a/workflows/pixelator.nf +++ b/workflows/pixelator.nf @@ -3,10 +3,9 @@ IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - include { FASTQC } from '../modules/nf-core/fastqc/main' include { MULTIQC } from '../modules/nf-core/multiqc/main' -include { paramsSummaryMap } from 'plugin/nf-validation' +include { paramsSummaryMap } from 'plugin/nf-schema' 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_pixelator_pipeline' @@ -21,12 +20,10 @@ workflow PIXELATOR { take: ch_samplesheet // channel: samplesheet read in from --input - main: ch_versions = Channel.empty() ch_multiqc_files = Channel.empty() - // // MODULE: Run FastQC // @@ -42,11 +39,12 @@ workflow PIXELATOR { softwareVersionsToYAML(ch_versions) .collectFile( storeDir: "${params.outdir}/pipeline_info", - name: 'nf_core_pipeline_software_mqc_versions.yml', + name: 'nf_core_' + 'pipeline_software_' + 'mqc_' + 'versions.yml', sort: true, newLine: true ).set { ch_collated_versions } + // // MODULE: MultiQC // @@ -59,18 +57,19 @@ workflow PIXELATOR { 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_files = ch_multiqc_files.mix( + ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) + 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( @@ -83,12 +82,14 @@ workflow PIXELATOR { ch_multiqc_files.collect(), ch_multiqc_config.toList(), ch_multiqc_custom_config.toList(), - ch_multiqc_logo.toList() + ch_multiqc_logo.toList(), + [], + [] ) - emit: - multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html + emit:multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html versions = ch_versions // channel: [ path(versions.yml) ] + } /* From 7be24d4c5a095f64bec07675ef239caaf9a9b1e2 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Wed, 9 Oct 2024 11:08:29 +0000 Subject: [PATCH 02/70] Template update for nf-core/tools version 3.0.1 --- .editorconfig | 4 - .github/CONTRIBUTING.md | 2 +- .github/workflows/awsfulltest.yml | 6 +- .github/workflows/linting.yml | 4 +- .nf-core.yml | 2 +- .prettierignore | 1 - docs/output.md | 1 - modules.json | 6 +- modules/nf-core/multiqc/environment.yml | 2 +- modules/nf-core/multiqc/main.nf | 4 +- .../nf-core/multiqc/tests/main.nf.test.snap | 26 +- nextflow.config | 8 +- .../utils_nfcore_pixelator_pipeline/main.nf | 12 +- .../nf-core/utils_nextflow_pipeline/main.nf | 46 ++- .../nf-core/utils_nfcore_pipeline/main.nf | 279 ++++++++++-------- 15 files changed, 209 insertions(+), 194 deletions(-) diff --git a/.editorconfig b/.editorconfig index e1058815..72dda289 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,7 +11,6 @@ indent_style = space [*.{md,yml,yaml,html,css,scss,js}] indent_size = 2 - # These files are edited and tested upstream in nf-core/modules [/modules/nf-core/**] charset = unset @@ -26,12 +25,9 @@ insert_final_newline = unset trim_trailing_whitespace = unset indent_style = unset - - [/assets/email*] indent_size = unset - # ignore python and markdown [*.{py,md}] indent_style = unset diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a61a2a48..7c5b2c19 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -90,7 +90,7 @@ Once there, use `nf-core pipelines schema build` to add to `nextflow_schema.json ### Default processes resource requirements -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. +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/main/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.cpus}` and `${task.memory}` variables in the `script:` block. diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 5980d4d7..8f21bb1c 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -14,16 +14,18 @@ on: jobs: run-platform: name: Run AWS full tests - if: github.repository == 'nf-core/pixelator' && github.event.review.state == 'approved' + # run only if the PR is approved by at least 2 reviewers and against the master branch or manually triggered + if: github.repository == 'nf-core/pixelator' && github.event.review.state == 'approved' && github.event.pull_request.base.ref == 'master' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest steps: - uses: octokit/request-action@v2.x id: check_approvals with: - route: GET /repos/${{ github.repository }}/pulls/${{ github.event.review.number }}/reviews + route: GET /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - id: test_variables + if: github.event_name != 'workflow_dispatch' run: | JSON_RESPONSE='${{ steps.check_approvals.outputs.data }}' CURRENT_APPROVALS_COUNT=$(echo $JSON_RESPONSE | jq -c '[.[] | select(.state | contains("APPROVED")) ] | length') diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index b882838a..a502573c 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -42,10 +42,10 @@ jobs: architecture: "x64" - name: read .nf-core.yml - uses: pietrobolcato/action-read-yaml@1.0.0 + uses: pietrobolcato/action-read-yaml@1.1.0 id: read_yml with: - config: ${{ github.workspace }}/.nf-core.yaml + config: ${{ github.workspace }}/.nf-core.yml - name: Install dependencies run: | diff --git a/.nf-core.yml b/.nf-core.yml index 3faeceae..59ea3676 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -4,7 +4,7 @@ lint: - assets/multiqc_config.yml - conf/igenomes.config multiqc_config: false -nf_core_version: 3.0.0 +nf_core_version: 3.0.1 org_path: null repository_type: pipeline template: diff --git a/.prettierignore b/.prettierignore index 610e5069..437d763d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,3 @@ - email_template.html adaptivecard.json slackreport.json diff --git a/docs/output.md b/docs/output.md index ddf2c98a..58af8fd6 100644 --- a/docs/output.md +++ b/docs/output.md @@ -14,7 +14,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d - [FastQC](#fastqc) - Raw read QC - [MultiQC](#multiqc) - Aggregate report describing results and QC from the whole pipeline - - [Pipeline information](#pipeline-information) - Report metrics generated during the workflow execution ### FastQC diff --git a/modules.json b/modules.json index 170c12d4..11acdd01 100644 --- a/modules.json +++ b/modules.json @@ -12,7 +12,7 @@ }, "multiqc": { "branch": "master", - "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", + "git_sha": "b8d36829fa84b6e404364abff787e8b07f6d058c", "installed_by": ["modules"] } } @@ -21,12 +21,12 @@ "nf-core": { "utils_nextflow_pipeline": { "branch": "master", - "git_sha": "d20fb2a9cc3e2835e9d067d1046a63252eb17352", + "git_sha": "9d05360da397692321d377b6102d2fb22507c6ef", "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "2fdce49d30c0254f76bc0f13c55c17455c1251ab", + "git_sha": "772684d9d66f37b650c8ba5146ac1ee3ecba2acb", "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index f1cd99b0..6f5b867b 100644 --- a/modules/nf-core/multiqc/environment.yml +++ b/modules/nf-core/multiqc/environment.yml @@ -2,4 +2,4 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::multiqc=1.24.1 + - bioconda::multiqc=1.25.1 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index b9ccebdb..9724d2f3 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.25--pyhdfd78af_0' : - 'biocontainers/multiqc:1.25--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.25.1--pyhdfd78af_0' : + 'biocontainers/multiqc:1.25.1--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 b779e469..2fcbb5ff 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,8c8724363a5efe0c6f43ab34faa57efd" + "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.0", + "nextflow": "24.04.4" }, - "timestamp": "2024-07-10T12:41:34.562023" + "timestamp": "2024-10-02T17:51:46.317523" }, "multiqc_stub": { "content": [ @@ -17,25 +17,25 @@ "multiqc_report.html", "multiqc_data", "multiqc_plots", - "versions.yml:md5,8c8724363a5efe0c6f43ab34faa57efd" + "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.0", + "nextflow": "24.04.4" }, - "timestamp": "2024-07-10T11:27:11.933869532" + "timestamp": "2024-10-02T17:52:20.680978" }, "multiqc_versions_config": { "content": [ [ - "versions.yml:md5,8c8724363a5efe0c6f43ab34faa57efd" + "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.0", + "nextflow": "24.04.4" }, - "timestamp": "2024-07-10T11:26:56.709849369" + "timestamp": "2024-10-02T17:52:09.185842" } -} +} \ No newline at end of file diff --git a/nextflow.config b/nextflow.config index 99c13ada..3d4b2f07 100644 --- a/nextflow.config +++ b/nextflow.config @@ -12,10 +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 @@ -36,6 +38,7 @@ params { show_hidden = false version = false pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' + // Config options config_profile_name = null config_profile_description = null @@ -44,9 +47,9 @@ params { custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" config_profile_contact = null config_profile_url = null + // Schema validation default options validate_params = true - } // Load base.config by default for all pipelines @@ -161,6 +164,7 @@ includeConfig !System.getenv('NXF_OFFLINE') && params.custom_config_base ? "${pa // Load nf-core/pixelator custom profiles from different institutions. // TODO nf-core: Optionally, you can add a pipeline-specific nf-core config at https://github.com/nf-core/configs // includeConfig !System.getenv('NXF_OFFLINE') && params.custom_config_base ? "${params.custom_config_base}/pipeline/pixelator.config" : "/dev/null" + // Set default registry for Apptainer, Docker, Podman, Charliecloud and Singularity independent of -profile // Will not be used unless Apptainer / Docker / Podman / Charliecloud / Singularity are enabled // Set to your registry if you have a mirror of containers @@ -172,6 +176,7 @@ charliecloud.registry = 'quay.io' // Load igenomes.config if required includeConfig !params.igenomes_ignore ? 'conf/igenomes.config' : 'conf/igenomes_ignored.config' + // 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. @@ -263,4 +268,3 @@ validation { // Load modules.config for DSL2 module specific options includeConfig 'conf/modules.config' - diff --git a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf index 7ae96c12..3f76c34e 100644 --- a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf @@ -18,9 +18,9 @@ include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SUBWORKFLOW TO INITIALISE PIPELINE -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ workflow PIPELINE_INITIALISATION { @@ -99,9 +99,9 @@ workflow PIPELINE_INITIALISATION { } /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SUBWORKFLOW FOR PIPELINE COMPLETION -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ workflow PIPELINE_COMPLETION { @@ -147,9 +147,9 @@ workflow PIPELINE_COMPLETION { } /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTIONS -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ // // Check and validate pipeline parameters diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf index 28e32b20..2b0dc67a 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf @@ -3,13 +3,12 @@ // /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SUBWORKFLOW DEFINITION -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ workflow UTILS_NEXTFLOW_PIPELINE { - take: print_version // boolean: print version dump_parameters // boolean: dump parameters @@ -22,7 +21,7 @@ workflow UTILS_NEXTFLOW_PIPELINE { // Print workflow version and exit on --version // if (print_version) { - log.info "${workflow.manifest.name} ${getWorkflowVersion()}" + log.info("${workflow.manifest.name} ${getWorkflowVersion()}") System.exit(0) } @@ -45,9 +44,9 @@ workflow UTILS_NEXTFLOW_PIPELINE { } /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTIONS -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ // @@ -72,11 +71,11 @@ def getWorkflowVersion() { // 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 = groovy.json.JsonOutput.toJson(params) - temp_pf.text = groovy.json.JsonOutput.prettyPrint(jsonStr) + 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 = groovy.json.JsonOutput.toJson(params) + temp_pf.text = groovy.json.JsonOutput.prettyPrint(jsonStr) nextflow.extension.FilesEx.copyTo(temp_pf.toPath(), "${outdir}/pipeline_info/params_${timestamp}.json") temp_pf.delete() @@ -91,9 +90,14 @@ def checkCondaChannels() { 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 + } + catch (NullPointerException e) { + log.warn("Could not verify conda channel configuration.") + return null + } + catch (IOException e) { + log.warn("Could not verify conda channel configuration.") + return null } // Check that all channels are present @@ -106,19 +110,13 @@ def checkCondaChannels() { required_channels_in_order.eachWithIndex { channel, index -> if (index < required_channels_in_order.size() - 1) { - channel_priority_violation |= !(channels.indexOf(channel) < channels.indexOf(required_channels_in_order[index+1])) + channel_priority_violation |= !(channels.indexOf(channel) < channels.indexOf(required_channels_in_order[index + 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" + - "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + 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_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index cbd8495b..b78273ca 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -3,13 +3,12 @@ // /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SUBWORKFLOW DEFINITION -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ workflow UTILS_NFCORE_PIPELINE { - take: nextflow_cli_args @@ -22,9 +21,9 @@ workflow UTILS_NFCORE_PIPELINE { } /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTIONS -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ // @@ -33,12 +32,9 @@ workflow UTILS_NFCORE_PIPELINE { def checkConfigProvided() { def valid_config = true as Boolean 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 " + 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 @@ -49,12 +45,14 @@ def checkConfigProvided() { // 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" + 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" + 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" + ) } } @@ -70,13 +68,7 @@ def workflowCitation() { manifest_doi.each { doi_ref -> 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" + - temp_doi_ref + "\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" + return "If you use ${workflow.manifest.name} for your analysis please cite:\n\n" + "* The pipeline\n" + temp_doi_ref + "\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" } // @@ -102,7 +94,7 @@ def getWorkflowVersion() { // def processVersionsFromYAML(yaml_file) { def yaml = new org.yaml.snakeyaml.Yaml() - def versions = yaml.load(yaml_file).collectEntries { k, v -> [ k.tokenize(':')[-1], v ] } + def versions = yaml.load(yaml_file).collectEntries { k, v -> [k.tokenize(':')[-1], v] } return yaml.dumpAsMap(versions).trim() } @@ -112,8 +104,8 @@ def processVersionsFromYAML(yaml_file) { def workflowVersionToYAML() { return """ Workflow: - $workflow.manifest.name: ${getWorkflowVersion()} - Nextflow: $workflow.nextflow.version + ${workflow.manifest.name}: ${getWorkflowVersion()} + Nextflow: ${workflow.nextflow.version} """.stripIndent().trim() } @@ -121,11 +113,7 @@ def workflowVersionToYAML() { // Get channel of software versions used in pipeline in YAML format // def softwareVersionsToYAML(ch_versions) { - return ch_versions - .unique() - .map { version -> processVersionsFromYAML(version) } - .unique() - .mix(Channel.of(workflowVersionToYAML())) + return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(Channel.of(workflowVersionToYAML())) } // @@ -133,25 +121,31 @@ def softwareVersionsToYAML(ch_versions) { // def paramsSummaryMultiqc(summary_params) { def summary_section = '' - summary_params.keySet().each { group -> - 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" - group_params.keySet().sort().each { param -> - summary_section += "
    $param
    ${group_params.get(param) ?: 'N/A'}
    \n" + summary_params + .keySet() + .each { group -> + 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" + group_params + .keySet() + .sort() + .each { param -> + summary_section += "
    ${param}
    ${group_params.get(param) ?: 'N/A'}
    \n" + } + summary_section += "
    \n" } - summary_section += "
    \n" } - } - def yaml_file_text = "id: '${workflow.manifest.name.replace('/','-')}-summary'\n" as String - 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}" + def yaml_file_text = "id: '${workflow.manifest.name.replace('/', '-')}-summary'\n" as String + 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 } @@ -199,54 +193,54 @@ def logColours(monochrome_logs=true) { 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" + 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" + 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" + 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" + 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" + 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 } @@ -261,14 +255,15 @@ def attachMultiqcReport(multiqc_report) { 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" + log.warn("[${workflow.manifest.name}] Found multiple reports from process 'MULTIQC', will use only one") } mqc_report = mqc_report[0] } } - } catch (all) { + } + catch (Exception all) { if (multiqc_report) { - log.warn "[$workflow.manifest.name] Could not attach MultiQC report to summary email" + log.warn("[${workflow.manifest.name}] Could not attach MultiQC report to summary email") } } return mqc_report @@ -280,26 +275,35 @@ def attachMultiqcReport(multiqc_report) { 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" + def subject = "[${workflow.manifest.name}] Successful: ${workflow.runName}" if (!workflow.success) { - subject = "[$workflow.manifest.name] FAILED: $workflow.runName" + subject = "[${workflow.manifest.name}] FAILED: ${workflow.runName}" } def summary = [:] - summary_params.keySet().sort().each { group -> - summary << summary_params[group] - } + summary_params + .keySet() + .sort() + .each { group -> + 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 + 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 = [:] @@ -337,7 +341,7 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi // 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 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() @@ -346,30 +350,32 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi def colors = logColours(monochrome_logs) as Map if (email_address) { try { - if (plaintext_email) { throw new org.codehaus.groovy.GroovyException('Send plaintext e-mail, not HTML') } + if (plaintext_email) { +new org.codehaus.groovy.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) { + ['sendmail', '-t'].execute() << sendmail_html + log.info("-${colors.purple}[${workflow.manifest.name}]${colors.green} Sent summary e-mail to ${email_address} (sendmail)-") + } + catch (Exception all) { // Catch failures and try with plaintext - def mail_cmd = [ 'mail', '-s', subject, '--content-type=text/html', email_address ] + 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)-" + 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 } - nextflow.extension.FilesEx.copyTo(output_hf.toPath(), "${outdir}/pipeline_info/pipeline_report.html"); + nextflow.extension.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 } - nextflow.extension.FilesEx.copyTo(output_tf.toPath(), "${outdir}/pipeline_info/pipeline_report.txt"); + nextflow.extension.FilesEx.copyTo(output_tf.toPath(), "${outdir}/pipeline_info/pipeline_report.txt") output_tf.delete() } @@ -380,12 +386,14 @@ def completionSummary(monochrome_logs=true) { def colors = logColours(monochrome_logs) as Map 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}-" + 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}-" + } + else { + log.info("-${colors.purple}[${workflow.manifest.name}]${colors.red} Pipeline completed with errors${colors.reset}-") } } @@ -394,21 +402,30 @@ def completionSummary(monochrome_logs=true) { // def imNotification(summary_params, hook_url) { def summary = [:] - summary_params.keySet().sort().each { group -> - summary << summary_params[group] - } + summary_params + .keySet() + .sort() + .each { group -> + 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 + 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() @@ -433,13 +450,13 @@ def imNotification(summary_params, hook_url) { def json_message = json_template.toString() // POST - def post = new URL(hook_url).openConnection(); + 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()); + post.getOutputStream().write(json_message.getBytes("UTF-8")) + def postRC = post.getResponseCode() + if (!postRC.equals(200)) { + log.warn(post.getErrorStream().getText()) } } From 7ae55f9fe2f08d6063d903b3018204b55786465a Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Fri, 11 Oct 2024 12:38:15 +0000 Subject: [PATCH 03/70] Template update for nf-core/tools version 3.0.2 --- .github/workflows/ci.yml | 60 +++++++++++++------ .../workflows/template_version_comment.yml | 21 ++++--- .gitignore | 1 + .nf-core.yml | 2 +- main.nf | 2 +- modules.json | 6 +- modules/nf-core/multiqc/main.nf | 2 +- nextflow.config | 4 +- .../utils_nfcore_pixelator_pipeline/main.nf | 4 +- .../nf-core/utils_nextflow_pipeline/main.nf | 30 +++++----- .../nf-core/utils_nfcore_pipeline/main.nf | 10 ++-- workflows/pixelator.nf | 2 - 12 files changed, 86 insertions(+), 58 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 232946a6..fb74d479 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,8 @@ on: env: NXF_ANSI_LOG: false + NXF_SINGULARITY_CACHEDIR: ${{ github.workspace }}/.singularity + NXF_SINGULARITY_LIBRARYDIR: ${{ github.workspace }}/.singularity concurrency: group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}" @@ -18,7 +20,7 @@ concurrency: jobs: test: - name: Run pipeline with test data + name: "Run pipeline with test data (${{ matrix.NXF_VER }} | ${{ matrix.test_name }} | ${{ matrix.profile }})" # Only run on push if this is the nf-core dev branch (merged PRs) if: "${{ github.event_name != 'push' || (github.event_name == 'push' && github.repository == 'nf-core/pixelator') }}" runs-on: ubuntu-latest @@ -27,33 +29,57 @@ jobs: NXF_VER: - "24.04.2" - "latest-everything" + profile: + - "conda" + - "docker" + - "singularity" + test_name: + - "test" + isMaster: + - ${{ github.base_ref == 'master' }} + # Exclude conda and singularity on dev + exclude: + - isMaster: false + profile: "conda" + - isMaster: false + profile: "singularity" steps: - name: Check out pipeline code uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 - - name: Install Nextflow + - name: Set up Nextflow uses: nf-core/setup-nextflow@v2 with: version: "${{ matrix.NXF_VER }}" - - name: Disk space cleanup - uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + - name: Set up Apptainer + if: matrix.profile == 'singularity' + uses: eWaterCycle/setup-apptainer@main - - name: Run pipeline with test data (docker) - # 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 + - name: Set up Singularity + if: matrix.profile == 'singularity' run: | - nextflow run ${GITHUB_WORKSPACE} -profile test,docker --outdir ./results + mkdir -p $NXF_SINGULARITY_CACHEDIR + mkdir -p $NXF_SINGULARITY_LIBRARYDIR + + - name: Set up Miniconda + if: matrix.profile == 'conda' + uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3 + with: + miniconda-version: "latest" + auto-update-conda: true + conda-solver: libmamba + channels: conda-forge,bioconda - - name: Run pipeline with test data (singularity) - # TODO nf-core: You can customise CI pipeline run tests as required + - name: Set up Conda + if: matrix.profile == 'conda' run: | - nextflow run ${GITHUB_WORKSPACE} -profile test,singularity --outdir ./results - if: "${{ github.base_ref == 'master' }}" + echo $(realpath $CONDA)/condabin >> $GITHUB_PATH + echo $(realpath python) >> $GITHUB_PATH + + - name: Clean up Disk space + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 - - name: Run pipeline with test data (conda) - # TODO nf-core: You can customise CI pipeline run tests as required + - name: "Run pipeline with test data ${{ matrix.NXF_VER }} | ${{ matrix.test_name }} | ${{ matrix.profile }}" run: | - nextflow run ${GITHUB_WORKSPACE} -profile test,conda --outdir ./results - if: "${{ github.base_ref == 'master' }}" + nextflow run ${GITHUB_WORKSPACE} -profile ${{ matrix.test_name }},${{ matrix.profile }} --outdir ./results diff --git a/.github/workflows/template_version_comment.yml b/.github/workflows/template_version_comment.yml index 9dea41f0..e8aafe44 100644 --- a/.github/workflows/template_version_comment.yml +++ b/.github/workflows/template_version_comment.yml @@ -10,9 +10,11 @@ jobs: steps: - name: Check out pipeline code uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Read template version from .nf-core.yml - uses: pietrobolcato/action-read-yaml@1.0.0 + uses: nichmor/minimal-read-yaml@v0.0.2 id: read_yml with: config: ${{ github.workspace }}/.nf-core.yml @@ -24,20 +26,21 @@ jobs: - name: Check nf-core outdated id: nf_core_outdated - run: pip list --outdated | grep nf-core + run: echo "OUTPUT=$(pip list --outdated | grep nf-core)" >> ${GITHUB_ENV} - name: Post nf-core template version comment uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 if: | - ${{ steps.nf_core_outdated.outputs.stdout }} =~ 'nf-core' + contains(env.OUTPUT, 'nf-core') with: repo-token: ${{ secrets.NF_CORE_BOT_AUTH_TOKEN }} allow-repeats: false message: | - ## :warning: Newer version of the nf-core template is available. - - Your pipeline is using an old version of the nf-core template: ${{ steps.read_yml.outputs['nf_core_version'] }}. - Please update your pipeline to the latest version. - - For more documentation on how to update your pipeline, please see the [nf-core documentation](https://github.com/nf-core/tools?tab=readme-ov-file#sync-a-pipeline-with-the-template) and [Synchronisation documentation](https://nf-co.re/docs/contributing/sync). + > [!WARNING] + > Newer version of the nf-core template is available. + > + > Your pipeline is using an old version of the nf-core template: ${{ steps.read_yml.outputs['nf_core_version'] }}. + > Please update your pipeline to the latest version. + > + > For more documentation on how to update your pipeline, please see the [nf-core documentation](https://github.com/nf-core/tools?tab=readme-ov-file#sync-a-pipeline-with-the-template) and [Synchronisation documentation](https://nf-co.re/docs/contributing/sync). # diff --git a/.gitignore b/.gitignore index 5124c9ac..a42ce016 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ results/ testing/ testing* *.pyc +null/ diff --git a/.nf-core.yml b/.nf-core.yml index 59ea3676..b18db0bf 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -4,7 +4,7 @@ lint: - assets/multiqc_config.yml - conf/igenomes.config multiqc_config: false -nf_core_version: 3.0.1 +nf_core_version: 3.0.2 org_path: null repository_type: pipeline template: diff --git a/main.nf b/main.nf index 349e8d79..6ad8c060 100644 --- a/main.nf +++ b/main.nf @@ -76,7 +76,7 @@ workflow { params.outdir, params.input ) - + // // WORKFLOW: Run main workflow // diff --git a/modules.json b/modules.json index 11acdd01..3453e2aa 100644 --- a/modules.json +++ b/modules.json @@ -12,7 +12,7 @@ }, "multiqc": { "branch": "master", - "git_sha": "b8d36829fa84b6e404364abff787e8b07f6d058c", + "git_sha": "cf17ca47590cc578dfb47db1c2a44ef86f89976d", "installed_by": ["modules"] } } @@ -21,12 +21,12 @@ "nf-core": { "utils_nextflow_pipeline": { "branch": "master", - "git_sha": "9d05360da397692321d377b6102d2fb22507c6ef", + "git_sha": "3aa0aec1d52d492fe241919f0c6100ebf0074082", "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "772684d9d66f37b650c8ba5146ac1ee3ecba2acb", + "git_sha": "1b6b9a3338d011367137808b49b923515080e3ba", "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 9724d2f3..cc0643e1 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -52,7 +52,7 @@ process MULTIQC { stub: """ mkdir multiqc_data - touch multiqc_plots + mkdir multiqc_plots touch multiqc_report.html cat <<-END_VERSIONS > versions.yml diff --git a/nextflow.config b/nextflow.config index 3d4b2f07..e55b4fbf 100644 --- a/nextflow.config +++ b/nextflow.config @@ -254,10 +254,10 @@ validation { """ afterText = """${manifest.doi ? "* The pipeline\n" : ""}${manifest.doi.tokenize(",").collect { " https://doi.org/${it.trim().replace('https://doi.org/','')}"}.join("\n")}${manifest.doi ? "\n" : ""} * The nf-core framework - https://doi.org/10.1038/s41587-020-0439-x + https://doi.org/10.1038/s41587-020-0439-x * Software dependencies - https://github.com/${manifest.name}/blob/master/CITATIONS.md + https://github.com/${manifest.name}/blob/master/CITATIONS.md """ } summary { diff --git a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf index 3f76c34e..05695fe1 100644 --- a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf @@ -47,7 +47,6 @@ workflow PIPELINE_INITIALISATION { workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1 ) - // // Validate parameters and generate parameter summary to stdout // @@ -56,7 +55,6 @@ workflow PIPELINE_INITIALISATION { validate_params, null ) - // // Check config provided to the pipeline @@ -64,6 +62,7 @@ workflow PIPELINE_INITIALISATION { UTILS_NFCORE_PIPELINE ( nextflow_cli_args ) + // // Custom validation for pipeline parameters // @@ -110,7 +109,6 @@ workflow PIPELINE_COMPLETION { 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 diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf index 2b0dc67a..0fcbf7b3 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf @@ -3,9 +3,9 @@ // /* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SUBWORKFLOW DEFINITION -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ workflow UTILS_NEXTFLOW_PIPELINE { @@ -44,9 +44,9 @@ workflow UTILS_NEXTFLOW_PIPELINE { } /* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTIONS -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ // @@ -106,17 +106,19 @@ def checkCondaChannels() { 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 - - required_channels_in_order.eachWithIndex { channel, index -> - if (index < required_channels_in_order.size() - 1) { - channel_priority_violation |= !(channels.indexOf(channel) < channels.indexOf(required_channels_in_order[index + 1])) - } - } + def channel_priority_violation = required_channels_in_order != channels.findAll { ch -> ch in required_channels_in_order } 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" + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - ) + log.warn """\ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + There is a problem with your Conda configuration! + You will need to set-up the conda-forge and bioconda channels correctly. + Please refer to https://bioconda.github.io/ + The observed channel order is + ${channels} + but the following channel order is required: + ${required_channels_in_order} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + """.stripIndent(true) } } diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index b78273ca..5cb7bafe 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -3,9 +3,9 @@ // /* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SUBWORKFLOW DEFINITION -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ workflow UTILS_NFCORE_PIPELINE { @@ -21,9 +21,9 @@ workflow UTILS_NFCORE_PIPELINE { } /* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTIONS -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ // @@ -62,7 +62,7 @@ def checkProfileProvided(nextflow_cli_args) { def workflowCitation() { def temp_doi_ref = "" def manifest_doi = workflow.manifest.doi.tokenize(",") - // Using a loop to handle multiple DOIs + // Handling 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 manifest_doi.each { doi_ref -> diff --git a/workflows/pixelator.nf b/workflows/pixelator.nf index d9263cc1..0af43732 100644 --- a/workflows/pixelator.nf +++ b/workflows/pixelator.nf @@ -57,13 +57,11 @@ workflow PIXELATOR { 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_files = ch_multiqc_files.mix( ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) - 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) From f82e485812e1d7e695f2a0f61ef6363fda74ccc7 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Mon, 21 Oct 2024 13:56:57 +0200 Subject: [PATCH 04/70] Update cat/fastq module --- modules.json | 2 +- modules/nf-core/cat/fastq/environment.yml | 2 +- modules/nf-core/cat/fastq/main.nf | 14 +- modules/nf-core/cat/fastq/meta.yml | 43 ++-- modules/nf-core/cat/fastq/tests/main.nf.test | 138 ++++++++-- .../nf-core/cat/fastq/tests/main.nf.test.snap | 237 ++++++++++++++++-- 6 files changed, 378 insertions(+), 58 deletions(-) diff --git a/modules.json b/modules.json index c005251e..7c89a4f9 100644 --- a/modules.json +++ b/modules.json @@ -7,7 +7,7 @@ "nf-core": { "cat/fastq": { "branch": "master", - "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", + "git_sha": "a1abf90966a2a4016d3c3e41e228bfcbd4811ccc", "installed_by": ["modules"] } } diff --git a/modules/nf-core/cat/fastq/environment.yml b/modules/nf-core/cat/fastq/environment.yml index c7eb9bd1..71e04c3d 100644 --- a/modules/nf-core/cat/fastq/environment.yml +++ b/modules/nf-core/cat/fastq/environment.yml @@ -2,4 +2,4 @@ channels: - conda-forge - bioconda dependencies: - - conda-forge::coreutils=8.30 + - conda-forge::coreutils=9.5 diff --git a/modules/nf-core/cat/fastq/main.nf b/modules/nf-core/cat/fastq/main.nf index f132b2ad..4364a389 100644 --- a/modules/nf-core/cat/fastq/main.nf +++ b/modules/nf-core/cat/fastq/main.nf @@ -4,8 +4,8 @@ process CAT_FASTQ { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : - 'nf-core/ubuntu:20.04' }" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/c2/c262fc09eca59edb5a724080eeceb00fb06396f510aefb229c2d2c6897e63975/data' : + 'community.wave.seqera.io/library/coreutils:9.5--ae99c88a9b28c264' }" input: tuple val(meta), path(reads, stageAs: "input*/*") @@ -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/meta.yml b/modules/nf-core/cat/fastq/meta.yml index db4ac3c7..91ff2fb5 100644 --- a/modules/nf-core/cat/fastq/meta.yml +++ b/modules/nf-core/cat/fastq/meta.yml @@ -10,30 +10,33 @@ tools: The cat utility reads files sequentially, writing them to the standard output. documentation: https://www.gnu.org/software/coreutils/manual/html_node/cat-invocation.html licence: ["GPL-3.0-or-later"] + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - reads: - type: file - description: | - List of input FastQ files to be concatenated. + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - reads: + type: file + description: | + List of input FastQ files to be concatenated. output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - reads: - type: file - description: Merged fastq file - pattern: "*.{merged.fastq.gz}" + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.merged.fastq.gz": + type: file + description: Merged fastq file + pattern: "*.{merged.fastq.gz}" - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" authors: - "@joseespinosa" - "@drpatelh" diff --git a/modules/nf-core/cat/fastq/tests/main.nf.test b/modules/nf-core/cat/fastq/tests/main.nf.test index dab2e14c..f88a78b6 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" @@ -11,9 +13,6 @@ nextflow_process { test("test_cat_fastq_single_end") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -36,9 +35,6 @@ nextflow_process { test("test_cat_fastq_paired_end") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -63,9 +59,6 @@ nextflow_process { test("test_cat_fastq_single_end_same_name") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -88,9 +81,6 @@ nextflow_process { test("test_cat_fastq_paired_end_same_name") { when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -115,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..f8689a1c 100644 --- a/modules/nf-core/cat/fastq/tests/main.nf.test.snap +++ b/modules/nf-core/cat/fastq/tests/main.nf.test.snap @@ -12,7 +12,7 @@ ] ], "1": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" ], "reads": [ [ @@ -24,11 +24,15 @@ ] ], "versions": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" ] } ], - "timestamp": "2024-01-17T17:30:39.816981" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-10-19T20:02:07.519211144" }, "test_cat_fastq_single_end_same_name": { "content": [ @@ -43,7 +47,7 @@ ] ], "1": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" ], "reads": [ [ @@ -55,11 +59,15 @@ ] ], "versions": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" ] } ], - "timestamp": "2024-01-17T17:32:35.229332" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-10-19T20:02:31.618628921" }, "test_cat_fastq_single_end_single_file": { "content": [ @@ -74,7 +82,7 @@ ] ], "1": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" ], "reads": [ [ @@ -86,11 +94,15 @@ ] ], "versions": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" ] } ], - "timestamp": "2024-01-17T17:34:00.058829" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-10-19T20:02:57.904149581" }, "test_cat_fastq_paired_end_same_name": { "content": [ @@ -108,7 +120,7 @@ ] ], "1": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" ], "reads": [ [ @@ -123,11 +135,126 @@ ] ], "versions": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" ] } ], - "timestamp": "2024-01-17T17:33:33.031555" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-10-19T20:02:44.577183829" + }, + "test_cat_fastq_single_end - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions": [ + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-10-19T20:03:10.603734777" + }, + "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,6ef4fd28546a005865b9454bbedbf81a" + ], + "reads": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "versions": [ + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-10-19T20:03:46.041808828" + }, + "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,6ef4fd28546a005865b9454bbedbf81a" + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions": [ + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-10-19T20:03:34.13865402" }, "test_cat_fastq_paired_end": { "content": [ @@ -145,7 +272,7 @@ ] ], "1": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" ], "reads": [ [ @@ -160,10 +287,90 @@ ] ], "versions": [ - "versions.yml:md5,d42d6e24d67004608495883e00bd501b" + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-10-19T20:02:19.64383573" + }, + "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,6ef4fd28546a005865b9454bbedbf81a" + ], + "reads": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "versions": [ + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-10-19T20:03:22.597246066" + }, + "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,6ef4fd28546a005865b9454bbedbf81a" + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions": [ + "versions.yml:md5,6ef4fd28546a005865b9454bbedbf81a" ] } ], - "timestamp": "2024-01-17T17:32:02.270935" + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-10-19T20:03:58.44849001" } } \ No newline at end of file From 769d9ab89cc7fbac9db51e1e45e550751d291e00 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Mon, 21 Oct 2024 13:57:30 +0200 Subject: [PATCH 05/70] Remove duplicated lines form old template --- nextflow.config | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/nextflow.config b/nextflow.config index 663b4e2f..20d752e6 100644 --- a/nextflow.config +++ b/nextflow.config @@ -119,21 +119,6 @@ params { // Load base.config by default for all pipelines includeConfig 'conf/base.config' -// Load nf-core custom profiles from different Institutions -try { - includeConfig "${params.custom_config_base}/nfcore_custom.config" -} catch (Exception e) { - System.err.println("WARNING: Could not load nf-core/config profiles: ${params.custom_config_base}/nfcore_custom.config") -} - -// Load nf-core/pixelator 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/pixelator.config" -// } catch (Exception e) { -// System.err.println("WARNING: Could not load nf-core/config/pixelator profiles: ${params.custom_config_base}/pipeline/pixelator.config") -// } - def container_env_options = [ "MPLCONFIGDIR": '/tmp/.config/matplotlib', @@ -315,7 +300,7 @@ manifest { homePage = 'https://github.com/nf-core/pixelator' description = """Pipeline for analysis of Molecular Pixelation assays""" mainScript = 'main.nf' - nextflowVersion = '!>=23.04.2' + nextflowVersion = '!>=24.04.2' version = '1.4.0dev' doi = '10.1101/2023.06.05.543770' } From 6c9accaace163af57c06123048a9bf4056b96fc9 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Mon, 21 Oct 2024 13:57:36 +0200 Subject: [PATCH 06/70] Update logo --- assets/nf-core-pixelator_logo_light.png | Bin 80637 -> 79808 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/nf-core-pixelator_logo_light.png b/assets/nf-core-pixelator_logo_light.png index 9b643424a35ba9d3c7dd653522220ea377485add..a3ccb46351ce4346149fc660d11551ea03893548 100644 GIT binary patch literal 79808 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

    );ZzjCK~k0> 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 !_^*Q)(Gm_l3{IhD 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 literal 80637 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 D?%u&q From a36aa730e261ebe7c15f314b694dee27cd7db5da Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Mon, 21 Oct 2024 14:39:34 +0200 Subject: [PATCH 07/70] Add graph refinement options and remove unused use_counts --- conf/modules.config | 4 ++-- nextflow.config | 11 ++++++----- nextflow_schema.json | 21 +++++++++++++-------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index c8350e70..06d17e9f 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -193,7 +193,6 @@ process { params.max_neighbours ? "--max-neighbours ${params.max_neighbours}": '', params.collapse_mismatches ? "--mismatches ${params.collapse_mismatches}": '', params.collapse_min_count ? "--min-count ${params.collapse_min_count}": '', - params.collapse_use_counts ? "--use-counts": '', ].join(' ').trim() } @@ -222,8 +221,9 @@ process { ext.args = { [ params.multiplet_recovery ? "--multiplet-recovery" : '', - params.leiden_iterations ? "--leiden-iterations ${params.leiden_iterations}" : '', params.graph_min_count ? "--min-count ${params.graph_min_count}" : '', + params.graph_max_refinement_recursion_depth ? "--max-refinement-recursion-depth ${params.graph_max_refinement_recursion_depth}" : '', + params.graph_max_edges_to_split ? "--max-edges-to-split ${params.graph_max_edges_to_split}" : '', ].join(' ').trim() } diff --git a/nextflow.config b/nextflow.config index 20d752e6..fa151d01 100644 --- a/nextflow.config +++ b/nextflow.config @@ -37,12 +37,12 @@ params { max_neighbours = 60 collapse_mismatches = 2 collapse_min_count = 2 - collapse_use_counts = false // graph options - multiplet_recovery = true - leiden_iterations = 10 - graph_min_count = 2 + multiplet_recovery = true + graph_max_refinement_recursion_depth = 5 + graph_max_edges_to_split = 5 + graph_min_count = 2 // annotate options min_size = null @@ -87,7 +87,8 @@ params { skip_layout = false // Main pixelator container override - pixelator_container = null + // TODO: Remove this once the pixelator 0.19 is out + pixelator_container = "ghcr.io/pixelgentechnologies/pixelator:dev" // Boilerplate options outdir = null diff --git a/nextflow_schema.json b/nextflow_schema.json index 24a2cb05..8ca85a06 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -210,10 +210,6 @@ "minimum": 1, "type": "integer" }, - "collapse_use_counts": { - "description": "Use counts when collapsing (the difference in counts between two molecules must be more than double in order to be collapsed)", - "type": "boolean" - }, "save_collapsed_reads": { "fa_icon": "fas fa-save", "type": "boolean", @@ -232,13 +228,22 @@ "type": "boolean", "default": true }, - "leiden_iterations": { - "fa_icon": "fas repeat", - "description": "Number of iterations for the leiden algorithm, high values will decrease the variance of the results but increase the runtime [default: 10; 1<=x<=100]", + "graph_max_refinement_recursion_depth": { + "fa_icon": "fas less-than-equal", + "description": "The number of times a component can be broken down into smaller components during the multiplet recovery process.", "type": "integer", + "default": 5, "minimum": 1, "maximum": 100, - "default": 10, + "hidden": true + }, + "graph_max_edges_to_split": { + "fa_icon": "fas less-than-equal", + "description": "Maximum number of edges between the product components as a result of a component split operation during the multiplet recovery process.", + "type": "integer", + "default": 5, + "minimum": 1, + "maximum": 1000, "hidden": true }, "graph_min_count": { From 789abc78dcb6c558caca8f3c559c126913b9eb5d Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Mon, 21 Oct 2024 14:45:58 +0200 Subject: [PATCH 08/70] Update CHANGELOG --- CHANGELOG.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed9f0a16..28cbc8da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,13 +3,29 @@ 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). -## [[1.4.0](https://github.com/nf-core/pixelator/releases/tag/1.4.0] - ????-??-?? +## [[1.4.0dev](https://github.com/nf-core/pixelator/releases/tag/1.4.0] - ????-??-?? ### Enhancements & fixes - [[PR #111](https://github.com/nf-core/pixelator/pull/111)] - Template update for nf-core/tools v3.0.2 +- [[PR #112](https://github.com/nf-core/pixelator/pull/112)] - Add graph refinement options for pixelator 0.19 -## [[1.3.1](https://github.com/nf-core/pixelator/releases/tag/1.3.1)] - 2024-07-31 +### Parameters + +| Old parameter | New parameter | +| ------------------------------------ | ---------------------------------- | +| | `--help_full` | +| | `--show_hidden` | +| `--validationFailUnrecognisedParams` | | +| `--validationLenientMode` | | +| `--validationSchemaIgnoreParams` | | +| `--validationShowHiddenParams` | | +| `--leiden-iterations` | `--max-refinement-recursion-depth` | + +> [!NOTE] +> Parameter has been **updated** if both old and new parameter information is present. +> Parameter has been **added** if just the new parameter information is present. +> Parameter has been **removed** if new parameter information isn't present. ### Software dependencies @@ -17,6 +33,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | ----------- | ----------- | ----------- | | `pixelator` | 0.18.2 | 0.19.0 | +> [!NOTE] +> Dependency has been **updated** if both old and new parameter information is present. +> Dependency has been **added** if just the new parameter information is present. +> Dependency has been **removed** if new parameter information isn't present. + +## [[1.3.1](https://github.com/nf-core/pixelator/releases/tag/1.3.1)] - 2024-07-31 + ### Enhancements & fixes - [[PR #107](https://github.com/nf-core/pixelator/pull/107)] - Fix conda version tag to use pixelator 0.18.2 From fe74a1680a11d18d3e7f113541cccdb1a6c92f2d Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Mon, 21 Oct 2024 15:37:09 +0200 Subject: [PATCH 09/70] Ignore linting failure on logo --- .nf-core.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.nf-core.yml b/.nf-core.yml index c885ed26..eb1755a9 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -1,6 +1,8 @@ bump_version: null lint: multiqc_config: false + files_unchanged: + - assets/nf-core-pixelator_logo_light.png files_exist: - assets/multiqc_config.yml - conf/igenomes.config From c644129cc292738f06aa65742437d235f634332e Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Mon, 21 Oct 2024 15:39:58 +0200 Subject: [PATCH 10/70] Fix stray space and typo --- nextflow_schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index 8ca85a06..44bf0df5 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -239,7 +239,7 @@ }, "graph_max_edges_to_split": { "fa_icon": "fas less-than-equal", - "description": "Maximum number of edges between the product components as a result of a component split operation during the multiplet recovery process.", + "description": "Maximum number of edges between the produced components as a result of a component split operation during the multiplet recovery process.", "type": "integer", "default": 5, "minimum": 1, From 0e8759f88489c8c7432f433070e98506df7235d4 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Mon, 21 Oct 2024 16:15:51 +0200 Subject: [PATCH 11/70] Add `--max-edges-to-split` parameter to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28cbc8da..798073dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | `--validationSchemaIgnoreParams` | | | `--validationShowHiddenParams` | | | `--leiden-iterations` | `--max-refinement-recursion-depth` | +| | `--max-edges-to-split` | > [!NOTE] > Parameter has been **updated** if both old and new parameter information is present. From c3591650a88643fd9eb9640b0f02bc920487d03f Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Mon, 21 Oct 2024 16:18:37 +0200 Subject: [PATCH 12/70] Fix parameter names in CHANGELOG --- CHANGELOG.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 798073dc..0f36d126 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,16 +12,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Parameters -| Old parameter | New parameter | -| ------------------------------------ | ---------------------------------- | -| | `--help_full` | -| | `--show_hidden` | -| `--validationFailUnrecognisedParams` | | -| `--validationLenientMode` | | -| `--validationSchemaIgnoreParams` | | -| `--validationShowHiddenParams` | | -| `--leiden-iterations` | `--max-refinement-recursion-depth` | -| | `--max-edges-to-split` | +| Old parameter | New parameter | +| ------------------------------------ | ---------------------------------------- | +| | `--help_full` | +| | `--show_hidden` | +| `--validationFailUnrecognisedParams` | | +| `--validationLenientMode` | | +| `--validationSchemaIgnoreParams` | | +| `--validationShowHiddenParams` | | +| `--leiden_iterations` | `--graph_max_refinement_recursion_depth` | +| | `--graph_max_edges_to_split` | > [!NOTE] > Parameter has been **updated** if both old and new parameter information is present. From ad31578b5fd0c6c259d060513c36d17e3ed384f2 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Tue, 29 Oct 2024 10:30:39 +0100 Subject: [PATCH 13/70] Fix validation check after nf-schema 2 update --- subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf index 29012bcb..82872b8a 100644 --- a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf @@ -335,7 +335,7 @@ def resolve_relative_path(relative_path, URI samplesheet_path) { // Validate a given panel key if present against the (dynamic) set of panel options retrieved from pixelator // def validate_panel(LinkedHashMap meta, HashSet options) { - if (meta.panel == null) { + if (meta.panel == null || meta.panel == []) { return meta } @@ -352,7 +352,7 @@ def validate_panel(LinkedHashMap meta, HashSet options) { // Validate a given design key if present against the (dynamic) set of design options retrieved from pixelator // def validate_design(LinkedHashMap meta, HashSet options) { - if (meta.design == null) { + if (meta.design == null || meta.design == []) { return meta } From 3827a3eb9b3393e8f30fc4d46cbaa25b8b815b50 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Tue, 29 Oct 2024 13:22:34 +0100 Subject: [PATCH 14/70] Fix non existence check on input_basedir --- nextflow_schema.json | 1 - 1 file changed, 1 deletion(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index 44bf0df5..c7e57cb7 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -26,7 +26,6 @@ "input_basedir": { "type": "string", "format": "directory-path", - "exists": false, "description": "Path to a local or remote directory that is the \"current working directory\" for relative paths defined in the input samplesheet", "fa_icon": "fas fa-folder" }, From 0e7e0c2d188618539b8b8d8b94de67257f41c115 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Tue, 29 Oct 2024 13:25:11 +0100 Subject: [PATCH 15/70] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f36d126..6a525989 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [[PR #111](https://github.com/nf-core/pixelator/pull/111)] - Template update for nf-core/tools v3.0.2 - [[PR #112](https://github.com/nf-core/pixelator/pull/112)] - Add graph refinement options for pixelator 0.19 +- [[PR #113](https://github.com/nf-core/pixelator/pull/113)] - Fix validation issues after nf-core/tools v3.0.2 update ### Parameters From 3067ff374a0ac172f3c41f7896431b2a7086a7ce Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Tue, 10 Dec 2024 15:24:35 +0100 Subject: [PATCH 16/70] Remove `--save_recovered_components` options for graph outputs --- CHANGELOG.md | 3 +++ conf/modules.config | 6 ------ docs/output.md | 4 +--- modules/local/pixelator/single-cell/graph/main.nf | 1 - nextflow.config | 1 - nextflow_schema.json | 7 ------- 6 files changed, 4 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a525989..831f1174 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [[PR #111](https://github.com/nf-core/pixelator/pull/111)] - Template update for nf-core/tools v3.0.2 - [[PR #112](https://github.com/nf-core/pixelator/pull/112)] - Add graph refinement options for pixelator 0.19 - [[PR #113](https://github.com/nf-core/pixelator/pull/113)] - Fix validation issues after nf-core/tools v3.0.2 update +- [[PR #114](https://github.com/nf-core/pixelator/pull/114)] - Remove `--save_recovered_components` options for graph outputs ### Parameters @@ -23,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | `--validationShowHiddenParams` | | | `--leiden_iterations` | `--graph_max_refinement_recursion_depth` | | | `--graph_max_edges_to_split` | +| | `--graph_max_edges_to_split` | +| `--save_recovered_components` | | > [!NOTE] > Parameter has been **updated** if both old and new parameter information is present. diff --git a/conf/modules.config b/conf/modules.config index 06d17e9f..a0e74146 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -228,12 +228,6 @@ process { } publishDir = [ - [ - path: { "${params.outdir}/pixelator" }, - mode: params.publish_dir_mode, - pattern: 'graph/*.components_recovered.csv', - saveAs: { (params.save_recovered_components || params.save_all) ? it : null } - ], [ path: { "${params.outdir}/pixelator" }, mode: params.publish_dir_mode, diff --git a/docs/output.md b/docs/output.md index 7d3f5d09..70b5e72f 100644 --- a/docs/output.md +++ b/docs/output.md @@ -156,9 +156,7 @@ When graphs are computed and identified, their ID names are added back to the ed The graph command has the option to recover components (technical multiplets) into smaller components using community detection to find and remove problematic edges -(see `--multiplet_recovery`). These new component IDs are then stored in the "component" column. The information to keep track of the original and -newly recovered components are stored in a file (components_recovered.csv). -This file is not included in the output folder by default, but can be included by passing `--save_recovered_components`. +(see `--multiplet_recovery`). These new component IDs are then stored in the "component" column. The edge list is intermediate and by default not placed in the output folder with the final files delivered to users. Set `--save_edgelist` to enable publishing of these file. diff --git a/modules/local/pixelator/single-cell/graph/main.nf b/modules/local/pixelator/single-cell/graph/main.nf index b26b8e4d..4cd5db80 100644 --- a/modules/local/pixelator/single-cell/graph/main.nf +++ b/modules/local/pixelator/single-cell/graph/main.nf @@ -13,7 +13,6 @@ process PIXELATOR_GRAPH { output: tuple val(meta), path("graph/*.edgelist.parquet") , emit: edgelist - tuple val(meta), path("graph/*.components_recovered.csv"), emit: components_recovered, optional: true tuple val(meta), path("graph/*.report.json") , emit: report_json tuple val(meta), path("graph/*.meta.json") , emit: input_params tuple val(meta), path("graph/*") , emit: all_results diff --git a/nextflow.config b/nextflow.config index fa151d01..a7ae9710 100644 --- a/nextflow.config +++ b/nextflow.config @@ -70,7 +70,6 @@ params { save_demux_processed_reads = false save_demux_failed_reads = false save_collapsed_reads = false - save_recovered_components = false save_edgelist = false save_annotate_dataset = false save_raw_component_metrics = false diff --git a/nextflow_schema.json b/nextflow_schema.json index c7e57cb7..40a3d9b9 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -260,13 +260,6 @@ "default": false, "description": "Save an intermediate CSV file containing the unfiltered graph edge list.", "help": "By default, the unfiltered edge list 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." - }, - "save_recovered_components": { - "fa_icon": "fas fa-save", - "type": "boolean", - "default": false, - "description": "Save an intermediate CSV file containing the recovered components after multiplet recovery.", - "help": "By default, the recovered component 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." } } }, From 2b52d0013aa2d58104a872f19f6890042455da84 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Tue, 10 Dec 2024 15:45:27 +0100 Subject: [PATCH 17/70] Remove reference to `--save_recovered_components` from nextflow_schema.json --- nextflow_schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index 40a3d9b9..cc5f7b34 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -428,7 +428,7 @@ "type": "boolean", "default": false, "description": "Save all intermediate results.", - "help": "This option is equivalent to passing:\n`--save_amplicon_reads --save_qc_passed_reads --save_qc_failed_reads --save_demux_processed_reads --save_demux_failed_reads --save_collapsed_reads --save_edgelist --save_recovered_components --save_annotate_dataset --save_analysis_dataset`" + "help": "This option is equivalent to passing:\n`--save_amplicon_reads --save_qc_passed_reads --save_qc_failed_reads --save_demux_processed_reads --save_demux_failed_reads --save_collapsed_reads --save_edgelist --save_annotate_dataset --save_analysis_dataset`" } } }, From 37cc14d24e9ee6bc473e4fcde34c97842ef2c0a2 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Tue, 10 Dec 2024 17:02:49 +0100 Subject: [PATCH 18/70] Fix test config defaults --- conf/test.config | 1 + conf/test_panel_v2.config | 1 + 2 files changed, 2 insertions(+) diff --git a/conf/test.config b/conf/test.config index 0952ac70..3f5690d4 100644 --- a/conf/test.config +++ b/conf/test.config @@ -32,6 +32,7 @@ params { multiplet_recovery = true min_size = 2 max_size = 100000 + dynamic_filtering = null compute_polarization = true use_full_bipartite = true colocalization_min_region_count = 0 diff --git a/conf/test_panel_v2.config b/conf/test_panel_v2.config index 3e2c3d22..37875578 100644 --- a/conf/test_panel_v2.config +++ b/conf/test_panel_v2.config @@ -33,6 +33,7 @@ params { multiplet_recovery = true min_size = 2 max_size = 100000 + dynamic_filtering = nu compute_polarization = true use_full_bipartite = true colocalization_min_region_count = 0 From ed7e5a6b0c254064ada5aa9e19f373d925321c9f Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Tue, 10 Dec 2024 17:03:05 +0100 Subject: [PATCH 19/70] Update help for `--dynamic_filter` --- conf/test.config | 2 +- conf/test_panel_v2.config | 2 +- nextflow_schema.json | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/conf/test.config b/conf/test.config index 3f5690d4..76444d71 100644 --- a/conf/test.config +++ b/conf/test.config @@ -32,7 +32,7 @@ params { multiplet_recovery = true min_size = 2 max_size = 100000 - dynamic_filtering = null + dynamic_filter = null compute_polarization = true use_full_bipartite = true colocalization_min_region_count = 0 diff --git a/conf/test_panel_v2.config b/conf/test_panel_v2.config index 37875578..7707d127 100644 --- a/conf/test_panel_v2.config +++ b/conf/test_panel_v2.config @@ -33,7 +33,7 @@ params { multiplet_recovery = true min_size = 2 max_size = 100000 - dynamic_filtering = nu + dynamic_filter = null compute_polarization = true use_full_bipartite = true colocalization_min_region_count = 0 diff --git a/nextflow_schema.json b/nextflow_schema.json index cc5f7b34..9d6335ab 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -276,7 +276,8 @@ "type": "integer" }, "dynamic_filter": { - "description": " Enable the estimation of dynamic size filters using a log-rank approach both: estimate both min and max size, min: estimate min size (--min-size), max: estimate max size (--max-size)", + "description": "Enable the estimation of dynamic size filters using a log-rank approach.", + "help_text": "Following options are available:\n- both: estimates both minimum and maximum component size\n- min: estimates the minimum component size (or uses {MINIMUM_N_EDGES_CELL_SIZE} edges, whichever is smallest)\n- max: estimates the maximum component size.\n\nNote that this cannot be set at the same time as `--min-size` or `--max-size`.", "type": "string", "enum": ["both", "min", "max"], "default": "min" From 7d6510e643cac6a5f62303294d97311161f73ec2 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 11 Dec 2024 09:20:35 +0100 Subject: [PATCH 20/70] Remove `--min-size` from test profile --- conf/test.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/test.config b/conf/test.config index 76444d71..d9683271 100644 --- a/conf/test.config +++ b/conf/test.config @@ -30,7 +30,7 @@ params { input_basedir = params.pipelines_testdata_base_path + 'pixelator/testdata' multiplet_recovery = true - min_size = 2 + min_size = null max_size = 100000 dynamic_filter = null compute_polarization = true From 55927f8f4c44d7dfd89099850ff6ad987f12c4ea Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 11 Dec 2024 09:20:54 +0100 Subject: [PATCH 21/70] Fix linter warning --- subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf index 82872b8a..bcad4b4c 100644 --- a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf @@ -100,13 +100,13 @@ workflow PIPELINE_INITIALISATION { // Create a set of valid pixelator options to pass to --design ch_design_options = PIXELATOR_LIST_OPTIONS.out.designs .splitText() - .map( text -> text.trim()) + .map { it.trim() } .reduce( new HashSet() ) { prev, curr -> prev << curr } // Create a set of valid pixelator panel keys to pass using --panel ch_panel_options = PIXELATOR_LIST_OPTIONS.out.panels .splitText() - .map( text -> text.trim()) + .map { it.trim() } .reduce( new HashSet() ) { prev, curr -> prev << curr } // From e0ecbe91c4360d8a0b38194d172faf375ae8ed2f Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 11 Dec 2024 09:33:07 +0100 Subject: [PATCH 22/70] Update images to pixelator 0.19 --- modules/local/pixelator/collect_metadata.nf | 4 ++-- modules/local/pixelator/list_options.nf | 4 ++-- modules/local/pixelator/single-cell/amplicon/main.nf | 4 ++-- modules/local/pixelator/single-cell/analysis/main.nf | 4 ++-- modules/local/pixelator/single-cell/annotate/main.nf | 4 ++-- modules/local/pixelator/single-cell/collapse/main.nf | 4 ++-- modules/local/pixelator/single-cell/demux/main.nf | 4 ++-- modules/local/pixelator/single-cell/graph/main.nf | 4 ++-- modules/local/pixelator/single-cell/layout/main.nf | 4 ++-- modules/local/pixelator/single-cell/qc/main.nf | 4 ++-- modules/local/pixelator/single-cell/report/main.nf | 4 ++-- nextflow.config | 3 +-- 12 files changed, 23 insertions(+), 24 deletions(-) diff --git a/modules/local/pixelator/collect_metadata.nf b/modules/local/pixelator/collect_metadata.nf index 0817d806..160810f4 100644 --- a/modules/local/pixelator/collect_metadata.nf +++ b/modules/local/pixelator/collect_metadata.nf @@ -8,8 +8,8 @@ process PIXELATOR_COLLECT_METADATA { conda "bioconda::pixelator=0.18.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:0.18.2--pyhdfd78af_0' : - 'biocontainers/pixelator:0.18.2--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: diff --git a/modules/local/pixelator/list_options.nf b/modules/local/pixelator/list_options.nf index 880be7cc..17fa8b22 100644 --- a/modules/local/pixelator/list_options.nf +++ b/modules/local/pixelator/list_options.nf @@ -4,8 +4,8 @@ process PIXELATOR_LIST_OPTIONS { conda "bioconda::pixelator=0.18.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:0.18.2--pyhdfd78af_0' : - 'biocontainers/pixelator:0.18.2--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" output: path "design_options.txt" , emit: designs diff --git a/modules/local/pixelator/single-cell/amplicon/main.nf b/modules/local/pixelator/single-cell/amplicon/main.nf index 87b5095b..3bdca1e1 100644 --- a/modules/local/pixelator/single-cell/amplicon/main.nf +++ b/modules/local/pixelator/single-cell/amplicon/main.nf @@ -5,8 +5,8 @@ process PIXELATOR_AMPLICON { conda "bioconda::pixelator=0.18.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:0.18.2--pyhdfd78af_0' : - 'biocontainers/pixelator:0.18.2--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: tuple val(meta), path(reads) diff --git a/modules/local/pixelator/single-cell/analysis/main.nf b/modules/local/pixelator/single-cell/analysis/main.nf index 077fc1f4..9320c854 100644 --- a/modules/local/pixelator/single-cell/analysis/main.nf +++ b/modules/local/pixelator/single-cell/analysis/main.nf @@ -4,8 +4,8 @@ process PIXELATOR_ANALYSIS { conda "bioconda::pixelator=0.18.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:0.18.2--pyhdfd78af_0' : - 'biocontainers/pixelator:0.18.2--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: tuple val(meta), path(data) diff --git a/modules/local/pixelator/single-cell/annotate/main.nf b/modules/local/pixelator/single-cell/annotate/main.nf index 48e97194..7164fd38 100644 --- a/modules/local/pixelator/single-cell/annotate/main.nf +++ b/modules/local/pixelator/single-cell/annotate/main.nf @@ -5,8 +5,8 @@ process PIXELATOR_ANNOTATE { conda "bioconda::pixelator=0.18.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:0.18.2--pyhdfd78af_0' : - 'biocontainers/pixelator:0.18.2--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: tuple val(meta), path(dataset), path(panel_file), val(panel) diff --git a/modules/local/pixelator/single-cell/collapse/main.nf b/modules/local/pixelator/single-cell/collapse/main.nf index 0fbe600c..6ac95987 100644 --- a/modules/local/pixelator/single-cell/collapse/main.nf +++ b/modules/local/pixelator/single-cell/collapse/main.nf @@ -4,8 +4,8 @@ process PIXELATOR_COLLAPSE { conda "bioconda::pixelator=0.18.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:0.18.2--pyhdfd78af_0' : - 'biocontainers/pixelator:0.18.2--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: tuple val(meta), path(reads), path(panel_file), val(panel) diff --git a/modules/local/pixelator/single-cell/demux/main.nf b/modules/local/pixelator/single-cell/demux/main.nf index 29e9e769..a4c8f869 100644 --- a/modules/local/pixelator/single-cell/demux/main.nf +++ b/modules/local/pixelator/single-cell/demux/main.nf @@ -5,8 +5,8 @@ process PIXELATOR_DEMUX { conda "bioconda::pixelator=0.18.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:0.18.2--pyhdfd78af_0' : - 'biocontainers/pixelator:0.18.2--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: tuple val(meta), path(reads), path(panel_file), val(panel) diff --git a/modules/local/pixelator/single-cell/graph/main.nf b/modules/local/pixelator/single-cell/graph/main.nf index 4cd5db80..1b405436 100644 --- a/modules/local/pixelator/single-cell/graph/main.nf +++ b/modules/local/pixelator/single-cell/graph/main.nf @@ -5,8 +5,8 @@ process PIXELATOR_GRAPH { conda "bioconda::pixelator=0.18.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:0.18.2--pyhdfd78af_0' : - 'biocontainers/pixelator:0.18.2--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: tuple val(meta), path(edge_list) diff --git a/modules/local/pixelator/single-cell/layout/main.nf b/modules/local/pixelator/single-cell/layout/main.nf index ad2524ba..6b919137 100644 --- a/modules/local/pixelator/single-cell/layout/main.nf +++ b/modules/local/pixelator/single-cell/layout/main.nf @@ -5,8 +5,8 @@ process PIXELATOR_LAYOUT { conda "bioconda::pixelator=0.18.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:0.18.2--pyhdfd78af_0' : - 'biocontainers/pixelator:0.18.2--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: tuple val(meta), path(data) diff --git a/modules/local/pixelator/single-cell/qc/main.nf b/modules/local/pixelator/single-cell/qc/main.nf index 2184363f..68d3d454 100644 --- a/modules/local/pixelator/single-cell/qc/main.nf +++ b/modules/local/pixelator/single-cell/qc/main.nf @@ -5,8 +5,8 @@ process PIXELATOR_QC { conda "bioconda::pixelator=0.18.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:0.18.2--pyhdfd78af_0' : - 'biocontainers/pixelator:0.18.2--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: tuple val(meta), path(reads) diff --git a/modules/local/pixelator/single-cell/report/main.nf b/modules/local/pixelator/single-cell/report/main.nf index 11d73c21..517a0bbb 100644 --- a/modules/local/pixelator/single-cell/report/main.nf +++ b/modules/local/pixelator/single-cell/report/main.nf @@ -5,8 +5,8 @@ process PIXELATOR_REPORT { conda "bioconda::pixelator=0.18.2" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:0.18.2--pyhdfd78af_0' : - 'biocontainers/pixelator:0.18.2--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: tuple val(meta), path(panel_file), val(panel) diff --git a/nextflow.config b/nextflow.config index a7ae9710..6320c244 100644 --- a/nextflow.config +++ b/nextflow.config @@ -86,8 +86,7 @@ params { skip_layout = false // Main pixelator container override - // TODO: Remove this once the pixelator 0.19 is out - pixelator_container = "ghcr.io/pixelgentechnologies/pixelator:dev" + pixelator_container = null // Boilerplate options outdir = null From a580cdfead570ff9dcb043893cf13a7305c866c9 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 11 Dec 2024 09:41:51 +0100 Subject: [PATCH 23/70] Update nf-core subworkflows --- modules.json | 4 ++-- subworkflows/nf-core/utils_nextflow_pipeline/main.nf | 2 ++ .../tests/main.workflow.nf.test | 10 ++++++---- .../nf-core/utils_nfschema_plugin/tests/main.nf.test | 4 ++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/modules.json b/modules.json index 7c89a4f9..4e150dc1 100644 --- a/modules.json +++ b/modules.json @@ -16,7 +16,7 @@ "nf-core": { "utils_nextflow_pipeline": { "branch": "master", - "git_sha": "3aa0aec1d52d492fe241919f0c6100ebf0074082", + "git_sha": "c2b22d85f30a706a3073387f30380704fcae013b", "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { @@ -26,7 +26,7 @@ }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "bbd5a41f4535a8defafe6080e00ea74c45f4f96c", + "git_sha": "2fd2cd6d0e7b273747f32e465fdc6bcc3ae0814e", "installed_by": ["subworkflows"] } } diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf index 0fcbf7b3..d6e593e8 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf @@ -92,10 +92,12 @@ def checkCondaChannels() { channels = config.channels } catch (NullPointerException e) { + log.debug(e) log.warn("Could not verify conda channel configuration.") return null } catch (IOException e) { + log.debug(e) log.warn("Could not verify conda channel configuration.") return null } 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 ca964ce8..02dbf094 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 @@ -52,10 +52,12 @@ nextflow_workflow { } then { - assertAll( - { assert workflow.success }, - { assert workflow.stdout.contains("nextflow_workflow v9.9.9") } - ) + expect { + with(workflow) { + assert success + assert "nextflow_workflow v9.9.9" in stdout + } + } } } diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test b/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test index 842dc432..8fb30164 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test @@ -42,7 +42,7 @@ nextflow_workflow { params { test_data = '' - outdir = 1 + outdir = null } workflow { @@ -94,7 +94,7 @@ nextflow_workflow { params { test_data = '' - outdir = 1 + outdir = null } workflow { From 1811faa30b10c527158c6e325302860086d3f53a Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 11 Dec 2024 10:16:34 +0100 Subject: [PATCH 24/70] Reduce `--min-size` filter in test_panel_v2 profile --- conf/test_panel_v2.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/test_panel_v2.config b/conf/test_panel_v2.config index 7707d127..ccca0d59 100644 --- a/conf/test_panel_v2.config +++ b/conf/test_panel_v2.config @@ -31,7 +31,7 @@ params { input_basedir = params.pipelines_testdata_base_path + 'pixelator/testdata/' multiplet_recovery = true - min_size = 2 + min_size = 1 max_size = 100000 dynamic_filter = null compute_polarization = true From f6f937dfeb8824049128af7a766bb3fedfff1b6e Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 11 Dec 2024 10:33:00 +0100 Subject: [PATCH 25/70] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 831f1174..08fad568 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [[PR #112](https://github.com/nf-core/pixelator/pull/112)] - Add graph refinement options for pixelator 0.19 - [[PR #113](https://github.com/nf-core/pixelator/pull/113)] - Fix validation issues after nf-core/tools v3.0.2 update - [[PR #114](https://github.com/nf-core/pixelator/pull/114)] - Remove `--save_recovered_components` options for graph outputs +- [[PR #115](https://github.com/nf-core/pixelator/pull/115)] - Update containers for pixelator 0.19 ### Parameters From 1559e09d380faf1d2150f2803ed32617f82ecf07 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 11 Dec 2024 11:43:36 +0100 Subject: [PATCH 26/70] Bump version from 1.4.0dev to 1.4.0 --- nextflow.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index 6320c244..8c0a8246 100644 --- a/nextflow.config +++ b/nextflow.config @@ -300,7 +300,7 @@ manifest { description = """Pipeline for analysis of Molecular Pixelation assays""" mainScript = 'main.nf' nextflowVersion = '!>=24.04.2' - version = '1.4.0dev' + version = '1.4.0' doi = '10.1101/2023.06.05.543770' } From f36120b0dfd7894cf02dd5d9d91d6d20467d0031 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Thu, 12 Dec 2024 11:25:32 +0000 Subject: [PATCH 27/70] Template update for nf-core/tools version 3.1.0 --- .github/CONTRIBUTING.md | 14 +- .github/workflows/awsfulltest.yml | 21 +- .github/workflows/branch.yml | 18 +- .github/workflows/ci.yml | 2 +- .github/workflows/download_pipeline.yml | 8 +- .github/workflows/fix-linting.yml | 4 +- .github/workflows/linting.yml | 10 +- .github/workflows/linting_comment.yml | 2 +- .github/workflows/release-announcements.yml | 2 +- .../workflows/template_version_comment.yml | 2 +- .gitpod.yml | 11 +- .nf-core.yml | 12 +- .vscode/settings.json | 3 + CITATIONS.md | 8 - README.md | 3 - assets/methods_description_template.yml | 29 -- assets/multiqc_config.yml | 15 - assets/sendmail_template.txt | 22 - conf/base.config | 2 +- conf/igenomes.config | 440 ------------------ conf/igenomes_ignored.config | 9 - conf/modules.config | 12 - conf/test.config | 3 +- conf/test_full.config | 4 +- docs/output.md | 33 +- docs/usage.md | 37 +- main.nf | 16 - modules.json | 19 +- modules/nf-core/fastqc/environment.yml | 5 - modules/nf-core/fastqc/main.nf | 64 --- modules/nf-core/fastqc/meta.yml | 66 --- modules/nf-core/fastqc/tests/main.nf.test | 309 ------------ .../nf-core/fastqc/tests/main.nf.test.snap | 392 ---------------- modules/nf-core/fastqc/tests/tags.yml | 2 - modules/nf-core/multiqc/environment.yml | 5 - modules/nf-core/multiqc/main.nf | 63 --- modules/nf-core/multiqc/meta.yml | 78 ---- modules/nf-core/multiqc/tests/main.nf.test | 92 ---- .../nf-core/multiqc/tests/main.nf.test.snap | 41 -- modules/nf-core/multiqc/tests/nextflow.config | 5 - modules/nf-core/multiqc/tests/tags.yml | 2 - nextflow.config | 60 +-- nextflow_schema.json | 80 +--- ro-crate-metadata.json | 299 ++++++++++++ .../utils_nfcore_pixelator_pipeline/main.nf | 47 +- .../nf-core/utils_nextflow_pipeline/main.nf | 2 + .../tests/main.workflow.nf.test | 10 +- .../nf-core/utils_nfcore_pipeline/main.nf | 89 +--- .../tests/main.function.nf.test | 46 +- .../tests/main.function.nf.test.snap | 30 -- .../utils_nfschema_plugin/tests/main.nf.test | 4 +- tower.yml | 2 - workflows/pixelator.nf | 56 +-- 53 files changed, 480 insertions(+), 2130 deletions(-) create mode 100644 .vscode/settings.json delete mode 100644 assets/methods_description_template.yml delete mode 100644 assets/multiqc_config.yml delete mode 100644 conf/igenomes.config delete mode 100644 conf/igenomes_ignored.config delete mode 100644 modules/nf-core/fastqc/environment.yml delete mode 100644 modules/nf-core/fastqc/main.nf delete mode 100644 modules/nf-core/fastqc/meta.yml delete mode 100644 modules/nf-core/fastqc/tests/main.nf.test delete mode 100644 modules/nf-core/fastqc/tests/main.nf.test.snap delete mode 100644 modules/nf-core/fastqc/tests/tags.yml delete mode 100644 modules/nf-core/multiqc/environment.yml delete mode 100644 modules/nf-core/multiqc/main.nf delete mode 100644 modules/nf-core/multiqc/meta.yml delete mode 100644 modules/nf-core/multiqc/tests/main.nf.test delete mode 100644 modules/nf-core/multiqc/tests/main.nf.test.snap delete mode 100644 modules/nf-core/multiqc/tests/nextflow.config delete mode 100644 modules/nf-core/multiqc/tests/tags.yml create mode 100644 ro-crate-metadata.json diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 7c5b2c19..e091e270 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# nf-core/pixelator: Contributing Guidelines +# `nf-core/pixelator`: Contributing Guidelines Hi there! Many thanks for taking an interest in improving nf-core/pixelator. @@ -55,9 +55,9 @@ These tests are run both with the latest available version of `Nextflow` and als :warning: Only in the unlikely and regretful event of a release happening with a bug. -- On your own fork, make a new branch `patch` based on `upstream/master`. +- On your own fork, make a new branch `patch` based on `upstream/main` or `upstream/master`. - Fix the bug, and bump version (X.Y.Z+1). -- A PR should be made on `master` from patch to directly this particular bug. +- Open a pull-request from `patch` to `main`/`master` with the changes. ## Getting help @@ -65,13 +65,13 @@ For further information/help, please consult the [nf-core/pixelator documentatio ## Pipeline contribution conventions -To make the nf-core/pixelator code and processing logic more understandable for new contributors and to ensure quality, we semi-standardise the way the code and other contributions are written. +To make the `nf-core/pixelator` code and processing logic more understandable for new contributors and to ensure quality, we semi-standardise the way the code and other contributions are written. ### Adding a new step If you wish to contribute a new step, please use the following coding standards: -1. Define the corresponding input channel into your new process from the expected previous process channel +1. Define the corresponding input channel into your new process from the expected previous process channel. 2. Write the process block (see below). 3. Define the output channel if needed (see below). 4. Add any new parameters to `nextflow.config` with a default (see below). @@ -79,12 +79,10 @@ If you wish to contribute a new step, please use the following coding standards: 6. Add sanity checks and validation for all relevant parameters. 7. Perform local tests to validate that the new code works as expected. 8. If applicable, add a new test command in `.github/workflow/ci.yml`. -9. Update MultiQC config `assets/multiqc_config.yml` so relevant suffixes, file name clean up and module plots are in the appropriate order. If applicable, add a [MultiQC](https://https://multiqc.info/) module. -10. Add a description of the output files and if relevant any appropriate images from the MultiQC report to `docs/output.md`. ### Default values -Parameters should be initialised / defined with default values in `nextflow.config` under the `params` scope. +Parameters should be initialised / defined with default values within the `params` scope in `nextflow.config`. Once there, use `nf-core pipelines schema build` to add to `nextflow_schema.json`. diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 8f21bb1c..3d81614f 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -1,11 +1,12 @@ name: nf-core AWS full size tests -# This workflow is triggered on PRs opened against the master branch. +# This workflow is triggered on PRs opened against the main/master branch. # It can be additionally triggered manually with GitHub actions workflow dispatch button. # It runs the -profile 'test_full' on AWS batch on: pull_request: branches: + - main - master workflow_dispatch: pull_request_review: @@ -18,18 +19,30 @@ jobs: if: github.repository == 'nf-core/pixelator' && github.event.review.state == 'approved' && github.event.pull_request.base.ref == 'master' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest steps: - - uses: octokit/request-action@v2.x + - name: Get PR reviews + uses: octokit/request-action@v2.x + if: github.event_name != 'workflow_dispatch' id: check_approvals + continue-on-error: true with: - route: GET /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews + route: GET /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews?per_page=100 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - id: test_variables + + - name: Check for approvals + if: ${{ failure() && github.event_name != 'workflow_dispatch' }} + run: | + echo "No review approvals found. At least 2 approvals are required to run this action automatically." + exit 1 + + - name: Check for enough approvals (>=2) + id: test_variables if: github.event_name != 'workflow_dispatch' run: | JSON_RESPONSE='${{ steps.check_approvals.outputs.data }}' CURRENT_APPROVALS_COUNT=$(echo $JSON_RESPONSE | jq -c '[.[] | select(.state | contains("APPROVED")) ] | length') test $CURRENT_APPROVALS_COUNT -ge 2 || exit 1 # At least 2 approvals are required + - name: Launch workflow via Seqera Platform uses: seqeralabs/action-tower-launch@v2 # TODO nf-core: You can customise AWS full pipeline tests as required diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index a4b89fd4..0e3d6360 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -1,15 +1,17 @@ name: nf-core branch protection -# This workflow is triggered on PRs to master branch on the repository -# It fails when someone tries to make a PR against the nf-core `master` branch instead of `dev` +# This workflow is triggered on PRs to `main`/`master` branch on the repository +# It fails when someone tries to make a PR against the nf-core `main`/`master` branch instead of `dev` on: pull_request_target: - branches: [master] + branches: + - main + - master jobs: test: runs-on: ubuntu-latest steps: - # PRs to the nf-core repo master branch are only ok if coming from the nf-core repo `dev` or any `patch` branches + # PRs to the nf-core repo main/master branch are only ok if coming from the nf-core repo `dev` or any `patch` branches - name: Check PRs if: github.repository == 'nf-core/pixelator' run: | @@ -22,7 +24,7 @@ jobs: uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 with: message: | - ## This PR is against the `master` branch :x: + ## This PR is against the `${{github.event.pull_request.base.ref}}` branch :x: * Do not close this PR * Click _Edit_ and change the `base` to `dev` @@ -32,9 +34,9 @@ jobs: Hi @${{ github.event.pull_request.user.login }}, - It looks like this pull-request is has been made against the [${{github.event.pull_request.head.repo.full_name }}](https://github.com/${{github.event.pull_request.head.repo.full_name }}) `master` branch. - The `master` branch on nf-core repositories should always contain code from the latest release. - Because of this, PRs to `master` are only allowed if they come from the [${{github.event.pull_request.head.repo.full_name }}](https://github.com/${{github.event.pull_request.head.repo.full_name }}) `dev` branch. + It looks like this pull-request is has been made against the [${{github.event.pull_request.head.repo.full_name }}](https://github.com/${{github.event.pull_request.head.repo.full_name }}) ${{github.event.pull_request.base.ref}} branch. + The ${{github.event.pull_request.base.ref}} branch on nf-core repositories should always contain code from the latest release. + Because of this, PRs to ${{github.event.pull_request.base.ref}} are only allowed if they come from the [${{github.event.pull_request.head.repo.full_name }}](https://github.com/${{github.event.pull_request.head.repo.full_name }}) `dev` branch. You do not need to close this PR, you can change the target branch to `dev` by clicking the _"Edit"_ button at the top of this page. Note that even after this, the test will continue to show as failing until you push a new commit. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb74d479..1abe6193 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,7 @@ jobs: profile: "singularity" steps: - name: Check out pipeline code - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Set up Nextflow uses: nf-core/setup-nextflow@v2 diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml index 713dc3e7..2576cc0c 100644 --- a/.github/workflows/download_pipeline.yml +++ b/.github/workflows/download_pipeline.yml @@ -2,7 +2,7 @@ name: Test successful pipeline download with 'nf-core pipelines download' # Run the workflow when: # - dispatched manually -# - when a PR is opened or reopened to master branch +# - when a PR is opened or reopened to main/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: @@ -17,9 +17,11 @@ on: - edited - synchronize branches: + - main - master pull_request_target: branches: + - main - master env: @@ -35,7 +37,7 @@ jobs: - name: Disk space cleanup uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 - - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 + - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5 with: python-version: "3.12" architecture: "x64" @@ -69,7 +71,7 @@ jobs: --outdir ./${{ env.REPOTITLE_LOWERCASE }} \ --compress "none" \ --container-system 'singularity' \ - --container-library "quay.io" -l "docker.io" -l "community.wave.seqera.io" \ + --container-library "quay.io" -l "docker.io" -l "community.wave.seqera.io/library/" \ --container-cache-utilisation 'amend' \ --download-configuration 'yes' diff --git a/.github/workflows/fix-linting.yml b/.github/workflows/fix-linting.yml index 350811c0..c13cea31 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@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: token: ${{ secrets.nf_core_bot_auth_token }} @@ -32,7 +32,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.nf_core_bot_auth_token }} # Install and run pre-commit - - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 + - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5 with: python-version: "3.12" diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index a502573c..dbd52d5a 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@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Set up Python 3.12 - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5 with: python-version: "3.12" @@ -31,12 +31,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out pipeline code - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Install Nextflow uses: nf-core/setup-nextflow@v2 - - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 + - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5 with: python-version: "3.12" architecture: "x64" @@ -74,7 +74,7 @@ jobs: - name: Upload linting log file artifact if: ${{ always() }} - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4 with: name: linting-logs path: | diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index 42e519bf..0bed96d3 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@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6 + uses: dawidd6/action-download-artifact@80620a5d27ce0ae443b965134db88467fc607b43 # v7 with: workflow: linting.yml workflow_conclusion: completed diff --git a/.github/workflows/release-announcements.yml b/.github/workflows/release-announcements.yml index c6ba35df..450b1d5e 100644 --- a/.github/workflows/release-announcements.yml +++ b/.github/workflows/release-announcements.yml @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 + - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5 with: python-version: "3.10" - name: Install dependencies diff --git a/.github/workflows/template_version_comment.yml b/.github/workflows/template_version_comment.yml index e8aafe44..537529bc 100644 --- a/.github/workflows/template_version_comment.yml +++ b/.github/workflows/template_version_comment.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out pipeline code - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: ref: ${{ github.event.pull_request.head.sha }} diff --git a/.gitpod.yml b/.gitpod.yml index 46118637..83599f63 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -6,12 +6,5 @@ tasks: nextflow self-update vscode: - extensions: # based on nf-core.nf-core-extensionpack - #- esbenp.prettier-vscode # Markdown/CommonMark linting and style checking for Visual Studio Code - - 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 - - oderwat.indent-rainbow # Highlight indentation level - - streetsidesoftware.code-spell-checker # Spelling checker for source code - - charliermarsh.ruff # Code linter Ruff + extensions: + - nf-core.nf-core-extensionpack # https://github.com/nf-core/vscode-extensionpack diff --git a/.nf-core.yml b/.nf-core.yml index b18db0bf..fad0297f 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -1,11 +1,11 @@ -bump_version: null lint: files_exist: - assets/multiqc_config.yml - conf/igenomes.config + files_unchanged: + - assets/nf-core-pixelator_logo_light.png multiqc_config: false -nf_core_version: 3.0.2 -org_path: null +nf_core_version: 3.1.0 repository_type: pipeline template: author: Pixelgen Technologies AB @@ -15,6 +15,8 @@ template: name: pixelator org: nf-core outdir: . - skip_features: null + skip_features: + - fastqc + - multiqc + - igenomes version: 1.3.1 -update: null diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..a33b527c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "markdown.styles": ["public/vscode_markdown.css"] +} diff --git a/CITATIONS.md b/CITATIONS.md index d2fcc108..4a9a8d3d 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -10,14 +10,6 @@ ## Pipeline tools -- [FastQC](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/) - -> 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 - [Anaconda](https://anaconda.com) diff --git a/README.md b/README.md index ed807c37..539057b6 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,6 @@ workflows use the "tube map" design for that. See https://nf-co.re/docs/contributing/design_guidelines#examples for examples. --> -1. Read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/)) -2. Present QC for raw reads ([`MultiQC`](http://multiqc.info/)) - ## Usage > [!NOTE] diff --git a/assets/methods_description_template.yml b/assets/methods_description_template.yml deleted file mode 100644 index 2b6ed3cd..00000000 --- a/assets/methods_description_template.yml +++ /dev/null @@ -1,29 +0,0 @@ -id: "nf-core-pixelator-methods-description" -description: "Suggested text and references to use when describing pipeline usage within the methods section of a publication." -section_name: "nf-core/pixelator Methods Description" -section_href: "https://github.com/nf-core/pixelator" -plot_type: "html" -## 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/pixelator 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. 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:
    -
      - ${nodoi_text} -
    • The command above does not include parameters contained in any configs or profiles that may have been used. Ensure the config file is also uploaded with your publication!
    • -
    • You should also cite all software used within this run. Check the "Software Versions" of this report to get version information.
    • -
    -
    diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml deleted file mode 100644 index adefdf6c..00000000 --- a/assets/multiqc_config.yml +++ /dev/null @@ -1,15 +0,0 @@ -report_comment: > - This report has been generated by the nf-core/pixelator - analysis pipeline. For information about how to interpret these results, please see the - documentation. -report_section_order: - "nf-core-pixelator-methods-description": - order: -1000 - software_versions: - order: -1001 - "nf-core-pixelator-summary": - order: -1002 - -export_plots: true - -disable_version_detection: true diff --git a/assets/sendmail_template.txt b/assets/sendmail_template.txt index 5a184630..6792160f 100644 --- a/assets/sendmail_template.txt +++ b/assets/sendmail_template.txt @@ -26,28 +26,6 @@ Content-Disposition: inline; filename="nf-core-pixelator_logo_light.png" join( '\n' ) %> <% -if (mqcFile){ -def mqcFileObj = new File("$mqcFile") -if (mqcFileObj.length() < mqcMaxSize){ -out << """ ---nfcoremimeboundary -Content-Type: text/html; name=\"multiqc_report\" -Content-Transfer-Encoding: base64 -Content-ID: -Content-Disposition: attachment; filename=\"${mqcFileObj.getName()}\" - -${mqcFileObj. - bytes. - encodeBase64(). - toString(). - tokenize( '\n' )*. - toList()*. - collate( 76 )*. - collect { it.join() }. - flatten(). - join( '\n' )} -""" -}} %> --nfcoremimeboundary-- diff --git a/conf/base.config b/conf/base.config index 11eeb9e5..9029cad3 100644 --- a/conf/base.config +++ b/conf/base.config @@ -20,7 +20,7 @@ process { maxErrors = '-1' // Process-specific resource requirements - // NOTE - Please try and re-use the labels below as much as possible. + // NOTE - Please try and reuse the labels below as much as possible. // These labels are used and recognised by default in DSL2 files hosted on nf-core/modules. // If possible, it would be nice to keep the same label naming convention when // adding in your local modules too. diff --git a/conf/igenomes.config b/conf/igenomes.config deleted file mode 100644 index 3f114377..00000000 --- a/conf/igenomes.config +++ /dev/null @@ -1,440 +0,0 @@ -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Nextflow config file for iGenomes paths -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Defines reference genomes using iGenome paths. - Can be used by any config that customises the base path using: - $params.igenomes_base / --igenomes_base ----------------------------------------------------------------------------------------- -*/ - -params { - // illumina iGenomes reference file paths - genomes { - 'GRCh37' { - fasta = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/README.txt" - mito_name = "MT" - macs_gsize = "2.7e9" - blacklist = "${projectDir}/assets/blacklists/GRCh37-blacklist.bed" - } - 'GRCh38' { - fasta = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Annotation/Genes/genes.bed" - mito_name = "chrM" - 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/" - bowtie2 = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/README.txt" - mito_name = "MT" - macs_gsize = "1.87e9" - blacklist = "${projectDir}/assets/blacklists/GRCm38-blacklist.bed" - } - 'TAIR10' { - fasta = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/README.txt" - mito_name = "Mt" - } - 'EB2' { - fasta = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/README.txt" - } - 'UMD3.1' { - fasta = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/README.txt" - mito_name = "MT" - } - 'WBcel235' { - fasta = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.bed" - mito_name = "MtDNA" - macs_gsize = "9e7" - } - 'CanFam3.1' { - fasta = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/README.txt" - mito_name = "MT" - } - 'GRCz10' { - fasta = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.bed" - mito_name = "MT" - } - 'BDGP6' { - fasta = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.bed" - mito_name = "M" - macs_gsize = "1.2e8" - } - 'EquCab2' { - fasta = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/README.txt" - mito_name = "MT" - } - 'EB1' { - fasta = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/README.txt" - } - 'Galgal4' { - fasta = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.bed" - mito_name = "MT" - } - 'Gm01' { - fasta = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/README.txt" - } - 'Mmul_1' { - fasta = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/README.txt" - mito_name = "MT" - } - 'IRGSP-1.0' { - fasta = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.bed" - mito_name = "Mt" - } - 'CHIMP2.1.4' { - fasta = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/README.txt" - mito_name = "MT" - } - 'Rnor_5.0' { - fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Annotation/Genes/genes.bed" - mito_name = "MT" - } - 'Rnor_6.0' { - fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.bed" - mito_name = "MT" - } - 'R64-1-1' { - fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.bed" - mito_name = "MT" - macs_gsize = "1.2e7" - } - 'EF2' { - fasta = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/README.txt" - mito_name = "MT" - macs_gsize = "1.21e7" - } - 'Sbi1' { - fasta = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/README.txt" - } - 'Sscrofa10.2' { - fasta = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/README.txt" - mito_name = "MT" - } - 'AGPv3' { - fasta = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.bed" - mito_name = "Mt" - } - 'hg38' { - fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Annotation/Genes/genes.bed" - mito_name = "chrM" - macs_gsize = "2.7e9" - blacklist = "${projectDir}/assets/blacklists/hg38-blacklist.bed" - } - 'hg19' { - fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/README.txt" - mito_name = "chrM" - macs_gsize = "2.7e9" - blacklist = "${projectDir}/assets/blacklists/hg19-blacklist.bed" - } - 'mm10' { - fasta = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/README.txt" - mito_name = "chrM" - macs_gsize = "1.87e9" - blacklist = "${projectDir}/assets/blacklists/mm10-blacklist.bed" - } - 'bosTau8' { - fasta = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Annotation/Genes/genes.bed" - mito_name = "chrM" - } - 'ce10' { - fasta = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/README.txt" - mito_name = "chrM" - macs_gsize = "9e7" - } - 'canFam3' { - fasta = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/README.txt" - mito_name = "chrM" - } - 'danRer10' { - fasta = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Annotation/Genes/genes.bed" - mito_name = "chrM" - macs_gsize = "1.37e9" - } - 'dm6' { - fasta = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Annotation/Genes/genes.bed" - mito_name = "chrM" - macs_gsize = "1.2e8" - } - 'equCab2' { - fasta = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/README.txt" - mito_name = "chrM" - } - 'galGal4' { - fasta = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/README.txt" - mito_name = "chrM" - } - 'panTro4' { - fasta = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/README.txt" - mito_name = "chrM" - } - 'rn6' { - fasta = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Annotation/Genes/genes.bed" - mito_name = "chrM" - } - 'sacCer3' { - fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BismarkIndex/" - readme = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Annotation/README.txt" - mito_name = "chrM" - macs_gsize = "1.2e7" - } - 'susScr3' { - fasta = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/README.txt" - mito_name = "chrM" - } - } -} diff --git a/conf/igenomes_ignored.config b/conf/igenomes_ignored.config deleted file mode 100644 index b4034d82..00000000 --- a/conf/igenomes_ignored.config +++ /dev/null @@ -1,9 +0,0 @@ -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Nextflow config file for iGenomes paths -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Empty genomes dictionary to use when igenomes is ignored. ----------------------------------------------------------------------------------------- -*/ - -params.genomes = [:] diff --git a/conf/modules.config b/conf/modules.config index d266a387..e27fd282 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -18,16 +18,4 @@ process { saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] - withName: FASTQC { - ext.args = '--quiet' - } - withName: 'MULTIQC' { - ext.args = { params.multiqc_title ? "--title \"$params.multiqc_title\"" : '' } - publishDir = [ - path: { "${params.outdir}/multiqc" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - } diff --git a/conf/test.config b/conf/test.config index e2f55d9a..5e51871f 100644 --- a/conf/test.config +++ b/conf/test.config @@ -27,6 +27,5 @@ params { // TODO nf-core: Give any required params for the test so that command line flags are not needed 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 b8f7cf2a..54efb7a8 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -19,6 +19,6 @@ params { // TODO nf-core: Give any required params for the test so that command line flags are not needed input = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_full_illumina_amplicon.csv' - // Genome references - genome = 'R64-1-1' + // Fasta references + fasta = params.pipelines_testdata_base_path + 'viralrecon/genome/NC_045512.2/GCF_009858895.2_ASM985889v3_genomic.200409.fna.gz' } diff --git a/docs/output.md b/docs/output.md index 58af8fd6..368739f9 100644 --- a/docs/output.md +++ b/docs/output.md @@ -2,7 +2,7 @@ ## Introduction -This document describes the output produced by the pipeline. Most of the plots are taken from the MultiQC report, which summarises results at the end of the pipeline. +This document describes the output produced by the pipeline. 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. @@ -12,39 +12,8 @@ The directories listed below will be created in the results directory after the The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes data using the following steps: -- [FastQC](#fastqc) - Raw read QC -- [MultiQC](#multiqc) - Aggregate report describing results and QC from the whole pipeline - [Pipeline information](#pipeline-information) - Report metrics generated during the workflow execution -### FastQC - -
    -Output files - -- `fastqc/` - - `*_fastqc.html`: FastQC report containing quality metrics. - - `*_fastqc.zip`: Zip archive containing the FastQC report, tab-delimited data file and plot images. - -
    - -[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 - -
    -Output files - -- `multiqc/` - - `multiqc_report.html`: a standalone HTML file that can be viewed in your web browser. - - `multiqc_data/`: directory containing parsed statistics from the different tools used in the pipeline. - - `multiqc_plots/`: directory containing static images from the report in various formats. - -
    - -[MultiQC](http://multiqc.info) is a visualization tool that generates a single HTML report summarising all samples in your project. Most of the pipeline QC results are visualised in the report and further statistics are available in the report data directory. - -Results generated by MultiQC collate pipeline QC from supported tools e.g. FastQC. The pipeline has special steps which also allow the software versions to be reported in the MultiQC output for future traceability. For more information about how to use MultiQC reports, see . - ### Pipeline information
    diff --git a/docs/usage.md b/docs/usage.md index 938053d7..5b2b5a27 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/pixelator --input ./samplesheet.csv --outdir ./results --genome GRCh37 -profile docker +nextflow run nf-core/pixelator --input ./samplesheet.csv --outdir ./results -profile docker ``` This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. @@ -75,9 +75,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: @@ -90,7 +89,6 @@ with: ```yaml title="params.yaml" input: './samplesheet.csv' outdir: './results/' -genome: 'GRCh37' <...> ``` @@ -106,23 +104,21 @@ nextflow pull nf-core/pixelator ### Reproducibility -It is 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. +It is a good idea to specify the 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/pixelator releases page](https://github.com/nf-core/pixelator/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. +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. -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. +To further assist in reproducibility, you can use share and reuse [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. ## 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` @@ -130,16 +126,15 @@ 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. -::: +> [!IMPORTANT] +> 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). +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 check if your system is suported, please see the [nf-core/configs documentation](https://github.com/nf-core/configs#documentation). Note that multiple profiles can be loaded, for example: `-profile test,docker` - the order of arguments is important! They are loaded in sequence, so later profiles can overwrite earlier profiles. -If `-profile` is not specified, the pipeline will run locally and expect all software to be installed and available on the `PATH`. This is _not_ recommended, since it can lead to different results on different machines dependent on the computer enviroment. +If `-profile` is not specified, the pipeline will run locally and expect all software to be installed and available on the `PATH`. This is _not_ recommended, since it can lead to different results on different machines dependent on the computer environment. - `test` - A profile with a complete configuration for automated testing @@ -175,13 +170,13 @@ Specify the path to a specific config file (this is a core Nextflow command). Se ### Resource requests -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. +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 pipeline steps, 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 resources request (2 x original, then 3 x original). If it still fails after the third attempt then the pipeline execution is stopped. 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. ### Custom Containers -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. +In some cases, you may wish to change the container or conda environment used by a pipeline steps 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. 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. diff --git a/main.nf b/main.nf index 6ad8c060..486f4f31 100644 --- a/main.nf +++ b/main.nf @@ -18,19 +18,6 @@ include { PIXELATOR } from './workflows/pixelator' include { PIPELINE_INITIALISATION } from './subworkflows/local/utils_nfcore_pixelator_pipeline' include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_pixelator_pipeline' -include { getGenomeAttribute } from './subworkflows/local/utils_nfcore_pixelator_pipeline' - -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - GENOME PARAMETER VALUES -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - -// 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 WORKFLOWS FOR PIPELINE @@ -53,8 +40,6 @@ workflow NFCORE_PIXELATOR { PIXELATOR ( samplesheet ) - emit: - multiqc_report = PIXELATOR.out.multiqc_report // channel: /path/to/multiqc_report.html } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -93,7 +78,6 @@ workflow { params.outdir, params.monochrome_logs, params.hook_url, - NFCORE_PIXELATOR.out.multiqc_report ) } diff --git a/modules.json b/modules.json index 3453e2aa..3fffd959 100644 --- a/modules.json +++ b/modules.json @@ -4,34 +4,23 @@ "repos": { "https://github.com/nf-core/modules.git": { "modules": { - "nf-core": { - "fastqc": { - "branch": "master", - "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", - "installed_by": ["modules"] - }, - "multiqc": { - "branch": "master", - "git_sha": "cf17ca47590cc578dfb47db1c2a44ef86f89976d", - "installed_by": ["modules"] - } - } + "nf-core": {} }, "subworkflows": { "nf-core": { "utils_nextflow_pipeline": { "branch": "master", - "git_sha": "3aa0aec1d52d492fe241919f0c6100ebf0074082", + "git_sha": "c2b22d85f30a706a3073387f30380704fcae013b", "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "1b6b9a3338d011367137808b49b923515080e3ba", + "git_sha": "51ae5406a030d4da1e49e4dab49756844fdd6c7a", "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "bbd5a41f4535a8defafe6080e00ea74c45f4f96c", + "git_sha": "2fd2cd6d0e7b273747f32e465fdc6bcc3ae0814e", "installed_by": ["subworkflows"] } } diff --git a/modules/nf-core/fastqc/environment.yml b/modules/nf-core/fastqc/environment.yml deleted file mode 100644 index 691d4c76..00000000 --- a/modules/nf-core/fastqc/environment.yml +++ /dev/null @@ -1,5 +0,0 @@ -channels: - - conda-forge - - bioconda -dependencies: - - bioconda::fastqc=0.12.1 diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf deleted file mode 100644 index d8989f48..00000000 --- a/modules/nf-core/fastqc/main.nf +++ /dev/null @@ -1,64 +0,0 @@ -process FASTQC { - 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/fastqc:0.12.1--hdfd78af_0' : - 'biocontainers/fastqc:0.12.1--hdfd78af_0' }" - - input: - tuple val(meta), path(reads) - - output: - tuple val(meta), path("*.html"), emit: html - tuple val(meta), path("*.zip") , emit: zip - 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}" - // 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(' ') - - // The total amount of allocated RAM by FastQC is equal to the number of threads defined (--threads) time the amount of RAM defined (--memory) - // https://github.com/s-andrews/FastQC/blob/1faeea0412093224d7f6a07f777fad60a5650795/fastqc#L211-L222 - // Dividing the task.memory by task.cpu allows to stick to requested amount of RAM in the label - def memory_in_mb = MemoryUnit.of("${task.memory}").toUnit('MB') / task.cpus - // 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 - done - - fastqc \\ - $args \\ - --threads $task.cpus \\ - --memory $fastqc_memory \\ - $renamed_files - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - fastqc: \$( fastqc --version | sed '/FastQC v/!d; s/.*v//' ) - END_VERSIONS - """ - - stub: - def prefix = task.ext.prefix ?: "${meta.id}" - """ - touch ${prefix}.html - touch ${prefix}.zip - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - 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 deleted file mode 100644 index 4827da7a..00000000 --- a/modules/nf-core/fastqc/meta.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: fastqc -description: Run FastQC on sequenced reads -keywords: - - quality control - - qc - - adapters - - fastq -tools: - - fastqc: - description: | - FastQC gives general quality metrics about your reads. - It provides information about the quality score distribution - across your reads, the per base sequence content (%A/C/G/T). - You get information about adapter contamination and other - overrepresented sequences. - homepage: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/ - documentation: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/ - licence: ["GPL-2.0-only"] - identifier: biotools:fastqc -input: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - reads: - type: file - description: | - List of input FastQ files of size 1 and 2 for single-end and paired-end data, - respectively. -output: - - html: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - "*.html": - type: file - description: FastQC report - pattern: "*_{fastqc.html}" - - zip: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - "*.zip": - type: file - description: FastQC report archive - pattern: "*_{fastqc.zip}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" -authors: - - "@drpatelh" - - "@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 deleted file mode 100644 index e9d79a07..00000000 --- a/modules/nf-core/fastqc/tests/main.nf.test +++ /dev/null @@ -1,309 +0,0 @@ -nextflow_process { - - name "Test Process FASTQC" - script "../main.nf" - process "FASTQC" - - tag "modules" - tag "modules_nfcore" - tag "fastqc" - - test("sarscov2 single-end [fastq]") { - - 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 }, - // 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("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - 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("File typeConventional base calls") }, - { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - 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("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - 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("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - 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("File typeConventional base calls") }, - { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][2]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][3]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - 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("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - 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).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 deleted file mode 100644 index d5db3092..00000000 --- a/modules/nf-core/fastqc/tests/main.nf.test.snap +++ /dev/null @@ -1,392 +0,0 @@ -{ - "sarscov2 custom_prefix": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:16.374038" - }, - "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]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:01:42.355718" - }, - "sarscov2 paired-end [bam]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:01:53.276274" - }, - "sarscov2 multiple [fastq]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:05.527626" - }, - "sarscov2 paired-end [fastq]": { - "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" - }, - "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-07-22T11:03:02.304411" - }, - "sarscov2 single-end [fastq]": { - "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" - }, - "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-07-22T11:02:53.550742" - } -} \ No newline at end of file diff --git a/modules/nf-core/fastqc/tests/tags.yml b/modules/nf-core/fastqc/tests/tags.yml deleted file mode 100644 index 7834294b..00000000 --- a/modules/nf-core/fastqc/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -fastqc: - - modules/nf-core/fastqc/** diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml deleted file mode 100644 index 6f5b867b..00000000 --- a/modules/nf-core/multiqc/environment.yml +++ /dev/null @@ -1,5 +0,0 @@ -channels: - - conda-forge - - bioconda -dependencies: - - bioconda::multiqc=1.25.1 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf deleted file mode 100644 index cc0643e1..00000000 --- a/modules/nf-core/multiqc/main.nf +++ /dev/null @@ -1,63 +0,0 @@ -process MULTIQC { - label 'process_single' - - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.25.1--pyhdfd78af_0' : - 'biocontainers/multiqc:1.25.1--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 - path "*_data" , emit: data - path "*_plots" , optional:true, emit: plots - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ? "--filename ${task.ext.prefix}.html" : '' - 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 \\ - $args \\ - $config \\ - $prefix \\ - $extra_config \\ - $logo \\ - $replace \\ - $samples \\ - . - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) - END_VERSIONS - """ - - stub: - """ - mkdir multiqc_data - mkdir multiqc_plots - touch multiqc_report.html - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) - END_VERSIONS - """ -} diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml deleted file mode 100644 index b16c1879..00000000 --- a/modules/nf-core/multiqc/meta.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: multiqc -description: Aggregate results from bioinformatics analyses across many samples into - a single report -keywords: - - QC - - bioinformatics tools - - Beautiful stand-alone HTML report -tools: - - multiqc: - description: | - MultiQC searches a given directory for analysis logs and compiles a HTML report. - It's a general use tool, perfect for summarising the output from numerous bioinformatics tools. - homepage: https://multiqc.info/ - documentation: https://multiqc.info/docs/ - licence: ["GPL-3.0-or-later"] - identifier: biotools:multiqc -input: - - - multiqc_files: - type: file - description: | - List of reports / files recognised by MultiQC, for example the html and zip output of FastQC - - - multiqc_config: - type: file - description: Optional config yml for MultiQC - pattern: "*.{yml,yaml}" - - - extra_multiqc_config: - type: file - description: Second optional config yml for MultiQC. Will override common sections - in multiqc_config. - pattern: "*.{yml,yaml}" - - - multiqc_logo: - 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: - - "*multiqc_report.html": - type: file - description: MultiQC report file - pattern: "multiqc_report.html" - - data: - - "*_data": - type: directory - description: MultiQC data dir - pattern: "multiqc_data" - - plots: - - "*_plots": - type: file - description: Plots created by MultiQC - pattern: "*_data" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" -authors: - - "@abhi18av" - - "@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 deleted file mode 100644 index 33316a7d..00000000 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ /dev/null @@ -1,92 +0,0 @@ -nextflow_process { - - name "Test Process MULTIQC" - script "../main.nf" - process "MULTIQC" - - tag "modules" - tag "modules_nfcore" - tag "multiqc" - - config "./nextflow.config" - - test("sarscov2 single-end [fastqc]") { - - when { - process { - """ - 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] = [] - input[4] = [] - input[5] = [] - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, - { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.versions).match("multiqc_versions_single") } - ) - } - - } - - test("sarscov2 single-end [fastqc] [config]") { - - when { - process { - """ - 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] = [] - input[4] = [] - input[5] = [] - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, - { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.versions).match("multiqc_versions_config") } - ) - } - } - - test("sarscov2 single-end [fastqc] - stub") { - - options "-stub" - - when { - process { - """ - 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] = [] - input[4] = [] - input[5] = [] - """ - } - } - - 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("multiqc_stub") } - ) - } - - } -} diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap deleted file mode 100644 index 2fcbb5ff..00000000 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ /dev/null @@ -1,41 +0,0 @@ -{ - "multiqc_versions_single": { - "content": [ - [ - "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-02T17:51:46.317523" - }, - "multiqc_stub": { - "content": [ - [ - "multiqc_report.html", - "multiqc_data", - "multiqc_plots", - "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-02T17:52:20.680978" - }, - "multiqc_versions_config": { - "content": [ - [ - "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-02T17:52:09.185842" - } -} \ No newline at end of file diff --git a/modules/nf-core/multiqc/tests/nextflow.config b/modules/nf-core/multiqc/tests/nextflow.config deleted file mode 100644 index c537a6a3..00000000 --- a/modules/nf-core/multiqc/tests/nextflow.config +++ /dev/null @@ -1,5 +0,0 @@ -process { - withName: 'MULTIQC' { - ext.prefix = null - } -} diff --git a/modules/nf-core/multiqc/tests/tags.yml b/modules/nf-core/multiqc/tests/tags.yml deleted file mode 100644 index bea6c0d3..00000000 --- a/modules/nf-core/multiqc/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -multiqc: - - modules/nf-core/multiqc/** diff --git a/nextflow.config b/nextflow.config index e55b4fbf..1970a075 100644 --- a/nextflow.config +++ b/nextflow.config @@ -13,18 +13,6 @@ params { // Input options input = null - // References - genome = null - igenomes_base = 's3://ngi-igenomes/igenomes/' - igenomes_ignore = false - - // MultiQC options - multiqc_config = null - multiqc_title = null - multiqc_logo = null - max_multiqc_email_size = '25.MB' - multiqc_methods_description = null - // Boilerplate options outdir = null publish_dir_mode = 'copy' @@ -38,8 +26,7 @@ params { show_hidden = false version = false pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' - - // Config options + trace_report_suffix = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss')// Config options config_profile_name = null config_profile_description = null @@ -153,6 +140,13 @@ profiles { executor.name = 'local' executor.cpus = 4 executor.memory = 8.GB + process { + resourceLimits = [ + memory: 8.GB, + cpus : 4, + time : 1.h + ] + } } test { includeConfig 'conf/test.config' } test_full { includeConfig 'conf/test_full.config' } @@ -174,8 +168,7 @@ podman.registry = 'quay.io' singularity.registry = 'quay.io' charliecloud.registry = 'quay.io' -// Load igenomes.config if required -includeConfig !params.igenomes_ignore ? 'conf/igenomes.config' : 'conf/igenomes_ignored.config' + // 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. @@ -201,30 +194,41 @@ set -C # No clobber - prevent output redirection from overwriting files. // 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 - file = "${params.outdir}/pipeline_info/execution_timeline_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/execution_timeline_${params.trace_report_suffix}.html" } report { enabled = true - file = "${params.outdir}/pipeline_info/execution_report_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/execution_report_${params.trace_report_suffix}.html" } trace { enabled = true - file = "${params.outdir}/pipeline_info/execution_trace_${trace_timestamp}.txt" + file = "${params.outdir}/pipeline_info/execution_trace_${params.trace_report_suffix}.txt" } dag { enabled = true - file = "${params.outdir}/pipeline_info/pipeline_dag_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/pipeline_dag_${params.trace_report_suffix}.html" } manifest { name = 'nf-core/pixelator' - author = """Pixelgen Technologies AB""" + author = """Pixelgen Technologies AB""" // The author field is deprecated from Nextflow version 24.10.0, use contributors instead + contributors = [ + // TODO nf-core: Update the field with the details of the contributors to your pipeline. New with Nextflow version 24.10.0 + [ + name: 'Pixelgen Technologies AB', + affiliation: '', + email: '', + github: '', + contribution: [], // List of contribution types ('author', 'maintainer' or 'contributor') + orcid: '' + ], + ] homePage = 'https://github.com/nf-core/pixelator' description = """Pipeline for analysis of Molecular Pixelation assays""" mainScript = 'main.nf' + defaultBranch = 'master' nextflowVersion = '!>=24.04.2' version = '1.3.1' doi = '' @@ -237,9 +241,10 @@ plugins { validation { defaultIgnoreParams = ["genomes"] + monochromeLogs = params.monochrome_logs help { enabled = true - command = "nextflow run $manifest.name -profile --input samplesheet.csv --outdir " + command = "nextflow run nf-core/pixelator -profile --input samplesheet.csv --outdir " fullParameter = "help_full" showHiddenParameter = "show_hidden" beforeText = """ @@ -249,15 +254,15 @@ validation { \033[0;34m |\\ | |__ __ / ` / \\ |__) |__ \033[0;33m} {\033[0m \033[0;34m | \\| | \\__, \\__/ | \\ |___ \033[0;32m\\`-._,-`-,\033[0m \033[0;32m`._,._,\'\033[0m -\033[0;35m ${manifest.name} ${manifest.version}\033[0m +\033[0;35m nf-core/pixelator ${manifest.version}\033[0m -\033[2m----------------------------------------------------\033[0m- """ - afterText = """${manifest.doi ? "* The pipeline\n" : ""}${manifest.doi.tokenize(",").collect { " https://doi.org/${it.trim().replace('https://doi.org/','')}"}.join("\n")}${manifest.doi ? "\n" : ""} + afterText = """${manifest.doi ? "\n* The pipeline\n" : ""}${manifest.doi.tokenize(",").collect { " https://doi.org/${it.trim().replace('https://doi.org/','')}"}.join("\n")}${manifest.doi ? "\n" : ""} * The nf-core framework https://doi.org/10.1038/s41587-020-0439-x * Software dependencies - https://github.com/${manifest.name}/blob/master/CITATIONS.md + https://github.com/nf-core/pixelator/blob/master/CITATIONS.md """ } summary { @@ -265,6 +270,3 @@ validation { afterText = validation.help.afterText } } - -// Load modules.config for DSL2 module specific options -includeConfig 'conf/modules.config' diff --git a/nextflow_schema.json b/nextflow_schema.json index 694bac27..3124caa5 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -35,50 +35,6 @@ "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})$" - }, - "multiqc_title": { - "type": "string", - "description": "MultiQC report title. Printed as page header, used for filename if not otherwise specified.", - "fa_icon": "fas fa-file-signature" - } - } - }, - "reference_genome_options": { - "title": "Reference genome options", - "type": "object", - "fa_icon": "fas fa-dna", - "description": "Reference genome related files and options required for the workflow.", - "properties": { - "genome": { - "type": "string", - "description": "Name of iGenomes reference.", - "fa_icon": "fas fa-book", - "help_text": "If using a reference genome configured in the pipeline using iGenomes, use this parameter to give the ID for the reference. This is then used to build the full paths for all required reference genome files e.g. `--genome GRCh38`. \n\nSee the [nf-core website docs](https://nf-co.re/usage/reference_genomes) for more details." - }, - "fasta": { - "type": "string", - "format": "file-path", - "exists": true, - "mimetype": "text/plain", - "pattern": "^\\S+\\.fn?a(sta)?(\\.gz)?$", - "description": "Path to FASTA genome file.", - "help_text": "This parameter is *mandatory* if `--genome` is not specified. If you don't have a BWA index available this will be generated for you automatically. Combine with `--save_reference` to save BWA index for future runs.", - "fa_icon": "far fa-file-code" - }, - "igenomes_ignore": { - "type": "boolean", - "description": "Do not load the iGenomes reference config.", - "fa_icon": "fas fa-ban", - "hidden": true, - "help_text": "Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`." - }, - "igenomes_base": { - "type": "string", - "format": "directory-path", - "description": "The base path to the igenomes reference files", - "fa_icon": "fas fa-ban", - "hidden": true, - "default": "s3://ngi-igenomes/igenomes/" } } }, @@ -166,14 +122,6 @@ "fa_icon": "fas fa-remove-format", "hidden": true }, - "max_multiqc_email_size": { - "type": "string", - "description": "File size limit when attaching MultiQC reports to summary emails.", - "pattern": "^\\d+(\\.\\d+)?\\.?\\s*(K|M|G|T)?B$", - "default": "25.MB", - "fa_icon": "fas fa-file-upload", - "hidden": true - }, "monochrome_logs": { "type": "boolean", "description": "Do not use coloured log outputs.", @@ -187,24 +135,6 @@ "help_text": "Incoming hook URL for messaging service. Currently, MS Teams and Slack are supported.", "hidden": true }, - "multiqc_config": { - "type": "string", - "format": "file-path", - "description": "Custom config file to supply to MultiQC.", - "fa_icon": "fas fa-cog", - "hidden": true - }, - "multiqc_logo": { - "type": "string", - "description": "Custom logo file to supply to MultiQC. File name must also be set in the MultiQC config file", - "fa_icon": "fas fa-image", - "hidden": true - }, - "multiqc_methods_description": { - "type": "string", - "description": "Custom MultiQC yaml file containing HTML including a methods description.", - "fa_icon": "fas fa-cog" - }, "validate_params": { "type": "boolean", "description": "Boolean whether to validate parameters against the schema at runtime", @@ -218,6 +148,12 @@ "description": "Base URL or local path to location of pipeline test dataset files", "default": "https://raw.githubusercontent.com/nf-core/test-datasets/", "hidden": true + }, + "trace_report_suffix": { + "type": "string", + "fa_icon": "far calendar", + "description": "Suffix to add to the trace report filename. Default is the date and time in the format yyyy-MM-dd_HH-mm-ss.", + "hidden": true } } } @@ -226,9 +162,7 @@ { "$ref": "#/$defs/input_output_options" }, - { - "$ref": "#/$defs/reference_genome_options" - }, + { "$ref": "#/$defs/institutional_config_options" }, diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json new file mode 100644 index 00000000..be7808b0 --- /dev/null +++ b/ro-crate-metadata.json @@ -0,0 +1,299 @@ +{ + "@context": [ + "https://w3id.org/ro/crate/1.1/context", + { + "GithubService": "https://w3id.org/ro/terms/test#GithubService", + "JenkinsService": "https://w3id.org/ro/terms/test#JenkinsService", + "PlanemoEngine": "https://w3id.org/ro/terms/test#PlanemoEngine", + "TestDefinition": "https://w3id.org/ro/terms/test#TestDefinition", + "TestInstance": "https://w3id.org/ro/terms/test#TestInstance", + "TestService": "https://w3id.org/ro/terms/test#TestService", + "TestSuite": "https://w3id.org/ro/terms/test#TestSuite", + "TravisService": "https://w3id.org/ro/terms/test#TravisService", + "definition": "https://w3id.org/ro/terms/test#definition", + "engineVersion": "https://w3id.org/ro/terms/test#engineVersion", + "instance": "https://w3id.org/ro/terms/test#instance", + "resource": "https://w3id.org/ro/terms/test#resource", + "runsOn": "https://w3id.org/ro/terms/test#runsOn" + } + ], + "@graph": [ + { + "@id": "./", + "@type": "Dataset", + "creativeWorkStatus": "Stable", + "datePublished": "2024-12-12T11:25:17+00:00", + "description": "

    \n \n \n \"nf-core/pixelator\"\n \n

    \n\n[![GitHub Actions CI Status](https://github.com/nf-core/pixelator/actions/workflows/ci.yml/badge.svg)](https://github.com/nf-core/pixelator/actions/workflows/ci.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/pixelator/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/pixelator/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/pixelator/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A524.04.2-23aa62.svg)](https://www.nextflow.io/)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![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/pixelator)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23pixelator-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/pixelator)[![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)\n\n## Introduction\n\n**nf-core/pixelator** is a bioinformatics pipeline that ...\n\n\n\n\n\n\n\n\n\n## Usage\n\n> [!NOTE]\n> 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.\n\n\n\nNow, you can run the pipeline using:\n\n\n\n```bash\nnextflow run nf-core/pixelator \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> 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/docs/usage/getting_started/configuration#custom-configuration-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/pixelator/usage) and the [parameter documentation](https://nf-co.re/pixelator/parameters).\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/pixelator/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/pixelator/output).\n\n## Credits\n\nnf-core/pixelator was originally written by Pixelgen Technologies AB.\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#pixelator` channel](https://nfcore.slack.com/channels/pixelator) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\n\n\n\n\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", + "hasPart": [ + { + "@id": "main.nf" + }, + { + "@id": "assets/" + }, + { + "@id": "conf/" + }, + { + "@id": "docs/" + }, + { + "@id": "docs/images/" + }, + { + "@id": "workflows/" + }, + { + "@id": "subworkflows/" + }, + { + "@id": "nextflow.config" + }, + { + "@id": "README.md" + }, + { + "@id": "nextflow_schema.json" + }, + { + "@id": "CHANGELOG.md" + }, + { + "@id": "LICENSE" + }, + { + "@id": "CODE_OF_CONDUCT.md" + }, + { + "@id": "CITATIONS.md" + }, + { + "@id": "modules.json" + }, + { + "@id": "docs/usage.md" + }, + { + "@id": "docs/output.md" + }, + { + "@id": ".nf-core.yml" + }, + { + "@id": ".pre-commit-config.yaml" + }, + { + "@id": ".prettierignore" + } + ], + "isBasedOn": "https://github.com/nf-core/pixelator", + "license": "MIT", + "mainEntity": { + "@id": "main.nf" + }, + "mentions": [ + { + "@id": "#52b2ffa5-42c3-4821-a002-cde80183bf67" + } + ], + "name": "nf-core/pixelator" + }, + { + "@id": "ro-crate-metadata.json", + "@type": "CreativeWork", + "about": { + "@id": "./" + }, + "conformsTo": [ + { + "@id": "https://w3id.org/ro/crate/1.1" + }, + { + "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0" + } + ] + }, + { + "@id": "main.nf", + "@type": ["File", "SoftwareSourceCode", "ComputationalWorkflow"], + "creator": [ + { + "@id": "#florian.detemmerman@pixelgen.com" + } + ], + "dateCreated": "", + "dateModified": "2024-12-12T11:25:17Z", + "dct:conformsTo": "https://bioschemas.org/profiles/ComputationalWorkflow/1.0-RELEASE/", + "keywords": [ + "nf-core", + "nextflow", + "molecular-pixelation", + "pixelator", + "pixelgen-technologies", + "proteins", + "single-cell", + "single-cell-omics" + ], + "license": ["MIT"], + "name": ["nf-core/pixelator"], + "programmingLanguage": { + "@id": "https://w3id.org/workflowhub/workflow-ro-crate#nextflow" + }, + "sdPublisher": { + "@id": "https://nf-co.re/" + }, + "url": ["https://github.com/nf-core/pixelator", "https://nf-co.re/pixelator/1.3.1/"], + "version": ["1.3.1"] + }, + { + "@id": "https://w3id.org/workflowhub/workflow-ro-crate#nextflow", + "@type": "ComputerLanguage", + "identifier": { + "@id": "https://www.nextflow.io/" + }, + "name": "Nextflow", + "url": { + "@id": "https://www.nextflow.io/" + }, + "version": "!>=24.04.2" + }, + { + "@id": "#52b2ffa5-42c3-4821-a002-cde80183bf67", + "@type": "TestSuite", + "instance": [ + { + "@id": "#ed980937-b4dd-48b0-b7c4-acf78a6ca685" + } + ], + "mainEntity": { + "@id": "main.nf" + }, + "name": "Test suite for nf-core/pixelator" + }, + { + "@id": "#ed980937-b4dd-48b0-b7c4-acf78a6ca685", + "@type": "TestInstance", + "name": "GitHub Actions workflow for testing nf-core/pixelator", + "resource": "repos/nf-core/pixelator/actions/workflows/ci.yml", + "runsOn": { + "@id": "https://w3id.org/ro/terms/test#GithubService" + }, + "url": "https://api.github.com" + }, + { + "@id": "https://w3id.org/ro/terms/test#GithubService", + "@type": "TestService", + "name": "Github Actions", + "url": { + "@id": "https://github.com" + } + }, + { + "@id": "assets/", + "@type": "Dataset", + "description": "Additional files" + }, + { + "@id": "conf/", + "@type": "Dataset", + "description": "Configuration files" + }, + { + "@id": "docs/", + "@type": "Dataset", + "description": "Markdown files for documenting the pipeline" + }, + { + "@id": "docs/images/", + "@type": "Dataset", + "description": "Images for the documentation files" + }, + { + "@id": "workflows/", + "@type": "Dataset", + "description": "Main pipeline workflows to be executed in main.nf" + }, + { + "@id": "subworkflows/", + "@type": "Dataset", + "description": "Smaller subworkflows" + }, + { + "@id": "nextflow.config", + "@type": "File", + "description": "Main Nextflow configuration file" + }, + { + "@id": "README.md", + "@type": "File", + "description": "Basic pipeline usage information" + }, + { + "@id": "nextflow_schema.json", + "@type": "File", + "description": "JSON schema for pipeline parameter specification" + }, + { + "@id": "CHANGELOG.md", + "@type": "File", + "description": "Information on changes made to the pipeline" + }, + { + "@id": "LICENSE", + "@type": "File", + "description": "The license - should be MIT" + }, + { + "@id": "CODE_OF_CONDUCT.md", + "@type": "File", + "description": "The nf-core code of conduct" + }, + { + "@id": "CITATIONS.md", + "@type": "File", + "description": "Citations needed when using the pipeline" + }, + { + "@id": "modules.json", + "@type": "File", + "description": "Version information for modules from nf-core/modules" + }, + { + "@id": "docs/usage.md", + "@type": "File", + "description": "Usage documentation" + }, + { + "@id": "docs/output.md", + "@type": "File", + "description": "Output documentation" + }, + { + "@id": ".nf-core.yml", + "@type": "File", + "description": "nf-core configuration file, configuring template features and linting rules" + }, + { + "@id": ".pre-commit-config.yaml", + "@type": "File", + "description": "Configuration file for pre-commit hooks" + }, + { + "@id": ".prettierignore", + "@type": "File", + "description": "Ignore file for prettier" + }, + { + "@id": "https://nf-co.re/", + "@type": "Organization", + "name": "nf-core", + "url": "https://nf-co.re/" + }, + { + "@id": "#florian.detemmerman@pixelgen.com", + "@type": "Person", + "email": "florian.detemmerman@pixelgen.com", + "name": "Florian De Temmerman" + } + ] +} diff --git a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf index 05695fe1..d2e8c7cf 100644 --- a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf @@ -63,11 +63,6 @@ workflow PIPELINE_INITIALISATION { nextflow_cli_args ) - // - // Custom validation for pipeline parameters - // - validateInputParameters() - // // Create channel from input file provided through params.input // @@ -112,11 +107,10 @@ workflow PIPELINE_COMPLETION { 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 // @@ -129,7 +123,7 @@ workflow PIPELINE_COMPLETION { plaintext_email, outdir, monochrome_logs, - multiqc_report.toList() + [] ) } @@ -149,12 +143,6 @@ workflow PIPELINE_COMPLETION { FUNCTIONS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -// -// Check and validate pipeline parameters -// -def validateInputParameters() { - genomeExistsError() -} // // Validate channels from input samplesheet @@ -171,31 +159,6 @@ def validateInputSamplesheet(input) { 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() { @@ -204,8 +167,6 @@ def toolCitationText() { // 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() @@ -217,15 +178,13 @@ def toolBibliographyText() { // 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 + // Convert to a named map so can be used as with familiar NXF ${workflow} variable syntax in the MultiQC YML file def meta = [:] meta.workflow = workflow.toMap() meta["manifest_map"] = workflow.manifest.toMap() diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf index 0fcbf7b3..d6e593e8 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf @@ -92,10 +92,12 @@ def checkCondaChannels() { channels = config.channels } catch (NullPointerException e) { + log.debug(e) log.warn("Could not verify conda channel configuration.") return null } catch (IOException e) { + log.debug(e) log.warn("Could not verify conda channel configuration.") return null } 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 ca964ce8..02dbf094 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 @@ -52,10 +52,12 @@ nextflow_workflow { } then { - assertAll( - { assert workflow.success }, - { assert workflow.stdout.contains("nextflow_workflow v9.9.9") } - ) + expect { + with(workflow) { + assert success + assert "nextflow_workflow v9.9.9" in stdout + } + } } } diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index 5cb7bafe..bfd25876 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -56,21 +56,6 @@ def checkProfileProvided(nextflow_cli_args) { } } -// -// Citation string for pipeline -// -def workflowCitation() { - def temp_doi_ref = "" - def manifest_doi = workflow.manifest.doi.tokenize(",") - // Handling 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 - manifest_doi.each { doi_ref -> - 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" + temp_doi_ref + "\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 // @@ -150,33 +135,6 @@ def paramsSummaryMultiqc(summary_params) { return yaml_file_text } -// -// nf-core logo -// -def nfCoreLogo(monochrome_logs=true) { - def colors = logColours(monochrome_logs) as Map - 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) { - def colors = logColours(monochrome_logs) as Map - return "-${colors.dim}----------------------------------------------------${colors.reset}-" -} - // // ANSII colours used for terminal logging // @@ -245,28 +203,24 @@ def logColours(monochrome_logs=true) { 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] - } +// Return a single report from an object that may be a Path or List +// +def getSingleReport(multiqc_reports) { + if (multiqc_reports instanceof Path) { + return multiqc_reports + } else if (multiqc_reports instanceof List) { + if (multiqc_reports.size() == 0) { + log.warn("[${workflow.manifest.name}] No reports found from process 'MULTIQC'") + return null + } else if (multiqc_reports.size() == 1) { + return multiqc_reports.first() + } else { + log.warn("[${workflow.manifest.name}] Found multiple reports from process 'MULTIQC', will use only one") + return multiqc_reports.first() } + } else { + return null } - catch (Exception all) { - if (multiqc_report) { - log.warn("[${workflow.manifest.name}] Could not attach MultiQC report to summary email") - } - } - return mqc_report } // @@ -320,7 +274,7 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi email_fields['summary'] = summary << misc_fields // On success try attach the multiqc report - def mqc_report = attachMultiqcReport(multiqc_report) + def mqc_report = getSingleReport(multiqc_report) // Check if we are only sending emails on failure def email_address = email @@ -340,7 +294,7 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi 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 max_multiqc_email_size = (params.containsKey('max_multiqc_email_size') ? params.max_multiqc_email_size : 0) as 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) @@ -351,14 +305,17 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi if (email_address) { try { if (plaintext_email) { -new org.codehaus.groovy.GroovyException('Send plaintext e-mail, not HTML') } + new org.codehaus.groovy.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 (Exception all) { + catch (Exception msg) { + log.debug(msg.toString()) + log.debug("Trying with mail instead of sendmail") // Catch failures and try with plaintext def mail_cmd = ['mail', '-s', subject, '--content-type=text/html', email_address] mail_cmd.execute() << email_html 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 index 1dc317f8..f117040c 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test @@ -41,26 +41,14 @@ nextflow_function { } } - test("Test Function workflowCitation") { - - function "workflowCitation" - - then { - assertAll( - { assert function.success }, - { assert snapshot(function.result).match() } - ) - } - } - - test("Test Function nfCoreLogo") { + test("Test Function without logColours") { - function "nfCoreLogo" + function "logColours" when { function { """ - input[0] = false + input[0] = true """ } } @@ -73,9 +61,8 @@ nextflow_function { } } - test("Test Function dashedLine") { - - function "dashedLine" + test("Test Function with logColours") { + function "logColours" when { function { @@ -93,14 +80,13 @@ nextflow_function { } } - test("Test Function without logColours") { - - function "logColours" + test("Test Function getSingleReport with a single file") { + function "getSingleReport" when { function { """ - input[0] = true + input[0] = file(params.modules_testdata_base_path + '/generic/tsv/test.tsv', checkIfExists: true) """ } } @@ -108,18 +94,22 @@ nextflow_function { then { assertAll( { assert function.success }, - { assert snapshot(function.result).match() } + { assert function.result.contains("test.tsv") } ) } } - test("Test Function with logColours") { - function "logColours" + test("Test Function getSingleReport with multiple files") { + function "getSingleReport" when { function { """ - input[0] = false + input[0] = [ + file(params.modules_testdata_base_path + '/generic/tsv/test.tsv', checkIfExists: true), + file(params.modules_testdata_base_path + '/generic/tsv/network.tsv', checkIfExists: true), + file(params.modules_testdata_base_path + '/generic/tsv/expression.tsv', checkIfExists: true) + ] """ } } @@ -127,7 +117,9 @@ nextflow_function { then { assertAll( { assert function.success }, - { assert snapshot(function.result).match() } + { assert function.result.contains("test.tsv") }, + { assert !function.result.contains("network.tsv") }, + { assert !function.result.contains("expression.tsv") } ) } } 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 1037232c..02c67014 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 @@ -17,26 +17,6 @@ }, "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" - ], - "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" - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - }, - "timestamp": "2024-02-28T12:03:07.019761" - }, "Test Function without logColours": { "content": [ { @@ -95,16 +75,6 @@ }, "timestamp": "2024-02-28T12:03:17.969323" }, - "Test Function dashedLine": { - "content": [ - "-\u001b[2m----------------------------------------------------\u001b[0m-" - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - }, - "timestamp": "2024-02-28T12:03:14.366181" - }, "Test Function with logColours": { "content": [ { diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test b/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test index 842dc432..8fb30164 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test @@ -42,7 +42,7 @@ nextflow_workflow { params { test_data = '' - outdir = 1 + outdir = null } workflow { @@ -94,7 +94,7 @@ nextflow_workflow { params { test_data = '' - outdir = 1 + outdir = null } workflow { diff --git a/tower.yml b/tower.yml index 787aedfe..c61323c0 100644 --- a/tower.yml +++ b/tower.yml @@ -1,5 +1,3 @@ reports: - multiqc_report.html: - display: "MultiQC HTML report" samplesheet.csv: display: "Auto-created samplesheet with collated metadata and FASTQ paths" diff --git a/workflows/pixelator.nf b/workflows/pixelator.nf index 0af43732..1c1e948c 100644 --- a/workflows/pixelator.nf +++ b/workflows/pixelator.nf @@ -3,10 +3,7 @@ IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { FASTQC } from '../modules/nf-core/fastqc/main' -include { MULTIQC } from '../modules/nf-core/multiqc/main' include { paramsSummaryMap } from 'plugin/nf-schema' -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_pixelator_pipeline' @@ -23,15 +20,6 @@ workflow PIXELATOR { main: ch_versions = Channel.empty() - ch_multiqc_files = Channel.empty() - // - // MODULE: Run FastQC - // - FASTQC ( - ch_samplesheet - ) - ch_multiqc_files = ch_multiqc_files.mix(FASTQC.out.zip.collect{it[1]}) - ch_versions = ch_versions.mix(FASTQC.out.versions.first()) // // Collate and save software versions @@ -39,53 +27,13 @@ workflow PIXELATOR { softwareVersionsToYAML(ch_versions) .collectFile( storeDir: "${params.outdir}/pipeline_info", - name: 'nf_core_' + 'pipeline_software_' + 'mqc_' + 'versions.yml', + name: 'nf_core_' + 'pixelator_software_' + '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_files = ch_multiqc_files.mix( - ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) - 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_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(), - ch_multiqc_config.toList(), - ch_multiqc_custom_config.toList(), - ch_multiqc_logo.toList(), - [], - [] - ) - - emit:multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html + emit: versions = ch_versions // channel: [ path(versions.yml) ] } From e15a0d1386572ad44ef78e3dcacfb66e97e359ea Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Fri, 13 Dec 2024 13:54:33 +0100 Subject: [PATCH 28/70] Sync some nf-core template files --- .github/CONTRIBUTING.md | 2 ++ .github/PULL_REQUEST_TEMPLATE.md | 4 ++-- assets/sendmail_template.txt | 22 ++++++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e091e270..332a5c4a 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -79,6 +79,8 @@ If you wish to contribute a new step, please use the following coding standards: 6. Add sanity checks and validation for all relevant parameters. 7. Perform local tests to validate that the new code works as expected. 8. If applicable, add a new test command in `.github/workflow/ci.yml`. +9. Update MultiQC config `assets/multiqc_config.yml` so relevant suffixes, file name clean up and module plots are in the appropriate order. If applicable, add a [MultiQC](https://https://multiqc.info/) module. +10. Add a description of the output files and if relevant any appropriate images from the MultiQC report to `docs/output.md`. ### Default values diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3e33e429..b107a8e1 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -8,14 +8,14 @@ These are the most common things requested on pull requests (PRs). Remember that PRs should be made against the dev branch, unless you're preparing a pipeline release. -Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/pixelator/tree/master/.github/CONTRIBUTING.md) +Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/pixelator/tree/main/.github/CONTRIBUTING.md) --> ## PR checklist - [ ] 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/pixelator/tree/master/.github/CONTRIBUTING.md) +- [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/nf-core/pixelator/tree/main/.github/CONTRIBUTING.md) - [ ] If necessary, also make a PR on the nf-core/pixelator _branch_ on the [nf-core/test-datasets](https://github.com/nf-core/test-datasets) repository. - [ ] Make sure your code lints (`nf-core pipelines lint`). - [ ] Ensure the test suite passes (`nextflow run . -profile test,docker --outdir `). diff --git a/assets/sendmail_template.txt b/assets/sendmail_template.txt index 6792160f..5a184630 100644 --- a/assets/sendmail_template.txt +++ b/assets/sendmail_template.txt @@ -26,6 +26,28 @@ Content-Disposition: inline; filename="nf-core-pixelator_logo_light.png" join( '\n' ) %> <% +if (mqcFile){ +def mqcFileObj = new File("$mqcFile") +if (mqcFileObj.length() < mqcMaxSize){ +out << """ +--nfcoremimeboundary +Content-Type: text/html; name=\"multiqc_report\" +Content-Transfer-Encoding: base64 +Content-ID: +Content-Disposition: attachment; filename=\"${mqcFileObj.getName()}\" + +${mqcFileObj. + bytes. + encodeBase64(). + toString(). + tokenize( '\n' )*. + toList()*. + collate( 76 )*. + collect { it.join() }. + flatten(). + join( '\n' )} +""" +}} %> --nfcoremimeboundary-- From 41f8bef47fd7de1ece3805f7aac2ed680121e45b Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Fri, 13 Dec 2024 14:02:58 +0100 Subject: [PATCH 29/70] Fix missing modules.config include --- conf/base.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/base.config b/conf/base.config index b53faa52..3914089f 100644 --- a/conf/base.config +++ b/conf/base.config @@ -59,3 +59,5 @@ process { maxRetries = 2 } } + +includeConfig 'modules.config' From 5d7a14b193fb2ff405952ab53edf1e40a7b45bba Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Fri, 13 Dec 2024 14:07:08 +0100 Subject: [PATCH 30/70] Fix some linter errors --- .github/PULL_REQUEST_TEMPLATE.md | 4 ++-- .nf-core.yml | 1 + nextflow.config | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b107a8e1..3e33e429 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -8,14 +8,14 @@ These are the most common things requested on pull requests (PRs). Remember that PRs should be made against the dev branch, unless you're preparing a pipeline release. -Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/pixelator/tree/main/.github/CONTRIBUTING.md) +Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/pixelator/tree/master/.github/CONTRIBUTING.md) --> ## PR checklist - [ ] 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/pixelator/tree/main/.github/CONTRIBUTING.md) +- [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/nf-core/pixelator/tree/master/.github/CONTRIBUTING.md) - [ ] If necessary, also make a PR on the nf-core/pixelator _branch_ on the [nf-core/test-datasets](https://github.com/nf-core/test-datasets) repository. - [ ] Make sure your code lints (`nf-core pipelines lint`). - [ ] Ensure the test suite passes (`nextflow run . -profile test,docker --outdir `). diff --git a/.nf-core.yml b/.nf-core.yml index 28e12c5c..3efdd783 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -5,6 +5,7 @@ lint: files_exist: - assets/multiqc_config.yml - conf/igenomes.config + - conf/igenomes_ignored.config nf_core_version: 3.1.0 org_path: null repository_type: pipeline diff --git a/nextflow.config b/nextflow.config index 70d1bd13..b6299ddc 100644 --- a/nextflow.config +++ b/nextflow.config @@ -245,8 +245,7 @@ profiles { includeConfig !System.getenv('NXF_OFFLINE') && params.custom_config_base ? "${params.custom_config_base}/nfcore_custom.config" : "/dev/null" // Load nf-core/pixelator custom profiles from different institutions. -// TODO nf-core: Optionally, you can add a pipeline-specific nf-core config at https://github.com/nf-core/configs -// includeConfig !System.getenv('NXF_OFFLINE') && params.custom_config_base ? "${params.custom_config_base}/pipeline/pixelator.config" : "/dev/null" +includeConfig !System.getenv('NXF_OFFLINE') && params.custom_config_base ? "${params.custom_config_base}/pipeline/pixelator.config" : "/dev/null" // Set default registry for Apptainer, Docker, Podman, Charliecloud and Singularity independent of -profile // Will not be used unless Apptainer / Docker / Podman / Charliecloud / Singularity are enabled From 444ec7d8e25b0a633f1f7421b0fd9e5c644e04f6 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Fri, 13 Dec 2024 15:12:09 +0100 Subject: [PATCH 31/70] Update metromap and CHANGELOG --- CHANGELOG.md | 3 + docs/images/nf-core-pixelator-metromap.svg | 152 ++++++++++----------- 2 files changed, 79 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08fad568..5384d8b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [[PR #113](https://github.com/nf-core/pixelator/pull/113)] - Fix validation issues after nf-core/tools v3.0.2 update - [[PR #114](https://github.com/nf-core/pixelator/pull/114)] - Remove `--save_recovered_components` options for graph outputs - [[PR #115](https://github.com/nf-core/pixelator/pull/115)] - Update containers for pixelator 0.19 +- [[PR #116](https://github.com/nf-core/pixelator/pull/116)] - Bump version to 1.4 +- [[PR #117](https://github.com/nf-core/pixelator/pull/117)] - Template update for nf-core/tools v3.1.0 +- [[PR #118](https://github.com/nf-core/pixelator/pull/118)] - Update metromap for 1.4 release ### Parameters diff --git a/docs/images/nf-core-pixelator-metromap.svg b/docs/images/nf-core-pixelator-metromap.svg index 9a1b4188..ea184fdb 100644 --- a/docs/images/nf-core-pixelator-metromap.svg +++ b/docs/images/nf-core-pixelator-metromap.svg @@ -1,33 +1,33 @@ - + - - - - + + + + - - + + - - - + + + - + - - - + + + @@ -89,39 +89,39 @@ - - + + - - - + + + - - - + + + - - - + + + - + - - + + @@ -133,10 +133,10 @@ - + - + @@ -145,132 +145,132 @@ - + - - - - - - - - - - - - - + + + + + + + + + + + + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - + - + - + - + - + - + - + From c6205e6e02f7c239e94337d568b3905b2062602b Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Fri, 13 Dec 2024 15:22:16 +0100 Subject: [PATCH 32/70] Bump conda versions --- CHANGELOG.md | 2 +- modules/local/pixelator/collect_metadata.nf | 2 +- modules/local/pixelator/list_options.nf | 2 +- modules/local/pixelator/single-cell/amplicon/main.nf | 2 +- modules/local/pixelator/single-cell/analysis/main.nf | 2 +- modules/local/pixelator/single-cell/annotate/main.nf | 2 +- modules/local/pixelator/single-cell/collapse/main.nf | 2 +- modules/local/pixelator/single-cell/demux/main.nf | 2 +- modules/local/pixelator/single-cell/graph/main.nf | 2 +- modules/local/pixelator/single-cell/layout/main.nf | 2 +- modules/local/pixelator/single-cell/qc/main.nf | 2 +- modules/local/pixelator/single-cell/report/main.nf | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5384d8b0..04018b49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [[PR #115](https://github.com/nf-core/pixelator/pull/115)] - Update containers for pixelator 0.19 - [[PR #116](https://github.com/nf-core/pixelator/pull/116)] - Bump version to 1.4 - [[PR #117](https://github.com/nf-core/pixelator/pull/117)] - Template update for nf-core/tools v3.1.0 -- [[PR #118](https://github.com/nf-core/pixelator/pull/118)] - Update metromap for 1.4 release +- [[PR #118](https://github.com/nf-core/pixelator/pull/118)] - Update metromap, bump conda versions ### Parameters diff --git a/modules/local/pixelator/collect_metadata.nf b/modules/local/pixelator/collect_metadata.nf index c119cd2e..9d74975e 100644 --- a/modules/local/pixelator/collect_metadata.nf +++ b/modules/local/pixelator/collect_metadata.nf @@ -3,7 +3,7 @@ process PIXELATOR_COLLECT_METADATA { label 'process_single' cache false - conda "bioconda::pixelator=0.18.2" + conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/list_options.nf b/modules/local/pixelator/list_options.nf index 17fa8b22..e7b65e86 100644 --- a/modules/local/pixelator/list_options.nf +++ b/modules/local/pixelator/list_options.nf @@ -2,7 +2,7 @@ process PIXELATOR_LIST_OPTIONS { label 'process_single' - conda "bioconda::pixelator=0.18.2" + conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/amplicon/main.nf b/modules/local/pixelator/single-cell/amplicon/main.nf index 3bdca1e1..533db432 100644 --- a/modules/local/pixelator/single-cell/amplicon/main.nf +++ b/modules/local/pixelator/single-cell/amplicon/main.nf @@ -3,7 +3,7 @@ process PIXELATOR_AMPLICON { label 'process_low' - conda "bioconda::pixelator=0.18.2" + conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/analysis/main.nf b/modules/local/pixelator/single-cell/analysis/main.nf index 9320c854..ec97b803 100644 --- a/modules/local/pixelator/single-cell/analysis/main.nf +++ b/modules/local/pixelator/single-cell/analysis/main.nf @@ -2,7 +2,7 @@ process PIXELATOR_ANALYSIS { tag "$meta.id" label 'process_medium' - conda "bioconda::pixelator=0.18.2" + conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/annotate/main.nf b/modules/local/pixelator/single-cell/annotate/main.nf index 7164fd38..87042d3a 100644 --- a/modules/local/pixelator/single-cell/annotate/main.nf +++ b/modules/local/pixelator/single-cell/annotate/main.nf @@ -3,7 +3,7 @@ process PIXELATOR_ANNOTATE { label 'process_high' - conda "bioconda::pixelator=0.18.2" + conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/collapse/main.nf b/modules/local/pixelator/single-cell/collapse/main.nf index 6ac95987..ef4fcefb 100644 --- a/modules/local/pixelator/single-cell/collapse/main.nf +++ b/modules/local/pixelator/single-cell/collapse/main.nf @@ -2,7 +2,7 @@ process PIXELATOR_COLLAPSE { tag "$meta.id" label 'process_medium' - conda "bioconda::pixelator=0.18.2" + conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/demux/main.nf b/modules/local/pixelator/single-cell/demux/main.nf index a4c8f869..0c3138e4 100644 --- a/modules/local/pixelator/single-cell/demux/main.nf +++ b/modules/local/pixelator/single-cell/demux/main.nf @@ -3,7 +3,7 @@ process PIXELATOR_DEMUX { label 'process_medium' - conda "bioconda::pixelator=0.18.2" + conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/graph/main.nf b/modules/local/pixelator/single-cell/graph/main.nf index 1b405436..132deb28 100644 --- a/modules/local/pixelator/single-cell/graph/main.nf +++ b/modules/local/pixelator/single-cell/graph/main.nf @@ -3,7 +3,7 @@ process PIXELATOR_GRAPH { label 'process_high' - conda "bioconda::pixelator=0.18.2" + conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/layout/main.nf b/modules/local/pixelator/single-cell/layout/main.nf index 6b919137..9e8de554 100644 --- a/modules/local/pixelator/single-cell/layout/main.nf +++ b/modules/local/pixelator/single-cell/layout/main.nf @@ -3,7 +3,7 @@ process PIXELATOR_LAYOUT { label 'process_medium' - conda "bioconda::pixelator=0.18.2" + conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/qc/main.nf b/modules/local/pixelator/single-cell/qc/main.nf index 68d3d454..a5878e78 100644 --- a/modules/local/pixelator/single-cell/qc/main.nf +++ b/modules/local/pixelator/single-cell/qc/main.nf @@ -3,7 +3,7 @@ process PIXELATOR_QC { label 'process_medium' - conda "bioconda::pixelator=0.18.2" + conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/report/main.nf b/modules/local/pixelator/single-cell/report/main.nf index 517a0bbb..900e4b23 100644 --- a/modules/local/pixelator/single-cell/report/main.nf +++ b/modules/local/pixelator/single-cell/report/main.nf @@ -3,7 +3,7 @@ process PIXELATOR_REPORT { label 'process_low' - conda "bioconda::pixelator=0.18.2" + conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" From e58bee0427ec0e67723aacf1cbc2cc464be2e090 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Fri, 13 Dec 2024 15:47:03 +0100 Subject: [PATCH 33/70] Add `process_long` labels to AMPLICON and COLLAPSE --- CHANGELOG.md | 1 + modules/local/pixelator/single-cell/amplicon/main.nf | 1 + modules/local/pixelator/single-cell/collapse/main.nf | 1 + 3 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04018b49..66b22cba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [[PR #116](https://github.com/nf-core/pixelator/pull/116)] - Bump version to 1.4 - [[PR #117](https://github.com/nf-core/pixelator/pull/117)] - Template update for nf-core/tools v3.1.0 - [[PR #118](https://github.com/nf-core/pixelator/pull/118)] - Update metromap, bump conda versions +- [[PR #119](https://github.com/nf-core/pixelator/pull/119)] - Add process_long to AMPLICON and COLLAPSE steps ### Parameters diff --git a/modules/local/pixelator/single-cell/amplicon/main.nf b/modules/local/pixelator/single-cell/amplicon/main.nf index 533db432..b9c6bda1 100644 --- a/modules/local/pixelator/single-cell/amplicon/main.nf +++ b/modules/local/pixelator/single-cell/amplicon/main.nf @@ -1,6 +1,7 @@ process PIXELATOR_AMPLICON { tag "$meta.id" label 'process_low' + label 'process_long' conda "bioconda::pixelator=0.19.0" diff --git a/modules/local/pixelator/single-cell/collapse/main.nf b/modules/local/pixelator/single-cell/collapse/main.nf index ef4fcefb..ce50ecbb 100644 --- a/modules/local/pixelator/single-cell/collapse/main.nf +++ b/modules/local/pixelator/single-cell/collapse/main.nf @@ -1,6 +1,7 @@ process PIXELATOR_COLLAPSE { tag "$meta.id" label 'process_medium' + label 'process_long' conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? From c5b84724f73acaffe8f9eac17362346c5e3ca3dc Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Fri, 13 Dec 2024 15:49:44 +0100 Subject: [PATCH 34/70] Fix CHANGELOG pr number --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66b22cba..a28a176f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [[PR #116](https://github.com/nf-core/pixelator/pull/116)] - Bump version to 1.4 - [[PR #117](https://github.com/nf-core/pixelator/pull/117)] - Template update for nf-core/tools v3.1.0 - [[PR #118](https://github.com/nf-core/pixelator/pull/118)] - Update metromap, bump conda versions -- [[PR #119](https://github.com/nf-core/pixelator/pull/119)] - Add process_long to AMPLICON and COLLAPSE steps +- [[PR #120](https://github.com/nf-core/pixelator/pull/120)] - Add process_long to AMPLICON and COLLAPSE steps ### Parameters From 4cdeef60856114f34adb7fc414a21721c538f758 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Fri, 13 Dec 2024 15:54:39 +0100 Subject: [PATCH 35/70] Fix 1.4 version in CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a28a176f..c83a5cde 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). -## [[1.4.0dev](https://github.com/nf-core/pixelator/releases/tag/1.4.0] - ????-??-?? +## [[1.4.0](https://github.com/nf-core/pixelator/releases/tag/1.4.0)] - 2024-12-13 ### Enhancements & fixes From 40724066adcbf8101aa9b9fed79664c24b37aa9c Mon Sep 17 00:00:00 2001 From: Alvaro Martinez Barrio Date: Thu, 19 Dec 2024 13:54:06 +0100 Subject: [PATCH 36/70] fix: double singularity pixelator container reference --- modules/local/pixelator/collect_metadata.nf | 2 +- modules/local/pixelator/list_options.nf | 2 +- modules/local/pixelator/single-cell/amplicon/main.nf | 2 +- modules/local/pixelator/single-cell/analysis/main.nf | 2 +- modules/local/pixelator/single-cell/annotate/main.nf | 2 +- modules/local/pixelator/single-cell/collapse/main.nf | 2 +- modules/local/pixelator/single-cell/demux/main.nf | 2 +- modules/local/pixelator/single-cell/graph/main.nf | 2 +- modules/local/pixelator/single-cell/layout/main.nf | 2 +- modules/local/pixelator/single-cell/qc/main.nf | 2 +- modules/local/pixelator/single-cell/report/main.nf | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/local/pixelator/collect_metadata.nf b/modules/local/pixelator/collect_metadata.nf index 9d74975e..ca6a5086 100644 --- a/modules/local/pixelator/collect_metadata.nf +++ b/modules/local/pixelator/collect_metadata.nf @@ -5,7 +5,7 @@ process PIXELATOR_COLLECT_METADATA { conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" output: diff --git a/modules/local/pixelator/list_options.nf b/modules/local/pixelator/list_options.nf index e7b65e86..f49dbd56 100644 --- a/modules/local/pixelator/list_options.nf +++ b/modules/local/pixelator/list_options.nf @@ -4,7 +4,7 @@ process PIXELATOR_LIST_OPTIONS { conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" output: diff --git a/modules/local/pixelator/single-cell/amplicon/main.nf b/modules/local/pixelator/single-cell/amplicon/main.nf index b9c6bda1..690af80c 100644 --- a/modules/local/pixelator/single-cell/amplicon/main.nf +++ b/modules/local/pixelator/single-cell/amplicon/main.nf @@ -6,7 +6,7 @@ process PIXELATOR_AMPLICON { conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: diff --git a/modules/local/pixelator/single-cell/analysis/main.nf b/modules/local/pixelator/single-cell/analysis/main.nf index ec97b803..c9cc8f18 100644 --- a/modules/local/pixelator/single-cell/analysis/main.nf +++ b/modules/local/pixelator/single-cell/analysis/main.nf @@ -4,7 +4,7 @@ process PIXELATOR_ANALYSIS { conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: diff --git a/modules/local/pixelator/single-cell/annotate/main.nf b/modules/local/pixelator/single-cell/annotate/main.nf index 87042d3a..5096ff50 100644 --- a/modules/local/pixelator/single-cell/annotate/main.nf +++ b/modules/local/pixelator/single-cell/annotate/main.nf @@ -5,7 +5,7 @@ process PIXELATOR_ANNOTATE { conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: diff --git a/modules/local/pixelator/single-cell/collapse/main.nf b/modules/local/pixelator/single-cell/collapse/main.nf index ce50ecbb..765e51e9 100644 --- a/modules/local/pixelator/single-cell/collapse/main.nf +++ b/modules/local/pixelator/single-cell/collapse/main.nf @@ -5,7 +5,7 @@ process PIXELATOR_COLLAPSE { conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: diff --git a/modules/local/pixelator/single-cell/demux/main.nf b/modules/local/pixelator/single-cell/demux/main.nf index 0c3138e4..19bfe96e 100644 --- a/modules/local/pixelator/single-cell/demux/main.nf +++ b/modules/local/pixelator/single-cell/demux/main.nf @@ -5,7 +5,7 @@ process PIXELATOR_DEMUX { conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: diff --git a/modules/local/pixelator/single-cell/graph/main.nf b/modules/local/pixelator/single-cell/graph/main.nf index 132deb28..e14f74cb 100644 --- a/modules/local/pixelator/single-cell/graph/main.nf +++ b/modules/local/pixelator/single-cell/graph/main.nf @@ -5,7 +5,7 @@ process PIXELATOR_GRAPH { conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: diff --git a/modules/local/pixelator/single-cell/layout/main.nf b/modules/local/pixelator/single-cell/layout/main.nf index 9e8de554..00e414ec 100644 --- a/modules/local/pixelator/single-cell/layout/main.nf +++ b/modules/local/pixelator/single-cell/layout/main.nf @@ -5,7 +5,7 @@ process PIXELATOR_LAYOUT { conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: diff --git a/modules/local/pixelator/single-cell/qc/main.nf b/modules/local/pixelator/single-cell/qc/main.nf index a5878e78..49f28504 100644 --- a/modules/local/pixelator/single-cell/qc/main.nf +++ b/modules/local/pixelator/single-cell/qc/main.nf @@ -5,7 +5,7 @@ process PIXELATOR_QC { conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: diff --git a/modules/local/pixelator/single-cell/report/main.nf b/modules/local/pixelator/single-cell/report/main.nf index 900e4b23..fe443316 100644 --- a/modules/local/pixelator/single-cell/report/main.nf +++ b/modules/local/pixelator/single-cell/report/main.nf @@ -5,7 +5,7 @@ process PIXELATOR_REPORT { conda "bioconda::pixelator=0.19.0" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pixelator:pixelator:0.19.0--pyhdfd78af_0' : + 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" input: From feefc84e1aca1705590c5ba6cc84b8b993522de2 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Fri, 20 Dec 2024 16:54:30 +0100 Subject: [PATCH 37/70] Template update for nf-core/tools version 3.1.0 --- .editorconfig | 4 + .github/CONTRIBUTING.md | 2 + .github/ISSUE_TEMPLATE/bug_report.yml | 1 - .github/PULL_REQUEST_TEMPLATE.md | 4 +- .github/workflows/download_pipeline.yml | 41 +- .nf-core.yml | 10 +- .prettierignore | 1 + CITATIONS.md | 6 + LICENSE | 2 +- README.md | 12 +- assets/methods_description_template.yml | 29 ++ assets/multiqc_config.yml | 15 + assets/nf-core-pixelator_logo_light.png | Bin 80637 -> 80620 bytes assets/schema_input.json | 2 +- assets/sendmail_template.txt | 22 + conf/igenomes.config | 440 ++++++++++++++++++ conf/igenomes_ignored.config | 9 + conf/modules.config | 13 + conf/test.config | 5 +- conf/test_full.config | 4 +- docs/images/nf-core-pixelator_logo_dark.png | Bin 29213 -> 29125 bytes docs/images/nf-core-pixelator_logo_light.png | Bin 24897 -> 24878 bytes docs/output.md | 30 +- docs/usage.md | 7 +- main.nf | 16 + modules.json | 13 +- modules/nf-core/fastqc/environment.yml | 5 + modules/nf-core/fastqc/main.nf | 64 +++ modules/nf-core/fastqc/meta.yml | 67 +++ modules/nf-core/fastqc/tests/main.nf.test | 309 ++++++++++++ .../nf-core/fastqc/tests/main.nf.test.snap | 392 ++++++++++++++++ modules/nf-core/fastqc/tests/tags.yml | 2 + modules/nf-core/multiqc/environment.yml | 5 + modules/nf-core/multiqc/main.nf | 63 +++ modules/nf-core/multiqc/meta.yml | 78 ++++ modules/nf-core/multiqc/tests/main.nf.test | 92 ++++ .../nf-core/multiqc/tests/main.nf.test.snap | 41 ++ modules/nf-core/multiqc/tests/nextflow.config | 5 + modules/nf-core/multiqc/tests/tags.yml | 2 + nextflow.config | 22 +- nextflow_schema.json | 76 ++- ro-crate-metadata.json | 55 ++- .../utils_nfcore_pixelator_pipeline/main.nf | 46 +- tower.yml | 2 + workflows/pixelator.nf | 56 ++- 45 files changed, 2000 insertions(+), 70 deletions(-) create mode 100644 assets/methods_description_template.yml create mode 100644 assets/multiqc_config.yml create mode 100644 conf/igenomes.config create mode 100644 conf/igenomes_ignored.config create mode 100644 modules/nf-core/fastqc/environment.yml create mode 100644 modules/nf-core/fastqc/main.nf create mode 100644 modules/nf-core/fastqc/meta.yml create mode 100644 modules/nf-core/fastqc/tests/main.nf.test create mode 100644 modules/nf-core/fastqc/tests/main.nf.test.snap create mode 100644 modules/nf-core/fastqc/tests/tags.yml create mode 100644 modules/nf-core/multiqc/environment.yml create mode 100644 modules/nf-core/multiqc/main.nf create mode 100644 modules/nf-core/multiqc/meta.yml create mode 100644 modules/nf-core/multiqc/tests/main.nf.test create mode 100644 modules/nf-core/multiqc/tests/main.nf.test.snap create mode 100644 modules/nf-core/multiqc/tests/nextflow.config create mode 100644 modules/nf-core/multiqc/tests/tags.yml diff --git a/.editorconfig b/.editorconfig index 72dda289..6d9b74cc 100644 --- a/.editorconfig +++ b/.editorconfig @@ -31,3 +31,7 @@ indent_size = unset # ignore python and markdown [*.{py,md}] indent_style = unset + +# ignore ro-crate metadata files +[**/ro-crate-metadata.json] +insert_final_newline = unset diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e091e270..332a5c4a 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -79,6 +79,8 @@ If you wish to contribute a new step, please use the following coding standards: 6. Add sanity checks and validation for all relevant parameters. 7. Perform local tests to validate that the new code works as expected. 8. If applicable, add a new test command in `.github/workflow/ci.yml`. +9. Update MultiQC config `assets/multiqc_config.yml` so relevant suffixes, file name clean up and module plots are in the appropriate order. If applicable, add a [MultiQC](https://https://multiqc.info/) module. +10. Add a description of the output files and if relevant any appropriate images from the MultiQC report to `docs/output.md`. ### Default values diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 88f2d3e4..324c7da5 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -9,7 +9,6 @@ body: - [nf-core website: troubleshooting](https://nf-co.re/usage/troubleshooting) - [nf-core/pixelator pipeline documentation](https://nf-co.re/pixelator/usage) - - type: textarea id: description attributes: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3e33e429..b107a8e1 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -8,14 +8,14 @@ These are the most common things requested on pull requests (PRs). Remember that PRs should be made against the dev branch, unless you're preparing a pipeline release. -Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/pixelator/tree/master/.github/CONTRIBUTING.md) +Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/pixelator/tree/main/.github/CONTRIBUTING.md) --> ## PR checklist - [ ] 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/pixelator/tree/master/.github/CONTRIBUTING.md) +- [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/nf-core/pixelator/tree/main/.github/CONTRIBUTING.md) - [ ] If necessary, also make a PR on the nf-core/pixelator _branch_ on the [nf-core/test-datasets](https://github.com/nf-core/test-datasets) repository. - [ ] Make sure your code lints (`nf-core pipelines lint`). - [ ] Ensure the test suite passes (`nextflow run . -profile test,docker --outdir `). diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml index 2576cc0c..13b51e2c 100644 --- a/.github/workflows/download_pipeline.yml +++ b/.github/workflows/download_pipeline.yml @@ -28,8 +28,12 @@ env: NXF_ANSI_LOG: false jobs: - download: + configure: runs-on: ubuntu-latest + outputs: + REPO_LOWERCASE: ${{ steps.get_repo_properties.outputs.REPO_LOWERCASE }} + REPOTITLE_LOWERCASE: ${{ steps.get_repo_properties.outputs.REPOTITLE_LOWERCASE }} + REPO_BRANCH: ${{ steps.get_repo_properties.outputs.REPO_BRANCH }} steps: - name: Install Nextflow uses: nf-core/setup-nextflow@v2 @@ -53,22 +57,27 @@ jobs: pip install git+https://github.com/nf-core/tools.git@dev - name: Get the repository name and current branch set as environment variable + id: get_repo_properties run: | - echo "REPO_LOWERCASE=${GITHUB_REPOSITORY,,}" >> ${GITHUB_ENV} - echo "REPOTITLE_LOWERCASE=$(basename ${GITHUB_REPOSITORY,,})" >> ${GITHUB_ENV} - echo "REPO_BRANCH=${{ github.event.inputs.testbranch || 'dev' }}" >> ${GITHUB_ENV} + echo "REPO_LOWERCASE=${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT" + echo "REPOTITLE_LOWERCASE=$(basename ${GITHUB_REPOSITORY,,})" >> "$GITHUB_OUTPUT" + echo "REPO_BRANCH=${{ github.event.inputs.testbranch || 'dev' }}" >> "$GITHUB_OUTPUT" - name: Make a cache directory for the container images run: | mkdir -p ./singularity_container_images + download: + runs-on: ubuntu-latest + needs: configure + steps: - name: Download the pipeline env: NXF_SINGULARITY_CACHEDIR: ./singularity_container_images run: | - nf-core pipelines download ${{ env.REPO_LOWERCASE }} \ - --revision ${{ env.REPO_BRANCH }} \ - --outdir ./${{ env.REPOTITLE_LOWERCASE }} \ + nf-core pipelines download ${{ needs.configure.outputs.REPO_LOWERCASE }} \ + --revision ${{ needs.configure.outputs.REPO_BRANCH }} \ + --outdir ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }} \ --compress "none" \ --container-system 'singularity' \ --container-library "quay.io" -l "docker.io" -l "community.wave.seqera.io/library/" \ @@ -76,14 +85,14 @@ jobs: --download-configuration 'yes' - name: Inspect download - run: tree ./${{ env.REPOTITLE_LOWERCASE }} + run: tree ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }} - name: Count the downloaded number of container images id: count_initial run: | image_count=$(ls -1 ./singularity_container_images | wc -l | xargs) echo "Initial container image count: $image_count" - echo "IMAGE_COUNT_INITIAL=$image_count" >> ${GITHUB_ENV} + echo "IMAGE_COUNT_INITIAL=$image_count" >> "$GITHUB_OUTPUT" - name: Run the downloaded pipeline (stub) id: stub_run_pipeline @@ -91,27 +100,27 @@ jobs: env: NXF_SINGULARITY_CACHEDIR: ./singularity_container_images 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 ./${{needs.configure.outputs.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ needs.configure.outputs.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() }} + if: ${{ steps.stub_run_pipeline.outcome == 'failure' }} env: NXF_SINGULARITY_CACHEDIR: ./singularity_container_images NXF_SINGULARITY_HOME_MOUNT: true - run: nextflow run ./${{ env.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ env.REPO_BRANCH }}) -profile test,singularity --outdir ./results + run: nextflow run ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ needs.configure.outputs.REPO_BRANCH }}) -profile test,singularity --outdir ./results - name: Count the downloaded number of container images id: count_afterwards run: | image_count=$(ls -1 ./singularity_container_images | wc -l | xargs) echo "Post-pipeline run container image count: $image_count" - echo "IMAGE_COUNT_AFTER=$image_count" >> ${GITHUB_ENV} + echo "IMAGE_COUNT_AFTER=$image_count" >> "$GITHUB_OUTPUT" - name: Compare container image counts run: | - if [ "${{ env.IMAGE_COUNT_INITIAL }}" -ne "${{ env.IMAGE_COUNT_AFTER }}" ]; then - initial_count=${{ env.IMAGE_COUNT_INITIAL }} - final_count=${{ env.IMAGE_COUNT_AFTER }} + if [ "${{ steps.count_initial.outputs.IMAGE_COUNT_INITIAL }}" -ne "${{ steps.count_afterwards.outputs.IMAGE_COUNT_AFTER }}" ]; then + initial_count=${{ steps.count_initial.outputs.IMAGE_COUNT_INITIAL }} + final_count=${{ steps.count_afterwards.outputs.IMAGE_COUNT_AFTER }} difference=$((final_count - initial_count)) echo "$difference additional container images were \n downloaded at runtime . The pipeline has no support for offline runs!" tree ./singularity_container_images diff --git a/.nf-core.yml b/.nf-core.yml index fad0297f..1d103dc1 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -1,9 +1,7 @@ lint: files_exist: - - assets/multiqc_config.yml - - conf/igenomes.config - files_unchanged: - - assets/nf-core-pixelator_logo_light.png + - assets/multiqc_config.yml + - conf/igenomes.config multiqc_config: false nf_core_version: 3.1.0 repository_type: pipeline @@ -15,8 +13,4 @@ template: name: pixelator org: nf-core outdir: . - skip_features: - - fastqc - - multiqc - - igenomes version: 1.3.1 diff --git a/.prettierignore b/.prettierignore index 437d763d..edd29f01 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,3 +10,4 @@ testing/ testing* *.pyc bin/ +ro-crate-metadata.json diff --git a/CITATIONS.md b/CITATIONS.md index 4a9a8d3d..7bc0af15 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -10,6 +10,12 @@ ## Pipeline tools +- [FastQC](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/) + +> 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 - [Anaconda](https://anaconda.com) diff --git a/LICENSE b/LICENSE index c94e986a..036449a8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) Pixelgen Technologies AB +Copyright (c) The nf-core/pixelator team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 539057b6..d8501206 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,7 @@ nf-core/pixelator - - -[![GitHub Actions CI Status](https://github.com/nf-core/pixelator/actions/workflows/ci.yml/badge.svg)](https://github.com/nf-core/pixelator/actions/workflows/ci.yml) +[![GitHub Actions CI Status](https://github.com/nf-core/pixelator/actions/workflows/ci.yml/badge.svg)](https://github.com/nf-core/pixelator/actions/workflows/ci.yml) [![GitHub Actions Linting Status](https://github.com/nf-core/pixelator/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/pixelator/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/pixelator/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) @@ -29,12 +27,12 @@ - +1. Read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/))2. Present QC for raw reads ([`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. +> 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. - - - + 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/assets/methods_description_template.yml b/assets/methods_description_template.yml new file mode 100644 index 00000000..2b6ed3cd --- /dev/null +++ b/assets/methods_description_template.yml @@ -0,0 +1,29 @@ +id: "nf-core-pixelator-methods-description" +description: "Suggested text and references to use when describing pipeline usage within the methods section of a publication." +section_name: "nf-core/pixelator Methods Description" +section_href: "https://github.com/nf-core/pixelator" +plot_type: "html" +## 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/pixelator 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. 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:
    +
      + ${nodoi_text} +
    • The command above does not include parameters contained in any configs or profiles that may have been used. Ensure the config file is also uploaded with your publication!
    • +
    • You should also cite all software used within this run. Check the "Software Versions" of this report to get version information.
    • +
    +
    diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml new file mode 100644 index 00000000..adefdf6c --- /dev/null +++ b/assets/multiqc_config.yml @@ -0,0 +1,15 @@ +report_comment: > + This report has been generated by the nf-core/pixelator + analysis pipeline. For information about how to interpret these results, please see the + documentation. +report_section_order: + "nf-core-pixelator-methods-description": + order: -1000 + software_versions: + order: -1001 + "nf-core-pixelator-summary": + order: -1002 + +export_plots: true + +disable_version_detection: true diff --git a/assets/nf-core-pixelator_logo_light.png b/assets/nf-core-pixelator_logo_light.png index 9b643424a35ba9d3c7dd653522220ea377485add..ab111c85aca3cf58f66fffb87c583467bcf16beb 100644 GIT binary patch delta 46017 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

    eVP3+bqHT#dWfb*Lnit;f8hE!c_oqNc?E_`!} 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 delta 47161 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 diff --git a/assets/schema_input.json b/assets/schema_input.json index 148fd766..8fe831e4 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://raw.githubusercontent.com/nf-core/pixelator/master/assets/schema_input.json", + "$id": "https://raw.githubusercontent.com/nf-core/pixelator/main/assets/schema_input.json", "title": "nf-core/pixelator pipeline - params.input schema", "description": "Schema for the file provided with params.input", "type": "array", diff --git a/assets/sendmail_template.txt b/assets/sendmail_template.txt index 6792160f..5a184630 100644 --- a/assets/sendmail_template.txt +++ b/assets/sendmail_template.txt @@ -26,6 +26,28 @@ Content-Disposition: inline; filename="nf-core-pixelator_logo_light.png" join( '\n' ) %> <% +if (mqcFile){ +def mqcFileObj = new File("$mqcFile") +if (mqcFileObj.length() < mqcMaxSize){ +out << """ +--nfcoremimeboundary +Content-Type: text/html; name=\"multiqc_report\" +Content-Transfer-Encoding: base64 +Content-ID: +Content-Disposition: attachment; filename=\"${mqcFileObj.getName()}\" + +${mqcFileObj. + bytes. + encodeBase64(). + toString(). + tokenize( '\n' )*. + toList()*. + collate( 76 )*. + collect { it.join() }. + flatten(). + join( '\n' )} +""" +}} %> --nfcoremimeboundary-- diff --git a/conf/igenomes.config b/conf/igenomes.config new file mode 100644 index 00000000..3f114377 --- /dev/null +++ b/conf/igenomes.config @@ -0,0 +1,440 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for iGenomes paths +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Defines reference genomes using iGenome paths. + Can be used by any config that customises the base path using: + $params.igenomes_base / --igenomes_base +---------------------------------------------------------------------------------------- +*/ + +params { + // illumina iGenomes reference file paths + genomes { + 'GRCh37' { + fasta = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/README.txt" + mito_name = "MT" + macs_gsize = "2.7e9" + blacklist = "${projectDir}/assets/blacklists/GRCh37-blacklist.bed" + } + 'GRCh38' { + fasta = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Annotation/Genes/genes.bed" + mito_name = "chrM" + 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/" + bowtie2 = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/README.txt" + mito_name = "MT" + macs_gsize = "1.87e9" + blacklist = "${projectDir}/assets/blacklists/GRCm38-blacklist.bed" + } + 'TAIR10' { + fasta = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/README.txt" + mito_name = "Mt" + } + 'EB2' { + fasta = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/README.txt" + } + 'UMD3.1' { + fasta = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/README.txt" + mito_name = "MT" + } + 'WBcel235' { + fasta = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.bed" + mito_name = "MtDNA" + macs_gsize = "9e7" + } + 'CanFam3.1' { + fasta = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/README.txt" + mito_name = "MT" + } + 'GRCz10' { + fasta = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.bed" + mito_name = "MT" + } + 'BDGP6' { + fasta = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.bed" + mito_name = "M" + macs_gsize = "1.2e8" + } + 'EquCab2' { + fasta = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/README.txt" + mito_name = "MT" + } + 'EB1' { + fasta = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/README.txt" + } + 'Galgal4' { + fasta = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.bed" + mito_name = "MT" + } + 'Gm01' { + fasta = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/README.txt" + } + 'Mmul_1' { + fasta = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/README.txt" + mito_name = "MT" + } + 'IRGSP-1.0' { + fasta = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.bed" + mito_name = "Mt" + } + 'CHIMP2.1.4' { + fasta = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/README.txt" + mito_name = "MT" + } + 'Rnor_5.0' { + fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Annotation/Genes/genes.bed" + mito_name = "MT" + } + 'Rnor_6.0' { + fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.bed" + mito_name = "MT" + } + 'R64-1-1' { + fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.bed" + mito_name = "MT" + macs_gsize = "1.2e7" + } + 'EF2' { + fasta = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/README.txt" + mito_name = "MT" + macs_gsize = "1.21e7" + } + 'Sbi1' { + fasta = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/README.txt" + } + 'Sscrofa10.2' { + fasta = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/README.txt" + mito_name = "MT" + } + 'AGPv3' { + fasta = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.bed" + mito_name = "Mt" + } + 'hg38' { + fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Annotation/Genes/genes.bed" + mito_name = "chrM" + macs_gsize = "2.7e9" + blacklist = "${projectDir}/assets/blacklists/hg38-blacklist.bed" + } + 'hg19' { + fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/README.txt" + mito_name = "chrM" + macs_gsize = "2.7e9" + blacklist = "${projectDir}/assets/blacklists/hg19-blacklist.bed" + } + 'mm10' { + fasta = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/README.txt" + mito_name = "chrM" + macs_gsize = "1.87e9" + blacklist = "${projectDir}/assets/blacklists/mm10-blacklist.bed" + } + 'bosTau8' { + fasta = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Annotation/Genes/genes.bed" + mito_name = "chrM" + } + 'ce10' { + fasta = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/README.txt" + mito_name = "chrM" + macs_gsize = "9e7" + } + 'canFam3' { + fasta = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/README.txt" + mito_name = "chrM" + } + 'danRer10' { + fasta = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Annotation/Genes/genes.bed" + mito_name = "chrM" + macs_gsize = "1.37e9" + } + 'dm6' { + fasta = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Annotation/Genes/genes.bed" + mito_name = "chrM" + macs_gsize = "1.2e8" + } + 'equCab2' { + fasta = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/README.txt" + mito_name = "chrM" + } + 'galGal4' { + fasta = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/README.txt" + mito_name = "chrM" + } + 'panTro4' { + fasta = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/README.txt" + mito_name = "chrM" + } + 'rn6' { + fasta = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Annotation/Genes/genes.bed" + mito_name = "chrM" + } + 'sacCer3' { + fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BismarkIndex/" + readme = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Annotation/README.txt" + mito_name = "chrM" + macs_gsize = "1.2e7" + } + 'susScr3' { + fasta = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/README.txt" + mito_name = "chrM" + } + } +} diff --git a/conf/igenomes_ignored.config b/conf/igenomes_ignored.config new file mode 100644 index 00000000..b4034d82 --- /dev/null +++ b/conf/igenomes_ignored.config @@ -0,0 +1,9 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for iGenomes paths +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Empty genomes dictionary to use when igenomes is ignored. +---------------------------------------------------------------------------------------- +*/ + +params.genomes = [:] diff --git a/conf/modules.config b/conf/modules.config index e27fd282..d203d2b6 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -18,4 +18,17 @@ process { saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] + withName: FASTQC { + ext.args = '--quiet' + } + + withName: 'MULTIQC' { + ext.args = { params.multiqc_title ? "--title \"$params.multiqc_title\"" : '' } + publishDir = [ + path: { "${params.outdir}/multiqc" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + } diff --git a/conf/test.config b/conf/test.config index 5e51871f..8cf7cacf 100644 --- a/conf/test.config +++ b/conf/test.config @@ -25,7 +25,6 @@ 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 = params.pipelines_testdata_base_path + '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 54efb7a8..b8f7cf2a 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -19,6 +19,6 @@ params { // TODO nf-core: Give any required params for the test so that command line flags are not needed input = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_full_illumina_amplicon.csv' - // Fasta references - fasta = params.pipelines_testdata_base_path + 'viralrecon/genome/NC_045512.2/GCF_009858895.2_ASM985889v3_genomic.200409.fna.gz' + // Genome references + genome = 'R64-1-1' } diff --git a/docs/images/nf-core-pixelator_logo_dark.png b/docs/images/nf-core-pixelator_logo_dark.png index 52301749c18ffbb1d10f440600845a109b624a41..ab978d7d9f8ee5ee903730164b03335980fd9967 100644 GIT binary patch literal 29125 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 PGeRuQE+8vSJ#YRm_BN){ literal 29213 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 O#N5mVS!v>R>;D0>X%k@p diff --git a/docs/images/nf-core-pixelator_logo_light.png b/docs/images/nf-core-pixelator_logo_light.png index 283c6c5a9a221f28926c1334b079e4632b6738e0..07f4781b577a0bae5f51d9cd65f4e0e432959a81 100644 GIT binary patch literal 24878 zcmd42Rao2I6D=GdSaH{)!M(Us+`YIJDOQ|9@IY~Qm*U0UTHGn_?pEC0PWpepyYKc~ zoD1?i1d`w0GqY!AuURWhRapk@9q~H=0DvYZE2$0u!0G@1FhC>(=sVZl@}tmSysRZ8 zROKWjC{&#tzF2>?006+5-{RJpzN--qi1JV^QyDZn)^JtwjLvLHr*YZHaauGluDz%) zx3-;uT0YrpCpKRk1$034cl8*kXx#sBJAF4A|6S2&K7PPIzVAKmkv-;tu0y3uQ_Sm0 znZjnZY0}A0Zs^F0n$+yO z?u72#h5(z(XvdWJFq**ez}0jE)%&rTZ3|y+e#1S7ga%nKDf3D9m@C?VtW zN&~k~B`X8oVZv!S8A%IFYu}YqDPS@cIlB0K5s2azV-U&VYV(xan-WDw!*>`zl$Gb# zD5j&rujEzA-xTyF{*@!rog009J1NU1zDz1xhMTzlN_gfo(TXN2)pIZKAu`9TTBOUO zJ-x#jsfRp|pe+3eu*9?ZTw2=azG;f`i+nZ}pGi*3Nr4gGp?D)yd>^fzHQ7sRaeoJf zisbUse03AXi*vi(0l|5{Wp#ZPnlAugY%eGIQ4^ebvg)1*`qaXEzJ8XeG5h%o51W(w zN9WiABw2*MKzZ!Sw0a7I-mJpvAjdG9E5xWi9VRPPx7z@tKbLSPlphfiyFlsKnz zOUJHWC)?P|NjytSi@iLv&-OWwYc;+drcHcO$vGz#V<=2im;Zn6MM?4474UCahen8` zj*v1oL%s_7E=|j?$bdsE1RUF(y6K{d)`OyqE#-lQD6X!5TbNO3_1tISK}t9`fvtk8 zW&+lUU1K4^h*5k3Fu{l*53XA|nrX`U-W7+Cc^1{hxnn3*|Jyn|V8LPFy`?@aIb`E~ z@Cq)70v5*T8E16IpY)=bLixEz_IxShwBxO2Omf}OpcqaS`Y6r)_s!cpbg)B~ETgn! zuxyv&Y>}a@I}0fw11bubc>PCJgnpjG(?aBA=mWU@PpW&+Hx+4(Ik}3FiHC4uz_Ny| z%rnqGa zXO6z-p->^+2(#?~6BI%}H0z?6IO8g6f1;RT2>;dFv7rNIy zI`;B0Yp$Z*64frJF@6}8z?jt%yiS92TR0W6d_X>f!Ng=c->OOov|Mvt_i1vYdbKb5 zZ{0BO>w6j<@Os`Z*We@#u|@BSyvXk_^i&8-y;)D0JYcI3F92cWYmRp>9U-@R6>;cT zjL=}h8EF?h;hLqH9PM`$1e}Mx?L^(J`MDKuAJP;}!_Y(j!{+N^vu|EQQJg_oMAwZY|8D`pxjM}DUm{!4S!OJ-{qZ&%W^KN05(dt3gW}qvxJOSM z&0j07_C?nZQazJs{~6gcfJOvuGmPauvkv;DwjFxO5#gXc6>L1jQJf~lOljW)8pFhQ z;eA`AFwtLc!0N0&H5nt8i8Pw{Hz07Np`#FKf*hpmzmBrPO8;BHb~XnX!@s10l&KT5 z!eHh!_19QDjfQ0NQ0aw+*-lAx|Ma$NXtj*p{j&RAQdyAi*|s|9qpU*^JSss7TBY~j z+zJGzIozaEqH`wXgBh)`9w%66G@}6aZ>1KBZicPB*!Mp!r>& zitv^^J4?LTymQ0r;vwx0M&{7P1fp-5V8O;G9lPHNgwv6A@;=TqDYNBRr91J<30{p5w1AlkkkK83q%h$o5R%d&tP-dCGtANw$o&)GsI+Ktb zUwSja0WO?r-X&?%ZcH+R2b(wRwUv%ieq$l6rSnYtoQ`j_PO#=G<-Ji%XZDXY z{tyBrOZhw6hJ{(|G$1jMzDuFx`B`2RJe;Td(j-LAd8-9X6lro_$5FWBY>?EluffVM zc`?a^z;Xp+J;Ynn27j3~NI0=RK7#3-X|>!UPj#7H$)I?x9mr4O-AWyf=avzy`8zSe z$9@&;cgDtA_BMk1U80b9cfOiiER*?`!_CNbL`rW|n}NIXI!WFbxMK#5>R1b-X4?im z!->=8CF?qcnAO3MO|tV^j8JWVFcCZnEImgx;9-jHck4NMHF5s=jAP-MzeW4`#8n)_ z>?SW)0)q*5^JDFa^{Xx+9qo`+~ z!wTso3-zI1{IH_Zy6SNIiO%q#;$dN{Df71K!NM`$}!VE8G^0yP{TenarCz| z8}SkEl;dN>2!W0C;cOCguarfe)1r1UOh>t0PftL+@y#_qV6lRR#d=uwTa%qG z$**l4ntJUg$Cnyjc9zL@ytWI7b1Ln3PG&Z0Gd5elJfE;>Ab0G!!c*ZLzPCwqt@hVw zHwa4AzZUwna|{q1Y0*kFCX>_;;d3cfi2E*hH5rpS8d%bKQhjETGe%kt3vx)9uB=9k z&Zh_it{#L@|H5BqV>dfGUZFi@FS!Wz!tFNu4PAZWAo_xdOwm9HvgCBU`eMv~m%0)_ zCd1WrXv%u)z>~Xb=d;=lO|x-{!<)8Z$8(1lWY1*%li>$SRjI!T4k|6JV*DM@Um7?) zvDh!p`>M}ZSoIV0+D*IphPe+*YB8YWA(mch*5AK)x=hwZI zoN8TGyJ#Hfca`v`jIL&O`eIwIboFDRvgkOn`36?j1gJuNlIG0603VRNe}nld4oKn& zPRtms68Nl-@NBHdsd4z8xCN7I&vkdve5Y%|?hvg5o!_Nf$lDd~bCYu|2Hbp(1voZ0 zXeOZ$o5l}2Mi8x95%Pgv|2to5pJQ@N0`k>xW#S=BHl06xz4OmdAt{n)wuzUZ0ZYTj z-1rncf?5;a(Oih@e4Hn$fLHHv8UFiUnD-XN+e9ePMKfR>kE14_9-w*)KXAO;<3w3^ zeeEgp^NnCqUZkk(Bd0lca8mnSm#Ds4Wx(oyniFZ-&E+S+#dYoaMD-^ISu1l)yxM_{ zRvSPpY!+-1sdDUiFxioXw0vR}FdH={G!2PxQ~a%0u;_Br6BJ?$7MiPlJ&(&D^C9je zs@ofFV^x$Fehk-=zriK%h~VPX7y4z|+EHC`v16X#F))g7j}_+S^)aCr*<>{PyW3?u z;I(S{qCSIG$Ixo5EIT_gG$TTV3Nm_B&pCz%2D_ljFcb>>32ns?o7mcnfp6Gqb?Z+^si+k8!4CC_ zYgpR^Q^O*8wIkY^DmtfdjxxQq_lkIFk81JCm6s&ZcvtQ{JqEu#o3Tbr*y+>jB!9?a zJFcvFDH(^2JKv?C!72Q~zj6XDFq_p-8Smnq~p zfG*p(nC1cW=%}cP@gQWWUScyUUM@}jHTnYFTtQDM`9gK;bdC$nGsDU7L`l%sXK%&6 zUMH!5jm6yDTnj=B_#boms`Ou3W2qM|8}ToDc6Hjzvp9BXN;Tbn^p$I(q|cdsija(; zIU7*VH+@dlH}vw{%;ohdn>%n^D%8eiw)egnn$EgMLvB^XwnwI}gVw2dP7a63ddoqo zB4Cgs9}*?m2mVk5{t}+2KR78psr#ER8X)q5IK=$)6&zF=6nxUR9vixL!rXdaHr?$9 z-<5UE-?KYIsl-ydED&?LcZ~!lJe^Stsf?0wR=8rgUF?(+;;0(c;+^mXLKKNIghOUQ z^m_L~)p_5Ios$p3^Xaw> zy2K283%qcLJw5B`=}{24=Wh6VX|7l?ub@Bqlx0;d3|s~*$PN;Tl%~M&1!%?dg+~Pa zjER(Fmo&)*#KgYBV0hUUsz1;z8PIrBpf+9fAG5}4`>)`2GKc28bD$%Vr2vZYeDJ!! zv^|XP9sbj|#R(+C+hD_O>BEcgGj8|x29Z${ZSch>=<{mDWNvLRx zajW6_9X6mWo(9*2y8RWvyEQLckoIS|<5q*)L6Pkl84xD6RY295&-MHrY$P~x-@lLE z0k$x@aPXaFSf=eK?=n{ks+0sS4C{CW7NlOw+EU0}asu32@1-izCSt>khpZ>1P|yz* zKk$>`M)dLb4|bjNCH7_mc)KEmKUqrx@FO7ahAxh?-Pw_yUWUEZFpDtdZ39qdkY;hNC`Q9=Zs^XK^qskA)@MQi^K0{ z(dO%C)P*0>H_H61Cf<&>aSEJLApuY3Q{5NRyt!KxI@_Y3G^}cxIJarG!gUVo3GE_E zBpqIyL^7zd(DAl}>EU~YH z)em3KVK3U_WOr*qu#xq6ZjTg%KyiqGhZ58$6#Vw9ExKABQLnYIw=Yi-qWVWXd|@)l z!bk_qCi?f2dT>OgBIH$(jUHPI3fT%iU1YPy%%@Df7gWxKLkD)PiAd)ZlpW{nDO!w4 z%W-EDrhX-w;1sM()Jr`6#@||_=0^napmpNtJio|3?sV$%Xxke70u(Pwd-b^RznuYxChq zkv47scRx0R9gE@=Y1;Ya?7y1kaz>eh>8V8$d-z7s+U-c~w8K!g>IO z8eSsV*GsY^ZD3P&sFrBr$MkU{b~`TjrcxufqV=YN5&;xj9l{0`IoX%j{?0Y`FaXO~ z!m>xPPh#yNnk89iCXSJn{KS=2I``CrZF>AVzMdn~-%3lo zGp1oMxzF?c(e>&3n2!q{4te~p%y?1*w0z>pI zUDNoPZ{m|nHBXxR%CXpSM&G3s(yi%+JVeZNUA9y}lTOkUqnE7y3x4^--tn$VE4p^p zd3#WZ<=LqEsu}Hsr~#ulaqQi9W_S8XNT=%GC z&CX4s`T=#4e4$<0@5hKfAEDhBhe5O3w4G)7}W_-PnX@E1%U)=0{9ij^FsgPls~58SBDkQ!Ls-y!Q)l z`qv}qAZ7C|J1Vuy_^JWIywrQ^gLbcN32o4S5&6!W9Nrk|%I z?3!MbZ`#~k4c5H1bm*)YLpTG$I9-*^#SNt$xMZ6+*)p}WFE`FIjt;ix8O|-nD`dzwKT4B><*EPP!!}$r6MX?!eHGGR)Joe0Y24kj3moBZ94|R z=pxE{5vfhaw~r2M+*C?>2pd>&SH6$W`QtB$opn(h{tlJuk*y}4gt+asi_$%3zE)~J zK`D-QhSwYb6uC7HyC0A3XvK?*pC?ipYVGeKZ!#s~WzQ>9Zr@qvr98-Nb zN;wl8pV`Ln7YfQfN$}jZ5gb!lu<|Y6!ki30tZ$}1)+eggPCe*?~1&0UqY;m|?7P2BuT3OGA*6=KY4H@z^#GyqWPpVY9bGUHpKoO3p| zZoSpggY;0_B zW<^Res{kgZ*xN#d(9Han_F|o7y3B8b&S(Gfc=~?n!XkJ^U|a1lV}K01H(&oP({`Tn zi{E3$hhv)EVH9xhHVZMXcJ-NGa6D4+-9JDS^)rDM8vTaHEhIN3q3CRm7Vt}W?w=e) zrrl2xL9jpeq>MOA4ESB<5WY-{PiSAg8b1okb`$1lMTrWUm8p0Kvm6W7{vC|4U%o#~ zSjU`+AMe_bs1BB!+VmK-n|mND557pyje_1b9fdwm53BI~oUZvf35^im?|kHhZ$o&H z2~2`G7Kh;F&(D%A27HtXC{yM9JZp*HO$fpbAeHi!>4Vy`q<$p{l-GB6YLptZ(@49wgNR){l=Z1OEc^I2bXP>wc@PhHxGN128 zDny;WFb&Nz{zG%lw`B|*gYRBf<&Jaw%1`wx#za}aDFkqfgh9pxBwp#pX3ln@7-5S0 z_x+fOt=~KL^V-bqIh~YQ(Po-L?TJpZHY;r$83>Abb)poLmDs3@SOdxOh4}*CJmlj2 z;98s_LbOxwQI?5SGnjw5Os}&DJwLnPzrVUk4(1^jeeOmfgT72l>jS)&GGkVEh3!$l zr=aW1wwV+=m)!R=yflO(0pvv5haxvI?1l0bKZMSG$kU|fo3Xhd&#s((TesRGw4THw zc;O-nUnA7L{ffpchEqNQ3ja7fZ{K*dk|p>)!e-Rf1hSSRQ%kouuEdDjh&xy;@P5E5 zF7q_%fsuB?=cg8}kbVI_jg9JrzaPOPlu(tLaz3T@ZLh`Jlu3~?!=~_lDhRftW z4-PA^(E$S4=|(b5d1@OU)08Z=qI38QtI#=Y)6(JNL$^TwgO*0GmvtXb2y6eQM%e4S z-aq&aPDwW%t&%L49v%m?v3l7J^a{Wb{t}~i80~PHMW0pQ)S&SEl0TVx*~LQ_adN~! zh0a3oZo6!srO+9(6?VgKXEr-jh$+DD-Hr-mg*o826ez{h4cJ(b{BB@(a?UDIev^_y z-=~hz)X`oa?hxyTtj=gs-vu_-wiYl zJR~wCPLWqRhJ-Pw%c@W))L^kn)IhL0h^m-z=Rp;&tzuiC9GMUTF-Igx5yVQrd<(3a zq7CA(_4M-6rzC8+-?xo2wFuZx@l`Xl{qg94m(R`LAt%{{@8Nz%$VQom_8a6jw$8l^ z>c$7GCun=Y3W;?o6|A5SCScYjnzQ8QD2^W(nUfHoqHN5LSb~$-pXnh-lkZ7ns?wvk zGW^I};6l58MQ~OG%u)PfHcJQIkEC+u`r~>4gUgub>jC0;JB{Pspm~EOirg4$a3NTj z=}wL+e5;qpyDh8cHvS^VB+kTY)7DAJv?a#LIihn#jtwKdQ|NOUVRSbiPkf;1cagBI z(YSLwDli<{ovDe^T=-!;IMi{OrBdkI9(CvRkuaHCJL-J<*8DYz(mRT$sl~Qwe61wU zOBWb?G4oYkMoSZlVGA2;0~Uv|Zhc?IeX2ww;9cy!Af=!Gxlzr~6d%v`{#2VSAFGO- zkzPf-4GYj6U1IrQB<^p%r#-w03g}cAHzZRZCdpf1L8Jh_lg962&bwXY>|^(wfsN%U z@>Md0&bmvnGWpP}D#AsT^$nQASp=}U&@NSAfVeTp?PKpVga-)pmuet>+0E{|(Z7tY z(2hC-MgZx*t4ED<_QpKr?OyGZyDUB$Io<)95mLx}Zi~7KUcP2}NBghxYQ)pPVso}$ zut}gGYt^|8`Bk1=)j@k{hV7BH{L{WIl(&byZfZ|=zvBAzHf@=m83Q~c-|X0Z?Xua9 zd^J*6AA8`r51l9Q+N4vU{ zaCG%5D@N5iyn=R^mcov9OT2hg&diWu4t$h%t>k@ovSb*+w%YZ)Kh{jc^h+D~sEB0K z1rmUOmcKtxmwT1Cwms4DSzy?piSV*JhM8}xTToxN5{gq>3~f=f{^IzscY{r{zOQ$* z*eC`NkYKwgzm94Rt-U4rrqJrTetE`9F-I0bn%s}FvnT0z4uy&g8uZ$TDrmH+AM`42 z|DHRZJm<>aMEMWeWBMTg-FZZfB~f%WS`2(2==aLXSwhh(jzt+aBhQ^<%uUz$ zKSfm8Z;o=jtAfub>pq!#`Cgvmctsh1cf-9C$#cp6pc3DH=wSR8Rkf0m~W3F8O&f-Z>K5Y zi~71B++rqTwj_S694028vx1xu`ng|4HnL%15rGJ?5V=t!j2|}^D@qNy-AvZii+?+| zuz=d=pKM(w+daq|HaC|X0M7^&kxyZysTQuPoo7(Mz3)IDJgHjfY-C&lCY?&5_`%DE zB%EsEe;JJ0)6DJv;G8_nW*ENfL-WAVsZwkMxkLbn{=x3~HF_LUF4TSlcKlSaWJsbB zLjWS@O3r7ERKh;LJaX%u8RqJ;@q7+NvCnqd4Qt|XeJad}p=nda^3H0#k21uxe`6Eu zjG18$QF~Z6`zd<)b$fA2D7#;*RgBrBlVCq8&g80x5Y7zM3hgiRUnD1d5!4NwoXV7m z4YWZX-2)Dtr!&Ieat%krmrr8HiMcPEk~>qV`&E_lgAcI2ymoNc3xZJOQA)Q{yZEIK zXV91_>F{R=g0`heq z6S@6rn2 z#hv>JbS7ziV*>NarBiXp*q8{^5n6&FHbV*(`c&a@!c9t}R4pyrJ5H`bqU@ga#a{29 zkyqQAIZ&GqH9#Bb!s?Cuk_*r5jT|7WOuOgRN@Cit-fMy=PWX;do4u2VM@JbjCc~)4 zi)MYBOXHlGIf5u((@M~j&INYPH^@r#Dp-L#IYj9T&8qa*GeXjy9l}#FxZsTS*aJ-X zyCR_`BwP0phUgR?1LjjH$91ik;thkHXD`7x!gNcS-vJYPaJfS52e;(og`p>sdB}4} z1zsWw{^Q6|QDmhyoGslpc;88e65-2XRwKxxc1j;673=>hQl~lNujzsvT#enmXpKJQ&biQWqx>DAG#BJ^HyJwb@G5@-B9t*)8^2r~5Ho)@e$9;FV zOQ>*|6V+)+6m7&b{kP5LK#HaFMPl}_Y6)vVax+fzg^yJ!a44JHMFYS{db)xZJ+ADf>g?0I-Kwu7ZVy7F9JBv%WjMoC&cGCn|zh9 zm9brpnrC4FTY5LAQ(6FTP6y7Ja zb`yrgqw-rn6`;R^*`uHc?N%eZ=9&m`3{Xwz&-iGuB?w{~5z8)Qck+0GW~QN>g2l+x z38UX$99CKim5MG;d7r|jOLzWM@GvhNx0qgy6C^Of0r7dPu6-%xIN&2j)N{(yL8&>L z&$s6b^e5l-C9{i>Q|eWPT&{&qhiBN7b7-87d4Lu@^~iMoFqjU5Y^jRQXS#~0(bRfO z)l31FLC;QW9Ew~bw;$OL)c~-Gjm(aJzX?eGoFZw_bNn=pC*zwQ^#OH`%d3Xir7BXt zL42Zh!DZHf1Id^K})|B1RRN*^-rJF#g5atSypH(bXh)4q->@ZA6_}r>qVue-|8JX~5nt3O_ za)HiuWfG`RSf}TF!{$;MDqUM|(>_}YDtmA@Lpwf1PBG->vN9$lHkchwviL?vQQ{>P zXi#I?7rqi6z84gqOV#!xnkOlPouf>53I8)0iL86j>+36w^|3DBY1m+azrX*AFOOP- zBW@Qz3z-qz2)u`(7Zpwn8vh?BQ-86aULr-g$jQWbSgD_cKP7driM?chah7U5zYrgv z9sJz!Lsw^po31P*Dw}~sfZdTj7arQsyf4_G$b~~ehqlxEm5j@sTpe}C3Qsrc1>uUq zAMC`7*7ky887H#c3$Sz(P|ac_E0^b8HRD0>KX(5(_r@s-S;RFyBqOemaFH|&74G8B>brtoVswCWt7B%ovv33d5+dd^n zVVI>~)e)1MA~`5-t6;N(bMfa;q?B+}Aj8t+wYZ$)Vh0~!an%W`K+`*D*ag=?kXNN3e;FVE4f{ z;fpP8v!CtH%T7L1QqFHK@VsWVxtzA`7fISLYQ8mk8XmoL8Gd&FRmP4Tp*&zBiTjMX zR4-0D|}6eCI#!@N!3R02g*ozEs8H=& zGkkzxFw@OZov|hi1l%zx;J&Fd%}@0s#VDPG|BL5tUsb=XOa5+hLgxMwp+Z@pta?=< z0fSPuP)oh{!)2v>bt>g%{tpa0M(KEv+z@fF^>~Wfv;DW<0%Fpi$+~6|X5i_i)Mk8ow5S?p zisPl~t?gr7+IyvAjP(qY2ETlcED-G}q(T;Wz`I7HnwiFetXJ00uKw64 zXRYuMs*DuyL!9Cp)ry@YNJD*Xe!hv4;>_v+xD}7b^kcbhr@&;CbV`xP4kH;1(^aA( zbdi?5MCZ!<7c=+J!~Btq836OX>0{u`a%6qb`N4ING>4Bx4IkdD&FN4imWS@}mF*m) zGhS%>pkOK-uc1qwQUPNw7D@U0#rPh+rf2=~I`3QB-W^W>I!vK5j}yobJoh?y{?FgfLF zB1jN_|MXV_w-KK4RiQL}=J&U_ss}hi@TPT%N{OiF3mc9vMFwyREYnt&awdC?uNjou zRps;KBhDXh)Ir8cU!1CtOwgWSMxb<={5*-k(mUj{F=qjI#QfnyA}pQET~~~+Y5MHc z$VS<_$Drl;S-VzD-FP5%;`~0o5+W2k=EYp7>FdFv7HX=1QDRRq@+`sYvX}etXvZQ2 z3}XL5u%7KDjWG>WxDn#m^EGF{mp`3>jzH3kB^Ny|DFG$CFtpVw(VGAOtxC2KUMHFL zI6>UL?CqSO`DR<1GGa_7^7THRa>#_(ze?`EBBWEXwlW5xO@DD~_d|!AZ1JtK^bmI9 zEbo$hI{V*K%tm0bhSWK_Juk0UVE@1j4FGl0+hJPq`9+%(Ja-|?B(^vP>_S4%irF0B z(kCpJ=rcPTdwlwOT;3H^Lx;kr0CbxhFppIBpBoH5}VWoZimHoBTDZ6M7k!nY=P z98GYwLK-At-riFMa?_XL)+1q=k@z7C@L<8IBM?sq^Tw6&xS{SVw! ze_O&=XKikrVBV4o(c%R`H;?=teO$@^$ZX=#Hqc>rAHcInQ-=3`d0iQuzSce78H@?Q zW`md{oP4>9S(og9gVszOSi4Im^Kv;!6MeY1E9iCETKRKDr6w!>`m#3jbBzx3X>I%W zpjOJ^KH2s{(qM;?DQOMBg>m;|LiabKNU7IM3FcL4ihHF!tx2AY*rEzHylo_Ye0s7>MhV)6_5`8{_mqRHa+U72z#;t)V=OM!dx8ll zK`9nia6X0ImdK>>g=jFZ>SeR|=GOW8L}yhnQv|_2x$k@4pg^5(Q%8sBU3U`{mN9J6 zdDevfM2PLl1^Co8^1mmfaPlr2z-fh+QszINhBxZn_Yids`l2j9crGpM;9QrvCB?gU z=Bs6{nb6Xzgqs~;knD@IkR3dqs1T%(aaAjAxCwrAMZLbkGn&?BHllEHr9)#wsL{Wg zW?4lJ2?#8yZSwntJPa)gdbQ6|pRh=^7p8{KK(MS0M zWO}y$I+uXS{WFAjc$iu-)`_fb0J!r zQS(Lpe6$=>UV?0DDL3+VgBS6pwC~Hs$JgARhf}Bi z#WUGVp_WCof$WxzALO^^WiL|cCM977TMRke8%Z8K@+N|SWukK+CBU{cuZ;E@ca-r&^#LCOcXH515+_*5hQliov`8R*&0)CeedZqoxPAq%0gKQ69^nJV<8@QHDzGE9#jt>ZP6_XOID?e^i0kt`# z@qWkZ!&0wT=wRb8+1p_~6janXqg}}`;&9h$GZG#TJXKOxq1gIp`A52%pH?=Y(4~4t za@%@^2tan~O5s6NsD6$asy5c#n~drSr}nU7)<}$>O5Lfy2;Zo7EyQ=)z<$ z7orZ;EZT0acrx6#GRk|RP>(YT@OgQ-fB;*{nnllRaQ zc)^6^DkFX%rb^{CDD&x$Yz$g2tV&l~Eq^460s zsl8*m?2`=Ri0}>r5gp(C? z+Hp3|SJuolamKVWeX;&FQ)g@XpMz&j!8AUuPXW}v&0h_bUbaui+g*GseESW@S;*Th zsslPOv{n+F46rAFpzxx}D(qOD`1|e<0+Ewj4_}Lu<}?i(FZ9HB@MZ?g0l>@d!8KXA zEj8yZ%PpC9`nM<7n+$Rv(~H-+!4RvFE_2S?2Hz}LK*F?Nem}uK@9=0=_*PVDUP8RF zqF8MDIiYd=mT$nU{3RbGc8BE=AK;EI)zjoIkf>a$$>_&|A0eYVNCU8R7s$>Gly-DJ zayi`9W;(igS|*xkc3SlQpu=(|D+Gda+Uhn(tbfuKBYzKa*~8JD(Ni4AN6U1HI2oO1DxE!4dU@GAqS;fC#!Y+Q^yl+^ zy4p;tg4HF%^D<6!3v--@OGrx*$FEOe_%MW=8Nqd*wJLCYoEULoI#IHtg^^k(G#W&J znDLmMYeG5@8?F1vgD(N^#kce~TAm z#Yx3D(xPYM=F{nDs;W9eJ0Ic)L`&U`M7;MQ?avHPHs*CcnovDa$#0itOSt)346>rt zKeDGiVVfwGL;;0Jt{Be#dXgzbAga*_f-#ZR0l;Gup1cM}0WZT6DWe5fFHN;dx1pij z(=)p?DgK5Zx-yr`PKLL|S!nakx8E&3*XG3*mW(Q3eIHx*9jp+@NSU~D=2a=7jGKg* z*wgc;y70%p7&u+4S<#4MTuZ{N!@DK~wKp&HQeZO3H^sR$Fp};hi{K3rmrWh6EUt`q zAc(ZK?FqMMz!}+@^lvyBGb{{T#N_J&A)##ij#j=*U_T#Lq4BOB{5wX>}C09 zFed$}0IW?w=bcLQeJaN8>_-;)|Eu!rwG6DmEkpq}vK#=AGuWNcLc z(tTgCKxJd2YK}-W_Dn5fY&aB^cB#F%1%0-4A%q8mp=^A{Pl>`KI5A5+C;BriAo)Oc zoG;;G`#9y6Zn!{|mD7B425H?fV-uKhneHw+mqpXAbn~E?^Le$DW_UorwLz>5DFWEQ z=3*TbE<+&YVl3$NMVHJ;(Q!7{=Ef4>tHqjP{84TVq3fe~yHGJ@6QkrS@>Y}deMZvk z(mKq{lBPWe^tk$=Z(P2bIvG>0v2=bU-EAZ|qNWA)CYefw9mG!s5;Oa2M(f>^LG zXMY^Sb~VD_x z_{N+5Z66o$y59p9Q_V%^*7f(Ls^fdrv4mv*h$3C30GkV;4KZ27eMab)4!b`tK7U*W zG>whdgV$ud)JCAxaaj`=07+hhX?9#_IpBc{(uXUAupt8L7vyqv_4DH=R(w(MtzoFH zfJ#C5pRT}1=;)i*=y93yLYApL%;vARCg*D%$5_4R9%yfI-mECCo3HNib2d{;rgfPw~EMX2bH$fXp{FmAdx9yQzTjnYL>^Okh zUD&$AWE{aa8{eZ;=uH$VIb(b&oSKBS{#KST7~oa)(<&{xAfN0H+{7d#ncC0Yr?@88u@sm!$*_98)X;I zgXt>JT3Pcy$ybRQQEJNjPhx2XWXkyjM#2bP|(D$!v$IFw#rWdA!> zkD~`1`*FGd>93;F{aZ0uDkTZJ43p$vn(WZ6p9PPY*}_CMs6?oOUp(JJ%d^emL2=bT3Yv#>tG7~SOST9WlwzFP zBi9<2%OocZW1cuq@zD|>A&V;tbBS1#o%yz~%sN*1_ZD3IPfk~oe3SC780o$ZAERpe z(GU^w=&q6bC)v%PD`oWTHHrs6u07EM#gB*iRSF{$;#6;{@u^KLB8RPhi?G&Xtu0l7 zT`~Z&q0ZnV#d@Sp!U=4O%_F&_#ASdBzp26Nz1lt-(Km>&;{Qy`!bA{34rifV?k7b- z+3MA-_wq~_I6KXg<-X-Vms%%ws$xswWGk%4%qN>D)Y(hk4z=xE+K&BgM2i>l$N{Dw zpM-Ysk2tG}^g0^IjG5SZpsGD@XB6`Bw}@!IH~YVb6WmY;>7O{$`9A?o+NB-`A9^e= zdvyW;c1_~B^u+}pKq9O-);XV`A3!f~8`t!*(WOyv2-*0-(cQ5`I1_ z=)IE+B?E5_DrDQv&o3(cC*A9hThz{OEp%E~_wr-+&!R|0i<1Megno|2fV8u{NItd_T#J` z>z1tXtm^&7k&|<(>~-=Mgmkq+1%)L>`vUJFumEf6XmxD9S$kGq@@X>^(sE57 z05su-^MDkpn*5{E#eatrpHXZF+1Wq3dHnPc zRFHTG{C74PMG-nH0gZ~wkUQU=l{_{1Z;}5*nwsr-%ydw^lu7;u@Sg~_(D^^jXQAfU ze-23elLnP7WmLBS^PmPS8G#C2+%e;g@#B=Hcw#|AJ{|}K|K7ib%6_oba9;|h zIsU0T8Ofm|ihl-A;{5-8x2F%f7K~Vn0V_e@`BE0FL|Zft6gsNCBg=_M2_% z0Xtu@7DIPj0SS@?q5W_^p91h;e#Uw$OX8E5k;%vJklCIH-+21K2;7NPQFu+wM-2_S z?yuYe+$6T|d{M9#kvbFkqMs)37j*!!!Etx1lVw1^+8X&@() z;P$U;-tCG~+uR+8{ON$7aR$g6)&LZ#9V38yzmqoxu|xd~uv-~1R=uOa4a01t3vdfp z%>ohPmA#>=1$5>_aaVK{( zLRa1oT-dcp!z-c$Y(!Bx;|^)VEzp~JF~K~4l4OnA29pur1~E_JO)ece2nMyJgbt6-x&u4*Yyj=yPVE~n)*6u z)nO@cR_CcAOb<9lvAUu^1&LtGOmkc`-<94K25AxbVb+LGp!5PiAV z58-)76aDjI?=1FLlmWNY9+1#uMQ5CXw^dv$kH{Sdshusp=(lvU^3sT?GT<=(9b^0% zZk&Xiy|C6iUR+2NM~aRu8}u#}vE+nid$I|Nkqme505PfI`e1ju9Px8Gju|Rmu9gIl zew3_?+P-%*Us-S~pg>wf*$5#@*FoR-(Te?VmaNuhBudnI0pcCcALZ7er`jKIdNu@% z@2`S+X>>kADZp)hoI|{DV0g%oNBwWsQL?}sU0b%2S(})>$s(6iL{Q9Venq+DP77aj z6WsY%BRhnT)i@9h0BP8<1Fc>SVP_#|ylVa^t8|~20ky|RYKMi&S@r5+Dw_Y#CxCH8 z-d~N0&68|iR%~Y56I)r|)E(Q&zu~8eG*p+OPNaS){2few9*_Yp z&Q=a>k~>CbBLmRf!*=<#i3GcR@91t_t{q*>FS+ppn5>fqYC4=wYF%RIF+(wDdy&r; z)Kn_HPOY4CZ+oS9B#0l+od5&*oT9}RYfmT%pa*P-W&c*d*#GJ6%)_C4!#)0rQa`d2 z8rw9MPz>33W^7raLfNVjvV}?3m{iuW%-G6WBxK(kd-ZFWFqBZ%%4Cv|A!7;W>74V& zxvq1af6qUz%jJ6Ko#%O<=f1!9=lR|*(zHdF32MeNxU&AmGjJ@~yV_5f%R4_>&=w(h z6;SGrT1-~VKnP;?J{5Gf)gdX^SjkNT`cz@Kx|K?Qvj3Si{X(<3=^OKG1ll7isk5<# zwMW{5VeN5zem7X0a5cG(^?u#(%^SYTNL zT@l6Y2U4ehs$eyj z4h5dZRa_Dcq85xYBN2ITTRf5)ke)#60zTrKMhbzdDsC>TwC6CK1C z4$22gVS-}aSRo$2@=tYht#o*ZhOUQsSHD&$3pqw9`SID=>I_}Q!?EGevrz498*n9z z=#FCk&W%HK3$VS6IT6pM$N9SYp5zNl)air2p8x!EvN?MC;g#R4oBEUvhpHxii|BV+ zOhCwp#vXVrYgA$1lj;oc70r^?ETOJ@>lp>U@ZjKN?9kX-Ev644u`uR_>~R&YWMuQYt9ud`uu^9oq)a_ zqU>|M{xxh9CkZc!&H+v~aaD2@gd2*u1Gy^+{8N(K%ft54jOAy>b}`M1h#;L_+Jb=d znhtFu+vG^1U%Fo@>sE~zt*a2tz;^g~3x)wi(FB_-qb#H^#`bbjwZ*Pany=LK$s}JD zAFjr!K-Katb594dAMaYojOdI$h+CN-{t#zDj5>CTdLxj!#PPXX#bqTaqI2&XC!N(0 zWLc(p0HMC%HgaaCmgV861;dCbS!De@#{YBYz7Tncr-|j4!2@Hd{>2Mt;pNEji$@%I z*e2CDHdAyE8vP{-?fk`Z+fNgw3Y*1<@lBe@5EW6AdlfRl$$fV~#?}$d$~cdu7H~@T z)3#eqkkCAA;kFwWPo(EB)8@?MvQWJR*eiSMH*l zbZ8uooz}j!q{wgN2!%-me-urimE~i1Y8M|$9@ak_OwY^_W(z#f;22$qW{ikT3f}qq;%Pd_t`)sgM_vaWhh&>8!j0yvZJi^M&Bd=*>y?Z7 zD~xivhM4dYZg|uvwCUl#!By^?9-P(|wYW~8AYXIo zzK7rQ1k;7M-MYB1@naJvEPo;=$Y@&kSIsWzJ7Gt`$PRyMb$p)CXA8OT^{yJMzV96M z15rgXbxyC7DeI}YtNbZ4<{w<*`wTTXxWaJxsDoKa6q?{+fIAr$gq_x1;*0y@aLR#i z~y?wflBZ#dkO0tMVyzP+l5YfBJ7d3ZL8ZtEks+3JkAa+=5wRl!Q) zEs$U&=Sdt99THJD;1nIY7~j0_()NQ?IZ-wlJsiGXt|trchHphe%*(z-H4c^i?_Su| zMo4|MuQ;QYRICNLSu+Bm9eBJ)GL84mwN=$ijx8x04SiBTuyoJm>!j0oAH_Dt&^|IHC60DHq0q+2pE-hTO#n>>q`OAf!Th71$ zcoUCYsU7vGE&en?+}?WGz#_y|Qz^*+ymFm{}dY7_D@$5&08&ac5o6TL**tf}{h{jqfo zVKPa@{AMzaC7&}8B=yv}@dJHLKP8}Cy=!y7#ood(13T}&?@@nL0+qr68S!*v&?4!*1i71b9wg0|92 zAi7jf@wI`VdK6bnAO66}y9Gj_4(q1M`!{lsJ`ehx0XBi1N^(^VxOFE81PPnS2IPFd zdH2IB5;WDE>xvH`KHe=Pu5(T^+7`=YEq+870-?a*K-e*rq6~QMQ|MDH)|C?GzhD#CugYOPIFsK^dLQ+CHi5)WqWN zif7_%8?{lW8rC|Cw`=>dNySApo?iJ{vu%s__YmD#-@XD_Ys9;C=k17B+*Qqhq+dzq zlJHPMlrOAzg`!~LmZ6z?^FW{x*^}}8&JRl}$=`xX9sXAW$ga`we~Ac62%OQ+X|2g? z;riIAqW*n`Mn)AN#UW5Y-}|_PpO4OKR(tmb(s+P`R2-b(p)^(g4oE8g&VQ+P|NXhJ zD-#)L+B1-N47rT{z)d)JJUjQCD#jOqPWv+v(ODQi)Gy?kK=%1^0rl?_vz0_dD7s}d z$G~tyOu|hPPWSY?S=({V?zw9O!;{F$5*S2QzfC!jZr7(r@!8P4<)gYNi$`MLIay@q zEI_yW0{1SII1~03MK$!Cygw-RR||6T{a7Y(r@P;f!UCvPgRP;_0sV7)CL~g#J&nd%!3W)+gdxNl;hlFd72;KWD{9rip^S&jpex5;x%!SO2pRS$?*sJPbM)zs8 zHa*ImIr7;7GvGdUfmnKJ6ItzMRRcZd{`4cb`CF(pYPr7-8^1O~zv$sm(K5{DJKZql zl+V=fxAs3X;f7VPAkH4gbg@Ye?e4f4qr?;EHU*k04ogt9L~N9Z11d2J8svwceC6Ce zE^UKkbEqc>+CY5rDGnGm?>Ynx7-2Y`jdU^YaQW12~YP{@uB7 z(jzQ|3}ZoOMc4{^`jfBiS^f^1-0 z=wEYpF{>y(0Utkl{vdq{4e7_$w-4R#tLsHX+)6lyGJaZn_nU>MMeJB zT!hJtI8E|VF^`GiAui>9r-5my#U@;I9Qpg`yGoWmtte4$N*2K%kK|*`=)=@)9zDjI zL2)bnk(mJ3kt6_TXj+vTq~TkC~@ZskQv&N>l(8>G8|C)FXm`01gNX?t5Ian=zu?WYYp!5+NO#IOYNo$&bg z@g2QY7L|45M000{;|f{e+;r@TmY3}B!O|4$v9T~xeOr3-Mh1erzn)?NQPGhKnX=yJ zx8k`DBR4EU&gNr#2~!;-LFLEPR!nXz-m6bZ4%s#r0w(N;gT?k3qu#o4Bb1D)iL@@X zbotH*a%`ei7{i#tg=bBJ73v~@mhdx~gm}DMj%Gn&;sq<;Bvt&reDFj=z4KGgAg9yt zd)^J2X&mGChd~`yeE@nWsM6NA#wENAf zs99?qNJ&^ooF!0I6m7*pC9PycnN9SU>DEpj1tzW=i)CueUjwdWkEsk7qO-DP^Ia-f zt-PP4UoZ3*U@^bBDwo!RK*TtnB0sgHu8=x+v*akHJ3%+|TNLr;phC8I*0jFk!0T@29gUyFD*YBjGb99i4m)l74dVHcX8~G_!L+ z;@}fgA;vOE9I6Zbn@1BZOBuIPSLL#Fz(Ra=xm^jT*xo#wEbi1S#P+fV>bi?`Yc^#l z(x=43TSVAic0vv7fqu07ygWx;J#u1SCMSKr)S>eFkE;VlLo!bAV8^(TvO`9Jh5;|3 zy0K;3;6_gC0W-|$Vtd!KU1YT8=ochz3FS&HNU(IQB6{J*c~cI-$2Wh z_lGE|uau`wm!(G}nzU@Y6xh_@#BJ)JsZ_rQTC>TpSr0;#J9#5uP(i440?l8gRyQVo z_;ZR#?k{LB-}X#3FQFsyAz%ZCDAV?Z`xoY+KG!^KHv{m}?xBz5rg?QE3@K%h%lvf_5>n^^@*_f)%Fcz;xM+C%zSJp zw5g99zZTVDqem$fp~i%eT&ODape#iuPM1$H?WeQKQrf%DLg(#W$?%Z2K(}A=^r_JF zXt^-S!?9pjgl9{lXgLr$IES;;UW8j?*};D$e}~Q9#;SEp{6~Jfc#p3NnUK&oq|)-v z;yCMz!-np;VCkK=6PRX&>;zo@`TPfV4Y;TF#c1b0pE1=(-lg@YAiHlSRjuJ~9qgUD>@&emITtpkK^tXk2>xL9n6f0xJ&G zctSwc8JrwyMKpf+`nHrk*<(x$R+Ru?SmdMTjklMpTZB{G>XkWPr=UGTdA0a@o-&@ThK&hu_a$z5z6zKxYs4c*c@ zi2*rOBjb<9+mVAkW`CVozS|zK-d6BTO;mhW&WrSrAg-S85{gQ^=yyZ82QRqiAfJUu ziE`&1kxHFw&*h%9a;{9*or#Qjh+WQ|kG{_>jL9af!@r`QO2S#m4;N;3E0GtLu>+glfbl)Js7K=t)#fQRHQ}#{ni567dsM&$PXW3QNB(6gnuwe? zfOJ2-eF@Gp>*rT5(c5@>#=%y15ScU*K<7Z4#$&fXaEKpFzfFwjO#tR;qDKY4n*AH$ zwYB^SpJaeT?vtacRzLd=hGmI5o_YD!93?Iru87MjNWICM^FF^l*CZcX&1qYc299SWhW%nfN@-ai~LLfj*(g z9{3OLWhT8FN0TkU?p*h0PeCl6hisrql(C9DF=c=^6Z=dFOkDH{0XM|nYu-pdtspny!!1;Rb(h^r zYC6W4i2=|r?|mUR6a<@qCJ&xJ8Dy61#NM)mlnDnA(ED z>if~t3r=HKK1S|uX{OFTfbs1%mjkBFLztZW5bXvATyW@fC%mCN<8DHq*vyUzs2Yzw z>7@ANFP5??Fhd{v)-{m?2lB{^NkSmRBhvbZ|E;zl<`=P>iY@XXN3*61btU#owv=>kR-arU3%*Fd;uTNTHzP1BzzJtEFr~v@IFD z4oKNseo#sXrWm)oo=Pe{`&D!1cu(u__v_-S@P>0JebL@k77OC7U8ZG)!@5HuS`T*e<(AoM<{ZD2NFKi8mT?#3yR@?w zHg3h(lsr5?&wJrK;85%5 z1F@m)aI6*_D3-`YDByEWr^g7BXc}HK)qQm8P^D|~gN6@LKiBuNee!=ie-iJx^0xJSVYIUV zI`V)rmE=g!73lG0@#DT?nY5A3`rT%E1we%SorVTa9*!;O zU>-kl{bmtzo+OvVc$mM(2f$tqf>MPaOs6pbRqB^6S8D?Fum&D1M;U)?N7C-Ed&*u{ zrN#TF2--7d%+GfPgv)Ekeb+h-FC471M-@tw*m_Lh3`1BiH;a=>98zHv z*;)A4^Ur}L)8Q2k*_zp{ z8#6KyN(H8E+xrToZSF%>!H&Q#mH9*He|bkh>(T$=()b?^kiXa3YyGDI4LCc1efRJ0 z|HFXtzdmHl{|Km?C;i=%fdiyeMs9ooGKF7aSI%UtH_`v=V)?Uab~;vEuLD_$Dii!E r$WhDEhH^2Z|NP_s?+@$1eTk|S{h*M056Z#+L4YjKHmDloE3y9p_j{5N literal 24897 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 diff --git a/docs/output.md b/docs/output.md index 368739f9..14b4ebb0 100644 --- a/docs/output.md +++ b/docs/output.md @@ -2,7 +2,7 @@ ## Introduction -This document describes the output produced by the pipeline. +This document describes the output produced by the pipeline. Most of the plots are taken from the MultiQC report, which summarises results at the end of the pipeline. 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. @@ -12,9 +12,35 @@ The directories listed below will be created in the results directory after the The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes data using the following steps: +- [FastQC](#fastqc) - Raw read QC- [MultiQC](#multiqc) - Aggregate report describing results and QC from the whole pipeline - [Pipeline information](#pipeline-information) - Report metrics generated during the workflow execution -### Pipeline information +### FastQC + +
    +Output files + +- `fastqc/` + - `*_fastqc.html`: FastQC report containing quality metrics. + - `*_fastqc.zip`: Zip archive containing the FastQC report, tab-delimited data file and plot images. + +
    + +[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 + +
    +Output files + +- `multiqc/` + - `multiqc_report.html`: a standalone HTML file that can be viewed in your web browser. + - `multiqc_data/`: directory containing parsed statistics from the different tools used in the pipeline. + - `multiqc_plots/`: directory containing static images from the report in various formats. + +
    + +[MultiQC](http://multiqc.info) is a visualization tool that generates a single HTML report summarising all samples in your project. Most of the pipeline QC results are visualised in the report and further statistics are available in the report data directory. + +Results generated by MultiQC collate pipeline QC from supported tools e.g. FastQC. The pipeline has special steps which also allow the software versions to be reported in the MultiQC output for future traceability. For more information about how to use MultiQC reports, see .### Pipeline information
    Output files diff --git a/docs/usage.md b/docs/usage.md index 5b2b5a27..cdfc2fc2 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/pixelator --input ./samplesheet.csv --outdir ./results -profile docker +nextflow run nf-core/pixelator --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. @@ -89,6 +89,7 @@ with: ```yaml title="params.yaml" input: './samplesheet.csv' outdir: './results/' +genome: 'GRCh37' <...> ``` @@ -108,7 +109,7 @@ It is a good idea to specify the pipeline version when running the pipeline on y First, go to the [nf-core/pixelator releases page](https://github.com/nf-core/pixelator/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. +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 reproducibility, you can use share and reuse [parameter files](#running-the-pipeline) to repeat pipeline runs with the same settings without having to write out a command with every single parameter. @@ -129,7 +130,7 @@ Several generic profiles are bundled with the pipeline which instruct the pipeli > [!IMPORTANT] > 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 check if your system is suported, please see the [nf-core/configs documentation](https://github.com/nf-core/configs#documentation). +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 check if your system is supported, please see the [nf-core/configs documentation](https://github.com/nf-core/configs#documentation). Note that multiple profiles can be loaded, for example: `-profile test,docker` - the order of arguments is important! They are loaded in sequence, so later profiles can overwrite earlier profiles. diff --git a/main.nf b/main.nf index 486f4f31..6ad8c060 100644 --- a/main.nf +++ b/main.nf @@ -18,6 +18,19 @@ include { PIXELATOR } from './workflows/pixelator' include { PIPELINE_INITIALISATION } from './subworkflows/local/utils_nfcore_pixelator_pipeline' include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_pixelator_pipeline' +include { getGenomeAttribute } from './subworkflows/local/utils_nfcore_pixelator_pipeline' + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + GENOME PARAMETER VALUES +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +// 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 WORKFLOWS FOR PIPELINE @@ -40,6 +53,8 @@ workflow NFCORE_PIXELATOR { PIXELATOR ( samplesheet ) + emit: + multiqc_report = PIXELATOR.out.multiqc_report // channel: /path/to/multiqc_report.html } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -78,6 +93,7 @@ workflow { params.outdir, params.monochrome_logs, params.hook_url, + NFCORE_PIXELATOR.out.multiqc_report ) } diff --git a/modules.json b/modules.json index 3fffd959..1b41957e 100644 --- a/modules.json +++ b/modules.json @@ -4,7 +4,18 @@ "repos": { "https://github.com/nf-core/modules.git": { "modules": { - "nf-core": {} + "nf-core": { + "fastqc": { + "branch": "master", + "git_sha": "dc94b6ee04a05ddb9f7ae050712ff30a13149164", + "installed_by": ["modules"] + }, + "multiqc": { + "branch": "master", + "git_sha": "cf17ca47590cc578dfb47db1c2a44ef86f89976d", + "installed_by": ["modules"] + } + } }, "subworkflows": { "nf-core": { diff --git a/modules/nf-core/fastqc/environment.yml b/modules/nf-core/fastqc/environment.yml new file mode 100644 index 00000000..691d4c76 --- /dev/null +++ b/modules/nf-core/fastqc/environment.yml @@ -0,0 +1,5 @@ +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::fastqc=0.12.1 diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf new file mode 100644 index 00000000..752c3a10 --- /dev/null +++ b/modules/nf-core/fastqc/main.nf @@ -0,0 +1,64 @@ +process FASTQC { + 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/fastqc:0.12.1--hdfd78af_0' : + 'biocontainers/fastqc:0.12.1--hdfd78af_0' }" + + input: + tuple val(meta), path(reads) + + output: + tuple val(meta), path("*.html"), emit: html + tuple val(meta), path("*.zip") , emit: zip + 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}" + // 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(' ') + + // The total amount of allocated RAM by FastQC is equal to the number of threads defined (--threads) time the amount of RAM defined (--memory) + // https://github.com/s-andrews/FastQC/blob/1faeea0412093224d7f6a07f777fad60a5650795/fastqc#L211-L222 + // Dividing the task.memory by task.cpu allows to stick to requested amount of RAM in the label + def memory_in_mb = MemoryUnit.of("${task.memory}").toUnit('MB') / task.cpus + // 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 + done + + fastqc \\ + $args \\ + --threads $task.cpus \\ + --memory $fastqc_memory \\ + $renamed_files + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + fastqc: \$( fastqc --version | sed '/FastQC v/!d; s/.*v//' ) + END_VERSIONS + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.html + touch ${prefix}.zip + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + 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 new file mode 100644 index 00000000..2b2e62b8 --- /dev/null +++ b/modules/nf-core/fastqc/meta.yml @@ -0,0 +1,67 @@ +name: fastqc +description: Run FastQC on sequenced reads +keywords: + - quality control + - qc + - adapters + - fastq +tools: + - fastqc: + description: | + FastQC gives general quality metrics about your reads. + It provides information about the quality score distribution + across your reads, the per base sequence content (%A/C/G/T). + + You get information about adapter contamination and other + overrepresented sequences. + homepage: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/ + documentation: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/ + licence: ["GPL-2.0-only"] + identifier: biotools:fastqc +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - reads: + type: file + description: | + List of input FastQ files of size 1 and 2 for single-end and paired-end data, + respectively. +output: + - html: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.html": + type: file + description: FastQC report + pattern: "*_{fastqc.html}" + - zip: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.zip": + type: file + description: FastQC report archive + pattern: "*_{fastqc.zip}" + - versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@drpatelh" + - "@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..e9d79a07 --- /dev/null +++ b/modules/nf-core/fastqc/tests/main.nf.test @@ -0,0 +1,309 @@ +nextflow_process { + + name "Test Process FASTQC" + script "../main.nf" + process "FASTQC" + + tag "modules" + tag "modules_nfcore" + tag "fastqc" + + test("sarscov2 single-end [fastq]") { + + 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 }, + // 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("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } + ) + } + } + + 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("File typeConventional base calls") }, + { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } + ) + } + } + + 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("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } + ) + } + } + + 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("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } + ) + } + } + + 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("File typeConventional base calls") }, + { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, + { assert path(process.out.html[0][1][2]).text.contains("File typeConventional base calls") }, + { assert path(process.out.html[0][1][3]).text.contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } + ) + } + } + + 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("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } + ) + } + } + + 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).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 new file mode 100644 index 00000000..d5db3092 --- /dev/null +++ b/modules/nf-core/fastqc/tests/main.nf.test.snap @@ -0,0 +1,392 @@ +{ + "sarscov2 custom_prefix": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:02:16.374038" + }, + "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]": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:01:42.355718" + }, + "sarscov2 paired-end [bam]": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:01:53.276274" + }, + "sarscov2 multiple [fastq]": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:02:05.527626" + }, + "sarscov2 paired-end [fastq]": { + "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" + }, + "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-07-22T11:03:02.304411" + }, + "sarscov2 single-end [fastq]": { + "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" + }, + "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-07-22T11:02:53.550742" + } +} \ 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..6f5b867b --- /dev/null +++ b/modules/nf-core/multiqc/environment.yml @@ -0,0 +1,5 @@ +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::multiqc=1.25.1 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf new file mode 100644 index 00000000..cc0643e1 --- /dev/null +++ b/modules/nf-core/multiqc/main.nf @@ -0,0 +1,63 @@ +process MULTIQC { + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/multiqc:1.25.1--pyhdfd78af_0' : + 'biocontainers/multiqc:1.25.1--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 + path "*_data" , emit: data + path "*_plots" , optional:true, emit: plots + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ? "--filename ${task.ext.prefix}.html" : '' + 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 \\ + $args \\ + $config \\ + $prefix \\ + $extra_config \\ + $logo \\ + $replace \\ + $samples \\ + . + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) + END_VERSIONS + """ + + stub: + """ + mkdir multiqc_data + mkdir multiqc_plots + touch multiqc_report.html + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) + END_VERSIONS + """ +} diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml new file mode 100644 index 00000000..b16c1879 --- /dev/null +++ b/modules/nf-core/multiqc/meta.yml @@ -0,0 +1,78 @@ +name: multiqc +description: Aggregate results from bioinformatics analyses across many samples into + a single report +keywords: + - QC + - bioinformatics tools + - Beautiful stand-alone HTML report +tools: + - multiqc: + description: | + MultiQC searches a given directory for analysis logs and compiles a HTML report. + It's a general use tool, perfect for summarising the output from numerous bioinformatics tools. + homepage: https://multiqc.info/ + documentation: https://multiqc.info/docs/ + licence: ["GPL-3.0-or-later"] + identifier: biotools:multiqc +input: + - - multiqc_files: + type: file + description: | + List of reports / files recognised by MultiQC, for example the html and zip output of FastQC + - - multiqc_config: + type: file + description: Optional config yml for MultiQC + pattern: "*.{yml,yaml}" + - - extra_multiqc_config: + type: file + description: Second optional config yml for MultiQC. Will override common sections + in multiqc_config. + pattern: "*.{yml,yaml}" + - - multiqc_logo: + 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: + - "*multiqc_report.html": + type: file + description: MultiQC report file + pattern: "multiqc_report.html" + - data: + - "*_data": + type: directory + description: MultiQC data dir + pattern: "multiqc_data" + - plots: + - "*_plots": + type: file + description: Plots created by MultiQC + pattern: "*_data" + - versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@abhi18av" + - "@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..33316a7d --- /dev/null +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -0,0 +1,92 @@ +nextflow_process { + + name "Test Process MULTIQC" + script "../main.nf" + process "MULTIQC" + + tag "modules" + tag "modules_nfcore" + tag "multiqc" + + config "./nextflow.config" + + test("sarscov2 single-end [fastqc]") { + + when { + process { + """ + 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] = [] + input[4] = [] + input[5] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, + { assert process.out.data[0] ==~ ".*/multiqc_data" }, + { assert snapshot(process.out.versions).match("multiqc_versions_single") } + ) + } + + } + + test("sarscov2 single-end [fastqc] [config]") { + + when { + process { + """ + 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] = [] + input[4] = [] + input[5] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, + { assert process.out.data[0] ==~ ".*/multiqc_data" }, + { assert snapshot(process.out.versions).match("multiqc_versions_config") } + ) + } + } + + test("sarscov2 single-end [fastqc] - stub") { + + options "-stub" + + when { + process { + """ + 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] = [] + input[4] = [] + input[5] = [] + """ + } + } + + 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("multiqc_stub") } + ) + } + + } +} 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..2fcbb5ff --- /dev/null +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -0,0 +1,41 @@ +{ + "multiqc_versions_single": { + "content": [ + [ + "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-10-02T17:51:46.317523" + }, + "multiqc_stub": { + "content": [ + [ + "multiqc_report.html", + "multiqc_data", + "multiqc_plots", + "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-10-02T17:52:20.680978" + }, + "multiqc_versions_config": { + "content": [ + [ + "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-10-02T17:52:09.185842" + } +} \ No newline at end of file diff --git a/modules/nf-core/multiqc/tests/nextflow.config b/modules/nf-core/multiqc/tests/nextflow.config new file mode 100644 index 00000000..c537a6a3 --- /dev/null +++ b/modules/nf-core/multiqc/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: 'MULTIQC' { + ext.prefix = null + } +} 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 1970a075..7296500e 100644 --- a/nextflow.config +++ b/nextflow.config @@ -13,6 +13,18 @@ params { // Input options input = null + // References + genome = null + igenomes_base = 's3://ngi-igenomes/igenomes/' + igenomes_ignore = false + + // MultiQC options + multiqc_config = null + multiqc_title = null + multiqc_logo = null + max_multiqc_email_size = '25.MB' + multiqc_methods_description = null + // Boilerplate options outdir = null publish_dir_mode = 'copy' @@ -168,7 +180,8 @@ podman.registry = 'quay.io' singularity.registry = 'quay.io' charliecloud.registry = 'quay.io' - +// Load igenomes.config if required +includeConfig !params.igenomes_ignore ? 'conf/igenomes.config' : 'conf/igenomes_ignored.config' // 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. @@ -228,7 +241,7 @@ manifest { homePage = 'https://github.com/nf-core/pixelator' description = """Pipeline for analysis of Molecular Pixelation assays""" mainScript = 'main.nf' - defaultBranch = 'master' + defaultBranch = 'main' nextflowVersion = '!>=24.04.2' version = '1.3.1' doi = '' @@ -262,7 +275,7 @@ validation { https://doi.org/10.1038/s41587-020-0439-x * Software dependencies - https://github.com/nf-core/pixelator/blob/master/CITATIONS.md + https://github.com/nf-core/pixelator/blob/main/CITATIONS.md """ } summary { @@ -270,3 +283,6 @@ validation { afterText = validation.help.afterText } } + +// Load modules.config for DSL2 module specific options +includeConfig 'conf/modules.config' diff --git a/nextflow_schema.json b/nextflow_schema.json index 3124caa5..e3a99fe4 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://raw.githubusercontent.com/nf-core/pixelator/master/nextflow_schema.json", + "$id": "https://raw.githubusercontent.com/nf-core/pixelator/main/nextflow_schema.json", "title": "nf-core/pixelator pipeline parameters", "description": "Pipeline for analysis of Molecular Pixelation assays", "type": "object", @@ -35,6 +35,50 @@ "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})$" + }, + "multiqc_title": { + "type": "string", + "description": "MultiQC report title. Printed as page header, used for filename if not otherwise specified.", + "fa_icon": "fas fa-file-signature" + } + } + }, + "reference_genome_options": { + "title": "Reference genome options", + "type": "object", + "fa_icon": "fas fa-dna", + "description": "Reference genome related files and options required for the workflow.", + "properties": { + "genome": { + "type": "string", + "description": "Name of iGenomes reference.", + "fa_icon": "fas fa-book", + "help_text": "If using a reference genome configured in the pipeline using iGenomes, use this parameter to give the ID for the reference. This is then used to build the full paths for all required reference genome files e.g. `--genome GRCh38`. \n\nSee the [nf-core website docs](https://nf-co.re/usage/reference_genomes) for more details." + }, + "fasta": { + "type": "string", + "format": "file-path", + "exists": true, + "mimetype": "text/plain", + "pattern": "^\\S+\\.fn?a(sta)?(\\.gz)?$", + "description": "Path to FASTA genome file.", + "help_text": "This parameter is *mandatory* if `--genome` is not specified. If you don't have a BWA index available this will be generated for you automatically. Combine with `--save_reference` to save BWA index for future runs.", + "fa_icon": "far fa-file-code" + }, + "igenomes_ignore": { + "type": "boolean", + "description": "Do not load the iGenomes reference config.", + "fa_icon": "fas fa-ban", + "hidden": true, + "help_text": "Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`." + }, + "igenomes_base": { + "type": "string", + "format": "directory-path", + "description": "The base path to the igenomes reference files", + "fa_icon": "fas fa-ban", + "hidden": true, + "default": "s3://ngi-igenomes/igenomes/" } } }, @@ -122,6 +166,14 @@ "fa_icon": "fas fa-remove-format", "hidden": true }, + "max_multiqc_email_size": { + "type": "string", + "description": "File size limit when attaching MultiQC reports to summary emails.", + "pattern": "^\\d+(\\.\\d+)?\\.?\\s*(K|M|G|T)?B$", + "default": "25.MB", + "fa_icon": "fas fa-file-upload", + "hidden": true + }, "monochrome_logs": { "type": "boolean", "description": "Do not use coloured log outputs.", @@ -135,6 +187,24 @@ "help_text": "Incoming hook URL for messaging service. Currently, MS Teams and Slack are supported.", "hidden": true }, + "multiqc_config": { + "type": "string", + "format": "file-path", + "description": "Custom config file to supply to MultiQC.", + "fa_icon": "fas fa-cog", + "hidden": true + }, + "multiqc_logo": { + "type": "string", + "description": "Custom logo file to supply to MultiQC. File name must also be set in the MultiQC config file", + "fa_icon": "fas fa-image", + "hidden": true + }, + "multiqc_methods_description": { + "type": "string", + "description": "Custom MultiQC yaml file containing HTML including a methods description.", + "fa_icon": "fas fa-cog" + }, "validate_params": { "type": "boolean", "description": "Boolean whether to validate parameters against the schema at runtime", @@ -162,7 +232,9 @@ { "$ref": "#/$defs/input_output_options" }, - + { + "$ref": "#/$defs/reference_genome_options" + }, { "$ref": "#/$defs/institutional_config_options" }, diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json index be7808b0..68edfd72 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -22,8 +22,8 @@ "@id": "./", "@type": "Dataset", "creativeWorkStatus": "Stable", - "datePublished": "2024-12-12T11:25:17+00:00", - "description": "

    \n \n \n \"nf-core/pixelator\"\n \n

    \n\n[![GitHub Actions CI Status](https://github.com/nf-core/pixelator/actions/workflows/ci.yml/badge.svg)](https://github.com/nf-core/pixelator/actions/workflows/ci.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/pixelator/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/pixelator/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/pixelator/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A524.04.2-23aa62.svg)](https://www.nextflow.io/)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![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/pixelator)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23pixelator-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/pixelator)[![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)\n\n## Introduction\n\n**nf-core/pixelator** is a bioinformatics pipeline that ...\n\n\n\n\n\n\n\n\n\n## Usage\n\n> [!NOTE]\n> 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.\n\n\n\nNow, you can run the pipeline using:\n\n\n\n```bash\nnextflow run nf-core/pixelator \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> 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/docs/usage/getting_started/configuration#custom-configuration-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/pixelator/usage) and the [parameter documentation](https://nf-co.re/pixelator/parameters).\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/pixelator/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/pixelator/output).\n\n## Credits\n\nnf-core/pixelator was originally written by Pixelgen Technologies AB.\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#pixelator` channel](https://nfcore.slack.com/channels/pixelator) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\n\n\n\n\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", + "datePublished": "2024-12-20T15:54:28+00:00", + "description": "

    \n \n \n \"nf-core/pixelator\"\n \n

    [![GitHub Actions CI Status](https://github.com/nf-core/pixelator/actions/workflows/ci.yml/badge.svg)](https://github.com/nf-core/pixelator/actions/workflows/ci.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/pixelator/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/pixelator/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/pixelator/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A524.04.2-23aa62.svg)](https://www.nextflow.io/)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![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/pixelator)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23pixelator-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/pixelator)[![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)\n\n## Introduction\n\n**nf-core/pixelator** is a bioinformatics pipeline that ...\n\n\n\n\n1. Read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/))2. Present QC for raw reads ([`MultiQC`](http://multiqc.info/))\n\n## Usage\n\n> [!NOTE]\n> 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.\n\n\n\nNow, you can run the pipeline using:\n\n\n\n```bash\nnextflow run nf-core/pixelator \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> 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/docs/usage/getting_started/configuration#custom-configuration-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/pixelator/usage) and the [parameter documentation](https://nf-co.re/pixelator/parameters).\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/pixelator/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/pixelator/output).\n\n## Credits\n\nnf-core/pixelator was originally written by Pixelgen Technologies AB.\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#pixelator` channel](https://nfcore.slack.com/channels/pixelator) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\n\n\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", "hasPart": [ { "@id": "main.nf" @@ -40,6 +40,12 @@ { "@id": "docs/images/" }, + { + "@id": "modules/" + }, + { + "@id": "modules/nf-core/" + }, { "@id": "workflows/" }, @@ -93,7 +99,7 @@ }, "mentions": [ { - "@id": "#52b2ffa5-42c3-4821-a002-cde80183bf67" + "@id": "#aba939f2-3f2b-4a32-a91f-948f641264d8" } ], "name": "nf-core/pixelator" @@ -115,14 +121,18 @@ }, { "@id": "main.nf", - "@type": ["File", "SoftwareSourceCode", "ComputationalWorkflow"], + "@type": [ + "File", + "SoftwareSourceCode", + "ComputationalWorkflow" + ], "creator": [ { "@id": "#florian.detemmerman@pixelgen.com" } ], "dateCreated": "", - "dateModified": "2024-12-12T11:25:17Z", + "dateModified": "2024-12-20T16:54:28Z", "dct:conformsTo": "https://bioschemas.org/profiles/ComputationalWorkflow/1.0-RELEASE/", "keywords": [ "nf-core", @@ -134,16 +144,25 @@ "single-cell", "single-cell-omics" ], - "license": ["MIT"], - "name": ["nf-core/pixelator"], + "license": [ + "MIT" + ], + "name": [ + "nf-core/pixelator" + ], "programmingLanguage": { "@id": "https://w3id.org/workflowhub/workflow-ro-crate#nextflow" }, "sdPublisher": { "@id": "https://nf-co.re/" }, - "url": ["https://github.com/nf-core/pixelator", "https://nf-co.re/pixelator/1.3.1/"], - "version": ["1.3.1"] + "url": [ + "https://github.com/nf-core/pixelator", + "https://nf-co.re/pixelator/1.3.1/" + ], + "version": [ + "1.3.1" + ] }, { "@id": "https://w3id.org/workflowhub/workflow-ro-crate#nextflow", @@ -158,11 +177,11 @@ "version": "!>=24.04.2" }, { - "@id": "#52b2ffa5-42c3-4821-a002-cde80183bf67", + "@id": "#aba939f2-3f2b-4a32-a91f-948f641264d8", "@type": "TestSuite", "instance": [ { - "@id": "#ed980937-b4dd-48b0-b7c4-acf78a6ca685" + "@id": "#541cd5d8-272c-4da6-b27f-c1af890bb283" } ], "mainEntity": { @@ -171,7 +190,7 @@ "name": "Test suite for nf-core/pixelator" }, { - "@id": "#ed980937-b4dd-48b0-b7c4-acf78a6ca685", + "@id": "#541cd5d8-272c-4da6-b27f-c1af890bb283", "@type": "TestInstance", "name": "GitHub Actions workflow for testing nf-core/pixelator", "resource": "repos/nf-core/pixelator/actions/workflows/ci.yml", @@ -208,6 +227,16 @@ "@type": "Dataset", "description": "Images for the documentation files" }, + { + "@id": "modules/", + "@type": "Dataset", + "description": "Modules used by the pipeline" + }, + { + "@id": "modules/nf-core/", + "@type": "Dataset", + "description": "nf-core modules" + }, { "@id": "workflows/", "@type": "Dataset", @@ -296,4 +325,4 @@ "name": "Florian De Temmerman" } ] -} +} \ No newline at end of file diff --git a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf index d2e8c7cf..cfd2e9b0 100644 --- a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf @@ -63,6 +63,11 @@ workflow PIPELINE_INITIALISATION { nextflow_cli_args ) + // + // Custom validation for pipeline parameters + // + validateInputParameters() + // // Create channel from input file provided through params.input // @@ -107,10 +112,12 @@ workflow PIPELINE_COMPLETION { 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") - + def multiqc_reports = multiqc_report.toList() + // // Completion email and summary // @@ -123,7 +130,7 @@ workflow PIPELINE_COMPLETION { plaintext_email, outdir, monochrome_logs, - [] + multiqc_reports.getVal(), ) } @@ -143,6 +150,12 @@ workflow PIPELINE_COMPLETION { FUNCTIONS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +// +// Check and validate pipeline parameters +// +def validateInputParameters() { + genomeExistsError() +} // // Validate channels from input samplesheet @@ -159,6 +172,31 @@ def validateInputSamplesheet(input) { 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() { @@ -167,6 +205,8 @@ def toolCitationText() { // 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() @@ -178,6 +218,8 @@ def toolBibliographyText() { // 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 diff --git a/tower.yml b/tower.yml index c61323c0..787aedfe 100644 --- a/tower.yml +++ b/tower.yml @@ -1,3 +1,5 @@ reports: + multiqc_report.html: + display: "MultiQC HTML report" samplesheet.csv: display: "Auto-created samplesheet with collated metadata and FASTQ paths" diff --git a/workflows/pixelator.nf b/workflows/pixelator.nf index 1c1e948c..78e2429e 100644 --- a/workflows/pixelator.nf +++ b/workflows/pixelator.nf @@ -3,7 +3,10 @@ IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +include { FASTQC } from '../modules/nf-core/fastqc/main' +include { MULTIQC } from '../modules/nf-core/multiqc/main' include { paramsSummaryMap } from 'plugin/nf-schema' +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_pixelator_pipeline' @@ -20,6 +23,15 @@ workflow PIXELATOR { main: ch_versions = Channel.empty() + ch_multiqc_files = Channel.empty() + // + // MODULE: Run FastQC + // + FASTQC ( + ch_samplesheet + ) + ch_multiqc_files = ch_multiqc_files.mix(FASTQC.out.zip.collect{it[1]}) + ch_versions = ch_versions.mix(FASTQC.out.versions.first()) // // Collate and save software versions @@ -27,13 +39,53 @@ workflow PIXELATOR { softwareVersionsToYAML(ch_versions) .collectFile( storeDir: "${params.outdir}/pipeline_info", - name: 'nf_core_' + 'pixelator_software_' + 'versions.yml', + name: 'nf_core_' + 'pixelator_software_' + 'mqc_' + 'versions.yml', sort: true, newLine: true ).set { ch_collated_versions } - emit: + // + // 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_files = ch_multiqc_files.mix( + ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) + 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_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(), + ch_multiqc_config.toList(), + ch_multiqc_custom_config.toList(), + ch_multiqc_logo.toList(), + [], + [] + ) + + emit:multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html versions = ch_versions // channel: [ path(versions.yml) ] } From c0614e3acf5cbef678e7cda9097fe0356d4e79d9 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Fri, 20 Dec 2024 17:00:34 +0100 Subject: [PATCH 38/70] Template update for nf-core/tools version 3.1.1 --- .nf-core.yml | 2 +- ro-crate-metadata.json | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.nf-core.yml b/.nf-core.yml index 1d103dc1..3ecd4287 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -3,7 +3,7 @@ lint: - assets/multiqc_config.yml - conf/igenomes.config multiqc_config: false -nf_core_version: 3.1.0 +nf_core_version: 3.1.1 repository_type: pipeline template: author: Pixelgen Technologies AB diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json index 68edfd72..cf7a22b3 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -22,7 +22,7 @@ "@id": "./", "@type": "Dataset", "creativeWorkStatus": "Stable", - "datePublished": "2024-12-20T15:54:28+00:00", + "datePublished": "2024-12-20T16:00:33+00:00", "description": "

    \n \n \n \"nf-core/pixelator\"\n \n

    [![GitHub Actions CI Status](https://github.com/nf-core/pixelator/actions/workflows/ci.yml/badge.svg)](https://github.com/nf-core/pixelator/actions/workflows/ci.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/pixelator/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/pixelator/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/pixelator/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A524.04.2-23aa62.svg)](https://www.nextflow.io/)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![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/pixelator)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23pixelator-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/pixelator)[![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)\n\n## Introduction\n\n**nf-core/pixelator** is a bioinformatics pipeline that ...\n\n\n\n\n1. Read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/))2. Present QC for raw reads ([`MultiQC`](http://multiqc.info/))\n\n## Usage\n\n> [!NOTE]\n> 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.\n\n\n\nNow, you can run the pipeline using:\n\n\n\n```bash\nnextflow run nf-core/pixelator \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> 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/docs/usage/getting_started/configuration#custom-configuration-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/pixelator/usage) and the [parameter documentation](https://nf-co.re/pixelator/parameters).\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/pixelator/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/pixelator/output).\n\n## Credits\n\nnf-core/pixelator was originally written by Pixelgen Technologies AB.\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#pixelator` channel](https://nfcore.slack.com/channels/pixelator) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\n\n\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", "hasPart": [ { @@ -99,7 +99,7 @@ }, "mentions": [ { - "@id": "#aba939f2-3f2b-4a32-a91f-948f641264d8" + "@id": "#1d466b14-0901-4d00-b62d-85ebd1318f2b" } ], "name": "nf-core/pixelator" @@ -132,7 +132,7 @@ } ], "dateCreated": "", - "dateModified": "2024-12-20T16:54:28Z", + "dateModified": "2024-12-20T17:00:33Z", "dct:conformsTo": "https://bioschemas.org/profiles/ComputationalWorkflow/1.0-RELEASE/", "keywords": [ "nf-core", @@ -177,11 +177,11 @@ "version": "!>=24.04.2" }, { - "@id": "#aba939f2-3f2b-4a32-a91f-948f641264d8", + "@id": "#1d466b14-0901-4d00-b62d-85ebd1318f2b", "@type": "TestSuite", "instance": [ { - "@id": "#541cd5d8-272c-4da6-b27f-c1af890bb283" + "@id": "#d46e78e5-8700-4fac-b959-90ecc9555299" } ], "mainEntity": { @@ -190,7 +190,7 @@ "name": "Test suite for nf-core/pixelator" }, { - "@id": "#541cd5d8-272c-4da6-b27f-c1af890bb283", + "@id": "#d46e78e5-8700-4fac-b959-90ecc9555299", "@type": "TestInstance", "name": "GitHub Actions workflow for testing nf-core/pixelator", "resource": "repos/nf-core/pixelator/actions/workflows/ci.yml", From 4058d84d538d798547e93c4093aa6b7bbe4ff296 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Fri, 3 Jan 2025 11:56:32 +0100 Subject: [PATCH 39/70] Revert move of 'conf/modules.config` from nextflow.config to conf/base.config --- conf/base.config | 2 -- nextflow.config | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/conf/base.config b/conf/base.config index 3914089f..b53faa52 100644 --- a/conf/base.config +++ b/conf/base.config @@ -59,5 +59,3 @@ process { maxRetries = 2 } } - -includeConfig 'modules.config' diff --git a/nextflow.config b/nextflow.config index b6299ddc..ec757902 100644 --- a/nextflow.config +++ b/nextflow.config @@ -358,3 +358,6 @@ validation { afterText = validation.help.afterText } } + +// Load modules.config for DSL2 module specific options +includeConfig 'conf/modules.config' From ca529a0f889ef7b6f2d741e8f919d8c9e0834919 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Fri, 3 Jan 2025 11:56:40 +0100 Subject: [PATCH 40/70] Remove empty config file --- conf/pixelgen_aws.config | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 conf/pixelgen_aws.config diff --git a/conf/pixelgen_aws.config b/conf/pixelgen_aws.config deleted file mode 100644 index e69de29b..00000000 From 02864b120e077012becf625be24ccb2dac150669 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 8 Jan 2025 10:50:33 +0100 Subject: [PATCH 41/70] Update CHANGELOG --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c83a5cde..a2a47ca0 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). -## [[1.4.0](https://github.com/nf-core/pixelator/releases/tag/1.4.0)] - 2024-12-13 +## [[1.4.0](https://github.com/nf-core/pixelator/releases/tag/1.4.0)] - 2024-01-?? ### Enhancements & fixes @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [[PR #117](https://github.com/nf-core/pixelator/pull/117)] - Template update for nf-core/tools v3.1.0 - [[PR #118](https://github.com/nf-core/pixelator/pull/118)] - Update metromap, bump conda versions - [[PR #120](https://github.com/nf-core/pixelator/pull/120)] - Add process_long to AMPLICON and COLLAPSE steps +- [[PR #122](https://github.com/nf-core/pixelator/pull/122)] - Template update for nf-core/tools v3.1.1 ### Parameters From f61441587e08913bae45604f5ddf36cf953ac893 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 8 Jan 2025 10:56:37 +0100 Subject: [PATCH 42/70] Remove unused multiqc parameters --- nextflow.config | 12 -------- nextflow_schema.json | 70 -------------------------------------------- 2 files changed, 82 deletions(-) diff --git a/nextflow.config b/nextflow.config index 144119fc..3be2f6b3 100644 --- a/nextflow.config +++ b/nextflow.config @@ -88,18 +88,6 @@ params { // Main pixelator container override pixelator_container = null - // References - genome = null - igenomes_base = 's3://ngi-igenomes/igenomes/' - igenomes_ignore = false - - // MultiQC options - multiqc_config = null - multiqc_title = null - multiqc_logo = null - max_multiqc_email_size = '25.MB' - multiqc_methods_description = null - // Boilerplate options outdir = null publish_dir_mode = 'copy' diff --git a/nextflow_schema.json b/nextflow_schema.json index 8392705e..17d7a6d4 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -41,50 +41,6 @@ "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})$" - }, - "multiqc_title": { - "type": "string", - "description": "MultiQC report title. Printed as page header, used for filename if not otherwise specified.", - "fa_icon": "fas fa-file-signature" - } - } - }, - "reference_genome_options": { - "title": "Reference genome options", - "type": "object", - "fa_icon": "fas fa-dna", - "description": "Reference genome related files and options required for the workflow.", - "properties": { - "genome": { - "type": "string", - "description": "Name of iGenomes reference.", - "fa_icon": "fas fa-book", - "help_text": "If using a reference genome configured in the pipeline using iGenomes, use this parameter to give the ID for the reference. This is then used to build the full paths for all required reference genome files e.g. `--genome GRCh38`. \n\nSee the [nf-core website docs](https://nf-co.re/usage/reference_genomes) for more details." - }, - "fasta": { - "type": "string", - "format": "file-path", - "exists": true, - "mimetype": "text/plain", - "pattern": "^\\S+\\.fn?a(sta)?(\\.gz)?$", - "description": "Path to FASTA genome file.", - "help_text": "This parameter is *mandatory* if `--genome` is not specified. If you don't have a BWA index available this will be generated for you automatically. Combine with `--save_reference` to save BWA index for future runs.", - "fa_icon": "far fa-file-code" - }, - "igenomes_ignore": { - "type": "boolean", - "description": "Do not load the iGenomes reference config.", - "fa_icon": "fas fa-ban", - "hidden": true, - "help_text": "Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`." - }, - "igenomes_base": { - "type": "string", - "format": "directory-path", - "description": "The base path to the igenomes reference files", - "fa_icon": "fas fa-ban", - "hidden": true, - "default": "s3://ngi-igenomes/igenomes/" } } }, @@ -561,14 +517,6 @@ "fa_icon": "fas fa-remove-format", "hidden": true }, - "max_multiqc_email_size": { - "type": "string", - "description": "File size limit when attaching MultiQC reports to summary emails.", - "pattern": "^\\d+(\\.\\d+)?\\.?\\s*(K|M|G|T)?B$", - "default": "25.MB", - "fa_icon": "fas fa-file-upload", - "hidden": true - }, "monochrome_logs": { "type": "boolean", "description": "Do not use coloured log outputs.", @@ -582,24 +530,6 @@ "help_text": "Incoming hook URL for messaging service. Currently, MS Teams and Slack are supported.", "hidden": true }, - "multiqc_config": { - "type": "string", - "format": "file-path", - "description": "Custom config file to supply to MultiQC.", - "fa_icon": "fas fa-cog", - "hidden": true - }, - "multiqc_logo": { - "type": "string", - "description": "Custom logo file to supply to MultiQC. File name must also be set in the MultiQC config file", - "fa_icon": "fas fa-image", - "hidden": true - }, - "multiqc_methods_description": { - "type": "string", - "description": "Custom MultiQC yaml file containing HTML including a methods description.", - "fa_icon": "fas fa-cog" - }, "validate_params": { "type": "boolean", "description": "Boolean whether to validate parameters against the schema at runtime", From 0dad8f2b7f7bf14c6fe220174c4c42407f2669f9 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 8 Jan 2025 11:05:37 +0100 Subject: [PATCH 43/70] Fix zenodo placeholder and update ro-create-metadata.json --- README.md | 2 +- ro-crate-metadata.json | 34 +++++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c93fac23..7ea5060e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ nf-core/pixelator

    [![GitHub Actions CI Status](https://github.com/nf-core/pixelator/actions/workflows/ci.yml/badge.svg)](https://github.com/nf-core/pixelator/actions/workflows/ci.yml) -[![GitHub Actions Linting Status](https://github.com/nf-core/pixelator/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/pixelator/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/pixelator/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 Linting Status](https://github.com/nf-core/pixelator/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/pixelator/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/pixelator/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.10015112-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.10015112) [![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%A524.04.2-23aa62.svg)](https://www.nextflow.io/) diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json index cf7a22b3..3760453b 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -22,8 +22,8 @@ "@id": "./", "@type": "Dataset", "creativeWorkStatus": "Stable", - "datePublished": "2024-12-20T16:00:33+00:00", - "description": "

    \n \n \n \"nf-core/pixelator\"\n \n

    [![GitHub Actions CI Status](https://github.com/nf-core/pixelator/actions/workflows/ci.yml/badge.svg)](https://github.com/nf-core/pixelator/actions/workflows/ci.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/pixelator/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/pixelator/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/pixelator/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A524.04.2-23aa62.svg)](https://www.nextflow.io/)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![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/pixelator)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23pixelator-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/pixelator)[![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)\n\n## Introduction\n\n**nf-core/pixelator** is a bioinformatics pipeline that ...\n\n\n\n\n1. Read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/))2. Present QC for raw reads ([`MultiQC`](http://multiqc.info/))\n\n## Usage\n\n> [!NOTE]\n> 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.\n\n\n\nNow, you can run the pipeline using:\n\n\n\n```bash\nnextflow run nf-core/pixelator \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> 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/docs/usage/getting_started/configuration#custom-configuration-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/pixelator/usage) and the [parameter documentation](https://nf-co.re/pixelator/parameters).\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/pixelator/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/pixelator/output).\n\n## Credits\n\nnf-core/pixelator was originally written by Pixelgen Technologies AB.\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#pixelator` channel](https://nfcore.slack.com/channels/pixelator) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\n\n\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", + "datePublished": "2025-01-08T10:04:53+00:00", + "description": "

    \n \n \n \"nf-core/pixelator\"\n \n

    [![GitHub Actions CI Status](https://github.com/nf-core/pixelator/actions/workflows/ci.yml/badge.svg)](https://github.com/nf-core/pixelator/actions/workflows/ci.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/pixelator/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/pixelator/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/pixelator/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.10015112-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.10015112)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A524.04.2-23aa62.svg)](https://www.nextflow.io/)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![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/pixelator)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23pixelator-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/pixelator)[![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)\n\n## Introduction\n\n**nf-core/pixelator** is a bioinformatics best-practice analysis pipeline for analysis of Molecular Pixelation assays.\nIt takes a samplesheet as input and will process your data using `pixelator` to produce final antibody counts.\n\n![](./docs/images/nf-core-pixelator-metromap.svg)\n\n1. Build amplicon from input reads ([`pixelator amplicon`](https://github.com/PixelgenTechnologies/pixelator))\n2. Read QC and filtering, correctness of the pixel binding sequence sequences ([`pixelator preqc | pixelator adapterqc`](https://github.com/PixelgenTechnologies/pixelator))\n3. Assign a marker (barcode) to each read ([`pixelator demux`](https://github.com/PixelgenTechnologies/pixelator))\n4. Error correction, duplicate removal, compute read counts ([`pixelator collapse`](https://github.com/PixelgenTechnologies/pixelator))\n5. Compute the components of the graph from the edge list in order to create putative cells ([`pixelator graph`](https://github.com/PixelgenTechnologies/pixelator))\n6. Call and annotate cells ([`pixelator annotate`](https://github.com/PixelgenTechnologies/pixelator))\n7. Analyze the cells for polarization and colocalization ([`pixelator analysis`](https://github.com/PixelgenTechnologies/pixelator))\n8. Generate 3D graph layouts for visualization of cells ([`pixelator layout`](https://github.com/PixelgenTechnologies/pixelator))\n9. Report generation ([`pixelator report`](https://github.com/PixelgenTechnologies/pixelator))\n\n> [!WARNING]\n> Since Nextflow 23.07.0-edge, Nextflow no longer mounts the host's home directory when using Apptainer or Singularity.\n> This causes issues in some dependencies. As a workaround, you can revert to the old behavior by setting the environment variable\n> `NXF_APPTAINER_HOME_MOUNT` or `NXF_SINGULARITY_HOME_MOUNT` to `true` in the machine from which you launch the pipeline.\n\n## Usage\n\n> [!NOTE]\n> 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.\n\nFirst, prepare a samplesheet with your input data that looks as follows:\n\n`samplesheet.csv`:\n\n```csv\nsample,design,panel,fastq_1,fastq_2\nuropod_control,D21,human-sc-immunology-spatial-proteomics,uropod_control_300k_S1_R1_001.fastq.gz,uropod_control_300k_S1_R2_001.fastq.gz\n```\n\nEach row represents a sample and gives the design, a panel file and the input fastq files.\n\nNow, you can run the pipeline using:\n\n```bash\nnextflow run nf-core/pixelator \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> 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/docs/usage/getting_started/configuration#custom-configuration-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/pixelator/usage) and the [parameter documentation](https://nf-co.re/pixelator/parameters).\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/pixelator/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/pixelator/output).\n\n## Credits\n\nnf-core/pixelator was originally written for [Pixelgen Technologies AB](https://www.pixelgen.com/) by:\n\n- Florian De Temmerman\n- Johan Dahlberg\n- Alvaro Martinez Barrio\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#pixelator` channel](https://nfcore.slack.com/channels/pixelator) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\nIf you use nf-core/pixelator for your analysis, please cite it using the following doi: [10.5281/zenodo.10015112](https://doi.org/10.5281/zenodo.10015112)\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n\nYou can cite the molecular pixelation technology as follows:\n\n> **Molecular pixelation: spatial proteomics of single cells by sequencing.**\n>\n> Filip Karlsson, Tomasz Kallas, Divya Thiagarajan, Max Karlsson, Maud Schweitzer, Jose Fernandez Navarro, Louise Leijonancker, Sylvain Geny, Erik Pettersson, Jan Rhomberg-Kauert, Ludvig Larsson, Hanna van Ooijen, Stefan Petkov, Marcela Gonz\u00e1lez-Granillo, Jessica Bunz, Johan Dahlberg, Michele Simonetti, Prajakta Sathe, Petter Brodin, Alvaro Martinez Barrio & Simon Fredriksson\n>\n> _Nat Methods._ 2024 May 08. doi: [10.1038/s41592-024-02268-9](https://doi.org/10.1038/s41592-024-02268-9)\n", "hasPart": [ { "@id": "main.nf" @@ -31,6 +31,9 @@ { "@id": "assets/" }, + { + "@id": "bin/" + }, { "@id": "conf/" }, @@ -43,6 +46,9 @@ { "@id": "modules/" }, + { + "@id": "modules/local/" + }, { "@id": "modules/nf-core/" }, @@ -99,7 +105,7 @@ }, "mentions": [ { - "@id": "#1d466b14-0901-4d00-b62d-85ebd1318f2b" + "@id": "#fd58d57b-4b6d-4214-9c72-518f6c733637" } ], "name": "nf-core/pixelator" @@ -132,7 +138,7 @@ } ], "dateCreated": "", - "dateModified": "2024-12-20T17:00:33Z", + "dateModified": "2025-01-08T11:04:53Z", "dct:conformsTo": "https://bioschemas.org/profiles/ComputationalWorkflow/1.0-RELEASE/", "keywords": [ "nf-core", @@ -158,10 +164,10 @@ }, "url": [ "https://github.com/nf-core/pixelator", - "https://nf-co.re/pixelator/1.3.1/" + "https://nf-co.re/pixelator/1.4.0/" ], "version": [ - "1.3.1" + "1.4.0" ] }, { @@ -177,11 +183,11 @@ "version": "!>=24.04.2" }, { - "@id": "#1d466b14-0901-4d00-b62d-85ebd1318f2b", + "@id": "#fd58d57b-4b6d-4214-9c72-518f6c733637", "@type": "TestSuite", "instance": [ { - "@id": "#d46e78e5-8700-4fac-b959-90ecc9555299" + "@id": "#47fea3ac-bc60-4b4c-82cb-e5e235cbf751" } ], "mainEntity": { @@ -190,7 +196,7 @@ "name": "Test suite for nf-core/pixelator" }, { - "@id": "#d46e78e5-8700-4fac-b959-90ecc9555299", + "@id": "#47fea3ac-bc60-4b4c-82cb-e5e235cbf751", "@type": "TestInstance", "name": "GitHub Actions workflow for testing nf-core/pixelator", "resource": "repos/nf-core/pixelator/actions/workflows/ci.yml", @@ -212,6 +218,11 @@ "@type": "Dataset", "description": "Additional files" }, + { + "@id": "bin/", + "@type": "Dataset", + "description": "Scripts that must be callable from a pipeline process" + }, { "@id": "conf/", "@type": "Dataset", @@ -232,6 +243,11 @@ "@type": "Dataset", "description": "Modules used by the pipeline" }, + { + "@id": "modules/local/", + "@type": "Dataset", + "description": "Pipeline-specific modules" + }, { "@id": "modules/nf-core/", "@type": "Dataset", From 7cbb58b0008529bb0b721547d94bc7e22d21aac5 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 8 Jan 2025 11:31:09 +0100 Subject: [PATCH 44/70] Remove unused igenomes configs --- .nf-core.yml | 1 + conf/igenomes.config | 440 ----------------------------------- conf/igenomes_ignored.config | 9 - nextflow.config | 3 - 4 files changed, 1 insertion(+), 452 deletions(-) delete mode 100644 conf/igenomes.config delete mode 100644 conf/igenomes_ignored.config diff --git a/.nf-core.yml b/.nf-core.yml index 77144247..e5532e28 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -5,6 +5,7 @@ lint: files_exist: - assets/multiqc_config.yml - conf/igenomes.config + - conf/igenomes_ignored.config nf_core_version: 3.1.1 repository_type: pipeline template: diff --git a/conf/igenomes.config b/conf/igenomes.config deleted file mode 100644 index 3f114377..00000000 --- a/conf/igenomes.config +++ /dev/null @@ -1,440 +0,0 @@ -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Nextflow config file for iGenomes paths -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Defines reference genomes using iGenome paths. - Can be used by any config that customises the base path using: - $params.igenomes_base / --igenomes_base ----------------------------------------------------------------------------------------- -*/ - -params { - // illumina iGenomes reference file paths - genomes { - 'GRCh37' { - fasta = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/README.txt" - mito_name = "MT" - macs_gsize = "2.7e9" - blacklist = "${projectDir}/assets/blacklists/GRCh37-blacklist.bed" - } - 'GRCh38' { - fasta = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Annotation/Genes/genes.bed" - mito_name = "chrM" - 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/" - bowtie2 = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/README.txt" - mito_name = "MT" - macs_gsize = "1.87e9" - blacklist = "${projectDir}/assets/blacklists/GRCm38-blacklist.bed" - } - 'TAIR10' { - fasta = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/README.txt" - mito_name = "Mt" - } - 'EB2' { - fasta = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/README.txt" - } - 'UMD3.1' { - fasta = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/README.txt" - mito_name = "MT" - } - 'WBcel235' { - fasta = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.bed" - mito_name = "MtDNA" - macs_gsize = "9e7" - } - 'CanFam3.1' { - fasta = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/README.txt" - mito_name = "MT" - } - 'GRCz10' { - fasta = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.bed" - mito_name = "MT" - } - 'BDGP6' { - fasta = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.bed" - mito_name = "M" - macs_gsize = "1.2e8" - } - 'EquCab2' { - fasta = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/README.txt" - mito_name = "MT" - } - 'EB1' { - fasta = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/README.txt" - } - 'Galgal4' { - fasta = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.bed" - mito_name = "MT" - } - 'Gm01' { - fasta = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/README.txt" - } - 'Mmul_1' { - fasta = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/README.txt" - mito_name = "MT" - } - 'IRGSP-1.0' { - fasta = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.bed" - mito_name = "Mt" - } - 'CHIMP2.1.4' { - fasta = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/README.txt" - mito_name = "MT" - } - 'Rnor_5.0' { - fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Annotation/Genes/genes.bed" - mito_name = "MT" - } - 'Rnor_6.0' { - fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.bed" - mito_name = "MT" - } - 'R64-1-1' { - fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.bed" - mito_name = "MT" - macs_gsize = "1.2e7" - } - 'EF2' { - fasta = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/README.txt" - mito_name = "MT" - macs_gsize = "1.21e7" - } - 'Sbi1' { - fasta = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/README.txt" - } - 'Sscrofa10.2' { - fasta = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/README.txt" - mito_name = "MT" - } - 'AGPv3' { - fasta = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.bed" - mito_name = "Mt" - } - 'hg38' { - fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Annotation/Genes/genes.bed" - mito_name = "chrM" - macs_gsize = "2.7e9" - blacklist = "${projectDir}/assets/blacklists/hg38-blacklist.bed" - } - 'hg19' { - fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/README.txt" - mito_name = "chrM" - macs_gsize = "2.7e9" - blacklist = "${projectDir}/assets/blacklists/hg19-blacklist.bed" - } - 'mm10' { - fasta = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/README.txt" - mito_name = "chrM" - macs_gsize = "1.87e9" - blacklist = "${projectDir}/assets/blacklists/mm10-blacklist.bed" - } - 'bosTau8' { - fasta = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Annotation/Genes/genes.bed" - mito_name = "chrM" - } - 'ce10' { - fasta = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/README.txt" - mito_name = "chrM" - macs_gsize = "9e7" - } - 'canFam3' { - fasta = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/README.txt" - mito_name = "chrM" - } - 'danRer10' { - fasta = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Annotation/Genes/genes.bed" - mito_name = "chrM" - macs_gsize = "1.37e9" - } - 'dm6' { - fasta = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Annotation/Genes/genes.bed" - mito_name = "chrM" - macs_gsize = "1.2e8" - } - 'equCab2' { - fasta = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/README.txt" - mito_name = "chrM" - } - 'galGal4' { - fasta = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/README.txt" - mito_name = "chrM" - } - 'panTro4' { - fasta = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/README.txt" - mito_name = "chrM" - } - 'rn6' { - fasta = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Annotation/Genes/genes.bed" - mito_name = "chrM" - } - 'sacCer3' { - fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BismarkIndex/" - readme = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Annotation/README.txt" - mito_name = "chrM" - macs_gsize = "1.2e7" - } - 'susScr3' { - fasta = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/README.txt" - mito_name = "chrM" - } - } -} diff --git a/conf/igenomes_ignored.config b/conf/igenomes_ignored.config deleted file mode 100644 index b4034d82..00000000 --- a/conf/igenomes_ignored.config +++ /dev/null @@ -1,9 +0,0 @@ -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Nextflow config file for iGenomes paths -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Empty genomes dictionary to use when igenomes is ignored. ----------------------------------------------------------------------------------------- -*/ - -params.genomes = [:] diff --git a/nextflow.config b/nextflow.config index 3be2f6b3..e24adb4d 100644 --- a/nextflow.config +++ b/nextflow.config @@ -256,9 +256,6 @@ podman.registry = 'quay.io' singularity.registry = 'quay.io' charliecloud.registry = 'quay.io' -// Load igenomes.config if required -includeConfig !params.igenomes_ignore ? 'conf/igenomes.config' : 'conf/igenomes_ignored.config' - // 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. From 6aed698e804c8aaa0d8276338fc6acb17ef64faa Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 8 Jan 2025 15:58:52 +0100 Subject: [PATCH 45/70] Fix defaultBranch in nextflow.config --- nextflow.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index e24adb4d..7f19f98c 100644 --- a/nextflow.config +++ b/nextflow.config @@ -314,7 +314,7 @@ manifest { homePage = 'https://github.com/nf-core/pixelator' description = """Pipeline for analysis of Molecular Pixelation assays""" mainScript = 'main.nf' - defaultBranch = 'main' + defaultBranch = 'master' nextflowVersion = '!>=24.04.2' version = '1.4.0' doi = '10.1101/2023.06.05.543770' From 7c7a5e02d23ff7287a01760784b2ecee7d3ece6a Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 8 Jan 2025 16:02:47 +0100 Subject: [PATCH 46/70] Manually fix PULL_REQUEST_TEMPLATE --- .github/PULL_REQUEST_TEMPLATE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b107a8e1..3e33e429 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -8,14 +8,14 @@ These are the most common things requested on pull requests (PRs). Remember that PRs should be made against the dev branch, unless you're preparing a pipeline release. -Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/pixelator/tree/main/.github/CONTRIBUTING.md) +Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/pixelator/tree/master/.github/CONTRIBUTING.md) --> ## PR checklist - [ ] 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/pixelator/tree/main/.github/CONTRIBUTING.md) +- [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/nf-core/pixelator/tree/master/.github/CONTRIBUTING.md) - [ ] If necessary, also make a PR on the nf-core/pixelator _branch_ on the [nf-core/test-datasets](https://github.com/nf-core/test-datasets) repository. - [ ] Make sure your code lints (`nf-core pipelines lint`). - [ ] Ensure the test suite passes (`nextflow run . -profile test,docker --outdir `). From d8a2534bdf13626fe35524e30c661a640a8c2374 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 8 Jan 2025 16:59:31 +0100 Subject: [PATCH 47/70] Revert license change --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 036449a8..c94e986a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) The nf-core/pixelator team +Copyright (c) Pixelgen Technologies AB Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From cfd130b56df533546a90a82bfc71e7de9177fcb2 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Thu, 9 Jan 2025 11:45:15 +0100 Subject: [PATCH 48/70] Fix some template merge errors Remove references to FastQC and MultiQC revert main branch to master. --- assets/schema_input.json | 2 +- docs/output.md | 28 +--------------------------- docs/usage.md | 5 ++--- nextflow.config | 2 +- nextflow_schema.json | 2 +- 5 files changed, 6 insertions(+), 33 deletions(-) diff --git a/assets/schema_input.json b/assets/schema_input.json index 489d0de4..5dbf2922 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://raw.githubusercontent.com/nf-core/pixelator/main/assets/schema_input.json", + "$id": "https://raw.githubusercontent.com/nf-core/pixelator/master/assets/schema_input.json", "title": "nf-core/pixelator pipeline - params.input schema", "description": "Schema for the file provided with params.input", "type": "array", diff --git a/docs/output.md b/docs/output.md index 6b9c4a9b..7225d0f2 100644 --- a/docs/output.md +++ b/docs/output.md @@ -12,7 +12,6 @@ of [`pixelator`](https://github.com/PixelgenTechnologies/pixelator). The pipeline consists of the following steps: -- [FastQC](#fastqc) - Raw read QC- [MultiQC](#multiqc) - Aggregate report describing results and QC from the whole pipeline - [Pipeline information](#pipeline-information) - Report metrics generated during the workflow execution - [Preprocessing](#Preprocessing) - [Quality control](#quality-control) @@ -295,32 +294,7 @@ More information on the report can be found in the [pixelator documentation](htt
    -### FastQC - -
    -Output files - -- `fastqc/` - - `*_fastqc.html`: FastQC report containing quality metrics. - - `*_fastqc.zip`: Zip archive containing the FastQC report, tab-delimited data file and plot images. - -
    - -[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 - -
    -Output files - -- `multiqc/` - - `multiqc_report.html`: a standalone HTML file that can be viewed in your web browser. - - `multiqc_data/`: directory containing parsed statistics from the different tools used in the pipeline. - - `multiqc_plots/`: directory containing static images from the report in various formats. - -
    - -[MultiQC](http://multiqc.info) is a visualization tool that generates a single HTML report summarising all samples in your project. Most of the pipeline QC results are visualised in the report and further statistics are available in the report data directory. - -Results generated by MultiQC collate pipeline QC from supported tools e.g. FastQC. The pipeline has special steps which also allow the software versions to be reported in the MultiQC output for future traceability. For more information about how to use MultiQC reports, see .### Pipeline information +### Pipeline information
    Output files diff --git a/docs/usage.md b/docs/usage.md index 34a0f9af..d4223a1f 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -139,7 +139,7 @@ Currently, two built-in panels are available: The typical command for running the pipeline is as follows: ```bash -nextflow run nf-core/pixelator --input ./samplesheet.csv --outdir ./results --genome GRCh37 -profile docker +nextflow run nf-core/pixelator --input ./samplesheet.csv --outdir ./results -profile docker ``` This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. @@ -171,7 +171,6 @@ with: ```yaml title="params.yaml" input: './samplesheet.csv' outdir: './results/' -genome: 'GRCh37' <...> ``` @@ -193,7 +192,7 @@ It is a good idea to specify the pipeline version when running the pipeline on y First, go to the [nf-core/pixelator releases page](https://github.com/nf-core/pixelator/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. +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. To further assist in reproducibility, you can use share and reuse [parameter files](#running-the-pipeline) to repeat pipeline runs with the same settings without having to write out a command with every single parameter. diff --git a/nextflow.config b/nextflow.config index 7f19f98c..135dd325 100644 --- a/nextflow.config +++ b/nextflow.config @@ -348,7 +348,7 @@ validation { https://doi.org/10.1038/s41587-020-0439-x * Software dependencies - https://github.com/nf-core/pixelator/blob/main/CITATIONS.md + https://github.com/nf-core/pixelator/blob/master/CITATIONS.md """ } summary { diff --git a/nextflow_schema.json b/nextflow_schema.json index 17d7a6d4..a8f15854 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://raw.githubusercontent.com/nf-core/pixelator/main/nextflow_schema.json", + "$id": "https://raw.githubusercontent.com/nf-core/pixelator/master/nextflow_schema.json", "title": "nf-core/pixelator pipeline parameters", "description": "Pipeline for analysis of Molecular Pixelation assays", "type": "object", From ba6ffee1a3be12c7af41e3db2b3c535a3150eb44 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 15 Jan 2025 11:16:38 +0100 Subject: [PATCH 49/70] Update contributors in nextflow.config --- nextflow.config | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/nextflow.config b/nextflow.config index 135dd325..0caed64a 100644 --- a/nextflow.config +++ b/nextflow.config @@ -299,18 +299,35 @@ dag { manifest { name = 'nf-core/pixelator' + // Keep both author and contributors fields for compatibility with Nextflow versions < 24.10.0 author = """Pixelgen Technologies AB""" // The author field is deprecated from Nextflow version 24.10.0, use contributors instead contributors = [ - // TODO nf-core: Update the field with the details of the contributors to your pipeline. New with Nextflow version 24.10.0 [ - name: 'Pixelgen Technologies AB', - affiliation: '', - email: '', - github: '', - contribution: [], // List of contribution types ('author', 'maintainer' or 'contributor') - orcid: '' + name: 'Florian De Temmerman', + affiliation: 'Pixelgen Technologies AB', + email: 'florian.detemmerman@pixelgen.com', + github: '@fbdtemme', + contribution: ["author", "maintainer"], // List of contribution types ('author', 'maintainer' or 'contributor') + orcid: '0009-0006-0086-2470' + ], + [ + name: 'Johan Dahlberg', + affiliation: 'Pixelgen Technologies AB', + email: 'johan.dahlberg@pixelgen.com', + github: '@johandahlberg', + contribution: ["contributor"], // List of contribution types ('author', 'maintainer' or 'contributor') + orcid: '0000-0001-6962-1460' + ], + [ + name: 'Alvaro Martinez Barrio', + affiliation: 'Pixelgen Technologies AB', + email: 'alvaro.martinez.barrio@pixelgen.com', + github: '@ambarrio', + contribution: ["contributor"], // List of contribution types ('author', 'maintainer' or 'contributor') + orcid: '0000-0001-5064-2093' ], ] + homePage = 'https://github.com/nf-core/pixelator' description = """Pipeline for analysis of Molecular Pixelation assays""" mainScript = 'main.nf' From 8f232ed3d80ceb3ec90e794f08c661f1a980c0d4 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 15 Jan 2025 11:20:14 +0100 Subject: [PATCH 50/70] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2a47ca0..4749d6dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [[PR #118](https://github.com/nf-core/pixelator/pull/118)] - Update metromap, bump conda versions - [[PR #120](https://github.com/nf-core/pixelator/pull/120)] - Add process_long to AMPLICON and COLLAPSE steps - [[PR #122](https://github.com/nf-core/pixelator/pull/122)] - Template update for nf-core/tools v3.1.1 +- [[PR #124](https://github.com/nf-core/pixelator/pull/122)] - Add manifest.contributors metadata to nextflow.config ### Parameters From 64a239893b572237e517619440044e56e450db9b Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 15 Jan 2025 12:41:35 +0100 Subject: [PATCH 51/70] Use environment.yml files for all conda process directives --- modules/local/collect_metadata/environment.yml | 7 +++++++ .../main.nf} | 2 +- .../pixelator/list_options/environment.yml | 7 +++++++ .../{list_options.nf => list_options/main.nf} | 2 +- .../single-cell/amplicon/environment.yml | 7 +++++++ .../pixelator/single-cell/amplicon/main.nf | 3 +-- .../single-cell/analysis/environment.yml | 7 +++++++ .../pixelator/single-cell/analysis/main.nf | 2 +- .../single-cell/annotate/environment.yml | 7 +++++++ .../pixelator/single-cell/annotate/main.nf | 3 +-- .../single-cell/collapse/environment.yml | 7 +++++++ .../pixelator/single-cell/collapse/main.nf | 2 +- .../single-cell/demux/environment.yml | 7 +++++++ .../local/pixelator/single-cell/demux/main.nf | 3 +-- .../single-cell/graph/environment.yml | 7 +++++++ .../local/pixelator/single-cell/graph/main.nf | 3 +-- .../single-cell/layout/environment.yml | 7 +++++++ .../local/pixelator/single-cell/layout/main.nf | 3 +-- .../pixelator/single-cell/qc/environment.yml | 7 +++++++ modules/local/pixelator/single-cell/qc/main.nf | 3 +-- .../single-cell/report/environment.yml | 7 +++++++ .../local/pixelator/single-cell/report/main.nf | 3 +-- .../utils_nfcore_pixelator_pipeline/main.nf | 2 +- workflows/pixelator.nf | 18 +++++++++--------- 24 files changed, 98 insertions(+), 28 deletions(-) create mode 100644 modules/local/collect_metadata/environment.yml rename modules/local/{pixelator/collect_metadata.nf => collect_metadata/main.nf} (97%) create mode 100644 modules/local/pixelator/list_options/environment.yml rename modules/local/pixelator/{list_options.nf => list_options/main.nf} (93%) create mode 100644 modules/local/pixelator/single-cell/amplicon/environment.yml create mode 100644 modules/local/pixelator/single-cell/analysis/environment.yml create mode 100644 modules/local/pixelator/single-cell/annotate/environment.yml create mode 100644 modules/local/pixelator/single-cell/collapse/environment.yml create mode 100644 modules/local/pixelator/single-cell/demux/environment.yml create mode 100644 modules/local/pixelator/single-cell/graph/environment.yml create mode 100644 modules/local/pixelator/single-cell/layout/environment.yml create mode 100644 modules/local/pixelator/single-cell/qc/environment.yml create mode 100644 modules/local/pixelator/single-cell/report/environment.yml diff --git a/modules/local/collect_metadata/environment.yml b/modules/local/collect_metadata/environment.yml new file mode 100644 index 00000000..21a756c8 --- /dev/null +++ b/modules/local/collect_metadata/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::pixelator=0.19.0 diff --git a/modules/local/pixelator/collect_metadata.nf b/modules/local/collect_metadata/main.nf similarity index 97% rename from modules/local/pixelator/collect_metadata.nf rename to modules/local/collect_metadata/main.nf index ca6a5086..556f32e8 100644 --- a/modules/local/pixelator/collect_metadata.nf +++ b/modules/local/collect_metadata/main.nf @@ -3,7 +3,7 @@ process PIXELATOR_COLLECT_METADATA { label 'process_single' cache false - conda "bioconda::pixelator=0.19.0" + conda "modules/local/collect_metadata/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/list_options/environment.yml b/modules/local/pixelator/list_options/environment.yml new file mode 100644 index 00000000..21a756c8 --- /dev/null +++ b/modules/local/pixelator/list_options/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::pixelator=0.19.0 diff --git a/modules/local/pixelator/list_options.nf b/modules/local/pixelator/list_options/main.nf similarity index 93% rename from modules/local/pixelator/list_options.nf rename to modules/local/pixelator/list_options/main.nf index f49dbd56..a8e1bf80 100644 --- a/modules/local/pixelator/list_options.nf +++ b/modules/local/pixelator/list_options/main.nf @@ -2,7 +2,7 @@ process PIXELATOR_LIST_OPTIONS { label 'process_single' - conda "bioconda::pixelator=0.19.0" + conda "modules/local/pixelator/list_options/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/amplicon/environment.yml b/modules/local/pixelator/single-cell/amplicon/environment.yml new file mode 100644 index 00000000..21a756c8 --- /dev/null +++ b/modules/local/pixelator/single-cell/amplicon/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::pixelator=0.19.0 diff --git a/modules/local/pixelator/single-cell/amplicon/main.nf b/modules/local/pixelator/single-cell/amplicon/main.nf index 690af80c..4c9cc91c 100644 --- a/modules/local/pixelator/single-cell/amplicon/main.nf +++ b/modules/local/pixelator/single-cell/amplicon/main.nf @@ -3,8 +3,7 @@ process PIXELATOR_AMPLICON { label 'process_low' label 'process_long' - - conda "bioconda::pixelator=0.19.0" + conda "modules/local/pixelator/single-cell/amplicon/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/analysis/environment.yml b/modules/local/pixelator/single-cell/analysis/environment.yml new file mode 100644 index 00000000..21a756c8 --- /dev/null +++ b/modules/local/pixelator/single-cell/analysis/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::pixelator=0.19.0 diff --git a/modules/local/pixelator/single-cell/analysis/main.nf b/modules/local/pixelator/single-cell/analysis/main.nf index c9cc8f18..ca5955d9 100644 --- a/modules/local/pixelator/single-cell/analysis/main.nf +++ b/modules/local/pixelator/single-cell/analysis/main.nf @@ -2,7 +2,7 @@ process PIXELATOR_ANALYSIS { tag "$meta.id" label 'process_medium' - conda "bioconda::pixelator=0.19.0" + conda "modules/local/pixelator/single-cell/analysis/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/annotate/environment.yml b/modules/local/pixelator/single-cell/annotate/environment.yml new file mode 100644 index 00000000..21a756c8 --- /dev/null +++ b/modules/local/pixelator/single-cell/annotate/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::pixelator=0.19.0 diff --git a/modules/local/pixelator/single-cell/annotate/main.nf b/modules/local/pixelator/single-cell/annotate/main.nf index 5096ff50..46565979 100644 --- a/modules/local/pixelator/single-cell/annotate/main.nf +++ b/modules/local/pixelator/single-cell/annotate/main.nf @@ -2,8 +2,7 @@ process PIXELATOR_ANNOTATE { tag "$meta.id" label 'process_high' - - conda "bioconda::pixelator=0.19.0" + conda "modules/local/pixelator/single-cell/annotate/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/collapse/environment.yml b/modules/local/pixelator/single-cell/collapse/environment.yml new file mode 100644 index 00000000..21a756c8 --- /dev/null +++ b/modules/local/pixelator/single-cell/collapse/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::pixelator=0.19.0 diff --git a/modules/local/pixelator/single-cell/collapse/main.nf b/modules/local/pixelator/single-cell/collapse/main.nf index 765e51e9..8982c060 100644 --- a/modules/local/pixelator/single-cell/collapse/main.nf +++ b/modules/local/pixelator/single-cell/collapse/main.nf @@ -3,7 +3,7 @@ process PIXELATOR_COLLAPSE { label 'process_medium' label 'process_long' - conda "bioconda::pixelator=0.19.0" + conda "modules/local/pixelator/single-cell/collapse/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/demux/environment.yml b/modules/local/pixelator/single-cell/demux/environment.yml new file mode 100644 index 00000000..21a756c8 --- /dev/null +++ b/modules/local/pixelator/single-cell/demux/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::pixelator=0.19.0 diff --git a/modules/local/pixelator/single-cell/demux/main.nf b/modules/local/pixelator/single-cell/demux/main.nf index 19bfe96e..cec59f72 100644 --- a/modules/local/pixelator/single-cell/demux/main.nf +++ b/modules/local/pixelator/single-cell/demux/main.nf @@ -2,8 +2,7 @@ process PIXELATOR_DEMUX { tag "$meta.id" label 'process_medium' - - conda "bioconda::pixelator=0.19.0" + conda "modules/local/pixelator/single-cell/demux/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/graph/environment.yml b/modules/local/pixelator/single-cell/graph/environment.yml new file mode 100644 index 00000000..21a756c8 --- /dev/null +++ b/modules/local/pixelator/single-cell/graph/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::pixelator=0.19.0 diff --git a/modules/local/pixelator/single-cell/graph/main.nf b/modules/local/pixelator/single-cell/graph/main.nf index e14f74cb..40ca850a 100644 --- a/modules/local/pixelator/single-cell/graph/main.nf +++ b/modules/local/pixelator/single-cell/graph/main.nf @@ -2,8 +2,7 @@ process PIXELATOR_GRAPH { tag "$meta.id" label 'process_high' - - conda "bioconda::pixelator=0.19.0" + conda "modules/local/pixelator/single-cell/graph/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/layout/environment.yml b/modules/local/pixelator/single-cell/layout/environment.yml new file mode 100644 index 00000000..21a756c8 --- /dev/null +++ b/modules/local/pixelator/single-cell/layout/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::pixelator=0.19.0 diff --git a/modules/local/pixelator/single-cell/layout/main.nf b/modules/local/pixelator/single-cell/layout/main.nf index 00e414ec..4ea05b58 100644 --- a/modules/local/pixelator/single-cell/layout/main.nf +++ b/modules/local/pixelator/single-cell/layout/main.nf @@ -2,8 +2,7 @@ process PIXELATOR_LAYOUT { tag "$meta.id" label 'process_medium' - - conda "bioconda::pixelator=0.19.0" + conda "modules/local/pixelator/single-cell/layout/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/qc/environment.yml b/modules/local/pixelator/single-cell/qc/environment.yml new file mode 100644 index 00000000..21a756c8 --- /dev/null +++ b/modules/local/pixelator/single-cell/qc/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::pixelator=0.19.0 diff --git a/modules/local/pixelator/single-cell/qc/main.nf b/modules/local/pixelator/single-cell/qc/main.nf index 49f28504..b36ad056 100644 --- a/modules/local/pixelator/single-cell/qc/main.nf +++ b/modules/local/pixelator/single-cell/qc/main.nf @@ -2,8 +2,7 @@ process PIXELATOR_QC { tag "$meta.id" label 'process_medium' - - conda "bioconda::pixelator=0.19.0" + conda "modules/local/pixelator/single-cell/qc/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/report/environment.yml b/modules/local/pixelator/single-cell/report/environment.yml new file mode 100644 index 00000000..21a756c8 --- /dev/null +++ b/modules/local/pixelator/single-cell/report/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::pixelator=0.19.0 diff --git a/modules/local/pixelator/single-cell/report/main.nf b/modules/local/pixelator/single-cell/report/main.nf index fe443316..3dcab9c0 100644 --- a/modules/local/pixelator/single-cell/report/main.nf +++ b/modules/local/pixelator/single-cell/report/main.nf @@ -2,8 +2,7 @@ process PIXELATOR_REPORT { tag "$meta.id" label 'process_low' - - conda "bioconda::pixelator=0.19.0" + conda "modules/local/pixelator/single-cell/report/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf index e9a7ccc0..b88a43b3 100644 --- a/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_pixelator_pipeline/main.nf @@ -17,7 +17,7 @@ include { imNotification } from '../../nf-core/utils_nfcore_pipeline' include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' -include { PIXELATOR_LIST_OPTIONS } from '../../../modules/local/pixelator/list_options.nf' +include { PIXELATOR_LIST_OPTIONS } from '../../../modules/local/pixelator/list_options' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/workflows/pixelator.nf b/workflows/pixelator.nf index 865c13a1..53aef853 100644 --- a/workflows/pixelator.nf +++ b/workflows/pixelator.nf @@ -49,15 +49,15 @@ include { CAT_FASTQ } from '../modules/nf-core/cat/fastq/main' // // MODULE: Defined locally // -include { PIXELATOR_COLLECT_METADATA } from '../modules/local/pixelator/collect_metadata' -include { PIXELATOR_AMPLICON } from '../modules/local/pixelator/single-cell/amplicon/main' -include { PIXELATOR_QC } from '../modules/local/pixelator/single-cell/qc/main' -include { PIXELATOR_DEMUX } from '../modules/local/pixelator/single-cell/demux/main' -include { PIXELATOR_COLLAPSE } from '../modules/local/pixelator/single-cell/collapse/main' -include { PIXELATOR_GRAPH } from '../modules/local/pixelator/single-cell/graph/main' -include { PIXELATOR_ANALYSIS } from '../modules/local/pixelator/single-cell/analysis/main' -include { PIXELATOR_ANNOTATE } from '../modules/local/pixelator/single-cell/annotate/main' -include { PIXELATOR_LAYOUT } from '../modules/local/pixelator/single-cell/layout/main' +include { PIXELATOR_COLLECT_METADATA } from '../modules/local/collect_metadata' +include { PIXELATOR_AMPLICON } from '../modules/local/pixelator/single-cell/amplicon' +include { PIXELATOR_QC } from '../modules/local/pixelator/single-cell/qc' +include { PIXELATOR_DEMUX } from '../modules/local/pixelator/single-cell/demux' +include { PIXELATOR_COLLAPSE } from '../modules/local/pixelator/single-cell/collapse' +include { PIXELATOR_GRAPH } from '../modules/local/pixelator/single-cell/graph' +include { PIXELATOR_ANALYSIS } from '../modules/local/pixelator/single-cell/analysis' +include { PIXELATOR_ANNOTATE } from '../modules/local/pixelator/single-cell/annotate' +include { PIXELATOR_LAYOUT } from '../modules/local/pixelator/single-cell/layout' /* ======================================================================================== From cbf7bd46d53880999f6bb11a5e1ae83102724e9a Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 15 Jan 2025 14:04:01 +0100 Subject: [PATCH 52/70] Update CHANGELOG --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4749d6dd..282fff36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [[PR #118](https://github.com/nf-core/pixelator/pull/118)] - Update metromap, bump conda versions - [[PR #120](https://github.com/nf-core/pixelator/pull/120)] - Add process_long to AMPLICON and COLLAPSE steps - [[PR #122](https://github.com/nf-core/pixelator/pull/122)] - Template update for nf-core/tools v3.1.1 -- [[PR #124](https://github.com/nf-core/pixelator/pull/122)] - Add manifest.contributors metadata to nextflow.config +- [[PR #124](https://github.com/nf-core/pixelator/pull/124)] - Add manifest.contributors metadata to nextflow.config +- [[PR #125](https://github.com/nf-core/pixelator/pull/125)] - Use environment.yml files for all conda process directives ### Parameters From 7c55c64a42b697984fbe6cd76568d26d826ed991 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 8 Jan 2025 16:55:59 +0100 Subject: [PATCH 53/70] Add new small test config --- conf/test_mpx_scsp_v1.config | 49 ++++++++++++++++++++++++++++++++++++ nextflow.config | 7 +++--- 2 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 conf/test_mpx_scsp_v1.config diff --git a/conf/test_mpx_scsp_v1.config b/conf/test_mpx_scsp_v1.config new file mode 100644 index 00000000..fc339e4f --- /dev/null +++ b/conf/test_mpx_scsp_v1.config @@ -0,0 +1,49 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for running minimal tests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Defines input files and everything required to run a fast and simple pipeline test + using the v2 panel. + + Use as follows: + nextflow run nf-core/pixelator -profile test_panel_v2, --outdir + +---------------------------------------------------------------------------------------- +*/ + + +aws.client.downloadParallel = true + +process { + resourceLimits = [ + cpus: 4, + memory: '15.GB', + time: '1.h' + ] +} + +params { + config_profile_name = 'Test profile' + config_profile_description = 'Minimal test dataset to check pipeline function' + + // Input data + // TODO: Add pixelator back here as the first dir + input = params.pipelines_testdata_base_path + 'samplesheet/samplesheet_mpx_scsp_v1.csv' + input_basedir = params.pipelines_testdata_base_path + '' + + multiplet_recovery = true + min_size = 1 + max_size = 100000 + dynamic_filter = null + compute_polarization = true + use_full_bipartite = true + colocalization_min_region_count = 0 + colocalization_n_permutations = 10 + colocalization_neighbourhood_size = 1 + + // For now skip the layout step since it is very slow on these + // small test datasets + skip_layout = false + // using this since the default pmds_3d does not work on very small graphs + layout_algorithm = "fruchterman_reingold_3d" +} diff --git a/nextflow.config b/nextflow.config index 0caed64a..e962be53 100644 --- a/nextflow.config +++ b/nextflow.config @@ -236,9 +236,10 @@ profiles { ] } } - test { includeConfig 'conf/test.config' } - test_panel_v2 { includeConfig 'conf/test_panel_v2.config' } - test_full { includeConfig 'conf/test_full.config' } + test { includeConfig 'conf/test.config' } + test_mpx_scsp_v1 { includeConfig 'conf/test_mpx_scsp_v1.config' } + test_panel_v2 { includeConfig 'conf/test_panel_v2.config' } + test_full { includeConfig 'conf/test_full.config' } } // Load nf-core custom profiles from different Institutions From 6bf38afa91ec277f0b02be387408600b2d9e3f00 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Thu, 9 Jan 2025 16:01:56 +0100 Subject: [PATCH 54/70] Add versioning to collect_metadata.py script --- bin/collect_metadata.py | 10 +++++++++- modules/local/collect_metadata/main.nf | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/bin/collect_metadata.py b/bin/collect_metadata.py index 8eef3d74..b091bce5 100755 --- a/bin/collect_metadata.py +++ b/bin/collect_metadata.py @@ -16,6 +16,8 @@ import ruamel.yaml as yaml +__version__ = "1.0.0" + installed_packages = {d.name: d.version for d in importlib.metadata.distributions()} @@ -72,7 +74,13 @@ def main(args): if __name__ == "__main__": - parser = argparse.ArgumentParser() + parser = argparse.ArgumentParser( + prog="collect-metadata", + description="Collect version information about the pixelator python environment.", + ) + parser.add_argument( + "--version", action="version", version=f"%(prog)s {__version__}" + ) parser.add_argument("--process-name", dest="process_name", type=str) parser.add_argument( diff --git a/modules/local/collect_metadata/main.nf b/modules/local/collect_metadata/main.nf index 556f32e8..89f92959 100644 --- a/modules/local/collect_metadata/main.nf +++ b/modules/local/collect_metadata/main.nf @@ -69,5 +69,10 @@ process PIXELATOR_COLLECT_METADATA { """ echo '${nextflowJson}' > nextflow-metadata.json collect_metadata.py --process-name ${task.process} --workflow-data "nextflow-metadata.json" + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + collect_metadata.py: \$(echo \$(collect_metadata.py --version 2>/dev/null) | sed 's/collect-metadata //g' ) + END_VERSIONS """ } From 066b8f2bbcd712e60c31e307472efe660e5c26b6 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Thu, 9 Jan 2025 16:04:36 +0100 Subject: [PATCH 55/70] Add stubs for all local modules --- modules/local/collect_metadata/main.nf | 59 +++++++++++++++++++ modules/local/pixelator/list_options/main.nf | 18 ++++++ .../pixelator/single-cell/amplicon/main.nf | 15 +++++ .../pixelator/single-cell/analysis/main.nf | 19 +++++- .../pixelator/single-cell/annotate/main.nf | 16 +++++ .../pixelator/single-cell/collapse/main.nf | 18 +++++- .../local/pixelator/single-cell/demux/main.nf | 19 +++++- .../local/pixelator/single-cell/graph/main.nf | 18 +++++- .../pixelator/single-cell/layout/main.nf | 17 +++++- .../local/pixelator/single-cell/qc/main.nf | 25 ++++++++ .../pixelator/single-cell/report/main.nf | 15 +++++ 11 files changed, 233 insertions(+), 6 deletions(-) diff --git a/modules/local/collect_metadata/main.nf b/modules/local/collect_metadata/main.nf index 89f92959..412cf0bc 100644 --- a/modules/local/collect_metadata/main.nf +++ b/modules/local/collect_metadata/main.nf @@ -70,6 +70,65 @@ process PIXELATOR_COLLECT_METADATA { echo '${nextflowJson}' > nextflow-metadata.json collect_metadata.py --process-name ${task.process} --workflow-data "nextflow-metadata.json" + cat <<-END_VERSIONS > versions.yml + "${task.process}": + collect_metadata.py: \$(echo \$(collect_metadata.py --version 2>/dev/null) | sed 's/collect-metadata //g' ) + END_VERSIONS + """ + + stub: + def nextflow_dict = [ + version: workflow.nextflow.version, + build: workflow.nextflow.build, + timestamp: workflow.nextflow.timestamp?.toString(), + ] + def manifest_dict = [ + author: workflow.manifest.getAuthor(), + defaultBranch: workflow.manifest.getDefaultBranch(), + description: workflow.manifest.getDescription(), + homePage: workflow.manifest.getHomePage(), + gitmodules: workflow.manifest.getGitmodules(), + mainScript: workflow.manifest.getMainScript(), + version: workflow.manifest.getVersion(), + nextflowVersion: workflow.manifest.getNextflowVersion(), + doi: workflow.manifest.getDoi(), + ] + + def workflow_dict = [ + scriptId: workflow.scriptId, + scriptName: workflow.scriptName, + scriptFile: workflow.scriptFile.toString(), + repository: workflow.repository, + commitId: workflow.commitId, + revision: workflow.revision, + projectDir: workflow.projectDir.toString(), + launchDir: workflow.launchDir.toString(), + workDir: workflow.workDir.toString(), + homeDir: workflow.homeDir.toString(), + userName: workflow.userName, + configFiles: workflow.configFiles.collect { it.toString() }, + container: workflow.container.collectEntries { [it.key, it.value?.toString()] }, + containerEngine: workflow.containerEngine, + commandLine: workflow.commandLine, + profile: workflow.profile, + runName: workflow.runName, + sessionId: workflow.sessionId, + resume: workflow.resume, + stubRun: workflow.stubRun, + start: workflow.start?.toString(), + ] + + def metadata = [ + nextflow: nextflow_dict, + manifest: manifest_dict, + workflow : workflow_dict, + parameters: params + ] + + """ + echo '${metadata}' > metadata.json + touch nextflow-metadata.json + cat <<-END_VERSIONS > versions.yml "${task.process}": collect_metadata.py: \$(echo \$(collect_metadata.py --version 2>/dev/null) | sed 's/collect-metadata //g' ) diff --git a/modules/local/pixelator/list_options/main.nf b/modules/local/pixelator/list_options/main.nf index a8e1bf80..c2aafcee 100644 --- a/modules/local/pixelator/list_options/main.nf +++ b/modules/local/pixelator/list_options/main.nf @@ -28,4 +28,22 @@ process PIXELATOR_LIST_OPTIONS { pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) END_VERSIONS """ + + stub: + """ + cat <<-END_DESIGN > design_options.txt + D21 + END_DESIGN + + cat <<-END_PANELS > panel_options.txt + human-sc-immunology-spatial-proteomics-1 + human-sc-immunology-spatial-proteomics-2 + human-sc-immunology-spatial-proteomics + END_PANELS + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) + END_VERSIONS + """ } diff --git a/modules/local/pixelator/single-cell/amplicon/main.nf b/modules/local/pixelator/single-cell/amplicon/main.nf index 4c9cc91c..28b4b2e0 100644 --- a/modules/local/pixelator/single-cell/amplicon/main.nf +++ b/modules/local/pixelator/single-cell/amplicon/main.nf @@ -55,6 +55,21 @@ process PIXELATOR_AMPLICON { pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) END_VERSIONS """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + mkdir amplicon + touch "${prefix}.pixelator-amplicon.log" + touch amplicon/${prefix}.merged.fq.gz + touch amplicon/${prefix}.report.json + touch amplicon/${prefix}.meta.json + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) + END_VERSIONS + """ } diff --git a/modules/local/pixelator/single-cell/analysis/main.nf b/modules/local/pixelator/single-cell/analysis/main.nf index ca5955d9..97b14481 100644 --- a/modules/local/pixelator/single-cell/analysis/main.nf +++ b/modules/local/pixelator/single-cell/analysis/main.nf @@ -23,8 +23,7 @@ process PIXELATOR_ANALYSIS { task.ext.when == null || task.ext.when script: - - prefix = task.ext.prefix ?: "${meta.id}" + def prefix = task.ext.prefix ?: "${meta.id}" def args = task.ext.args ?: '' """ @@ -43,4 +42,20 @@ process PIXELATOR_ANALYSIS { pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) END_VERSIONS """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + mkdir analysis + touch "${prefix}.pixelator-analysis.log" + touch "analysis/${prefix}.dataset.pxl" + touch "analysis/${prefix}.report.json" + touch "analysis/${prefix}.meta.json" + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) + END_VERSIONS + """ } diff --git a/modules/local/pixelator/single-cell/annotate/main.nf b/modules/local/pixelator/single-cell/annotate/main.nf index 46565979..aa6c10ba 100644 --- a/modules/local/pixelator/single-cell/annotate/main.nf +++ b/modules/local/pixelator/single-cell/annotate/main.nf @@ -49,4 +49,20 @@ process PIXELATOR_ANNOTATE { pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) END_VERSIONS """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + mkdir annotate + touch "${prefix}.pixelator-annotate.log" + touch "annotate/${prefix}.dataset.pxl" + touch "annotate/${prefix}.report.json" + touch "annotate/${prefix}.meta.json" + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) + END_VERSIONS + """ } diff --git a/modules/local/pixelator/single-cell/collapse/main.nf b/modules/local/pixelator/single-cell/collapse/main.nf index 8982c060..01d1044b 100644 --- a/modules/local/pixelator/single-cell/collapse/main.nf +++ b/modules/local/pixelator/single-cell/collapse/main.nf @@ -25,7 +25,7 @@ process PIXELATOR_COLLAPSE { script: assert meta.design != null - prefix = task.ext.prefix ?: "${meta.id}" + def prefix = task.ext.prefix ?: "${meta.id}" def args = task.ext.args ?: '' def readsArg = reads.join(' ') def panelOpt = ( @@ -52,4 +52,20 @@ process PIXELATOR_COLLAPSE { pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) END_VERSIONS """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + mkdir collapse + touch "${prefix}.pixelator-collapse.log" + touch "collapse/${prefix}.collapsed.parquet" + touch "collapse/${prefix}.report.json" + touch "collapse/${prefix}.meta.json" + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) + END_VERSIONS + """ } diff --git a/modules/local/pixelator/single-cell/demux/main.nf b/modules/local/pixelator/single-cell/demux/main.nf index cec59f72..9719e93a 100644 --- a/modules/local/pixelator/single-cell/demux/main.nf +++ b/modules/local/pixelator/single-cell/demux/main.nf @@ -25,7 +25,7 @@ process PIXELATOR_DEMUX { script: // --design is passed in meta and added to args through modules.conf - prefix = task.ext.prefix ?: "${meta.id}" + def prefix = task.ext.prefix ?: "${meta.id}" def args = task.ext.args ?: '' def panelOpt = ( panel ? "--panel $panel" : @@ -50,4 +50,21 @@ process PIXELATOR_DEMUX { pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) END_VERSIONS """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + mkdir demux + touch "${prefix}.pixelator-demux.log" + touch "demux/${prefix}.report.json" + touch "demux/${prefix}.meta.json" + touch "demux/${prefix}.processed.fq.gz" + touch "demux/${prefix}.failed.fq.gz" + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) + END_VERSIONS + """ } diff --git a/modules/local/pixelator/single-cell/graph/main.nf b/modules/local/pixelator/single-cell/graph/main.nf index 40ca850a..d0f18f8f 100644 --- a/modules/local/pixelator/single-cell/graph/main.nf +++ b/modules/local/pixelator/single-cell/graph/main.nf @@ -24,7 +24,7 @@ process PIXELATOR_GRAPH { script: - prefix = task.ext.prefix ?: "${meta.id}" + def prefix = task.ext.prefix ?: "${meta.id}" def args = task.ext.args ?: '' """ @@ -43,4 +43,20 @@ process PIXELATOR_GRAPH { pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) END_VERSIONS """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + mkdir graph + touch "${prefix}.pixelator-graph.log" + touch "graph/${prefix}.edgelist.parquet" + touch "graph/${prefix}.report.json" + touch "graph/${prefix}.meta.json" + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) + END_VERSIONS + """ } diff --git a/modules/local/pixelator/single-cell/layout/main.nf b/modules/local/pixelator/single-cell/layout/main.nf index 4ea05b58..ad0c3d40 100644 --- a/modules/local/pixelator/single-cell/layout/main.nf +++ b/modules/local/pixelator/single-cell/layout/main.nf @@ -24,7 +24,7 @@ process PIXELATOR_LAYOUT { script: - prefix = task.ext.prefix ?: "${meta.id}" + def prefix = task.ext.prefix ?: "${meta.id}" def args = task.ext.args ?: '' """ @@ -43,4 +43,19 @@ process PIXELATOR_LAYOUT { pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) END_VERSIONS """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + mkdir layout + touch "${prefix}.pixelator-layout.log" + touch "layout/${prefix}.dataset.pxl" + touch "layout/${prefix}.report.json" + touch "layout/${prefix}.meta.json" + + cat <<-END_VERSIONS > versions.yml + pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) + END_VERSIONS + """ } diff --git a/modules/local/pixelator/single-cell/qc/main.nf b/modules/local/pixelator/single-cell/qc/main.nf index b36ad056..0aca8a8c 100644 --- a/modules/local/pixelator/single-cell/qc/main.nf +++ b/modules/local/pixelator/single-cell/qc/main.nf @@ -76,4 +76,29 @@ process PIXELATOR_QC { pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) END_VERSIONS """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + mkdir preqc + touch "preqc/${prefix}.processed.fq.gz" + touch "preqc/${prefix}.failed.fq.gz" + touch "preqc/${prefix}.report.json" + touch "preqc/${prefix}.meta.json" + touch "preqc/${prefix}.qc-report.html" + touch "${prefix}.pixelator-preqc.log" + + mkdir adapterqc + touch "adapterqc/${prefix}.processed.fq.gz" + touch "adapterqc/${prefix}.failed.fq.gz" + touch "adapterqc/${prefix}.report.json" + touch "adapterqc/${prefix}.meta.json" + touch "${prefix}.pixelator-adapterqc.log" + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) + END_VERSIONS + """ } diff --git a/modules/local/pixelator/single-cell/report/main.nf b/modules/local/pixelator/single-cell/report/main.nf index 3dcab9c0..5526f981 100644 --- a/modules/local/pixelator/single-cell/report/main.nf +++ b/modules/local/pixelator/single-cell/report/main.nf @@ -54,4 +54,19 @@ process PIXELATOR_REPORT { pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) END_VERSIONS """ + + stub: + + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + mkdir report + touch "${prefix}.pixelator-report.log" + touch "report/${prefix}.html" + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + pixelator: \$(echo \$(pixelator --version 2>/dev/null) | sed 's/pixelator, version //g' ) + END_VERSIONS + """ } From ef447fa32903ddaa445be4161c6c7411490861f4 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Thu, 9 Jan 2025 16:14:39 +0100 Subject: [PATCH 56/70] Remove unused multiqc and fastqc modules --- modules/nf-core/fastqc/environment.yml | 5 - modules/nf-core/fastqc/main.nf | 64 --- modules/nf-core/fastqc/meta.yml | 67 --- modules/nf-core/fastqc/tests/main.nf.test | 309 -------------- .../nf-core/fastqc/tests/main.nf.test.snap | 392 ------------------ modules/nf-core/fastqc/tests/tags.yml | 2 - modules/nf-core/multiqc/environment.yml | 5 - modules/nf-core/multiqc/main.nf | 63 --- modules/nf-core/multiqc/meta.yml | 78 ---- modules/nf-core/multiqc/tests/main.nf.test | 92 ---- .../nf-core/multiqc/tests/main.nf.test.snap | 41 -- modules/nf-core/multiqc/tests/nextflow.config | 5 - modules/nf-core/multiqc/tests/tags.yml | 2 - 13 files changed, 1125 deletions(-) delete mode 100644 modules/nf-core/fastqc/environment.yml delete mode 100644 modules/nf-core/fastqc/main.nf delete mode 100644 modules/nf-core/fastqc/meta.yml delete mode 100644 modules/nf-core/fastqc/tests/main.nf.test delete mode 100644 modules/nf-core/fastqc/tests/main.nf.test.snap delete mode 100644 modules/nf-core/fastqc/tests/tags.yml delete mode 100644 modules/nf-core/multiqc/environment.yml delete mode 100644 modules/nf-core/multiqc/main.nf delete mode 100644 modules/nf-core/multiqc/meta.yml delete mode 100644 modules/nf-core/multiqc/tests/main.nf.test delete mode 100644 modules/nf-core/multiqc/tests/main.nf.test.snap delete mode 100644 modules/nf-core/multiqc/tests/nextflow.config delete mode 100644 modules/nf-core/multiqc/tests/tags.yml diff --git a/modules/nf-core/fastqc/environment.yml b/modules/nf-core/fastqc/environment.yml deleted file mode 100644 index 691d4c76..00000000 --- a/modules/nf-core/fastqc/environment.yml +++ /dev/null @@ -1,5 +0,0 @@ -channels: - - conda-forge - - bioconda -dependencies: - - bioconda::fastqc=0.12.1 diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf deleted file mode 100644 index 752c3a10..00000000 --- a/modules/nf-core/fastqc/main.nf +++ /dev/null @@ -1,64 +0,0 @@ -process FASTQC { - 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/fastqc:0.12.1--hdfd78af_0' : - 'biocontainers/fastqc:0.12.1--hdfd78af_0' }" - - input: - tuple val(meta), path(reads) - - output: - tuple val(meta), path("*.html"), emit: html - tuple val(meta), path("*.zip") , emit: zip - 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}" - // 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(' ') - - // The total amount of allocated RAM by FastQC is equal to the number of threads defined (--threads) time the amount of RAM defined (--memory) - // https://github.com/s-andrews/FastQC/blob/1faeea0412093224d7f6a07f777fad60a5650795/fastqc#L211-L222 - // Dividing the task.memory by task.cpu allows to stick to requested amount of RAM in the label - def memory_in_mb = MemoryUnit.of("${task.memory}").toUnit('MB') / task.cpus - // 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 - done - - fastqc \\ - $args \\ - --threads $task.cpus \\ - --memory $fastqc_memory \\ - $renamed_files - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - fastqc: \$( fastqc --version | sed '/FastQC v/!d; s/.*v//' ) - END_VERSIONS - """ - - stub: - def prefix = task.ext.prefix ?: "${meta.id}" - """ - touch ${prefix}.html - touch ${prefix}.zip - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - 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 deleted file mode 100644 index 2b2e62b8..00000000 --- a/modules/nf-core/fastqc/meta.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: fastqc -description: Run FastQC on sequenced reads -keywords: - - quality control - - qc - - adapters - - fastq -tools: - - fastqc: - description: | - FastQC gives general quality metrics about your reads. - It provides information about the quality score distribution - across your reads, the per base sequence content (%A/C/G/T). - - You get information about adapter contamination and other - overrepresented sequences. - homepage: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/ - documentation: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/ - licence: ["GPL-2.0-only"] - identifier: biotools:fastqc -input: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - reads: - type: file - description: | - List of input FastQ files of size 1 and 2 for single-end and paired-end data, - respectively. -output: - - html: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - "*.html": - type: file - description: FastQC report - pattern: "*_{fastqc.html}" - - zip: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - "*.zip": - type: file - description: FastQC report archive - pattern: "*_{fastqc.zip}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" -authors: - - "@drpatelh" - - "@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 deleted file mode 100644 index e9d79a07..00000000 --- a/modules/nf-core/fastqc/tests/main.nf.test +++ /dev/null @@ -1,309 +0,0 @@ -nextflow_process { - - name "Test Process FASTQC" - script "../main.nf" - process "FASTQC" - - tag "modules" - tag "modules_nfcore" - tag "fastqc" - - test("sarscov2 single-end [fastq]") { - - 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 }, - // 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("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - 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("File typeConventional base calls") }, - { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - 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("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - 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("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - 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("File typeConventional base calls") }, - { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][2]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][3]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - 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("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - 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).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 deleted file mode 100644 index d5db3092..00000000 --- a/modules/nf-core/fastqc/tests/main.nf.test.snap +++ /dev/null @@ -1,392 +0,0 @@ -{ - "sarscov2 custom_prefix": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:16.374038" - }, - "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]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:01:42.355718" - }, - "sarscov2 paired-end [bam]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:01:53.276274" - }, - "sarscov2 multiple [fastq]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:05.527626" - }, - "sarscov2 paired-end [fastq]": { - "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" - }, - "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-07-22T11:03:02.304411" - }, - "sarscov2 single-end [fastq]": { - "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" - }, - "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-07-22T11:02:53.550742" - } -} \ No newline at end of file diff --git a/modules/nf-core/fastqc/tests/tags.yml b/modules/nf-core/fastqc/tests/tags.yml deleted file mode 100644 index 7834294b..00000000 --- a/modules/nf-core/fastqc/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -fastqc: - - modules/nf-core/fastqc/** diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml deleted file mode 100644 index 6f5b867b..00000000 --- a/modules/nf-core/multiqc/environment.yml +++ /dev/null @@ -1,5 +0,0 @@ -channels: - - conda-forge - - bioconda -dependencies: - - bioconda::multiqc=1.25.1 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf deleted file mode 100644 index cc0643e1..00000000 --- a/modules/nf-core/multiqc/main.nf +++ /dev/null @@ -1,63 +0,0 @@ -process MULTIQC { - label 'process_single' - - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.25.1--pyhdfd78af_0' : - 'biocontainers/multiqc:1.25.1--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 - path "*_data" , emit: data - path "*_plots" , optional:true, emit: plots - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ? "--filename ${task.ext.prefix}.html" : '' - 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 \\ - $args \\ - $config \\ - $prefix \\ - $extra_config \\ - $logo \\ - $replace \\ - $samples \\ - . - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) - END_VERSIONS - """ - - stub: - """ - mkdir multiqc_data - mkdir multiqc_plots - touch multiqc_report.html - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) - END_VERSIONS - """ -} diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml deleted file mode 100644 index b16c1879..00000000 --- a/modules/nf-core/multiqc/meta.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: multiqc -description: Aggregate results from bioinformatics analyses across many samples into - a single report -keywords: - - QC - - bioinformatics tools - - Beautiful stand-alone HTML report -tools: - - multiqc: - description: | - MultiQC searches a given directory for analysis logs and compiles a HTML report. - It's a general use tool, perfect for summarising the output from numerous bioinformatics tools. - homepage: https://multiqc.info/ - documentation: https://multiqc.info/docs/ - licence: ["GPL-3.0-or-later"] - identifier: biotools:multiqc -input: - - - multiqc_files: - type: file - description: | - List of reports / files recognised by MultiQC, for example the html and zip output of FastQC - - - multiqc_config: - type: file - description: Optional config yml for MultiQC - pattern: "*.{yml,yaml}" - - - extra_multiqc_config: - type: file - description: Second optional config yml for MultiQC. Will override common sections - in multiqc_config. - pattern: "*.{yml,yaml}" - - - multiqc_logo: - 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: - - "*multiqc_report.html": - type: file - description: MultiQC report file - pattern: "multiqc_report.html" - - data: - - "*_data": - type: directory - description: MultiQC data dir - pattern: "multiqc_data" - - plots: - - "*_plots": - type: file - description: Plots created by MultiQC - pattern: "*_data" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" -authors: - - "@abhi18av" - - "@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 deleted file mode 100644 index 33316a7d..00000000 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ /dev/null @@ -1,92 +0,0 @@ -nextflow_process { - - name "Test Process MULTIQC" - script "../main.nf" - process "MULTIQC" - - tag "modules" - tag "modules_nfcore" - tag "multiqc" - - config "./nextflow.config" - - test("sarscov2 single-end [fastqc]") { - - when { - process { - """ - 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] = [] - input[4] = [] - input[5] = [] - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, - { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.versions).match("multiqc_versions_single") } - ) - } - - } - - test("sarscov2 single-end [fastqc] [config]") { - - when { - process { - """ - 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] = [] - input[4] = [] - input[5] = [] - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, - { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.versions).match("multiqc_versions_config") } - ) - } - } - - test("sarscov2 single-end [fastqc] - stub") { - - options "-stub" - - when { - process { - """ - 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] = [] - input[4] = [] - input[5] = [] - """ - } - } - - 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("multiqc_stub") } - ) - } - - } -} diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap deleted file mode 100644 index 2fcbb5ff..00000000 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ /dev/null @@ -1,41 +0,0 @@ -{ - "multiqc_versions_single": { - "content": [ - [ - "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-02T17:51:46.317523" - }, - "multiqc_stub": { - "content": [ - [ - "multiqc_report.html", - "multiqc_data", - "multiqc_plots", - "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-02T17:52:20.680978" - }, - "multiqc_versions_config": { - "content": [ - [ - "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-02T17:52:09.185842" - } -} \ No newline at end of file diff --git a/modules/nf-core/multiqc/tests/nextflow.config b/modules/nf-core/multiqc/tests/nextflow.config deleted file mode 100644 index c537a6a3..00000000 --- a/modules/nf-core/multiqc/tests/nextflow.config +++ /dev/null @@ -1,5 +0,0 @@ -process { - withName: 'MULTIQC' { - ext.prefix = null - } -} diff --git a/modules/nf-core/multiqc/tests/tags.yml b/modules/nf-core/multiqc/tests/tags.yml deleted file mode 100644 index bea6c0d3..00000000 --- a/modules/nf-core/multiqc/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -multiqc: - - modules/nf-core/multiqc/** From 1a94fb8b5f2fc4305a8fce073c3edf89019cb107 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Tue, 14 Jan 2025 17:31:39 +0100 Subject: [PATCH 57/70] Add local module and subworkflow tests --- .github/workflows/ci.yml | 114 +- .gitignore | 2 + conf/base.config | 1 - ...nfig => test_scsp_v1_immunology_v1.config} | 11 +- modules/local/collect_metadata/main.nf | 11 +- .../pixelator/single-cell/amplicon/main.nf | 2 +- .../single-cell/amplicon/tests/main.nf.test | 78 + .../amplicon/tests/main.nf.test.snap | 149 + .../single-cell/analysis/tests/main.nf.test | 76 + .../analysis/tests/main.nf.test.snap | 178 + .../pixelator/single-cell/annotate/main.nf | 3 +- .../single-cell/annotate/tests/main.nf.test | 83 + .../annotate/tests/main.nf.test.snap | 178 + .../single-cell/collapse/tests/main.nf.test | 86 + .../collapse/tests/main.nf.test.snap | 149 + .../local/pixelator/single-cell/demux/main.nf | 4 +- .../single-cell/demux/tests/main.nf.test | 80 + .../single-cell/demux/tests/main.nf.test.snap | 2875 +++++++++++++++++ .../local/pixelator/single-cell/graph/main.nf | 4 +- .../single-cell/graph/tests/main.nf.test | 70 + .../single-cell/graph/tests/main.nf.test.snap | 179 + .../pixelator/single-cell/layout/main.nf | 2 +- .../single-cell/layout/tests/main.nf.test | 82 + .../layout/tests/main.nf.test.snap | 178 + .../local/pixelator/single-cell/qc/main.nf | 18 +- .../single-cell/qc/tests/main.nf.test | 88 + .../single-cell/qc/tests/main.nf.test.snap | 395 +++ .../pixelator/single-cell/report/main.nf | 6 +- .../single-cell/report/tests/main.nf.test | 156 + .../report/tests/main.nf.test.snap | 76 + nextflow.config | 8 +- nf-test.config | 21 + .../main.nf} | 53 +- .../local/generate_reports/tests/main.nf.test | 200 ++ .../generate_reports/tests/main.nf.test.snap | 53 + tests/.nftignore | 2 + tests/default.nf.test | 62 + tests/default.nf.test.snap | 66 + tests/nextflow.config | 38 + tests/save_all.nf.test | 63 + tests/save_all.nf.test.snap | 185 ++ workflows/pixelator.nf | 2 +- 42 files changed, 6006 insertions(+), 81 deletions(-) rename conf/{test_mpx_scsp_v1.config => test_scsp_v1_immunology_v1.config} (80%) create mode 100644 modules/local/pixelator/single-cell/amplicon/tests/main.nf.test create mode 100644 modules/local/pixelator/single-cell/amplicon/tests/main.nf.test.snap create mode 100644 modules/local/pixelator/single-cell/analysis/tests/main.nf.test create mode 100644 modules/local/pixelator/single-cell/analysis/tests/main.nf.test.snap create mode 100644 modules/local/pixelator/single-cell/annotate/tests/main.nf.test create mode 100644 modules/local/pixelator/single-cell/annotate/tests/main.nf.test.snap create mode 100644 modules/local/pixelator/single-cell/collapse/tests/main.nf.test create mode 100644 modules/local/pixelator/single-cell/collapse/tests/main.nf.test.snap create mode 100644 modules/local/pixelator/single-cell/demux/tests/main.nf.test create mode 100644 modules/local/pixelator/single-cell/demux/tests/main.nf.test.snap create mode 100644 modules/local/pixelator/single-cell/graph/tests/main.nf.test create mode 100644 modules/local/pixelator/single-cell/graph/tests/main.nf.test.snap create mode 100644 modules/local/pixelator/single-cell/layout/tests/main.nf.test create mode 100644 modules/local/pixelator/single-cell/layout/tests/main.nf.test.snap create mode 100644 modules/local/pixelator/single-cell/qc/tests/main.nf.test create mode 100644 modules/local/pixelator/single-cell/qc/tests/main.nf.test.snap create mode 100644 modules/local/pixelator/single-cell/report/tests/main.nf.test create mode 100644 modules/local/pixelator/single-cell/report/tests/main.nf.test.snap create mode 100644 nf-test.config rename subworkflows/local/{generate_reports.nf => generate_reports/main.nf} (72%) create mode 100644 subworkflows/local/generate_reports/tests/main.nf.test create mode 100644 subworkflows/local/generate_reports/tests/main.nf.test.snap create mode 100644 tests/.nftignore create mode 100644 tests/default.nf.test create mode 100644 tests/default.nf.test.snap create mode 100644 tests/nextflow.config create mode 100644 tests/save_all.nf.test create mode 100644 tests/save_all.nf.test.snap diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1abe6193..99b5d84e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,14 +5,21 @@ on: branches: - dev pull_request: + paths-ignore: + - "docs/**" release: types: [published] workflow_dispatch: env: + NFT_DIFF: "pdiff" + NFT_DIFF_ARGS: "--line-numbers --width 120 --expand-tabs=2" + NFT_VER: "0.9.2" + NFT_WORKDIR: "~" NXF_ANSI_LOG: false NXF_SINGULARITY_CACHEDIR: ${{ github.workspace }}/.singularity NXF_SINGULARITY_LIBRARYDIR: ${{ github.workspace }}/.singularity + TEST_DATA_BASE: "${{ github.workspace }}/test-datasets" concurrency: group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}" @@ -20,39 +27,52 @@ concurrency: jobs: test: - name: "Run pipeline with test data (${{ matrix.NXF_VER }} | ${{ matrix.test_name }} | ${{ matrix.profile }})" - # Only run on push if this is the nf-core dev branch (merged PRs) - if: "${{ github.event_name != 'push' || (github.event_name == 'push' && github.repository == 'nf-core/pixelator') }}" runs-on: ubuntu-latest + name: "Test ${{ matrix.filter }} | ${{ matrix.profile }} | ${{ matrix.NXF_VER }} | ${{ matrix.shard }}/5" strategy: + fail-fast: false matrix: NXF_VER: - "24.04.2" - "latest-everything" - profile: - - "conda" - - "docker" - - "singularity" - test_name: - - "test" + filter: ["workflow", "function", "pipeline"] + profile: ["conda", "docker", "singularity"] + shard: [1, 2, 3, 4, 5] isMaster: - ${{ github.base_ref == 'master' }} - # Exclude conda and singularity on dev exclude: - isMaster: false profile: "conda" - isMaster: false profile: "singularity" + steps: - name: Check out pipeline code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 + with: + fetch-depth: 0 + + - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5 + with: + python-version: "3.11" + architecture: "x64" + + - uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4 + with: + distribution: "temurin" + java-version: "17" - name: Set up Nextflow uses: nf-core/setup-nextflow@v2 with: version: "${{ matrix.NXF_VER }}" - - name: Set up Apptainer + - name: Set up nf-test + uses: nf-core/setup-nf-test@v1 + with: + version: ${{ env.NFT_VER }} + + - name: Set up apptainer if: matrix.profile == 'singularity' uses: eWaterCycle/setup-apptainer@main @@ -62,7 +82,17 @@ jobs: mkdir -p $NXF_SINGULARITY_CACHEDIR mkdir -p $NXF_SINGULARITY_LIBRARYDIR - - name: Set up Miniconda + - name: Cache pdiff + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4 + id: cache-pip-pdiff + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-pdiff + + - name: Install pdiff + run: python -m pip install --upgrade pip pdiff cryptography + + - name: Set up miniconda if: matrix.profile == 'conda' uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3 with: @@ -77,9 +107,59 @@ jobs: echo $(realpath $CONDA)/condabin >> $GITHUB_PATH echo $(realpath python) >> $GITHUB_PATH - - name: Clean up Disk space - uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + - name: Disk space cleanup + uses: jlumbroso/free-disk-space@v1.3.1 + + - name: Start summary + id: print-test + run: | + echo "## nf-test tests summary :rocket:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "This \`${{ matrix.filter }}\` ${{ matrix.shard }}/5 shard was run on \`${{ matrix.profile }}\` | \`NXF_VER=${{ matrix.NXF_VER }}\`, and contains the following test(s):" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + nf-test test \ + --ci \ + --dryRun \ + --junitxml="TEST-${{ matrix.filter }}_${{ matrix.profile }}_${{ matrix.shard }}.xml" \ + --shard ${{ matrix.shard }}/5 \ + --changed-since HEAD^ \ + --follow-dependencies \ + --profile "+${{ matrix.profile }}" \ + --filter ${{ matrix.filter }} \ + | grep PASSED | cut -d "'" -f 2 | sed 's/^/- /' | sort -u >> $GITHUB_STEP_SUMMARY + + - name: "Run tests | ${{ matrix.filter }}_${{ matrix.profile }} | ${{ matrix.shard }}/5" + run: | + nf-test test \ + --ci \ + --debug \ + --verbose \ + --junitxml="TEST-${{ matrix.filter }}_${{ matrix.profile }}_${{ matrix.shard }}.xml" \ + --shard ${{ matrix.shard }}/5 \ + --changed-since HEAD^ \ + --follow-dependencies \ + --profile "+${{ matrix.profile }}" \ + --filter ${{ matrix.filter }} + + - name: Print success in summary + if: success() + run: | + echo "" >> $GITHUB_STEP_SUMMARY + echo "All test(s) successfull :tada:" >> $GITHUB_STEP_SUMMARY + + - name: Print failure in summary + if: failure() + run: | + echo "" >> $GITHUB_STEP_SUMMARY + echo "Some test(s) failed :cold_sweat:" >> $GITHUB_STEP_SUMMARY + + - name: Publish Test Report + uses: mikepenz/action-junit-report@v4 + if: success() || failure() # always run even if the previous step fails + with: + report_paths: "TEST-*.xml" - - name: "Run pipeline with test data ${{ matrix.NXF_VER }} | ${{ matrix.test_name }} | ${{ matrix.profile }}" + - name: Clean up + if: success() || failure() run: | - nextflow run ${GITHUB_WORKSPACE} -profile ${{ matrix.test_name }},${{ matrix.profile }} --outdir ./results + sudo rm -rf /home/ubuntu/tests/ diff --git a/.gitignore b/.gitignore index 6178afb7..2c8c13dc 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ testing* null/ .idea .vscode + +.nf-test* diff --git a/conf/base.config b/conf/base.config index b53faa52..0930b520 100644 --- a/conf/base.config +++ b/conf/base.config @@ -10,7 +10,6 @@ process { - // TODO nf-core: Check the defaults for all processes cpus = { 1 * task.attempt } memory = { 6.GB * task.attempt } time = { 4.h * task.attempt } diff --git a/conf/test_mpx_scsp_v1.config b/conf/test_scsp_v1_immunology_v1.config similarity index 80% rename from conf/test_mpx_scsp_v1.config rename to conf/test_scsp_v1_immunology_v1.config index fc339e4f..39b75d3d 100644 --- a/conf/test_mpx_scsp_v1.config +++ b/conf/test_scsp_v1_immunology_v1.config @@ -12,8 +12,6 @@ */ -aws.client.downloadParallel = true - process { resourceLimits = [ cpus: 4, @@ -24,12 +22,13 @@ process { params { config_profile_name = 'Test profile' - config_profile_description = 'Minimal test dataset to check pipeline function' + config_profile_description = 'Minimal test dataset to check pipeline function with MPX SCSP v1 | Immunology-I data' + + pipelines_testdata_base_path = "https://raw.githubusercontent.com/nf-core/test-datasets/" // Input data - // TODO: Add pixelator back here as the first dir - input = params.pipelines_testdata_base_path + 'samplesheet/samplesheet_mpx_scsp_v1.csv' - input_basedir = params.pipelines_testdata_base_path + '' + input = params.pipelines_testdata_base_path + 'pixelator/samplesheet/samplesheet_mpx_scsp_v1_immunology1.csv' + input_basedir = params.pipelines_testdata_base_path + 'pixelator' multiplet_recovery = true min_size = 1 diff --git a/modules/local/collect_metadata/main.nf b/modules/local/collect_metadata/main.nf index 412cf0bc..f4fddce2 100644 --- a/modules/local/collect_metadata/main.nf +++ b/modules/local/collect_metadata/main.nf @@ -69,14 +69,10 @@ process PIXELATOR_COLLECT_METADATA { """ echo '${nextflowJson}' > nextflow-metadata.json collect_metadata.py --process-name ${task.process} --workflow-data "nextflow-metadata.json" - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - collect_metadata.py: \$(echo \$(collect_metadata.py --version 2>/dev/null) | sed 's/collect-metadata //g' ) - END_VERSIONS """ - stub: + stub: + def nextflow_dict = [ version: workflow.nextflow.version, build: workflow.nextflow.build, @@ -131,7 +127,8 @@ process PIXELATOR_COLLECT_METADATA { cat <<-END_VERSIONS > versions.yml "${task.process}": - collect_metadata.py: \$(echo \$(collect_metadata.py --version 2>/dev/null) | sed 's/collect-metadata //g' ) + python: 3.11.4 + collect-metadata: 1.0.0 END_VERSIONS """ } diff --git a/modules/local/pixelator/single-cell/amplicon/main.nf b/modules/local/pixelator/single-cell/amplicon/main.nf index 28b4b2e0..79e74751 100644 --- a/modules/local/pixelator/single-cell/amplicon/main.nf +++ b/modules/local/pixelator/single-cell/amplicon/main.nf @@ -61,7 +61,7 @@ process PIXELATOR_AMPLICON { """ mkdir amplicon touch "${prefix}.pixelator-amplicon.log" - touch amplicon/${prefix}.merged.fq.gz + echo "" | gzip >> amplicon/${prefix}.merged.fq.gz touch amplicon/${prefix}.report.json touch amplicon/${prefix}.meta.json diff --git a/modules/local/pixelator/single-cell/amplicon/tests/main.nf.test b/modules/local/pixelator/single-cell/amplicon/tests/main.nf.test new file mode 100644 index 00000000..8f9f00d5 --- /dev/null +++ b/modules/local/pixelator/single-cell/amplicon/tests/main.nf.test @@ -0,0 +1,78 @@ +nextflow_process { + + name "Test Process PIXELATOR_AMPLICON" + script "../main.nf" + process "PIXELATOR_AMPLICON" + tag "modules" + tag "pixelator" + tag "pixelator/mpx" + tag "pixelator/single_cell_mpx_amplicon" + + + test("Test MPX amplicon - stub") { + + options "-stub" + + when { + params { + save_all = true + } + process { + """ + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/fastq/sample01_1k_pbmcs_scsp_v1_immunology1_R1.fastq.gz', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/fastq/sample01_1k_pbmcs_scsp_v1_immunology1_R2.fastq.gz', checkIfExists: true) + ] + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() }, + + ) + } + } + + test("Test MPX amplicon - SCSP v1 | Immunology-I") { + when { + params { + save_all = true + } + process { + """ + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/fastq/sample01_1k_pbmcs_scsp_v1_immunology1_R1.fastq.gz', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/fastq/sample01_1k_pbmcs_scsp_v1_immunology1_R2.fastq.gz', checkIfExists: true) + ] + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.merged, + process.out.report_json, + process.out.metadata + ).match() + }, + { + with (process.out.log) { + assert path(get(0).get(1)).readLines().last().contains("Finished pixelator amplicon") + } + }, + ) + } + } +} + diff --git a/modules/local/pixelator/single-cell/amplicon/tests/main.nf.test.snap b/modules/local/pixelator/single-cell/amplicon/tests/main.nf.test.snap new file mode 100644 index 00000000..343224d2 --- /dev/null +++ b/modules/local/pixelator/single-cell/amplicon/tests/main.nf.test.snap @@ -0,0 +1,149 @@ +{ + "Test MPX amplicon - SCSP v1 | Immunology-I": { + "content": [ + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.merged.fastq.gz:md5,b66b4946d695f8e2202e2018dcfd6a15" + ] + ], + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,5c15027e9dd0e441f8695a166817c9a5" + ] + ], + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,dc6b727f2af60706878f60522f4b5db8" + ] + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T13:50:23.37329316" + }, + "Test MPX amplicon - stub": { + "content": [ + { + "0": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.merged.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-amplicon.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + "versions.yml:md5,a9212d1f12a510a9aee9e75fe8271130" + ], + "log": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-amplicon.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "merged": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.merged.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "metadata": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "report_json": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,a9212d1f12a510a9aee9e75fe8271130" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T13:34:43.381527836" + } +} \ No newline at end of file diff --git a/modules/local/pixelator/single-cell/analysis/tests/main.nf.test b/modules/local/pixelator/single-cell/analysis/tests/main.nf.test new file mode 100644 index 00000000..bffb8e92 --- /dev/null +++ b/modules/local/pixelator/single-cell/analysis/tests/main.nf.test @@ -0,0 +1,76 @@ +nextflow_process { + + name "Test Process PIXELATOR_ANALYSIS" + script "../main.nf" + process "PIXELATOR_ANALYSIS" + tag "modules" + tag "pixelator" + tag "pixelator/mpx" + tag "pixelator/single_cell_mpx_analysis" + + + test("Test MPX analysis - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.annotate.dataset.pxl', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("Test MPX analysis - SCSP v1 | Immunology-I") { + when { + params { + save_all + } + process { + """ + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.annotate.dataset.pxl', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.report_json, + process.out.metadata + ).match() + }, + { + with (process.out.dataset.get(0)) { + assert path(get(1)).zip.extract("adata.h5ad").exists() + assert path(get(1)).zip.extract("edgelist.parquet").exists() + assert snapshot( + path(get(1)).zip.extract("metadata.json") + ).match("pxl") + } + }, + { + with (process.out.log) { + assert path(get(0).get(1)).readLines().last().contains("Finished pixelator analysis") + } + }, + ) + } + } +} + diff --git a/modules/local/pixelator/single-cell/analysis/tests/main.nf.test.snap b/modules/local/pixelator/single-cell/analysis/tests/main.nf.test.snap new file mode 100644 index 00000000..7c18aa4b --- /dev/null +++ b/modules/local/pixelator/single-cell/analysis/tests/main.nf.test.snap @@ -0,0 +1,178 @@ +{ + "Test MPX analysis - SCSP v1 | Immunology-I": { + "content": [ + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,5db6473f8c444276e3b287231fc87481" + ] + ], + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d716c80b935e110538316f432c3d1533" + ] + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T13:51:26.272946693" + }, + "pxl": { + "content": [ + "metadata.json:md5,f2fb857ccf3ee1b600c6903b7406444d" + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T13:51:26.337552389" + }, + "Test MPX analysis - stub": { + "content": [ + { + "0": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.dataset.pxl:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.dataset.pxl:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "4": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-analysis.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "5": [ + "versions.yml:md5,ad4e8730f9d912cff32b6bfc14fca5c3" + ], + "all_results": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.dataset.pxl:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "dataset": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.dataset.pxl:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-analysis.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "metadata": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "report_json": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,ad4e8730f9d912cff32b6bfc14fca5c3" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T13:50:33.066033773" + } +} \ No newline at end of file diff --git a/modules/local/pixelator/single-cell/annotate/main.nf b/modules/local/pixelator/single-cell/annotate/main.nf index aa6c10ba..5b21c63f 100644 --- a/modules/local/pixelator/single-cell/annotate/main.nf +++ b/modules/local/pixelator/single-cell/annotate/main.nf @@ -23,8 +23,7 @@ process PIXELATOR_ANNOTATE { task.ext.when == null || task.ext.when script: - - prefix = task.ext.prefix ?: "${meta.id}" + def prefix = task.ext.prefix ?: "${meta.id}" def args = task.ext.args ?: '' def panelOpt = ( panel ? "--panel $panel" : diff --git a/modules/local/pixelator/single-cell/annotate/tests/main.nf.test b/modules/local/pixelator/single-cell/annotate/tests/main.nf.test new file mode 100644 index 00000000..0e5cd5f0 --- /dev/null +++ b/modules/local/pixelator/single-cell/annotate/tests/main.nf.test @@ -0,0 +1,83 @@ +nextflow_process { + + name "Test Process PIXELATOR_ANNOTATE" + script "../main.nf" + process "PIXELATOR_ANNOTATE" + tag "modules" + tag "pixelator" + tag "pixelator/mpx" + tag "pixelator/single_cell_mpx_annotate" + + + test("Test MPX annotate - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/graph/sample01_1k_pbmcs_scsp_v1_immunology1.edgelist.parquet', checkIfExists: true), + [], + "human-sc-immunology-spatial-proteomics-1" + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() }, + + ) + } + } + + test("Test MPX annotate - SCSP v1 | Immunology-I") { + options "--save_all" + + when { + params { + save_all = true + } + process { + """ + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/graph/sample01_1k_pbmcs_scsp_v1_immunology1.edgelist.parquet', checkIfExists: true), + [], + "human-sc-immunology-spatial-proteomics-1" + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.report_json, + process.out.metadata + ).match() + }, + { + with (process.out.dataset.get(0)) { + assert path(get(1)).zip.extract("adata.h5ad").exists() + assert path(get(1)).zip.extract("edgelist.parquet").exists() + assert snapshot( + path(get(1)).zip.extract("metadata.json") + ).match("pxl") + } + }, + { + with (process.out.log) { + assert path(get(0).get(1)).readLines().last().contains("Finished pixelator annotate") + } + }, + ) + } + } +} + diff --git a/modules/local/pixelator/single-cell/annotate/tests/main.nf.test.snap b/modules/local/pixelator/single-cell/annotate/tests/main.nf.test.snap new file mode 100644 index 00000000..12e79b54 --- /dev/null +++ b/modules/local/pixelator/single-cell/annotate/tests/main.nf.test.snap @@ -0,0 +1,178 @@ +{ + "Test MPX annotate - SCSP v1 | Immunology-I": { + "content": [ + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,24c4e9dad0344dc099e76a41fe258882" + ] + ], + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,167ea8f99901e16236aa771e84886cc3" + ] + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T13:52:02.738078158" + }, + "pxl": { + "content": [ + "metadata.json:md5,5f73e696c17306072fb528d529165b5d" + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T13:52:02.762658591" + }, + "Test MPX annotate - stub": { + "content": [ + { + "0": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.dataset.pxl:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.dataset.pxl:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "4": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-annotate.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "5": [ + "versions.yml:md5,6bd537721b173686314a17aec8eecbb8" + ], + "all_results": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.dataset.pxl:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "dataset": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.dataset.pxl:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-annotate.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "metadata": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "report_json": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,6bd537721b173686314a17aec8eecbb8" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T13:51:36.347630055" + } +} \ No newline at end of file diff --git a/modules/local/pixelator/single-cell/collapse/tests/main.nf.test b/modules/local/pixelator/single-cell/collapse/tests/main.nf.test new file mode 100644 index 00000000..89a5cc94 --- /dev/null +++ b/modules/local/pixelator/single-cell/collapse/tests/main.nf.test @@ -0,0 +1,86 @@ +nextflow_process { + name "Test Process PIXELATOR_COLLAPSE" + script "../main.nf" + process "PIXELATOR_COLLAPSE" + tag "modules" + tag "pixelator" + tag "pixelator/mpx" + tag "pixelator/single_cell_mpx_collapse" + + + test("Test MPX collapse - stub") { + + options "-stub" + + when { + process { + """ + demuxed_input = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.processed-AAAGCAAC.fastq.gz', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.processed-AACAAGAC.fastq.gz', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.processed-AACCTTCC.fastq.gz', checkIfExists: true) + ] + + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel: "human-sc-immunology-spatial-proteomics-1", technology:'mpx' ], + demuxed_input, + [], + "human-sc-immunology-spatial-proteomics-1" + ] + input.dump() + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + + test("Test MPX collapse - - SCSP v1 | Immunology-I") { + when { + params { + save_all = true + } + process { + """ + demuxed_input = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.processed-AAAGCAAC.fastq.gz', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.processed-AACAAGAC.fastq.gz', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.processed-AACCTTCC.fastq.gz', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.processed-AACGGCTA.fastq.gz', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.processed-AAGCATAG.fastq.gz', checkIfExists: true), + ] + + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel: "human-sc-immunology-spatial-proteomics-1", technology:'mpx' ], + demuxed_input, + [], + "human-sc-immunology-spatial-proteomics-1" + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.collapsed, + process.out.report_json, + process.out.metadata + ).match() + }, + { + with (process.out.log) { + assert path(get(0).get(1)).readLines().last().contains("Finished pixelator collapse") + } + }, + ) + } + } +} diff --git a/modules/local/pixelator/single-cell/collapse/tests/main.nf.test.snap b/modules/local/pixelator/single-cell/collapse/tests/main.nf.test.snap new file mode 100644 index 00000000..ecffb684 --- /dev/null +++ b/modules/local/pixelator/single-cell/collapse/tests/main.nf.test.snap @@ -0,0 +1,149 @@ +{ + "Test MPX collapse - - SCSP v1 | Immunology-I": { + "content": [ + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.collapsed.parquet:md5,c92632a8e4866e6be9cc9a490362804a" + ] + ], + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,dd843f96bca3802fa558afefabf1864f" + ] + ], + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d0606874047996db5aa7da532c9d0624" + ] + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T16:07:43.798024301" + }, + "Test MPX collapse - stub": { + "content": [ + { + "0": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.collapsed.parquet:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-collapse.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + "versions.yml:md5,efd747c4e8243f4ec1cd38ea7873d137" + ], + "collapsed": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.collapsed.parquet:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-collapse.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "metadata": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "report_json": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,efd747c4e8243f4ec1cd38ea7873d137" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T13:52:13.085170439" + } +} \ No newline at end of file diff --git a/modules/local/pixelator/single-cell/demux/main.nf b/modules/local/pixelator/single-cell/demux/main.nf index 9719e93a..148a51d6 100644 --- a/modules/local/pixelator/single-cell/demux/main.nf +++ b/modules/local/pixelator/single-cell/demux/main.nf @@ -59,8 +59,8 @@ process PIXELATOR_DEMUX { touch "${prefix}.pixelator-demux.log" touch "demux/${prefix}.report.json" touch "demux/${prefix}.meta.json" - touch "demux/${prefix}.processed.fq.gz" - touch "demux/${prefix}.failed.fq.gz" + echo "" | gzip >> "demux/${prefix}.processed.fq.gz" + echo "" | gzip >> "demux/${prefix}.failed.fq.gz" cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/pixelator/single-cell/demux/tests/main.nf.test b/modules/local/pixelator/single-cell/demux/tests/main.nf.test new file mode 100644 index 00000000..2dfc5da9 --- /dev/null +++ b/modules/local/pixelator/single-cell/demux/tests/main.nf.test @@ -0,0 +1,80 @@ +nextflow_process { + + name "Test Process PIXELATOR_DEMUX" + script "../main.nf" + process "PIXELATOR_DEMUX" + tag "modules" + tag "pixelator" + tag "pixelator/mpx" + tag "pixelator/single_cell_mpx_demux" + + + test("Test MPX demux - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/adapterqc/sample01_1k_pbmcs_scsp_v1_immunology1.processed.fastq.gz', checkIfExists: true), + [], + "human-sc-immunology-spatial-proteomics-1" + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("Test MPX demux - SCSP v1 | Immunology-I") { + when { + params { + save_all = true + } + process { + """ + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/adapterqc/sample01_1k_pbmcs_scsp_v1_immunology1.processed.fastq.gz', checkIfExists: true), + [], + "human-sc-immunology-spatial-proteomics-1" + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.processed, + process.out.failed, + process.out.metadata, + process.out.versions + ).match() + }, + { + with (process.out.report_json) { + def data = path(get(0).get(1)).json + data.remove("command_line_arguments") + assert snapshot(data).match("report_json") + } + }, + { + with (process.out.log) { + assert path(get(0).get(1)).readLines().last().contains("Finished pixelator demux") + } + }, + ) + } + } +} + diff --git a/modules/local/pixelator/single-cell/demux/tests/main.nf.test.snap b/modules/local/pixelator/single-cell/demux/tests/main.nf.test.snap new file mode 100644 index 00000000..2d8ae752 --- /dev/null +++ b/modules/local/pixelator/single-cell/demux/tests/main.nf.test.snap @@ -0,0 +1,2875 @@ +{ + "Test MPX demux - stub": { + "content": [ + { + "0": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.processed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.failed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "2": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-demux.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "5": [ + "versions.yml:md5,45a1e09467ac109bf6e69b74c0daeb8c" + ], + "failed": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.failed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "log": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-demux.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "metadata": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "processed": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.processed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "report_json": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,45a1e09467ac109bf6e69b74c0daeb8c" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T16:07:56.483066923" + }, + "Test MPX demux - SCSP v1 | Immunology-I": { + "content": [ + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-AAAGCAAC.fastq.gz:md5,2be11ce9cafb75568f78085801253509", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-AACAAGAC.fastq.gz:md5,f9ff0b5eadf6e7bbd4c3d52fc5444d2b", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-AACCTTCC.fastq.gz:md5,1a652d8a86edee3ffc3e15051d74c29d", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-AACGGCTA.fastq.gz:md5,19d85529d3c3c9af112596d4594d8a0c", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-AAGCATAG.fastq.gz:md5,bfdc67d2dbc23f6919fbc3f838f44b75", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-AAGTAGCT.fastq.gz:md5,60adc5de820ca5683f318bb74e8f675b", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-AAGTCGTG.fastq.gz:md5,5d5df1c1dfec5f5105d2487f1c28a3b6", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-ACATTGAC.fastq.gz:md5,cb79e9b0810d1dd057feb4efe7083a39", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-ACCAGTAC.fastq.gz:md5,9e621a32529c72644949ae40baffda93", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-ACCTTGTG.fastq.gz:md5,345dc1bfd7c082bb108f3de96391aa85", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-ACTCGGAA.fastq.gz:md5,28ef340136eeda1ef9f4d50f90d61a6c", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-ACTCTCAC.fastq.gz:md5,8bd69299f5733228daa7a34c2c1a9746", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-ACTGTGTC.fastq.gz:md5,c9062dfb823417c51807e8bcaab5df83", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-AGAGGCTC.fastq.gz:md5,6f13d07767f5b5c40bba2860ecedf0df", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-AGCCCGAA.fastq.gz:md5,0fc734fe06b7463386768219235acdac", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-AGCTACTA.fastq.gz:md5,051e03ddcb55009c143f2618b9898b99", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-AGGATGTT.fastq.gz:md5,61b78cfbe10941d026949a903c901018", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-AGGGCAGT.fastq.gz:md5,b669fb56c5feb7ad8a1ad6921bd2fc93", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-AGTTATCG.fastq.gz:md5,dc52cc495bda419f1484f15d5a88512a", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-ATAGGGGA.fastq.gz:md5,e81bb2551be608cf28201e7e867299f0", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-ATGACTGC.fastq.gz:md5,f7331624948d7a4d80d9ec8ccbd9feae", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-ATTCGCCT.fastq.gz:md5,0d3549c1111a907f68019e72ac1a3c6e", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-ATTGGCAC.fastq.gz:md5,ef51ae01e3f4a0a40471f161a1d3ec72", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-ATTTCGAG.fastq.gz:md5,a5e8c0c4f1a94269721ea1403793be34", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CAATCGGC.fastq.gz:md5,87c72a995833444114bec2540d02a0c0", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CACACGGT.fastq.gz:md5,2e9412f0b2417f7bc9444a0df5bafa1d", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CACGTTTC.fastq.gz:md5,154ed56123e6f97b1b47afe0234f323f", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CAGATCCG.fastq.gz:md5,fb2f438c0d71b1758e26ab00978ff832", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CAGTCAGT.fastq.gz:md5,384093871acb5cadfbb685e5dca3e29f", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CATGGGCA.fastq.gz:md5,1c1c21f3e1bf5ae4dcc7b75e0b75aa82", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CCAGACAC.fastq.gz:md5,28043a27df2c133186deec31bc3b9921", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CCAGCATG.fastq.gz:md5,4937857331b3b26dcc82229b71b90553", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CCGATATC.fastq.gz:md5,007bfe6aaf6426bf9c4627492d21bf51", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CCTAAGAA.fastq.gz:md5,cc2260d540b98a984ee4d01188d72469", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CTACGACG.fastq.gz:md5,31972b1a0979e6f814e1075c80494b90", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CTACTCGC.fastq.gz:md5,5edd5bba357e95c6531008a4d21d9f09", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CTCAAGAG.fastq.gz:md5,7a442714b77ada1dbaca91663e1cc22a", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CTCAGATG.fastq.gz:md5,5818dd8b5061ab8efd166a9cf015525a", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CTGACCAT.fastq.gz:md5,d20fd12fc9eba7f7a4e4d249a35c7837", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CTGTAGGA.fastq.gz:md5,d11f9ec5e2510f3d839b4db9e71ea907", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CTTCTTGA.fastq.gz:md5,0d84ccdd28c879e0983838305db14f52", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-CTTGCACC.fastq.gz:md5,007a6e7eb4c1c3608bf8a3dddc5f75dc", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GAAAGTCA.fastq.gz:md5,ab497850624c21670bc7317dbd9865f4", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GAATCCCG.fastq.gz:md5,966f6167f29cec8cf2e728dd388dc0be", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GACCACTC.fastq.gz:md5,012ca430a152a70dc45b7659edfe7ef3", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GACTGGGA.fastq.gz:md5,35b1e7c1a78601222499e76f17e404ee", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GAGGTTAG.fastq.gz:md5,97ad07e025ecc4d5f08dd5b0d43c48bc", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GATAGGGT.fastq.gz:md5,edaebfd326ce12572125310d5b9922fa", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GATTGTGC.fastq.gz:md5,b9dab9f9ab1d927bbf5c05e55bba7d7b", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GCACTTAG.fastq.gz:md5,904c9d6755c56786cc4eb4643c9df32f", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GCATTCTG.fastq.gz:md5,5a801b02054823152a9770a766466c25", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GCCGGACG.fastq.gz:md5,442a9e2637a3baf80127036898ea9954", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GCGCAACT.fastq.gz:md5,7bf6d28e6c85086285a5e2d66fbd6501", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GCTATTGA.fastq.gz:md5,0a5bda017d3cbe48ccd676eff98b06f2", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GCTGAACC.fastq.gz:md5,4f558e3130feb29a20c49a8d22266e16", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GGAGCCAA.fastq.gz:md5,03dbfa1a69abf49f5e999e914451dc3c", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GGTTTACC.fastq.gz:md5,58e57f104c7ae0682520bf5c27f213e2", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GTAGGACC.fastq.gz:md5,bd09f8d96a13eb2fcc24e5d63ca2310c", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GTATCGGT.fastq.gz:md5,df197a9089593e7b11674d0455041323", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GTCTTTGT.fastq.gz:md5,787b3878efb07dcd491b4281aae789dd", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GTGAGTAG.fastq.gz:md5,4e326f4d7480808e47062d3e9be4afc7", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GTGCATTC.fastq.gz:md5,ad4e6c6f4b680740848cf28fe009a859", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GTTCAGAC.fastq.gz:md5,2c96d4d25bd7bf510666bd6cd54259a7", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-GTTGTCCG.fastq.gz:md5,4ef8830e94e4d081ec5b41684eda1f62", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TACTCTTG.fastq.gz:md5,0cff4ebf5b50e561bed196d2bdd9bfd3", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TATCCCTT.fastq.gz:md5,f86d88350696646d60dc2fb09c4c80a3", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TCAACGCT.fastq.gz:md5,13b947369a05597fc0a0c0dc2bc8ea7a", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TCAGGGTG.fastq.gz:md5,7a4a755b755cb27187739a133158388d", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TCCCAGTG.fastq.gz:md5,55f1975421e7b88439b6072f7c618ed1", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TCCCTTGC.fastq.gz:md5,a36866035e811f2256a421fc0a25996b", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TCCGTAAC.fastq.gz:md5,4370f3aa108b5e784038fb1674c56984", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TCGTAACG.fastq.gz:md5,319a9f3f45c486d8e6b7271038b8b28d", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TCTGCTCC.fastq.gz:md5,887869e93a80f350d242fe58585583e3", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TGATAGAA.fastq.gz:md5,892622cf98833b2e75c244735a66e4cf", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TGCATGTC.fastq.gz:md5,b0aa3857be96a576ff96b5a597fdb6ce", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TGGGGCTT.fastq.gz:md5,0e445cadab10b55e9a5e757b012dfc61", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TTCTGGGT.fastq.gz:md5,eddafbb008b1f85c9159b27f13da7165", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TTGTCCAA.fastq.gz:md5,5f5b97e5d6009da8e006031d00d48d9a", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TTTCTGGT.fastq.gz:md5,c8c9c588a76f247f69acdb0438fe8593", + "sample01_1k_pbmcs_scsp_v1_immunology1.processed-TTTGGAAG.fastq.gz:md5,7cd6c6c247032cdb063f69cb0bbcc2ad" + ] + ] + ], + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.failed.fastq.gz:md5,62b151206fd8ec15dd788e5a22474d1d" + ] + ], + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,e3cc30548a00bfb53e9e3474be0ee495" + ] + ], + [ + "versions.yml:md5,45a1e09467ac109bf6e69b74c0daeb8c" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T14:03:39.282659716" + }, + "report_json": { + "content": [ + { + "tag": "Cutadapt report", + "schema_version": [ + 0, + 3 + ], + "cutadapt_version": "4.9", + "python_version": "3.11.11", + "cores": 8, + "input": { + "path1": "sample01_1k_pbmcs_scsp_v1_immunology1.processed.fastq.gz", + "path2": null, + "paired": false + }, + "read_counts": { + "input": 99898, + "filtered": { + "too_short": null, + "too_long": null, + "too_many_n": null, + "too_many_expected_errors": null, + "casava_filtered": null, + "discard_trimmed": null, + "discard_untrimmed": 0 + }, + "output": 99898, + "reverse_complemented": null, + "read1_with_adapter": 99612, + "read2_with_adapter": null + }, + "basepair_counts": { + "input": 13186536, + "input_read1": 13186536, + "input_read2": null, + "quality_trimmed": null, + "quality_trimmed_read1": null, + "quality_trimmed_read2": null, + "poly_a_trimmed": null, + "poly_a_trimmed_read1": null, + "poly_a_trimmed_read2": null, + "output": 13186536, + "output_read1": 13186536, + "output_read2": null + }, + "adapters_read1": [ + { + "name": "B2M", + "total_matches": 10089, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CTGTAGGA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 10089, + "adjacent_bases": { + "A": 1530, + "C": 2674, + "G": 2778, + "T": 3107, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 10089 + ] + } + ] + } + }, + { + "name": "CD102", + "total_matches": 175, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TTTCTGGT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 175, + "adjacent_bases": { + "A": 51, + "C": 41, + "G": 55, + "T": 28, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 175 + ] + } + ] + } + }, + { + "name": "CD11a", + "total_matches": 4647, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "ACATTGAC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 4647, + "adjacent_bases": { + "A": 862, + "C": 863, + "G": 1130, + "T": 1792, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 4647 + ] + } + ] + } + }, + { + "name": "CD11b", + "total_matches": 7, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "ACTGTGTC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 7, + "adjacent_bases": { + "A": 0, + "C": 0, + "G": 4, + "T": 3, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 7 + ] + } + ] + } + }, + { + "name": "CD11c", + "total_matches": 47, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "AAGTCGTG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 47, + "adjacent_bases": { + "A": 19, + "C": 7, + "G": 14, + "T": 7, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 47 + ] + } + ] + } + }, + { + "name": "CD127", + "total_matches": 396, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TGATAGAA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 396, + "adjacent_bases": { + "A": 67, + "C": 99, + "G": 120, + "T": 110, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 396 + ] + } + ] + } + }, + { + "name": "CD137", + "total_matches": 4, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CCTAAGAA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 4, + "adjacent_bases": { + "A": 2, + "C": 0, + "G": 2, + "T": 0, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 4 + ] + } + ] + } + }, + { + "name": "CD14", + "total_matches": 70, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "AGAGGCTC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 70, + "adjacent_bases": { + "A": 20, + "C": 9, + "G": 32, + "T": 9, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 70 + ] + } + ] + } + }, + { + "name": "CD150", + "total_matches": 25, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CTTGCACC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 25, + "adjacent_bases": { + "A": 8, + "C": 0, + "G": 5, + "T": 12, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 25 + ] + } + ] + } + }, + { + "name": "CD152", + "total_matches": 39, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "AACGGCTA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 39, + "adjacent_bases": { + "A": 18, + "C": 2, + "G": 7, + "T": 12, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 39 + ] + } + ] + } + }, + { + "name": "CD154", + "total_matches": 4, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TGGGGCTT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 4, + "adjacent_bases": { + "A": 0, + "C": 1, + "G": 3, + "T": 0, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 4 + ] + } + ] + } + }, + { + "name": "CD158", + "total_matches": 12, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "ACTCGGAA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 12, + "adjacent_bases": { + "A": 1, + "C": 0, + "G": 10, + "T": 1, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 12 + ] + } + ] + } + }, + { + "name": "CD16", + "total_matches": 86, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GTGCATTC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 86, + "adjacent_bases": { + "A": 40, + "C": 8, + "G": 25, + "T": 13, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 86 + ] + } + ] + } + }, + { + "name": "CD161", + "total_matches": 26, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GTGAGTAG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 26, + "adjacent_bases": { + "A": 15, + "C": 5, + "G": 3, + "T": 3, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 26 + ] + } + ] + } + }, + { + "name": "CD162", + "total_matches": 77, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GCTATTGA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 77, + "adjacent_bases": { + "A": 32, + "C": 19, + "G": 12, + "T": 14, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 77 + ] + } + ] + } + }, + { + "name": "CD163", + "total_matches": 18, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CATGGGCA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 18, + "adjacent_bases": { + "A": 0, + "C": 11, + "G": 6, + "T": 1, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 18 + ] + } + ] + } + }, + { + "name": "CD18", + "total_matches": 959, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CACACGGT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 959, + "adjacent_bases": { + "A": 253, + "C": 209, + "G": 294, + "T": 203, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 959 + ] + } + ] + } + }, + { + "name": "CD19", + "total_matches": 173, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CTACGACG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 173, + "adjacent_bases": { + "A": 38, + "C": 49, + "G": 48, + "T": 38, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 173 + ] + } + ] + } + }, + { + "name": "CD197", + "total_matches": 543, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "AGGATGTT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 543, + "adjacent_bases": { + "A": 180, + "C": 97, + "G": 130, + "T": 136, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 543 + ] + } + ] + } + }, + { + "name": "CD1d", + "total_matches": 64, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TACTCTTG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 64, + "adjacent_bases": { + "A": 23, + "C": 13, + "G": 14, + "T": 14, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 64 + ] + } + ] + } + }, + { + "name": "CD2", + "total_matches": 1229, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CCGATATC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 1229, + "adjacent_bases": { + "A": 290, + "C": 283, + "G": 361, + "T": 295, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 1229 + ] + } + ] + } + }, + { + "name": "CD20", + "total_matches": 570, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GAATCCCG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 570, + "adjacent_bases": { + "A": 146, + "C": 116, + "G": 213, + "T": 95, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 570 + ] + } + ] + } + }, + { + "name": "CD200", + "total_matches": 35, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "AGGGCAGT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 35, + "adjacent_bases": { + "A": 21, + "C": 8, + "G": 4, + "T": 2, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 35 + ] + } + ] + } + }, + { + "name": "CD22", + "total_matches": 1505, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CTCAAGAG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 1505, + "adjacent_bases": { + "A": 381, + "C": 337, + "G": 482, + "T": 305, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 1505 + ] + } + ] + } + }, + { + "name": "CD229", + "total_matches": 156, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GTTCAGAC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 156, + "adjacent_bases": { + "A": 47, + "C": 44, + "G": 38, + "T": 27, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 156 + ] + } + ] + } + }, + { + "name": "CD244", + "total_matches": 37, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "AGCCCGAA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 37, + "adjacent_bases": { + "A": 0, + "C": 15, + "G": 12, + "T": 10, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 37 + ] + } + ] + } + }, + { + "name": "CD25", + "total_matches": 39, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GCCGGACG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 39, + "adjacent_bases": { + "A": 13, + "C": 1, + "G": 12, + "T": 13, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 39 + ] + } + ] + } + }, + { + "name": "CD26", + "total_matches": 943, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GTCTTTGT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 943, + "adjacent_bases": { + "A": 238, + "C": 183, + "G": 311, + "T": 211, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 943 + ] + } + ] + } + }, + { + "name": "CD268", + "total_matches": 164, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CACGTTTC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 164, + "adjacent_bases": { + "A": 52, + "C": 54, + "G": 46, + "T": 12, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 164 + ] + } + ] + } + }, + { + "name": "CD27", + "total_matches": 612, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GTTGTCCG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 612, + "adjacent_bases": { + "A": 152, + "C": 142, + "G": 121, + "T": 197, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 612 + ] + } + ] + } + }, + { + "name": "CD274", + "total_matches": 187, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TCCCTTGC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 187, + "adjacent_bases": { + "A": 52, + "C": 55, + "G": 39, + "T": 41, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 187 + ] + } + ] + } + }, + { + "name": "CD278", + "total_matches": 11, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "AAAGCAAC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 11, + "adjacent_bases": { + "A": 3, + "C": 5, + "G": 1, + "T": 2, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 11 + ] + } + ] + } + }, + { + "name": "CD279", + "total_matches": 18, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TTCTGGGT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 18, + "adjacent_bases": { + "A": 0, + "C": 8, + "G": 8, + "T": 2, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 18 + ] + } + ] + } + }, + { + "name": "CD29", + "total_matches": 580, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "ATTCGCCT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 580, + "adjacent_bases": { + "A": 109, + "C": 99, + "G": 182, + "T": 190, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 580 + ] + } + ] + } + }, + { + "name": "CD314", + "total_matches": 20, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CTTCTTGA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 20, + "adjacent_bases": { + "A": 7, + "C": 1, + "G": 11, + "T": 1, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 20 + ] + } + ] + } + }, + { + "name": "CD32", + "total_matches": 1547, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CAATCGGC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 1547, + "adjacent_bases": { + "A": 470, + "C": 284, + "G": 401, + "T": 392, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 1547 + ] + } + ] + } + }, + { + "name": "CD33", + "total_matches": 18, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TCCGTAAC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 18, + "adjacent_bases": { + "A": 8, + "C": 2, + "G": 8, + "T": 0, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 18 + ] + } + ] + } + }, + { + "name": "CD337", + "total_matches": 9, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TCCCAGTG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 9, + "adjacent_bases": { + "A": 1, + "C": 2, + "G": 6, + "T": 0, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 9 + ] + } + ] + } + }, + { + "name": "CD35", + "total_matches": 1455, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CCAGACAC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 1455, + "adjacent_bases": { + "A": 388, + "C": 285, + "G": 527, + "T": 255, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 1455 + ] + } + ] + } + }, + { + "name": "CD36", + "total_matches": 1483, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "ATTTCGAG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 1483, + "adjacent_bases": { + "A": 365, + "C": 385, + "G": 375, + "T": 358, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 1483 + ] + } + ] + } + }, + { + "name": "CD37", + "total_matches": 2492, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TTGTCCAA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 2492, + "adjacent_bases": { + "A": 1094, + "C": 304, + "G": 613, + "T": 481, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 2492 + ] + } + ] + } + }, + { + "name": "CD38", + "total_matches": 549, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TCAACGCT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 549, + "adjacent_bases": { + "A": 182, + "C": 133, + "G": 143, + "T": 91, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 549 + ] + } + ] + } + }, + { + "name": "CD3E", + "total_matches": 517, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "AGCTACTA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 517, + "adjacent_bases": { + "A": 134, + "C": 90, + "G": 151, + "T": 142, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 517 + ] + } + ] + } + }, + { + "name": "CD4", + "total_matches": 648, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CTGACCAT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 648, + "adjacent_bases": { + "A": 183, + "C": 126, + "G": 177, + "T": 162, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 648 + ] + } + ] + } + }, + { + "name": "CD40", + "total_matches": 441, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TCAGGGTG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 441, + "adjacent_bases": { + "A": 123, + "C": 76, + "G": 99, + "T": 143, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 441 + ] + } + ] + } + }, + { + "name": "CD41", + "total_matches": 2530, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "AACAAGAC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 2530, + "adjacent_bases": { + "A": 582, + "C": 522, + "G": 594, + "T": 832, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 2530 + ] + } + ] + } + }, + { + "name": "CD43", + "total_matches": 177, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GTAGGACC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 177, + "adjacent_bases": { + "A": 54, + "C": 36, + "G": 50, + "T": 37, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 177 + ] + } + ] + } + }, + { + "name": "CD44", + "total_matches": 1655, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TATCCCTT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 1655, + "adjacent_bases": { + "A": 393, + "C": 303, + "G": 475, + "T": 484, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 1655 + ] + } + ] + } + }, + { + "name": "CD45", + "total_matches": 11108, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "ATAGGGGA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 11108, + "adjacent_bases": { + "A": 3348, + "C": 2450, + "G": 2868, + "T": 2442, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 11108 + ] + } + ] + } + }, + { + "name": "CD45RA", + "total_matches": 1285, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GGAGCCAA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 1285, + "adjacent_bases": { + "A": 363, + "C": 232, + "G": 418, + "T": 272, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 1285 + ] + } + ] + } + }, + { + "name": "CD45RB", + "total_matches": 559, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GCATTCTG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 559, + "adjacent_bases": { + "A": 142, + "C": 99, + "G": 177, + "T": 141, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 559 + ] + } + ] + } + }, + { + "name": "CD47", + "total_matches": 1206, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GATAGGGT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 1206, + "adjacent_bases": { + "A": 419, + "C": 251, + "G": 313, + "T": 223, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 1206 + ] + } + ] + } + }, + { + "name": "CD48", + "total_matches": 263, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GACCACTC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 263, + "adjacent_bases": { + "A": 79, + "C": 59, + "G": 68, + "T": 57, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 263 + ] + } + ] + } + }, + { + "name": "CD49D", + "total_matches": 186, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "ACCTTGTG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 186, + "adjacent_bases": { + "A": 54, + "C": 36, + "G": 61, + "T": 35, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 186 + ] + } + ] + } + }, + { + "name": "CD5", + "total_matches": 509, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CAGATCCG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 509, + "adjacent_bases": { + "A": 115, + "C": 165, + "G": 138, + "T": 91, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 509 + ] + } + ] + } + }, + { + "name": "CD50", + "total_matches": 162, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "ACTCTCAC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 162, + "adjacent_bases": { + "A": 50, + "C": 37, + "G": 42, + "T": 33, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 162 + ] + } + ] + } + }, + { + "name": "CD52", + "total_matches": 321, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GACTGGGA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 321, + "adjacent_bases": { + "A": 84, + "C": 50, + "G": 80, + "T": 107, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 321 + ] + } + ] + } + }, + { + "name": "CD53", + "total_matches": 149, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TGCATGTC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 149, + "adjacent_bases": { + "A": 36, + "C": 37, + "G": 32, + "T": 44, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 149 + ] + } + ] + } + }, + { + "name": "CD54", + "total_matches": 1306, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GAAAGTCA", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 1306, + "adjacent_bases": { + "A": 388, + "C": 284, + "G": 357, + "T": 277, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 1306 + ] + } + ] + } + }, + { + "name": "CD55", + "total_matches": 362, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CAGTCAGT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 362, + "adjacent_bases": { + "A": 142, + "C": 58, + "G": 78, + "T": 84, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 362 + ] + } + ] + } + }, + { + "name": "CD59", + "total_matches": 1091, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GAGGTTAG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 1091, + "adjacent_bases": { + "A": 341, + "C": 207, + "G": 253, + "T": 290, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 1091 + ] + } + ] + } + }, + { + "name": "CD62P", + "total_matches": 22, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "ATGACTGC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 22, + "adjacent_bases": { + "A": 3, + "C": 11, + "G": 8, + "T": 0, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 22 + ] + } + ] + } + }, + { + "name": "CD64", + "total_matches": 31, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GCTGAACC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 31, + "adjacent_bases": { + "A": 10, + "C": 9, + "G": 9, + "T": 3, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 31 + ] + } + ] + } + }, + { + "name": "CD69", + "total_matches": 138, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "AAGCATAG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 138, + "adjacent_bases": { + "A": 42, + "C": 29, + "G": 39, + "T": 28, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 138 + ] + } + ] + } + }, + { + "name": "CD7", + "total_matches": 1071, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GATTGTGC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 1071, + "adjacent_bases": { + "A": 317, + "C": 235, + "G": 281, + "T": 238, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 1071 + ] + } + ] + } + }, + { + "name": "CD71", + "total_matches": 29, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GCACTTAG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 29, + "adjacent_bases": { + "A": 9, + "C": 4, + "G": 8, + "T": 8, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 29 + ] + } + ] + } + }, + { + "name": "CD72", + "total_matches": 1351, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GGTTTACC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 1351, + "adjacent_bases": { + "A": 394, + "C": 304, + "G": 359, + "T": 294, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 1351 + ] + } + ] + } + }, + { + "name": "CD8", + "total_matches": 3632, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CTCAGATG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 3632, + "adjacent_bases": { + "A": 1021, + "C": 664, + "G": 957, + "T": 990, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 3632 + ] + } + ] + } + }, + { + "name": "CD82", + "total_matches": 749, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "AACCTTCC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 749, + "adjacent_bases": { + "A": 208, + "C": 115, + "G": 241, + "T": 185, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 749 + ] + } + ] + } + }, + { + "name": "CD84", + "total_matches": 108, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "AGTTATCG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 108, + "adjacent_bases": { + "A": 35, + "C": 22, + "G": 21, + "T": 30, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 108 + ] + } + ] + } + }, + { + "name": "CD86", + "total_matches": 269, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TCTGCTCC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 269, + "adjacent_bases": { + "A": 75, + "C": 49, + "G": 86, + "T": 59, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 269 + ] + } + ] + } + }, + { + "name": "CD9", + "total_matches": 28, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "ACCAGTAC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 28, + "adjacent_bases": { + "A": 10, + "C": 7, + "G": 8, + "T": 3, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 28 + ] + } + ] + } + }, + { + "name": "HLA-ABC", + "total_matches": 31124, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "ATTGGCAC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 31124, + "adjacent_bases": { + "A": 6847, + "C": 7665, + "G": 6833, + "T": 9779, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 31124 + ] + } + ] + } + }, + { + "name": "HLA-DR", + "total_matches": 5119, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CCAGCATG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 5119, + "adjacent_bases": { + "A": 1562, + "C": 894, + "G": 1738, + "T": 925, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 5119 + ] + } + ] + } + }, + { + "name": "CD328", + "total_matches": 43, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "AAGTAGCT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 43, + "adjacent_bases": { + "A": 14, + "C": 12, + "G": 8, + "T": 9, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 43 + ] + } + ] + } + }, + { + "name": "TCRVb5", + "total_matches": 114, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GCGCAACT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 114, + "adjacent_bases": { + "A": 28, + "C": 15, + "G": 28, + "T": 43, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 114 + ] + } + ] + } + }, + { + "name": "ACTB", + "total_matches": 15, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TCGTAACG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 15, + "adjacent_bases": { + "A": 1, + "C": 7, + "G": 3, + "T": 4, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 15 + ] + } + ] + } + }, + { + "name": "mIgG1", + "total_matches": 20, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "TTTGGAAG", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 20, + "adjacent_bases": { + "A": 6, + "C": 1, + "G": 3, + "T": 10, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 20 + ] + } + ] + } + }, + { + "name": "mIgG2a", + "total_matches": 134, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "CTACTCGC", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 134, + "adjacent_bases": { + "A": 38, + "C": 6, + "G": 57, + "T": 33, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 134 + ] + } + ] + } + }, + { + "name": "mIgG2b", + "total_matches": 20, + "on_reverse_complement": null, + "linked": false, + "five_prime_end": null, + "three_prime_end": { + "type": "anchored_three_prime", + "sequence": "GTATCGGT", + "error_rate": 0.1, + "indels": false, + "error_lengths": null, + "matches": 20, + "adjacent_bases": { + "A": 3, + "C": 4, + "G": 1, + "T": 12, + "": 0 + }, + "dominant_adjacent_base": null, + "trimmed_lengths": [ + { + "len": 8, + "expect": 1.5, + "counts": [ + 20 + ] + } + ] + } + } + ], + "adapters_read2": null, + "poly_a_trimmed_read1": null, + "poly_a_trimmed_read2": null, + "sample_id": "sample01_1k_pbmcs_scsp_v1_immunology1" + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T14:03:39.782385981" + } +} \ No newline at end of file diff --git a/modules/local/pixelator/single-cell/graph/main.nf b/modules/local/pixelator/single-cell/graph/main.nf index d0f18f8f..324caef5 100644 --- a/modules/local/pixelator/single-cell/graph/main.nf +++ b/modules/local/pixelator/single-cell/graph/main.nf @@ -11,9 +11,9 @@ process PIXELATOR_GRAPH { tuple val(meta), path(edge_list) output: - tuple val(meta), path("graph/*.edgelist.parquet") , emit: edgelist + tuple val(meta), path("graph/*.edgelist.parquet") , emit: edgelist tuple val(meta), path("graph/*.report.json") , emit: report_json - tuple val(meta), path("graph/*.meta.json") , emit: input_params + tuple val(meta), path("graph/*.meta.json") , emit: metadata tuple val(meta), path("graph/*") , emit: all_results tuple val(meta), path("*pixelator-graph.log") , emit: log diff --git a/modules/local/pixelator/single-cell/graph/tests/main.nf.test b/modules/local/pixelator/single-cell/graph/tests/main.nf.test new file mode 100644 index 00000000..ca0eca80 --- /dev/null +++ b/modules/local/pixelator/single-cell/graph/tests/main.nf.test @@ -0,0 +1,70 @@ +nextflow_process { + + name "Test Process PIXELATOR_GRAPH" + script "../main.nf" + process "PIXELATOR_GRAPH" + tag "modules" + tag "pixelator" + tag "pixelator/mpx" + tag "pixelator/single_cell_mpx_graph" + + + test("Test MPX graph - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/collapse/sample01_1k_pbmcs_scsp_v1_immunology1.collapsed.parquet', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() }, + + ) + } + } + + test("Test MPX graph - SCSP v1 | Immunology-I") { + + when { + params { + save_all = true + } + process { + """ + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/collapse/sample01_1k_pbmcs_scsp_v1_immunology1.collapsed.parquet', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.edgelist, + process.out.report_json, + process.out.metadata + ).match() + }, + { + with (process.out.log) { + assert path(get(0).get(1)).readLines().last().contains("Finished pixelator graph") + } + }, + ) + } + } +} + diff --git a/modules/local/pixelator/single-cell/graph/tests/main.nf.test.snap b/modules/local/pixelator/single-cell/graph/tests/main.nf.test.snap new file mode 100644 index 00000000..7259fed1 --- /dev/null +++ b/modules/local/pixelator/single-cell/graph/tests/main.nf.test.snap @@ -0,0 +1,179 @@ +{ + "Test MPX graph - SCSP v1 | Immunology-I": { + "content": [ + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.edgelist.parquet:md5,c0fa82f95565a5ba7434e2e7c90a5ba6" + ] + ], + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,42f85a10b4bda24de42f293d485e806e" + ] + ], + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,25008fee7d821a33f38bdc85b709675a" + ] + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T16:08:54.607474562" + }, + "Test MPX graph - stub": { + "content": [ + { + "0": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.edgelist.parquet:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.edgelist.parquet:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "4": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-graph.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "5": [ + "versions.yml:md5,aa2a2d45cb57ed64e1fad6c83a1bc77e" + ], + "all_results": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.edgelist.parquet:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "edgelist": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.edgelist.parquet:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-graph.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "metadata": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "report_json": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,aa2a2d45cb57ed64e1fad6c83a1bc77e" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T13:52:47.782033516" + } +} \ No newline at end of file diff --git a/modules/local/pixelator/single-cell/layout/main.nf b/modules/local/pixelator/single-cell/layout/main.nf index ad0c3d40..e7042b84 100644 --- a/modules/local/pixelator/single-cell/layout/main.nf +++ b/modules/local/pixelator/single-cell/layout/main.nf @@ -50,7 +50,7 @@ process PIXELATOR_LAYOUT { """ mkdir layout touch "${prefix}.pixelator-layout.log" - touch "layout/${prefix}.dataset.pxl" + touch "layout/${prefix}.layout.dataset.pxl" touch "layout/${prefix}.report.json" touch "layout/${prefix}.meta.json" diff --git a/modules/local/pixelator/single-cell/layout/tests/main.nf.test b/modules/local/pixelator/single-cell/layout/tests/main.nf.test new file mode 100644 index 00000000..6f90834c --- /dev/null +++ b/modules/local/pixelator/single-cell/layout/tests/main.nf.test @@ -0,0 +1,82 @@ +nextflow_process { + + name "Test Process PIXELATOR_LAYOUT" + script "../main.nf" + process "PIXELATOR_LAYOUT" + tag "modules" + tag "pixelator" + tag "pixelator/mpx" + tag "pixelator/single_cell_mpx_layout" + + + test("Test MPX layout - stub") { + + options "-stub" + + when { + params { + layout_algorithm = "fruchterman_reingold_3d" + skip_layout = false + } + process { + """ + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design: 'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/analysis/sample01_1k_pbmcs_scsp_v1_immunology1.analysis.dataset.pxl', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("Test MPX layout - SCSP v1 | Immunology-I") { + when { + params { + save_all = true + layout_algorithm = "fruchterman_reingold_3d" + skip_layout = false + } + process { + """ + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design: 'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/analysis/sample01_1k_pbmcs_scsp_v1_immunology1.analysis.dataset.pxl', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.report_json, + process.out.metadata + ).match() + }, + { + with (process.out.dataset.get(0)) { + assert path(get(1)).zip.extract("adata.h5ad").exists() + assert path(get(1)).zip.extract("edgelist.parquet").exists() + assert snapshot( + path(get(1)).zip.extract("metadata.json") + ).match("pxl") + } + }, + { + with (process.out.log) { + assert path(get(0).get(1)).readLines().last().contains("Finished pixelator layout") + } + }, + ) + } + } +} + diff --git a/modules/local/pixelator/single-cell/layout/tests/main.nf.test.snap b/modules/local/pixelator/single-cell/layout/tests/main.nf.test.snap new file mode 100644 index 00000000..5d1b24ee --- /dev/null +++ b/modules/local/pixelator/single-cell/layout/tests/main.nf.test.snap @@ -0,0 +1,178 @@ +{ + "pxl": { + "content": [ + "metadata.json:md5,f2fb857ccf3ee1b600c6903b7406444d" + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T13:53:40.923684802" + }, + "Test MPX layout - SCSP v1 | Immunology-I": { + "content": [ + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,479afd25dcacc45540d81d1d8b7b5346" + ] + ], + [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,64e167effed9d3160c1d9f2964538c2a" + ] + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T13:53:40.903975567" + }, + "Test MPX layout - stub": { + "content": [ + { + "0": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.layout.dataset.pxl:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.layout.dataset.pxl:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "4": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-layout.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "5": [ + "versions.yml:md5,a6eae3a2fec653d9668e392abeafe825" + ], + "all_results": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.layout.dataset.pxl:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "dataset": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.layout.dataset.pxl:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "log": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-layout.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "metadata": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "report_json": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,a6eae3a2fec653d9668e392abeafe825" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T13:53:18.727581453" + } +} \ No newline at end of file diff --git a/modules/local/pixelator/single-cell/qc/main.nf b/modules/local/pixelator/single-cell/qc/main.nf index 0aca8a8c..fc439c9d 100644 --- a/modules/local/pixelator/single-cell/qc/main.nf +++ b/modules/local/pixelator/single-cell/qc/main.nf @@ -30,6 +30,8 @@ process PIXELATOR_QC { tuple val(meta), path("preqc/*.meta.json") , emit: preqc_metadata tuple val(meta), path("{adapterqc,preqc}/*.meta.json") , emit: metadata + tuple val(meta), path("*pixelator-preqc.log") , emit: preqc_log + tuple val(meta), path("*pixelator-adapterqc.log") , emit: adapterqc_log tuple val(meta), path("*pixelator-*.log") , emit: log path "versions.yml" , emit: versions @@ -38,9 +40,9 @@ process PIXELATOR_QC { task.ext.when == null || task.ext.when script: - assert meta.design + assert meta.design : "Missing `design` field in meta map" - prefix = task.ext.prefix ?: "${meta.id}" + def prefix = task.ext.prefix ?: "${meta.id}" def preqc_args = task.ext.args ?: '' def adapterqc_args = task.ext.args2 ?: '' @@ -48,7 +50,7 @@ process PIXELATOR_QC { """ pixelator \\ --cores $task.cpus \\ - --log-file ${prefix}.pixelator-qc.log \\ + --log-file ${prefix}.pixelator-preqc.log \\ --verbose \\ single-cell \\ preqc \\ @@ -63,7 +65,7 @@ process PIXELATOR_QC { pixelator \\ --cores $task.cpus \\ - --log-file ${prefix}.pixelator-qc.log \\ + --log-file ${prefix}.pixelator-adapterqc.log \\ --verbose \\ single-cell \\ adapterqc \\ @@ -82,16 +84,16 @@ process PIXELATOR_QC { """ mkdir preqc - touch "preqc/${prefix}.processed.fq.gz" - touch "preqc/${prefix}.failed.fq.gz" + echo "" | gzip >> "preqc/${prefix}.processed.fq.gz" + echo "" | gzip >> "preqc/${prefix}.failed.fq.gz" touch "preqc/${prefix}.report.json" touch "preqc/${prefix}.meta.json" touch "preqc/${prefix}.qc-report.html" touch "${prefix}.pixelator-preqc.log" mkdir adapterqc - touch "adapterqc/${prefix}.processed.fq.gz" - touch "adapterqc/${prefix}.failed.fq.gz" + echo "" | gzip >> "adapterqc/${prefix}.processed.fq.gz" + echo "" | gzip >> "adapterqc/${prefix}.failed.fq.gz" touch "adapterqc/${prefix}.report.json" touch "adapterqc/${prefix}.meta.json" touch "${prefix}.pixelator-adapterqc.log" diff --git a/modules/local/pixelator/single-cell/qc/tests/main.nf.test b/modules/local/pixelator/single-cell/qc/tests/main.nf.test new file mode 100644 index 00000000..439ff91e --- /dev/null +++ b/modules/local/pixelator/single-cell/qc/tests/main.nf.test @@ -0,0 +1,88 @@ +nextflow_process { + + name "Test Process PIXELATOR_QC" + script "../main.nf" + process "PIXELATOR_QC" + tag "modules" + tag "pixelator" + tag "pixelator/mpx" + tag "pixelator/single_cell_mpx_qc" + + + test("Test MPX qc - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/amplicon/sample01_1k_pbmcs_scsp_v1_immunology1.merged.fastq.gz', checkIfExists: true), + ] + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("Test MPX qc - SCSP v1 | Immunology-I") { + when { + params { + save_all = true + } + process { + """ + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/amplicon/sample01_1k_pbmcs_scsp_v1_immunology1.merged.fastq.gz', checkIfExists: true), + ] + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.adapterqc_processed, + process.out.preqc_processed, + process.out.adapterqc_failed, + process.out.preqc_failed, + process.out.adapterqc_report_json, + process.out.preqc_report_json, + process.out.adapterqc_metadata, + process.out.preqc_metadata, + process.out.versions + ) + }, + { + with(process.out.preqc_report_html) { + assert path(get(0).get(1)).exists() + } + }, + { + with (process.out.preqc_log) { + assert path(get(0).get(1)).readLines().any { it.contains("Finished pixelator preqc") } + } + }, + { + with (process.out.adapterqc_log) { + assert path(get(0).get(1)).readLines().any { it.contains("Finished pixelator adapterqc") } + } + }, + ) + } + } +} + diff --git a/modules/local/pixelator/single-cell/qc/tests/main.nf.test.snap b/modules/local/pixelator/single-cell/qc/tests/main.nf.test.snap new file mode 100644 index 00000000..90c13539 --- /dev/null +++ b/modules/local/pixelator/single-cell/qc/tests/main.nf.test.snap @@ -0,0 +1,395 @@ +{ + "Test MPX qc - stub": { + "content": [ + { + "0": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.processed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.processed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "10": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "11": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "12": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "13": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-preqc.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "14": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-adapterqc.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "15": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-adapterqc.log:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-preqc.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "16": [ + "versions.yml:md5,3d671a9296c6c0dc792641a15a34c92a" + ], + "2": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.processed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "3": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.failed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "4": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.failed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "5": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.failed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "sample01_1k_pbmcs_scsp_v1_immunology1.failed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "6": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "7": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "8": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "9": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.qc-report.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "adapterqc_failed": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.failed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "adapterqc_log": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-adapterqc.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "adapterqc_metadata": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "adapterqc_processed": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.processed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "adapterqc_report_json": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "failed": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.failed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "sample01_1k_pbmcs_scsp_v1_immunology1.failed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "log": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-adapterqc.log:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-preqc.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "metadata": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "preqc_failed": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.failed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "preqc_log": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-preqc.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "preqc_metadata": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.meta.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "preqc_processed": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.processed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "preqc_report_html": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.qc-report.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "preqc_report_json": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "processed": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.processed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "report_json": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + [ + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "sample01_1k_pbmcs_scsp_v1_immunology1.report.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions": [ + "versions.yml:md5,3d671a9296c6c0dc792641a15a34c92a" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T13:37:20.1784758" + } +} \ No newline at end of file diff --git a/modules/local/pixelator/single-cell/report/main.nf b/modules/local/pixelator/single-cell/report/main.nf index 5526f981..f04c654f 100644 --- a/modules/local/pixelator/single-cell/report/main.nf +++ b/modules/local/pixelator/single-cell/report/main.nf @@ -21,9 +21,9 @@ process PIXELATOR_REPORT { output: - path "report/*.html" , emit: reports - path "versions.yml" , emit: versions - path "*pixelator-*.log" , emit: log + tuple val(meta), path("report/*.html") , emit: reports + tuple val(meta), path("*pixelator-*.log") , emit: log + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/pixelator/single-cell/report/tests/main.nf.test b/modules/local/pixelator/single-cell/report/tests/main.nf.test new file mode 100644 index 00000000..6540d59e --- /dev/null +++ b/modules/local/pixelator/single-cell/report/tests/main.nf.test @@ -0,0 +1,156 @@ +nextflow_process { + + name "Test Process PIXELATOR_REPORT" + script "../main.nf" + process "PIXELATOR_REPORT" + tag "modules" + tag "pixelator" + tag "pixelator/mpx" + tag "pixelator/single_cell_mpx_report" + + test("Test MPX report - stub") { + + options "-stub" + + when { + process { + """ + def meta = + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + [], + "human-sc-immunology-spatial-proteomics-1" + ] + + input[1] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/amplicon/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/amplicon/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + input[2] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/preqc/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/preqc/sample01_1k_pbmcs_scsp_v1_immunology1.processed.fastq.gz', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/preqc/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + input[3] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/adapterqc/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/adapterqc/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + input[4] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + input[5] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/collapse/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/collapse/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + input[6] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/graph/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/graph/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/graph/sample01_1k_pbmcs_scsp_v1_immunology1.edgelist.parquet', checkIfExists: true), + ] + input[7] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.annotate.dataset.pxl', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.raw_components_metrics.csv.gz', checkIfExists: true), + ] + input[8] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/analysis/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/analysis/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/analysis/sample01_1k_pbmcs_scsp_v1_immunology1.analysis.dataset.pxl', checkIfExists: true), + ] + input[9] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/layout/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/layout/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/layout/sample01_1k_pbmcs_scsp_v1_immunology1.layout.dataset.pxl', checkIfExists: true), + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("Test MPX report - SCSP v1 | Immunology-I") { + when { + params { + save_all = true + } + process { + """ + def meta = + input[0] = [ + [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ], + [], + "human-sc-immunology-spatial-proteomics-1" + ] + + input[1] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/amplicon/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/amplicon/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + input[2] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/preqc/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/preqc/sample01_1k_pbmcs_scsp_v1_immunology1.processed.fastq.gz', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/preqc/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + input[3] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/adapterqc/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/adapterqc/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + input[4] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + input[5] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/collapse/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/collapse/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + input[6] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/graph/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/graph/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/graph/sample01_1k_pbmcs_scsp_v1_immunology1.edgelist.parquet', checkIfExists: true), + ] + input[7] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.annotate.dataset.pxl', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.raw_components_metrics.csv.gz', checkIfExists: true), + ] + input[8] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/analysis/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/analysis/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/analysis/sample01_1k_pbmcs_scsp_v1_immunology1.analysis.dataset.pxl', checkIfExists: true), + ] + input[9] = [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/layout/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/layout/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/layout/sample01_1k_pbmcs_scsp_v1_immunology1.layout.dataset.pxl', checkIfExists: true), + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.report, + process.out.versions + ).match() + }, + { + with (process.out.log) { + assert path(get(0).get(1)).readLines().any { it.contains("Finished pixelator report") } + } + } + ) + } + } +} + diff --git a/modules/local/pixelator/single-cell/report/tests/main.nf.test.snap b/modules/local/pixelator/single-cell/report/tests/main.nf.test.snap new file mode 100644 index 00000000..56d8355b --- /dev/null +++ b/modules/local/pixelator/single-cell/report/tests/main.nf.test.snap @@ -0,0 +1,76 @@ +{ + "Test MPX report - stub": { + "content": [ + { + "0": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-report.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,0d62eaeda0bec01691c5c930041a62f0" + ], + "log": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.pixelator-report.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "reports": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,0d62eaeda0bec01691c5c930041a62f0" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T16:10:14.235399369" + }, + "Test MPX report - SCSP v1 | Immunology-I": { + "content": [ + null, + [ + "versions.yml:md5,0d62eaeda0bec01691c5c930041a62f0" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T14:34:03.329015243" + } +} \ No newline at end of file diff --git a/nextflow.config b/nextflow.config index e962be53..62cd71ce 100644 --- a/nextflow.config +++ b/nextflow.config @@ -236,10 +236,10 @@ profiles { ] } } - test { includeConfig 'conf/test.config' } - test_mpx_scsp_v1 { includeConfig 'conf/test_mpx_scsp_v1.config' } - test_panel_v2 { includeConfig 'conf/test_panel_v2.config' } - test_full { includeConfig 'conf/test_full.config' } + test { includeConfig 'conf/test.config' } + test_full { includeConfig 'conf/test_full.config' } + test_panel_v2 { includeConfig 'conf/test_panel_v2.config' } + test_scsp_v1_immunology_v1 { includeConfig 'conf/test_scsp_v1_immunology_v1.config' } } // Load nf-core custom profiles from different Institutions diff --git a/nf-test.config b/nf-test.config new file mode 100644 index 00000000..84c773dd --- /dev/null +++ b/nf-test.config @@ -0,0 +1,21 @@ +config { + // Location of nf-tests + testsDir "." + + // nf-test directory used to create temporary files for each test + workDir System.getenv("NFT_WORKDIR") ?: ".nf-test" + + // Location of an optional nextflow.config file specific for executing pipeline tests + configFile "tests/nextflow.config" + + // run all test with defined profile(s) from the main nextflow.config + profile "test_scsp_v1_immunology_v1" + triggers 'nextflow.config', 'nf-test.config', 'conf/test.config', 'conf/test_full.config' + + // load the necessary plugins + plugins { + load "nft-utils@0.0.3" + load "nft-fasta@1.0.0" + load "nft-compress@0.1.0" + } +} diff --git a/subworkflows/local/generate_reports.nf b/subworkflows/local/generate_reports/main.nf similarity index 72% rename from subworkflows/local/generate_reports.nf rename to subworkflows/local/generate_reports/main.nf index 73c599b7..7f88d69e 100644 --- a/subworkflows/local/generate_reports.nf +++ b/subworkflows/local/generate_reports/main.nf @@ -4,7 +4,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { PIXELATOR_REPORT } from '../../modules/local/pixelator/single-cell/report/main' +include { PIXELATOR_REPORT } from '../../../modules/local/pixelator/single-cell/report/main' /* @@ -29,15 +29,14 @@ workflow GENERATE_REPORTS { main: ch_versions = Channel.empty() + // Combine meta maps for all input samples ch_meta_col = panel_files - .map { meta, data -> [ meta.id, meta] } + .map { meta, _path -> [ meta.id, meta] } .groupTuple() .map { id, data -> if (data instanceof List) { def newMeta = [:] - for (item in data) { - newMeta += item - } + data.forEach { newMeta += it } return [id, newMeta] } return [id, data] @@ -62,7 +61,7 @@ workflow GENERATE_REPORTS { // // Combine all inputs and group them, then split them up again. - // This is neded to have the per subcommand outputs in the sample order + // This is needed to have the per subcommand outputs in the sample order // // ch_report_data: [ // [ @@ -102,16 +101,18 @@ workflow GENERATE_REPORTS { // If no `panel_file` (data[1]) is given we need to pass in `panel` from the samplesheet instead // - ch_panel_files_grouped = ch_report_data.map { id, data -> [ data[0], data[1], data[1] ? null : data[0].panel ] } - ch_amplicon_grouped = ch_report_data.map { id, data -> data[2] ? data[2].flatten() : [] } - ch_preqc_grouped = ch_report_data.map { id, data -> data[3] ? data[3].flatten() : [] } - ch_adapterqc_grouped = ch_report_data.map { id, data -> data[4] ? data[4].flatten() : [] } - ch_demux_grouped = ch_report_data.map { id, data -> data[5] ? data[5].flatten() : [] } - ch_collapse_grouped = ch_report_data.map { id, data -> data[6] ? data[6].flatten() : [] } - ch_graph_grouped = ch_report_data.map { id, data -> data[7] ? data[7].flatten() : [] } - ch_annotate_grouped = ch_report_data.map { id, data -> data[8] ? data[8].flatten() : [] } - ch_analysis_grouped = ch_report_data.map { id, data -> data[9] ? data[9].flatten() : [] } - ch_layout_grouped = ch_report_data.map { id, data -> data[10] ? data[10].flatten() : [] } + ch_report_inputs = ch_report_data.multiMap { _id, data -> + panels: [ data[0], data[1], data[1] ? null : data[0].panel ] + amplicon: data[2] ? data[2].flatten() : [] + preqc: data[3] ? data[3].flatten() : [] + adapterqc: data[4] ? data[4].flatten() : [] + demux: data[5] ? data[5].flatten() : [] + collapse: data[6] ? data[6].flatten() : [] + graph: data[7] ? data[7].flatten() : [] + annotate: data[8] ? data[8].flatten() : [] + analysis: data[9] ? data[9].flatten() : [] + layout: data[10] ? data[10].flatten() : [] + } // // MODULE: Run pixelator single-cell report for each samples @@ -119,16 +120,16 @@ workflow GENERATE_REPORTS { // NB: These channels need to be split per stage to allow PIXELATOR_REPORT to // use stageAs directives to reorder the inputs and prevent filename collisions PIXELATOR_REPORT ( - ch_panel_files_grouped, - ch_amplicon_grouped, - ch_preqc_grouped, - ch_adapterqc_grouped, - ch_demux_grouped, - ch_collapse_grouped, - ch_graph_grouped, - ch_annotate_grouped, - ch_analysis_grouped, - ch_layout_grouped, + ch_report_inputs.panels, + ch_report_inputs.amplicon, + ch_report_inputs.preqc, + ch_report_inputs.adapterqc, + ch_report_inputs.demux, + ch_report_inputs.collapse, + ch_report_inputs.graph, + ch_report_inputs.annotate, + ch_report_inputs.analysis, + ch_report_inputs.layout ) ch_versions = ch_versions.mix(PIXELATOR_REPORT.out.versions.first()) diff --git a/subworkflows/local/generate_reports/tests/main.nf.test b/subworkflows/local/generate_reports/tests/main.nf.test new file mode 100644 index 00000000..e41ae29c --- /dev/null +++ b/subworkflows/local/generate_reports/tests/main.nf.test @@ -0,0 +1,200 @@ +nextflow_workflow { + name "Test Subworkflow GENERATE_REPORTS" + script "../main.nf" + workflow "GENERATE_REPORTS" + + test("Test MPX Generate reports - stub") { + + options "-stub" + + when { + workflow { + """ + def meta = [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ] + + input[0] = Channel.of([ + meta, + [] + ]) + + input[1] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/amplicon/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/amplicon/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + ]) + input[2] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/preqc/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/preqc/sample01_1k_pbmcs_scsp_v1_immunology1.processed.fastq.gz', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/preqc/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + ]) + input[3] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/adapterqc/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/adapterqc/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + ]) + input[4] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + ]) + input[5] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/collapse/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/collapse/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + ]) + input[6] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/graph/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/graph/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/graph/sample01_1k_pbmcs_scsp_v1_immunology1.edgelist.parquet', checkIfExists: true), + ] + ]) + input[7] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.annotate.dataset.pxl', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.raw_components_metrics.csv.gz', checkIfExists: true), + ] + ]) + input[8] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/analysis/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/analysis/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/analysis/sample01_1k_pbmcs_scsp_v1_immunology1.analysis.dataset.pxl', checkIfExists: true), + ] + ]) + input[9] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/layout/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/layout/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/layout/sample01_1k_pbmcs_scsp_v1_immunology1.layout.dataset.pxl', checkIfExists: true), + ] + ]) + """ + } + } + + then { + assertAll( + { assert workflow.success}, + { assert snapshot(workflow.out).match() } + ) + } + } + + test("Test MPX Generate reports - SCSP v1 | Immunology-I") { + when { + params { + save_all = true + } + workflow { + """ + def meta = [ id:'sample01_1k_pbmcs_scsp_v1_immunology1', design:'D21', panel:'human-sc-immunology-spatial-proteomics-1', technology:'mpx' ] + + input[0] = Channel.of([ + meta, + [] + ]) + + input[1] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/amplicon/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/amplicon/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + ]) + input[2] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/preqc/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/preqc/sample01_1k_pbmcs_scsp_v1_immunology1.processed.fastq.gz', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/preqc/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + ]) + input[3] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/adapterqc/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/adapterqc/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + ]) + input[4] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/demux/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + ]) + input[5] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/collapse/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/collapse/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + ] + ]) + input[6] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/graph/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/graph/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/graph/sample01_1k_pbmcs_scsp_v1_immunology1.edgelist.parquet', checkIfExists: true), + ] + ]) + input[7] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.annotate.dataset.pxl', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/annotate/sample01_1k_pbmcs_scsp_v1_immunology1.raw_components_metrics.csv.gz', checkIfExists: true), + ] + ]) + input[8] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/analysis/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/analysis/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/analysis/sample01_1k_pbmcs_scsp_v1_immunology1.analysis.dataset.pxl', checkIfExists: true), + ] + ]) + input[9] = Channel.of([ + meta, + [ + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/layout/sample01_1k_pbmcs_scsp_v1_immunology1.meta.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/layout/sample01_1k_pbmcs_scsp_v1_immunology1.report.json', checkIfExists: true), + file(params.pipelines_testdata_base_path + 'testdata/mpx/modules/layout/sample01_1k_pbmcs_scsp_v1_immunology1.layout.dataset.pxl', checkIfExists: true), + ] + ]) + """ + } + } + + then { + assertAll( + { assert workflow.success}, + { assert snapshot(workflow.out.versions).match() }, + { + with (workflow.out.pixelator_reports) { + assert path(get(0).get(1)).exists() + } + } + ) + } + } +} diff --git a/subworkflows/local/generate_reports/tests/main.nf.test.snap b/subworkflows/local/generate_reports/tests/main.nf.test.snap new file mode 100644 index 00000000..bfc0edec --- /dev/null +++ b/subworkflows/local/generate_reports/tests/main.nf.test.snap @@ -0,0 +1,53 @@ +{ + "Test MPX Generate reports - SCSP v1 | Immunology-I": { + "content": [ + [ + "versions.yml:md5,f7a5fde1e258d64b63d135c95829d03a" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T16:40:31.458444005" + }, + "Test MPX Generate reports - stub": { + "content": [ + { + "0": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,f7a5fde1e258d64b63d135c95829d03a" + ], + "pixelator_reports": [ + [ + { + "id": "sample01_1k_pbmcs_scsp_v1_immunology1", + "design": "D21", + "panel": "human-sc-immunology-spatial-proteomics-1", + "technology": "mpx" + }, + "sample01_1k_pbmcs_scsp_v1_immunology1.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,f7a5fde1e258d64b63d135c95829d03a" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T16:44:16.524680775" + } +} \ No newline at end of file diff --git a/tests/.nftignore b/tests/.nftignore new file mode 100644 index 00000000..b03dfe32 --- /dev/null +++ b/tests/.nftignore @@ -0,0 +1,2 @@ +pixelator/logs/**/*.log +pipeline_info/*.{html,json,txt,yml} diff --git a/tests/default.nf.test b/tests/default.nf.test new file mode 100644 index 00000000..ecccbe5b --- /dev/null +++ b/tests/default.nf.test @@ -0,0 +1,62 @@ +nextflow_pipeline { + + name "Test pipeline with default settings" + script "../main.nf" + + test("Params: default") { + + when { + params { + outdir = "$outputDir" + } + } + + then { + // stable_name: All files + folders in ${params.outdir}/ with a stable name + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) + // stable_path: All files in ${params.outdir}/ with stable content + def stable_path = [] + + assertAll( + { assert workflow.success}, + { assert snapshot( + // Number of successful tasks + workflow.trace.succeeded().size(), + // All stable path name, with a relative path + stable_name, + // All files with stable contents + stable_path + ).match() } + ) + } + } + + test("Params: default - stub") { + + options "-stub" + + when { + params { + outdir = "$outputDir" + } + } + + then { + // stable_name: All files + folders in ${params.outdir}/ with a stable name + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) + // stable_path: All files in ${params.outdir}/ with stable content + def stable_path = [] + assertAll( + { assert workflow.success}, + { assert snapshot( + // Number of successful tasks + workflow.trace.succeeded().size(), + // All stable path name, with a relative path + stable_name, + // All files with stable contents + stable_path + ).match() } + ) + } + } +} diff --git a/tests/default.nf.test.snap b/tests/default.nf.test.snap new file mode 100644 index 00000000..d7318496 --- /dev/null +++ b/tests/default.nf.test.snap @@ -0,0 +1,66 @@ +{ + "Params: default - stub": { + "content": [ + 11, + [ + "pipeline_info", + "pipeline_info/nf_core_pixelator_software_mqc_versions.yml", + "pixelator", + "pixelator/logs", + "pixelator/logs/sample01", + "pixelator/logs/sample01/sample01.pixelator-adapterqc.log", + "pixelator/logs/sample01/sample01.pixelator-amplicon.log", + "pixelator/logs/sample01/sample01.pixelator-analysis.log", + "pixelator/logs/sample01/sample01.pixelator-annotate.log", + "pixelator/logs/sample01/sample01.pixelator-collapse.log", + "pixelator/logs/sample01/sample01.pixelator-demux.log", + "pixelator/logs/sample01/sample01.pixelator-graph.log", + "pixelator/logs/sample01/sample01.pixelator-layout.log", + "pixelator/logs/sample01/sample01.pixelator-preqc.log", + "pixelator/logs/sample01/sample01.pixelator-report.log", + "pixelator/sample01.html", + "pixelator/sample01.layout.dataset.pxl" + ], + [ + + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-13T17:41:37.776422163" + }, + "Params: default": { + "content": [ + 11, + [ + "pipeline_info", + "pipeline_info/nf_core_pixelator_software_mqc_versions.yml", + "pixelator", + "pixelator/logs", + "pixelator/logs/sample01", + "pixelator/logs/sample01/sample01.pixelator-adapterqc.log", + "pixelator/logs/sample01/sample01.pixelator-amplicon.log", + "pixelator/logs/sample01/sample01.pixelator-analysis.log", + "pixelator/logs/sample01/sample01.pixelator-annotate.log", + "pixelator/logs/sample01/sample01.pixelator-collapse.log", + "pixelator/logs/sample01/sample01.pixelator-demux.log", + "pixelator/logs/sample01/sample01.pixelator-graph.log", + "pixelator/logs/sample01/sample01.pixelator-layout.log", + "pixelator/logs/sample01/sample01.pixelator-preqc.log", + "pixelator/logs/sample01/sample01.pixelator-report.log", + "pixelator/sample01.layout.dataset.pxl", + "pixelator/sample01.qc-report.html" + ], + [ + + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T14:44:14.780391273" + } +} \ No newline at end of file diff --git a/tests/nextflow.config b/tests/nextflow.config new file mode 100644 index 00000000..7d12df6f --- /dev/null +++ b/tests/nextflow.config @@ -0,0 +1,38 @@ +/* +======================================================================================== + Nextflow config file for running tests +======================================================================================== +*/ + +params { + // Base directory for nf-core/modules test data + modules_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/modules/' + pipelines_testdata_base_path = "https://raw.githubusercontent.com/nf-core/test-datasets/" + + // TODO: check if we rather do this or disable publishdir for all processes when testing modules/subworkflows + outdir = 'results' +} + +validation { + ignoreParams = ['modules_testdata_base_path', 'pipelines_testdata_base_path'] +} + +// Impose sensible resource limits for testing +process { + withName: '.*' { + cpus = 2 + memory = 3.GB + time = 2.h + } +} + +// Impose same minimum Nextflow version as the pipeline for testing +manifest { + nextflowVersion = '!>=23.10.4' +} + +// Disable all Nextflow reporting options +timeline { enabled = false } +report { enabled = false } +trace { enabled = false } +dag { enabled = false } diff --git a/tests/save_all.nf.test b/tests/save_all.nf.test new file mode 100644 index 00000000..889976f3 --- /dev/null +++ b/tests/save_all.nf.test @@ -0,0 +1,63 @@ +nextflow_pipeline { + + name "Test pipeline with --save_all" + script "../main.nf" + + test("Params: --save_all") { + + when { + params { + outdir = "$outputDir" + save_all = true + } + } + + then { + // stable_name: All files + folders in ${params.outdir}/ with a stable name + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) + // stable_path: All files in ${params.outdir}/ with stable content + def stable_path = [] + + assertAll( + { assert workflow.success}, + { assert snapshot( + // Number of successful tasks + workflow.trace.succeeded().size(), + // All stable path name, with a relative path + stable_name, + // All files with stable contents + stable_path + ).match() } + ) + } + } + + test("Params: --save_all - stub") { + + options "-stub" + + when { + params { + outdir = "$outputDir" + } + } + + then { + // stable_name: All files + folders in ${params.outdir}/ with a stable name + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) + // stable_path: All files in ${params.outdir}/ with stable content + def stable_path = [] + assertAll( + { assert workflow.success}, + { assert snapshot( + // Number of successful tasks + workflow.trace.succeeded().size(), + // All stable path name, with a relative path + stable_name, + // All files with stable contents + stable_path + ).match() } + ) + } + } +} diff --git a/tests/save_all.nf.test.snap b/tests/save_all.nf.test.snap new file mode 100644 index 00000000..a4eea76e --- /dev/null +++ b/tests/save_all.nf.test.snap @@ -0,0 +1,185 @@ +{ + "Params: --save_all": { + "content": [ + 11, + [ + "pipeline_info", + "pipeline_info/nf_core_pixelator_software_mqc_versions.yml", + "pixelator", + "pixelator/adapterqc", + "pixelator/adapterqc/sample01.failed.fastq.gz", + "pixelator/adapterqc/sample01.meta.json", + "pixelator/adapterqc/sample01.processed.fastq.gz", + "pixelator/adapterqc/sample01.report.json", + "pixelator/amplicon", + "pixelator/amplicon/sample01.merged.fastq.gz", + "pixelator/amplicon/sample01.meta.json", + "pixelator/amplicon/sample01.report.json", + "pixelator/analysis", + "pixelator/analysis/sample01.analysis.dataset.pxl", + "pixelator/analysis/sample01.meta.json", + "pixelator/analysis/sample01.report.json", + "pixelator/annotate", + "pixelator/annotate/sample01.annotate.dataset.pxl", + "pixelator/annotate/sample01.meta.json", + "pixelator/annotate/sample01.report.json", + "pixelator/collapse", + "pixelator/collapse/sample01.collapsed.parquet", + "pixelator/collapse/sample01.meta.json", + "pixelator/collapse/sample01.report.json", + "pixelator/demux", + "pixelator/demux/sample01.failed.fastq.gz", + "pixelator/demux/sample01.meta.json", + "pixelator/demux/sample01.processed-AAAGCAAC.fastq.gz", + "pixelator/demux/sample01.processed-AACAAGAC.fastq.gz", + "pixelator/demux/sample01.processed-AACCTTCC.fastq.gz", + "pixelator/demux/sample01.processed-AACGGCTA.fastq.gz", + "pixelator/demux/sample01.processed-AAGCATAG.fastq.gz", + "pixelator/demux/sample01.processed-AAGTAGCT.fastq.gz", + "pixelator/demux/sample01.processed-AAGTCGTG.fastq.gz", + "pixelator/demux/sample01.processed-ACATTGAC.fastq.gz", + "pixelator/demux/sample01.processed-ACCAGTAC.fastq.gz", + "pixelator/demux/sample01.processed-ACCTTGTG.fastq.gz", + "pixelator/demux/sample01.processed-ACTCGGAA.fastq.gz", + "pixelator/demux/sample01.processed-ACTCTCAC.fastq.gz", + "pixelator/demux/sample01.processed-ACTGTGTC.fastq.gz", + "pixelator/demux/sample01.processed-AGAGGCTC.fastq.gz", + "pixelator/demux/sample01.processed-AGCCCGAA.fastq.gz", + "pixelator/demux/sample01.processed-AGCTACTA.fastq.gz", + "pixelator/demux/sample01.processed-AGGATGTT.fastq.gz", + "pixelator/demux/sample01.processed-AGGGCAGT.fastq.gz", + "pixelator/demux/sample01.processed-AGTTATCG.fastq.gz", + "pixelator/demux/sample01.processed-ATAGGGGA.fastq.gz", + "pixelator/demux/sample01.processed-ATGACTGC.fastq.gz", + "pixelator/demux/sample01.processed-ATTCGCCT.fastq.gz", + "pixelator/demux/sample01.processed-ATTGGCAC.fastq.gz", + "pixelator/demux/sample01.processed-ATTTCGAG.fastq.gz", + "pixelator/demux/sample01.processed-CAATCGGC.fastq.gz", + "pixelator/demux/sample01.processed-CACACGGT.fastq.gz", + "pixelator/demux/sample01.processed-CACGTTTC.fastq.gz", + "pixelator/demux/sample01.processed-CAGATCCG.fastq.gz", + "pixelator/demux/sample01.processed-CAGTCAGT.fastq.gz", + "pixelator/demux/sample01.processed-CATGGGCA.fastq.gz", + "pixelator/demux/sample01.processed-CCAGACAC.fastq.gz", + "pixelator/demux/sample01.processed-CCAGCATG.fastq.gz", + "pixelator/demux/sample01.processed-CCGATATC.fastq.gz", + "pixelator/demux/sample01.processed-CCTAAGAA.fastq.gz", + "pixelator/demux/sample01.processed-CTACGACG.fastq.gz", + "pixelator/demux/sample01.processed-CTACTCGC.fastq.gz", + "pixelator/demux/sample01.processed-CTCAAGAG.fastq.gz", + "pixelator/demux/sample01.processed-CTCAGATG.fastq.gz", + "pixelator/demux/sample01.processed-CTGACCAT.fastq.gz", + "pixelator/demux/sample01.processed-CTGTAGGA.fastq.gz", + "pixelator/demux/sample01.processed-CTTCTTGA.fastq.gz", + "pixelator/demux/sample01.processed-CTTGCACC.fastq.gz", + "pixelator/demux/sample01.processed-GAAAGTCA.fastq.gz", + "pixelator/demux/sample01.processed-GAATCCCG.fastq.gz", + "pixelator/demux/sample01.processed-GACCACTC.fastq.gz", + "pixelator/demux/sample01.processed-GACTGGGA.fastq.gz", + "pixelator/demux/sample01.processed-GAGGTTAG.fastq.gz", + "pixelator/demux/sample01.processed-GATAGGGT.fastq.gz", + "pixelator/demux/sample01.processed-GATTGTGC.fastq.gz", + "pixelator/demux/sample01.processed-GCACTTAG.fastq.gz", + "pixelator/demux/sample01.processed-GCATTCTG.fastq.gz", + "pixelator/demux/sample01.processed-GCCGGACG.fastq.gz", + "pixelator/demux/sample01.processed-GCGCAACT.fastq.gz", + "pixelator/demux/sample01.processed-GCTATTGA.fastq.gz", + "pixelator/demux/sample01.processed-GCTGAACC.fastq.gz", + "pixelator/demux/sample01.processed-GGAGCCAA.fastq.gz", + "pixelator/demux/sample01.processed-GGTTTACC.fastq.gz", + "pixelator/demux/sample01.processed-GTAGGACC.fastq.gz", + "pixelator/demux/sample01.processed-GTATCGGT.fastq.gz", + "pixelator/demux/sample01.processed-GTCTTTGT.fastq.gz", + "pixelator/demux/sample01.processed-GTGAGTAG.fastq.gz", + "pixelator/demux/sample01.processed-GTGCATTC.fastq.gz", + "pixelator/demux/sample01.processed-GTTCAGAC.fastq.gz", + "pixelator/demux/sample01.processed-GTTGTCCG.fastq.gz", + "pixelator/demux/sample01.processed-TACTCTTG.fastq.gz", + "pixelator/demux/sample01.processed-TATCCCTT.fastq.gz", + "pixelator/demux/sample01.processed-TCAACGCT.fastq.gz", + "pixelator/demux/sample01.processed-TCAGGGTG.fastq.gz", + "pixelator/demux/sample01.processed-TCCCAGTG.fastq.gz", + "pixelator/demux/sample01.processed-TCCCTTGC.fastq.gz", + "pixelator/demux/sample01.processed-TCCGTAAC.fastq.gz", + "pixelator/demux/sample01.processed-TCGTAACG.fastq.gz", + "pixelator/demux/sample01.processed-TCTGCTCC.fastq.gz", + "pixelator/demux/sample01.processed-TGATAGAA.fastq.gz", + "pixelator/demux/sample01.processed-TGCATGTC.fastq.gz", + "pixelator/demux/sample01.processed-TGGGGCTT.fastq.gz", + "pixelator/demux/sample01.processed-TTCTGGGT.fastq.gz", + "pixelator/demux/sample01.processed-TTGTCCAA.fastq.gz", + "pixelator/demux/sample01.processed-TTTCTGGT.fastq.gz", + "pixelator/demux/sample01.processed-TTTGGAAG.fastq.gz", + "pixelator/demux/sample01.report.json", + "pixelator/graph", + "pixelator/graph/sample01.discarded_edgelist.parquet", + "pixelator/graph/sample01.edgelist.parquet", + "pixelator/graph/sample01.meta.json", + "pixelator/graph/sample01.report.json", + "pixelator/layout", + "pixelator/layout/sample01.meta.json", + "pixelator/layout/sample01.report.json", + "pixelator/logs", + "pixelator/logs/sample01", + "pixelator/logs/sample01/sample01.pixelator-adapterqc.log", + "pixelator/logs/sample01/sample01.pixelator-amplicon.log", + "pixelator/logs/sample01/sample01.pixelator-analysis.log", + "pixelator/logs/sample01/sample01.pixelator-annotate.log", + "pixelator/logs/sample01/sample01.pixelator-collapse.log", + "pixelator/logs/sample01/sample01.pixelator-demux.log", + "pixelator/logs/sample01/sample01.pixelator-graph.log", + "pixelator/logs/sample01/sample01.pixelator-layout.log", + "pixelator/logs/sample01/sample01.pixelator-preqc.log", + "pixelator/logs/sample01/sample01.pixelator-report.log", + "pixelator/preqc", + "pixelator/preqc/sample01.failed.fastq.gz", + "pixelator/preqc/sample01.meta.json", + "pixelator/preqc/sample01.processed.fastq.gz", + "pixelator/preqc/sample01.qc-report.html", + "pixelator/preqc/sample01.report.json", + "pixelator/sample01.layout.dataset.pxl", + "pixelator/sample01.qc-report.html" + ], + [ + + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T15:34:00.041487058" + }, + "Params: --save_all - stub": { + "content": [ + 11, + [ + "pipeline_info", + "pipeline_info/nf_core_pixelator_software_mqc_versions.yml", + "pixelator", + "pixelator/logs", + "pixelator/logs/sample01", + "pixelator/logs/sample01/sample01.pixelator-adapterqc.log", + "pixelator/logs/sample01/sample01.pixelator-amplicon.log", + "pixelator/logs/sample01/sample01.pixelator-analysis.log", + "pixelator/logs/sample01/sample01.pixelator-annotate.log", + "pixelator/logs/sample01/sample01.pixelator-collapse.log", + "pixelator/logs/sample01/sample01.pixelator-demux.log", + "pixelator/logs/sample01/sample01.pixelator-graph.log", + "pixelator/logs/sample01/sample01.pixelator-layout.log", + "pixelator/logs/sample01/sample01.pixelator-preqc.log", + "pixelator/logs/sample01/sample01.pixelator-report.log", + "pixelator/sample01.html", + "pixelator/sample01.layout.dataset.pxl" + ], + [ + + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-14T15:35:22.361483814" + } +} \ No newline at end of file diff --git a/workflows/pixelator.nf b/workflows/pixelator.nf index 53aef853..cb9a1314 100644 --- a/workflows/pixelator.nf +++ b/workflows/pixelator.nf @@ -28,7 +28,7 @@ params.samplesheet_sha = ch_input.bytes.digest('sha-1') // // SUBWORKFLOW: Consisting of a mix of local and nf-core/modules // -include { GENERATE_REPORTS } from '../subworkflows/local/generate_reports' +include { GENERATE_REPORTS } from '../subworkflows/local/generate_reports/main' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 05677f7be7b5a3efa9137da975e3faa7e8a44602 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Tue, 14 Jan 2025 17:32:50 +0100 Subject: [PATCH 58/70] Update collect_metadata versioning --- bin/collect_metadata.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/collect_metadata.py b/bin/collect_metadata.py index b091bce5..9e25e41e 100755 --- a/bin/collect_metadata.py +++ b/bin/collect_metadata.py @@ -66,7 +66,8 @@ def main(args): yaml.dump( data={ args.process_name: { - "python": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}" + "python": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}", + "collect-metadata": __version__, } }, stream=f, From 441114a8aeb53a2925531baf68407b548a591934 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Tue, 14 Jan 2025 18:14:16 +0100 Subject: [PATCH 59/70] Update nf-core/cat/fastq module --- modules.json | 2 +- modules/nf-core/cat/fastq/environment.yml | 5 +++++ modules/nf-core/cat/fastq/main.nf | 22 +++++++++++--------- modules/nf-core/cat/fastq/tests/main.nf.test | 2 -- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/modules.json b/modules.json index 7fc00dd1..66eb481c 100644 --- a/modules.json +++ b/modules.json @@ -7,7 +7,7 @@ "nf-core": { "cat/fastq": { "branch": "master", - "git_sha": "a1abf90966a2a4016d3c3e41e228bfcbd4811ccc", + "git_sha": "0e9cb409c32d3ec4f0d3804588e4778971c09b7e", "installed_by": ["modules"] } } diff --git a/modules/nf-core/cat/fastq/environment.yml b/modules/nf-core/cat/fastq/environment.yml index 71e04c3d..ae4fa457 100644 --- a/modules/nf-core/cat/fastq/environment.yml +++ b/modules/nf-core/cat/fastq/environment.yml @@ -3,3 +3,8 @@ channels: - bioconda dependencies: - conda-forge::coreutils=9.5 + - conda-forge::grep=3.11 + - conda-forge::gzip=1.13 + - conda-forge::lbzip2=2.5 + - conda-forge::sed=4.8 + - conda-forge::tar=1.34 diff --git a/modules/nf-core/cat/fastq/main.nf b/modules/nf-core/cat/fastq/main.nf index 4364a389..7e6bafe8 100644 --- a/modules/nf-core/cat/fastq/main.nf +++ b/modules/nf-core/cat/fastq/main.nf @@ -1,18 +1,18 @@ process CAT_FASTQ { - tag "$meta.id" + tag "${meta.id}" label 'process_single' conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/c2/c262fc09eca59edb5a724080eeceb00fb06396f510aefb229c2d2c6897e63975/data' : - 'community.wave.seqera.io/library/coreutils:9.5--ae99c88a9b28c264' }" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/52/52ccce28d2ab928ab862e25aae26314d69c8e38bd41ca9431c67ef05221348aa/data' + : 'community.wave.seqera.io/library/coreutils_grep_gzip_lbzip2_pruned:838ba80435a629f8'}" input: tuple val(meta), path(reads, stageAs: "input*/*") output: tuple val(meta), path("*.merged.fastq.gz"), emit: reads - path "versions.yml" , emit: versions + path "versions.yml", emit: versions when: task.ext.when == null || task.ext.when @@ -20,7 +20,7 @@ process CAT_FASTQ { script: def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - def readList = reads instanceof List ? reads.collect{ it.toString() } : [reads.toString()] + def readList = reads instanceof List ? reads.collect { it.toString() } : [reads.toString()] if (meta.single_end) { if (readList.size >= 1) { """ @@ -32,11 +32,12 @@ process CAT_FASTQ { END_VERSIONS """ } - } else { + } + else { if (readList.size >= 2) { def read1 = [] def read2 = [] - readList.eachWithIndex{ v, ix -> ( ix & 1 ? read2 : read1 ) << v } + readList.eachWithIndex { v, ix -> (ix & 1 ? read2 : read1) << v } """ cat ${read1.join(' ')} > ${prefix}_1.merged.fastq.gz cat ${read2.join(' ')} > ${prefix}_2.merged.fastq.gz @@ -51,7 +52,7 @@ process CAT_FASTQ { stub: def prefix = task.ext.prefix ?: "${meta.id}" - def readList = reads instanceof List ? reads.collect{ it.toString() } : [reads.toString()] + def readList = reads instanceof List ? reads.collect { it.toString() } : [reads.toString()] if (meta.single_end) { if (readList.size >= 1) { """ @@ -63,7 +64,8 @@ process CAT_FASTQ { END_VERSIONS """ } - } else { + } + else { if (readList.size >= 2) { """ echo '' | gzip > ${prefix}_1.merged.fastq.gz diff --git a/modules/nf-core/cat/fastq/tests/main.nf.test b/modules/nf-core/cat/fastq/tests/main.nf.test index f88a78b6..0de5e185 100644 --- a/modules/nf-core/cat/fastq/tests/main.nf.test +++ b/modules/nf-core/cat/fastq/tests/main.nf.test @@ -1,5 +1,3 @@ -// 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" From 7a1351d75b089eaae7c0cf85555af5dd29fb0dc3 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 15 Jan 2025 14:47:38 +0100 Subject: [PATCH 60/70] Fix module and pipeline testdata references --- conf/test.config | 4 ++-- conf/test_panel_v2.config | 4 ++-- conf/test_scsp_v1_immunology_v1.config | 8 +++----- nextflow.config | 2 +- tests/nextflow.config | 4 ++-- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/conf/test.config b/conf/test.config index d9683271..bec96703 100644 --- a/conf/test.config +++ b/conf/test.config @@ -26,8 +26,8 @@ params { config_profile_description = 'Minimal test dataset to check pipeline function' // Input data - input = params.pipelines_testdata_base_path + 'pixelator/samplesheet/samplesheet.csv' - input_basedir = params.pipelines_testdata_base_path + 'pixelator/testdata' + input = params.pipelines_testdata_base_path + 'samplesheet/samplesheet.csv' + input_basedir = params.pipelines_testdata_base_path + 'testdata' multiplet_recovery = true min_size = null diff --git a/conf/test_panel_v2.config b/conf/test_panel_v2.config index ccca0d59..9d1c59ad 100644 --- a/conf/test_panel_v2.config +++ b/conf/test_panel_v2.config @@ -27,8 +27,8 @@ params { config_profile_description = 'Minimal test dataset to check pipeline function' // Input data - input = params.pipelines_testdata_base_path + 'pixelator/samplesheet/samplesheet_v2.csv' - input_basedir = params.pipelines_testdata_base_path + 'pixelator/testdata/' + input = params.pipelines_testdata_base_path + 'samplesheet/samplesheet_v2.csv' + input_basedir = params.pipelines_testdata_base_path + '' multiplet_recovery = true min_size = 1 diff --git a/conf/test_scsp_v1_immunology_v1.config b/conf/test_scsp_v1_immunology_v1.config index 39b75d3d..98716434 100644 --- a/conf/test_scsp_v1_immunology_v1.config +++ b/conf/test_scsp_v1_immunology_v1.config @@ -6,7 +6,7 @@ using the v2 panel. Use as follows: - nextflow run nf-core/pixelator -profile test_panel_v2, --outdir + nextflow run nf-core/-profile test_panel_v2, --outdir ---------------------------------------------------------------------------------------- */ @@ -24,11 +24,9 @@ params { config_profile_name = 'Test profile' config_profile_description = 'Minimal test dataset to check pipeline function with MPX SCSP v1 | Immunology-I data' - pipelines_testdata_base_path = "https://raw.githubusercontent.com/nf-core/test-datasets/" - // Input data - input = params.pipelines_testdata_base_path + 'pixelator/samplesheet/samplesheet_mpx_scsp_v1_immunology1.csv' - input_basedir = params.pipelines_testdata_base_path + 'pixelator' + input = params.pipelines_testdata_base_path + 'samplesheet/samplesheet_mpx_scsp_v1_immunology1.csv' + input_basedir = params.pipelines_testdata_base_path multiplet_recovery = true min_size = 1 diff --git a/nextflow.config b/nextflow.config index 62cd71ce..5ea1f19f 100644 --- a/nextflow.config +++ b/nextflow.config @@ -100,7 +100,7 @@ params { help_full = false show_hidden = false version = false - pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' + pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/pixelator/' trace_report_suffix = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss')// Config options config_profile_name = null config_profile_description = null diff --git a/tests/nextflow.config b/tests/nextflow.config index 7d12df6f..5fcf70c2 100644 --- a/tests/nextflow.config +++ b/tests/nextflow.config @@ -6,8 +6,8 @@ params { // Base directory for nf-core/modules test data - modules_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/modules/' - pipelines_testdata_base_path = "https://raw.githubusercontent.com/nf-core/test-datasets/" + modules_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/' + pipelines_testdata_base_path = "https://raw.githubusercontent.com/nf-core/test-datasets/pixelator/" // TODO: check if we rather do this or disable publishdir for all processes when testing modules/subworkflows outdir = 'results' From 9ce49fb9b0abef91595b0c6985dfc08c1124203f Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 15 Jan 2025 15:12:18 +0100 Subject: [PATCH 61/70] Fix `pipelines_testdata_base_path` default in nextflow_schema.json --- nextflow_schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index a8f15854..1aba4daa 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -541,7 +541,7 @@ "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/", + "default": "https://raw.githubusercontent.com/nf-core/test-datasets/pixelator/", "hidden": true }, "trace_report_suffix": { From 36c3d2716b9f04c3bb9d3fbd360a10565189df28 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 15 Jan 2025 15:17:17 +0100 Subject: [PATCH 62/70] Silence actions_ci linter check --- .nf-core.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.nf-core.yml b/.nf-core.yml index e5532e28..c11d95fd 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -1,4 +1,5 @@ lint: + actions_ci: false multiqc_config: false files_unchanged: - assets/nf-core-pixelator_logo_light.png From 408281111a717c909bf8ee6df3572ec7be755023 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 15 Jan 2025 15:18:48 +0100 Subject: [PATCH 63/70] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 282fff36..34473bd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [[PR #122](https://github.com/nf-core/pixelator/pull/122)] - Template update for nf-core/tools v3.1.1 - [[PR #124](https://github.com/nf-core/pixelator/pull/124)] - Add manifest.contributors metadata to nextflow.config - [[PR #125](https://github.com/nf-core/pixelator/pull/125)] - Use environment.yml files for all conda process directives +- [[PR #123](https://github.com/nf-core/pixelator/pull/123)] - Add nf-test tests for local modules and subworkflows ### Parameters From 0b0b2caf5aa490841bd304cf1a43a0a85efbcdd5 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 15 Jan 2025 16:27:40 +0100 Subject: [PATCH 64/70] Some docs/output.md fixes - Fix ordering of sections in Pipeline overview - Remove unclear `multiplet_recovery` sentence --- docs/output.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/output.md b/docs/output.md index 7225d0f2..031c480e 100644 --- a/docs/output.md +++ b/docs/output.md @@ -12,7 +12,6 @@ of [`pixelator`](https://github.com/PixelgenTechnologies/pixelator). The pipeline consists of the following steps: -- [Pipeline information](#pipeline-information) - Report metrics generated during the workflow execution - [Preprocessing](#Preprocessing) - [Quality control](#quality-control) - [Demultiplexing](#demultiplexing) @@ -22,6 +21,7 @@ The pipeline consists of the following steps: - [Downstream analysis](#downstream-analysis) - [Generate layouts for visualization](#compute-layouts-for-visualization) - [Generate reports](#generate-reports) +- [Pipeline information](#pipeline-information) - Report metrics generated during the workflow execution ### Preprocessing @@ -157,7 +157,7 @@ When graphs are computed and identified, their ID names are added back to the ed The graph command has the option to recover components (technical multiplets) into smaller components using community detection to find and remove problematic edges -(see `--multiplet_recovery`). These new component IDs are then stored in the "component" column. +(see `--multiplet_recovery`). The edge list is intermediate and by default not placed in the output folder with the final files delivered to users. Set `--save_edgelist` to enable publishing of these file. From 2aa0a3125ea492c6a3f3bcc659fe95374ccabceb Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 15 Jan 2025 17:04:47 +0100 Subject: [PATCH 65/70] Fix environment.yml reference failing with nf-test --- modules/local/collect_metadata/main.nf | 2 +- modules/local/pixelator/list_options/main.nf | 2 +- modules/local/pixelator/single-cell/amplicon/main.nf | 2 +- modules/local/pixelator/single-cell/analysis/main.nf | 2 +- modules/local/pixelator/single-cell/annotate/main.nf | 2 +- modules/local/pixelator/single-cell/collapse/main.nf | 2 +- modules/local/pixelator/single-cell/demux/main.nf | 2 +- modules/local/pixelator/single-cell/graph/main.nf | 2 +- modules/local/pixelator/single-cell/layout/main.nf | 2 +- modules/local/pixelator/single-cell/qc/main.nf | 2 +- modules/local/pixelator/single-cell/report/main.nf | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/local/collect_metadata/main.nf b/modules/local/collect_metadata/main.nf index f4fddce2..324ad245 100644 --- a/modules/local/collect_metadata/main.nf +++ b/modules/local/collect_metadata/main.nf @@ -3,7 +3,7 @@ process PIXELATOR_COLLECT_METADATA { label 'process_single' cache false - conda "modules/local/collect_metadata/environment.yml" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/list_options/main.nf b/modules/local/pixelator/list_options/main.nf index c2aafcee..3783b2e2 100644 --- a/modules/local/pixelator/list_options/main.nf +++ b/modules/local/pixelator/list_options/main.nf @@ -2,7 +2,7 @@ process PIXELATOR_LIST_OPTIONS { label 'process_single' - conda "modules/local/pixelator/list_options/environment.yml" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/amplicon/main.nf b/modules/local/pixelator/single-cell/amplicon/main.nf index 79e74751..5d37620a 100644 --- a/modules/local/pixelator/single-cell/amplicon/main.nf +++ b/modules/local/pixelator/single-cell/amplicon/main.nf @@ -3,7 +3,7 @@ process PIXELATOR_AMPLICON { label 'process_low' label 'process_long' - conda "modules/local/pixelator/single-cell/amplicon/environment.yml" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/analysis/main.nf b/modules/local/pixelator/single-cell/analysis/main.nf index 97b14481..749b1f56 100644 --- a/modules/local/pixelator/single-cell/analysis/main.nf +++ b/modules/local/pixelator/single-cell/analysis/main.nf @@ -2,7 +2,7 @@ process PIXELATOR_ANALYSIS { tag "$meta.id" label 'process_medium' - conda "modules/local/pixelator/single-cell/analysis/environment.yml" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/annotate/main.nf b/modules/local/pixelator/single-cell/annotate/main.nf index 5b21c63f..9e9c39ea 100644 --- a/modules/local/pixelator/single-cell/annotate/main.nf +++ b/modules/local/pixelator/single-cell/annotate/main.nf @@ -2,7 +2,7 @@ process PIXELATOR_ANNOTATE { tag "$meta.id" label 'process_high' - conda "modules/local/pixelator/single-cell/annotate/environment.yml" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/collapse/main.nf b/modules/local/pixelator/single-cell/collapse/main.nf index 01d1044b..b1764ba8 100644 --- a/modules/local/pixelator/single-cell/collapse/main.nf +++ b/modules/local/pixelator/single-cell/collapse/main.nf @@ -3,7 +3,7 @@ process PIXELATOR_COLLAPSE { label 'process_medium' label 'process_long' - conda "modules/local/pixelator/single-cell/collapse/environment.yml" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/demux/main.nf b/modules/local/pixelator/single-cell/demux/main.nf index 148a51d6..09cfb954 100644 --- a/modules/local/pixelator/single-cell/demux/main.nf +++ b/modules/local/pixelator/single-cell/demux/main.nf @@ -2,7 +2,7 @@ process PIXELATOR_DEMUX { tag "$meta.id" label 'process_medium' - conda "modules/local/pixelator/single-cell/demux/environment.yml" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/graph/main.nf b/modules/local/pixelator/single-cell/graph/main.nf index 324caef5..cda7eedf 100644 --- a/modules/local/pixelator/single-cell/graph/main.nf +++ b/modules/local/pixelator/single-cell/graph/main.nf @@ -2,7 +2,7 @@ process PIXELATOR_GRAPH { tag "$meta.id" label 'process_high' - conda "modules/local/pixelator/single-cell/graph/environment.yml" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/layout/main.nf b/modules/local/pixelator/single-cell/layout/main.nf index e7042b84..480ffdb5 100644 --- a/modules/local/pixelator/single-cell/layout/main.nf +++ b/modules/local/pixelator/single-cell/layout/main.nf @@ -2,7 +2,7 @@ process PIXELATOR_LAYOUT { tag "$meta.id" label 'process_medium' - conda "modules/local/pixelator/single-cell/layout/environment.yml" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/qc/main.nf b/modules/local/pixelator/single-cell/qc/main.nf index fc439c9d..bb10e6fc 100644 --- a/modules/local/pixelator/single-cell/qc/main.nf +++ b/modules/local/pixelator/single-cell/qc/main.nf @@ -2,7 +2,7 @@ process PIXELATOR_QC { tag "$meta.id" label 'process_medium' - conda "modules/local/pixelator/single-cell/qc/environment.yml" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" diff --git a/modules/local/pixelator/single-cell/report/main.nf b/modules/local/pixelator/single-cell/report/main.nf index f04c654f..20541a31 100644 --- a/modules/local/pixelator/single-cell/report/main.nf +++ b/modules/local/pixelator/single-cell/report/main.nf @@ -2,7 +2,7 @@ process PIXELATOR_REPORT { tag "$meta.id" label 'process_low' - conda "modules/local/pixelator/single-cell/report/environment.yml" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pixelator:0.19.0--pyhdfd78af_0' : 'biocontainers/pixelator:0.19.0--pyhdfd78af_0' }" From 034ef888f9d21aee792c59dd3858556303c529f5 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 15 Jan 2025 17:05:25 +0100 Subject: [PATCH 66/70] Bump release date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34473bd1..e5f6be8f 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). -## [[1.4.0](https://github.com/nf-core/pixelator/releases/tag/1.4.0)] - 2024-01-?? +## [[1.4.0](https://github.com/nf-core/pixelator/releases/tag/1.4.0)] - 2024-01-16 ### Enhancements & fixes From ea4e2c97d6b0425c6828d572a710999bcf2654a6 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Thu, 16 Jan 2025 12:05:29 +0100 Subject: [PATCH 67/70] Use fixed download_pipeline.yml workflow from https://github.com/nf-core/tools/pull/3389 --- .github/workflows/download_pipeline.yml | 28 ++++++++++++++----------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml index 13b51e2c..ab06316e 100644 --- a/.github/workflows/download_pipeline.yml +++ b/.github/workflows/download_pipeline.yml @@ -34,6 +34,17 @@ jobs: REPO_LOWERCASE: ${{ steps.get_repo_properties.outputs.REPO_LOWERCASE }} REPOTITLE_LOWERCASE: ${{ steps.get_repo_properties.outputs.REPOTITLE_LOWERCASE }} REPO_BRANCH: ${{ steps.get_repo_properties.outputs.REPO_BRANCH }} + steps: + - name: Get the repository name and current branch + id: get_repo_properties + run: | + echo "REPO_LOWERCASE=${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT" + echo "REPOTITLE_LOWERCASE=$(basename ${GITHUB_REPOSITORY,,})" >> "$GITHUB_OUTPUT" + echo "REPO_BRANCH=${{ github.event.inputs.testbranch || 'dev' }}" >> "$GITHUB_OUTPUT" + + download: + runs-on: ubuntu-latest + needs: configure steps: - name: Install Nextflow uses: nf-core/setup-nextflow@v2 @@ -56,21 +67,10 @@ jobs: 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 - id: get_repo_properties - run: | - echo "REPO_LOWERCASE=${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT" - echo "REPOTITLE_LOWERCASE=$(basename ${GITHUB_REPOSITORY,,})" >> "$GITHUB_OUTPUT" - echo "REPO_BRANCH=${{ github.event.inputs.testbranch || 'dev' }}" >> "$GITHUB_OUTPUT" - - name: Make a cache directory for the container images run: | mkdir -p ./singularity_container_images - download: - runs-on: ubuntu-latest - needs: configure - steps: - name: Download the pipeline env: NXF_SINGULARITY_CACHEDIR: ./singularity_container_images @@ -87,6 +87,9 @@ jobs: - name: Inspect download run: tree ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }} + - name: Inspect container images + run: tree ./singularity_container_images | tee ./container_initial + - name: Count the downloaded number of container images id: count_initial run: | @@ -123,7 +126,8 @@ jobs: final_count=${{ steps.count_afterwards.outputs.IMAGE_COUNT_AFTER }} difference=$((final_count - initial_count)) echo "$difference additional container images were \n downloaded at runtime . The pipeline has no support for offline runs!" - tree ./singularity_container_images + tree ./singularity_container_images > ./container_afterwards + diff ./container_initial ./container_afterwards exit 1 else echo "The pipeline can be downloaded successfully!" From 47af4cbf296fa630debcdc391b6ae5d906c1174d Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Thu, 16 Jan 2025 12:23:49 +0100 Subject: [PATCH 68/70] Update apptainer version --- .github/workflows/download_pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml index ab06316e..3fa3e416 100644 --- a/.github/workflows/download_pipeline.yml +++ b/.github/workflows/download_pipeline.yml @@ -60,7 +60,7 @@ jobs: - name: Setup Apptainer uses: eWaterCycle/setup-apptainer@4bb22c52d4f63406c49e94c804632975787312b3 # v2.0.0 with: - apptainer-version: 1.3.4 + apptainer-version: 1.3.6 - name: Install dependencies run: | From f0c98358c5a7960baa875c61a811d59ab8d00da8 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 22 Jan 2025 11:36:49 +0100 Subject: [PATCH 69/70] Update release date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5f6be8f..fb2c8d6e 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). -## [[1.4.0](https://github.com/nf-core/pixelator/releases/tag/1.4.0)] - 2024-01-16 +## [[1.4.0](https://github.com/nf-core/pixelator/releases/tag/1.4.0)] - 2024-01-22 ### Enhancements & fixes From 6669ebd265bce963efb466ffc5cfd8cddc935ca9 Mon Sep 17 00:00:00 2001 From: Florian De Temmerman Date: Wed, 22 Jan 2025 12:05:11 +0100 Subject: [PATCH 70/70] Fix `process.shell` in `nextflow.config` (https://github.com/nf-core/tools/pull/3416)) --- nextflow.config | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/nextflow.config b/nextflow.config index 5ea1f19f..1d0023da 100644 --- a/nextflow.config +++ b/nextflow.config @@ -269,14 +269,13 @@ env { } // Set bash options -process.shell = """\ -bash - -set -e # Exit if a tool returns a non-zero status/exit code -set -u # Treat unset variables and parameters as an error -set -o pipefail # Returns the status of the last command to exit with a non-zero status or zero if all successfully execute -set -C # No clobber - prevent output redirection from overwriting files. -""" +process.shell = [ + "bash", + "-C", // No clobber - prevent output redirection from overwriting files. + "-e", // Exit if a tool returns a non-zero status/exit code + "-u", // Treat unset variables and parameters as an error + "-o pipefail" // Returns the status of the last command to exit with a non-zero status or zero if all successfully execute +] // Disable process selector warnings by default. Use debug profile to enable warnings. nextflow.enable.configProcessNamesValidation = false