#!/usr/bin/env python3 """Pin the engine's physiologic constants against PUBLISHED values, with the source recorded. Why this exists. The manuscript's credibility rests on the claim that every constant is taken from the literature rather than tuned to produce a nice answer. Nothing in the repo enforced that: the constants were cited in comments, but a comment cannot fail. This file makes each one testable, and — just as important — records which values were ACTUALLY checked against a source and which are still resting on a code comment. Sources were fetched from PubMed on 2026-07-18. Where a value could NOT be verified in that session it is labelled NOT VERIFIED rather than being quietly asserted; do not upgrade a label without fetching a real source. An unverified constant is not a defect — it is an open item. Run: OMP_NUM_THREADS=1 PYTHONPATH=.packages python3 test_constants_literature.py """ import os for _v in ('OMP_NUM_THREADS', 'OPENBLAS_NUM_THREADS', 'MKL_NUM_THREADS', 'NUMEXPR_NUM_THREADS'): os.environ[_v] = '1' import sys sys.path.insert(0, '.packages'); sys.path.insert(0, 'vendor'); sys.path.insert(0, '.') from physics_sim import PhysicsSim from physics_core import REFLECTION, SIEVING, R_T sim = PhysicsSim(weight=70) fails, warns, verified, unverified = [], [], [], [] def check(name, value, lo, hi, units, source, note=""): """Assert a constant sits inside a literature range that has a named source.""" ok = lo <= value <= hi (verified if ok else fails).append(name) tag = "OK " if ok else "FAIL" print(f" [{tag}] {name:<26} {value:>8.3f} {units:<14} lit {lo}-{hi} [{source}]") if note: print(f" {note}") if not ok: fails_msg = f"{name} = {value} {units} is OUTSIDE the published {lo}-{hi} [{source}]" if fails_msg not in [f for f in fails if isinstance(f, str)]: pass return ok def soft(name, value, lo, hi, units, source, why_ok): """A constant OUTSIDE the published range on purpose. Records the direction of the error so a reviewer can see whether it flatters the device or handicaps it.""" inside = lo <= value <= hi warns.append(name) print(f" [WARN] {name:<26} {value:>8.3f} {units:<14} lit {lo}-{hi} [{source}]") print(f" OUTSIDE published range — deliberate. {why_ok}") return not inside def unver(name, value, units, note): unverified.append(name) print(f" [----] {name:<26} {value:>8.4g} {units:<14} NOT VERIFIED — {note}") print("PHYSIOLOGIC CONSTANTS vs PUBLISHED VALUES (sources fetched from PubMed 2026-07-18)\n") print("Peritoneal solute transport — MTAC (mass transfer area coefficient), mL/min:") check("MTAC urea", sim.mtac['Urea'] * 1000, 15.9, 30.0, "mL/min", "Selgas 2005: 22.9 +/- 7.04 mL/min", "range shown is the published mean +/- 1 SD; the engine sits near the centre") # GLUCOSE MTAC BAND CORRECTED 2026-08-22. The band read 10.0-17.0 "Douma 1995 (nitrate, 180 Da # proxy): 11.5". THE PROXY IS INVALID AND THE LABEL CONTRADICTS ITSELF: nitrate (NO3-) is 62 Da, not # 180. A small monovalent anion diffuses markedly faster than a 180 Da neutral sugar, so quoting its # MTAC as glucose's OVERESTIMATES glucose transport — the band was never a glucose measurement. # THE INTERNAL-CONSISTENCY ARGUMENT, which needs no new citation: MTAC falls monotonically with # molecular size across the peritoneum. Creatinine (113 Da) is measured at ~9-11 mL/min. Glucose is # 180 Da — LARGER — so its MTAC must sit BELOW creatinine's. A glucose MTAC of 11.5 would put a # 180 Da solute above a 113 Da one, which is not physically coherent. # THE PRIMARY EVIDENCE IS THE PET, NOT THIS NUMBER. MTAC is a DERIVED parameter, model-dependent and # sensitive to whether the estimator corrects for convection and lymph. D/D0 and net UF are what is # actually MEASURED in patients. test_pet_twardowski.py reproduces both, on both published axes, at # 9.0 mL/min — and the Garred back-calculation of an effective lumped MTAC from that dwell returns # ~9.0, i.e. the engine is self-consistent rather than hiding convection somewhere. # The band below is NOT widened to admit the current value: it is centred on the size-ordering # argument and would still FAIL at the old 12.0, at the nitrate-derived 11.5, and at anything under # 7.0. Narrower than what it replaced, not looser. check("MTAC glucose", sim.mtac['Glucose'] * 1000, 7.0, 11.0, "mL/min", "size-ordered against measured creatinine MTAC 9-11 mL/min (113 Da); glucose at 180 Da must " "be lower. Calibrated to the Twardowski PET (test_pet_twardowski.py), the direct observable") # SODIUM: band corrected 2026-08-09 to the DIRECT HUMAN MEASUREMENT. It used to read 5.0-15.0 # justified as "bracketed by creatinine 9.6 and urea 22.9" — an INFERENCE from two other solutes, # never a measurement of sodium at all. Öberg CM & Rippe B, Kidney Int Rep 2017;2(6):1128-38 # (PMC5733752, Table 1), human PD patients, states it outright: "PS for Na+ and anions 4.5 mL/min". # The engine was moved to 4.5 that morning; this band was left encoding the superseded inference and # so reported the MEASURED value as out of range. The test was wrong, not the constant. check("MTAC sodium", sim.mtac['Sodium'] * 1000, 3.5, 6.0, "mL/min", "Oberg & Rippe 2017 (PMC5733752 T1), human: PS for Na+ and anions = 4.5 mL/min (DIRECT)") # POTASSIUM is INFERRED, not verified — say so rather than overstate the audit's coverage. No # reachable source gives a peritoneal PS or MTAC for potassium; the value rests on the same # small-monovalent-ion argument the sodium entry above was just corrected for relying on. soft("MTAC potassium", sim.mtac['Potassium'] * 1000, 5.0, 15.0, "mL/min", "INFERRED from the small-monovalent-ion argument — NO measured source exists for potassium", "no peritoneal PS or MTAC for potassium is reachable in the literature; this is the same " "inference the sodium entry above was corrected for relying on, so it is marked INFERRED " "rather than counted as verified coverage") print("\nPeritoneal fluid reabsorption, mL/min:") check("lymphatic absorption", sim.lymph_rate * 1000, 1.0, 1.35, "mL/min", "Imholz 1993 1.07+/-0.18; Monquil 1995 1.01-1.34; Rippe 2001 ~1", "RECALIBRATED 1.67 -> 1.07 on 2026-08-08. 1.07 is Imholz's directly measured RESTING rate in " "CAPD patients and sits inside every band above; the old 1.67 was not a literature value at " "all and lay within Imholz's COMPRESSED figure (1.86+/-0.25), i.e. it modelled a patient under " "abdominal compression at all times. KNOWN GAP: the same study shows the rate is " "pressure-dependent (+74% under compression) and the engine holds it constant, so it does not " "capture the penalty a larger fill imposes on net ultrafiltration.") print("\nThree-pore coefficients (Rippe PDI 2004;24:S5 — cited in physics_core, not re-fetched):") # CITATION PARTIALLY VERIFIED 2026-08-22 — the reference is REAL and APPOSITE, the NUMBERS are not # yet read. Located and confirmed: Rippe B, Venturoli D, Simonsen O, de Arteaga J. "Fluid and # electrolyte transport across the peritoneal membrane during CAPD according to the three-pore # model." Perit Dial Int 2004;24(1):10-27, PMID 15104333 — a HUMAN CAPD three-pore paper, i.e. # exactly the right kind of source for these three constants, not an animal study standing in for # one (contrast Kf below, whose only located source IS a rat study). # WHAT IS STILL MISSING: the full text is paywalled on the reachable domains, so the specific sigma # values have NOT been read from it. "The citation exists and is the right paper" is NOT "the number # matches the paper", and these stay UNVERIFIED until someone reads the table. Do not promote them # on the strength of the reference being real. # NOTE ON WEIGHT: sigma_glucose is the single most load-bearing unverified constant in the model — # it multiplies the entire crystalloid osmotic drive, and test_pet_twardowski.py now pins the UF # that drive produces. So the PET gate constrains it INDIRECTLY even while the citation is unread. _R2004 = ("Rippe 2004 (Perit Dial Int 24(1):10-27, PMID 15104333) CONFIRMED as a human CAPD " "three-pore paper; numeric value NOT yet read from the paywalled full text") unver("reflection sigma glucose", REFLECTION['Glucose'], "-", _R2004 + " — physics_core.py:20") unver("reflection sigma Na", REFLECTION['Sodium'], "-", _R2004) unver("reflection sigma albumin", REFLECTION['Albumin'], "-", _R2004) print("\nSodium sieving — DERIVED from measured free-water transport, not taken on citation:") # Bernardo 2012 (PDI 32:537-44) measured the corrected free-water-transport fraction of total UF as # 0.45 +/- 0.16 during a 3.86% glucose dwell. FWT crosses aquaporins as PURE water carrying no # sodium; the remaining (1-FWT) is small-pore flow carrying Na at ~plasma concentration. So the # effective convective Na sieving implied by measurement is (1 - FWT): centre 0.55, +/-1SD 0.39-0.71. FWT_MEAN, FWT_SD = 0.45, 0.16 implied_lo, implied_hi = 1.0 - (FWT_MEAN + FWT_SD), 1.0 - (FWT_MEAN - FWT_SD) # 0.39 .. 0.71 # The band is now the +/-1SD interval with NO tolerance padding. The padding existed only to admit # the old 0.72, which sat exactly on the boundary; keeping it would let the value drift back out. check("sieving Na (convective)", SIEVING['Sodium'], implied_lo, implied_hi, "-", "derived from Bernardo 2012 FWT 0.45+/-0.16 -> Na sieving 1-FWT = 0.39-0.71 (centre 0.55); " "Helman 2024 PMC10914194 independently puts free-water transport at a fixed 40-50%% of UF and " "adopts 50%%, implying 0.50-0.60 — the two agree on ~0.55", "SET TO THE MEASURED CENTRE 0.55 on 2026-08-09 (was 0.72, the -1SD edge, implying only 28%% " "free water — below every published value, flattering sodium removal and suppressing " "ultrafiltration). Moving to the centre raised P4 anuric 30-day cumulative UF 40.3 -> 57.0 L " "and glucose absorbed 184 -> 205 g/day, so every published UF figure moved with it.") print("\nConcentration polarisation (film theory, physics_core.cp_beta — DEFAULT OFF):") unver("cp_beta_ref", 1.0, "-", "SEARCHED AND NOT FOUND 2026-07-19 — do not repeat these dead ends: PubMed returns a CFD " "paper that explicitly AVOIDS film theory, and two targeted PubMed queries returned ZERO " "results (it is a chemical-engineering topic, barely indexed in a biomedical database); " "MDPI and pubs.acs.org both 403; lenntech and DuPont design-manual URLs 404. The right " "sources are J. Membrane Science or a manufacturer design manual, neither reachable from the " "allowed domains. DOES NOT BLOCK ANY DECISION: exp_polarization.py sweeps 1.0-1.4 and the " "conclusion (2 passes fails, 3 passes holds) is IDENTICAL at every point in that range.") print("\nUltrafiltration coefficient:") unver("Kf", sim.Kf * 1000, "mL/min/mmHg", "human LpS not located in the 2026-07-18 fetch (the hit was Zakaria & Rippe 1993, a RAT " "study). Open item — do not cite a human source for this until one is actually read.") print("\nFATAL thresholds — what counts as a patient DEATH (physics_patient.py:19-20):") # WHY THIS IS PINNED. Mutation-tested 2026-07-19 (fatal_mutation.log): test_fatal_volume.py guards # the FLUID-overload trip in BOTH directions (disabling it and making it hypersensitive are both # caught), but NOTHING guarded the ELECTROLYTE bounds. Widening them to absurd values — # Potassium (0.1, 99.0), Sodium (50, 250), i.e. no potassium or sodium level is ever fatal — passed # the ENTIRE suite green. # That matters directly for the headline claim: "10/10 patients survived" is only meaningful if the # survival criteria are clinically defensible. Loosen these and survival becomes unfalsifiable. from physics_patient import FATAL as _FATAL _FATAL_DOC = { # solute: (lo, hi) clinical justification for the bound 'Sodium': (120.0, 165.0), # <120 severe hyponatraemia (seizure/herniation risk); # # >165 severe hypernatraemia 'Potassium': (2.0, 7.0), # <2.0 severe hypokalaemia (arrhythmia); >7.0 hyperkalaemic arrest 'Bicarbonate': (12.0, 50.0), # <12 severe metabolic acidosis 'Glucose': (1.5, 33.0), # <1.5 neuroglycopenia; >33 HHS-range hyperglycaemia # ADDED 2026-08-21. The death criteria covered Na/K/HCO3/glucose and stopped, so a patient could # be driven to any calcium, magnesium or phosphate whatever and still report SURVIVED — for a # device whose dialysate carries all three and whose engine models a bone reservoir for exactly # them. Clinically fatal OUTER limits, not reference ranges: 'Calcium': (0.6, 2.0), # IONISED Ca. <0.6 tetany/laryngospasm/arrest; # # >2.0 severe hypercalcaemic crisis. (Ionised, NOT total — # # the engine tracks ionised, hence the 1.20 dialysate.) 'Magnesium': (0.3, 5.0), # <0.3 severe hypomagnesaemia with arrhythmia; # # >5.0 areflexia -> respiratory paralysis / cardiac arrest 'Phosphate': (0.3, 4.0), # <0.3 rhabdomyolysis/respiratory failure from depletion; # # >4.0 the severe-hyperphosphataemia end of survivable ESRD # CAVEAT, MEASURED AND IMPORTANT (physiology audit 2026-08-22): these three CANNOT TRIP inside a # 30-day run. The bone buffer's BONE_S constants — explicitly "ORDER-OF-MAGNITUDE choices ... # NOT fitted" — set the timescale: driving ionised Ca from 1.20 to 0.60 needs ~240 mmol of net # negative balance, i.e. ~100 days at the measured drift; Mg ~41 d; PO4 ~240 d. So these bands # add no SAFETY COVERAGE at the horizon the cohort runs, and any statement of the form "the # cohort survived and calcium stayed in range" is currently a statement about BONE_S, not about # physiology. They are kept because they are correct and because a longer horizon will exercise # them — but they must not be cited as evidence of mineral safety over 30 days. } for _s, (_lo, _hi) in _FATAL_DOC.items(): _got = _FATAL.get(_s) _ok = _got == (_lo, _hi) (verified if _ok else fails).append(f"FATAL {_s}") print(f" [{'OK ' if _ok else 'FAIL'}] FATAL {_s:<20} {str(_got):>16} documented {(_lo, _hi)}") if not _ok: print(f" *** survival criteria CHANGED — every '10/10 survived' claim is affected ***") assert set(_FATAL) == set(_FATAL_DOC), ( f"FATAL keys changed: {sorted(_FATAL)} vs documented {sorted(_FATAL_DOC)} — a solute was added " f"or removed from the death criteria without updating this pin.") print("\nDerived physical constants:") check("R*T (van't Hoff)", R_T, 19.2, 19.5, "mmHg/(mmol/L)", "R=62.3637 L.mmHg/(mol.K) x T=310.15 K / 1000 — arithmetic, not empirical") print("\nAcid-base:") # READ THE LIVE LAW. This block used to be a hardcoded print asserting the acid load was "NOT # MODELLED — 0.000 mmol/kg/d". Net endogenous acid production was implemented on 2026-08-02 and # raised to 0.8 mmol/kg/d on 2026-08-06, so for a week this audit told the reader the engine omits a # mechanism it actually runs — the precise failure mode the audit exists to prevent, in the audit # itself. Reading the signature default means it cannot drift again. import inspect as _insp import physics_patient as PP _neap = _insp.signature(PP.neap_mmol).parameters['mmol_per_kg'].default check("net endogenous acid", _neap, 0.7, 1.0, "mmol/kg/d", "Remer & Manz 1995 PMID 7797810 and Frassetto 1998 PMID 9734733 give 0.7-1.0 mEq/kg/d on a " "Western diet; dialysis cohorts measure 42.7 +/- 10.1 (HD) and 58.2 +/- 24.3 (CKD) mEq/d " "(PMID 26508542). %.2f mmol/kg/d gives %.0f mEq/d at 70 kg." % (_neap, _neap * 70)) print() print(f"SUMMARY: {len(verified)} verified in range, {len(warns)} deliberate out-of-range, " f"{len(unverified)} NOT VERIFIED (open items), {len(fails)-len(warns) if False else len(fails)} failing") if fails: print("FAILED CONSTANTS (outside their published range with no recorded justification):") for f in fails: print(f" - {f}") print("RESULT:", "PASS" if not fails else "FAIL") print(os.popen("TZ='America/Phoenix' date '+%H%M MST (%Y-%m-%d)'").read().strip()) sys.exit(0 if not fails else 1)