Skip to content

v2.8.1: fiberhmm-extract single-pass multi-type

Choose a tag to compare

@mtcicero26 mtcicero26 released this 17 Apr 13:16
· 495 commits to main since this release

⚠️ Reverse-strand MM/ML parsing bug — UPGRADE TO v2.9.0

Versions 2.6 – 2.8.2 had a parser bug that shifted m6A/m5C modification positions on reverse-aligned reads (~24 bp median), causing ns/nl/as/al/MA/AQ tags to be wrong on reverse reads. Forward reads unaffected. DAF with IUPAC (R/Y) encoding unaffected.

Upgrade: pip install --upgrade fiberhmm (v2.9.0+). See v2.9.0 release notes for details.


fiberhmm-extract ~5× speedup for the default `--all` case

Two changes to `fiberhmm-extract` that together give N× speedup for N extract types plus a correctness fix.

Single-pass multi-type extraction

The old default (`--all`) ran the region-parallel pool 5 separate times, one per extract type. Every pass iterated the full BAM, rebuilt the query→ref `aligned_pairs` dict per read, and paid a fresh ProcessPool startup cost. That's 5× BAM I/O and 5× Python tuple allocations for data that could be shared.

The new worker takes a list of requested extract types and handles all of them in one BAM traversal:

  • BAM iteration shared across types
  • query→ref mapping computed once per read, passed to each extractor
  • One ProcessPool startup

Benchmarks on test BAMs:

Test Reads Types with data New time
DddB 22,913 footprint, msp, tf 6.1s
Hia5 1,190 footprint, msp, tf, m6a, m5c 3.0s

For production BAMs on NAS (where I/O dominates), this is the biggest win — you go from 5× BAM reads to 1× BAM reads.

Correctness: empty-ML guard in m6a/m5c extractors

`_extract_m6a` and `_extract_m5c` call `read.modified_bases`, which segfaults pysam on reads where the MM tag has base-type header entries but the ML array is empty. Same bug we guarded against in the apply engine in 2.6.6.

Symptom before fix: on Hia5 PacBio BAMs with any empty-ML reads, extract workers silently terminated ("A process in the process pool was terminated abruptly") and produced 0-read output across all extract types.

Fix: check `len(read.get_tag('ML')) == 0` before calling `modified_bases`. O(1) on `array.array`, not materializing a PyInt list.

API compatibility

`extract_tags_parallel` signature extended: `output_bed` → `output_beds` (dict) and `extract_type` → `extract_types` (list). Old single-string calls still work for back-compat.

Install

```bash
pip install --upgrade fiberhmm
```

🤖 Generated with Claude Code