Fixed periodic 2:1 coupled backend — bounded implementation, 2026-10-13
Decision: A, directional arrival override between coarse pull and collision.
Implemented and locally checked; no Simulation/Jet/general-AMR integration.
Default single-grid source files, existing geometry and all prior evidence are
unchanged. This increment adds 312 production lines and 222 test lines only.
A/B comparison against the active tree
OneStep currently pulls, applies channel BC, computes moments, collides, and
stores. LBMStepper runs Curved before OneStep, immediately swaps after launch,
then runs force/sensor readers. LBMField macros/snapshot read current data;
checkpoint saves BOTH current and spare buffers without a phase guard.
All-FLUID flags do not remove OneStep's y=1/NY-2 wall correction. InitTubeFlow
reconstructs channel flags. Reserved bits in active core/flags.cuh are only
reservations: is_fluid does not exclude AMR and no skip-collision contract
exists in init, body overlays or checkpoint. No old clone behavior was assumed.
A keeps coarse source G immutable and replaces local incoming components.
It needs the existing compact target/children tables (sorted together at
upload), no source backup or full coarse override array. Only boundary-ring
targets binary-search this table; performance optimization is not claimed.
B could map incoming (q,K) to source (q,K-cq) because periodic pull is a
bijection for each q. It is algebraically valid even for the eight corner-pass
links, whose sources are UNCOVERED. But these overwritten source vectors no
longer form consistent postcollision G. A safe B needs sparse backups (100
floats for this patch), source-slot indices, exclusion of all macro, donor,
snapshot, checkpoint and BC readers, same-stream scatter AFTER Curved and
before OneStep, restoration to the captured old allocation before reuse or
publication, and a failed-state policy if asynchronous errors prevent restore.
Swapping pointers does not remove contamination from checkpoint's spare read.
B also still needs true periodic and covered-cell behavior. A is clearer here.
Implementation and ownership
src/CelerisLab/lbm/refinement_stepper.py: PeriodicPatchStepper(cfg, bounds,
context=caller_owned_CudaContext), initialize(coarse_g,fine_g), step(n),
download(), close(). Use its context-manager scope before closing context.
src/CelerisLab/lbm/kernels/refinement.cu: separate compile entry, reusing active
layout, pull, macro/equilibrium and unforced SRT operators. No channel
kernels, physical flags, Curved, body, force or sensor dispatch.
Each level owns two FP32 Q-major (9,ny,nx) arrays and its own module with fixed
dimensions and omega. Both d_params force vectors and n_objects are zero.
Coarse/fine viscosity gives tau .8/1.1 here; configs are copied, modules are
separate, so async parameter mutation is unnecessary. One caller-owned CUDA
context, one backend-owned stream; private compiler directories are removed
after module loading. Allocations and modules are released on close; partial
construction preserves the original exception while attempting cleanup.
Explicit initial G arrays define the periodic state. initialize does NOT
collide, invent channel flags, or run a channel initializer. The test constructs
G0=C(F0) once. Each interval is:
explode original coarse G into ALL fine halo once;
fine pull + ACTIVE collision; inner halo only pulls, outer becomes NaN;
fine pull + ACTIVE collision again; same halo policy;
coarse periodic pull + ALL specified arrival overrides + ACTIVE collision;
synchronize, publish coarse buffer swap and completed step count.
The backend alone updates ghosts. At the second fine output, active cells hold
G while inner ghosts retain F2 for coalescence. Some inner-ghost directions
are legitimately invalid; all actual coalescence reads must be valid. Public
downloads mask every halo cell back to NaN and return synchronized leaf G.
No time-interpolated ghosts or nonequilibrium transfer scaling were added.
Covered coarse cells are skipped and permanently NaN in BOTH buffers.
Every uncovered arrival whose donor was covered is overridden before moments;
the closed map also replaces eight grazing-corner links with uncovered donors.
Explosion parents lie outside the patch. No BC/donor reader accesses covered
values; this backend exposes no old LBMField macro/cache/checkpoint interface.
Public arrays mark non-leaves NaN. There is no claim of complete multilevel
restart, snapshot, object coupling or a ready Simulation adapter.
Methods serialize via a lock. A failed interval can have overwritten fine G:
no transactional rollback is claimed. The instance becomes failed, rejects
download/step/initialize, and must be closed/recreated. Publishing happens only
after stream synchronization. Cleanup tries all allocations even after an
earlier free fails and does not replace a preexisting operation exception.
Reference basis
Pinned CPUREF-0.3, tests/validation/multigrid/cpu_reference.py:
SHA256 bba2a06a9f6517b32079ffff15e4060d8c3b7ed35f16ca134e1877226c9e4e1e.
Its stored phase is arrival_f. Test-only C(F_ref) is compared to production G;
that observation conversion is not an additional production collision.
ref/lbmpy/src/lbmpy/relaxationrates.py:61 confirms acoustic tau scaling.
ref/palabos/src/multiGrid/multiGridGenerator2D.hh:190 uses two fine substeps
and distinct interface processing. Its interpolation/rescaling is a different
method and was not imported into the pinned volumetric algorithm.
Applied local .github/skills/lbm-ref-architecture-guard/SKILL.md: reference
search, actual data-path map and scope were completed before editing.
Independent local agent /root/coupling_review found no numerical-path blocker.
Its cleanup and partial-failure test suggestions were implemented. This does
not replace Claude/Grok/TRON review; Claude's earlier local_stress code review
remains incomplete.
Validation plan fixed before running
No force/objects, double periodic 16x16 coarse, [4,12)^2 patch, 24x24 fine
including halo4, SRT tau .8/1.1. FP32 GPU (existing fast_math/FMA) versus FP64
pinned reference. Rest and seed1 nonequilibrium (u=.03,-.02, relative random
perturbation amplitude 1e-3) each <=8 coarse steps. Populations/corner packets
max absolute tolerance 3e-6, leaf mass/momentum absolute drift AND reference
discrepancy 2e-4. No tolerance was changed after results.
Actual device-write instrumentation checks collision count per leaf, zero
halo/covered collision, explosion per ghost and per-slot coalescence ownership.
The audit entry defines one diagnostic macro in a PRIVATE build and includes
the real refinement.cu; ordinary compile entry is separately smoke-tested.
No old 7x32 matrix, Jet replay, physical stability sweep or large datasets.
Observed results
CPU geometry: 9/9 pass under 256MiB address-space/2MiB file/core0 limits.
CPU cleanup fault-injection: 1/1 pass under the same limits.
GPU audit, rest 8 steps:
max population error 2.11927626e-7
max leaf drift 4.43765894e-5; max leaf reference error 4.62839387e-5
max corner packet error 7.65754117e-9
GPU audit, nonequilibrium seed1 8 steps:
max population error 1.67235548e-7
max leaf drift 2.23806128e-5; max leaf reference error 2.20813948e-5
max corner packet error 1.09677929e-8
At every step: coarse leaf count=step, fine leaf count=2*step, halo/covered
count=0, explosion writes/ghost=step, coalescence writes/slot=step; PASS.
Hop2 finite mask, all coalescence reads and all eight corner packets PASS.
Normal entry: rest 1 step PASS. Eight-step equivalence evidence comes from
the audit build of the same kernel, not an eight-step normal-entry run.
Failure after explosion+two fine hops actually completed: 0 coarse steps
published, download/step rejected, close passed. Separate targeted test;
eight-step cases were not rerun to add this failure test.
Budgets and provenance
Before each GPU run: physical GPU 0/1 idle (0%, 5MiB, no compute processes).
Used only physical GPU0, UUID GPU-e8853ae7-a302-6a17-bcfa-aa767e9ed20c.
Exact Python /home/frank14f/anaconda3/envs/pycuda_3_10/bin/python; runtime asserts
CelerisLab package and kernel root are from /home/frank14f/CelerisLab/src.
PYTHONPATH explicit, no user site/bytecode, BLAS one thread, CUDA cache disabled.
Production arrays 66,464 bytes, audit-only arrays 36,608 bytes: total 103,072
(<128KiB). This excludes CUDA context/module overhead, not measured as arrays.
GPU child watched at 50ms intervals, killed if sampled RSS exceeds 512MiB or
120s. CUDA virtual address space was NOT restricted to 256MiB; driver mapping
needs more. Largest sampled RSS 194,355,200 bytes (~185.35MiB); child getrusage
184.902MiB. Full first run 3.77s; partial-failure check 2.29s. GPU logs total
880 bytes (<2MiB); no data dumps, plots, dependency installs or system changes.
CPU logs summarized from tool executions in cpu_validation.json. Exact GPU
commands, environment, exit status, wall time and RSS are in gpu*.json; actual
stdout/stderr in gpu*.txt. Compiler scratch cleaned on every build.
Audit and next boundary
baseline.json contains the pre-edit tree and 311 preserved old-file hashes
(including the prior evidence hash scope). incremental.patch contains only the
THREE new code/test files; existing dirty changes are not folded into it.
manifest.json records unchanged-baseline verification and artifact hashes.
No commit/staging/push, DynamisLab or old file cleanup/modification occurred.
This validates bounded implementation equivalence, NOT interface accuracy,
stress transfer, long-time stability or 32-step production performance. The
prior ~2.9% excess shear decay remains a research concern. Next joint decisions
are whether/how to expose this narrow periodic backend through Simulation and
when to implement an explicit two-level restart schema; neither is silently
included here. No generic hierarchy or minimal flat-wall Jet work was started.
Authorization, verbatim as relayed by the coordinating thread
<transcript_evidence>
user(Sentinel_ed1ee5edd5e88191a1aaa4d710ce523f): 推进吧,~/CelerisLab就是开发环境,可以改动,只要符合架构风格。遇到问题可以用undermind看文献,也可以让grok搜索互联网信息,还可以参考开源项目。
user(Sentinel_d0d3a42b2c088191aa8aebc105fb1b27): 允许,你用GPU验证都行
</transcript_evidence>