CelerisLab/tests/audit/审计.md

210 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.

## 审计结论(第二轮)
本轮审计的视角与上一轮不同。上一轮聚焦"主链路上是否有显式 bug"(找到了 16 项)。本轮审计的四个维度:
| 维度 | 上一轮 | 本轮 |
|---|---|---|
| 主链路正确性 | 找显式 bug | 确认修补正确、无回归 |
| 代码架构质量 | 少量提及 | 系统评估 Python 层职责分离 |
| 新代码 | 不存在 | streakline.py 全篇 + test runners |
| 跨层一致性 | 仅一处 | 系统性检查 config → compiler → kernel → docs 同步 |
核心结论:**上次 16 项修补经逐条审查确认正确,无回归。**
### 第二轮修改完成状态
根据审计发现,已完成以下修改:
| 修改项 | 状态 |
|---|---|
| EsoPull 添加 y=1/NY-2 半格 bounce-back 修正D2Q9 + D3Q19 | ✅ 已实施 |
| `macro.cuh` diagnostic 函数标注 | ✅ 已标注 `// --- Diagnostic only ---` |
| `config.py` `omega_max` 默认值 1.99 → 1.96 | ✅ 已修改 |
| `BC_MOVING`/`BC_PERIODIC` 代码注释说明 | ✅ 已添加 TODO 注释 |
| Streakline 模块重构779 行单文件 → `common/streakline/` 子包 (5 文件) | ✅ 已完成 |
| `run_kan99b_streakline.py` 更新为新 API | ✅ 已完成 |
| `run_exp_ctrl_matrix_streakline.py` 更新为新 API | ✅ 已完成 |
| `render_vorticity_field` 移到 `common/render.py` | ✅ 已完成 |
| `ParticleTrailSet` 移到 `common/pathline.py` | ✅ 已完成 |
| 向后兼容 shim `common/streakline.py` | ✅ 已创建(带 DeprecationWarning |
---
## 状态说明
- `[已确认]` 经代码审查确认正确
- `[无法确认: 需运行验证]` 需数值算例确认,不能单靠读代码定论
- `[新发现]` 本轮审计首次发现
- `[已修复]` 已实施修改
- `[保留说明]` 当前不修,但需在代码或文档中明确限制
---
## 第一轮审计修补确认
逐一确认 16 项"已解决"修补在代码中的真实状态。**全部 [已确认],无回归。**
| 问题 | 结论 | 关键文件:行号 |
|---|---|---|
| `lbm/__init__.py` 导出错误 | 已确认 | 当前导出真实存在的 `add_vortex` |
| forcing 主链路 + 预因子不一致 | 已确认 — 三模型统一使用 `c_tau = 1-omega/2` | `operators/collision_srt.cuh:15`, `collision_trt.cuh:35`, `collision_mrt.cuh:41/116` |
| TRT outlet NEQ 重构未补齐 | 已确认 — COMPILE_MODEL==0\|1 时全分布 damped NEQ | `boundary/outlet/pressure_neq.cuh:45-51` (D2Q9) |
| `add_vortex()` 动量当速度 | 已确认 — `ux = sum(f*cx) / rho_safe` | `lbm/initializers.py:57-58` |
| Sensor 面积归一化 | 已确认 — ObjectManager 层已提供 | `body/manager.py` |
| `sync_to_gpu()` 重置非流体 | 已确认 — 已收缩为只覆盖 obstacle interior | `body/manager.py` |
| curved donor 合法性 | 已确认 — 扩展到实际 domain flags | `body/objects.py` `_donor_is_fluid` |
| curved Bouzidi 时序 | 已确认 — 步前写入 obstacle source slot | `lbm/stepper.py:70-71``step/aux_kernels.cu:14` |
| `q >= 0.5` 分支读错时间层 | 已确认 — 读 `load_ddf(fi, ...)` 即同一步 post-collision | `boundary/curved_boundary.cuh:73-75` |
| moving wall 修正未按 q 分支 | 已确认 — 分三路fallback / q<0.5 / q>=0.5 | `boundary/curved_boundary.cuh:30-43` |
| 初始化链路 flag 叠加顺序 | 已确认 — obstacle overlay → init kernel preserve → equilibrium | `step/init_flow.cu:48-52`, `lbm/stepper.py:43-54` |
| `config_body.json` 未进入初始化 | 已确认 — Simulation 已消费 | `simulation.py` |
| inlet `U0` 语义 | 已确认 — 已补充截面平均速度注释 | `configs/CONFIG.md`, `README` |
---
## 本轮发现与处理
### CUDA Kernel 层
| 严重度 | 问题 | 文件:行号 | 处理 |
|---|---|---|---|
| **[新发现]** [高] | **`BC_MOVING``BC_PERIODIC` 标记未在 step kernel 中分发。** `core/flags.cuh` 定义了两种标记,但 step kernel 中没有 `is_moving()``is_periodic()` 分支。设了这两种标记的 cell 会静默 fall through 到 `bounce_back_swap()`。 | `step/one_step_double.cu`, `step/one_step_esopull.cu` | **[保留说明]** 已添加 TODO 注释,暂不实现 |
| **[新发现]** [高] | **EsoPull 缺少 y=1/NY-2 的显式半格 bounce-back 修正。** Double-buffer 路径有该修正而 EsoPull 无。 | `step/one_step_esopull.cu` | **[已修复]** 已添加 D2Q9 和 D3Q19 分支,标注了未来可能需要更精确方案 |
| **[新发现]** [中] | **`USE_DDF_SHIFTING` 路径完整性存疑。** 审查后确认:`macro.cuh` 和 `init_flow.cu` 已处理 shifted各 collision/curved operator 通过 `load_ddf`/`store_ddf` 抽象层自动适配。**实际已完整,无需修改。** | — | **[已确认无需处理]** |
| **[新发现]** [低] | **`compute_pressure``compute_pressure_perturbation` 未标注诊断用途。** | `operators/macro.cuh:160-166` | **[已修复]** 已标注 `// --- Diagnostic only ---` |
| **[新发现]** [低] | **Curved/Sensor kernel 无运行时下标越界保护。** 完全依赖 host 侧验证。 | `step/aux_kernels.cu:26-99` | **[保留说明]** 设计选择:不引入多余合法性检查 |
### 第一轮遗留待验证项复查
| 待验证项 | 状态 | 说明 |
|---|---|---|
| **MRT D2Q9 moment transform/inverse** | **[无法确认: 需运行验证]** | 方向索引与 paired ordering 自洽moment 投影物理正确。但全部系数的数值精度需在 Poiseuille 或衰减涡算例中验证。 |
| **EsoPull 邻壁 vs double-buffer 一致性** | **[已修复]** | 已添加 y=1/NY-2 反弹修正。需运行验证确认。 |
| **Force 提取与 host 侧归一化** | **[无需处理]** | Cd/Cl 管道经确认语义一致。 |
| **Plain linear Bouzidi / TRT 不兼容** | **[保留说明]** | 注释已存在且准确,引用了 [Gin08b]。无方法级替代方案。 |
---
## 架构与设计审计
### Streakline 模块重构
**旧 `common/streakline.py` (779 行) 已被拆解为 `common/streakline/` 子包:**
```
src/CelerisLab/common/
streakline/ 后处理子包
__init__.py 导出 Streakline, ReleaseConfig, IntegratorConfig
_config.py 配置 dataclass + FlowFrame 内部类
_integrate.py 核心积分引擎 (RK4 + 时空插值)
_render.py 密度图渲染 (render_density)
_streakline.py Streakline 类 (被动消费者)
render.py 涡度计算与渲染 (从旧 streakline 移出)
pathline.py ParticleTrailSet + render_trails (从旧 streakline 移出)
preprocess.py 增加 cylinders_from_triangle_layout
```
**核心设计变更:**
| 旧设计 | 新设计 |
|---|---|
| `run_streakline_online(sim, ...)` 控制仿真循环 | `Streakline.observe(ux, uy, step)` 被动接收帧 |
| `run_streakline_offline(frames, ...)` 批处理帧列表 | 移除(无需求) |
| `render_streakline_density(positions, ages, ...)` 15 参数 | `Streakline.render(path)` 内部维护状态 |
| `ParticleTrailSet` 与正确实现混在同一文件 | 移到独立 `pathline.py` |
| `render_vorticity_field` 与粒子跟踪无关 | 移到独立 `render.py` |
| `gaussian_blur2d``np.apply_along_axis` | 改为显式 `for` 循环 + `np.convolve` |
| `minimal_axes=True/False` 分支重复 | 合并为单路径 `_save_minimal_image` |
**用法示例:**
```python
streak = Streakline(release_points=..., nx=nx, ny=ny, cylinders=...)
# 在自己的仿真循环中:
macro = sim.get_macroscopic()
streak.observe(ux=macro["ux"], uy=macro["uy"], step=step)
# ...同时可以做 body actions、checkpoint、其他模块...
streak.render("output.png")
```
### Body 模块
| 严重度 | 问题 | 行号 | 处理 |
|---|---|---|---|
| **[架构]** | **`ObjectManager` 承担 8 种以上职责。** `sync_to_gpu()` 单枪匹马编排了全部流程。 | `body/manager.py` (423 行) | **[暂不处理]** |
| **[架构]** | **`Cylinder.get_curved_list()` ~180 行包含 7 种职责。** 内嵌函数无法单独测试。 | `body/objects.py:110-291` | **[暂不处理]** |
| **[架构]** | **自上一轮审计以来 body 模块重构进展为零。** | 全部 | **[暂不处理]** |
### Config/API 层
| 严重度 | 问题 | 行号 | 处理 |
|---|---|---|---|
| **[已确认]** | **FP16C 被正确拒绝。** | `config.py:119-123` | ✅ |
| **[已确认]** | **28/28 参数通过四层一致性检查。** | B4a 参数追踪表 | ✅ |
| **[已确认]** | **OBS 布局四层完全匹配。** | B4d 对比表 | ✅ |
| **[架构/低]** | **CONFIG.md 写"建议整除"而非"必须"。** 代码用 ceiling division。 | `configs/CONFIG.md:13`, `lbm/stepper.py:272-274` | **[保留说明]** |
| **[已修复]** | **`LBMConfig` 默认 `omega_max=1.99``1.96`,与 JSON/CONFIG 一致。** | `config.py:84` | ✅ |
### 跨层 Flag/常量同步
| 问题 | 状态 |
|---|---|
| **`FLAG_*` 常量 Python ↔ CUDA 同步** | **[已确认]** 全部一致 |
| **`LBMParams` struct 布局耦合** | **[保留说明]** |
| **V_TAYLOR 硬编码 1** | **[保留说明]** |
---
## 测试覆盖率审计
### Validation runner 与文档一致性
| 结论 | 项目 | 说明 |
|---|---|---|
| **[通过]** | Sah04 runner S1-S4 | 四个锚点全部定义并运行 |
| **[缺口]** | Sah04 runner `--u-max` | `u_max_nominal=0.1` 写死 |
| **[缺口]** | Sah04 runner high-beta 网格 | 默认直径与文档推荐不一致 |
| **[通过]** | Kan99b runner K1-K5 | 全部 5 个 caseK2 有 gate |
| **[缺口]** | Kan99b runner K3-K5 | 未做抑制分类自动检测 |
| **[通过]** | 输出机器可读 | 均输出 JSON/CSV |
### 测试基础设施
| 严重度 | 结论 |
|---|---|
| **[严重缺口]** | **零 pytest/unittest 基础设施。** |
| **[严重缺口]** | **四个旧待验证项仅 EsoPull 已修余三项MRT、curved boundary、force 归一化)未覆盖。** |
### 建议的最低测试覆盖面(优先级排列)
1. **MRT 单元测试**uniform flow / Poiseuille / decaying vortex— 单元级
2. **力系数归一化测试** — 单元级
3. **Curved boundary 单列测试** — 单元级
4. **EsoPull vs double-buffer 一致性**Poiseuille 流对比)— 单元/集成级
5. **Validation runner smoke 测试** — 验证级
---
## 保留说明
- **`BC_MOVING` / `BC_PERIODIC` 未分发** — 已标注 TODO暂不实现
- **Curved/Sensor kernel 无运行时越界检查** — 设计选择(依赖 host 验证)
- **Plain linear Bouzidi 与 TRT 不天然相容** [Gin08b] — 注释已存在
- **Curved wall 无质量守恒修正** — 长时间高 Re 周期 curved flow 可能出现力漂移 [San18]
- **入口 `U0` 是截面平均速度**,抛物入口峰值为 `1.5*U0`
- **角点 flag 语义不一致**:初始化时按 inlet/outlet 分类,边界核又落回 `bounce_back_swap()`
- **3D 刚体旋转契约是 z 轴占位实现**`aux_kernels.cu:58-63``Ww = 0.0f`
- **Curved boundary 仍是圆形几何特化**,没有为任意离散几何留出入路径
- **`LBMParams` struct 布局** 在 Python `struct.pack` 与 CUDA struct 之间硬耦合
- **CONFIG.md NT 整除性措辞**:写"建议",代码用 ceiling division
---
## 修改项汇总
| 类别 | 计数 |
|---|---|
| 第一轮修补确认 | 12 项全部 [已确认] |
| 本轮已修复 | 6 项 |
| 保留说明 | 10 项 |
| 暂不处理 | Body 重构 / 测试基础设施 / Validation runner 缺口 |