Tests load research drivers via importlib under unique module names instead of a bare 'import run' (shared-process collision between the Dütsch and VIV drivers). lifecycle.md qualifies immutable geometry and the host-only get_flags for translating circles; supported_settings.md points to the dense-only moving-circle feature; leontini_viv_predeclare.md is renamed viv_re150_predeclare.md (Re 150 Kolahdouz/Qin case) with references updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4.3 KiB
4.3 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 blocked slot/reservoir root reads its slot from the d_block_wall constant (the former dense route used WALL_* macros; both were bit-identical in the parity gates). |
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, except translating circles on the uniform grid: their swept-band flags and cut links are rewritten on the device every advancing step (MovingCircleCells/MovingCircleLinks, docs/moving_bodies.md); the host flag mirror is then stale for those cells. Uniform grid otherwise: rebuilt by body sync. FixedPatchStepper: a geometry change is a new instance (remap_finest), 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). |
Input (index, level, amplitude) is validated before any device write; invalid input changes nothing and the instance stays usable. The host copy commits only after the upload returned. Any error after validation leaves the device column undefined and fails the instance: FixedPatchStepper status failed, Simulation._failed; every later device-touching public method (Simulation: stream, set_jet_amplitude, initialize, sync_bodies, run/step, read_surface_exchange, read_body(s), get_macroscopic, get_ddf, update_runtime_params, snapshot, restore, save/load checkpoint) raises; cached host readers and host-side staging (e.g. get_flags without translating circles, add_body/remove_body before a sync) do not touch the device and stay callable; with translating circles get_flags reads the device flags back and refuses after a failure. Translating-circle targets follow the same rule: set_body validates before mutation, the applied offset commits only after a successful synchronized step, and a failed moving step fails the instance (docs/moving_bodies.md). close() still releases resources and stays retryable. |
| 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) were removed:level_blocksis required and every refinement level is blocked.
A single-rectangle refinement (FixedPatch2D) is stored in its own fine
window frame (FixedPatchStepper.__init__,
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).