diff --git a/CHANGELOG.md b/CHANGELOG.md
index dccde28..9bb3a0c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,16 +25,18 @@ Initial release of nf-core/deepmutscan, created with the [nf-core](https://nf-co
- DMS library QC per library: count and count-per-coverage heatmaps, sorted count distributions with LogDiff (variants without counts drawn at a floor derived from the data and counted separately; LogDiff not reported when more than 10% of variants have no counts), sliding-window coverage and count profiles (`--sliding_window_size`, `--aimed_cov`), and sequencing-depth rarefaction on a geometric depth grid (`--run_seqdepth`)
- Optional fitness estimation (`--fitness`): merged count tables, experimental design, synonymous wildtype proxy selection, default log-ratio fitness with replicate rescaling and summary statistics, replicate correlation plots and fitness heatmap
- Optional fitness estimation with DiMSum (`--dimsum`) and mutscan edgeR / limma (`--mutscan`)
-- Minimum observation count for a variant to be retained (`--min_counts`, default 1), applied during variant counting; the sequencing-error correction runs on the pre-threshold counts
+- Minimum number of reads a variant needs in every `input` replicate to receive a fitness estimate (`--min_counts`, default 10), applied in the same way by the default estimator, DiMSum and mutscan; variant counting, the sequencing-error correction and the library QC always use all reads
+- Pseudocount for variants that drop out of an `output` replicate (`--output_pseudocount`, default 1; 0 gives dropouts no fitness value)
- Optional interactive 3D variant effect inspection tool built from a user-supplied wildtype structure (`--pdb`)
-- Self-contained, all-in-one run report (`deepmutscan_report.html`) embedding QC, error-correction, fitness, MultiQC and run statistics
+- Self-contained, all-in-one run report (`deepmutscan_report.html`) embedding QC, error-correction, fitness and MultiQC results, with links to Nextflow's execution report and timeline
+- Docker and Singularity images (amd64 and arm64) and conda lock files for all modules, built from each module's `environment.yml`; DiMSum and mutscan are amd64 only for now
- `test` profile on a 50,000 read-pair subsample of a GID1A nicking-mutagenesis GluePCA experiment, with three nf-test pipeline tests (all options; without fitness, error correction, SeqDepth and structure; stub run), and `test_full` profile on the complete dataset (ENA PRJEB110196); test data and the PDB structure are hosted on [nf-core/test-datasets](https://github.com/nf-core/test-datasets/tree/deepmutscan)
### `Dependencies`
| Dependency | Version |
| ------------- | --------------------- |
-| `fastqc` | 0.12.1 |
+| `fastqc` | 0.13.0 |
| `fq` | 0.12.0 |
| `multiqc` | 1.35 |
| `bwa` | 0.7.19 |
diff --git a/assets/summary_report/summary_report_template.html b/assets/summary_report/summary_report_template.html
index f528a5d..bc178a9 100644
--- a/assets/summary_report/summary_report_template.html
+++ b/assets/summary_report/summary_report_template.html
@@ -1319,56 +1319,16 @@
(s) =>
`
| ${esc(s.id)} | ${s.ec ? fmt(s.ec.n_variants) : "–"} | ${s.ec ? fmt(s.ec.total_corrected) : "–"} |
`,
).join("")}`;
- // Run statistics from the Nextflow execution trace (Overview), when it was available.
- const RS = (DATA.run || {}).stats;
- if (RS && RS.processes && RS.processes.length) {
- const dur = (s) => {
- s = Math.round(s);
- if (s < 60) return s + " s";
- const m = Math.floor(s / 60),
- ss = s % 60;
- if (m < 60) return m + "m" + (ss ? " " + ss + "s" : "");
- return Math.floor(m / 60) + "h " + (m % 60) + "m";
- };
- const sz = (b) => {
- if (!b) return "–";
- const u = ["B", "KB", "MB", "GB", "TB"];
- let i = 0;
- while (b >= 1000 && i < u.length - 1) ((b /= 1000), i++);
- return (b < 10 ? b.toFixed(1) : Math.round(b)) + " " + u[i];
- };
- const t = RS.total;
- h += `Run statistics ${info(
- "Per-process compute from Nextflow's execution trace at report time (excludes this report and the trailing version collation). CPU time sums task runtimes; CACHED tasks reused earlier results.",
- )}
`;
- h += `
${[
- ["Tasks", fmt(t.tasks)],
- ["Cached", fmt(t.cached)],
- ["CPU time", dur(t.cpu_time)],
- ["Peak memory", sz(t.peak_rss)],
- ]
- .map(([k, v]) => `
`)
- .join("")}
`;
- h += `
| Process | Tasks | Cached | CPU time | Mean %CPU | Peak RSS |
${RS.processes
- .map(
- (p) =>
- `| ${esc(p.process)} | ${fmt(p.tasks)} | ${fmt(p.cached)} | ${dur(
- p.cpu_time,
- )} | ${p.cpu_pct == null ? "–" : fmt(p.cpu_pct) + "%"} | ${sz(p.peak_rss)} |
`,
- )
- .join("")}
`;
- // Straight into Nextflow's own richer report + timeline, which sit next to this file in
- // pipeline_info/. Relative links, so they resolve when the report is opened from the results
- // folder (the location it is published to).
- const sfx = (DATA.run || {}).trace_report_suffix;
- if (sfx)
- h += `
Nextflow's own outputs, next to this file: execution report ↗ · timeline ↗
`;
- h += `
`;
- }
+ // Run statistics: Nextflow's own execution report and timeline, which sit next to this file in
+ // pipeline_info/. Linked rather than parsed, because the trace is still being written while this
+ // report is built. Relative links resolve when the report is opened from the results folder.
+ const sfx = (DATA.run || {}).trace_report_suffix;
+ if (sfx)
+ h += `Run statistics
Task runtimes, CPU and memory usage of this run are in Nextflow's own reports, next to this file: execution report ↗ · timeline ↗
`;
// README: what this file is and how it maps onto the results folder. The report is meant as
// the way in - a reader should be able to orient here and then find the underlying files.
const ec = r.error_correction && r.error_correction !== "none";
diff --git a/docs/output.md b/docs/output.md
index 3272267..75b9f4a 100644
--- a/docs/output.md
+++ b/docs/output.md
@@ -198,7 +198,7 @@ This tool projects the mean per-residue fitness, coverage, counts, counts per co
-The report brings all the important metrics and visual results of a run together in one file; it can be opened in any browser and shared without any accompanying files. Features are a complete `nf-core` run overview with parameters and execution statistics, interactive sequencing and library QC plots per library, the error-correction report, the fitness results and heatmap (with `--fitness`), the DiMSum and mutscan results (if run), a 3D structure view (with `--pdb`), the MultiQC report, and the citations of all the tools and major dependencies that were used in the run.
+The report brings all the important metrics and visual results of a run together in one file; it can be opened in any browser and shared without any accompanying files. Features are a complete `nf-core` run overview with parameters and links to Nextflow's execution report and timeline, interactive sequencing and library QC plots per library, the error-correction report, the fitness results and heatmap (with `--fitness`), the DiMSum and mutscan results (if run), a 3D structure view (with `--pdb`), the MultiQC report, and the citations of all the tools and major dependencies that were used in the run.

diff --git a/docs/usage.md b/docs/usage.md
index 9fe4ad3..76a02af 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -207,7 +207,7 @@ When `--fitness` is set and a wildtype 3D structure is supplied via `--pdb per-process compute stats
- try:
- run["stats"] = run_stats(path)
- except Exception as exc: # a malformed/partial trace must never sink the whole report
- print(f"WARNING: could not parse execution trace: {exc}")
# Coverage needed for every residue outcome to reach --aimed_cov counts, assuming all 21 outcomes
# are equally represented. Same expression as the reference line in global_position_biases_cov.R;
diff --git a/workflows/deepmutscan.nf b/workflows/deepmutscan.nf
index 25a4bf7..8cac135 100644
--- a/workflows/deepmutscan.nf
+++ b/workflows/deepmutscan.nf
@@ -453,14 +453,6 @@ workflow DEEPMUTSCAN {
ch_report_assets = ch_report_assets.mix(
ch_collated_versions.map { f -> [['versions', 'run', 'versions.yml'], f] }
)
- // Nextflow's own execution trace drives the Overview run-statistics table. It is still being
- // appended to as the report is built, so it captures every compute-heavy task (all but the report
- // task itself) - the page labels it as of report generation. checkIfExists is off because the file
- // is engine-managed, not a process output.
- ch_report_assets = ch_report_assets.mix(
- Channel.fromPath("${outdir}/pipeline_info/execution_trace_${params.trace_report_suffix}.txt", checkIfExists: false)
- .map { f -> [['trace', 'run', 'execution_trace.txt'], f] }
- )
// Sorting keeps the manifest and the staged files in one deterministic, matching order.
def ch_summary_input = ch_report_assets