Files

8.6 KiB

src coherence stage (from main 914906e)

Owner direction 2026-10-28: unified style over historical compatibility, inside src. No numerical change is intended. Stages after 5f69eba: 65339ab (one boundary/Jet record, host preparation helpers, pair accessors), c5a3cdb (block_collide families), 442979b (exchange metadata on the boundary record). All three received parent/candidate generated-config and host/GPU equality checks. Only the collision slice ran a new PTX matrix (a4fc46d, whose src is identical to c5a3cdb); 65339ab and 442979b reused prior PTX evidence after unchanged CUDA/compiler and generated-input checks. In the collision matrix, only the two channel-root SRT modules changed PTX (omega load/clamp moved); their parent/candidate outputs matched exactly in the exercised cases.

Conventions (defined once, in lbm.hierarchy.Hierarchy)

  • Level l = 0 .. depth-1 (0 = root). Pair hierarchy.pairs[l-1] builds level l.
  • Array shapes are (ny, nx); rectangles, origins and centers are (x, y).
  • Coarse/fine name the two members (parent/child) of ANY pair, not absolute L0/L1: fine_shape, fine_origin, prepare_fine_boundary, blocked_fine_tables, blocked_coarse_tables.
  • Refined levels (l >= 1) of FixedPatchStepper place bodies/Jets in the root EDGE frame (root cell i = [i, i+1)). Uniform Simulation objects AND the static circles of a single-level (depth 1) FixedPatchStepper use the integer-NODE frame. Nothing converts between them. This concerns input placement only: within the EDGE frame, refined levels still project root-edge coordinates to fine-local cell indices with the half-cell shift (prepare_fine_boundary: (v - o)/dx - .5; hits back via fine_hits_to_edge_frame origin + dx*(hit + .5)), using edge_frame/fine_origin below.
  • Hierarchy.edge_frame(l) -> ((ox, oy), h): cell (i, j) of level l's allocated array (ghost band and holes included) covers [o + h*i, o + h*(i+1)). A scalar FixedPatch2D window carries the half-coarse-cell ghost shift bounds - HALO/2 in fine_origin; a set's level-wide grid has origin 0. Level 1 boundaries are built from the root config (the wall-aware fields live there); deeper ones from the parent frame.
  • FixedPatch2D.fine_level_offset (was fine_level_origin) is an array INDEX offset (y, x), not an (x, y) origin.

FixedPatchStepper migration map

Historical: left column = names at or after 914906e that no longer exist; right column = the current name.

removed / changed replacement
patch, child_patch hierarchy.pairs[0], hierarchy.pairs[1]
base_layout, fine_layout, child_layout (stepper properties) layouts[0], layouts[1], layouts[2] (FixedPatchSet2D.fine_layout(block) is unchanged)
fine_boundary, child_boundary boundaries[1], boundaries[2] (host geometry; None = no bodies/Jets)
_jets jets[1]
_boundaries[l] (dict from L1, level keys), _level_boundaries (b4eacf7), _device_boundaries (65339ab) _boundaries[l]: the one combined per-level _BlockedBoundary record (list from L0, None at L0 unless single-level static circles): host geometry .host, .tables, .jets, .jet_cache, exchange .spacing/.centers, device handles
_fine_tables, _actuated, _jet_cache _boundaries[1].tables / .actuated / .jet_cache
_level_jets (private) _boundaries[l].jets (public jets[l] is derived)
_exchange_spacing[l], _exchange_centers[l] (private) _boundaries[l].spacing (h_l, root units) / .centers (root edge frame); only levels with a boundary report exchange
_level_blocks (private) _layouts[l].block
_remap_cfg (private) _root_cfg
refinement_tables.blocked_base_tables (also via refinement_stepper) refinement_tables.blocked_coarse_tables (import from refinement_tables; the stepper no longer re-exports)
_fine_leaf, _child_leaf leaf[1], leaf[2] (copies)
_middle_kind hierarchy.kinds[1]
_boundary_hosts (private) public boundaries[l] = _boundaries[l].host (host geometry only; the private record is the combined one)
remap_child(rects, child_objects=...) remap_finest(rects, objects=...)
set_jet_amplitude(i, a) (implicit level 1) set_jet_amplitude(i, a, level=l) (required)
read_raw_exchange(b) / read_exchange_window(b) (implicit level 1) read_raw_exchange(b, level=l) / read_exchange_window(b, level=l) (required)
_level_name(l) "base/fine/child" messages "level l"
refinement.MIN_PATCH_GAP deleted (no gap policy exists)
params.cuh HaloPlan, collide_trt_no_force deleted (zero references)

Kept: step_count, constructor keywords (refinements, level_blocks, level_objects, level_jets, coarse_boundary, explosion), Simulation.set_jet_amplitude(i, a) (one level), RemapTopology.from_config(..., child_objects=, child_jets=) (internal remap helper; "child" = the replaced level relative to its parent).

Responsibilities

  • Construction: _check_levels (inputs); host preparation, numpy only, before any device work: _level_layouts, _kernel_configs (per-level kernel configs), _host_boundaries, _prepare_blocked_boundary, _fluid_leaves; Hierarchy.edge_frame (geometry frames); then _planned_bytes() (memory preflight) and _build_level / _build_pair / _upload_boundary (device). A construction failure closes the partial instance. Observation reads share _observed_boundary + _summarize.
  • Pair accessors: rectangles (a scalar FixedPatch2D gives (bounds,)) and fine_level_offset ((0, 0) for a set) on both pair types; the types and their storage frames stay distinct.
  • Per-level state, by lifecycle:
    • Fixed plan structure (built once in __init__, read by _planned_bytes() before any allocation, readable after close() through the public views): _layouts, _level_cfgs, _leaf, _state, and in each _boundaries[l] record the host geometry .host, link tables, .jet_cache, .spacing, .centers.
    • Mutable boundary data in the same record: .jets and .tables["surface_velocity"], changed only by set_jet_amplitude (host prepare -> device write -> commit; an uncertain write fails the instance); device handles (.flags, .device, .kernel, ledgers) are set by _upload_boundary and cleared by close().
    • Runtime: _levels (_Level) holds compiled modules, kernels, the two population buffers (swapped per step) and transfer/kind handles. It is created only after the memory preflight and cleared on close(); .layout/.boundary reference the plan for _hop. Folding the plan into _Level would mix both lifecycles in one record.
  • Blocked kernels: operators/block_collision.cuh block_collide is the one collision extension point of BlockStep and BlockChannelStep. It computes rho/u once and reads no runtime force (d_params.fx/fy). Two compile-time families: uniform-equivalent (MRT on any level, SRT on the channel root BLOCK_ROOT_BC == 2): clamped omega, collide_mrt_no_force or collide_srt with its zero Guo term; and level SRT (BLOCK_ROOT_BC 0/1): unclamped omega, collide_srt_no_force, with the shifted direct-momentum feq under USE_DDF_SHIFTING. The uniform path keeps collide_dispatch (runtime force, LES, TRT).
  • explosion="projected_linear" stays an optional capability; "constant" stays default.

Not done / open

  • Two per-level config derivations stay distinct on purpose: Hierarchy.configs (_middle_config, wall fields reset on every refined level, geometry validation) vs. FixedPatchStepper._kernel_configs (reset only on level 1 of a slot_reservoir root; generates each level's config.h). Folding them needs a config.h/PTX diff gate.
  • No single-Simulation facade over FixedPatchStepper: the two own different state models (uniform node frame, body sync, forcing, checkpoint vs. fixed blocked hierarchy, edge frame, remap-as-new-instance). A facade would only forward calls; no concrete need found.
  • Deferred, each needing its own evidence first: sharing the channel-root cell/donor selector with OneStep (the closure functions are already shared; a shared selector changes uniform signatures and needs a uniform PTX gate); merging FixedPatch2D into FixedPatchSet2D (different origin, ghost band, layout size and addressing; needs a geometry/parity table and would need tiles that are not grid-aligned); one clamp_omega helper for uniform and blocked paths (it lives in the hash-pinned LES header turbulence_smag.cuh).
  • Tests, examples and validation callers are migrated separately (pinned runners stay frozen).