diff --git a/CHANGELOG.md b/CHANGELOG.md index 542d2ffa..db7ca789 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | `deepvariant` | 1.9.0 | 1.10.0 | nf-core update; `make_examples` now takes its flags from the model (`--checkpoint`): the ONT model is 199 wide with the new fuzzy channel, and both models call easy sites with the small model | | `deepsomatic` | 1.7.0 | 1.10.0 | `make_examples_somatic` now takes its flags from the model (`--checkpoint`) instead of a hard-coded channel list and pileup width; the paired PacBio model is 147 wide with 9 channels. The small model is kept off explicitly (`--nocall_small_model_examples`), because the module does not pass its calls on | +- [#214](https://github.com/IntGenomicsLab/lrsomatic/pull/214) - Updated Wakhan from 0.4.4 to 0.5.0, run from `docker.io/ljwharbers/wakhan:0.5.0-histfix-1afd44d` (`oras://docker.io/ljwharbers/wakhan-sif:0.5.0-histfix-1afd44d` for Singularity/Apptainer) because no biocontainer was built for it. The image carries upstream commit 1afd44d4, which fixes the `IndexError` in `update_coverage_hist` that killed WAKHAN on some samples (KolmogorovLab/Wakhan#64). **The `wakhan/` output layout changes**: each solution is now `solution_{ploidy}_{purity}_{confidence}/` with `integer_profile.{bed,vcf,html,pdf}` (one boundary-aligned table for both haplotypes, replacing the two `*_HP_{1,2}.bed` files), `subclonal_profile.*`, `genes/genes_copynumber_states.*` and a `HiScanner_plots_data.zip` for the Wakhan web viewer; ranked solutions are `solution_rank_{n}`. Wakhan 0.5.0 no longer writes the per-chromosome `variation_plots`, `genome_copynumbers_details` plots or per-solution `loh_regions*.bed`. `LRSOMATICREPORT` now runs lrsomatic_report v1.6.1 (`ghcr.io/ljwharbers/lrsomatic-report:1.6.1`), which finds the copy-number plots in both layouts; v1.6.0 silently dropped them for 0.5.0 output. The WAKHAN stub now writes the outputs the module declares, and the version comes from `wakhan --version` (@ljwharbers). + ## v1.1.0 - [2026-04-28] ### `Added` diff --git a/docs/output.md b/docs/output.md index 54fb647c..ccc2188c 100644 --- a/docs/output.md +++ b/docs/output.md @@ -626,24 +626,28 @@ Mutational signature analysis of the PASS SNVs and indels in the phased somatic ``` ├── wakhan -│ ├── {ploidy}_{purity}_{confidence} -│ │ ├── bed_output +│ ├── solution_{ploidy}_{purity}_{confidence} +│ │ ├── genes │ │ │ ├── genes_copynumber_states.bed -│ │ │ ├── loh_regions.bed -│ │ │ ├── sample_{ploidy}_{purity}_{confidence}_HP_1.bed -│ │ │ ├── sample_{ploidy}_{purity}_{confidence}_HP_2.bed -│ │ ├── variation_plots -│ │ │ ├── chr{1-22,X,Y}_cn.html -│ │ │ ├── chr{1-22,X,Y}_cn.pdf -│ │ │ ├── CN_VARIATION_INDEX.html -│ │ ├── sample_{purity}_{ploidy}_{confidence}_genes_genome.html -│ │ ├── sample_{purity}_{ploidy}_{confidence}_genes_genome.pdf -│ │ ├── sample_{purity}_{ploidy}_{confidence}_genome_copynumbers_breakpoints.html -│ │ ├── sample_{purity}_{ploidy}_{confidence}_genome_copynumbers_breakpoints.pdf -│ │ ├── sample_{purity}_{ploidy}_{confidence}_genome_copynumbers_details.html -│ │ ├── sample_{purity}_{ploidy}_{confidence}_genome_copynumbers_details.pdf +│ │ │ ├── genes_copynumber_states.html +│ │ │ ├── genes_copynumber_states.pdf +│ │ ├── integer_profile.bed +│ │ ├── integer_profile.html +│ │ ├── integer_profile.pdf +│ │ ├── integer_profile.vcf +│ │ ├── subclonal_profile.bed +│ │ ├── subclonal_profile.html +│ │ ├── subclonal_profile.pdf +│ │ ├── subclonal_profile.vcf +│ │ ├── HiScanner_plots_data.zip +│ ├── solution_rank_{rank} │ ├── coverage_data -│ │ ├── {0-23}_SNPS.csv +│ │ ├── {0-23}_SNPs.csv +│ │ ├── baf.csv +│ │ ├── cancer_genes_coverage.csv +│ │ ├── cn_coverage.png +│ │ ├── cn_peaks.png +│ │ ├── coverage.csv │ │ ├── coverage_ps.csv │ │ ├── phase_corrected_coverage.csv │ │ ├── pileup_SNPs.csv @@ -652,53 +656,36 @@ Mutational signature analysis of the PASS SNVs and indels in the phased somatic │ │ ├── chr{1-22,X,Y}.pdf │ │ ├── COVERAGE_INDEX.html │ ├── phasing_output -│ │ ├── chr{1-22,X,Y}_phase_correction_0.html -│ │ ├── chr{1-22,X,Y}_phase_correction_1.html +│ │ ├── chr{1-22,X,Y}_phase_correction_{0.1,0.2,0.3,1,2}.html │ │ ├── chr{1-22,X,Y}_without_phase_correction.html │ │ ├── chr{1-22,X,Y}.pdf -│ │ ├── sample.rephased.vcf.gz -│ │ ├── sample.rephased.vcf.gz.tbi +│ │ ├── PHASE_CORRECTION_INDEX.html +│ │ ├── rephased.vcf.gz +│ │ ├── rephased.vcf.gz.csi │ ├── snps_loh_plots -│ │ ├── chr{1-22,X,Y}_snps_loh.html -│ ├── sample_heatmap_ploidy_purity.html -│ ├── sample_heatmap_ploidy_purity.html.pdf -│ ├── sample_optimized_peak.html +│ │ ├── {sample}_genome_snps_ratio_loh.html +│ ├── {sample}_heatmap_ploidy_purity.html +│ ├── {sample}_heatmap_ploidy_purity.html.pdf │ ├── solutions_ranks.tsv - ``` -| File | Description | -| ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- | -| `{ploidy}_{purity}_{confidence}/bed_output/genes_copynumber_states.bed` | bed file containing allele specific copy number values with coverage information | -| `{ploidy}_{purity}_{confidence}/bed_output/loh_regions.bed` | bed file containing positions of loss of heterozygosity regions | -| `{ploidy}_{purity}_{confidence}/bed_output/sample_{ploidy}_{purity}_{confidence}_HP_1.bed` | bed file containing copy number states, coverage, and SV breakpoints for haplotype 1 | -| `{ploidy}_{purity}_{confidence}/bed_output/sample_{ploidy}_{purity}_{confidence}_HP_2.bed` | bed file containing copy number states, coverage, and SV breakpoints for haplotype 2 | -| `{ploidy}_{purity}_{confidence}/variation_plots/chr{1-22,X,Y}_cn.html` | html based plotly plot of copy number and coverage for individual chromosomes | -| `{ploidy}_{purity}_{confidence}/variation_plots/chr{1-22,X,Y}_cn.pdf` | pdf based plotly plot of copy number and coverage for individual chromosomes | -| `{ploidy}_{purity}_{confidence}/variation_plots/CN_VARIATION_INDEX.html` | unclear html plot | -| `{ploidy}_{purity}_{confidence}/sample_{purity}_{ploidy}_{confidence}_genes_genome.html` | html plots of copy number variations in highlighted genes | -| `{ploidy}_{purity}_{confidence}/sample_{purity}_{ploidy}_{confidence}_genes_genome.pdf` | pdf plots of copy number variations in highlighted genes | -| `{ploidy}_{purity}_{confidence}/sample_{purity}_{ploidy}_{confidence}_genome_copynumbers_details.html` | genome-wide html copy number plots with coverage information on same axis | -| `{ploidy}_{purity}_{confidence}/sample_{purity}_{ploidy}_{confidence}_genome_copynumbers_details.pdf` | genome-wide pdf copy number plots with coverage information on same axis | -| `coverage_data/{0-23}_SNP.csv` | CSV of coverage data per chromosome | -| `coverage_data/coverage_ps.csv` | CSV of overall haplotype specific coverage data | -| `coverage_data/coverage.csv` | CSV of overall coverage data | -| `coverage_data/phase_corrected_coverage.csv` | CSV of overall phase-corrected coverage data | -| `coverage_data/pileup_SNPs.csv` | CSV of SNP pileup data | -| `coverage_plots/chr{1-22,X,Y}_cov.html` | chromosome specific html coverage plots | -| `coverage_plots/chr{1-22,X,Y}_cov.pdf` | chromosome specific pdf coverage plots | -| `coverage_plots/COVERAGE_INDEX.html` | unclear html plot | -| `phasing_output/chr{1-23,X,Y}_phase_correction_0.html` | Phase-switch error correction plot per chromosome | -| `phasing_output/chr{1-23,X,Y}_phase_correction_1.html` | Phase-switch error correction plot per chromosome | -| `phasing_output/chr{1-22,X,Y}_without_phase_correction.html` | Phase-switch error without phase correction plot per chromosome | -| `phasing_output/chr{1-22,X,Y}.pdf` | Phase-switch error correction plot | -| `phasing_output/sample_rephased.vcf.gz` | phase corrected SNP vcf file | -| `phasing_output/sample_rephased.vcf.gz.tbi` | phase corrected SNP vcf index file | -| `snps_loh_plots/chr{1-22,X,Y}_snps_loh.html` | interactive HTML plots of SNP allele frequencies and loss of heterozygosity regions per chromosome | -| `sample_heatmap_ploidy_purity.html` | heatmap html plot of purity ploidy fit | -| `sample_heatmap_ploidy_purity.html.pdf` | heatmap pdf plot of purity ploidy fit | -| `sample_optimized_peak.html` | optimization peak plot | -| `solutions_ranks.tsv` | rank of potential purity ploidy solutions | +| File | Description | +| ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `solution_{ploidy}_{purity}_{confidence}/integer_profile.bed` | Integer copy-number segments for one purity/ploidy solution, both haplotypes on shared boundaries: coverage, copy-number state and confidence per haplotype, and the IDs of SV breakpoints in the segment | +| `solution_{ploidy}_{purity}_{confidence}/integer_profile.vcf` | The integer copy-number segments as VCF | +| `solution_{ploidy}_{purity}_{confidence}/integer_profile.html` | Interactive genome-wide plot of the integer copy-number profile with SV breakpoints (`.pdf`: static version) | +| `solution_{ploidy}_{purity}_{confidence}/subclonal_profile.*` | The same for subclonal copy-number states (`.bed`, `.vcf`, `.html`, `.pdf`) | +| `solution_{ploidy}_{purity}_{confidence}/genes/genes_copynumber_states.*` | Copy-number states of the genes of interest (`.bed`) and their plots (`.html`, `.pdf`) | +| `solution_{ploidy}_{purity}_{confidence}/HiScanner_plots_data.zip` | The solution's profiles, coverage, BAF and breakpoints bundled for the [Wakhan visualisation web viewer](https://wakhan-visualization.github.io/) | +| `solution_rank_{rank}` | The solution of that rank in `solutions_ranks.tsv` (a copy of its `solution_{ploidy}_{purity}_{confidence}` directory) | +| `coverage_data/*.csv` | Per-chromosome SNP tables, BAF, haplotype-specific and phase-corrected coverage, and SNP pileups; tumour-only runs also write `{sample}_loh_segments.csv` | +| `coverage_data/*.png` | Copy-number coverage and peak plots | +| `coverage_plots/chr{1-22,X,Y}_cov.html` | Coverage plot per chromosome (`.pdf`: static version); `COVERAGE_INDEX.html` links them | +| `phasing_output/*.html` | Phase-switch error plots per chromosome, with and without correction; `PHASE_CORRECTION_INDEX.html` links them | +| `phasing_output/rephased.vcf.gz` | Phase-corrected SNP VCF, with its `.csi` index | +| `snps_loh_plots/{sample}_genome_snps_ratio_loh.html` | SNP allele ratios and loss-of-heterozygosity regions (tumour-only runs) | +| `{sample}_heatmap_ploidy_purity.html` | Heatmap of the purity/ploidy fit (`.html.pdf`: static version) | +| `solutions_ranks.tsv` | Ranked purity/ploidy solutions; `repository_name` is the solution's directory | diff --git a/modules/local/lrsomaticreport/main.nf b/modules/local/lrsomaticreport/main.nf index 6724a2be..683ebdf7 100644 --- a/modules/local/lrsomaticreport/main.nf +++ b/modules/local/lrsomaticreport/main.nf @@ -5,8 +5,8 @@ process LRSOMATICREPORT { // No conda: the image ships render_report.R itself, not just its dependencies (guard in `script:`). // TODO: switch to bioconda `lrsomatic-report` once the recipe in ljwharbers/lrsomatic_report is merged. Version bump = these two tags. container "${(workflow.containerEngine == 'singularity' || workflow.containerEngine == 'apptainer') && !task.ext.singularity_pull_docker_container - ? 'oras://ghcr.io/ljwharbers/lrsomatic-report-sif:1.6.0' - : 'ghcr.io/ljwharbers/lrsomatic-report:1.6.0'}" + ? 'oras://ghcr.io/ljwharbers/lrsomatic-report-sif:1.6.1' + : 'ghcr.io/ljwharbers/lrsomatic-report:1.6.1'}" input: // Every path input is optional (`[]` when skipped); tumor/normal QC stage apart because a pair shares meta.id diff --git a/modules/local/lrsomaticreport/tests/main.nf.test.snap b/modules/local/lrsomaticreport/tests/main.nf.test.snap index fdf944d0..ca0029e3 100644 --- a/modules/local/lrsomaticreport/tests/main.nf.test.snap +++ b/modules/local/lrsomaticreport/tests/main.nf.test.snap @@ -16,7 +16,7 @@ [ "LRSOMATICREPORT", "lrsomatic_report", - "1.6.0" + "1.6.1" ] ], "report": [ @@ -33,7 +33,7 @@ [ "LRSOMATICREPORT", "lrsomatic_report", - "1.6.0" + "1.6.1" ] ] } @@ -50,7 +50,7 @@ [ "LRSOMATICREPORT", "lrsomatic_report", - "1.6.0" + "1.6.1" ] ] ], diff --git a/modules/local/wakhan/environment.yml b/modules/local/wakhan/environment.yml index 747954d5..1b3cfed8 100644 --- a/modules/local/wakhan/environment.yml +++ b/modules/local/wakhan/environment.yml @@ -5,4 +5,4 @@ channels: - bioconda dependencies: # renovate: datasource=conda depName=bioconda/wakhan - - bioconda::wakhan=0.4.4 + - bioconda::wakhan=0.5.0 diff --git a/modules/local/wakhan/main.nf b/modules/local/wakhan/main.nf index c768c397..f0acfcc2 100644 --- a/modules/local/wakhan/main.nf +++ b/modules/local/wakhan/main.nf @@ -3,9 +3,14 @@ process WAKHAN { label 'process_medium' conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/wakhan:0.4.4--pyhdfd78af_0' : - 'biocontainers/wakhan:0.4.4--pyhdfd78af_0' }" + // No biocontainer was built for 0.5.0. This image is bioconda::wakhan=0.5.0 plus upstream commit + // 1afd44d4 (KolmogorovLab/Wakhan#64), which stops update_coverage_hist raising IndexError on reads + // past a chromosome's last coverage bin. Recipe: + // https://github.com/ljwharbers/Wakhan/tree/container/0.5.0-histfix/container + // Docker Hub rather than ghcr, for the reason given in modules/local/clairsto/main.nf. + container "${(workflow.containerEngine == 'singularity' || workflow.containerEngine == 'apptainer') && !task.ext.singularity_pull_docker_container + ? 'oras://docker.io/ljwharbers/wakhan-sif:0.5.0-histfix-1afd44d' + : 'docker.io/ljwharbers/wakhan:0.5.0-histfix-1afd44d'}" input: tuple val(meta), path(tumor_input), path(tumor_index), path(normal_input), path(normal_index), path(vcf), path(breakpoints) @@ -13,17 +18,15 @@ process WAKHAN { path(centromere_bed) output: - tuple val(meta), path("*/*_genes_genome.html") , emit: genes_genome_html - tuple val(meta), path("*/*_genes_genome.pdf") , emit: genes_genome_pdf - tuple val(meta), path("*/*_genome_copynumbers_breakpoints.html") , emit: breakpoints_html - tuple val(meta), path("*/*_genome_copynumbers_breakpoints.pdf") , emit: breakpoints_pdf - tuple val(meta), path("*/*_genome_copynumbers_breakpoints_subclonal.html") , emit: breakpoints_subclonal_html - tuple val(meta), path("*/*_genome_copynumbers_breakpoints_subclonal.pdf") , emit: breakpoints_subclonal_pdf - tuple val(meta), path("*/*_genome_copynumbers_details.html") , emit: copynumbers_details_html - tuple val(meta), path("*/*_genome_copynumbers_details.pdf") , emit: copynumbers_details_pdf - tuple val(meta), path("*/bed_output/*.bed") , emit: bed_files - tuple val(meta), path("*/variation_plots/*.html") , emit: variation_plots - tuple val(meta), path("*/vcf_output/*_wakhan_cna_*.vcf") , emit: vcf_files + // Per-solution outputs live in solution___/; solution_rank_ links to them + tuple val(meta), path("solution_*_*_*/integer_profile.html") , emit: integer_profile_html + tuple val(meta), path("solution_*_*_*/integer_profile.pdf") , emit: integer_profile_pdf + tuple val(meta), path("solution_*_*_*/integer_profile.{bed,vcf}") , emit: integer_profile + tuple val(meta), path("solution_*_*_*/subclonal_profile.html") , emit: subclonal_profile_html + tuple val(meta), path("solution_*_*_*/subclonal_profile.pdf") , emit: subclonal_profile_pdf + tuple val(meta), path("solution_*_*_*/subclonal_profile.{bed,vcf}") , emit: subclonal_profile + tuple val(meta), path("solution_*_*_*/genes/genes_copynumber_states.*") , emit: genes + tuple val(meta), path("solution_*_*_*/HiScanner_plots_data.zip") , emit: hiscanner_zip tuple val(meta), path("*_heatmap_ploidy_purity.html") , emit: heatmap_html tuple val(meta), path("*_heatmap_ploidy_purity.html.pdf") , emit: heatmap_pdf tuple val(meta), path("coverage_data/*.csv") , emit: coverage_csv @@ -37,10 +40,9 @@ process WAKHAN { tuple val(meta), path("snps_loh_plots/*_genome_snps_ratio_loh.html") , emit: snps_loh_plot, optional: true tuple val(meta), path("solutions_ranks.tsv") , emit: solutions_ranks // Whole directories, not the plots inside: every solution's plot has the same basename, - // and LRSOMATICREPORT resolves them by solution_/ path - tuple val(meta), path("solution_*", type: 'dir') , emit: solution_dirs, optional: true - // WARN: Manually update version information as tool does not provide on CLI - tuple val("${task.process}"), val('wakhan'), val("0.4.4"), topic: versions, emit: versions_wakhan + // and LRSOMATICREPORT resolves them by rank directory + tuple val(meta), path("solution_rank_*", type: 'dir') , emit: solution_dirs, optional: true + tuple val("${task.process}"), val('wakhan'), eval("wakhan --version 2>/dev/null | sed 's/^wakhan //'"), topic: versions, emit: versions_wakhan when: task.ext.when == null || task.ext.when @@ -49,7 +51,7 @@ process WAKHAN { def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" def phased_vcf = normal_input ? "--normal-phased-vcf $vcf" : "--tumor-phased-vcf $vcf" - def centromere = centromere_bed ? "--centromere \$PWD/${centromere_bed}" : "" + def centromere = centromere_bed ? "--centromere-bed \$PWD/${centromere_bed}" : "" """ wakhan \\ @@ -67,8 +69,21 @@ process WAKHAN { stub: def prefix = task.ext.prefix ?: "${meta.id}" - """ - touch ${prefix}.bam + sol=solution_2.0_0.8_0.9 + mkdir -p \$sol/genes coverage_data coverage_plots phasing_output snps_loh_plots + for f in integer_profile subclonal_profile; do + touch \$sol/\$f.html \$sol/\$f.pdf \$sol/\$f.bed \$sol/\$f.vcf + done + touch \$sol/genes/genes_copynumber_states.html \$sol/genes/genes_copynumber_states.pdf \$sol/genes/genes_copynumber_states.bed + touch \$sol/HiScanner_plots_data.zip + ln -s \$sol solution_rank_1 + touch ${prefix}_heatmap_ploidy_purity.html ${prefix}_heatmap_ploidy_purity.html.pdf + touch coverage_data/coverage.csv coverage_data/cn_peaks.png coverage_plots/COVERAGE_INDEX.html coverage_plots/chr1.pdf + touch phasing_output/PHASE_CORRECTION_INDEX.html phasing_output/chr1.pdf + echo "" | gzip > phasing_output/rephased.vcf.gz + touch phasing_output/rephased.vcf.gz.csi + touch snps_loh_plots/${prefix}_genome_snps_ratio_loh.html + printf 'repository_name\\tdna_purity\\tcell_purity\\tploidy\\tconfidence\\tsolution_rank\\n%s\\t0.8\\t0.8\\t2.0\\t0.9\\t1\\n' \$sol > solutions_ranks.tsv """ } diff --git a/modules/local/wakhan/meta.yml b/modules/local/wakhan/meta.yml index ee0a90c1..6dc4cbce 100644 --- a/modules/local/wakhan/meta.yml +++ b/modules/local/wakhan/meta.yml @@ -58,116 +58,86 @@ input: pattern: "*.{fasta,fa,fna}" output: - genes_genome_html: + integer_profile_html: - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*/*_genes_genome.html": + - "solution_*_*_*/integer_profile.html": type: file - description: Genes genome HTML plot - pattern: "*/*_genes_genome.html" - genes_genome_pdf: + description: Per-solution integer copy-number profile plot (HTML) + pattern: "solution_*_*_*/integer_profile.html" + integer_profile_pdf: - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*/*_genes_genome.pdf": + - "solution_*_*_*/integer_profile.pdf": type: file - description: Genes genome PDF plot - pattern: "*/*_genes_genome.pdf" - breakpoints_html: + description: Per-solution integer copy-number profile plot (PDF) + pattern: "solution_*_*_*/integer_profile.pdf" + integer_profile: - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*/*_genome_copynumbers_breakpoints.html": + - "solution_*_*_*/integer_profile.{bed,vcf}": type: file - description: Genome copy numbers with breakpoints HTML plot - pattern: "*/*_genome_copynumbers_breakpoints.html" - breakpoints_pdf: + description: Per-solution integer copy-number segments, both haplotypes boundary-aligned (BED and VCF) + pattern: "solution_*_*_*/integer_profile.{bed,vcf}" + subclonal_profile_html: - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*/*_genome_copynumbers_breakpoints.pdf": + - "solution_*_*_*/subclonal_profile.html": type: file - description: Genome copy numbers with breakpoints PDF plot - pattern: "*/*_genome_copynumbers_breakpoints.pdf" - breakpoints_subclonal_html: + description: Per-solution subclonal copy-number profile plot (HTML) + pattern: "solution_*_*_*/subclonal_profile.html" + subclonal_profile_pdf: - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*/*_genome_copynumbers_breakpoints_subclonal.html": + - "solution_*_*_*/subclonal_profile.pdf": type: file - description: Genome copy numbers with subclonal breakpoints HTML plot - pattern: "*/*_genome_copynumbers_breakpoints_subclonal.html" - breakpoints_subclonal_pdf: + description: Per-solution subclonal copy-number profile plot (PDF) + pattern: "solution_*_*_*/subclonal_profile.pdf" + subclonal_profile: - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*/*_genome_copynumbers_breakpoints_subclonal.pdf": + - "solution_*_*_*/subclonal_profile.{bed,vcf}": type: file - description: Genome copy numbers with subclonal breakpoints PDF plot - pattern: "*/*_genome_copynumbers_breakpoints_subclonal.pdf" - copynumbers_details_html: + description: Per-solution subclonal copy-number segments (BED and VCF) + pattern: "solution_*_*_*/subclonal_profile.{bed,vcf}" + genes: - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*/*_genome_copynumbers_details.html": + - "solution_*_*_*/genes/genes_copynumber_states.*": type: file - description: Genome copy numbers details HTML plot - pattern: "*/*_genome_copynumbers_details.html" - copynumbers_details_pdf: + description: Per-solution gene copy-number states (BED, HTML and PDF) + pattern: "solution_*_*_*/genes/genes_copynumber_states.*" + hiscanner_zip: - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*/*_genome_copynumbers_details.pdf": + - "solution_*_*_*/HiScanner_plots_data.zip": type: file - description: Genome copy numbers details PDF plot - pattern: "*/*_genome_copynumbers_details.pdf" - bed_files: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'sample1', single_end:false ]` - - "*/bed_output/*.bed": - type: file - description: BED output files - pattern: "*/bed_output/*.bed" - variation_plots: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'sample1', single_end:false ]` - - "*/variation_plots/*.html": - type: file - description: Variation plots HTML files - pattern: "*/variation_plots/*.html" - vcf_files: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'sample1', single_end:false ]` - - "*/vcf_output/*_wakhan_cna_*.vcf": - type: file - description: Wakhan CNA VCF files - pattern: "*/vcf_output/*_wakhan_cna_*.vcf" + description: Per-solution bundle for the Wakhan visualisation web viewer + pattern: "solution_*_*_*/HiScanner_plots_data.zip" heatmap_html: - meta: type: map @@ -176,7 +146,7 @@ output: e.g. `[ id:'sample1', single_end:false ]` - "*_heatmap_ploidy_purity.html": type: file - description: Heatmap ploidy purity HTML plot + description: Ploidy/purity heatmap (HTML) pattern: "*_heatmap_ploidy_purity.html" heatmap_pdf: - meta: @@ -186,28 +156,28 @@ output: e.g. `[ id:'sample1', single_end:false ]` - "*_heatmap_ploidy_purity.html.pdf": type: file - description: Heatmap ploidy purity PDF plot + description: Ploidy/purity heatmap (PDF) pattern: "*_heatmap_ploidy_purity.html.pdf" - optimized_peak_html: + coverage_csv: - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*_optimized_peak.html": + - "coverage_data/*.csv": type: file - description: Optimized peak HTML plot - pattern: "*_optimized_peak.html" - coverage_csv: + description: Coverage, BAF and SNP tables + pattern: "coverage_data/*.csv" + coverage_png: - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "coverage_data/*.csv": + - "coverage_data/*.png": type: file - description: Coverage data CSV files - pattern: "coverage_data/*.csv" + description: Copy-number coverage and peak plots + pattern: "coverage_data/*.png" coverage_plots_html: - meta: type: map @@ -216,7 +186,7 @@ output: e.g. `[ id:'sample1', single_end:false ]` - "coverage_plots/*.html": type: file - description: Coverage plots HTML files + description: Per-chromosome coverage plots (HTML) pattern: "coverage_plots/*.html" coverage_plots_pdf: - meta: @@ -226,7 +196,7 @@ output: e.g. `[ id:'sample1', single_end:false ]` - "coverage_plots/*.pdf": type: file - description: Coverage plots PDF files + description: Per-chromosome coverage plots (PDF) pattern: "coverage_plots/*.pdf" phasing_html: - meta: @@ -236,7 +206,7 @@ output: e.g. `[ id:'sample1', single_end:false ]` - "phasing_output/*.html": type: file - description: Phasing output HTML plots + description: Phase-correction plots (HTML) pattern: "phasing_output/*.html" phasing_pdf: - meta: @@ -246,7 +216,7 @@ output: e.g. `[ id:'sample1', single_end:false ]` - "phasing_output/*.pdf": type: file - description: Phasing output PDF plots + description: Phase-correction plots (PDF) pattern: "phasing_output/*.pdf" rephased_vcf: - meta: @@ -254,20 +224,20 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "phasing_output/*.rephased.vcf.gz": + - "phasing_output/*rephased.vcf.gz": type: file - description: Rephased VCF file - pattern: "phasing_output/*.rephased.vcf.gz" + description: Phase-corrected VCF + pattern: "phasing_output/*rephased.vcf.gz" rephased_vcf_index: - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "phasing_output/*.rephased.vcf.gz.csi": + - "phasing_output/*rephased.vcf.gz.csi": type: file - description: Rephased VCF index file - pattern: "phasing_output/*.rephased.vcf.gz.csi" + description: Index of the phase-corrected VCF + pattern: "phasing_output/*rephased.vcf.gz.csi" snps_loh_plot: - meta: type: map @@ -276,7 +246,7 @@ output: e.g. `[ id:'sample1', single_end:false ]` - "snps_loh_plots/*_genome_snps_ratio_loh.html": type: file - description: SNPs LOH plot HTML file + description: SNP ratio / LOH plot (tumour-only runs) pattern: "snps_loh_plots/*_genome_snps_ratio_loh.html" solutions_ranks: - meta: @@ -286,31 +256,39 @@ output: e.g. `[ id:'sample1', single_end:false ]` - "solutions_ranks.tsv": type: file - description: Solutions ranks TSV file + description: Ranked ploidy/purity solutions pattern: "solutions_ranks.tsv" + solution_dirs: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1', single_end:false ]` + - "solution_rank_*": + type: directory + description: Ranked solution directories (links to solution___) versions_wakhan: - - ${task.process}: type: string - description: The process the versions were collected from + description: The name of the process - wakhan: type: string - description: The tool name - - "0.2.0": - type: string - description: The version of wakhan + description: The name of the tool + - wakhan --version 2>/dev/null | sed 's/^wakhan //': + type: eval + description: The expression to obtain the version of the tool topics: versions: - - ${task.process}: type: string - description: The process the versions were collected from + description: The name of the process - wakhan: type: string - description: The tool name - - "0.2.0": - type: string - description: The version of wakhan - + description: The name of the tool + - wakhan --version 2>/dev/null | sed 's/^wakhan //': + type: eval + description: The expression to obtain the version of the tool authors: - "@ljwharbers" maintainers: diff --git a/modules/local/wakhan/tests/main.nf.test b/modules/local/wakhan/tests/main.nf.test new file mode 100644 index 00000000..ffd7f903 --- /dev/null +++ b/modules/local/wakhan/tests/main.nf.test @@ -0,0 +1,56 @@ +nextflow_process { + + name "Test Process WAKHAN" + script "../main.nf" + process "WAKHAN" + + tag "modules" + tag "modules_local" + tag "wakhan" + tag "small" + + // Wakhan needs whole-genome coverage to fit a solution, so only the stub runs in CI. It checks the + // output declarations against the 0.5.0 layout, the solution_rank_* link, and the version read from + // the image. The inputs are stand-ins: the stub never reads them. + test("paired - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test', paired_data:true ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test2.paired_end.sorted.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test2.paired_end.sorted.bam.bai', checkIfExists: true), + file("${projectDir}/modules/local/clairsto/verdict_tag/tests/fixtures/snv.vcf.gz", checkIfExists: true), + file("${projectDir}/modules/local/clairsto/verdict_tag/tests/fixtures/indel.vcf.gz", checkIfExists: true) + ] + input[1] = [ + [ id:'genome' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ] + input[2] = file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.bed', checkIfExists: true) + """ + } + } + + then { + def rank_dir = path(process.out.solution_dirs[0][1].toString()) + + assertAll( + { assert process.success }, + // Every declared output channel was filled + { assert process.out.findAll { name, ch -> !(name ==~ /\d+/) }.every { name, ch -> ch.size() == 1 } }, + // The rank link is captured as a directory that resolves to the solution it ranks, + // which is how LRSOMATICREPORT finds the per-solution plots + { assert rank_dir.fileName.toString() == 'solution_rank_1' }, + { assert rank_dir.toRealPath().fileName.toString() == 'solution_2.0_0.8_0.9' }, + { assert rank_dir.resolve('integer_profile.html').toFile().exists() }, + { assert snapshot(process.out).match() } + ) + } + } +} diff --git a/modules/local/wakhan/tests/main.nf.test.snap b/modules/local/wakhan/tests/main.nf.test.snap new file mode 100644 index 00000000..fcb2be8a --- /dev/null +++ b/modules/local/wakhan/tests/main.nf.test.snap @@ -0,0 +1,455 @@ +{ + "paired - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "paired_data": true + }, + "integer_profile.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "paired_data": true + }, + "integer_profile.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "10": [ + [ + { + "id": "test", + "paired_data": true + }, + "coverage.csv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "11": [ + [ + { + "id": "test", + "paired_data": true + }, + "cn_peaks.png:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "12": [ + [ + { + "id": "test", + "paired_data": true + }, + "COVERAGE_INDEX.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "13": [ + [ + { + "id": "test", + "paired_data": true + }, + "chr1.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "14": [ + [ + { + "id": "test", + "paired_data": true + }, + "PHASE_CORRECTION_INDEX.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "15": [ + [ + { + "id": "test", + "paired_data": true + }, + "chr1.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "16": [ + [ + { + "id": "test", + "paired_data": true + }, + "rephased.vcf.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "17": [ + [ + { + "id": "test", + "paired_data": true + }, + "rephased.vcf.gz.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "18": [ + [ + { + "id": "test", + "paired_data": true + }, + "test_genome_snps_ratio_loh.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "19": [ + [ + { + "id": "test", + "paired_data": true + }, + "solutions_ranks.tsv:md5,563b0692a9825c94b2f1d3bf1397cdaf" + ] + ], + "2": [ + [ + { + "id": "test", + "paired_data": true + }, + [ + "integer_profile.bed:md5,d41d8cd98f00b204e9800998ecf8427e", + "integer_profile.vcf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "20": [ + [ + { + "id": "test", + "paired_data": true + }, + [ + "HiScanner_plots_data.zip:md5,d41d8cd98f00b204e9800998ecf8427e", + [ + "genes_copynumber_states.bed:md5,d41d8cd98f00b204e9800998ecf8427e", + "genes_copynumber_states.html:md5,d41d8cd98f00b204e9800998ecf8427e", + "genes_copynumber_states.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ], + "integer_profile.bed:md5,d41d8cd98f00b204e9800998ecf8427e", + "integer_profile.html:md5,d41d8cd98f00b204e9800998ecf8427e", + "integer_profile.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "integer_profile.vcf:md5,d41d8cd98f00b204e9800998ecf8427e", + "subclonal_profile.bed:md5,d41d8cd98f00b204e9800998ecf8427e", + "subclonal_profile.html:md5,d41d8cd98f00b204e9800998ecf8427e", + "subclonal_profile.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "subclonal_profile.vcf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "21": [ + [ + "WAKHAN", + "wakhan", + "0.5.0" + ] + ], + "3": [ + [ + { + "id": "test", + "paired_data": true + }, + "subclonal_profile.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + [ + { + "id": "test", + "paired_data": true + }, + "subclonal_profile.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "5": [ + [ + { + "id": "test", + "paired_data": true + }, + [ + "subclonal_profile.bed:md5,d41d8cd98f00b204e9800998ecf8427e", + "subclonal_profile.vcf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "6": [ + [ + { + "id": "test", + "paired_data": true + }, + [ + "genes_copynumber_states.bed:md5,d41d8cd98f00b204e9800998ecf8427e", + "genes_copynumber_states.html:md5,d41d8cd98f00b204e9800998ecf8427e", + "genes_copynumber_states.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "7": [ + [ + { + "id": "test", + "paired_data": true + }, + "HiScanner_plots_data.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "8": [ + [ + { + "id": "test", + "paired_data": true + }, + "test_heatmap_ploidy_purity.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "9": [ + [ + { + "id": "test", + "paired_data": true + }, + "test_heatmap_ploidy_purity.html.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "coverage_csv": [ + [ + { + "id": "test", + "paired_data": true + }, + "coverage.csv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "coverage_plots_html": [ + [ + { + "id": "test", + "paired_data": true + }, + "COVERAGE_INDEX.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "coverage_plots_pdf": [ + [ + { + "id": "test", + "paired_data": true + }, + "chr1.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "coverage_png": [ + [ + { + "id": "test", + "paired_data": true + }, + "cn_peaks.png:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "genes": [ + [ + { + "id": "test", + "paired_data": true + }, + [ + "genes_copynumber_states.bed:md5,d41d8cd98f00b204e9800998ecf8427e", + "genes_copynumber_states.html:md5,d41d8cd98f00b204e9800998ecf8427e", + "genes_copynumber_states.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "heatmap_html": [ + [ + { + "id": "test", + "paired_data": true + }, + "test_heatmap_ploidy_purity.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "heatmap_pdf": [ + [ + { + "id": "test", + "paired_data": true + }, + "test_heatmap_ploidy_purity.html.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "hiscanner_zip": [ + [ + { + "id": "test", + "paired_data": true + }, + "HiScanner_plots_data.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "integer_profile": [ + [ + { + "id": "test", + "paired_data": true + }, + [ + "integer_profile.bed:md5,d41d8cd98f00b204e9800998ecf8427e", + "integer_profile.vcf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "integer_profile_html": [ + [ + { + "id": "test", + "paired_data": true + }, + "integer_profile.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "integer_profile_pdf": [ + [ + { + "id": "test", + "paired_data": true + }, + "integer_profile.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "phasing_html": [ + [ + { + "id": "test", + "paired_data": true + }, + "PHASE_CORRECTION_INDEX.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "phasing_pdf": [ + [ + { + "id": "test", + "paired_data": true + }, + "chr1.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "rephased_vcf": [ + [ + { + "id": "test", + "paired_data": true + }, + "rephased.vcf.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "rephased_vcf_index": [ + [ + { + "id": "test", + "paired_data": true + }, + "rephased.vcf.gz.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "snps_loh_plot": [ + [ + { + "id": "test", + "paired_data": true + }, + "test_genome_snps_ratio_loh.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "solution_dirs": [ + [ + { + "id": "test", + "paired_data": true + }, + [ + "HiScanner_plots_data.zip:md5,d41d8cd98f00b204e9800998ecf8427e", + [ + "genes_copynumber_states.bed:md5,d41d8cd98f00b204e9800998ecf8427e", + "genes_copynumber_states.html:md5,d41d8cd98f00b204e9800998ecf8427e", + "genes_copynumber_states.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ], + "integer_profile.bed:md5,d41d8cd98f00b204e9800998ecf8427e", + "integer_profile.html:md5,d41d8cd98f00b204e9800998ecf8427e", + "integer_profile.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "integer_profile.vcf:md5,d41d8cd98f00b204e9800998ecf8427e", + "subclonal_profile.bed:md5,d41d8cd98f00b204e9800998ecf8427e", + "subclonal_profile.html:md5,d41d8cd98f00b204e9800998ecf8427e", + "subclonal_profile.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "subclonal_profile.vcf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "solutions_ranks": [ + [ + { + "id": "test", + "paired_data": true + }, + "solutions_ranks.tsv:md5,563b0692a9825c94b2f1d3bf1397cdaf" + ] + ], + "subclonal_profile": [ + [ + { + "id": "test", + "paired_data": true + }, + [ + "subclonal_profile.bed:md5,d41d8cd98f00b204e9800998ecf8427e", + "subclonal_profile.vcf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "subclonal_profile_html": [ + [ + { + "id": "test", + "paired_data": true + }, + "subclonal_profile.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "subclonal_profile_pdf": [ + [ + { + "id": "test", + "paired_data": true + }, + "subclonal_profile.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_wakhan": [ + [ + "WAKHAN", + "wakhan", + "0.5.0" + ] + ] + } + ], + "timestamp": "2026-10-01T15:42:20.391785654", + "meta": { + "nf-test": "0.9.4", + "nextflow": "26.04.3" + } + } +} \ No newline at end of file diff --git a/tests/chm13.nf.test.snap b/tests/chm13.nf.test.snap index 4327cb72..60506cbf 100644 --- a/tests/chm13.nf.test.snap +++ b/tests/chm13.nf.test.snap @@ -50,7 +50,7 @@ "longphase": "2.0.1" }, "LRSOMATICREPORT": { - "lrsomatic_report": "1.6.0" + "lrsomatic_report": "1.6.1" }, "METAEXTRACT": { "samtools": 1.24 diff --git a/tests/clair_only.nf.test.snap b/tests/clair_only.nf.test.snap index 5a1b8866..0529ec6d 100644 --- a/tests/clair_only.nf.test.snap +++ b/tests/clair_only.nf.test.snap @@ -60,7 +60,7 @@ "longphase": "2.0.1" }, "LRSOMATICREPORT": { - "lrsomatic_report": "1.6.0" + "lrsomatic_report": "1.6.1" }, "METAEXTRACT": { "samtools": 1.24 diff --git a/tests/consensus.nf.test.snap b/tests/consensus.nf.test.snap index d8b7d765..6a639067 100644 --- a/tests/consensus.nf.test.snap +++ b/tests/consensus.nf.test.snap @@ -80,7 +80,7 @@ "longphase": "2.0.1" }, "LRSOMATICREPORT": { - "lrsomatic_report": "1.6.0" + "lrsomatic_report": "1.6.1" }, "METAEXTRACT": { "samtools": 1.24 diff --git a/tests/deep_only.nf.test.snap b/tests/deep_only.nf.test.snap index a0c453c1..26324ae1 100644 --- a/tests/deep_only.nf.test.snap +++ b/tests/deep_only.nf.test.snap @@ -56,7 +56,7 @@ "longphase": "2.0.1" }, "LRSOMATICREPORT": { - "lrsomatic_report": "1.6.0" + "lrsomatic_report": "1.6.1" }, "METAEXTRACT": { "samtools": 1.24 diff --git a/tests/default.nf.test.snap b/tests/default.nf.test.snap index e7e6b434..46b3525a 100644 --- a/tests/default.nf.test.snap +++ b/tests/default.nf.test.snap @@ -47,7 +47,7 @@ "longphase": "2.0.1" }, "LRSOMATICREPORT": { - "lrsomatic_report": "1.6.0" + "lrsomatic_report": "1.6.1" }, "METAEXTRACT": { "samtools": 1.24 diff --git a/tests/union.nf.test.snap b/tests/union.nf.test.snap index 9bd00070..ebc7753d 100644 --- a/tests/union.nf.test.snap +++ b/tests/union.nf.test.snap @@ -77,7 +77,7 @@ "longphase": "2.0.1" }, "LRSOMATICREPORT": { - "lrsomatic_report": "1.6.0" + "lrsomatic_report": "1.6.1" }, "METAEXTRACT": { "samtools": 1.24