Keep records with conflicting mod probabilities; fix pileup on PacBio (Jasmine) tags - #720
Keep records with conflicting mod probabilities; fix pileup on PacBio (Jasmine) tags#720ljwharbers wants to merge 2 commits into
Conversation
… tags PacBio Jasmine (>= 26.1.3) calls 5mC and 5hmC with independent models and writes them as separate `C+m?` and `C+h?`/`G-h?` sub-tags, so at a CpG the probabilities can sum to well over 1.0. modkit rejected the entire record (`conflict-explicit-prob-greater-than-one`) in adjust-mods, update-tags, call-mods, extract, summary, sample-probs and the older pileup paths, which removed 32-65% of the reads of affected samples, mostly silently. - mod_bam: positions whose probabilities from separate sub-tags sum to more than one are now dropped instead of the whole record. When the caller has a collapse method (`--ignore h`, `--convert h m`) the position is resolved with it first (h removed / summed and saturated at 1.0), so the 5mC call is kept. The number of dropped positions is counted and reported at the end of pileup, adjust-mods, update-tags, extract and friends; check-tags still reports the records as invalid. - pileup: the same positions are skipped in the htslib-based general worker and in the optimized `BaseModsAdapter` (previously accepted unchecked). - pileup: a record without MM/ML tags no longer aborts the whole interval (the aggregator only logged the failure at DEBUG and dropped all rows of the interval). Failed intervals are now reported as errors. - pileup: `BaseModsAdapter` accepts opposite-strand sub-tags (`T-a.`), fixing threshold estimation on PacBio HiFi BAMs, and `pileup` falls back to the general workers when such calls are present instead of failing every record in the optimized workers. - tests: synthetic PacBio-style BAMs (tests/make_pacbio_style_tags.py) with unit and integration tests; CHANGELOG and troubleshooting docs updated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…t image Builds modkit from this checkout (pacbio-conflict-fix, 697de7b) and pushes ghcr.io/ljwharbers/modkit:0.6.4-pacbiofix-697de7b for use in the lrsomatic pipeline until the fix for nanoporetech#612 (PR nanoporetech#720) is released upstream.
The general pileup workers (used for multiple motifs, --duplex and, since the previous commit, automatically for modBAMs with opposite-strand calls such as PacBio 6mA `T-a.`) ignored two options that the optimized workers honour: - `--phased` read no `HP` tag, so the hp1/hp2 outputs were empty and only the combined file was written. The worker now keeps three tallies (combined, HP=1, HP=2) like the optimized workers and fills `phased_feature_counts`; without `--phased` the output is unchanged. - `--modified-bases` did not restrict the output rows, every code present in the modBAM produced a row (an `h` row next to every `m` row on PacBio data). The requested codes are now passed to the worker and rows with other codes are dropped after tallying, so those calls still count in `N_other` of the remaining rows, as in the optimized workers. With `--combine-mods` all codes are summed as before. Tests: the PacBio-style fixtures now carry HP tags and a regular 5hmC call (tests/make_pacbio_style_tags.py); new integration tests cover the phased partition and the row filter, and a snapshot of the previous general-worker output guards the no-flag behaviour. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Pushed a second commit (6e0afa2) that fixes two gaps in the general pileup workers, which this PR routes PacBio HiFi BAMs (opposite-strand
Tests: the PacBio-style fixtures now carry Verified on a haplotagged PacBio chr20 subset (8,604 reads, 86 % with |
Fixes #612 (PacBio BAMs give "~N failed processing" / 0 rows in 0.6.x pileup; the MM-tag-missing reads noted there are the second point below). Related: #545.
Problem
PacBio Jasmine (>= 26.1.3) calls 5mC and 5hmC with independent models and writes them as separate
C+m?andC+h?/G-h?sub-tags. At the sparse 5hmC positions the two probabilities sum to well over 1.0 (PacBio documents that they "may sum to more than 100%"). modkit rejects the whole record withconflict-explicit-prob-greater-than-one, which removed 32–65% of the reads in our samples inadjust-mods,extract,summary,call-modsand the pre-0.6.1 pileup paths, with the loss only visible at DEBUG level.Two further issues surfaced on the same BAMs in the 0.6.1+ pileup:
--regionruns returned 0 rows;BaseModsAdapterbails on any opposite-strand sub-tag (T-a., present on every PacBio HiFi read), so the optimized workers fail every record and threshold sampling sees no probabilities. This is the failure reported in V0.6.1 does not work on pacbio samples, while v0.5.0 worked fine (no problems with ONT) #612.Changes
mod_bam: a position whose probabilities from separate sub-tags sum to more than one is dropped instead of the record. When the caller has a collapse method (--ignore h,--convert h m) the position is resolved with it first (h removed / summed and saturated at 1.0). Dropped positions are counted and reported at the end of the run;modbam check-tagsstill reports the records as invalid.pileup: the same positions are skipped in the general worker and the optimized adapter; a record that fails to parse no longer aborts the interval, failed intervals are reported as errors.pileup:BaseModsAdapteraccepts-strand sub-tags (fixes threshold estimation) andpileupfalls back to the general workers when such calls are present.tests/make_pacbio_style_tags.py) with unit and integration tests; CHANGELOG and troubleshooting docs.Verification
On a chr20 slice of an affected sample:
adjust-mods --ignore hkeeps 2,687 of 2,687 tagged primary records (was 1,035);pileup --cpg --modified-bases 5mCgives 21,958 CpG rows (was 0), matching modkit 0.4.4 on a BAM with the 5hmC track stripped;pileup --regionon the full BAM gives 1.14 M rows (was 0); ONT output is byte-identical to 0.6.2.cargo testpasses.🤖 Generated with Claude Code