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>
89 lines
7.9 KiB
Markdown
89 lines
7.9 KiB
Markdown
# Supported settings: 2D Jet + fixed multilevel refinement (candidate 888c8038)
|
|
|
|
Every entry names the guard that enforces it (file and function or kernel guard,
|
|
at source revision 888c80381c006e976be2af8a452288729fc17c1b) and, where one
|
|
exists, an existing test that exercises it. A setting not listed here is not
|
|
claimed. Observations at the end are tied to the exact case in which they were
|
|
measured; they are not general bounds.
|
|
|
|
## Lattice, storage, collision
|
|
|
|
| Setting | Supported | Guard |
|
|
|---|---|---|
|
|
| Dimension / lattice | 2D D2Q9 only (3D refinement is future work) | `lbm/refinement.py` `FixedPatch2D.from_config`; `#error` guards in `lbm/kernels/blocks.cu` and `lbm/kernels/refinement.cu` |
|
|
| Precision / streaming | FP32 storage, double buffer | same guards |
|
|
| Collision on refinement levels | SRT or MRT; TRT and LES rejected | `lbm/refinement.py` `FixedPatch2D.from_config` (re-checked for fine boundaries in `prepare_fine_boundary`) |
|
|
| Shifted (ddf_shifting) storage | only when every level is blocked; dense or mixed rejected | `lbm/refinement_stepper.py` `FixedPatchStepper.__init__`, `FixedPatchStepper._check_storage`; `#error` guard in `lbm/kernels/refinement.cu` (dense patch kernel unshifted only) |
|
|
| Fine relaxation | 1/tau_fine must lie inside the configured omega guards | `lbm/refinement.py` `FixedPatch2D.from_config` |
|
|
| Single blocked level `FixedPatchStepper(refinements=[], level_blocks=[(by, bx)], level_objects=[circles])` (replaces `PeriodicBlockStepper` after 888c8038) | doubly periodic, SRT only, no LES/Jets/projection/exchange observation, stationary passive circles; `download()` returns a 1-tuple | `lbm/refinement_stepper.py` `_check_levels`, `FixedPatchStepper.__init__`; `lbm/blocks.py` `static_circle_tables` |
|
|
|
|
Tests: `tests/unit/test_refinement_mrt.py`, `tests/validation/multigrid/test_refinement_mrt_gpu.py`,
|
|
`tests/unit/test_shifted_storage.py`, `tests/unit/test_shifted_block_operators.py`.
|
|
|
|
## Refinement hierarchy (`FixedPatchStepper(cfg, *, context, refinements, ...)`)
|
|
|
|
| Setting | Supported | Guard |
|
|
|---|---|---|
|
|
| Depth | at least one refinement level; one entry per level in `level_blocks`/`level_objects`/`level_jets` | `lbm/refinement_stepper.py` `_check_levels` |
|
|
| Single L1 rectangle | two-coarse-cell margin to the domain edge | `lbm/refinement.py` `FixedPatch2D.from_config` |
|
|
| Several L1 rectangles (union) | require `level_blocks[0]` and `level_blocks[1]`; transfers must close (dependency checks, no fixed gap rule) | `lbm/refinement_stepper.py` `_check_levels`; `lbm/refinement.py` `_check_parent_pull_closure` |
|
|
| Nested levels | depth >= 3 must be all blocked; a blocked level requires blocked levels below; a scalar child needs a scalar parent | `lbm/refinement_stepper.py` `_check_levels`; `lbm/hierarchy.py` `build_hierarchy` |
|
|
| Nested transfer support | child only over inherited ACTIVE cells, donors/receivers uncovered ACTIVE, no child over the parent restriction footprint | `lbm/refinement.py` `_nested_kind` |
|
|
| Tile shape | positive `(by, bx)`; the level allocation must be divisible by the tile (no partial tiles yet) | `lbm/refinement_stepper.py` `_check_levels`, `lbm/refinement.py` `FixedPatchSet2D.fine_layout` (shape); `lbm/blocks.py` `BlockLayout2D.build` (divisibility) |
|
|
| Coarse boundary | `periodic`, `slot_reservoir` or `channel` | `lbm/refinement_stepper.py` `FixedPatchStepper.__init__` |
|
|
| `slot_reservoir` | on-site velocity bottom slot, reservoir top, velocity 0, 2 <= slot width < nx, patch rows 4..ny-4 | `lbm/refinement_stepper.py` `FixedPatchStepper.__init__`; `lbm/refinement.py` `prepare_fine_boundary` |
|
|
| `channel` | all levels blocked; Zou-He inlet, pressure-NEQ outlet, stationary bounce-back walls; transfers away from the closure | `lbm/channel.py` `validate_channel_config`, `validate_channel_transfers` |
|
|
| Explosion | `constant` (default); `projected_linear` only periodic, all-blocked SRT, no bodies/Jets, no LES (experimental) | `lbm/refinement_stepper.py` `FixedPatchStepper.__init__` |
|
|
| L2 runtime remap (`remap_child`) | periodic three-level L2 sets only, no L0/L1 bodies, identical pinned boundary | `lbm/refinement_stepper.py` `FixedPatchStepper.remap_child` |
|
|
|
|
Tests: `tests/unit/test_refinement_three_level_multipatch.py`, `tests/validation/multigrid/test_refinement_multipatch.py`,
|
|
`test_refinement_three_level.py`, `test_refinement_three_level_multipatch_gpu.py`, `test_refinement_blocked_base.py`,
|
|
`test_refinement_blocked_fine.py`, `test_channel_root_gpu.py`, `tests/unit/test_channel_root.py`,
|
|
`tests/unit/test_projected_pair_stepper.py`, `test_runtime_child_remap_gpu.py`, `test_pinned_body_remap_gpu.py`.
|
|
|
|
## Bodies and Jets on refined levels
|
|
|
|
| Setting | Supported | Guard |
|
|
|---|---|---|
|
|
| Bodies | stationary circles without sensor/force-region roles, entirely inside the patch union, fully resolved, disjoint, stencil away from the two-hop transfer footprint | `lbm/refinement.py` `prepare_fine_boundary` |
|
|
| Level | not on L0; only on the finest level of a nested hierarchy | `lbm/refinement_stepper.py` `_check_levels` |
|
|
| Jet condition | velocity only; `pressure` is reserved and raises NotImplementedError | `body/jets.py` `Jet.__post_init__` |
|
|
| Jet geometry | each Jet selects resolved links of exactly one stationary body; no Jet/Jet or Jet/SurfaceActuation overlap; abs(amplitude) < 1 lattice | `body/jets.py` `Jet.__post_init__`, `jet_link_shapes`, `_surface_links` |
|
|
| Jets with shifted storage | only in the all-blocked stepper with SRT and no LES | `body/jets.py` `_surface_links` |
|
|
| SurfaceActuation | unshifted storage only | `body/objects.py` `SimObject.validate_surface_actuation` |
|
|
| Raw boundary exchange (force) | blocked body levels only; the window ledger requires `observe_raw_exchange` | `lbm/refinement_stepper.py` `FixedPatchStepper.__init__` |
|
|
| Checkpoint with Jets | refused | `simulation.py` `Simulation.save_checkpoint` |
|
|
|
|
Raw exchange is the cut-link momentum reaction (wall + aperture), not a validated
|
|
nozzle thrust or stress load. Jet amplitude is a lattice velocity, not a flow rate.
|
|
|
|
Tests: `tests/unit/test_jets.py`, `test_jets_review.py`, `test_shifted_jets.py`, `test_raw_exchange.py`,
|
|
`tests/validation/multigrid/test_refinement_jets.py`, `test_shifted_jets_gpu.py`, `test_raw_exchange_gpu.py`,
|
|
`test_exchange_window.py`, `test_fine_surface_gpu.py`.
|
|
|
|
## Observations from specific tested cases (not general bounds)
|
|
|
|
- SRT channel root vs uniform OneStep, strict-parity test
|
|
`tests/validation/multigrid/test_channel_root_gpu.py::ChannelRootGPU::test_uniform_matched_root`:
|
|
in one of its 18 sub-cases (2 storage modes x 3 profile/clamp/damp settings x 3 blocks; which
|
|
one is not recorded), 1 of the 4320 compared values differs, max abs 2.33e-10, max rel 1.77e-7
|
|
(about 2 ULP). The test remains failed; its cause and any general bound are unresolved.
|
|
- MRT root parity test
|
|
`tests/validation/multigrid/test_refinement_mrt_gpu.py::RefinementMRTGPU::test_uniform_matched_mrt_root`
|
|
(12 sub-cases: 2 storage modes x 2 profiles x 3 blocks, default outlet settings) passed bitwise
|
|
in the Horsea focused GPU run at K1 7813334 (2026-10-21).
|
|
- Periodic Taylor-Green Re 100, measured at 36ffc8b1 (V3 matched pair, N128 depth 2):
|
|
every per-sample screen passed; the constant explosion's aggregate worst velocity L2,
|
|
0.004418, exceeds its preregistered 0.002 budget, while projected_linear passed that budget.
|
|
- Curved-wall pressure (pilot harness, exact-q analytic annulus, tau 0.8): the coarse swirl r1
|
|
case exceeded its terminal density-gain cap (1.105e-4 vs 1e-4), so the frozen 9-case matrix
|
|
is NOT_ESTABLISHED. No validated fix exists. This is a pilot harness, not production code.
|
|
- DFG 2D-1 Re 20 (V4, SRT, t* 60, pressure-NEQ outlet and local Zou-He inlet): refined and uniform
|
|
runs were NOT_STEADY under the frozen steady rule, so no interval verdict was given.
|
|
|
|
## Not supported in this release
|
|
|
|
3D, dynamic/automatic AMR (tagging, time-varying hierarchies beyond `remap_child`),
|
|
moving bodies on refined levels, pressure Jets, Jet checkpoints, LES or TRT on refined
|
|
levels, partial (non-dividing) tiles.
|