All notable changes to this project are documented here. The format is based on Keep a Changelog, and the project aims to follow Semantic Versioning (pre-1.0, so minor versions may carry breaking changes).
0.2.0 - Unreleased
--verbosenow reports the resolved values of theDADA2RS_*development tuning gates, and anyDADA2RS_*variable that is set but not recognised is warned about regardless of--verbose(#145). Retired spellings carry an alias naming the replacement. Motivated by two full soil-pool A/B runs spent comparing a configuration against itself afterDADA2RS_SHUFFLE_CARRYwas renamed toDADA2RS_SHUFFLE_NO_CARRY: both arms ran carry-on, and came back byte-identical and within 1%, which is what a correct null looks like.--verboseprogress lines for pooleddada: per-window phase deltas, effective cores, map parallel efficiency and align fraction, everyDADA2RS_PROGRESS_SECSseconds (default 30,0disables) (#150). Totals hid that occupancy climbs 22 → 42 effective cores of 64 across a single run.summarysubcommand: per-position quality metrics, cumulative expected-error metrics, and an optional per-read sequence-complexity histogram (#8).sampleanderrors-from-samplesubcommands for subsampling input FASTQs and learning an error model from the subsample (usable for bootstrapping).--failed-uniquesdiagnostic ondada/dada-pseudo/dada-pooled: emits a TSV of uniques that failed to seed a partition (#60).chimera-diagnosticsfor higher-order (trimera) screening, with nearest-parent and flank gates (#54).- Experimental WFA alignment backend (
--align-backend wfa2) with a--wfa-max-editsedit-budget cap (#49, #51). ASV-equivalent to Needleman- Wunsch on tested Illumina and PacBio HiFi data, but not byte-identical. dada-pooled --gzipwrites the per-sample JSON files gzip-compressed as{sample}.json.gz(#70).dadaanddada-pseudogain the same--gzipflag, for consistency across the per-sample denoisers.merge-pairsrecords input-file provenance and warns on mismatch (#10).just/maketask runners for build, install, test, and docs (#46).
- The
nalignandnshroudcounters no longer overflow on large pooled runs (#143). Both count pairwise comparisons (nraw × nclusters) and wereu32, so any pool exceeding ~4.3 billion comparisons wrapped silently: a 1.23 M- unique NovaSeq soil 16S pool reported 3,015,581,030 alignments against an actual 11,605,515,622. The wrapped values reached theALIGN:verbose line and thenalign/nshroudfields ofdada,dada-pseudoanddada-pooledoutput JSON, so affected artifacts carry wrong values in those two fields. Nothing reads either counter — no clustering, error-model, p-value or table output was affected, and no re-run is needed to correct an archived result. Smaller pools (under ~4.3e9 comparisons) were never affected. - LOESS error models no longer collapse to a uniform
1e-7floor on input with five or fewer populated quality columns (#95). The tricube kernel zeroes the farthest neighbour in the local window, which left aspan = 0.75,degree = 2fit short of the coefficients it needed; the local fit now falls back to the highest degree the surviving points can identify. Affected--errfun loess(and thepacbioloess path) on binned-quality data, where a handful of distinct Q values is normal. Fits with six or more populated columns are byte-identical to before.loess_errfunandpacbio_errfunnow returnResultand report an error rather than emitting an unusable uniform matrix when every transition fails to fit. learn-errorsanderrors-from-samplenow gzip-compress their output when the-opath ends in.gz, for consistency with the other JSON-emitting subcommands (previously the file was written uncompressed) (#71).kdist-calibrate --from-dadanow resolves derep inputs whose filenames were renamed by the pipeline (e.g.{sample}.derep.R1.json.gz): it falls back from the exact{sample}.json[.gz]match to a{sample}.*.json[.gz]scan, disambiguating an ambiguous prefix by the derep JSON's ownsamplefield (#72).kdist-calibrate --from-dadanow reads gzip-compresseddadaoutput JSONs (*.json.gz, e.g. fromdada-pooled --gzip); previously the gzip bytes were parsed as raw JSON and failed withexpected value, line 1 column 1.make-sequence-tablenow reads gzip-compresseddada/merge-pairsinputs (*.json.gz, e.g. fromdada --gzip/dada-pooled --gzip); previously the gzip bytes were parsed as raw JSON and failed withexpected value, line 1 column 1.- Single-file JSON
-ooutputs now honor a.gzoutput path, routing through the shared gzip-aware writer instead of a raw write (matchinglearn-errors, #71):summary,summary-merge,merge-pairs,remove-primers,filter-and-trim,make-sequence-table,remove-bimera-denovo,assign-taxonomy,assign-species, anddada's single-sample output.
- The
DADA2_RS_PAR_GRAINtuning gate is renamedDADA2RS_PAR_GRAINfor consistency with every other gate (#145). The old spelling is still honoured and warns; it was the loneDADA2_RS_name, so anyone setting it from memory got silence and the default grain. - The experimental WFA backend is now gated behind an off-by-default
wfaCargo feature (#63). Default builds — and the published crate — are Needleman-Wunsch only; selecting--align-backend wfa2without the feature errors rather than silently falling back to NW. Building WFA requires a source checkout (cargo build --features wfa) because it depends on a git crate that cannot ship on crates.io. - Denoising/error-learning verbose logs now echo the active alignment backend (#51).
- Trimmed the published crate: development, benchmarking, concordance data (multi-MB PacBio FASTQs), examples, notes, and CI/infra files are excluded.
b_p_updateprefetches theRawit will read 16 iterations ahead (#154), cutting the phase 34-38% on four arms across two NovaSeq soil pools and −1.0 to −6.8% ofrun_dadadepending on how large a share the phase is (5.1% on 16S read 1, 14.3% on ITS2 read 2). Byte-identical by construction — a prefetch has no architectural effect. The phase is memory-bound on a random gather, not compute-bound: over 91% of repricings take an early exit doing no arithmetic, so the cost is a cache miss on a 160-byteRawread for ~20 bytes of it. Three layout fixes were priced first and all were worse; the only competitive one wins by fitting a 32 MB per-CCD L3 and therefore loses on the larger pool. x86_64 only;DADA2RS_PUPDATE_PREFETCH=0disables it.Raw::e_minmaxmoves offRawinto a denseVec<f64>onB, parallel toB::raw_cluster(#147).b_compare's serial store reads this value once per raw per call;Rawis 160 bytes, so as a field each read pulled a full 64-byte cache line to use 8 bytes of it, and that strided read measured as 83–87% of the store scan. Contiguous, the store falls from 18.8–19.1 to 4.9–5.5 ns per raw-visit — −71% of store time — worth −20.1 to −21.3% ofrun_dadaon NovaSeq soil 16S and −15.2% on ITS2, byte-identical on both pools across two replicates. Effective cores rise 31.4 → 38.4 (R1) and 29.4 → 36.5 (R2) of 64.b_compare's serial reduction is folded into the store loop it already shared a result vector with (#143): seven passes over that vector become one. Worth −24 to −30% ofrun_dadaon two NovaSeq soil pools (16S and ITS2, both reads), byte-identical. The reduction had been six separate passes costing 337 s on soil 16S — 31% ofrun_dada— on a phase whose parallel map is already bandwidth-saturated and cannot absorb it.b_shufflecarriescompmaxacross bud rounds instead of rebuilding it per bud (#139), deleting the build scan: 9,700 rebuilds collapse to 1. Measured −45 to −48% ofrun_dadaon soil 16S and −15.4 to −15.9% on ITS2 (64 threads, post-#143), byte-identical across arms.DADA2RS_SHUFFLE_NO_CARRY=1restores the per-bud rebuild.- Sparse k-mer-8 screen, gated to k ≥ 8, cutting resident memory in the high-k regime (#43).
dada-pooledstreams dereplication into merging instead of holding all dereps in memory, and uses an integer merge-quality accumulator (#39, #41).- Various k-mer-vector memory reductions in the alignment screen (#32).
- R DADA2 concordance guardrail for Illumina and PacBio, with abundance/recall/ precision gates (#35).
0.1.0 - 2026-06-03
- Initial crates.io release: Rust ports of the core DADA2 pipeline steps
(
filter-and-trim,derep,learn-errors,dada,merge-pairs,remove-bimera-denovo,assign-taxonomy/assign-species, sequence-table helpers).