Method
MNRC — struvite precipitation and NH₃ stripping
What it predicts
N and P recovery, struvite mass and purity from N/P-rich streams — not power.
Governing relations
Each relation is transcribed from the implementation. Where the code cites no source, the source line says so.
Cathode pH rise Source: Empirical buffer-saturation curve with a soft ceiling at pH 11; mnrc.ts cites no source for it.
An empirical curve, not a carbonate speciation model.
Symbol Meaning Unit influent pH pH H⁺ consumed per mole of alkalinity 1 anode current density from predict.ts A/m² anode area, fixed at 0.003 m² run duration (default 24 h) s alkalinity (default 500); 50 000 mg CaCO₃ per equivalent mg CaCO₃/L recovery chamber volume (default 100 mL) L Worked example
These inputs, passed to the predictor, return the output below. A test re-runs the example on every change, so this number is the one the code produces.
input value unit temperatureC 25 °C ph 7 pH electrodeSpacingCm 2 cm hrtHours 24 h codMgL 1,000 mg/L Output · mnrc.catholytePh = 7.995 pH, within ±0.1 %
By hand · j = 0.15 A/m² from predict.ts at 25 °C, pH 7, 1000 mg/L COD, no anode named (see the MFC worked example). I = 0.15 × 0.003 = 4.5×10⁻⁴ A; charge over 24 h = 38.88 C = 4.030×10⁻⁴ mol H⁺. Alkalinity = 500/50 000 × 0.1 = 1.0×10⁻³ mol, so x = 0.403. pH = 7 + 3 × (1 − e^−0.403) = 7.995.
Reproduce · Pinned by libs/shared/electrochemistry/src/predictors/worked-examples.test.ts. Run it from the repository root:
pnpm exec jest -c libs/shared/electrochemistry/jest.config.js worked-examples.test.ts -t "mnrc.catholytePh"
Struvite saturation index Source: K_sp from Münch & Barr 2001, Water Res. 35:151.
Activity coefficients are ignored (dilute-solution assumption).
Symbol Meaning Unit struvite saturation index; nucleation above 0.5 1 total influent concentrations (activities taken as 1) mol/L free PO₄³⁻ fraction 1 −log₁₀ of the struvite solubility product at 25 °C 1 Free-ammonia fraction Source: Henderson-Hasselbalch speciation with pK_a = 9.25; mnrc.ts cites no source for it.
Symbol Meaning Unit free-ammonia share of total ammoniacal nitrogen 1 NH₄⁺/NH₃ acid constant at 25 °C 1 Struvite yield Source: Linear precipitation-efficiency ramp above the nucleation threshold; mnrc.ts cites no source for it.
A heuristic ramp from 40 % at SI = 0.5 to a 95 % cap.
Symbol Meaning Unit struvite precipitated mol moles of each reactant in the chamber mol
Assumptions and constants
- Anode current from the shared Butler-Volmer biofilm kinetics in predict.ts (Geobacter on acetate), with the same Arrhenius, substrate, pH and ohmic corrections as the MFC predictor.
- Cathode pH rise is an empirical function of charge passed per unit alkalinity.
- Nucleation above SI = 0.5.
- Default urine matrix: 200 mg/L NH₄-N, 30 mg/L PO₄-P, 25 mg/L Mg — unsourced defaults.
Corrections applied
- Purity penalty from deviation of Mg:NH₄:PO₄ from 1:1:1.
Not modelled
- Crystal habit / dewaterability (needs CFD + supersaturation-gradient modelling).
- Calcium carbonate scaling — only a binary purity penalty.
- Continuous-flow operation — assumes batch over the stated duration.
- Temperature dependence of Henry's constant — 25 °C value used.
Literature anchors in the source
- Münch & Barr 2001, Water Res 35:151
- Kuntke et al. 2012, Water Res 46:2627
Implementation
libs/shared/electrochemistry/src/predictors/mnrc.ts
Interval the predictor ships
heuristic_fixed_fraction — A fixed ±25 % placeholder band. It is NOT a calibrated interval; when served through /api/ml/predict it is replaced by the benchmark band below, or withheld. How served intervals are built
Calibration artifacts used when served
- Benchmark out-of-fold residual quantiles: bes-benchmark-v1 · gkf5 · generated 2026-09-09
- Split-conformal calibration: split-conformal · generated 2026-05-21
- Hierarchical-priors v2 trust snapshot: populated · generated 2026-05-16
Benchmark cells for this predictor’s systems
Each row is a stratum with n ≥ 30 residuals at nominal level 90%. Coverage is the cross-validated share of held-out points inside the band.
| target | stratum | n | papers | coverageCV |
|---|---|---|---|---|
| No data (n = 0) | ||||
No benchmark cell reaches the minimum n for these systems — intervals are withheld.
Prior trust by served parameter
The state the lab badge shows for each served parameter and system, from the v2 priors fit.
| parameter | system | state | papers | prior |
|---|---|---|---|---|
| No data (n = 0) | ||||
No v2 prior row for these systems.
Scientific-rigor gates
pnpm verify:science runs these rules over the committed priors and validation artifacts in pre-commit. Known violations are baselined per rule and slug; a new one blocks the commit. Baseline from hierarchical-priors-v2.json@2026-10-26T00:10:47.721880+00:00.
| rule | baselined |
|---|---|
| gate-honestyNo parameter may pass a rounded-threshold gate read while converged=false | 1 |
| support-containmentBounded quantities must have ci95 inside physical support, width <= range | 3 |
| magnitude-sanityNo ci95 bound may exceed the plausibility ceiling (1.0e+6) | 0 |
| slug-uniquenessNo two slugs may share a spelling-independent identity; scale must agree | 2 |
| secondary-source-purityNo fitted prior may carry a REVIEW (secondary-source) stratum | 0 |
| artifact-pairingEach fit must have its own coverage evidence; the served fit must have some | 0 |
| coverage-sharpnessAny coverage figure must ship its interval width alongside | 0 |
| interval-calibrationHeld-out interval coverage per parameter may not newly degrade | 128 |
| effects-gap-completenesseffects.json is schema 2.0; every non-high effect has a gap per archetype; no gap is "high" | 0 |