CelerisLab/tests/audit/兼容性测试.md
Frank14f d5b7e98750 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>
2026-06-03 10:48:42 +08:00

459 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# FP16 与 ddf_shifting 兼容性指导
## 目标
这份文档用于指导下一阶段的兼容性工作,范围限定为:
- `store_precision = FP16S`
- `ddf_shifting = true`
- 与以下能力的兼容性
- `double_buffer`
- `esopull`
- curved boundary
- 新 body 模块
- `Kan99b_validation`
- `Sah04_validation`
这里的核心目标不是“多跑一些测试”,而是先把 **真正有代码级风险的点** 查清楚,再为这些点设计最少但有力的验证。
---
## 总体判断
## 1. FP16S 和 ddf_shifting 不是同一类问题
这两个开关虽然都作用在 DDF 存储层,但风险性质不同。
| 项目 | 风险类型 | 当前判断 |
|---|---|---|
| `FP16S` | 精度风险 | 低到中等,可直接进入 benchmark 验证 |
| `ddf_shifting` | 语义风险 | 中到高,先修高风险代码,再做 benchmark |
更直接地说:
- **FP16S 主要是“误差会不会把结果推偏”的问题**
- **`ddf_shifting` 主要是“现有公式是否仍然在算同一个物理量”的问题**
因此两者不应混在一起推进。
---
## 第一部分FP16S
## 当前代码结构判断
FP16S 当前结构的优点很明确:
- 所有 DDF 存取都集中在 `load_ddf()` / `store_ddf()`
- 所有数值计算都在 `float` 下完成
- EsoPull helper、macro kernel、sensor、force region、collision 都读入 `float` 后再算
- body 模块的 cut-link、action、obs、geometry 都仍然是 `float32`
这意味着 FP16S 的主要影响路径是:
- DDF 被量化到 half + scale
- 再由 `load_ddf()` 恢复到 `float`
- 后续计算不再额外降精度
因此 FP16S 的主要风险不是语义错,而是:
- 量化误差是否在长期统计量中积累
- curved 邻域和力学统计是否对量化更敏感
## 当前最合理的策略
FP16S 不需要先大规模改代码。当前更合理的是:
- 直接进入最小 benchmark 验证
- 用少量高价值算例判断是否达到可用精度
## FP16S 最小验证集
建议只做三项:
| 编号 | 用例 | 作用 |
|---|---|---|
| F1 | `Kan99b K2` | rotating cylinder 主锚点,覆盖 curved + body force/torque |
| F2 | `Sah04 S2` | 中等 blockage覆盖 channel + inlet/outlet + curved |
| F3 | `Sah04 S4` | 高 blockage 敏感 case放大 wall / curved / 精度误差 |
如果计算预算紧,可以先跑:
1. `K2`
2. `S2`
3. `S4`
这三项站住FP16S 基本就可视为进入正式可用状态。
## FP16S 主要观测量
### Kan99b K2
- `St`
- `mean Cd`
- `mean Cl`
- `C'_L`
- `C'_D`
- torque 趋势
- 最终涡量图
### Sah04 S2 / S4
- `St`
- `Re_real`
- 周期性
- 最终涡量图
- 宏观场是否有明显假结构
## FP16S 评估方式
不建议用“逐点场几乎完全相同”作为判据。更合理的是:
- benchmark 统计量是否稳定
- 流动结构是否保持
- 是否出现明显非物理噪声放大
## FP16S 通过标准建议
沿用现有 benchmark 文档标准即可,不需要另立一套更紧的标准。
若出现轻微偏差,优先看:
- 偏差是否主要体现在力振幅而不是频率
- 是否只在高 blockage 或强近壁 case 放大
- 是否存在长期漂移而不是瞬时差异
## FP16S 失败时优先排查
| 现象 | 优先怀疑 |
|---|---|
| `St` 稳定但振幅偏差大 | curved 邻域对量化敏感 |
| `rho` 漂移明显 | 精度不足导致守恒误差积累 |
| 高 blockage case 失真、低 blockage 正常 | wall-gap 分辨率与量化共同放大误差 |
| 只有 EsoPull 差、double 正常 | single-buffer 路径对量化更敏感 |
---
## 第二部分ddf_shifting
## 当前代码结构判断
`ddf_shifting` 不是“已跑通但没验证”的状态,而是“已有若干明确高风险点”的状态。
从当前代码看,至少有四类问题必须先处理。
---
## 风险点 S1inlet rho closure 不兼容 shifting
### 位置
- `boundary/inlet/common.cuh`
- `west_velocity_rho_closure_d2q9`
- `west_velocity_rho_closure_d3q19`
### 问题本质
这些 closure 直接对 `f[]` 求和并做速度闭合。
但在 shifting 模式下,存储变量是:
\[
\tilde f_i = f_i - w_i
\]
因此原来对 `f_i` 成立的 closure不能直接对 `\tilde f_i` 使用。
### 影响范围
所有依赖 west closure 的 inlet 都会受影响:
- `zou_he_local`
- `channel_stabilized`
- `regularized`
### 结论
这不是 benchmark 才能发现的小问题,而是**公式语义已变**。必须先修。
---
## 风险点 S2curved force/torque 统计不兼容 shifting
### 位置
- `curved_boundary.cuh`
- `PrepareEsoPullCurvedKernel` 中的 obs 累积
- `CurvedBoundaryKernel` 中的 obs 累积
### 问题本质
当前动量交换统计直接使用:
- `f_toward + f_reflected`
如果这两个量是 shifted population那么它们包含了权重偏移项不能再直接当成原始物理分布和来做 force 统计。
### 影响范围
这会直接污染:
- force
- torque
- `Cd`
- `Cl`
- 任何依赖 body obs 的 benchmark 输出
### 结论
只要 `ddf_shifting` 打开,当前 curved force/torque 统计不能默认可信。
---
## 风险点 S3host upload/download 路径不对称
### 位置
- `field.download_ddf()`
- `field.upload_ddf()`
### 当前状态
- `download_ddf()` 在 shifting 模式下会加回 `w_i`
- `upload_ddf()` 不会在上传前减去 `w_i`
### 影响范围
所有 host 侧修改 DDF 再上传的路径都可能错:
- `initializers.add_vortex()`
- `snapshot()/restore()`
- 任何直接操作 `field.ddf` 的调试脚本
### 结论
当前 host DDF 修改路径与 shifting 语义不对称,必须:
- 要么修正
- 要么显式禁止使用
---
## 风险点 S4checkpoint 对 streaming 不做匹配检查
### 位置
- `common/checkpoint.py`
### 当前状态
当前 checkpoint load 检查:
- lattice
- grid
- store precision
但不检查:
- `streaming`
- `ddf_shifting`
### 影响范围
可能出现:
- double-buffer checkpoint 被加载到 esopull
- unshifted checkpoint 被加载到 shifted 配置
- 反过来亦然
### 结论
只要 storage semantics 不同checkpoint 就不应默认兼容。
---
## ddf_shifting 的正确推进顺序
## Step S-A先修代码级高风险点
在任何 benchmark 之前,建议优先处理以下事项:
1. **修 inlet closure**
-`west_velocity_rho_closure_*` 对 shifting 成立
2. **修 curved force/torque 统计**
- 统计时使用物理 population而不是 shifted storage 量
3. **处理 host upload/download 对称性**
-`upload_ddf()`
- 或对 shifting 下 host-DDF-edit 路径显式加 guard
4. **补 checkpoint 配置检查**
- 至少检查 `streaming`
- 最好同时检查 `ddf_shifting`
### 为什么必须先修
因为这些不是“跑几个 benchmark 看看”的问题,而是:
- 不修的话benchmark 结果没有明确物理解释
- 即使数值接近,也可能只是错误抵消
---
## Step S-B再做最小 sanity 验证
在代码修完之后,先不要直接上长跑 benchmark先做最小 sanity
| 编号 | 用例 | 目标 |
|---|---|---|
| S5 | channel init sanity | 确认 shifting 下宏观场与初始条件一致 |
| S6 | inlet closure local check | 确认 west closure 不再系统偏移 |
| S7 | curved force local check | 确认 force/torque 不因 shift 常数偏置 |
这部分不需要设计得很复杂,重点是回答:
- inlet 闭合是否恢复物理意义
- curved force 是否恢复物理意义
---
## Step S-C再做 benchmark
修完并过了 sanity 之后,再做最小 benchmark
| 编号 | 用例 | 作用 |
|---|---|---|
| S8 | `Kan99b K2` | 主锚点,最关键 |
| S9 | `Sah04 S2` | 中等 blockage channel 验证 |
| S10 | `Sah04 S4` | 高 blockage 敏感验证 |
这套最小集与 FP16S 相同,便于复用现有脚本和比较口径。
---
## 第三部分:新 body 模块应该怎么理解
## 不要把“body 兼容性”当成一个单独的大问题
新 body 模块本身并不是当前主要风险源。因为它主要负责:
- geometry
- flag overlay
- compact list packing
- action/obs buffer 管理
这些层本身不直接定义 DDF 物理语义。
真正要关注的是body 模块接入后,哪些 kernel 会读或写 DDF
- `PrepareEsoPullCurvedKernel`
- `CurvedBoundaryKernel`
- `SensorKernel`
- `ForceRegionKernel`
- `MacroscopicEsoPullKernel`
### 其中需要区分风险等级
| 路径 | FP16 风险 | shifting 风险 |
|---|---|---|
| `MacroscopicEsoPullKernel` | 低 | 低到中等 |
| `SensorKernel` | 低 | 低到中等 |
| `ForceRegionKernel` | 低到中等 | 中等 |
| curved force/torque obs | 中等 | **高** |
| inlet / outlet related source states | 中等 | **高** |
### 结论
新 body 模块不需要另起一套大而全的验证设计。更有效的做法是:
- 在 FP16S / shifting 验证时,自动把 body 的核心使用路径覆盖掉
- 重点盯住 force、torque、sensor、curved、macro 这些 DDF 消费点
---
## 第四部分:推荐推进顺序
## 当前最推荐顺序
1. **先更新文档和注释**
2. **先做 FP16S 最小 benchmark 验证**
3. **再修 ddf_shifting 高风险代码**
4. **修完后做 shifting sanity**
5. **最后做 shifting benchmark**
不要反过来。
### 原因
- FP16S 现在已经具备直接验证条件
- shifting 现在还不具备可信 benchmark 条件
---
## 第五部分:每一步如何评估
## FP16S 评估口径
| 类型 | 关注点 | 判读方式 |
|---|---|---|
| K2 | `St`, `Cd`, `Cl`, amplitude | 是否保持 benchmark 可用精度 |
| S2 | `St`, `Re_real` | 中等 channel case 是否稳定 |
| S4 | `St`, vorticity | 高敏感 case 是否放大量化误差 |
## shifting 评估口径
| 类型 | 关注点 | 判读方式 |
|---|---|---|
| sanity | inlet / force / init 是否语义正确 | 是否恢复清楚的物理解释 |
| K2 | 力学统计量 | 是否与 unshifted 路径一致且可解释 |
| S2/S4 | channel / blockage 行为 | 是否出现边界条件系统偏差 |
---
## 第六部分:执行摘要
## 对 coder 的直接指导
### 先做什么
先做:
- 文档和注释更新
- FP16S 的 `K2 + S2 + S4`
### 暂时不要直接做什么
暂时不要直接把 `ddf_shifting` 扔进长跑 benchmark然后凭结果判断“看起来能不能用”。
### ddf_shifting 先修什么
先修四个点:
1. inlet rho closure
2. curved force/torque 统计
3. host upload/download 对称性或 guard
4. checkpoint semantic match check
### 修完再怎么测
先做 sanity
- init
- inlet
- curved force
再做:
- `K2`
- `S2`
- `S4`
---
## 最终一句话结论
**FP16S 现在主要是精度验证问题;`ddf_shifting` 现在首先是代码语义一致性问题。**
因此:
- **FP16S 可以直接用少量 benchmark 判可用性**
- **`ddf_shifting` 必须先修明确高风险代码,再做 benchmark 才有意义**