mtnoc-rs
mtNoC — a de-identified estimate of the number of distinct human maternal (mtDNA) contributors to a shotgun-metagenomic sample. It reports a conservative lower bound on the count of distinct maternal lineages (macro-clades) plus their composition — aggregate, never an individual haplotype.
Pure-Rust reimplementation of the reference Python pipeline. A single static binary takes raw FASTQ in and emits one TSV row per sample.
Pipeline
raw FASTQ.gz ─▶ k-mer prefilter (rCRS 21-mers) ─▶ align to chrM ─▶ per-read alleles at
PhyloTree-informative positions ─▶ mixture-EM + bootstrap-stability ─▶ contributor
lower bound (macro/sub-clade) + 95% CI + lineage composition
Two modes:
fast(100% pure Rust): raw FASTQ pair → embedded-rCRS k-mer prefilter → atriple_accelSIMD seed-anchored aligner (against the compact reference) → per-read alleles. No external tools.accurate: raw FASTQ pair →strobealign→samtoolsfilter (MAPQ≥20, NM/qlen≤0.027) +mpileup -Q20allele extraction → reproduces the reference pipeline exactly. Pass a pre-aligned chrM BAM with--bamto skip strobealign. Shells out tostrobealign+samtools.
Both modes feed the same mixture-EM, which is bit-for-bit identical to the reference Python implementation (including a numpy-compatible MT19937 so the bootstrap matches exactly).
Install / build
# or, once published: cargo install mtnoc-rs
Reference data
The EM reference dump and the rCRS k-mer prefilter sequence are embedded in the binary (gzip, decompressed at startup), so you only supply the alignment reference:
data/mtNoC_compact.fa— chrM (NC_012920.1) + NUMT-decoy contigs. Ships in the git repo; pass it via--ref.fastuses it for the pure-Rust aligner;accurateuses it as the strobealign index andmpileupreference.
data/mtref.txt (regenerable via scripts/dump_ref_for_rust.py) and data/rcrs_wrap.fa are the
sources for the embedded tables; you do not need to pass them.
Usage
# FAST (pure Rust) — one sample
# Shorthand: give the sample stem, mtnoc resolves _R1/_R2 (or .R1/.R2) + extension
# Multiple samples (one TSV row each): comma-separate, or comma-separate stems with --in
# Optionally save the chrM-candidate reads (omit to only emit the estimate)
# ACCURATE (needs strobealign + samtools on PATH)
# ...or from a pre-aligned chrM BAM (skips strobealign)
Common options: --thread N (0 = all cores), --header (prepend a column-name line), --n-boot,
--seed, --min-prop, --min-identity (fast). Progress goes to stderr; only the TSV goes to stdout.
Output
Tab-separated, one row per sample, no header unless --header is given (so multiple runs
concatenate cleanly). Columns:
| column | meaning |
|---|---|
sample |
sample name (derived from the R1 filename) |
informative_reads |
reads scored at PhyloTree-informative positions |
contributors_ci95 |
ci95_low;min_contributors_subclade;ci95_high (;-separated) |
composition |
haplogroup:proportion:reads components, ;-separated |
Example:
sample informative_reads contributors_ci95 composition
mix_EAS85_AFR15 4000 1;1;3 M7c2b:0.9770:3736r;Z2:0.0230:88r
min_contributors_subclade is a floor limited by the bootstrap-stability criterion (≥8 supporting
reads, stable in ≥80% of resamples); the true contributor count is generally higher.
Dependencies
- Build: Rust ≥ 1.74. All crates are pure Rust — no C toolchain, no
*-sysbuild steps. gzip isflate2(zlib-rs backend); FASTX parsing isneedletail(default-features = false). - Runtime:
fast— none. A single self-contained binary.accurate— externalstrobealignandsamtoolsonPATH(override with--strobealign/--samtools). Only this mode uses external tools.
Ethics
Reports only aggregate counts and maternal-lineage composition — never an individual's haplotype or a re-identifiable profile.
Attribution
Haplogroup definitions derive from PhyloTree (van Oven & Kayser); rCRS = NC_012920.1. Aligner kernels:
triple_accel. Please cite PhyloTree and this tool if used.
License
MIT — see LICENSE. (Bundled reference data derived from PhyloTree/rCRS retains its original terms.)