## 目标 第二阶段不再以补丁式修 bug 为主,而是重建 `body` 与 `LBM` 之间的模块边界,形成可持续扩展到 Bouzidi、IBM、粒子和多相耦合的骨架。重构后的代码需要保持短文件、清晰职责、显式契约,并避免几何语义直接渗入 CUDA 核心计算链路。 ## 第一阶段与第二阶段的边界 ### 第一阶段 目标是验证当前修复后的代码没有恶化,并保住最基本执行链路。 - 能稳定计算流场 - 能读取力与力矩 - Bouzidi 路径不出现新的时序性错误 - 初始化、flag、object overlay 不再互相污染 - 现有接口不做大改,只修运行期 bug 和明显契约错误 ### 第二阶段 目标是结构性重构,而不是继续在旧链路上叠加特例。 - 重构 `body` - 重构 curved boundary 数据链 - 为 IBM 预留统一入口 - 为简单几何和离散几何建立同一中间表示 - 为未来多相与多物理场保留清晰耦合面 ## 当前架构的核心问题 ### 主要问题 | 模块 | 当前问题 | 后果 | |---|---|---| | `body` | 几何、flag overlay、compact list、action、obs、coupling 混在一起 | 任一功能扩展都会牵动整条链路 | | `objects.py` | 几何对象直接生成 Bouzidi 专用数据 | 简单几何和离散几何无法共享同一接口 | | `curved_boundary` | 几何解释、边界格式、移动壁修正、力提取绑在同一层 | 替换边界方法成本高 | | `ObjectManager` | 过度集中,已经接近万能管理器 | 可读性下降,后续只能继续膨胀 | | host-device contract | 分散在多个文件,缺少统一定义 | 调试困难,容易出现隐式耦合 | ### 本质判断 当前最大问题不是公式本身,而是缺少稳定的中间层。几何对象、边界方法、运行时打包目前没有被拆开,导致代码很难既简洁又可扩展。 结合本轮修 bug 的经验,再补一条判断:很多问题不是几何本身出错,而是 donor、fallback、time layer 这类数值语义散落在不同文件中,读代码时必须来回跳转才能确认。当前项目更适合把这些语义集中写进少数注释位置,而不是继续加更多隐式保护逻辑。 ## 第二阶段的目标架构 ### 顶层模块 保持两大物理模块: - `LBM` - `body` 但它们之间不直接互相了解实现细节,而通过显式中间数据结构耦合。 ### 推荐分层 | 层级 | 职责 | 不应负责 | |---|---|---| | `simulation` | 装配模块,定义推进顺序 | 几何处理,边界公式细节 | | `body` | 几何、刚体状态、预处理、力回收 | DDF 操作,LBM 核心算法 | | `lbm` | 格子流体、collision、streaming、boundary operator | 几何来源,刚体业务语义 | | `coupling` | cut-link、IBM marker、body-fluid 数据交换 | 具体几何类定义,具体 collision 实现 | ## 推荐的 body 内部结构 ### 目标 `body` 应只表达拉格朗日对象和几何处理,不直接承载 LBM 业务逻辑。 补充边界:`body` 负责管理对象并产出统一 cut-link 几何记录,`lbm` 只消费 cut-link 做数值计算。对象类型区分、几何来源、以及“该记录来自圆柱还是离散几何”都不应进入 LBM kernel 视野。 ### 推荐文件树 ```text body geometry base circle sphere polygon mesh state rigid_body_state particle_state preprocess flag_overlay cut_links ibm_markers sensors runtime action_buffer telemetry_buffer registry coupling wall_velocity force_torque ``` ### 说明 - `geometry` 只回答几何问题 - `state` 只保存状态量 - `preprocess` 负责把几何投影到欧拉网格 - `runtime` 负责 GPU 上传与 buffer 管理 - `coupling` 负责 body 与 fluid 的交换规则 进一步要求: - `geometry` 不直接生成 Bouzidi 专用 SoA - `preprocess` 先产出统一 cut-link 结果,再由更薄的一层做运行时打包 - `runtime` 不回头参与几何判断 - 单文件保持简短,避免再出现一个文件同时含几何、打包、上传、观测解释四类职责 ## 推荐的 LBM 边界 ### LBM 应该看到什么 LBM 只应看到这些输入: - `flag` - `cut-link records` - `IBM marker records` - `runtime params` - `obs buffers` LBM 不应知道: - 该 link 来自圆柱还是三角网格 - 该对象是粒子还是障碍物 - 该边界记录由哪种 host 几何算法产生 ## curved boundary 的重构方向 ### 核心原则 不要把 curved boundary 等同于 Bouzidi。 需要拆成三个维度: - 几何表示 - 边界处理方法 - 运动模型 补充一条实现原则:donor、fallback、time layer 等关键数值语义,优先通过集中注释写清楚,不额外引入很多“自动保证语义”的复杂逻辑。当前项目更优先保持代码短、直、可读。 ### 建议的统一中间表示 定义通用 `cut-link record`,至少包含: | 字段 | 含义 | |---|---| | `fluid_idx` | 流体格点索引 | | `dir` | 指向边界的格子方向 | | `q` | 交点沿链路的位置 | | `body_id` | 所属物体 | | `hit_point` | 壁面交点 | | `lever_arm` | 相对参考点的力臂 | | `normal` | 壁面法向 | | `motion_tag` | 静止、平移、旋转等 | | `scheme_tag` | Bouzidi、half-way、未来 TRT-compatible scheme | | `fallback_tag` | donor 非法时的退化方式 | 补充约束: - `cut-link record` 只表达几何命中结果与最小运行时字段,不直接长成某一种 kernel 专用格式 - donor 的来源与时间层语义不额外做复杂自动推断,靠集中注释写清楚 - 记录字段命名要直接对应 kernel 使用含义,避免同一字段在不同文件中有不同解释 ### 这样做的好处 - 圆形和离散几何可以输出同一种记录 - Bouzidi 与 IBM 可以共享一部分几何预处理 - boundary kernel 只消费记录,不关心几何来源 - 以后替换边界方法时,不必回改对象类 - donor、fallback、hit-point 这类契约可以在少数固定注释位置集中说明,而不是散落在对象类和 kernel 两侧 ## IBM 的预留方式 IBM 不应和 Bouzidi 混成一条链,而应与 cut-link 平行。 建议另设统一 `marker record`,用于: - 插值点位置 - 支撑域格点 - 权重 - 与刚体的归属关系 这样未来可以并存: - cut-link boundary - IBM boundary - 混合策略 ## 运行时契约的建议 ### 必须显式化的契约 应把 host-device contract 从各文件中收口,单独维护。 建议集中定义: - action buffer layout - telemetry buffer layout - cut-link record layout - marker record layout - force torque sign convention - body velocity contract ### 运动状态契约 即使短期只做 2D 圆柱旋转,也建议按最终形式设计: | 状态 | 建议字段 | |---|---| | 平移 | `vx vy vz` | | 角运动 | `wx wy wz` 或 2D 的 `omega` 特化视图 | | 参考点 | `cx cy cz` | | 姿态 | `theta` 或旋转表示 | 不要再把 3D 路径固化为“只读一个 z 轴 `omega`”。 ## 第二阶段推荐顺序 ### 阶段 2A 先把职责边界拆开,不追求新功能。 - 拆 `ObjectManager` - 建立 `BodyRegistry` - 建立 clean `runtime buffer` 层 - 建立单独的 geometry preprocess 层 - 把“对象管理”和“cut-link 产出”分开 验收标准: - `body` 不再直接知道具体 LBM kernel 调度 - `ObjectManager` 不再承担几何、obs、state、flag 全部职责 - `objects.py` 不再直接输出某一种 boundary method 专用打包格式 ### 阶段 2B 重构 curved boundary 数据链。 - 定义统一 `cut-link record` - 让圆柱先输出新 record - 让 Bouzidi kernel 消费新 record - 把现有 `CurvedLinkSoA` 从“Bouzidi 专用”改成“通用 cut-link buffer` - donor 与 fallback 的契约集中写入注释,不额外增加复杂语义保护代码 验收标准: - kernel 不需要知道几何来源 - host 侧可以替换 cut-link builder 而不改 kernel 接口 - 读 builder 与 kernel 时,不需要跨很多文件才能理解 donor 和 fallback 的基本语义 ### 阶段 2C 为 IBM 留入口。 - 定义 `marker record` - 预留独立 preprocess 和 runtime buffer - 暂不实现完整 IBM 细节,只把架构位置留好 验收标准: - IBM 不需要重写 body 骨架 - IBM 与 Bouzidi 可以共存于同一 body 系统 ### 阶段 2D 补文档与契约说明。 - 当前能力 - 预留能力 - 不支持项 - 2D 与 3D 差异 - TRT 与 plain Bouzidi 的限制 ## 不建议做的事 - 不要继续强化万能 `ObjectManager` - 不要让几何对象直接生成某一种边界格式专用 SoA - 不要把 curved boundary 和 Bouzidi 永久绑定 - 不要在 3D 运动契约上继续堆占位特例 - 不要在第二阶段把多相、IBM、粒子一起全做完 - 不要为了“自动保证语义”继续增加很多隐式逻辑分支,优先用集中注释把契约写清楚 - 不要引入必须跨很多文件来回跳转才能理解的 host-kernel 组织方式 ## 第二阶段完成后的理想状态 ### 代码层面 - 文件更短 - 模块职责更单一 - host-device contract 更显式 - kernel 更专注于数值操作 - geometry 与 boundary method 解耦 ### 扩展层面 后续可自然扩展到: - 离散几何 cut-link - IBM marker 链路 - 粒子和刚体共用 body runtime - 多相流对 body 的额外 coupling ### 维护层面 后续新增功能时,优先在对应层增加文件,而不是回到单个 manager 中继续堆逻辑。 ## 建议的执行方式 第二阶段执行前,先固定一个简短设计约束: - 单文件不过长 - 新增模块必须有明确职责说明 - 任何 host-device 数据结构必须有集中定义 - 新接口先定义契约,再写 kernel - 能通过新增 builder 解决的问题,不要回写到 geometry 类中 - donor、fallback、time-layer 等关键数值语义必须在少数固定位置集中注释说明 - 优先保持文件短和职责单一,不为“保险”堆太多诊断与保护代码 这个阶段的核心产出不是新功能,而是一个能长期承载新功能的骨架。