117 lines
8.6 KiB
Markdown
117 lines
8.6 KiB
Markdown
# 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).
|