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 at1318fc2(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 the1318fc2record). - 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>
3.0 KiB
3.0 KiB
Device state lifecycle (uniform Simulation, FixedPatchStepper)
State is grouped by what a change invalidates. This file describes the code as
it is; it adds no framework. Line references are to candidate 0f8fdbc3.
| Class | Contents | How it changes | Owner rule |
|---|---|---|---|
| 1. Module and its globals | Compile-time (visible to the compiler, fixed per module): config.h macros incl. NX/NY, COLLISION_MODEL, BLOCK_ROOT_BC, WALL_*. Runtime per-module globals (not visible to the compiler; written by host code): __constant__ d_params, d_w, d_cx, d_cy, d_block_channel, d_block_wall; plus bound kernel handles |
Globals are written once by the owner right after load_module. Uniform grid: Simulation._recompile (construction, body-topology sync) loads a new module and re-uploads; update_runtime_params rewrites d_params (omega, force, n_objects) between runs. Steppers: never rewritten after construction, so they are immutable for the instance's lifetime although they are runtime values. The same quantity can be a macro in one route and a global in another (dense slot root: WALL_SLOT_WIDTH/WALL_NORMAL_VELOCITY macros; blocked slot root: d_block_wall), which can change generated arithmetic. |
Every owner loads its own module (compiler.load_module = module_from_file, no cache). A loaded module is never shared between live owners: globals are per module, so sharing would share mutable d_params. |
| 2. Geometry, layout, tables | flags, curved-link tables, block layouts and halo pairs, transfer (explode/coalesce) tables, block kinds | Immutable for the life of an instance. Uniform grid: rebuilt by body sync. FixedPatchStepper: a geometry change is a new instance (remap_child), committed only after a successful transfer. |
No in-place table edits. |
| 3. Controls and dependent boundary columns | Jet amplitude -> per-link surface_velocity; body actions (uniform grid) |
Between steps, without a table or module rebuild (set_jet_amplitude). |
Host copy commits only after the device upload succeeded; a device error fails the instance. |
| 4. Per-step state | population double buffers and their parity, raw-exchange ledgers, observations | Device-only during step(n) / run(n); buffer swaps are host-handle swaps. |
Valid on the host only after the single wait at the end of the call. |
Storage routes are separate concerns:
- Original uniform grid (
uniform.cu,Simulation): whole-domainNX/NY. - Blocked levels (
blocked.cu; everyFixedPatchStepperlevel, including the single level ofrefinements=[]):NX/NYare one block window including halo. - Dense refinement levels (
refinement.cu,level_blocks[l] is None).
A single-rectangle refinement (FixedPatch2D) is stored in its own fine
window frame in both dense and blocked form (refinement_stepper.py:222-224,
BlockLayout2D.build(*pair.fine_shape, ...)). Only a rectangle set
(FixedPatchSet2D) uses the level-wide frame (2*ny, 2*nx), whose
fine_layout requires that full grid to be divisible by the tile
(refinement.py:240-252).