read_result() returns cases/provenance for the old bare-list receipts and
the new schema-2 object, and rejects unknown schemas. Existing evidence
(e.g. 70f6617) and its digest scripts stay valid for schema 1; queue and
digest scripts must use read_result(...)['cases'] for new receipts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.1 KiB
DFG 2D-1 (Re 20) against the official reference intervals
tests/validation/run_dfg_re20.py runs the steady DFG 2D-1 case on the refined
channel root (D40 root, D80 wide fine patch) and on the uniform D80 grid. Geometry,
inflow, initial state, layout and observation are those of the pinned Re100 runner
(run_refined_dfg.py, re100_helpers.py, both unchanged); only the lattice
viscosity is set for Re 20 (root tau 0.56, fine 0.62, uniform 0.62, lattice speed 0.01).
Label: "compared against the official reference bands", not a full benchmark
certification: the outlet is pressure-NEQ (neq_extrap), not do-nothing, and the
inlet is local Zou-He.
Quantities
- Cd = 2 Fx / (rho U^2 D), Cl = 2 Fy / (rho U^2 D), interval means over each sample.
- p_diff = p(0.15, 0.2) - p(0.25, 0.2), linear extrapolation to the exact surface
points (
re100_helpers.pressure_probes). The helper returns dp / (rho U^2) in scaled units; p_diff = dp * 0.04 for U = 0.2 m/s, rho = 1. Both are reported. - Official intervals (Schaefer & Turek 1996): Cd [5.57, 5.59], Cl [0.0104, 0.0110], p_diff [0.1172, 0.1176].
Bounds and steady rule (frozen before any run)
- End time t* = 60 (30 s physical): 240,000 refined root steps, 480,000 uniform steps.
- One sample every t* = 0.5 (0.25 s) at the end of a synchronized root step; Cd and Cl are interval means. Trailing window t* 50..60 inclusive (21 samples).
- Steady rule (our engineering choice, not official): in the window, for each of Cd, Cl, p_diff, max - min <= 10 % and |least-squares slope x window| <= 2 % of its official interval width (range 2e-3 / 6e-5 / 4e-5; slope 4e-4 / 1.2e-5 / 8e-6). Absolute limits, so the small Cl is never a divisor. Never relaxed after a run.
- The verdict uses the window mean; the distance to the nearest interval edge is reported for each quantity (negative outside).
- Force sign: fluid on cylinder, x along the inflow, y up from the bottom wall; Cd > 0
and the official Cl > 0 (
cd_positiveis reported). - Not steady at t* = 60: status
NOT_STEADY, no interval verdict. Health limits (Mach <= 0.2, rho in [0.5, 1.5]) stop the run withUNHEALTHY. - Steady:
WITHIN_INTERVALSorOUTSIDE_INTERVALS, with the per-quantity verdict.
Run
python tests/validation/run_dfg_re20.py --output <new-dir> --plan
CUDA_VISIBLE_DEVICES=<n> python tests/validation/run_dfg_re20.py --case both \
--collision SRT --output <new-dir> --max-wall-seconds <cap>
The uniform D80 control separates method error from refinement error. --plan writes plan.json only. A GPU run writes plan.json and result.json
(per case: lattice parameters, every sample, window ranges, status, verdict).
Receipts: plan.json and result.json carry schema 2 and provenance (HEAD, src tree,
runner hash; clean checkout required, refused if it changes during the run). Receipts
written before this (schema 1, e.g. evidence 70f6617) are a bare list of cases. Read both
with run_dfg_re20.read_result(path) (["cases"][0] replaces the old [0]); existing
evidence scripts stay valid for schema-1 receipts and need this reader for new ones.
Host contract tests: tests/unit/test_dfg_re20.py.