feat(compat): FP16S and ddf_shifting compatibility, EsoPull curved closure

Phase A: FP16S store precision verification
- Kan99b K2 FP16S: quantization sensitivity documented (St 0.170 -> 0.142)
- Sah04 S2 FP16S: PASS (St error 1.53% within 5% gate)
- Sah04 S4 FP16S: diverges at high blockage (known limitation)

Phase B: ddf_shifting code fixes
- Fix inlet west_velocity_rho_closure for shifted DDF (common.cuh)
- Fix curved force/torque accumulation for shifted DDF (curved_boundary.cuh, aux_kernels.cu)
- Fix host upload_ddf() asymmetry (field.py)
- Add checkpoint streaming/ddf_shifting match check (checkpoint.py)
- MRT shifting fix: MRT is NOT shift-invariant; unshift/reshift around collision
- Generalize inlet knowns repair from Zou-He to all west inlet schemes

Phase C: EsoPull curved boundary semantic closure (from round 2)
- streaming/esopull_semantic_helpers.cuh: single truth for physical-value semantics
- step/esopull_macro.cu: MacroscopicEsoPullKernel for correct GPU diagnostics
- SensorKernel, ForceRegionKernel share semantic helpers
- Kan99b K2: bit-identical to double-buffer
- Code-level comments document compatibility boundaries
- README updated with compatibility matrix
- output/round3_compatibility_summary.md: full round documentation

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Frank14f
2026-06-03 10:48:42 +08:00
co-authored by Cursor
parent b110591433
commit d5b7e98750
24 changed files with 1303 additions and 110 deletions
@@ -28,6 +28,8 @@ _DEFAULT_LBM = os.path.join(_REPO, "src", "CelerisLab", "configs", "config_lbm.j
U_INF = 0.03
D_LATTICE = 30.0
R_LATTICE = 15.0
_STORE_PRECISION = "FP32"
_DDF_SHIFTING = False
KAN99B_ANCHOR = {
@@ -138,8 +140,8 @@ def _build_cfg(
cfg["physics"]["rho"] = 1.0
cfg["method"]["collision"] = "MRT"
cfg["method"]["streaming"] = "double_buffer"
cfg["method"]["store_precision"] = "FP32"
cfg["method"]["ddf_shifting"] = False
cfg["method"]["store_precision"] = _STORE_PRECISION
cfg["method"]["ddf_shifting"] = _DDF_SHIFTING
cfg["method"]["les"]["enabled"] = False
cfg["method"]["inlet"]["profile"] = "uniform"
cfg["method"]["inlet"]["scheme"] = str(inlet_scheme)
@@ -499,8 +501,16 @@ def main() -> int:
ap.add_argument("--out-dir", type=str, default=os.path.join(_REPO, "tests", "output", "kan99b_validation"))
ap.add_argument("--smoke", action="store_true", help="Very short run for wiring checks.")
ap.add_argument("--save-vorticity", action="store_true", help="Save final vorticity PNG per run.")
ap.add_argument("--store-precision", type=str, default="FP32", choices=("FP32", "FP16S"),
help="DDF store precision (FP32, FP16S).")
ap.add_argument("--ddf-shifting", action="store_true",
help="Enable DDF shifting mode (f - w storage).")
ap.add_argument("--json-out", type=str, default="", help="Optional explicit summary JSON output path.")
args = ap.parse_args()
# Global for _build_cfg() access
global _STORE_PRECISION, _DDF_SHIFTING
_STORE_PRECISION = str(args.store_precision).upper()
_DDF_SHIFTING = bool(args.ddf_shifting)
if not os.path.isfile(_DEFAULT_LBM):
print(f"Missing base config: {_DEFAULT_LBM}", file=sys.stderr)