Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# ampliseq: agents

This is a pipeline repository created with the nf-core pipeline template.
Follow the conventions described in docs/CONTRIBUTING.md.
!!CRITICAL!! For every session ALWAYS fetch and follow the instructions in the remote instruction file at https://raw.githubusercontent.com/nf-core/agents/main/resources/pipeline/AGENTS.md - this is an essential step.

## What this is

nf-core/ampliseq is a Nextflow (DSL2) bioinformatics pipeline for amplicon sequencing analysis (16S, ITS, CO1, 18S, and other markers; single- or multi-region such as 5R). It supports paired/single-end Illumina, PacBio, IonTorrent, and Oxford Nanopore data. It follows nf-core template/community conventions (`.nf-core.yml`, `nf_core_version: 4.0.2`), so most repo-wide conventions come from that template rather than being project-specific.

Core steps: FastQC → primer trimming (Cutadapt/Porechop/Chopper) → DADA2 denoising (ASVs) → optional VSEARCH post-clustering → decontam → Barrnap rRNA check → phylogenetic placement (EPA-NG/gappa) → taxonomic classification (DADA2 RDP, QIIME2, SINTAX, Kraken2, or Sidle multi-region) → QIIME2 downstream stats (barplots, diversity, ANCOM/ANCOM-BC) → Phyloseq/TreeSummarizedExperiment R objects → MultiQC + Rmarkdown summary report.

## Commands

Requires Nextflow, nf-core tools, and nf-test.

Run pipeline tests (small test profiles, requires Docker/Singularity/Conda):

```bash
nf-test test --tag test --profile +docker --verbose
```

Run a single test file:

```bash
nf-test test tests/default.nf.test --profile +docker --verbose
```

Update snapshots after intentional output changes:

```bash
nf-test test --tag test --profile +docker --verbose --update-snapshots
```

Lint (nf-core community rules, run before opening a PR):

```bash
nf-core pipelines lint .
```

Update `nextflow_schema.json` after changing params in `nextflow.config`:

```bash
nf-core pipelines schema build
```

Bump minimum required Nextflow version:

```bash
nf-core pipelines bump-version --nextflow . <min_nf_version>
```

pre-commit hooks (prettier, trailing whitespace, nextflow-lint) run via `prek`/`pre-commit`; CI runs this in `linting.yml`.

### Test profiles

`tests/*.nf.test` each pair with a `conf/test_*.config` profile (e.g. `default` ↔ `test`, `multiregion` ↔ `test_multiregion`, `pplace` ↔ `test_pplace`, `sintax` ↔ `test_sintax`, `fasta` ↔ `test_fasta`). When adding a new test scenario, add both the `.nf.test` file in `tests/` and its matching `conf/test_<name>.config`. Corresponding `.nf.test.snap` files hold expected outputs — regenerate with `--update-snapshots` rather than hand-editing.

Module/subworkflow tests under `modules/nf-core/**/tests` and `subworkflows/nf-core/**/tests` are vendored from nf-core/modules and excluded from local test runs (`ignore` list in `nf-test.config`) — don't hand-edit these, update via `nf-core modules update`.

## Architecture

- `main.nf` — entry point. Declares the pipeline-level `params` schema block, wires `PIPELINE_INITIALISATION` → `NFCORE_AMPLISEQ` (wraps the `AMPLISEQ` workflow) → `PIPELINE_COMPLETION`.
- `workflows/ampliseq.nf` — the single large orchestration workflow (~1400 lines). Nearly all processing logic is assembled here by including local modules/subworkflows and nf-core modules/subworkflows, then wiring channels between them. Whether a given tool runs is driven by `params.skip_*` flags and derived variables (e.g. `single_end`, `asv_calling`) computed near the top of the `AMPLISEQ` workflow.
- `subworkflows/local/` — pipeline-specific multi-step logic, one workflow per pipeline stage, e.g. `parse_input.nf` (sample sheet/input handling), `cutadapt_workflow.nf`, `dada2_preprocessing.nf`, `*_taxonomy_wf.nf` (one per taxonomy classifier: DADA2, SINTAX, Kraken2, VSEARCH-LCA), `qiime2_*.nf` (preptax, taxonomy, export, barplotavg, diversity, ancom), `sidle_wf.nf` (multi-region reconstruction), `robject_workflow.nf` (Phyloseq/TreeSE), `comparison_wf.nf`. `utils_nfcore_ampliseq_pipeline/` holds pipeline init/completion logic and parameter validation (this is where new taxonomy-database validation, e.g. `sbdi_compatible_databases`, is added).
- `subworkflows/nf-core/` and `modules/nf-core/` — vendored, unmodified subworkflows/modules from the nf-core/modules repo (tracked in `modules.json`); update via `nf-core modules/subworkflows update`, don't hand-edit.
- `modules/local/` — pipeline-specific processes (one tool/script invocation per `.nf` file), covering DADA2 steps, QIIME2 steps, taxonomy formatting per classifier, Sidle steps, filtering/stats-merging utilities, and report/export generation.
- `conf/` — config layered by concern: `base.config` (default resource labels), `modules.config` (per-process publishDir/args), `ref_databases.config` (taxonomy DB definitions), `test*.config` (one per test scenario, paired with `tests/*.nf.test`), `containers_*.config` (container digests per engine/arch).
- `assets/schema_input.json` — sample sheet schema validated via the `nf-schema` plugin (`samplesheetToList`).
- `bin/` — helper scripts (Python/R) invoked from `modules/local/*.nf` processes; linted with Ruff (see `pyproject.toml`).

## Conventions (from `docs/CONTRIBUTING.md`)

- PRs target the `dev` branch, not `master`/`main`.
- Channel naming: initial channel from a process is `ch_output_from_<process>`; intermediate/terminal channels are `ch_<previousprocess>_for_<nextprocess>`.
- New params: add to `nextflow.config` (with a default) and to `nextflow_schema.json` via `nf-core pipelines schema build`; also declare in the `params {}` block in `main.nf`.
- New processes: give them resource defaults in `conf/base.config` via `withLabel:` selectors (use standard nf-core labels), and route version info into `ch_versions` and relevant files into `ch_multiqc_files`/`assets/multiqc_config.yml`.
- New taxonomy databases go in `conf/ref_databases.config`, need an `enum` entry in `nextflow_schema.json`, and may need updates in `subworkflows/local/utils_nfcore_ampliseq_pipeline/main.nf` (`sbdi_compatible_databases`).
- Update `docs/usage.md`, `docs/output.md`, and `CITATIONS.md` alongside functional changes.
- AI-assisted PRs: keep them small and focused, avoid incidental refactors/moves, and the human submitter is expected to understand and review all generated code before opening the PR.

## Gotchas

- `results/` and `work/` at the repo root are local Nextflow run artifacts (from prior pipeline executions in this checkout), not source — don't treat their contents as project structure to preserve.
- `.nf-core.yml` disables `nextflow_config`/`schema_params` lint rules ("TODO: Remove when tools supports parameter types") — don't be surprised these are off, it's a known pending upstream fix, not a repo choice to replicate elsewhere.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
| --classifier | --qiime_classifier | |

- [#1028](https://github.com/nf-core/ampliseq/pull/1028) - Multi-region sample sheet via `--multiregion` had its header changed from `FW_primer` and `RV_primer` to `primer_fwd` and `primer_rev`, respectively. (by @d4straub)
- [#1032](https://github.com/nf-core/ampliseq/pull/1032) - Refactor the pipeline's parameter handling and initialization (by @erikrikarddaniel).

### `Fixed`

Expand Down
32 changes: 31 additions & 1 deletion main.nf
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_ampl
//
workflow NFCORE_AMPLISEQ {

take:
ch_metadata // channel: [ path(metadata) ] or empty
ch_report_template // channel: [ path(report_template) ]
ch_report_css // channel: [ path(report_css) ]
ch_report_logo // channel: [ path(report_logo) ]
ch_report_abstract // channel: [ path(report_abstract) ] or []
ch_pplace_sheet // channel: parsed pplace_sheet rows, or empty
ch_expected_sequences // channel: [ path(expected_sequences) ] or empty
ch_expected_abundances // channel: [ path(expected_abundances) ] or empty
ch_metadata_category // channel: tokenized metadata_category, or empty

main:

//
Expand All @@ -41,6 +52,15 @@ workflow NFCORE_AMPLISEQ {
params.multiqc_logo,
params.multiqc_methods_description,
params.outdir,
ch_metadata,
ch_report_template,
ch_report_css,
ch_report_logo,
ch_report_abstract,
ch_pplace_sheet,
ch_expected_sequences,
ch_expected_abundances,
ch_metadata_category,
)
emit:
multiqc_report = AMPLISEQ.out.multiqc_report // channel: /path/to/multiqc_report.html
Expand Down Expand Up @@ -251,7 +271,17 @@ workflow {
//
// WORKFLOW: Run main workflow
//
NFCORE_AMPLISEQ ()
NFCORE_AMPLISEQ (
PIPELINE_INITIALISATION.out.metadata,
PIPELINE_INITIALISATION.out.report_template,
PIPELINE_INITIALISATION.out.report_css,
PIPELINE_INITIALISATION.out.report_logo,
PIPELINE_INITIALISATION.out.report_abstract,
PIPELINE_INITIALISATION.out.pplace_sheet,
PIPELINE_INITIALISATION.out.expected_sequences,
PIPELINE_INITIALISATION.out.expected_abundances,
PIPELINE_INITIALISATION.out.metadata_category,
)

//
// SUBWORKFLOW: Run completion tasks
Expand Down
21 changes: 19 additions & 2 deletions modules/nf-core/cutadapt/cutadapt.diff

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions modules/nf-core/cutadapt/main.nf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 56 additions & 1 deletion subworkflows/local/utils_nfcore_ampliseq_pipeline/main.nf
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,52 @@ workflow PIPELINE_INITIALISATION {

ch_versions = channel.empty()

//
// Build channels from self-contained parameters
// (params only used to construct these channels; no other logic depends on how they're built)
//
if (params.metadata) {
ch_metadata = channel.fromPath( params.metadata )
} else { ch_metadata = channel.empty() }

// report sources
ch_report_template = channel.fromPath("${params.report_template}", checkIfExists: true)
ch_report_css = channel.fromPath("${params.report_css}", checkIfExists: true)
ch_report_logo = channel.fromPath("${params.report_logo}", checkIfExists: true)
ch_report_abstract = params.report_abstract ? channel.fromPath(params.report_abstract) : []

// Parse the --pplace_sheet file if present (may be overwritten later in AMPLISEQ based on --dada_ref_taxonomy)
ch_pplace_sheet = channel.empty()
if ( params.pplace_sheet ) {
ch_pplace_sheet = channel.fromPath(params.pplace_sheet)
.splitCsv(header: true)
.map { it ->
[
meta: [
id: it.target,
min_bitscore: it.min_bitscore
],
data: [
alignmethod: it.alignmethod ?: 'clustalo',
hmm: file(it.hmm, checkIfExists: true),
extract_hmm: it.extract_hmm,
refseqfile: it.refseqfile ? file(it.refseqfile, checkIfExists: true) : [],
refphylogeny: it.refphylogeny ? file(it.refphylogeny, checkIfExists: true) : [],
model: it.model,
taxonomy: it.taxonomy ? file(it.taxonomy, checkIfExists: true) : []
]
]
}
}

ch_expected_sequences = params.expected_sequences ? channel.fromPath( params.expected_sequences ) : channel.empty()
ch_expected_abundances = params.expected_abundances ? channel.fromPath( params.expected_abundances ) : channel.empty()

// Select metadata categories for diversity analysis & ancom, if explicitly specified
if (params.metadata_category) {
ch_metadata_category = channel.fromList(params.metadata_category.tokenize(','))
} else { ch_metadata_category = channel.empty() }

//
// Print version and exit if required and dump pipeline parameters to JSON file
//
Expand Down Expand Up @@ -124,7 +170,16 @@ workflow PIPELINE_INITIALISATION {
}

emit:
versions = ch_versions
versions = ch_versions
metadata = ch_metadata // channel: [ path(metadata) ] or empty
report_template = ch_report_template // channel: [ path(report_template) ]
report_css = ch_report_css // channel: [ path(report_css) ]
report_logo = ch_report_logo // channel: [ path(report_logo) ]
report_abstract = ch_report_abstract // channel: [ path(report_abstract) ] or []
pplace_sheet = ch_pplace_sheet // channel: parsed pplace_sheet rows, or empty
expected_sequences = ch_expected_sequences // channel: [ path(expected_sequences) ] or empty
expected_abundances = ch_expected_abundances // channel: [ path(expected_abundances) ] or empty
metadata_category = ch_metadata_category // channel: tokenized metadata_category, or empty
}

/*
Expand Down
27 changes: 27 additions & 0 deletions tests/default.nf.test
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,31 @@ nextflow_pipeline {
)
}
}

test("-profile test, --report_abstract, --metadata_category") {
// Covers 2 params whose channel construction (in PIPELINE_INITIALISATION) isn't
// exercised by any other test profile: --report_abstract and --metadata_category.
// By default (no --metadata_category), all suitable metadata columns are auto-detected
// for diversity/ancom (e.g. both "treatment1" and "mix8" beta-diversity dirs, see
// tests/default.nf.test.snap); restricting to "treatment1" here should exclude "mix8".
// (Note: alpha-rarefaction plots every metadata column regardless of --metadata_category,
// since QIIME2 reads the metadata file directly there, so it isn't a useful signal.)

when {
params {
outdir = "$outputDir"
report_abstract = "$projectDir/tower.yml"
metadata_category = "treatment1"
}
}

then {
assert workflow.success
assertAll(
{ assert path("$outputDir/summary_report/summary_report.html").text.contains("MultiQC HTML report") },
{ assert path("$outputDir/qiime2/diversity/beta_diversity/bray_curtis_distance_matrix-treatment1/index.html").exists() },
{ assert !file("$outputDir/qiime2/diversity/beta_diversity/bray_curtis_distance_matrix-mix8").exists() },
)
}
}
}
Loading
Loading