test_shifted_jets, test_shifted_storage, test_raw_exchange and
test_channel_root pass refinements/level_* lists; examples
fixed_patch_jet and fixed_periodic_patch pass refinements=[BOUNDS]
instead of the positional bounds. Assertions kept; the shifted-storage
case base_block-without-fine_block now expects the level-list rule
'blocked refined levels below' (same constraint).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
KW (legacy base/fine/child blocks + child_rectangles_in_parent) becomes
levels(): refinements=[PARENTS, CHILDREN], level_blocks, level_objects,
level_jets. Every negative case is kept and expressed per level (child
rectangles, per-level blocks); the L1-body case now expects the level-list
rule's message 'only on the finest level' instead of the legacy keyword
message 'only on L2' (same constraint).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The module-level import of CelerisLab.lbm.block_stepper loaded
pycuda.driver into the shared test process, unlike the other CPU host
tests (which load mocked copies via AST). find_spec gives the source path
without the import. Test content and assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review follow-up (non-blocking items): a launch failure on the second of
three steps fails closed without the batch wait, keeps step_count at its
entry value and blocks download; the docstring now states, as for
FixedPatchStepper, that async faults surface at the single wait.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Same change as the reviewed FixedPatchStepper end-sync (cherry-picked
ad1d82c+512dcc9 above): the n steps are enqueued in order and the host
waits once; step(0) launches nothing; step_count advances after the wait
and keeps its entry value on failure. Launches, buffer roles and bits are
those of n step(1) calls. Mocked-driver host test covers the single
wait, launch/role equality with n step(1), step(0) and failure.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Enqueue all n base intervals in order on the one stream and synchronize
once before returning (step(0): no launch, no wait). step_count, the raw
exchange ledger and an open window are published only after that wait;
any failure leaves step_count at its entry value and invalidates both
ledgers. Async device errors are no longer attributed to an interval;
the docstring says to use step(1) loops to localize one. Launch order and
buffers are unchanged. Adds a mocked-driver host test of the contract.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
BlockStep, BlockChannelStep and refinement.cu patch_collide each carried
the same compute_rho_u -> omega clamp -> collide_mrt_no_force sequence.
collide_mrt_unforced (collision_mrt.cuh, __forceinline__) now holds it
once; the three sites call it. Same operations in the same order: no
numerical, ABI or SRT change. The host source contract now requires one
helper definition and exactly one call per file, and forbids the old
inline sequence.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Supersedes 71221837. Samples every t* 0.5 (interval-mean forces), trailing
t* 50..60 window (21 samples); range <= 10 % and |slope*window| <= 2 % of
each official band width. Verdict on the window mean with the distance to
the nearest band edge. Our engineering rule, frozen before any run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 869d60d78e)
Samples every 0.5 s at synchronized root steps; trailing 5 s window (11
samples); range and |slope*window| each at most 1 % of the official band
width. States the fluid-on-cylinder force sign, reports cd_positive,
defaults to the refined case and uses the review's label.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 71221837f9)
Reuses the pinned Re100 runner and helpers unchanged; sets only the
lattice viscosity for Re 20. Reports Cd, Cl and p_diff (dp * 0.04 for
U = 0.2 m/s), a steady rule frozen before any run (window ranges at most
a tenth of each official interval width) and no interval verdict when
not steady. Declares the pressure-NEQ outlet and Zou-He inlet deviations.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 9b8ff90609)
A (per-base read-and-sum per 80-step interval), W (window + step(80) +
one read) and W1 (window + 80 x step(1)) over equal simulated duration
from the same fresh state and warm-up, 3 interleaved repeats. Bitwise
populations and per-interval total impulses (documented engineering
tolerance) are compared outside timing; health checks untimed. Records
candidate source identity (revision, dirty flag, file hashes) and does not
use or modify frozen refined-DFG manifests/results.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FixedPatchStepper(observe_window_exchange=True), which requires
observe_raw_exchange, allocates a second per-link FP64 ledger per body
level. While a window is open, the unchanged BlockAccumulateExchange
kernel also accumulates into it after each fine hop. Small API:
start_exchange_window() zeroes and opens at the current completed step;
read_exchange_window(body_id, level=) is non-destructive and reports
impulse with rates over the integer window duration. initialize/
_initialize_raw and step failure invalidate; remap builds a new instance
with no open window; Jet amplitude updates may stay in-window. Default
disabled: no allocation and no extra launch; last_substep/last_base_step
unchanged. summarize_exchange gains window='window' with duration.
Host contract tests (mocked driver) and a GPU gate against summed
per-base reads with a reordering-bound FP64 tolerance.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Simulation.get_ddf() is flat (9*ny*nx); view it as (Q, cells) before
applying the fluid mask, with a flat-DDF regression. Label A/E as
runner-like force-read workloads (values discarded, no aggregation or
validation; no macro/probe/CSV cost; not benchmark throughput) and split
status lines into CONSTRUCTED and WARM_READY. Test/doc only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Untimed physical-leaf/fluid health after warm-up and after each timed
window using the existing runner limits (finite macros, rho in [0.5,1.5],
max Mach <= 0.2); refined masks as in run_refined_dfg. Parity comparator
rejects unequal level counts and any infinity; matching NaN stays allowed
only as a storage mask. Regression tests for both. No numerical gate or
production change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Explicit stream synchronization before/after each timed loop (refined
FixedPatchStepper stream, uniform Simulation stream, in their contexts);
required --max-wall-seconds outer timeout checked between variants and in
per-step loops; untimed finite leaf/fluid health checks; force notes for
B/C/E' (no host reads; final base interval only; whole-window average with
different summation order). Parity stays A/B/C vs A and E/E' vs E only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Wall-time A/B/C/E/E' variants over equal simulated duration, reusing
run_refined_dfg setup functions. Fresh state and identical warm-up per
repeat, 3 interleaved repeats, construction/JIT, warm-up and bitwise
population/NaN-mask parity checks outside timed regions. B, C and E' are
labelled timing-only (no valid force history). No numerical or
production change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove MRT from the FixedPatch2D rejection matrix (TRT and other
rejections retained); convert host MRT tests to stdlib unittest; add GPU
gates for unshifted dense-vs-blocked MRT two-level roots (exact bits) and
a shifted all-blocked three-level MRT smoke checking per-level omega.
No numerical source change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Additive compile-time COLLISION_MODEL == 2 branches in BlockStep,
BlockChannelStep and patch_collide repeat the uniform collide_dispatch
MRT sequence (zero forcing, omega clamp, collide_mrt_no_force). SRT
statements, including the shifted retained-delta/direct-momentum path,
are unchanged under the alternate branch. Guards accept SRT or MRT only;
TRT, LES, non-FP32, non-double-buffer and shifted dense/mixed refinement
stay rejected. Transfers, subcycling, BFL, raw ledgers, channel closures,
shifted-Jet SRT guard and PeriodicBlockStepper are untouched. Existing
MRT operator, shifted representation and fixed kinetic rates are reused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Jet gains a last field condition='velocity'. 'pressure' raises
NotImplementedError in __post_init__ before profile/amplitude validation, so a
pressure jet never reaches surface_link_velocity, tables or kernels; unknown
values raise ValueError. Amplitude stays a lattice velocity (not a flow rate);
no pressure units, field reuse, tables or kernel changes are introduced.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit fbf6f1d122)
Schedule test drives _pairs[i].explode/coalesce and patches _advance(index,
buffer) for the stale L1->L2 feed mutant; remap rejection test patches
_boundary_hosts entries and hierarchy.pairs instead of the read-only views;
the GPU launch-failure test patches _pairs[0].explode. Assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
build_hierarchy(cfg, [], wall_aware=True) left both base wall rows ACTIVE;
the refined path already marked them OUTER. Add the regression test.
Found by native review of eeb90ac.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lbm/hierarchy.py loops the existing pair logic (FixedPatch2D/FixedPatchSet2D
for L0->L1, nest_patch/nest_patch_set for deeper pairs, _middle_config for
the per-level config chain) and returns validated per-level configs, pair
tables and composed kinds for any depth. Legacy scalar window forms are
accepted so existing public shapes are unchanged. Validates each config copy
because LBMConfig.omega is only computed by validate(). Not yet used by the
stepper.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>