131 lines
12 KiB
Markdown
131 lines
12 KiB
Markdown
## 审计结论
|
||
|
||
当前代码的问题不是单点误差,而是沿着主链路分布。最重的问题集中在三处: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 与 SRT、MRT 的结果仍可能因边界离散而系统分叉。 |
|
||
| `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 basis、inverse 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 已接入主碰撞分发链路,SRT、TRT、MRT 的 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 修完,边界策略本身仍然需要额外核验。
|