Validation dossier¶
This page is the credibility artefact for aeolus1d's parity claims. It collects, in one place, the parity workflows that define "GT-POWER / AVL Cruise M standard" for this project, the checked-in case that exercises each, the reference dataset it is validated against, the current pass/fail verdict, and the wall-clock budget it runs inside.
Citable, frozen snapshot. This page is a living document and its numbers move as the code does. For a citation that will not move, use the frozen per-release report
validation-report-v0.3.0.md— it pins the verdicts, meshes, reference types, and uncertainty classes at the v0.3.0 tag. Cite the report, not this page.
The thesis behind the project (see roadmap.md) is that
parity is not feature-count parity with a 30-year funded Fortran
product. It is validated competence on the core workflows at an
acceptable wall-clock, every claim reproducible from a checked-in,
text-defined case. This page is where that claim is made auditable:
every row points at a file in the repository that you can run.
How to read the status column. ✅ banked means the suite's TOML grid runs green under its
run_validation.pyagainst the committedpass_criteria.tomlon a fresh checkout. ⏳ pending means the case exists but the reference data or a closed-loop element is not yet in place. The honest, un-rounded numbers are in the per-workflow sections below — including the corners that fail and why.
The parity workflows¶
| # | Workflow | Reference case | Reference type | Status | Wall-clock |
|---|---|---|---|---|---|
| W1 | Engine breathing / manifold tuning | examples/validation/ricardo_ktm/, examples/validation/mendeley_ethanol_water/ |
mixed — see note. mendeley_ethanol_water: experiment (DOI 10.17632/yvb7khhbrj.1). ricardo_ktm: code-to-code vs Ricardo WAVE (IMECE2017-70638), reclassified 2026-08-30 |
⚠️ breathing physics verified; quantitative match re-cal owed (orifice default, ADR-0008) | seconds/operating-point |
| W1b | HD-diesel engine, full breathing + turbo | examples/validation/avl_epw_diesel_steady/ |
code-to-code (AVL Cruise M EPW steady sweep; vendor CSV no-derivatives, never committed) | ⚠️ 3/3 ops PASS in ANCHORED mode; CV-A + CV-B both close; u_num on T_EXH. CORRECTED 2026-09-10 — this cell read "3/3 ops PASS both modes". The predictive mode does not gate T_EXH: the channel is report-only and NOT VALIDATED there, reading −44.9 / −113.4 / −80.9 K at 1200 / 1500 / 1800 (measured 2026-09-07). Predictive is the mode a user without the vendor CSV runs, so the shipped default is the ungated one. See run_validation.py::PREDICTIVE_REPORT_ONLY and docs/scope-and-limitations.md. |
~10 min / 3 ops |
| W2 | Turbo matching | examples/validation/turbo_match/ (over examples/59_wastegate_boost_ctrl.toml) |
self-consistency (shaft power-balance + map fidelity — not external data) | ✅ self-consistency check, 3/3 | ~2.5 min / 3 points |
| W3 | Aftertreatment drive cycle | examples/avl_cruise_m/c02006_dpf_csf_regen_trans.toml |
code-to-code vs AVL Cruise M C02006 (DPF-CSF regen transient) | ✅ runs end-to-end (numeric promotion in progress; co_conv_cat structurally blocked) |
~6.5 min / 500 s cycle |
| W4 | Acoustics / NVH | examples/ muffler TL cases + aeolus1d acoustics CLI + examples/validation/gt_tmm_pipe/ + examples/validation/gt_acoustics_tl/ |
experiment (measured muffler TL), plus analytic + code-to-code vs GT-Suite TMM | ✅ experiment-referenced since 2026-08-29 — RMS 0.92 dB below 1.2 kHz and 1.26 dB below 2 kHz over 122 measured points, with no fitted parameter; maintainer-run, data never committed | seconds |
| W5 | Electrified drive cycle | examples/86_electrified_drive_cycle.toml (aeolus1d drive-cycle) |
self-consistency (parallel-hybrid SoC + energy bookkeeping) | ✅ self-consistency check (energy-balance) | seconds |
Reference-type honesty (the W2/W4/W5 relabel, and the 2026-08-30 W1 split). This paragraph used to open "Only W1 is validated against experimental data". Both halves of that have since changed and the sentence is kept here, struck, because it was the basis of a maturity headline.
W1 is mixed, not experiment (corrected 2026-08-30 by reading the paper). Its
ricardo_ktmhalf compares against the OEM column of Tables 2 + 3 of IMECE2017-70638, which is Ricardo WAVE's own simulated baseline — the thing the paper's tuning study computes a percentage gain over. The suite's README had asserted the opposite, that those numbers were "validated against the engine's chassis-dyno test … to within a few percent"; the paper's Figs. 3 + 4 show WAVE running 15-25 % above the dyno and attribute the gap to drivetrain and roller losses the simulation omits. A citation naming a simulation code as the source of an experimental reference should have been the tell. Detail and evidence inexamples/validation/ricardo_ktm/README.md. The paper's dyno curves are real measured data and are digitisable; that is filed there as the route to an actual experimental reference, not claimed as one.W1's experimental claim therefore rests on
mendeley_ethanol_wateralone (DOI10.17632/yvb7khhbrj.1, 39/60), and the KTM's 6/10 is a code-to-code score. The headline it fed — the 2026-08-29 sweep's "of the five parity workflows exactly one carries an experimental reference, and it scores 6/10 and 39/60" — needs the 6/10 removed from it. The count of experiment-referenced suites is unchanged at three, because W4'sgt_acoustics_tland the DD13 suite both landed on 2026-08-29 and neither depended on this.Its quantitative match is separately mid-re-calibration after the ADR-0008 breathing fix (see below). W2 and W5 are self-consistency checks — the solver is shown to agree with itself (conservation, energy bookkeeping), not with an external dataset. W4 is experiment-referenced as of 2026-08-29:
examples/validation/gt_acoustics_tl/compares the transfer-matrix transmission loss against a measured expansion chamber (191 points, 0-3202 Hz) and matches to 0.88 dB RMS below 1.2 kHz. Two caveats stated rather than buried. (a) Nothing is fitted as of 2026-08-29. It briefly was: the chamber length was recovered acoustically becausegt_suite_nativeread it 10x too small, and that importer defect is now FIXED — it ignored GT'sunitIDand assumed millimetres, so files in cm/inch/m came out wrong by that unit's ratio, uniformly and therefore invisibly to an area-ratio check. The file's own 0.53996 m and the acoustically recovered 0.538 m agree to 0.36 %, which is what confirms the fix. Going blind cost 0.88 -> 0.92 dB RMS. (b) The suite is maintainer-run — the measurements are a vendor example distribution, never committed, and the harness skips cleanly without them, so this upgrades the reference type but not third-party reproducibility. The analytic and GT-Suite TMM checks are retained alongside. AVL traces. These are real evidence of different strength; the report states the type beside every number so a reader never mistakes a self-check for an experimental validation.
v1.0 = all parity workflows pass inside their wall-clock budget, plus
this dossier and the perf baselines checked in, plus a Zenodo DOI minted
on the release tag (see release.md). W5 (electrified) is
included now that the hybrid drive-cycle deliverable runs.
W1 — Engine breathing / manifold tuning¶
What it proves. The Cylinder + WiebeCombustion +
WoschniHeatTransfer cycle physics, the runner/manifold tuning that
sets volumetric efficiency, and the per-cycle IMEP / ISFC reduction in
aeolus1d.analysis.engine_metrics — validated against published
experimental engine data, not against another simulator.
Ricardo WAVE KTM 510 cc SI — examples/validation/ricardo_ktm/¶
- Reference: Aradhye & Bari (2017), Continuously Varying Exhaust Pipe Length and Diameter…, IMECE2017-70638. OEM brake-torque / power column of Tables 2 + 3, ten operating points 1000–10000 RPM.
- Run:
python examples/validation/ricardo_ktm/run_validation.py - Verdict — re-validated 2026-06-09 against the default orifice valve coupling (ADR-0008). Read in two regimes:
- Breathing physics: verified correct. The compressible-orifice
cylinder↔runner coupling conserves mass across the valve to
<1e-10(tests/integration/test_cylinder_valve_conservation.py), replacing a legacy coupling that lost ~(1 − Cd·lift)of the charge every valve event — a deficit that grew with RPM (same-build motoring A/B: trapped-air ratio 1.05 at 5000 RPM → 1.56 at 9000 RPM). - Quantitative match: 6/10 at the 25 % gate with the recommended
--throttle --wall-heatinvocation (3/10 bare), down from the legacy coupling's 8/10 on the same invocation. The single TOML is calibrated at one point (7000 RPM) with a textbook polydyne valve lift and no port-flow losses; with physically-correct breathing this idealised geometry now over-breathes (η_v 0.87–1.18, peaking 1.18 at 8000 RPM), so the fixed calibration over-predicts torque at every point — most at the 1000–2000 (cam over-admits at low RPM: 1000 RPM 48 vs 29 N·m) and 8000–9000 (runner ram peak misplaced vs the paper's 7000) corners. This is a case-calibration limitation, not a solver regression — bare-default reproduces the post-!188 numbers exactly, so breathing is unchanged across !189–!203; closing the match needs a per-RPM cam / fuel / spark table (a 10-point case, not the single-case demonstration this is), which is owed and tracked. The legacy 8/10 was a partly-fortuitous cancellation between the under-breathing leak and the idealised over-breathing cam.
The honest takeaway: the breathing solver is now trustworthy and conservation-pinned; the KTM case needs a per-RPM re-calibration (gated on proprietary OEM cam geometry) before its quantitative match is re-quoted.
Mendeley ethanol/water blends — examples/validation/mendeley_ethanol_water/¶
- Reference: Mendeley Data, CC BY 4.0, DOI
10.17632/yvb7khhbrj.1— single-cylinder Otto SI, ethanol/water blends across a compression-ratio sweep. - Run:
python examples/validation/mendeley_ethanol_water/run_validation.py - ⚠️ 2026-08-15 note on the numbers and the diagnosis below. The
same invocation scores 39/60 on the 2026-08-15 tree — and the
same-day bisect attributed the difference to
643fc3fb(2026-07-01): until that fix the Livengood-Wu knock integral silently ratcheted a 10° timing retard on this scaffold, deflating predicted IMEP and flattering five gate-edge points, so the 44/60 was bug-flattered and 39/60 is the honest score (closure with the measured mechanism inBACKLOG_HISTORY.md, "Mendeley baseline drifted 44→39"). And the "charge-cooling + single-γ" structural diagnosis was implemented, measured over all 60 points, and retracted: charge cooling moves the prediction away from the data (39/60 → 36/60; predicted BMEP 9.27 → 9.55 bar against a measured 5.73 at 50 % water). The measured gap is combustion deterioration under water dilution — see the suite README's retraction. The verdict below is kept as written for the tree it measured. - Verdict — re-validated 2026-06-09 against the shipped-default orifice
coupling (ADR-0008). 44/60 under both the legacy and the orifice
coupling, at the 20/25/25 % tolerance bands (no re-tuning). The orifice is
near-neutral here (~1 % on BMEP) because the suite is fixed-fuel:
per-cycle fuel is prescribed from the paper's measured fuel-mass-flow, so the
Wiebe heat release dominates indicated work and trapped air only moves the
compression/pumping loop ~1 %. (Contrast the fuel-from-air Ricardo KTM suite,
where the same coupling change swung breathing 5–56 % and moved the gate
8/10 → 6/10 — the fueling mode, not the coupling, is why one suite is
sensitive and the other isn't.) The ~1 % nudge reshuffles gate-edge points
without changing the count: the 0–30 % w/w band reads 40/40 under orifice
(37/40 under legacy) — gate-edge realignment (it pulls three borderline
CR-9.44
eta_ipoints that sat at 25.2–26 % rel error under the 25 % gate), not a model-physics gain — and an equal number of high-water passes tip out (40–50 %: 7/20 → 4/20), where aeolus1d already over-predicts BMEP. The 40–50 % corner is the documented structural gap: charge-cooling from the water fraction + the bulk single-γ Volume mapping, unaffected by the breathing coupling. - ✅ The suite now runs on the shipped-default orifice coupling
(
cylinder_orifice_valve_flow=Truein the harness). Correction: earlier notes here called the Mendeley data "local-only (gitignored, not in CI)" — that was wrong.data/operating_points.csvis committed (allow-listed indata/.gitignore) and the suite is CI-reproducible; the legacy closure (2026-05-17) simply predated the orifice default (2026-06-07), which only changed the TOML build path and never reached the scaffold this suite uses.
U-Michigan heavy-duty diesel cylinder pressure — examples/validation/umich_diesel/¶
- Reference: heavy-duty diesel single-cylinder pressure trace; the harness
builds an aeolus1d cylinder via
aeolus1d.scaffold.scaffold_single_cylinder_engineand compares CA50 (crank angle of 50 % mass-burned) and the pressure trace. -
Status: ✅ LIVE — 9/9 measured operating points on the predictive path, 8/9 on the calibrated one. Corrected 2026-08-29: this row read "⏳ scaffolded, pending data fetch" and was stale. The suite's own README has recorded it as Active since the dataset was staged; the row here reasoned from
umich_diesel/data/being empty, which stopped being evidence once the harness gained$AEOLUS_DD13_DIRand the data was placed outside the tree. Same README-current / dossier-stale shape as the EPWIMEP_Highrow. Reference type: experiment, and — unlike every other maintainer-run suite here — the dataset is publicly obtainable at a stable handle (Deep Blue2027.42/116203), so a third party can reproduce this by fetching it themselves. Licence permits research redistribution but no derivative works, which is whydata/stays empty and nothing is transcribed into the repository. -
The predictive path is the result worth quoting.
--predictivecomputes start of combustion and premixed fraction from the charge state (Hardenberg-Hase ignition delay + Watson premixed fraction) under one global calibration, with only the measured injector commands as per-point input — no per-point phasing tuning. It passes 9/9 on peak pressure, CA50 and gross IMEP, and beats the hand-calibrated Wiebe path on phasing. -
One systematic bias, recorded rather than banded away. Gross IMEP is over-predicted at 9 of 9 points in the predictive path, mean +0.53 bar, and the offset falls monotonically with speed — +0.85 / +0.53 / +0.22 bar at 750 / 1100 / 1400 rpm. It survives the change of combustion model (calibrated: +0.74 / +0.36 / +0.18), so it sits in the closed-cycle thermodynamics rather than the burn, and peak pressure shows no matching structure. Consistent with under-modelled in-cylinder heat loss; the test is a Woschni
hAsweep on these same points. InBACKLOG.md, not acted on.
Directly validates the multi-stage two-zone Wiebe + Woschni cylinder physics against a compression-ignition trace, the diesel complement to the SI KTM / Mendeley suites above.
AVL EPW heavy-duty diesel, steady sweep — examples/validation/avl_epw_diesel_steady/¶
- Reference: AVL Cruise M EPW, a 12.9 L 6-cylinder turbocharged HD diesel: 6 cylinders on a split intake/exhaust manifold, compressor + VGT turbine on a shared shaft, charge-air cooler, HP-EGR leg. Code-to-code against AVL's own steady-state operating-point CSV.
- The vendor CSV is no-derivatives and is never committed. The harness skips cleanly without it, so this row describes a maintainer-run suite.
- Status: ✅ 3/3 operating points PASS, exit 0, in both modes
(predictive and
--anchor-bcs), re-measured 2026-08-08.
What is gated, and what is not. T_EXH, BMEP, IMEP_High, IMEP_Low,
PFP, MFB50 and SOC are gated, each declaring scale, band_basis,
floor, delta_min and band_op_set alongside exactly one tolerance.
NOX and Q_WHT are report-only with measured reasons — the honest form
of "not validated", as opposed to a tolerance too wide to fail.
Energy closure (the reason to believe the rest).
| Control volume | Result |
|---|---|
CV-A — cylinder, [IVC, EVO) |
closes within max(1 %, 3×floor) |
| CV-B — whole network, full cycle | 1.302 / 0.808 / 0.701 % of fuel against a 3 % threshold. Re-measured 2026-10-10 on the v0.4.0 tree: 0.001 % at all three ops, each half (cylinders / rest-of-network) under 3 % on its own. |
CV-B did not close until 2026-08-08. The 4.3 % residual was the charge-air cooler: a 7–27 kW heat sink the audit enumerated as nothing, because its refusal for pipe heat closures probed attribute names the builder never sets. Confirmed by timestep refinement — the residual is invariant under CFL (4.317 → 4.316 → 4.316 %), so it was a missing term and not a sampling artefact — and the split localised it to the non-cylinder half of the network.
Numerical uncertainty. T_EXH carries u_num = ±0.035 °C from a
three-level uniform mesh study (scale 1.0/1.5/2.25, observed order
p = 1.286, asymptotic ratio 0.99996; re-measured 2026-10-10 on the
v0.4.0 tree: ±0.015 °C, p = 2.28, ratio 0.99996, against anchored errors of
−10.5 / −35.9 / −29.3 °C). Against a +20.5 °C model error
that is negligible: the gap is model form, not mesh. u_val is not
claimed — the AVL CSV documents no instrument uncertainty.
CI coverage without the vendor data. The golden row epw_diesel_engine
pins the whole network state at t_end = 0.05 s (past heat release), screened
bit-reproducible across 3 processes × NUMBA_NUM_THREADS ∈ {1,2,4};
tests/validation/test_epw_engine_selfconsistency.py checks CV-A closure, the
valve specific-enthalpy identity, closed-period species conservation and the
temperature clamp.
Open gaps, stated: the plenum wall term is PARTIALLY CLOSED
(plenum_wall_fraction 0.0837, re-measured 2026-09-11 from 0.1646 — the
sink has halved, two of three ops are now under the 0.08 "closed" line, and
the max misses it by 0.0037; still not the dominant error sink, still not
proven physical, and the halving did not move the T_EXH residual); NOX is report-only.
Re-measured 2026-10-11 (--ops 3 predictive, main 56dad407): the
compared value is now the core-zone model, reading 892.5 / 620.7 /
1229.2 ppm against AVL 293.1 / 240.4 / 509.4, a 2.67× over-prediction
that does reproduce AVL's 1500 rpm dip. Peak flame T is 2648 / 2617 /
2755 K. The rest of this paragraph is the 2026-08-26 well-mixed account,
kept as history. The core-zone model it calls for is the one now compared
(docs/release-readiness.md). In that account the channel read
17.8 / 3964.9 / 5875.2 ppm against AVL 293 / 240 / 509 (2026-08-26). The N₂O kinetics defect that used to
pin this channel to a constant is FIXED — the total rate is now 0.99–1.81×
Heywood eq. 11.1, NO freezes kinetically, and moving the T_active_min gate
1500→1900 K shifts the answer by 0.08 % where it once shifted it 9.5×. What
the flatness was hiding is a single quantity: the peak burnt-zone temperature
runs 1995 / 2429 / 2577 K against the 2200–2800 K a diesel flame sheet
holds at every load, because a well-mixed burnt zone sits near the global φ
(0.41 → 0.67). exp(−38370/T) turns that 582 K swing into 330×. Closing it
needs a local-φ / stoichiometric-core burnt zone; see
docs/release-readiness.md and pass_criteria.toml for the measurement and
for the new compensating pair (equilibrium_NO_ppm currently caps the
1800 rpm op) that must not be "fixed" first. The species pool does not close
during gas exchange (~12 %, localised to valve-flow bookkeeping — closed-period
accounting is exact).
W2 — Turbo matching¶
What it proves. Off-design compressor/turbine operation: corrected speed/flow scaling away from the map reference gas, near-surge behaviour, and shaft mechanical losses.
- Reference case:
examples/validation/turbo_match/(run_validation.py+pass_criteria.toml), driving theexamples/59_wastegate_boost_ctrl.tomlturbo-shaft topology at three fixed wastegate settings. Exercises the v0.5 robustness pack incomponents/turbo.py(γ/R off-test-gas correction, near-surge damping, shaft mechanical efficiency). - What is validated. This is a physics-conservation + map-fidelity check (like W4's analytic transmission loss), not an external-dataset comparison — there is no open turbo map + transient reference to ship, and we do not fabricate one. The validated property is turbo matching: at steady state the solver must find the shaft-speed equilibrium where turbine power == compressor power (independently computed; conservation forces them equal), with the compressor above surge and inside its PR map.
- Verdict (2026-05-22): ✅ banked, 3/3. Power balance holds to
~1e-7 relative across
bypass_open ∈ {0.0, 0.2, 0.4}; the matched power is monotone in the wastegate (5767 → 4258 → 3017 W as it opens — the physically-correct response); surge margin and PR stay on-map at every point.
W3 — Aftertreatment drive cycle (the locked wedge)¶
What it proves. The keystone workflow: a transient aftertreatment drive cycle that GT-POWER and AVL Cruise M both target. This is where the project's existential constraint lived — at the acoustic-CFL floor a 500 s cycle was ~84 M steps (~4.6 h), impractical for unattended use.
- Reference case:
examples/avl_cruise_m/c02006_dpf_csf_regen_trans.toml— the AVL Cruise M C02006 DPF + catalysed-soot-filter regeneration transient. - What was needed. The v0.3 keystone: the low-Mach / quasi-steady
solver mode (
solver = "quasi_steady", pressure-projection SIMPLE with Rhie–Chow), transient inlet BCs, a steady gas-phase energy solve, and the JIT'd SIMPLE kernel (~75× per solve). Seelow-mach-at-plan.mdandperf-history.md. - Verdict: the full 500 s cycle runs end-to-end in ~6.5 min,
stable through regen ignition, soot burning down to completion — on
the merged
main. The acoustic-CFL floor that made this impractical is gone. W3's wall-clock gate, which the roadmap originally listed as failing (existential), now passes. - Code-to-code numeric promotion in progress. Seven Tier-A AVL EAT
cases (C02001 DOC light-off · C02002 SCRT ads/des · C02004 DPF ash
filt · C02005 DPF back-diff · C02006 DPF CSF regen · C02007 DPF filt
soot classes · C02022 DPF user-filter) now ship as scaffolded
validation suites under
examples/validation/avl_c020*/. Each auto-skips with exit 0 until a user populatesdata/with curves digitized from the AVL screenshots via WebPlotDigitizer, then runs the full code-to-code comparison automatically. The Tier-A audit + digitization workflow lives atexamples/avl_cruise_m/validation_audit.md(in the repo, outside the docs tree); C02001 is the canonical worked example. Numeric promotion of C02006 is the highest-value follow-up — it lifts the W3 keystone from "runs end-to-end" to "matches AVL numerically". - Aeolus-authored catalyst suites, and TWO OF THEM ARE
EXPERIMENT-REFERENCED. Beyond the AVL Cruise-M imports, four harnesses
exercise the generic
twc_brinkmeiercatalyst kinetics against published behaviour. They ship self-contained — no vendor data — and all four are CI-gated and passing.
This heading said "code-to-literature" for all of them until 2026-08-30,
and that is wrong for two. Literature here meant a published
correlation or band; but heliyon_twc_co_oxidation compares against
measured durations from an open-access synthetic-gas-bench study, and
ornl_passive_scr against measured selectivity from ORNL CLEERS. Those
are experiments. The mislabel mattered: it sat below the W1-W5 table, so
every summary claim drawn from that table — including
docs/scope-and-limitations.md's "Not validated against lab /
synthetic-gas-bench data", and release criterion EC-Q12, which asked for an
open synthetic-gas-bench set as future work — was written as though these
suites did not exist. Per-suite type is now stated on each entry:
- ORNL passive-SCR NH₃ generation — reference type:
experiment (trend-level); the comparison is against measured
selectivity bands, not point values
(examples/validation/ornl_passive_scr/): NO→NH₃ selectivity-vs-λ
over a rich TWC via the opt-in A_nh3_form_brnk channel — >80 %
rich, 7–40 % near-stoich, matching the ORNL CLEERS 2014 / SAE
2016-01-0934 open trend.
- DOC propylene (C₃H₆) light-off — reference type:
code-to-literature, correctly: the reference is a 200-280 °C T50
band from a 1973 correlation, not a dataset
(examples/validation/doc_propylene_lightoff/): the opt-in
A_c3h6_ox_brnk C₃H₆-oxidation channel run on a CO-free,
oxygen-storage-off DOC-like brick over an inlet-temperature sweep;
the light-off T50 ≈ 240 °C lands in the 200–280 °C literature
band for propylene over a noble-metal oxidation catalyst
(Voltz-Morgan-Liederman 1973). Code-to-literature: the single
pre-exponential is the fitted handle, the model form (a sharp
Voltz knee) is what is validated. run_validation.py +
plot_results.py + @slow CI gate.
- **Heliyon 2024 TWC CO-oxidation / oxygen-storage (OSC)** — *reference
type:* **experiment**, and **obtainable**: open access CC BY, with every
number quoted from the paper's tables and text rather than digitised
from a figure, so a third party can reproduce it exactly
(`examples/validation/heliyon_twc_co_oxidation/`): a CO-step OSC
titration at 300 °C over a Pd/CZ three-way catalyst, gated by the opt-in
`Omega_OSC_brnk` oxygen-storage capacity. ✅ **banked** — it reproduces
the paper's Table-11 discharge durations across three ageing states
(Fresh CZ 25.4 s vs ≈25 s · Mild 16.5 s vs ≈15 s · Severe 7.7 s vs
<10 s, `|Δ| ≤ 6 s` band). `Omega_OSC_brnk` is calibrated on the *fresh*
state only; the mild/severe capacities follow from the *independent*
Table-13 OSC site-density ratio (1 : 0.637 : 0.308), so reproducing all
three durations from a single scale is predictive content, not a
three-point fit. Independent of the un-packaged AVL SC630 TWC reference.
- **Passive-SCR system (TWC NH₃ source + underfloor SCR)** — *reference
type:* **self-consistency / characterization**, against
necessary-condition bands rather than external data
(`examples/validation/passive_scr_system/`): the system-level companion
to `ornl_passive_scr` — a rich TWC excursion generates NH₃ that an
underfloor SCR brick then consumes to reduce NOₓ. ✅ **characterization
(validated)** against necessary-condition bands (system NOₓ conversion
≥70 % with stored reductant → ~100 %; ≤5 % baseline with no NH₃ → ~0 %),
isolating each leg of the passive-SCR mechanism.
All are gated by their opt-in pre-exponential / capacity (default 0 → inert → bit-identical), so they add coverage without perturbing the shipped defaults.
W4 — Acoustics / NVH¶
What it proves. Muffler/silencer transmission loss and the post-processing NVH chain (SPL / dB(A) / dB(C) / octave bands / order tracks / Campbell diagram). This workflow is GT-unique among the reference tools — AVL Cruise M is not an acoustics package.
- Transmission loss. Three TL paths ship, with different
correctness envelopes — be precise about which one a number came
from. (1) The time-domain naïve amplitude-ratio
transmission_lossis whataeolus1d acoustics --probe-outreports; it is correct only for reflection-free (anechoic-terminated) setups and carries a warning docstring + CLI note to that effect. (2) The Chung–Blaser two-microphone wave-decompositiontransmission_loss_decomposedis correct in the presence of reflections; it is available through the Python API but not wired into the CLI (it needs two probes per side + a probe spacing). (3) The frequency-domain transfer-matrix solver (analysis/acoustics_tm.py) reproduces the analytic TL notch of a side-branch / quarter-wave / Helmholtz element at its resonance to within tolerance — that analytic agreement is the validated check. - Post-processing.
aeolus1d acousticsCLI emits SPL/dB(A)/dB(C) + octave bands (Butterworth analyzer roll-off) + the naïve TL from a trace HDF5; Campbell-diagram critical-speed crossings come from an order-track RPM sweep. - Code-to-code: GT-Suite TMM uniform pipe. New suite
examples/validation/gt_tmm_pipe/compares aeolus1d's analyticduct_four_poleagainst GT-Suite's TMM-computed transfer matrix for the same pipe (from the GT acoustics TMM demo atgt_suite/Acoustics/Other_Analysis/Transfer_Matrix_Method/tm-pipe.tm). Geometry recovered by least-squares (L≈0.52 m, D≈97 mm). Verdict: ✅ TL agrees to <0.5 dB across 10–200 Hz (the ideal-plane-wave regime); above ~200 Hz GT adds viscothermal / higher-mode physics aeolus1d doesn't model, reported as an informational model-fidelity gap (5.45 dB at 990 Hz). - Measured transmission loss (added 2026-08-29).
examples/validation/gt_acoustics_tl/comparesacoustics_tm's expansion-chamber TL against a measured curve — 191 points, 0-3202 Hz, provenanceSource - Measuredchecked per sheet rather than assumed. RMS 1.02 / 0.88 / 1.18 dB over bands of 600 / 1200 / 2000 Hz, gated at 2.0 dB. Widening to 3300 Hz takes RMS to 4.92 dB and max |err| to 25.29 dB — the plane-wave limit, measured for the first time, and report-only for that reason. One fitted parameter (chamber length; the importer reads it 10x small) and maintainer-run data — both stated in the suite README and in the honesty note above. - Status: ✅ the analytic checks pass, with a code-to-code
GT-Suite cross-check banked. Note the CLI's
--probe-outTL is the naïve (anechoic-only) metric; the reflection-correct wave-decomposition TL is API-only (see above). A measured-muffler dataset would upgrade this from analytic + code-to-code to experimental validation (future).
W5 — Electrified drive cycle¶
What it proves. The Cruise-M-derived electrified workflow: a hybrid/EV reporting state-of-charge + energy consumption + tailpipe over a drive cycle within the wall-clock budget.
- Reference case:
examples/86_electrified_drive_cycle.toml, run byaeolus1d drive-cycle. It extends the W-vehicle case format (the v0.7aeolus1d.io.vehicle_caselayer) with a[powertrain]block that builds a parallel hybrid (aeolus1d.hybrid.ParallelHybrid: envelope e-motor + coulomb-counted battery + power-split controller). Each step the closed- loop driver's torque demand is split between engine and motor; the battery SoC is integrated; the engine-share fuel comes from the BSFC. - What is validated. Like W2, this is an energy-bookkeeping
consistency check, not an external-dataset comparison: the run reports
a coherent SoC trajectory, electrical-energy-used vs regen-recovered
split, and engine-share fuel + CO₂ — and the battery responds correctly
(drive discharges, braking regenerates, SoC clamps to
[0, 1]). Unit- tested intests/unit/test_vehicle_case.py. - Status: ✅ the deliverable runs in seconds (longitudinal dynamics, not CFD). A measured hybrid drive-cycle dataset would upgrade this from a functional/energy-balance check to experimental validation (future, and the deep electrochemical battery tier is FMU-import territory).
- Toward experimental drive-cycle data —
examples/validation/argonne_d3/. A scaffolded vehicle drive-cycle suite (Phase H4d, ⏳ pending data fetch) compares the aeolus1d driveline + vehicle model against published Argonne D3 vehicle-test traces. The first pass stays in conventional-only mode (a non-hybrid SI car) because the driveline/vehicle MVP does not yet model the e-motor + battery side on the validated path; it becomes runnable oncedata/<vehicle_name>/is populated.
Cross-driver agreement¶
The quasi-steady driver runs W3's anchor case, so how far it sits from the
compressible drivers matters. Measured 2026-09-22 (EC-C2 Phase C), the gap
is grid error and nothing else. On the reacting parity case
(tests/integration/test_driver_reacting_parity.py), the QS − strang
temperature band is 0.58 / 0.30 / 0.15 K at 10 / 20 / 40 cells. Conversion
stays at 0.402–0.403 and the state is settled at every level. The band halves
per doubling and extrapolates to ~0 K. On the non-reacting sibling it is flat
in Mach from 0.032 down to 0.004, so the low-Mach model term is below 0.02 K
there. This is self-consistency evidence, code against code. It says the
drivers solve the same equations, not that either matches an engine. Tables
and harness: docs/roadmap.md §1.
Performance baselines¶
The wall-clock budgets above are anchored to checked-in baselines so a regression is caught in CI, not in production:
benchmarks-baseline.md— per-kernel latency table, regenerated bypython tests/benchmarks/run_baseline.py. The regression guard istests/benchmarks/test_baseline_regression.py.perf-history.md— the Perf-1 → Perf-7 audit trajectory and the low-Mach / QS-JIT collapse, with the empirical-vs-speculative record (which optimizations were rejected after profiling, so they are not re-attempted).
The system the current baseline was captured on (Python 3.10, 16-core WSL2, NumPy 2.2.6, Numba 0.64.0) is recorded in the baseline doc; absolute numbers are machine-relative, the ratios and the step-count collapse are the portable result.
Reproducing the dossier¶
Every row is runnable from a fresh checkout:
# W1 — published-data engine validation (slow; per-RPM sweep)
python examples/validation/ricardo_ktm/run_validation.py
python examples/validation/mendeley_ethanol_water/run_validation.py
# W2 — turbo matching (shaft power balance, ~2.5 min)
python examples/validation/turbo_match/run_validation.py
# W3 — AVL C02006 aftertreatment drive cycle (~6.5 min)
aeolus1d run examples/avl_cruise_m/c02006_dpf_csf_regen_trans.toml
# W4 — acoustics post-processing from a trace
aeolus1d acoustics --help
# W4 code-to-code: aeolus1d duct_four_pole vs GT-Suite TMM (uniform pipe)
python examples/validation/gt_tmm_pipe/run_validation.py
# W5 — electrified (parallel-hybrid) drive cycle
aeolus1d drive-cycle examples/86_electrified_drive_cycle.toml
# Perf baseline (regeneration + regression guard)
python tests/benchmarks/run_baseline.py
pytest tests/benchmarks/test_baseline_regression.py
The validation suites carry their dataset licences verbatim in each
suite's DATA_LICENSE; only fair-use published numerical reference
points are committed, raw datasets are fetched into the (gitignored)
data/ subdirectories per each suite README.