Files

10 KiB
Raw Permalink Blame History

Numerical repairs — 2026-10-10

Owner /root/numerical. User-authorized repairs, not jet/AMR implementation. Scope: numerical CUDA operator/boundary/step headers, lbm/stepper.py, permanent actual-operator regressions. No generated repository config headers, PTX, simulation.py, environment or GPU state modified by this agent. Historical audit scripts/results are retained as evidence, not rewritten to conceal their original failures.

Reference and design review before edits

Read repository architecture guard. Applicable physics/acceptance: advertised D2Q9/D3Q19 SRT/TRT/MRT local mass/momentum/equilibrium invariants, low-Mach nonuniform closed-channel FP32 reference, same-time storage conversion, moving impermeable wall; no production-Re extrapolation. Code path mapped from LBMStepper.step to collision dispatch, force-region postpass, EsoPull sync, curved-wall prepass and in-place step. Historical b110591 explicitly introduced force_region as an operator-split correction; 6e3756c introduced initialization-compatible EsoPull semantics. Those intentional choices are retained.

Reference set (local checked-in sources):

  1. ref/lbmpy/src/lbmpy/forcemodels.py, Guo lines 273–300: source correction is M^-1 (I-S/2) M Fin, with half-force equilibrium velocity. A single SRT scalar is not the general MRT/TRT correction.
  2. Same file, EDM lines 493–510: equilibrium difference at u+F/rho minus equilibrium at u. For the repository's quadratic equilibrium, raw Guo source at midpoint u+F/(2rho) is exactly this difference. It preserves the existing post-step force-density interface without claiming equivalence to collision-integrated global Guo at all orders.
  3. ref/lbmpy/src/lbmpy/boundaries/boundaryconditions.py, UBB lines 909–935: fluid-to-wall outgoing direction maps to opposite reflected population with negative wall-velocity correction; compressible convention multiplies by density. Also inspected NoSlipLinearBouzidi for interpolation branch context.
  4. ref/FluidX3D/src/kernel.cpp, load/store around 1333–1343 and streaming section: paired EsoPull layout is a parity-dependent mapping. Same-time conversion must invert the read addresses; advancing store is a different operation. Actual CelerisLab initialization and caller time-count evidence determine which stage is used here.
  5. ref/LBM_boundary_methods_for_stable_high_Re.md and current source descriptors informed scope: existing west inlet is a ghost-source scheme; only its algebraic shifted-weight restoration is repaired. No general stability claim or boundary-method replacement.

Dispositions

Finding Status Repair and preserved design
NUM01 global TRT/MRT force confirmed / fixed TRT source split into even/odd rates. MRT adds half source before linear relaxation and half after, exactly implementing the model-specific relaxation matrix. Existing half-force velocity and model rates remain. D2 entire vector checked against independent moment-matrix oracle.
NUM02 force-region underforcing confirmed / fixed Keep sparse post-step split impulse and public fx/fy force-density semantics. Remove spurious collision scalar. Midpoint source equals exact equilibrium difference, including second moments. Actual ForceRegionKernel regression checks full vector with non-unit rho, nonzero velocity, opposite signed forces and both layouts/parities. Overlapping actual fluid footprints are rejected by state owner's compact-list validation to avoid duplicate writers.
NUM03 full D3 entrypoint compile confirmed / runtime capability rejected; implementation deferred Architecture/root add validate_runtime() rejection for D3 Simulation. Legal schema and local D3 operator tests remain possible. Isolated complete D3 entrypoint still fails 18 dimension-mismatch errors in aux/sync. This round does not claim D3 solver support or complete dimension-qualified boundaries.
NUM03b shifted D3 MRT confirmed / local operator fixed D3 projection uses g-feq in the same representation. Removed inconsistent physical-unshift/shift around compile-time shifted equilibrium. Equilibrium/force local regression covers shift on/off.
NUM04 same-t EsoPull write confirmed / fixed Store uses exactly esopull_src_cell and esopull_slot, inverse to read at identical count, never the advancing store mapping. Nonuniform exact-address inverse at t=0,1,2,3.
NUM05 sync collision/shift confirmed / fixed Encode only subtracts weights when needed and encodes at same count. No unsolicited collision of patch/halo. Actual decode/encode preserves arbitrary nonequilibrium populations within FP32 conversion roundoff.
NUM06 moving wall confirmed / fixed Fluid→solid direction gets negative moving-wall reflection correction. Both paths use local physical density consistent with compressible equilibrium; EsoPull obtains density from pre-streaming donors. q<1/2, q≥1/2 and fallback retained. No omega API sign change.
NUM07 EsoPull y-wall stage/race confirmed / fixed New read-only PrepareEsoPullWalls snapshots 3 donors × 2 rows before any curved/source/in-place mutation. Main step reads compact scratch. t=0 uses initialization-aware helper; later t uses previous spatial postcollision values. Pure double-buffer helpers no longer use timestep as a storage-mode sentinel.
Shifted inlet density closure confirmed / fixed Both descriptor-weight sums equal 1; replace 5/6 and 19/18. Preserve existing west ghost-source boundary schemes, timing and damping.
LES model-family differences design retained No unsupported claim that closed-form and iterative LES are interchangeable, no change to LES definition.

Phase and interface details

load_physical_node_esopull(k,t) reconstructs the next pull state at the completed count. Its spatial meaning is not the same-cell postcollision state reconstructed by load_physical_dir_pre_streaming. Decode/encode and snapshot restore retain the existing next-pull interpretation. No clock advancement is hidden in encoding.

EsoPullStep now takes const float* wall_values immediately before t. LBMStepper allocates 2*nx*3*sizeof(float) scratch and launches the prepass on the same stream before _launch_curved. This costs one small boundary launch and 24*nx bytes; no performance-neutrality claim is made. Separating preparation from writes removes the added wall cross-thread read/write hazard; it is not a blanket race proof for all existing inlet/outlet schemes.

Force-region updates remain split and distinct from global collision-integrated Guo. Target momentum per cell per step is F. Macroscopic interpretation with time-dependent forces must respect each scheme's stage; no new global half-force convention or external control semantics is introduced. D2 Guo collision full-vector oracle checks more than momentum rescaling.

Verification

Permanent tests: tests/unit/test_numerical_operators.py and two tests/unit/cpp/*_regression.cpp fixtures. All C++ uses actual repository headers/kernels with CPU CUDA-qualifier shims; no copied production arithmetic replaces the invoked operators. Python contains independent D2 matrix/TRT references. Optional nvcc tests copy the kernel tree and edit only temporary headers, then emit temporary PTX.

Command:

PYTHONPATH=/home/frank14f/CelerisLab/src /home/frank14f/anaconda3/envs/pycuda_3_10/bin/python -m pytest tests/unit/test_numerical_operators.py -q

Coverage:

  • 12 local dispatch cases: both dimensions × shift on/off × SRT/TRT/MRT, each at omega .7/1.25/1.8, non-unit density, nonzero velocity and nonequilibrium. Mass/momentum increments, D2 full-vector relaxation, equilibrium invariance and inlet closure.
  • 12 semantic cases: D2 models × shift × no-slip/free-slip. Same-time nonuniform encoding, actual no-edit sync, actual wall prepass at initialization and both later parities, moving-wall all directions/branches with rho1.17, actual force-region kernel, and four actual closed-channel steps compared at identical postcollision spatial phase between double-buffer and EsoPull. x periodic, no inlet/outlet donors; this is a deterministic CPU schedule check, not GPU concurrency validation.
  • 12 isolated D2 entrypoint compile cases: collision × shift × FP32/FP16S, covering both entrypoints and both wall branches. FP16S is compile coverage only in this agent's work.

Initial 28-test run passed (before expanding semantic cases to all collision models); final expanded result is recorded below. FP32 summation tolerance permits four unit-density epsilons (5e-7) for D3 19-term accumulation; this is separated from per-population vector tolerances. Original bugs exceed tolerances by orders of magnitude.

GPU execution is owned by root, to prevent source/cache/device competition. Add root's observed GPU outcomes separately; no GPU or long-flow claims are inferred from these local tests. High-Re stability, curved-body force/torque convergence, inlet/outlet in-place race audit, LES combinations, complete D3 and performance remain beyond the demonstrated surface.

Cross-review and GPU handoff

State owner independently accepted same-count inverse addresses, encode-without-collision, and staging before curved/in-place writes on the same stream. I reviewed field.py snapshot/restore and common/checkpoint.py and reran tests/unit/test_state_regressions.py: 21 passed. Field-only snapshots decode at save count and encode at current count without resetting time. The t=0 initialization special pre-streaming mapping means restoring an initial field at later time promises restored next-pull field, not reproduction of the original initialization step. Full checkpoint restores raw storage plus original count and is the restart mechanism.

Expanded semantic CPU run: 12 passed, covering all SRT/TRT/MRT, shifted/unshifted, no-slip/free-slip combinations. Together with 12 local-operator cases and 12 isolated compilation cases, all 36 permanent numerical cases have been exercised successfully across the recorded focused runs.

Added tests/integration/test_numerical_gpu.py for root's coordinated execution: 18 bounded FP32 cases (4 nonuniform closed-channel layout comparisons over four steps, 4 actual t=0 initialization/staged-wall cases, 6 global-force momentum cases, 4 force-region total impulse cases). Syntax checked; this agent has not run GPU. The layout comparison constructs identical spatial postcollision input at completed count 1, rather than incorrectly comparing DB postcollision diagnostics with EsoPull next-pull diagnostics. Actual t=0 initialization is checked separately. No FP16 runtime or quantization tolerance is silently substituted.