Files
CelerisLab/docs/validation/taylor_green.md
T

511 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Periodic 2D Taylor–Green AMR campaign (prepared, not GPU-qualified)
This validation harness complements DFG Re100 and Jet/body tests. It measures
smooth 2D periodic decay and errors crossing fixed refinement interfaces at
Re_L=100 and 1000. It does **not** certify 3D turbulence, LES, Jet performance,
wall conditions, dynamic refinement or general high-Re flows.
## Reference and conventions
Primary implementation-author documentation, checked 2026-10-18:
- TensorMesh, exact velocity and pressure with a consistent phase:
https://docs.tensor-mesh.com/example_gallery/fluid/taylor_green.html
- AeroSim Nassu, 2D decay, energy and lattice-length Re definition:
https://docs.aerosim.io/nassu/validation/analytical/04_taylor_green_vortex_2d/README.html
We use the TensorMesh phase, rescaled to length L=N root cells:
k = 2*pi/L; A(t) = U*exp(-2*nu*k*k*t)
ux = -A*cos(k*x)*sin(k*y)
uy = A*sin(k*x)*cos(k*y)
p/rho0 = -A*A/4 * (cos(2*k*x)+cos(2*k*y))
E = <|u|^2>/2 = U*U/4 * exp(-4*nu*k*k*t)
Pressure is kinematic, with rho0=1. A global velocity sign reversal leaves
pressure unchanged; exchanging sine/cosine without the corresponding pressure
phase can reverse its sign. CPU tests independently check momentum residuals.
The nonlinear acceleration is a pressure gradient, **not zero**; the AeroSim
page's prose calling advection zero is not adopted. Do not mix phase variants
from different references. The formulas above are verified by substitution,
not by trusting a copied pressure expression.
Re_L=U*L/nu, not Re_k=U/(nu*k)=Re_L/(2*pi). U=.03 in lattice units,
Ma=U/cs=.0519615, cs^2=1/3, nu_root=.03*N/Re_L. Acoustic refinement uses
h_l=dt_l=2^-l: lattice velocity stays U, nu_l=2^l*nu_root and
tau_l=.5+3*nu_l. The worst root tau is .50288 (N32/Re1000), omega=1.98855,
inside the existing config guard. No viscosity clamping or guard override.
All initial arrays are physical FP64 equilibrium populations, supplied to the
public shifted-FP32 postcollision-G initializer. rho=1+3p at each true cell
center. These are valid equilibrium postcollision states, but do not include
Chapman–Enskog nonequilibrium stress; startup acoustic/kinetic error remains in
the measurements and is shared with uniform baselines. The incompressible
reference is not an exact finite-Mach LBM solution. This is why resolution alone
need not remove the full error floor.
## Geometry and workload
All patches use level-wide union form, so origins are zero, including fine
arrays with holes. Coordinates are (index+.5)*2^-level. Metrics integrate only
ACTIVE leaves, each weighted by 4^-level. Covered cells and halo cells never
enter norms or mass. Geometry tests prove exact single coverage at root-cell
resolution. All blocks are 8x8, and both root dimensions are periodic.
At each root N=32,64:
- 2 levels: L1 rectangle (N/8,N/8,7N/8,3N/4), in L0 indices.
- 3 levels: same L1 plus L2 rectangle (3N/4,N/2,3N/2,5N/4), in L1 indices.
These off-axis boundaries cross nonzero flow and gradients rather than sitting
only on symmetry or stagnation lines. Whole geometry scales with N.
16 cases: at each Re, uniform N=32,64,128,256 plus AMR (root32/root64)x(depth2/depth3).
Each AMR case therefore has both a same-root uniform baseline and a uniform
baseline at its finest spacing. Uniform N is its own lattice length, so nu and
step count are scaled to represent the same nondimensional solution.
Samples t*=tU/L = 0,.12,.24,.36,.48. End time is 16*N base steps, a meaningful
.48 domain turnover or 3.016 vortex-scale turnover times (scale 1/k).
At Re1000 energy decays about 7.3%; at Re100 about 53.1%. No plots or full fields;
each case writes five diagnostic rows and provenance, incrementally.
## Running (GPU owner must schedule launches)
CPU checks, from the repository root:
PYTHONPATH=src python -m unittest discover -s tests/validation/taylor_green -p 'test_*.py' -v
One GPU case, on the scheduled worker after checking occupancy:
CUDA_VISIBLE_DEVICES=<physical-id> python tests/validation/taylor_green/run_case.py --repo /path/to/reviewed/checkout --re 100 --n 32 --depth 1 --output output/taylor_green/re100_n32_d1.json
Depth 1 is uniform. Run uniform cases before AMR for each Re; inspect baseline
screening failures before proceeding. For a complete matrix, repeat the uniform
call with N=32,64,128,256 and AMR calls with N=32,64 / depth=2,3, at each Re.
Use serial process startup on the parent's assigned Horsea GPUs. This harness
does not schedule or acquire GPUs. No GPU was used during preparation.
python tests/validation/taylor_green/assess.py output/taylor_green/re*_n*_d*.json --output output/taylor_green/assessment.json
The local API/geometry review used clean staging commit
cd3a657f9d3833e812c3cca173525f165b48710a. This is **not** a claim of results on d79
or any historical commit. Each runtime output records actual Git HEAD/dirty
state, an aggregate source-tree hash, plus SHA256 of all harness Python files. Assessment refuses dirty checkouts and mixed source
or harness identities. Keep reports outside the checkout or .gitignore them so
new outputs do not change its dirty flag between cases. The source-tree hash excludes bytecode caches; production qualification requires
a clean checkout.
The runner uses the existing PeriodicBlockStepper / FixedPatchStepper periodic
paths only. It does not depend on the new channel-root implementation.
## Preregistered assessment, before any GPU results
All sampled times must satisfy finite screening ceilings:
- Relative composite velocity L2 <= 5%
- Relative globally gauge-adjusted pressure L2 <= 15%
- Relative kinetic-energy error <= 5%
- Composite mass drift from downloaded t0 <= 1e-5
These are screening budgets, not literature-certified tolerances. Acceptance
also requires all 16 cases, common source/harness, correct nondimensional times
and viscosity, and baseline-relative checks on worst post-startup-sample errors:
- AMR error <= max(2 * same-root uniform error, declared numerical floor).
- Root64 AMR error <= max(.9 * root32 AMR error, floor), for each depth/Re.
- Uniform256 error <= max(.9 * uniform32 error, floor).
Floors: velocity .002, pressure .02, energy .004. They are declared low-Mach /
equilibrium-startup budgets, not fitted to observed results. Ma^2=.0027 motivates
their scale; it is an asymptotic expectation, not a proof of those coefficients.
The coarse baseline sets the AMR budget because much of the domain remains
coarse. The finest uniform error and AMR/fine ratio are always reported, with no
claim that partial refinement should match a fully fine domain. A pass below a
floor is bounded accuracy, not a measured convergence order. Report errors and
ratios even for a pass. Failure requires diagnosis or a separately preregistered
follow-up, never retroactive tolerance tuning. Higher Re is deliberately absent;
Re100/1000 must first be stable, resolved and reviewed.
Diagnostics use one global pressure gauge, direct cell-center analytic values,
kinetic energy per unit reference mass, and actual leaf cell areas. Composite
midpoint quadrature introduces a small initial energy integration error, retained
rather than subtracted. Mass drift is relative to downloaded t0, so density
initialization and mixed-grid quadrature do not masquerade as time drift.
## Pilot scheduling and transfer-consistency scope
Start with one uniform case and one matched AMR case; the 16-case matrix is a
qualification plan, not authorization to launch every case automatically. The
GPU owner reviews the pilot before expanding it. Each process prints a flushed
READY only after initialization, a real base step exercising every level's
kernel/halo/transfer path, and a finite positive-density download check. That
step belongs to the measured trajectory; it is not discarded warmup. PROGRESS
messages contain each of the five diagnostic samples. READY alone is not an
accuracy pass. Reports include per-level active cells, hops and collision updates.
The complete matrix costs 768,540,672 active collision updates and 21,504 root
intervals, excluding ghost streaming, halos, transfers and diagnostic work.
Uniform N256 is the largest case (268,435,456 updates / 4096 intervals per Re).
AMR N64/depth3 needs 50,987,008 updates / 1024 intervals. These are work counts,
not GPU wall-time estimates. Baseline comparisons remain available on failed
screens and partial pilots; absent/nonfinite operands are null, never passing.
Acoustic viscosity scaling and unchanged lattice velocity do not by themselves
prove nonequilibrium-stress consistency across refinement interfaces. A smooth
collocated Chapman–Enskog postcollision nonequilibrium has a (tau-1)*h factor;
the existing implementation instead uses volumetric piecewise-constant explosion
and stream-only ghosts. Whether that actual transfer construction achieves the
needed stress accuracy is an unresolved question for this pilot to measure.
It is not a proven defect, and a collocated-state scaling factor must not be
inserted into this different transfer operator without a separate derivation
and validation. This campaign measures the current operator and makes no
theoretical stress-consistency certification or production-kernel change.
## Repository integration
The four Python harness files remain together under tests/validation/taylor_green, so runtime provenance hashes precisely this harness directory. Formatting changes produce a new harness identity; preparation and integrated receipts must not be mixed. All analytic definitions, numerical floors, assessment gates, sample times, and source-import assertions are unchanged. Production source is unchanged from the cd3 snapshot; these periodic tests do not waive the separate channel GPU gate.
## Oblique shear wave (test-only diagnostic, not GPU-qualified)
`shear_wave.py` reuses the frozen oracle's constants, cell centers and
geometry. `oracle.py` is byte-identical, and `test_shear_wave.py` pins its
eec4677 SHA-256. `run_case.py --flow shear_wave` selects the shear wave;
the default flow and its receipt are the unchanged Taylor–Green path.
### Convention
Integer mode (2,1) on the L=N periodic root domain:
- the wavevector `k = (2*pi/L)*(2,1)` points 26.565° from +x;
- mode (1,2) would point 63.435°, and a wrong-mode test catches a swap.
Polarization is `E = (-1,2)/sqrt(5)`, perpendicular to k:
u = U*E*sin(k.x + phi)*exp(-nu*|k|^2*t), phi = 0, p = const, rho0 = 1
`nu = U*N/100`, the Taylor–Green Re100 viscosity at the same N. This is an
exact incompressible Navier–Stokes solution. The initial condition is FP64
second-order equilibrium at the actual leaf centers, with no
non-equilibrium part.
### Physical caveats
1. *Scope of the cubic-term argument.* The second-order D2Q9 equilibrium
lacks the cubic third moment `rho*u_a*u_b*u_g` of the Maxwellian (Dellar,
https://people.maths.ox.ac.uk/dellar/papers/Galilean.pdf, eq. 3). At
Navier–Stokes order this produces a stress error proportional to
`d_g(rho u_a u_b u_g)`.
For the ideal constant-density, zero-background transverse wave, k.E = 0
makes that contracted derivative vanish. That is the only claim made.
It does not remove other discrete or finite-Mach errors. It is not
guaranteed once AMR introduces density, longitudinal or higher-mode
contamination. The analytic NS field itself is exact.
2. *Startup.* Equilibrium initialization is not the discrete shear
eigenmode (Mei et al., https://doi.org/10.1016/j.compfluid.2005.08.008).
- The decay rate is a free-intercept least-squares fit of ln R over the
samples with t* >= 0.12, where `R = hypot(a_hat, b_hat)`.
- The intercept cancels only a constant amplitude prefactor, and only
once a single exponential dominates.
- Per-interval rates and the maximum log-fit residual are kept, so a
lingering transient stays visible.
- Late sampling alone does not show that transients have gone.
### Metrics
Computed on ACTIVE leaf cells, each weighted by its area `4**-level` in
root-cell units. The partition must cover the domain exactly once, and one
global pressure gauge is used.
- `a_hat`, `b_hat`: weighted least-squares fit of `u.E` onto sin/cos, using
the 2x2 Gram matrix of the actual composite quadrature. A wrong Fourier
mode need not project to exactly zero on this quadrature.
- `amplitude_error = R/A_exact - 1`.
- `phase_drift = atan2(b_hat, a_hat)`, in radians, reported separately.
- Rates are positive (minus the fitted slope).
- Per root step they are compared with `nu*|k|^2`. Uniform 2N uses its
own `nu = 0.0768` at N=256 and doubled step counts.
- In t* they are compared with `5*(2*pi)^2/Re = 1.97392088`.
- `rate_error = |rate/exact - 1|`.
- `velocity_l2`, `residual_l2` (velocity left after removing the fitted
mode) and `longitudinal_l2` (the `u.k_hat` part), all relative to the
exact-field norm. A longitudinal perturbation also raises the
full-vector residual and the velocity L2.
- `spurious_pressure_rms`: the raw gauged rms of `p = (rho-1)/3`.
- `spurious_pressure_scaled`: that rms divided by `A_exact(t)^2/4`, a
continuum reference scale. It is *not* the discrete, globally gauged
Taylor–Green norm on the composite grid. Exact pressure is constant, so
no relative-to-exact claim is made. Max and per-level values are kept.
### Preregistered screens (`shear_wave.assess`)
Run set: uniform N, uniform 2N, and refined depth-2 runs at root N.
- `eps(N) = (|k| h_root)^2 = 5*(2*pi/N)^2`: dimensionless, coefficient
one, 0.01205 at N=128. This is a chosen screen, not a proven error bound.
- Absolute screens:
- rate_error, max |phase_drift| (radians) and max residual_l2 must each
be <= eps;
- velocity_l2 <= 0.05, mass <= 1e-5, spurious_pressure_scaled <= 0.02.
- Budgets keep the `assess.py` form, `refined <= max(2*control_N, floor)`:
- floors are 0.002 for rate and residual, 0.02 for pressure;
- the comparative pressure budget is always redundant:
`max(2*control, 0.02)` is never below the 0.02 absolute ceiling;
- raw ratios to both the root and finest controls, including raw
pressure rms, are always reported.
- Every record is validated before any screen is applied:
- exact scheduled steps and t*, with no duplicates;
- every numeric field finite, including list fields and density;
- error quantities nonnegative and rho_min > 0;
- signed quantities (amplitudes, `amplitude_error`, `phase_drift`,
per-interval rate errors) keep their sign.
- Outcomes are kept distinct:
- INVALID_CONTROL: a control or refined run is missing, a control is
incomplete or invalid, or the records come from mixed sources;
- INVALID_RUN: a refined record fails validation;
- CONTROL_SCREEN_FAIL: complete, valid controls fail their own screens.
Each refined run's `own_screens_pass` is still reported, but
`controlled_pass` is false, so it is never a controlled-comparison pass;
- PASS/FAIL: every refined run's `controlled_pass` (own screens and
budgets against valid, passing controls).
- Finite modal extinction (late R = 0) is a physical failure, not
malformed data. The run gets `rate_fit_valid=false` with null fit
quantities, and its other metrics are kept. Nothing is clipped and no
rate is invented. The result is CONTROL_SCREEN_FAIL for a control, or
FAIL for a refined run.
- Screens are never retuned.
### Limitations
One flow, one phase and one rectangle, SRT only. The rectangle's vertical
faces span 0.625 tangential periods and its horizontal faces 1.5, so this
is not placement robustness. Two resolutions show a trend, not an order.
### Receipt assessment and runner integrity
- Fixed four-case N128 contract:
`python assess_shear_wave.py U128.json U256.json R128_constant.json R128_projected.json --output report.json --expected-revision <sha>`.
It reuses the shared provenance, build, workload and sample-time checks
from `assess_projected_pairs.py`, and adds shear metadata checks (flow,
mode, polarization, angle, phase, eps, limits, disabled early trace, and
pinned `shear_wave.py` hash).
- Missing, extra, duplicate or mixed-source records give `INVALID_SET`,
as does any failed shared check.
- Otherwise the result comes from `shear_wave.assess`, which separates
`INVALID_CONTROL` from `CONTROL_SCREEN_FAIL`.
- `run_case.verify_source(..., flow="shear_wave")` requires the imported
`shear_wave.py` to be the selected harness file with the pinned
`SHEAR_WAVE_SHA256`. The default TG flow does not import it.
- Sample and READY finiteness use `finite_row`, which accepts scalar and
list diagnostics. For TG's all-scalar rows it behaves the same as before.
- Merge note: native 92b8afe adds a `scaled_n256` receipt block. When the
two are merged, keep both blocks and make `--flow shear_wave` and
`scaled_n256` mutually exclusive. Not merged here.
### Scaled shear diagnostic (opt-in `scaled_shear_n256`)
Runner: `run_case.py --flow shear_wave --diagnostic scaled_shear_n256 --re 100`
with one of these four cases:
- `--n 256 --depth 1` (U256)
- `--n 512 --depth 1` (U512)
- `--n 256 --depth 2 --explosion constant` (constant R256)
- `--n 256 --depth 2 --explosion projected_linear` (projected R256)
Everything physical is unchanged from N128:
- `rectangles(256,2)` covers the same physical box;
- same t* schedule (16N root steps);
- `nu = U*N/100`;
- same `eps(N)`, limits and floors.
`scaled_n256` (Taylor–Green, from native 92b8afe) and `scaled_shear_n256`
each require their own flow, so they are mutually exclusive. N512 is
accepted only through one of the two diagnostics. The shear diagnostic
takes no early-pressure trace.
Assessment:
python assess_shear_wave.py U256.json U512.json R256_constant.json R256_projected.json \
--diagnostic scaled_shear_n256 --reference-files <four de5b0cc N128 receipts> \
--output report.json --expected-revision <sha>
- The scaled N256/512 case, build and workload checks come from the
92b8afe assessor. Its TG-only diagnostic identity and early-sampling
checks are not used. Instead every record must carry
`diagnostic=scaled_shear_n256`, and N128 records must carry none.
- The reference N128 receipts are hash-pinned to the audited de5b0cc
evidence (commit cba6bca). They are never relabelled as fresh controls.
- The report always includes, for each case:
- the raw signed rate bias `rate/exact - 1` and the interval errors;
- each refined run's signed excess over *each* uniform control (rate
bias, residual, raw pressure rms);
- the N128→N256 signed changes and ratios. The ratio is null when the
N128 value is zero.
- These are descriptive. Passing or failing another floor-controlled
screen is not the conclusion, and a two-resolution ratio is not a
convergence order.
- Portability: the receipt's recomputed `eps = |k|^2` is compared within
4 ULPs (`close_ulps`), not by exact equality. A cross-runtime replay
differed by one ULP: 0.012047856934923534 on Horsea vs
0.012047856934923532 elsewhere. Source and file hashes, case identity,
the other metadata and every scientific threshold stay exact.
### Nested shear preset (opt-in `nested_shear_n128`)
A fixed three-level, two-region preset, defined in `shear_nested.py`. The
wave, phase, Re100/U=0.03, initialization, five sample times, eps(root N),
limits and floors are the same as before.
- Refinements, given as parent-frame `(x0, y0, x1, y1)` rectangles on
level-wide, zero-origin unions:
- L0→L1: `(16,16,60,112)`, `(68,24,112,120)`
- L1→L2: `(44,44,108,212)`, `(148,60,212,228)`
- Leaves `[7936, 12288, 86016]`, hops `[2048, 4096, 8192]`, work
771227648 per refined case; 3723493376 for all four cases.
- Level ν `[.0384, .0768, .1536]`, τ `[.6152, .7304, .9608]`.
Cases (`run_case.py --flow shear_wave --diagnostic nested_shear_n128 --re 100`):
- `--n 128 --depth 1`
- `--n 512 --depth 1` — the finest control is 4N, not 2N
- `--n 128 --depth 3`
- `--n 128 --depth 3 --explosion projected_linear [--final-snapshot]`
`--final-snapshot` is allowed only for the projected depth-3 case. It writes
`<output>.final_macro.npz`, containing:
- ACTIVE leaves packed as `level`/`i`/`j`;
- `rho`, `ux`, `uy` from the FP64 physical populations at the final root
synchronization;
- embedded metadata: exact time, phase, mode and config.
It contains no populations, restart state or time series. Its SHA-256 and
size go into the receipt. A file over 8 MiB is removed and reported, never
kept. All old paths stay scalar-only.
Assessment: `assess_shear_wave.py U128.json U512.json R128c.json R128p.json
--diagnostic nested_shear_n128 --output report.json --expected-revision <sha>`.
- It reuses the case-agnostic provenance checks from the TG assessor, plus
exact nested scales, builds, patch, workload, metadata and the pinned
`shear_nested.py` hash.
- The physics is `shear_wave.assess` generalized only in its depth-3 / 4N
shape contract; the metrics are unchanged.
- `shear_wave.py` is byte-identical (81d5c8ee…), so historical receipt
identities and verdicts are untouched.
- This preset changes placement and refined volume as well as depth. It
gives no isolated cost of an extra level and no resolution trend.
### Depth-2 twin of the nested preset (opt-in `twin_shear_n128`)
`shear_twin.py` uses the same two L0→L1 boxes as `shear_nested.py`, with no
L2. Leaves are `[7936, 33792]`, hops `[2048, 4096]`, and work is 154664960 per
refined case (611319808 for all four).
The campaign is four fresh runs:
`run_case.py --flow shear_wave --diagnostic twin_shear_n128 --re 100` with
- `--n 128 --depth 1`
- `--n 256 --depth 1` (the finest control is 2N)
- `--n 128 --depth 2`
- `--n 128 --depth 2 --explosion projected_linear`
There is no snapshot option. Older exact controls serve only as consistency
checks; they are not reused as references.
Assessment uses the same preset contract as the nested preset, through
`assess_shear_wave.py ... --diagnostic twin_shear_n128`:
- the physics is the unchanged depth-2 / 2N `shear_wave.assess`;
- receipts must pin `shear_twin.py`, `shear_nested.py` and `shear_wave.py`;
- `shear_nested.py` stays byte-identical (fa6cfe87…), so the 335624c nested
receipts still validate.
Labels:
- *Twin vs nested* is the effect of adding this nested L2 refinement.
Removing L2 also changes the finest spacing and refined volume, so it does
not isolate abstract depth.
- *Twin vs the single-box depth-2 runs* is a placement/geometry contrast at
equal depth.
- Neither contrast is additive by construction.
- The thin-band/acoustic explanation for the nested L1 pressure is a
hypothesis, not established.
### Signed interface-probe traces (opt-in `--probe-trace`, mechanism diagnostic)
`shear_probes.py` (pinned) uses native's validated 24-target layout through
box 1, in root-128 physical coordinates:
- a horizontal line y = 56, crossing the vertical faces x = 16 and 22;
- a vertical line x = 38, crossing the horizontal faces y = 16 and 22;
- normal coordinates 12.5, 14.5, 15.5, 16.25, 17.25, 19.25, 20.75, 21.75,
22.125, 23.125, 24.125, 26.125.
Each target maps to the nearest ACTIVE leaf center. The deterministic tie
rule is: distance, then finer level, then smaller j, then smaller i. This
gives 24 unique cells in every case, and nested has 3 L0 + 5 L1 + 4 L2 per
transect. Maximum displacement from target to center is 0.625 root cells in
U128 (0.177 in U512).
Allowed cases:
- nested U128, nested U512, nested projected depth 3;
- twin projected depth 2.
The option can't be combined with `--final-snapshot`.
Sampling:
- The receipt stores each probe's leaf level, `i`/`j`, actual cell center
and displacement from its target, all in root-physical units (N=128).
- Grids differ between cases, so centers are *not* collocated. Analytic
fields are evaluated at each actual center (`shear_probes.residuals`), and
comparisons across cases are between residuals at nearby but distinct
centers.
- Times are root-physical steps 0–128 and 1920–2048. U512 is sampled every 4
lattice steps to match.
- Each sample stores `rho`, `ux`, `uy` from the FP64 physical populations,
POST-collision G at root synchronization only. No substep content is
observed, and grid-scale alternation can alias.
What's kept and enforced:
- The five qualification samples stay unchanged.
- No field dumps. The trace is validated for exact schedule, finiteness and
a 600 kB cap. If invalid it is dropped and an error is recorded, keeping
the scalar receipt.
- There are no new pass gates; this is a mechanism diagnostic only.
### Single x-gap-width contrast (`wide_x_shear_n128`)
This opt-in admits only Re100/N128/projected depth3 with `--probe-trace`.
The outer boxes, three grid spacings, viscosities, initialization, five main
sample times and trace windows are unchanged. L1→L2 parent-frame rectangles
are `[(56,44,96,212),(160,60,200,228)]`: both x-normal middle gaps widen from
6 to 12 root cells, while y gaps remain 6. Active leaves are
`[7936,20352,53760]`, hops `[2048,4096,8192]`, work 540,016,640 active updates.
This also moves the L2 x faces and reduces its volume; it is not a pure
travel-distance experiment. No new qualification matrix, assessor, threshold
or snapshot is added. Existing scalar screens and all failures stay visible.
The same 24 targets and actual-center metadata are retained. The horizontal
probes stop before the new inner face x = 28: they do not bracket that interface
or sample its fine side. The first 8 horizontal L0/L1 probes keep identical
centers, and the y-normal x = 38 transect is unchanged. Their temporal residuals
can support a descriptive timing contrast, but cannot establish a crossing
or reflection coefficient. Changed-level probes must not be treated as
collocated samples. `rho-1` remains raw density deviation; do not substitute
the 24-probe mean for the global pressure gauge.
### POST-G initialization counterfactual (`postg_shear_n128`)
Exactly three fresh Re100 cases are admitted: U128, U512, and projected R128
depth 3 with the original nested rectangles. Each requires `--flow shear_wave
--diagnostic postg_shear_n128 --probe-trace`; snapshots and early-pressure mode
are excluded. Geometry, physical velocity/density, viscosities, collisions,
five main times and the 24 signed probes/windows are unchanged. Total work is
2,952,265,728 active updates, with 15 main rows, 774 trace rows and five builds.
Only initialization changes. At level spacing h, k_level = h k and
A_i = 3 w_i U cos(theta) (c_i dot e) (c_i dot k_level). Initialize physical
FP64 **POST G = feq - (tau - 1) A**, then use the existing shifted FP32 codec.
This is the first-gradient, low-Mach Chapman-Enskog approximation, not an
exact discrete eigenstate. The PRE coefficient is -tau; the physical viscous
stress coefficient tau - 1/2 must not replace the raw POST-G coefficient.
The correction has zero mass/momentum before encoding; FP32 introduces normal
roundoff. U512 uses its native k and tau, matching nested L2 physical spacing.
Receipts pin the new initializer module and identify `postg_first_gradient_v1`,
with `qualification_eligible=false`. Existing scalar screens remain visible
as descriptive outcomes, including failures; no new pass gate or assessor is
introduced. Historical assessors reject the new diagnostic and initialization
identities. Compare raw rows and signed traces with the retained equilibrium
receipts as a startup-state counterfactual. The host first-interval pressure
RMS reduction is not a prediction of long-time improvement, and individual
probe errors can increase. All equilibrium paths and historical verdicts stay
unchanged.