CelerisLab/tests/审计.md

131 lines
12 KiB
Markdown
Raw 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.

## 审计结论
当前代码的问题不是单点误差而是沿着主链路分布。最重的问题集中在三处curved Bouzidi 的施加时机不对Bouzidi 分支公式与文献不一致,以及若干运行时接口与内核实现脱节。这几类问题叠加后,足以让同一 case 在 SRT、TRT、MRT 之间出现远大于正常数值差异的结果。
需要单独说明的是,部分未来接口属于有意预留,不应被视为 bug。本审计只把已经进入当前执行契约、但实现与语义不一致的部分列为问题。
按当前项目约束,以下两类设计不再单列为缺陷:
- 运行时接口为后续能力预留,但当前未完全接通,只要注释明确即可
- `obs` 采用跨多步累加,由调用者决定何时清零,这属于有意设计而非实现错误
## 状态说明
- `[已解决]` 已进入当前代码
- `[待重构]` 不是单点修补能彻底解决,适合下一阶段重构
- `[待验证]` 需要最小算例或单元测试确认
- `[保留说明]` 当前不修,但需要在代码或文档中明确限制
## 当前总览
### 已解决
- [已解决] `lbm/__init__.py` 导出错误
- [已解决] forcing 主链路未接通,以及 SRT TRT MRT forcing 预因子不一致
- [已解决] TRT outlet NEQ 重构未补齐
- [已解决] `add_vortex()` 把动量当速度
- [已解决] Sensor 面积归一化缺失,已在 `ObjectManager` 层提供
- [已解决] `sync_to_gpu()` 末尾重置非流体节点的架构错误
- [已解决] curved donor 合法性未检查真实 domain flags
- [已解决] curved Bouzidi 时序错误
- [已解决] `q >= 0.5` 分支读错时间层
- [已解决] moving wall 修正未按 q 分支实现
- [已解决] 初始化链路与 object flag 叠加关系错误
- [已解决] `config_body.json` 未进入实际初始化链路
- [已解决] inlet `U0` 语义已补注释
### 仍需重构或继续处理
- [待重构] `body` 模块整体职责边界仍不清晰几何描述、flag overlay、compact list 生成、动作状态、观测打包仍然耦合过重
- [待重构] curved boundary 当前仍是“圆形简单几何特化 + Bouzidi kernel 特化”架构,不适合继续扩到离散几何与通用移动刚体
- [待重构] 3D 刚体旋转契约仍是 z 轴占位实现
- [待重构] plain linear Bouzidi 与 TRT 不相容问题已注明限制,但没有方法级替代方案
- [待重构] `config.py` 与文档层对预留能力、当前能力、限制条件的边界还不够清楚
- [待验证] MRT 路径仍需最小算例单独核对
- [待验证] Esopull 邻壁处理仍需与 double-buffer 做一致性复核
- [待验证] force 提取与 host 侧系数归一化仍需放到同一处核对
## 历史问题清单
### 主执行链路
| 文件 | 问题 | 影响 |
|---|---|---|
| `lbm/__init__.py` | [已解决] 导入了并不存在的 `add_lamb_oseen``add_taylor_green`。实际 `initializers.py` 只提供 `add_vortex`。 | `CelerisLab.lbm` 包导入会退化到空 `__all__`,对外 API 与代码不一致。 |
| `field.py`、`config.py`、`inlet_outlet.cuh`、`init_flow.cu` | [已解决] `update_runtime_params()` 暴露了 `u_inlet``rho_ref` 一类接口,但入口、出口、初始化全部仍然读编译期宏 `U0``RHO`。如果这些接口继续保留在活跃 API 中,就会形成假功能。 | 运行时接口语义与真实执行路径不一致。 |
| `helpers.cuh``forcing_guo.cuh` | [已解决] `collide_dispatch()` 每步都调用 `zero_forcing(Fin)`,没有任何地方根据 `d_params.fx fy fz` 生成 Guo forcing也没有调用速度半步修正。 | 运行时体力项接口是死路径。任何依赖体力驱动的算例都会静默失效。 |
| `collision_trt.cuh``collision_mrt.cuh` | [已解决] 在 forcing 真的接通之前TRT 与 MRT 版本目前都是直接加 `Fin[i]`SRT 则乘了 `(1-omega/2)`。 | forcing 一旦接通,三种碰撞模型会立刻表现出不一致的体力离散。 |
### Curved boundary 与几何预处理
| 文件 | 问题 | 影响 |
|---|---|---|
| `one_step_double.cu`、`aux_kernels.cu`、`curved_boundary.cuh` | [已解决] Curved Bouzidi 是在 `OneStep` 完成 collision 与 store 之后,通过 `CurvedBoundaryKernel` 二次修补。 | 紧邻曲壁的 fluid 节点在本步 collision 时已经使用了从 solid 方向拉来的错误分布。后修补只能影响下一步,不能修正本步碰撞污染。 |
| `curved_boundary.cuh` | [已解决] `q >= 0.5` 分支使用 `fi_in[k_f, dir_opp]`也就是上一步缓冲区而不是同一步、碰撞后传播前的分布函数。Bouzidi 线性插值两支公式都要求同一时间层的 post-collision 数据 [Bou01]。 | 该分支与文献公式不一致,会直接破坏 curved wall 的局部反射关系。 |
| `curved_boundary.cuh` | [已解决] moving wall 修正统一写成 `+ 6 w_i (c_i · u_w)`,没有区分 `q < 0.5``q >= 0.5` 两支,也没有体现 Bouzidi moving boundary 中的分支依赖系数 [Bou01]。 | 对旋转圆柱或移动物体,壁面速度修正的量级与形式都不对。 |
| `body/objects.py` | [已解决] `Cylinder.get_curved_list()` 的 donor 合法性只检查了“是否越界”和“是否落在圆柱内部”,没有检查 donor 是否落在上壁、下壁、入口、出口等非流体节点。 | `fallback_class` 的主机侧担保并不成立。靠近通道壁或边界时,`q < 0.5` 分支可能继续使用非法 donor |
| `aux_kernels.cu` | [待重构] 3D curved body 的运行时角速度契约只读取一个标量 `omega`并硬编码成 z 轴转动代码里也明确写了 placeholder | 3D 旋转物体路径并未真正完成但接口没有把这种限制暴露出来 |
### 初始化、观测与工具函数
| 文件 | 问题 | 影响 |
|---|---|---|
| `initializers.py` | [已解决] `add_vortex()` `ux_old` `uy_old` 用的是动量和没有除以 `rho_old` | 任何基于该函数构造的初值都会把速度场放大为密度加权动量场 |
| `step/aux_kernels.cu` `body/manager.py` | [已解决] `SensorKernel` 对传感器区域做的是逐格点求和`ObjectManager` 也没有按面积归一化 | 如果外部把传感器输出当成平均速度或平均观测量结果会系统偏大并随探针面积变化 |
| `body/manager.py` | [已解决] `sync_to_gpu()` 最后调用 `_rest_nonfluid()`会把所有非流体节点都重置成静止平衡态而不仅是物体节点 | 只要场中有物体就会额外改写入口出口壁面节点的初始化状态 |
### 文档与配置层
| 文件 | 问题 | 影响 |
|---|---|---|
| `configs/CONFIG` | 文档写 `nx` 必须整除 `threads_per_block`但实际 launch 使用的是 ceiling division | 配置说明与执行实现不一致 |
| `configs/CONFIG` | [已解决] 文档写 `neq_extrap` SRT TRT 都使用全分布 damped NEQ 重构但代码里只有 SRT 走全分布分支TRT 仍是少量未知方向重构 | 算法说明与真实边界实现不一致 |
| `README` `config.py` | 文档把 `FP16C` 当成可选存储精度 `LBMConfig.validate()` 会直接拒绝 `FP16C` | 对外能力声明与当前运行时不一致 |
## 高风险问题
### 边界方法与碰撞模型耦合
| 文件 | 问题 | 影响 |
|---|---|---|
| `curved_boundary.cuh` `collision_trt.cuh` | [保留说明] 当前实现采用 plain linear Bouzidi TRT 直接拼接TRT 的黏性无关参数化只在边界离散满足相应条件时才成立普通线性插值边界并不会自动保留该性质 [Gin08b]。 | 即使把显式 bug 全部修掉TRT SRTMRT 的结果仍可能因边界离散而系统分叉 |
| `curved_boundary.cuh` | 当前 curved wall 没有任何质量守恒修正对于高 Re长时间周期性 curved flow文献已经报告 plain Bouzidi 会出现质量泄漏与力漂移 [San18]。 | 长时间拖算时平均密度阻力与升力可能持续漂移 |
| `collision_mrt.cuh` | D2Q9 MRT 为配合新方向排序手工重写了整套 moment transform inverse transform但代码里没有任何一致性校验或自测痕迹 | 一旦某个符号系数或方向映射有误结果会直接体现在升阻力与稳定性上而且不容易从表面现象定位 |
| `inlet_outlet.cuh` `config.py` | 抛物入口把 `U0` 解释成截面平均速度峰值自动变成 `1.5 * U0`接口名字仍然叫 `velocity`没有区分平均速度与最大速度 | 只要用户按最大入口速度设参数实际 Re 就会整体偏移 |
| `init_flow.cu` | 四个角点优先按 inlet outlet 分类而不是 wall随后边界核又把非 `interior_y` 的角点落回 `bounce_back_swap()` | 角点的标记语义与实际处理语义不一致容易在后续扩展中埋下隐患 |
## 待验证问题
### 需要单元测试或最小算例复核的项
| 文件 | 问题 | 影响 |
|---|---|---|
| `one_step_esopull.cu` | Esopull 路径没有像 double-buffer 那样对 `y == 1` `y == NY-2` 的流体邻壁行做显式半格 bounce-back 修正 | bounded channel esopull double-buffer 之间可能存在额外差异需要最小通道算例核对 |
| `collision_mrt.cuh` | [待验证] D2Q9 MRT 的新配对顺序moment basisinverse transform 是否与 `compute_rho_u()`、`compute_feq()` 完全一致目前只能靠数值表现间接推断 | 这条路径可能包含隐藏的符号错位需要用均匀流Poiseuille衰减涡等简单算例单独验算 |
| `inlet_outlet.cuh` | SRT 出口在 `neq_extrap` 下重构了全体分布不仅是未知方向 | 该设计是否有利于稳定性是否额外改变质量守恒需要独立做 outlet 对比测试 |
| `curved_boundary.cuh` `aux_kernels.cu` | [待验证] 当前力提取采用 `f_toward + f_reflected` 的链路级动量交换但没有与 host 侧的阻力系数归一化和符号约定放在同一处核对 | 即使流场正确力的符号量级和平均方式也仍可能在后处理阶段出错 |
## 本轮已修复
- `lbm/__init__.py` 已改为导出真实存在的 `add_vortex`
- 运行时参数接口已收紧到当前真实生效的 `omega` forcing 相关项
- Guo forcing 已接入主碰撞分发链路SRTTRTMRT forcing 预因子已统一
- TRT outlet NEQ 重构已补齐为与 SRT 一致的全分布 damped NEQ 路径
- `add_vortex()` 已修正为用速度而不是动量直接叠加初值
- 传感器读数已在 `ObjectManager` 层提供面积归一化接口
- 物体同步后的静止平衡重置已收缩为只作用于 obstacle interior而不再覆盖所有非流体节点
- curved link donor 合法性检查已扩展到实际 domain flags而不只检查是否在圆柱内部
- curved Bouzidi 已从步后修补流体节点改为步前写入 obstacle source slot”,并改掉了 `q >= 0.5` 分支对前一时间层 opposite population 的读取
- curved moving-wall 修正已继续收紧为独立 helper并把 `q < 0.5` fallback 分支改回与 [Bou01] 一致的符号约定
- 初始化链路已改为先构建 clean channel flags再叠加 object mask再由 init kernel 保持 obstacle flag 并写入静止平衡态”,移除了 `sync_to_gpu()` 末尾对 obstacle interior 的二次主机侧重置
- `Simulation` 已开始消费 `config_body.json` 中的简单物体定义并在编译期同步 `N_OBJS` 契约
- inlet 抛物入口已补充注释明确 `U0` 在当前实现中表示截面平均速度峰值为 `1.5 * U0`
- curved boundary 文件已显式注释plain linear Bouzidi TRT 不具备 TRT-parametrized curved-wall 保证当前实现保留该限制说明
## 交叉症状解释
当前现象和代码结构是吻合的TRT Bouzidi 直接发散最符合 curved wall 时序错误与 `q >= 0.5` 分支读错时间层这两个问题叠加后的表现SRT MRT Bouzidi 不发散但升阻力偏离则更像是主链路虽然还能跑但边界修正观测累加入口参数语义和 MRT 未校验实现共同把结果拖离了正常范围
文献层面的两条提醒也和代码现状一致第一plain linear boundary TRT 的参数化并不天然相容 [Gin08b]。第二plain Bouzidi 在高 Re 周期 curved flow 中会出现质量泄漏与力漂移 [San18]。这两条不是当前代码里最先要解释的大偏差但它们说明就算显式 bug 修完边界策略本身仍然需要额外核验