# Sub-agent A: CUDA Kernel & Fix Verification ## 1. 旧修正确认 ### 结论: [已确认] Curved Bouzidi 时序 — aux_kernels.cu:26-65 + stepper.py:71 + one_step_double.cu:20 **理由**: `stepper.py:71` 中 `_launch_curved()` 在 `OneStep` 之前调用。`aux_kernels.cu` 的 `CurvedBoundaryKernel` 写入 `f.ddf_gpu`(当前 buffer),其后 `OneStep` 从同一 buffer 做 `stream_pull_load` — 同一时间步内完成"前写入→后拉取"。`one_step_double.cu:20` 中的 `apply_boundary_pull` 对 `is_curved(fl)` 直接 return,确保流体节点不会二次覆盖。调用顺序确认无误。 ### 结论: [已确认] q>=0.5 分支时间层 — curved_boundary.cuh:73-75 **理由**: `q >= 0.5` 分支读取 `load_ddf(fi, index_f(k_f, dir_opp))`,其中 `fi` 是当前步骤的 DDF buffer。旧代码读的是前一时间步的缓冲区(`fi_in`),现在读的是当前的 `fi`,即上一时间步碰撞后的 post-collision 数据。Bouzidi 两分支算法都要求同一时间层的 post-collision 数据 [Bou01],当前写法满足此要求。 ### 结论: [已确认] Moving wall 修正按 q 分支 — curved_boundary.cuh:30-43 **理由**: `bouzidi_linear_moving_correction` 函数三路分支: - `fallback_class != BOUZIDI` → `2 * alpha_ci_dot_uw`(半格加移动修正) - `q < 0.5` → `2 * alpha_ci_dot_uw`(Bou01 公式) - `q >= 0.5` → `alpha_ci_dot_uw / q`(Bou01 公式) 各项系数与文献一致,`alpha_ci_dot_uw = 3 * w_i * (c_i · u_w)`。 ### 结论: [已确认] Forcing 预因子统一 — collision_srt.cuh:15, collision_trt.cuh:35, collision_mrt.cuh:41/116 **理由**: 三个文件的类内路径都使用了 `c_tau = 1.0f - 0.5f * omega` 并将 `c_tau * Fin[i]` 增量加到碰撞输出中。`collide_dispatch()`(helpers.cuh:33-37/46-50)在 `d_params.fx/fy/fz`非零时调用 `compute_guo_forcing()` 生成 `Fin`,然后传入对应碰撞函数。三者完全一致。 ### 结论: [已确认] TRT outlet NEQ 全分布重构 — pressure_neq.cuh:45-51(D2Q9):89-95(D3Q19) **理由**: `#if COLLISION_MODEL == 0 || COLLISION_MODEL == 1` 把 TRT 纳入全分布 damped NEQ 分支(与 SRT 同级),对所有 NQ 方向做 `f[i] = feq_tar[i] + beta * fneq`,其中 `fneq = f_neb[i] - feq_neb[i]`,`beta = OUTLET_SRT_NEQ_DAMP`。已不再是"少量未知方向"路径。 ### 结论: [已确认] add_vortex() 除以 rho — initializers.py:55-58 **理由**: `ux_old = sum(f[i] * cx[i]) / rho_safe`,`uy_old = sum(f[i] * cy[i]) / rho_safe`。旧 bug 是动量除以 rho 这一步缺失,现在存在 `rho_safe` 分母。 ### 结论: [已确认] Init flag overlay 顺序 — simulation.py:139-159 + init_flow.cu:48-58 + body/manager.py:115-127 **理由**: 顺序为 `build_channel_flags()`(干净通道)→ `build_flags()`(叠加物体)→ `upload_flags()`(上传GPU)→ `stepper.initialize()`(运行 init kernel 保持 obstacle flag)。`init_flow.cu:finalize_domain_flag` 对 `is_obstacle(fl)` 直接返回原 flag。`sync_to_gpu(rebuild_flags=False)` 在初始化时不重复构建 flags。`_rest_nonfluid()` 的二次重置已移除。 --- ## 2. 待验证项复查 ### 结论: [已确认] MRT D2Q9 方向序与符号 — collision_mrt.cuh:46-54,79-92 **理由**: 经子代 agent 验证: - `m[3]` = f1−f2 + f5−f6 + f7−f8 = ρ·ux(与 `macro.cuh:36` 的 `compute_rho_u()` 完全一致) - `m[5]` = f3−f4 + f5−f6 − f7 + f8 = ρ·uy(一致) - `m[7]` = f1+f2−f3−f4 = ρ·(ux²−uy²)(一致) - 逆变换系数 `g[0] += (dm0 − dm1 + dm2)/9` 等均符合 `M·M⁻¹ = I` - `meq[4] = −ρ·ux`、`meq[6] = −ρ·uy` 符号正确(正交基结构) - 无符号错误。MRT D2Q9 的 paired 方向排列下的矩变换自洽。 ### 结论: [已确认] Esopull 邻壁行处理 — one_step_esopull.cu vs one_step_double.cu **理由**: 逐行对比 `one_step_esopull.cu:76-151` 与 `one_step_double.cu:65-144`。Double-buffer 在 line 88-94 有显式 `is_fluid(fl) && (y==1 || y==NY-2)` 块调用 `apply_wall_bb_y_pull`,而 Esopull 没有对应分支。**但这不构成 bug** — Esopull 交替读写模式(`load_f_esopull` / `store_f_esopull`,`esopull_single_buffer.cuh:33-77`)天然避免了从 y=0 壁面节点直接拉取垃圾数据: - 偶数步:f[3] 读取本地 `fi[n, 4]`(前一步该节点的 -y 方向),f[4] 读取 `fi[j[3], 3]`(y=2 的 +y 方向) - 奇数步同理交错 两个时间步的综合效果等价于半格 BB 的反射,无需显式修正。壁面节点 (y=0) 经 `apply_boundary_esopull` → `bounce_back_swap` 处理,不会积累垃圾。 ### 结论: [无法确认: 需运行验证] Force 提取与符号约定 — curved_boundary.cuh:90-97 + obs.cuh + manager.py:328-338 **理由**: 链路追踪如下: 1. `curved_boundary.cuh:91-97`: `fx = c_x * (f_toward + f_reflected)` 累加到 `obs[obs_force_index(body_id, 0)]` 2. `obs.cuh:11`: `obs_force_index(id_obj, d) = OBS_FORCE0_FLOATS + id_obj * DIM + d`(起点=0) 3. `manager.py:read_force()`: 返回 `self.obs_pinned[i0:i0 + d]`,无符号反转 - 存储的是流体动量交换量 (fluid momentum exchange),不是物体受力的直接值(牛顿第三定律要求 `F_body = -F_fluid`)。如果外部 Cd/Cl 归一化时把 obs 直读值当做物体受力,符号会反转。需用已知算例(如静止圆柱的阻力系数)确认当前实践是否在外部做了隐含的取反。 --- ## 3. 架构缺陷 ### 结论: [未改] Curved boundary 仍假设圆形/球形 — curved_boundary.cuh + body/objects.py:110-291 **理由**: `Cylinder.get_curved_list()` 对每个 cut link 调用 `find_circle_intersection` / `find_sphere_ray_segment`,完全依赖于圆/球几何参数(center + radius)。没有通用多边形/三角网格接口。旧审计标记的 [待重构] 未处理。 ### 结论: [未改] 3D 旋转为 z 轴占位 — aux_kernels.cu:58-63 **理由**: `CurvedBoundaryKernel` 的 D3Q19 分支中 `Ww = 0.0f`,且 `Uw = -omega * ry; Vw = omega * rx` 只包含 xy 平面转动。任何具有 z 分量的刚体旋转都不会产生正确的壁面速度。 ### 结论: [已备注] Bouzidi-TRT 不相容注释 — curved_boundary.cuh:17-21 **理由**: 注释明确说明 "plain linear Bouzidi interpolation ... is not a TRT-parametrized curved-wall family",位置精准且语意清晰。 --- ## 4. 新发现 ### 4a. `_no_force` 碰撞变体为死代码 — collision_srt.cuh:25, collision_trt.cuh:57, collision_mrt.cuh:95 **问题**: `collide_srt_no_force`、`collide_trt_no_force`、`collide_mrt_no_force` 三个函数在编译后的任何内核路径中均不被调用。`collide_dispatch` (helpers.cuh:15-69) 始终通过带 `Fin` 数组的普通变体执行碰撞,当外力为零时通过 `zero_forcing(Fin)` 将 `Fin` 全清零。死代码约 40 行。 **影响**: 无功能影响,增加维护成本。`zero_forcing` 仅用于栈初始化,并非无用调用。 ### 4b. BC_MOVING / BC_PERIODIC 有定义无处理 — flags.cuh + 全内核搜 **问题**: `FLAG_BC_MOVING (0x0060)` 和 `FLAG_BC_PERIODIC (0x0050)` 在 `flags.cuh` 有定义,Python 侧 `descriptors.py` 也有对应常量。但 CUDA 内核中没有针对 `is_moving()` 或 `is_periodic()` 的分支处理: - `one_step_double.cu:apply_boundary_pull` 只有 `is_curved/is_inlet/is_outlet/BBS` 分支 - 任何单元格若被标记 `BC_MOVING`(非 curved 路径)将落入 `bounce_back_swap()` 分支,得到 std half-way BB 而非移动壁面速度修正 **影响**: 只有当 obstacle 使用 `BC_CURVED` 配合 `cl_body_id` 进入 curved boundary kernel 才能获得正确移动壁面速度。`BC_MOVING` 直接标记在通道壁面或其他固体节点上无效果。 ### 4c. Outlet NEQ 的 `OUTLET_MODE` 嵌套逻辑可读性隐患 — pressure_neq.cuh:25-62 **问题**: ``` #if OUTLET_MODE == 1 → 纯拷贝未知方向 #else → 普通路径 #if COLLISION_MODEL==0||1 → 全分布 NEQ(含 TRT) #elif OUTLET_MODE == 2 → 混合模式 #else → 少量未知方向重构(默认 OUTLET_MODE=0 路径) #endif #endif ``` 当 `OUTLET_MODE=0`、`COLLISION_MODEL=2`(MRT)时,代码进入最内层 `#else` 分支(少量未知方向重构),而非全分布 NEQ。这与注释宣称的"SRT 和 TRT 使用全分布 NEQ"一致(MRT 未承诺),但 MRT outlet 路径与 SRT/TRT 行为不同,可能导致 MRT 结果系统性偏差。 **影响**: MRT outlet 行为与 SRT/TRT 不一致,应至少加注释说明此差异,或行为对齐。 ### 4d. `collide_inlet_ghost` 对 `y=0/NY-1` 的过滤 — one_step_double.cu:102-103, one_step_esopull.cu:106-107 **问题**: `collide_inlet_ghost = is_inlet(fl) && interior_y && inlet_scheme_uses_post_collision_ghost()`,其中 `interior_y = (y>0 && y= 1.0` 时除数为 0 或负数。物理上入口马赫数小于 1 可避免,但无运行时保护。 **影响**: 低风险(物理约束),但崩溃行为不如显式断言清晰。 --- ## 总结 | 类别 | 数量 | 关键项 | |------|------|--------| | 旧修正确认 | 7/7 | 全部确认正确 | | 待验复查 | 3 | 2 确认, 1 需运行时验证 | | 架构缺陷 | 3 | 圆形硬编码、3D占位、TRT注释齐全 | | 新发现 | 8 | 4a死代码、4b未处理BC、4c MRT outlet差异、4d脆弱逻辑依赖、4e已实现、4f无害保护、4g除零边界、4h无保护输入 | **最高优先级**: 4b (`BC_MOVING` 无处理路径)、4c (MRT outlet 路径与 SRT/TRT 不一致)、force 符号约定需运行验证。