From c29be20bba0b19cfafcc732a25bf5cfd461a316a Mon Sep 17 00:00:00 2001 From: robert-a-forsyth Date: Wed, 14 Oct 2026 16:58:02 +0200 Subject: [PATCH 1/2] Severus fix: run Severus on the haplotagged BAMs Build severus_input from PHASING_HAPLOTYPING's haplotagged BAMs instead of the unphased minimap2 BAMs, so Severus (and Wakhan, which reads the same channel) see the HP tags. SAVANA already built this channel itself; it now reuses severus_input. Co-Authored-By: Claude Opus 5.5 (1M context) --- CHANGELOG.md | 1 + workflows/lrsomatic.nf | 99 ++++++++++++++++-------------------------- 2 files changed, 38 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ea96028..fa8b59a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### `Fixed` +- [#PR](https://github.com/IntGenomicsLab/lrsomatic/pull/PR) - Fixed the Severus input channel (@robert-a-forsyth). - [#205](https://github.com/IntGenomicsLab/lrsomatic/pull/205) - `PREPARE_AA_DATA_REPO` no longer reads a `versions` output `UNTAR` does not have, which crashed every default GRCh38 run with CoRAL; overriding `--aa_data_repo_url` drops the genome's default MD5 (@robert-a-forsyth). - [#205](https://github.com/IntGenomicsLab/lrsomatic/pull/205) - `-profile test_full` starts again: it skips CoRAL and signatures and carries the chr19 SAVANA workarounds from `test` (@robert-a-forsyth). - [#205](https://github.com/IntGenomicsLab/lrsomatic/pull/205) - `CLAIRSTO_VERDICT_TAG` no longer crashes when ASCAT finds no solution and writes an empty segments table (@robert-a-forsyth). diff --git a/workflows/lrsomatic.nf b/workflows/lrsomatic.nf index 4a606c6f..6fd130a8 100644 --- a/workflows/lrsomatic.nf +++ b/workflows/lrsomatic.nf @@ -867,31 +867,47 @@ workflow LRSOMATIC { ) } - // SEVERUS input: tumor-only and paired samples with their phased germline VCF; [] normal BAM/BAI = tumor-only mode - branched_minimap.tumor_only - .map{ meta, bam, bai -> - def new_meta = meta.subMap('id', - 'paired_data', - 'platform', - 'sex', - 'fiber', - 'clair3_model', - 'clairS_model', - 'clairSTO_model', - 'kinetics') - return[new_meta, bam, bai] + // SEVERUS input: tumor-only and paired samples with their phased germline VCF; [] normal BAM/BAI = tumor-only mode. + // Severus, Wakhan and SAVANA read the HP (haplotype) tag per read, so build it from + // PHASING_HAPLOTYPING's haplotagged BAMs rather than the unphased minimap2 BAMs. + def sv_meta_keys = ['id', 'paired_data', 'platform', 'sex', 'fiber', + 'clair3_model', 'clairS_model', 'clairSTO_model', 'kinetics'] + + PHASING_HAPLOTYPING.out.tumor_normal_hapbams_ch + .branch { meta, _bam, _bai -> + tumor_only: !meta.paired_data + paired_tumor: meta.paired_data && meta.type == 'tumor' + paired_normal: meta.paired_data && meta.type == 'normal' } - .map{meta, tumor_bam, tumor_bai-> + .set { branched_hapbams } + + branched_hapbams.tumor_only + .map { meta, bam, bai -> def normal_bam = [] def normal_bai = [] - return [meta, tumor_bam, tumor_bai, normal_bam, normal_bai] + return [meta.subMap(sv_meta_keys), bam, bai, normal_bam, normal_bai] } - // Mix with paired T/N input (which already has normal BAM/BAI from somatic_smallvar_input) - .mix(somatic_smallvar_input) + .set { tumoronly_hapbams } + + branched_hapbams.paired_tumor + .map { meta, bam, bai -> return [meta.subMap(sv_meta_keys), bam, bai] } + .set { paired_tumor_hapbams } + + branched_hapbams.paired_normal + .map { meta, bam, bai -> return [meta.subMap(sv_meta_keys), bam, bai] } + .set { paired_normal_hapbams } + + paired_tumor_hapbams + .join(paired_normal_hapbams) + .set { paired_hapbams } + // paired_hapbams: [meta, tumor_bam, tumor_bai, normal_bam, normal_bai] + + tumoronly_hapbams + .mix(paired_hapbams) // Attach phased germline VCF (used by SEVERUS for phased SV calling) .join(PHASING_HAPLOTYPING.out.phased_germline_vcf) .set{severus_input} - // severus_input: [meta, tumor_bam, tumor_bai, normal_bam, normal_bai, phased_germline_vcf, phased_germline_tbi] + // severus_input: [meta, tumor_hapbam, tumor_bai, normal_hapbam, normal_bai, phased_germline_vcf, phased_germline_tbi] // normal_bam/bai are empty lists [] for tumor-only samples // @@ -1046,55 +1062,14 @@ workflow LRSOMATIC { savana_allele_counts = channel.empty() if (!params.skip_savana) { - // SAVANA reads the HP (haplotype) tag per read and its README recommends phased BAMs, - // so build its input from PHASING_HAPLOTYPING's haplotagged BAMs rather than the - // unphased ones severus_input carries. - def savana_meta_keys = ['id', 'paired_data', 'platform', 'sex', 'fiber', - 'clair3_model', 'clairS_model', 'clairSTO_model', 'kinetics'] - - PHASING_HAPLOTYPING.out.tumor_normal_hapbams_ch - .branch { meta, _bam, _bai -> - tumor_only: !meta.paired_data - paired_tumor: meta.paired_data && meta.type == 'tumor' - paired_normal: meta.paired_data && meta.type == 'normal' - } - .set { branched_savana_hapbams } - - branched_savana_hapbams.tumor_only - .map { meta, bam, bai -> - def normal_bam = [] - def normal_bai = [] - return [meta.subMap(savana_meta_keys), bam, bai, normal_bam, normal_bai] - } - .set { savana_tumoronly_hapbams } - - branched_savana_hapbams.paired_tumor - .map { meta, bam, bai -> return [meta.subMap(savana_meta_keys), bam, bai] } - .set { savana_paired_tumor_hapbams } - - branched_savana_hapbams.paired_normal - .map { meta, bam, bai -> return [meta.subMap(savana_meta_keys), bam, bai] } - .set { savana_paired_normal_hapbams } - - savana_paired_tumor_hapbams - .join(savana_paired_normal_hapbams) - .set { savana_paired_hapbams } - // savana_paired_hapbams: [meta, tumor_bam, tumor_bai, normal_bam, normal_bai] - - savana_tumoronly_hapbams - .mix(savana_paired_hapbams) - .join(PHASING_HAPLOTYPING.out.phased_germline_vcf) - .set { savana_input } - // savana_input: [meta, tumor_bam, tumor_bai, normal_bam, normal_bai, phased_germline_vcf, phased_germline_tbi] - // normal_bam/bai are [] for tumor-only samples - - savana_input + // SAVANA shares severus_input: haplotagged BAMs with the phased germline VCF + severus_input .branch { meta, _tumor_bam, _tumor_bai, normal_bam, _normal_bai, _phased_vcf, _phased_tbi -> tumor_only: !normal_bam paired: normal_bam } .set { branched_savana_input } - // branched_savana_input.tumor_only / .paired: same 7-tuple shape as savana_input + // branched_savana_input.tumor_only / .paired: same 7-tuple shape as severus_input branched_savana_input.tumor_only .map { meta, tumor_bam, tumor_bai, _normal_bam, _normal_bai, phased_vcf, phased_tbi -> From b6ed88466be559e2700d487da068379e7ae109ce Mon Sep 17 00:00:00 2001 From: robert-a-forsyth Date: Wed, 14 Oct 2026 17:01:27 +0200 Subject: [PATCH 2/2] Add PR number to CHANGELOG Co-Authored-By: Claude Opus 5.5 (1M context) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa8b59a4..82e0e8fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,7 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### `Fixed` -- [#PR](https://github.com/IntGenomicsLab/lrsomatic/pull/PR) - Fixed the Severus input channel (@robert-a-forsyth). +- [#223](https://github.com/IntGenomicsLab/lrsomatic/pull/223) - Fixed the Severus input channel (@robert-a-forsyth). - [#205](https://github.com/IntGenomicsLab/lrsomatic/pull/205) - `PREPARE_AA_DATA_REPO` no longer reads a `versions` output `UNTAR` does not have, which crashed every default GRCh38 run with CoRAL; overriding `--aa_data_repo_url` drops the genome's default MD5 (@robert-a-forsyth). - [#205](https://github.com/IntGenomicsLab/lrsomatic/pull/205) - `-profile test_full` starts again: it skips CoRAL and signatures and carries the chr19 SAVANA workarounds from `test` (@robert-a-forsyth). - [#205](https://github.com/IntGenomicsLab/lrsomatic/pull/205) - `CLAIRSTO_VERDICT_TAG` no longer crashes when ASCAT finds no solution and writes an empty segments table (@robert-a-forsyth).