Files
SystemSimulationApp/docs/other/C语言数值内核实施计划与可行性评估.md
T
2026-09-02 13:48:51 +08:00

407 lines
26 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.
# C 语言数值内核实施计划与可行性评估
> 文档状态:待评审实施方案
> 建立日期:2026-09-02
> 适用分支:`model-development`
> 关联文档:[求解器性能优化任务清单](求解器性能优化任务清单.md)、[后端求解逻辑与效率优化调研](后端求解逻辑与效率优化调研.md)
> 范围:后端数值执行内核;不包含前端重写,也不主张把整个 Python 后端改写为 C
## 1. 结论
这条路线值得实施,但正确的目标不是“把现有 Python 代码逐行翻译成 C”,而是:
1. 保留 Python 作为模型解析、网络编译、任务管理、结果服务和正确性参考;
2. 先把完整的一次 RHS 计算编译成无 Python 回调的扁平数值 IR;
3. 再让 C 内核一次完成整次 RHS、stream、物性、Jacobian 和事件计算;
4. Python 旧引擎长期保留为不支持模型的兼容路径和故障回退路径。
总体技术可行性为**中高**。仓库已经具备因果计划、参考 IR、稀疏 Jacobian 结构、性能埋点和 AMESim 回归基础,因此不是从零开始。主要难点不是 C 语法,而是完整冻结当前模型的计算顺序、副作用、事件和回滚语义。
“实现稳定的 C 数值后端”具有较高可能性;“仅靠换成 C 就达到接近 AMESim 的速度”目前不能承诺。高刚度 LSTP 接触会让积分器产生大量纳秒级小步,有限差分 Jacobian 又会重复调用 RHS。C 能降低每次计算的成本,但不会自动减少这些计算次数。真正的大幅收益需要同时完成:
- 完整扁平 IR;
- 整体 C RHS;
- 稀疏解析或半解析 Jacobian;
- 正确的接触事件和模式切换;
- 必要时再评估原生积分器。
## 2. 推荐的最终边界
```text
XML / JSON
↓
Python:解析、校验、组件注册、网络编译
↓
完整扁平 IR:槽位、阶段、依赖、模式、事件、Jacobian 结构
↓ 一次跨语言调用完成整次计算
C 数值内核:RHS / stream / 物性 / Jacobian / Event
↓
SciPy BDF(首阶段保留)或后续通过验证的原生积分器
↓
Python:采样、结果编码、API、任务状态和诊断
```
以下边界必须坚持:
- 不在每个组件上来回调用 Python 和 C;一次 RHS 最多进行一次主要跨语言调用。
- C 兼容模型的热路径内不得调用 Python callback。
- C 内核不直接解析 XML,不管理 HTTP,也不承担组件编辑和数据库职责。
- 自定义 Python 组件不能静默降级为跨语言逐组件调用;只要整模型不满足原生能力合同,就明确走 Python 引擎。
- 迁移期间始终保留 `python`、`native`、`shadow` 三种模式;通过长时发布门后才能增加 `auto` 默认选择。
建议统一配置为:
```text
SIMULATION_NUMERIC_ENGINE=python|native|shadow|auto
```
其中 `shadow` 由 Python 控制正式积分,C 只接收相同输入并逐阶段比较,不允许影响 Python 工作区。
## 3. 当前基础与首个阻断
### 3.1 已有基础
- `causal_ir.py` 已有 schema v1、结构签名、预分配工作区、阶段观察和事务回滚原型。
- 当前因果执行器已经消去一部分重复逻辑坐标,并证明了数组化和预编译执行计划的方向有效。
- 已有 Jacobian 稀疏图、局部切向原语和显式实验回退路径。
- 已有 AMESim 结果读取、物理投影、递进时域 runner、性能统计、取消和故障注入测试。
- 当前主模型约有 156 个运行组件、20 种组件类型和 132 个连续状态,适合用“能力矩阵 + 分阶段覆盖”推进。
### 3.2 当前 IR 的缺口
现有 schema v1 只覆盖全局因果代数计划,绑定仍依赖 Python 的 reader、writer 和 evaluator 回调。以下内容尚未进入同一个无回调执行计划:
- 状态写入和信号传播;
- dynamic volume 和物性状态包;
- secondary 压力/流量块;
- stream SCC/DAG 和热流体外层闭合;
- 状态导数;
- 离散 mode、事件检测、reset 和重启;
- Jacobian 数值填充;
- 结果投影。
因此,当前 IR 不能直接包一层 C 接口后就获得预期收益。
### 3.3 P0 跨平台换行阻断(已解决)
当前 Windows 工作树中的权威输入按原始字节计算时与 manifest 不一致;进一步核对确认,差异全部来自 Git 检出后的 `CRLF` 换行,而不是模型内容变化:
| 文件 | Windows 工作树原始字节 | 将 `CRLF` 还原为 `LF` 后 | manifest 记录值 |
| --- | --- | --- | --- |
| `tests/data/test-mql-8.xml` | 106,188 B;2,078 个 `CRLF`;SHA-256 `e7eef641...b801` | 104,110 B;`0a2d9331...7b0b` | 104,110 B;`0a2d9331...7b0b` |
| `tests/data/test-mql-8.json` | 282,796 B;10,204 个 `CRLF`;SHA-256 `51e1acb3...11e2` | 272,592 B;`b44bf540...fbe0` | 272,592 B;`b44bf540...fbe0` |
| `AmesimModels/test_mql.ame` | 21,708,800 B;`cbc3aadd...c20fbb` | 不适用 | 一致 |
因此没有证据表明 fixture 语义发生漂移,也不应仅因这一差异重建 golden。真正的问题是:manifest 按原始字节锁定输入,而 `.gitattributes` 没有固定这两个文本 fixture 的换行;当前加载器又直接校验工作树原始字节,所以同一提交在 Windows 上可能被拒绝、在 Linux 上通过。
该阻断已于 2026-09-02 完成本地修复:`.gitattributes` 已将两个主模型输入、历史 0.81 s 输入和 `tests/baselines/simulation` 下的 JSON 证据固定为 `LF`,当前 Windows 工作树也已从 Git 索引重新检出为 `LF`。自动测试会同时检查属性规则、禁止原始 `CR` 字节,并按 manifest 复核输入大小和 SHA-256;CI 已配置为在 Ubuntu 和 Windows 上分别执行这一合同,远端运行证据待提交后取得。
本地验收显示这些文件均为 `index=LF / worktree=LF / eol=lf`,两个 regression manifest 可在 Windows 正常完整加载,现有 manifest 和 golden 无需更新。未来只有在规范化后的内容确实变化时,才进入“模型变更、重建 manifest/golden”的流程。历史性能数字仍需按其代码版本看待,但不因换行差异失效。
## 4. 按重要性排序的实施计划
优先级定义:
- `P0`:正确性和架构前置,不完成就不能安全编写生产 C 内核;
- `P1`:形成可用且有明显收益的 C 后端;
- `P2`:P1 证明有效后再实施的增强项。
表中的工期是单名熟悉现有求解器的开发者的粗略有效工作量,不是交付承诺,也不包含长时仿真排队时间。
| 顺序 | ID | 优先级 | 工作项 | 可行性 | 粗略工作量 | 主要依赖 |
| ---: | --- | --- | --- | --- | --- | --- |
| 1 | C-00 | P0 | 固定权威基准的跨平台合同,建立双引擎与回滚合同 | 高 | 1–2 人周 | 现有 OPT-00 |
| 2 | C-01 | P0 | 定义完整数值 IR schema v2 | 高 | 3–5 人周 | C-00、OPT-01/02 |
| 3 | C-02 | P0 | 建立纯数值组件 kernel 合同和能力矩阵 | 中高 | 3–6 人周 | C-01 |
| 4 | C-03 | P0 | 完成 Python 扁平参考执行器与 Shadow 差分 | 中高 | 3–5 人周 | C-01、C-02 |
| 5 | C-04 | P1 | 稳定 C ABI、构建链和隔离 worker | 高 | 3–5 人周 | C-01,可并行 |
| 6 | C-05 | P1 | 完成一个闭环代表子系统的 C 纵向切片 | 高 | 2–4 人周 | C-03、C-04 |
| 7 | C-06 | P1 | 扩展到完整内置 RHS、stream 和物性 | 中高 | 5–9 人周 | C-05、OPT-04 |
| 8 | C-07 | P1 | 稀疏解析/半解析 Jacobian 与局部回退 | 中 | 6–12 人周 | C-02、C-06、OPT-03 |
| 9 | C-08 | P1 | LSTP/MECMAS 事件、模式和默认灰度 | 中 | 4–8 人周 | C-06、C-07、OPT-05/06 |
| 10 | C-09 | P2 | 模型专用 C 代码生成和编译缓存 | 中 | 4–8 人周 | C-06~C-08 |
| 11 | C-10 | P2 | 评估 CVODE;有真实 DAE 需求时再评估 IDA | 中/当前低 | 4–10 人周 | C-06~C-08 |
| 12 | C-11 | P2 | 输出、部署、并发和发布收口 | 中高 | 3–6 人周 | 原生默认候选 |
### 4.1 P0:先固定语义和参考答案
#### C-00 固定权威基准、双引擎和回滚合同
工作内容:
- [x] 固定 `test-mql-8.xml/json`、历史输入和回归证据的跨平台 `LF` 字节合同,实际重新规范化当前 Windows 工作树,并用 Git EOL 状态、原始 SHA-256 和双平台 CI 保护该合同;未重建语义未变的 golden。
- 重新加载 manifest 并执行 Python `0.01 s` smoke;只有发现规范化后的内容或物理结果确实变化时,才重新生成结构清单和 golden。
- 冻结当前 Python 引擎为参考实现,定义 `python/native/shadow/auto` 的启用条件。
- 原生不支持的模型只允许在编译或加载阶段整模型回退;正式验收时禁止静默回退。
- 每个阶段使用独立小提交,记录输入哈希、环境、二进制哈希和回滚开关。
完成标准:相同输入能够稳定强制走 Python;关闭原生后行为与当前参考提交一致;模型、环境和结果来源都能追溯。
#### C-01 完整数值 IR schema v2
完整 IR 必须描述共享数值阶段,以及 RHS、Event、Jacobian 和输出四类独立的按需入口。它们可以复用同一套槽位和依赖信息,但不能被误实现成“每次 RHS 都顺序计算 Event、Jacobian 和输出”。共享 primal 计划为:
```text
state scatter
→ signal
→ mechanical equivalence / dynamic volume
→ property bundle
→ first pressure-flow closure
→ stream SCC/DAG
→ temperature reference update
→ sensitive-island closure / thermofluid fixed point
→ mechanical acceleration
```
四类入口分别编译自己的依赖切片:
```text
eval_rhs = required primal stages → derivative
eval_events = required primal stages → event values
eval_jacobian = RHS primal / local derivative or JVP → CSR values
eval_outputs = required primal stages → output projection
```
IR 至少描述:
- 连续状态、代数坐标、参数、常量、离散模式和工作区槽位;
- 每个阶段和 opcode 的读写集合、单位、缩放、上下界和错误来源;
- stream 图、SCC、物性状态包、外层固定点和事务恢复集合;
- event ID、左/右状态、reset、Jacobian 失效和模式计划;
- 固定的 CSR Jacobian 结构和 output projection;
- IR schema、native ABI、组件模型/实现、介质、编译器、dtype、平台和构建选项组成的结构签名。
原生兼容 program 中不得存在 Python callback。schema v1 保留为参考适配器,不直接扩展成生产 ABI。
完成标准:同一模型重复编译得到字节级稳定的结构和签名;所有索引及读写集合可静态校验;缺少能力时明确拒绝编译。
#### C-02 纯数值组件合同
每个内置组件需声明:
- `kernel_id` 和实现版本;
- 输入、输出、参数、状态和 mode 槽位;
- primal、局部导数/JVP、event 和 reset 能力;
- 支持的正反流、接触和物性范围;
- 类型化错误码和局部数值差分回退边界。
组件 kernel 必须满足“相同输入得到相同输出”,不能依赖隐藏的 Python 对象写入。旧组件类继续作为参考实现。
首批纵向切片建议选择一条完整的 `MECMAS21 → PNRP17 → PNCH012 → PNL0001/LSTP00A` 支路及其介质/stream 闭合,因为它同时覆盖机械、气动、物性、流量和高刚度接触。
#### C-03 Python 扁平参考执行器
先用 Python/NumPy 完整执行 schema v2,目标是验证语义,而不是追求最终速度。它应摆脱 `PortState` 作为主语义载体,能在每个阶段与当前对象引擎比较首个差异。
完成标准:代表模型在普通点、反向流点、事件左右和 Jacobian 扰动点逐槽一致;`0.01/0.2/0.81/2.10 s` 的状态、事件、守恒和物理投影满足现有合同。
### 4.2 P1:形成真正有价值的 C 后端
#### C-04 稳定 C ABI、构建链和隔离 worker
底层使用稳定纯 C ABI,Python 绑定保持很薄。最小接口应包含:
```text
model_create
eval_rhs
eval_jacobian
eval_events
apply_event
eval_outputs
model_destroy
```
接口使用不透明 `ModelContext`、固定宽度整数、连续 `float64` 数组和显式长度;CSR 结构在编译时固定,运行时只填 values。每个任务独占可变 context/workspace/cache/mode,不使用可变全局缓存,热路径预分配且不进行常规堆分配。
首阶段仍由 SciPy BDF 积分,只替换整个 RHS/Jacobian 计算。构建链需覆盖 Windows x64 和 Linux x86_64,固定构建依赖,并禁止 `/fp:fast`、`-ffast-math`、`-march=native` 等会改变事件边界或破坏可移植性的默认选项。
原生访问违规、崩溃或死循环不能在同一 Python 进程中安全恢复。因此原生默认启用前,仿真必须运行在可硬终止的隔离 worker 中;C 同时接收取消标志并在组件阶段、stream SCC、Jacobian 和迭代处有界检查。
#### C-05 闭环纵向切片和首次 Go/No-Go
一次跨语言调用应完成代表子系统的整次 RHS,禁止按组件往返。先为该闭环子系统建立独立代表 fixture,执行 Shadow 和短时积分,不立即扩大组件覆盖。由于此阶段尚未覆盖主模型的全部组件,`test-mql-8` 整模型按能力合同回退 Python 是预期行为,不能拿它衡量 C-05 的端到端收益。
继续扩面的最低门槛:
- RHS 微基准至少达到 Python 的 `2×`;目标值为 `3×` 以上;
- 独立代表 fixture 的短时完整仿真中位时间至少降低 25%;
- 代表 fixture 的状态、事件、模式和守恒门全部通过;存在对应 AMESim 投影时也必须通过;
- `nfev/njev/nlu` 和接受步等工作量没有无法解释的变化;
- 无 Python callback、无静默回退、无内存错误。
如果 RHS 已快很多而完整仿真几乎不变,应先检查 Jacobian、微步数和跨语言边界,而不是直接继续扩大 C 代码。
#### C-06 完整内置 RHS、stream 和物性
- 把所有受支持的内置组件纳入能力矩阵;一个组件不支持时整模型明确走 Python。
- 将 stream 图编译成 SCC 和缩点 DAG:无环部分一次传播,只在循环 SCC 中迭代。
- 将 `p/T/rho/u/h` 及其导数组成同一物性状态包,按精确输入和阶段统一复用。
- 移除每轮临时字典/列表,使用预分配数组和原地误差统计。
- 保留试探状态事务回滚、反向流、温度参考更新和类型化可恢复失败语义。
完成标准:主目标使用的全部内置组件可原生执行;stream 迭代、压力流量残差和物性结果不恶化;跨平台字节合同修复后的同一权威输入通过短程与中程回归,且 `0.2 s` 完整仿真中位时间至少降低 30%。
#### C-07 稀疏解析/半解析 Jacobian
这是获得大幅端到端收益的关键步骤。当前历史报告中,有限差分 Jacobian 会贡献大量额外 RHS 调用;仅把 primal RHS 改成 C 仍会重复执行它。
- 组件局部导数沿完整 IR 传播,直接填充固定 CSR values。
- 不支持或非光滑点只对局部组件、状态列或 SCC 做数值差分,不能让一个局部问题恢复全网有限差分。
- 每次构建记录解析列、局部差分列、回退位置、JVP 审计和装配时间。
- LSTP 接触、流向切换、饱和及临界流动使用分段导数,并在边界上明确选择事件分段或局部回退。
完成标准:有限差分附加 RHS 至少减少 50%,相对完整 C RHS 阶段再降低至少 20% 总时间;事件顺序、模式和物理投影不变。
#### C-08 事件、模式和默认灰度
- 将 LSTP/MECMAS 的 event、mode、reset、Jacobian 失效和 solver restart 纳入正式 IR/C 合同。
- 对接触进入、保持、释放,上下端挡、回弹、同时事件、擦边事件和防抖分别测试。
- 按 `shadow → 显式 native → 模型签名白名单 → auto` 逐级启用。
- 只有当前权威 `10 s` 连续三次通过后,才允许受支持模型默认走 C。
需要特别注意:C-08 不只是把同一接触公式写成 C,还要减少因接触表达方式造成的不必要纳秒级微步。任何软化、容差或事件改动都属于数值算法变化,必须与纯执行优化分开提交和验收。
### 4.3 P2:证明 P1 有效后再做
#### C-09 模型专用 C 代码生成
通用 C IR 解释器稳定后,若 opcode 分派仍是明确热点,再为固定模型生成专用 C。XML 文本不得直接拼入源码;生成器只消费校验后的数值 IR。编译缓存键必须包含完整结构签名、编译器和 flags。
只有相对通用 C 执行器额外获得至少约 `1.5×` 的稳定收益,并且编译成本能在重复运行中摊销时才继续。否则保留通用执行器,放弃这一层复杂度。
#### C-10 原生积分器
- 当前系统是“RHS 内完成代数闭合”的半显式 ODE,先评估 CVODE,不直接切换为 DASSL/IDA。
- 只有 C RHS、Jacobian、事件、可恢复缩步、partial result、activity 和 cancel 合同稳定后,才对 CVODE 做独立 A/B。
- CVODE 在相同正确性门下额外降低至少 25% 总时间才值得替换 SciPy。
- IDA/DASSL 需要新的 `F(t,y,ydot)=0`、代数变量布局、一致初始化、指数和质量矩阵合同。只有真实模型证明无法稳健因果化或 ODE 化时再立项,当前不把它视为提速开关。
#### C-11 输出、部署和发布收口
吸收按需结果变量、列式输出、结果分块、编译缓存、并发限流、worker 硬终止和原生崩溃恢复。确保 native 崩溃只影响当前任务,服务仍能接收新任务。
## 5. 分阶段验证与 Go/No-Go 门
| 验证阶段 | 主要内容 | 通过条件 | 未通过时的处理 |
| --- | --- | --- | --- |
| V0 | fixture、环境、Python 和 AMESim 基线 | 来源一致;Python 连续 3 次稳定;现有测试通过 | 基线仍漂移时停止 C 默认路径开发 |
| V1 | 完整 Python IR | 槽位、阶段、读写集合、事件和回滚差分通过 | 先修隐藏副作用和 IR 合同 |
| V2 | C 纵向切片 | 单组件/逐阶段通过;RHS 至少 `2×` | 未达门槛则检查 IR/FFI,必要时停止扩面 |
| V3 | 完整 C RHS + SciPy | `0.01/0.2 s` 通过;总时间至少降低 30%;工作量变化不超过可解释范围 | 不作为纯执行优化合入默认路径 |
| V4 | C Jacobian/Event | FD 附加 RHS 至少减少 50%;相对 V3 再降低 20%;事件/模式一致 | 保留局部差分,禁止整网静默回退 |
| V5 | 长时与鲁棒性 | `1/5/10 s` 递进;10 s 连续 3 次;无泄漏、无静默回退 | 任一短时前驱失败即停止后续长跑 |
| V6 | 默认启用 | Windows/Linux 发布通过;支持模型走 C,不支持模型明确走 Python;可一键关闭 | 保持显式 opt-in |
正式性能比较统一要求:预热 1 次、完整仿真至少测量 3 次并比较中位数、固定机器与电源模式,冷编译和热缓存分开报告。至少记录:
- 总时间、积分、RHS、闭合、stream、物性、Jacobian 和输出时间;
- `nfev/njev/nlu`、接受/拒绝步、solver 启动和事件次数;
- Jacobian 附加 RHS、局部数值差分和回退原因;
- Python/C 边界调用次数和耗时;
- 峰值 RSS、C 工作区、IR/ABI 版本、编译器、flags 和二进制哈希。
附加硬门:关闭 C 时 Python 路径额外开销不超过 2%;纯执行层替换若使 `nfev/njev/nlu` 或接受步数变化超过 2%,必须按数值语义变化单独调查,不能直接归为性能优化;峰值 RSS 不超过 Python 基线的 110%;10 s 中 C 固定工作区不随步数增长,只有结果数组可随采样数增长。
## 6. 正确性验证范围
### 6.1 Shadow 阶段观察点
两个引擎必须接收完全相同的 `time/state/mode/parameters`,按第 4.1 节的 RHS 阶段逐项比较。差异报告至少包含:阶段、槽位、组件、输入、Python 值、C 值、绝对/相对误差和当前模式。
- 槽位布局、模式码、事件 ID、执行顺序和迭代次数要求一致。
- 连续量使用“每种物理量绝对容差 + 相对容差”,不能用一个绝对容差覆盖压力、流量、温度和位移。
- NaN/Inf、压力越界、符号错误和模式不同立即失败。
- 压力流量最大缩放残差继续使用现有 `1e-7` 门。
- 事件点分别比较左极限、事件处理结果和右极限,不扩大容差掩盖不连续。
差分语料至少覆盖:初始状态、接受状态、Jacobian 扰动状态、固定随机种子扰动、压力近似相等、流量换向、接触启停、端挡释放、物性边界,以及历史 `0.69/0.81/2.05 s` 区域。
### 6.2 AMESim 物理门
Python golden 只用于发现实现漂移,AMESim 结果仍是外部物理基线。正式默认前,应在现有 physical-state-v2.1 基础上至少覆盖:
- 代表性气室压力、温度和质量;
- PNL 管路压力、流量及换向;
- PNRP 活塞力;
- MECMAS 位移、速度和模式;
- LSTP 间隙、接触力和接触切换;
- 每个主要支路至少一个代表量。
检查点至少包含 `0`、`0.04 s` 左右、`0.2`、`0.8 s` 左右、`1`、`2`、`5` 和 `10 s`。AMESim 未保存的内部守恒量继续执行独立绝对残差门。
### 6.3 错误、取消和并发
必须覆盖 C 返回非有限值、物性域错误、闭合不收敛、未知 opcode、ABI 不匹配、损坏二进制、失败后事务回滚、编译失败、并发 context 隔离、单任务取消、重复创建/销毁无内存增长和 native 崩溃后的服务存活。
回退分为三层:
1. **启动前自动选择**:编译或加载时发现不支持能力,整次任务在开始积分前明确选择 Python;这是正式模式唯一允许的自动换引擎路径。
2. **受控运行时错误**:native 已开始积分后返回错误时,当前 native 任务直接失败并保留诊断。灰度验证可以从不可变原始请求的 `tStart` 另起一个 Python 重放任务,但必须标为独立重放,不能算作 native 成功。没有完整保存 BDF 历史、事件上下文和已有输出前,禁止从某个 `(t,y,mode)` 假装无缝续跑。
3. **进程级故障**:访问违规或无法返回时,由父进程硬终止 worker,禁止在受损进程中继续;如需 Python 对照,同样从原始请求重新执行。
正式 C 验收要求异常 `fallbackCount=0`。声明过的局部 Jacobian 数值差分不是异常回退,但必须单独计数。
## 7. 对现有优化清单的取舍
现有优化清单不能整体放弃,应按新路线重组:
| 现有任务 | 决策 | 在新路线中的位置 |
| --- | --- | --- |
| OPT-00 基线与回归 | 保留并加强 | C-00 和全部发布门 |
| OPT-01 因果代数内核 | 冻结成果 | 作为 IR 编译输入和 Python 回退,不再继续零散微调 |
| OPT-02 扁平 IR | 升为主线 | C-01、C-03、C-05 |
| OPT-03 Jacobian | 升为主线 | C-07 |
| OPT-04 stream/物性 | 升为主线 | C-06 |
| OPT-05 步长、接触和鲁棒性 | 必须保留 | C-08;C 不能消除微步根因 |
| OPT-06 dense output | 部分前置、其余后置 | 事件合同进入 C-01/C-08,插值微调后置 |
| OPT-07 输出与内存 | 暂缓但不删除 | C-11 |
| OPT-08 取消与并发 | 必须保留并提前 | C-04/C-11;原生代码更需要进程隔离 |
| OPT-09 10 s 验收 | 必须保留 | V5/V6 发布门 |
| OPT-10 高指数 DAE | 有条件暂缓 | 只有真实 DAE 需求时进入 C-10 |
可以停止继续投入的方向:
- 在现有对象热路径上继续做零散字典和属性访问微优化;
- 继续叠加缺少统一失效合同的通用缓存;
- 优化目标模型中未触发的 `least_squares` 回退;
- 不断增加少量特例半解析列,而不先建立通用组件导数合同;
- 直接对当前对象图使用 Numba;
- 通过修改容差、软化物理或寻找“幸运 maxStep”伪装性能收益。
Numba 可以在完整数组 IR 后用于 1–2 周的架构验证,但不作为长期生产依赖。若完整数组 RHS 在 Numba 原型中仍没有明显改善,应先修正 IR 和算法,而不是立即开始大规模 C 重写。
## 8. 可行性评估
| 目标 | 当前判断 | 原因 |
| --- | --- | --- |
| 验证框架、双引擎和基准恢复 | 高 | 现有 runner、golden、AMESim 读取和埋点可复用 |
| 完整 Python 扁平 IR | 中高 | 结构基础已有,主要工作是显式化隐藏副作用和事件语义 |
| 代表子系统通用 C RHS | 高 | 数值边界清楚,一次调用可避免 FFI 碎片化 |
| 当前全部内置组件的 C RHS | 中高 | 约 20 种类型可逐类迁移,但 stream/物性/模式较复杂 |
| 可维护的稀疏解析/半解析 Jacobian | 中 | 收益大,但非光滑接触、流向切换和导数覆盖难度最高 |
| 模型专用 C 代码生成 | 中 | 收益上限高,但构建、缓存、安全和诊断成本明显增加 |
| CVODE 替换 SciPy | 中,且后置 | 可能减少调度开销,但不会自动解决错误方程或接触微步 |
| IDA/DASSL 直接提速 | 当前低 | 目前缺少真正 DAE 的残差、一致初始化和质量矩阵合同 |
| 接近 AMESim 的总速度 | 中低、待实测 | 缺少同机 AMESim 墙钟基线,且当前主要瓶颈同时包含 Jacobian 和接触微步数 |
从项目节奏看,建议把目标分成三档;这里与第 4 节一样使用“人周”,多人并行时日历时间可短于人周总量:
1. **约 15–27 人周:技术决策闭环。** 完成 C-00~C-05,回答完整 IR 是否正确、C RHS 是否有足够收益。
2. **累计约 20–36 人周:可选原生后端。** 完成 C-06,使主要内置 RHS、stream/物性、双平台构建和受控回退可由用户显式启用。
3. **累计约 30–56 人周:默认候选。** 完成 C-07/C-08、10 s 长时、并发隔离和发布门。
模型专用代码生成和原生积分器属于额外阶段,不应计入首个可用 C 后端的承诺。多人并行可以缩短日历时间,但 IR、组件合同、Jacobian 和事件语义存在强依赖,不能按人数等比例压缩。
## 9. 建议立即开展的第一批工作
第一批只做 P0,不直接开始大规模 C 编码:
1. **已完成:** 固定当前权威输入和回归证据的 `LF` 检出规则,重新规范化 Windows 工作树,并增加 Windows/Linux 字节合同测试;未重建语义未变的 golden。
2. 生成当前模型的组件类型、槽位、阶段、副作用和事件能力矩阵。
3. 将 schema v2 写成独立规范,先冻结 RHS 阶段、错误、事务、事件和结构签名。
4. 建立对象引擎与扁平 IR 的逐阶段 Shadow runner。
5. 用一条完整机械—气动—管路—接触支路完成 Python 参考闭环。
6. 评审通过后,再建立最小 C ABI 和纵向切片。
第一批的退出条件不是“已经写了多少 C”,而是:当前基准可信、同一计算能被无回调 IR 完整表达、差异能定位到具体阶段和槽位。只有达到这个条件,后续 C 工作才具有可预测的收益和可控的回滚成本。