Test-only, on c6d5dc1. DenseBlockedRouteParity runs the same configuration,
initial state, body/Jet schedule and tilings on D/D [None, None], D/B
[None, FINE_BLOCK] and B/B [(12, 8), FINE_BLOCK], periodic and
slot/reservoir, for body-free, passive circle, actuated circle (+/-) and a
velocity Jet with an amplitude switch: every public and owner array must
match in FP32 bits and NaN masks at steps 0, 1, 2, 8 and after
re-initialize, and the D/B and B/B raw-exchange ledgers (last base step and
last substep) must be equal. No tolerance.
test_route_capability_matrix checks before CUDA what the dense route
rejects (raw exchange on a dense body level, shifted, projected, channel,
several L1 rectangles, depth >= 3 dense). The module docstring holds the
supported/unsupported table and the parked cases (MRT covered elsewhere,
shifted and depth >= 3 have no dense route, several bodies later).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8e1feff set root.last_raw on the single-level reference, which also makes
FixedPatchStepper._hop accumulate a ledger the reference never allocated.
The adapter now substitutes the raw output pointer in the BlockCurvedBoundary
launch (argument 10, as the deleted adapter did) and leaves last_raw unset;
Jet column and force arms still come through the root level boundary.
Comparison unchanged; no production change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Restores the PeriodicBlockStepper safeguard dropped in 8e1feff, for all
FixedPatchStepper levels: both G buffers, halo pairs and boundary columns
of every level are compared with cuda.mem_get_info() before the stream,
any module or any buffer exists, raising MemoryError('level buffers exceed
free device memory'). Transfer tables are not counted (lower bound).
Tests: the single-level MemoryError case is back beside the param-layout
check (no stream, no allocation); host test_single_level covers depth 1
and depth 2 (no stream, build or allocation) and the wait failure after a
good step (count stays 1). Driver-mocking fixtures report ample free memory.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The second owner of one blocked level goes. Its capability is the
zero-refinement FixedPatchStepper added in f764d68/985db14 (periodic SRT
level, stationary passive circles, shifted storage, NaN spare, single wait),
which matched it array for array on GPU at 1318fc2 (3 splits x +-circle x
shifted/unshifted) and passes the host lifecycle and fault contracts.
API change for callers:
PeriodicBlockStepper(cfg, BlockLayout2D.build(ny, nx, by, bx), context=c, objects=o)
-> FixedPatchStepper(cfg, context=c, refinements=[], level_blocks=[(by, bx)],
level_objects=[tuple(o)])
download() returns a 1-tuple; static-circle tables are
_level_boundaries[0].tables (was .boundary); no free-memory preflight.
- lbm/block_stepper.py deleted; MAX_GRID_DIM lives in refinement_stepper.
- tests/validation/multigrid/test_block_stepper.py: same frozen GPU gates
(split identity, FP64 oracle, circle across seams) and pre-CUDA rejection
cases on the single level; the old-vs-new bitwise test is retired with the
old class (its result is the 1318fc2 record).
- tests/unit/test_block_step_sync.py folded into test_single_level.py
(step(n) vs n x step(1) roles and one wait, step(0), mid-batch launch
failure), which also gains bad-state rejection before upload, download
failure and activation-failure retry on close.
- test_shifted_storage and test_raw_exchange_gpu use the single level; the
raw-exchange reference feeds the AMR Jet column and raw ledger through the
root level boundary instead of patching a private kernel field.
- Pinned historical runners (taylor_green/run_case.py, run_jet_circle_cv.py)
are unchanged: they only run on trees that still ship PeriodicBlockStepper.
No alias.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review follow-ups for S1 (f764d68):
- a single level starts its spare buffer NaN, as PeriodicBlockStepper does,
so stale halos cannot hide (multilevel initialization unchanged);
- projected explosion is rejected for a single level;
- new tests/unit/test_single_level.py: NaN spare after initialize, per-step
launch order halo -> BFL (circles only) -> BlockStep with a null kind and
one wait per step(n), circle solids excluded from the state mask;
- the GPU bitwise comparison also covers shifted storage.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A zero-refinement FixedPatchStepper is the PeriodicBlockStepper capability:
one doubly periodic blocked SRT level (no LES, Jets or exchange
observation) whose level_objects[0] are stationary passive circles. The
circle tables come from the same checks, now blocks.static_circle_tables
(moved from block_stepper, pycuda-free); BFL, halo and BlockStep launches
are the shared helpers, with an all-ACTIVE (null) kind. Base-level bodies
stay rejected for depth >= 2. PeriodicBlockStepper and its callers are
unchanged (deleted only after S1's GPU result).
Tests: host contract rejections before CUDA for the single level; GPU
bitwise comparison against PeriodicBlockStepper for every split, with and
without the circle (the S2 gate).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The package already exposed it as CelerisLab.cuda.compiler; the module now
has that name and every tip caller, doc and current-tree test imports it
directly (no alias).
Historical-revision tooling is not edited: the Taylor-Green harness
(run_case.py, hash-pinned check_projected_pairs.py, assess receipts) only
runs against a135252, whose package has cuda/compiler_v2.py, and the J
campaign runners and dated docs describe past trees. Its two current-tree
tests now import that package from git (historical_package) instead of the
tip, and the kernel-root test first checks the accepted case.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PeriodicBlockStepper and FixedPatchStepper each built the blocked level's
kernel config (block window NX/NY, neutralized wall/slot/inlet fields,
omega/tau check) and each spelled out the raw BlockHaloCopy and
BlockCurvedBoundary argument lists. These now live once in lbm/blocks.py
(level_config, launch_halo_copy, launch_curved_boundary), so a kernel ABI
change has one host site. Both owners keep their own lifecycle; no new
class, no behaviour or default change. PeriodicBlockStepper now checks its
level config before any device work (same errors). Dense refinement levels
keep their own config check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kernel_v2.cu -> uniform.cu (whole-domain NX/NY, Simulation) and
blocks.cu -> blocked.cu (one block window, every blocked level), with
InitTubeFlow_v2 -> InitTubeFlow. All live callers, include comments,
CONFIG.md, lifecycle doc and current-tree tests move together; no alias.
refinement.cu keeps its name until the dense-route decision.
Historical-revision tooling that names the old files (LES source pins,
timing/J campaign runners, TG run_case, supported_settings citations at
888c8038, development notes) is unchanged on purpose.
No arithmetic change; the PTX symbol InitTubeFlow_v2 is renamed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Test-side only; no production, manifest or pin change. Group A identity
checks (test_source_pin and the jets.py pins) are unchanged and stay
failing as recorded.
B test_refined_dfg: receipt/plan fixtures load the frozen manifest JSON
that verify_source returns for a matching tree (frozen_manifest), and
the two manifest-selection assertions call verify_source with only its
working-tree hash comparison neutralised (selected_manifest), so the
malformed/collision/observation-mode/checkout receipt checks run again.
test_source_pin remains the single identity check.
C test_channel_root: int(owner)-1 (uint64-int became float on NumPy 1);
test_shifted_storage: FP32 NaN fill so the arrays stay FP32. Both reach
the intended immutable/representation/FP32/density checks.
D test_block_stepper fake gets _ddf_shifting; test_fine_surface_gpu sets
_boundary_hosts/_level_jets instead of the read-only fine_boundary view;
test_refinement_followup fake_backend sets _layouts/_ddf_shifting/
_level_cfgs instead of the read-only fine_layout view (as reviewed in
32da2d73).
E test_kernel_contracts_reject_before_upload: an inconsistent pair tau is
now first rejected by the hierarchy chain check; the test asserts that
rejection, then bypasses _check_chain to prove the per-level omega/tau
guard still rejects, and asserts no mem_alloc/memcpy_htod in either case.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One local levels(bounds, blocks, objects, jets, **rest) builds the
two-level lists; run_steps and every rejection case use it. All five
before-CUDA rejections, the margin and one-jet checks keep their inputs.
Assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dense root + blocked fine level is level_blocks=[None, block]; bodies go
to level_objects[1]. Both before-CUDA rejections (non-dividing and
malformed fine block) keep their inputs. Assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FixedPatchStepper and the PeriodicPatchStepper alias are called with
refinements=[bounds] instead of the positional legacy bounds (same
_legacy_levels result). Assertions, including the before-CUDA and
four-cell/omega/layout rejections, unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
KW becomes levels() (scalar L1 + scalar L2, per-level blocks, objects,
Jets). All rejection cases are kept per level. Two cases change branch:
L2 bodies/Jets with no nested child (legacy 'child_objects/child_jets
require a nested child') are now an entry for a level that does not
exist ('needs one entry per level'); several L1 patches + scalar child
now meets 'a scalar child requires a scalar parent'. Both still reject
before CUDA. Assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_refinement_mrt_gpu, test_shifted_jets_gpu and
test_refinement_blocked_base pass refinements/level_* lists. The three
blocked-base rejection cases keep their inputs per level; base-only
blocks now meet the level-list rule (blocked refined levels below) where
the legacy keyword check fired before. Assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_exchange_window, test_raw_exchange_gpu (one fine(block) helper for
the repeated circle+jet construction), test_refinement_jets,
test_multiple_pinned_remap_gpu and test_pinned_body_remap_gpu pass
refinements/level_* lists. Dense fine levels stay level_blocks=[None,
None|block] as before. Assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_refinement_gpu (incl. PeriodicPatchStepper alias calls),
test_channel_root_gpu, test_fine_surface_gpu, test_shifted_remap_gpu,
test_runtime_child_remap_gpu and test_refinement_three_level_multipatch_gpu
pass refinements/level_* lists; scalar and set children map to the second
refinement entry exactly as _legacy_levels did. Assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
baba5e0 replaced _advance_child with _advance(index, parent_buffer) driven
from _hop; the two feed-order tests still patched the removed method.
Patch _advance and record only index 2 (L1 hop feeding L2); assertions,
expected order and the stale-feed negative control are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 3f47436073)
Integrate reviewed test changes from 7c1517de819741907fb945ea0ab7864734fa3856 and 340ba4e1dc6386581839c0b28c8fe8a1f4aeb70b unchanged. Document bounded 2D implementation, evidence and open gates; production source and historical manifests are unchanged.
Separate GPU class for a shifted MRT, all-blocked, stationary-body case
without Jets: window totals vs summed per-base reads (substep-scaled
tolerance), bitwise populations vs a raw-only stepper, a single step(N)
stepper with bitwise-equal window rows and populations, step(0)
non-change, and reset after a window. SRT/Jet test stays separately
scoped. Test-only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Scale the window-vs-summed-reads tolerance by the actual absolute fine
substep contributions (last_raw after every fine hop), labelled a
conservative engineering tolerance rather than a proof. Compare
populations by finite FP32 bits plus NaN masks and reject infinities.
Test-only.
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>
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>
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>
prepare_fine_boundary accepts a FixedPatchSet2D: objects are projected once
onto the level-wide fine grid (FixedPatchSet2D.fine_origin = (0, 0), same
coarse cell-edge -> fine cell transform), each circle must lie inside one
patch, coarse transfer cells are checked against the covered union, and body
ids stay object positions, so the existing jet one-body-per-jet, overlap and
(receiver, dir) writer checks run once over the whole level (caller obj_id
cannot bypass them). The stepper no longer rejects fine_objects/jets with
several patches; blocked link tables, BFL and the jet amplitude cache are
reused unchanged. No kernel change. README/docstring scope updated.
Tests: CPU translation/ids/rejections (outside one patch, one jet over two
bodies at zero amplitude); GPU one body via the new path == single-patch path
(both modes), two bodies (+jets, amplitude switch) == tiled single (bitwise).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FixedPatchStepper(..., child=(x0,y0,x1,y1), child_block=(by,bx)) adds an L2
patch in L1 window cells (requires fine_block/base_block, one L1 patch, no
bodies/jets). nest_patch() builds the L1->L2 FixedPatch2D (2*nu on L1) and
the composed L1 kind (inherited INNER/OUTER kept, child-covered ACTIVE made
OUTER), rejecting from the actual tables: coverage outside ACTIVE, donors or
receivers not uncovered ACTIVE, surviving ACTIVE pulls of covered/OUTER cells
without a child-supplied arrival, and overlap with L1's restriction footprint.
Step order per L1 hop: explode L1(src)->L2, two L2 hops (halo, step), L1 halo,
receiver-local L2->L1 staging into src, L1 step. The second hop thus feeds L2
from the new L1 G; L2 is never refilled from L0; L0 stays once per step (1:2:4).
Existing kernels only; a small _Pair holds the child transfer bindings (explode
from the child module, parent window stride). Two-level API unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FixedPatchSet2D.fine_layout rejects non-positive, float, bool or wrong-length
block sizes with ValueError before any modulo (was ZeroDivisionError/TypeError).
The face gap-4 GPU test now checks raw owner cores directly by kind/covered
for every patch (ACTIVE finite, OUTER/holes/covered NaN; INNER not asserted),
not only the masked download and reversed-order parity. README documents the
body-free multipatch call, scope and level-wide fine shape.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One rectangle via the multipatch path is bit-identical to the old
single-patch blocked path (both modes, raw masks); S1 two-patch 16x32 equals
the 16x16 one-patch run tiled (bitwise), in both rectangle orders; face
gap-4 pair is order-invariant with exact covered/hole masks. Mass printed
as a diagnostic only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Caller obj_id 99 spanning 2x2 fine blocks: driven rows carry the single
remapped owner 0 across several block ids, accepted; source id unchanged.
Caller ids (99, 7) under one tube are rejected at amplitude 0 and .002
on the 32x24 fixture; source ids unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
surface_link_velocity (the shared host check used by CurvedLinkSoA,
ObjectManager sync, prepare_fine_boundary and FixedPatchStepper) now
rejects a jet whose selected cut links carry more than one body id, at
any amplitude, before uploads. Identity is the scene-wide body id of the
physical cut-link list, so one body spanning storage blocks stays valid.
No body selector; empty-selection semantics unchanged.
Tests: two bodies under one jet rejected (amplitude 2e-3 and 0) on the
Simulation/manager path and on the fine path; separate jets on separate
bodies accepted on both; one fine body crossing 2x2 block seams accepted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FixedPatchStepper.set_jet_amplitude validates index/amplitude and builds
the new rows before touching the device; invalid input leaves the
instance usable. A copy/sync error marks it failed (as initialize/step/
download do) and re-raises; host state (_jets, blocked velocity table)
commits only after a successful upload. CurvedLinkSoA.set_jet_amplitude
likewise uploads a new array first and commits jets/surface_velocity
afterwards. Focused mocked-driver tests for dense and blocked copy
failure, invalid input and IndexError.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FixedPatchStepper(..., jets=()) passes jets (coarse cell-edge frame, as
fine_objects) to prepare_fine_boundary, which runs the shared assignment
checks before CUDA. Dense fine path: assign_surface with jets and the
boundary's true hits. Blocked path: surface_link_velocity with jets/hits;
unit-amplitude shapes cached. set_jet_amplitude (new/ready only) validates
first, then rewrites the dense SoA column or the blocked jet rows and
re-uploads only the velocity buffer after a stream sync. Scheduling,
kernels and launch ABI unchanged.
tests/validation/multigrid/test_refinement_jets.py: mocked-driver CPU
checks and frozen GPU gates G1-G3 (layout identity, jet vs legacy <=1e-6,
amplitude switch).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>