优化雅可比矩阵计算;端口转发情况下仿真结果传输方式优化

This commit is contained in:
lujingze committed 2026-09-12 03:57:31 +00:00
1 parent 3bc4be3c06
commit aa4951b14e
28 files changed
+8038 -23

No files matched your search

@@ -0,0 +1,322 @@
# 雅可比结构着色试验与八路验证
日期:2026-09-11。基线:已提交并推送的 `3bc4be3c061898d130be9b2b3cd633e9573acf04`(原生结果编码、传输与浏览器缓存优化)。
> 后续状态更新:用户已确认接受本文披露的误差,结构着色差分现已转为正式默认,旧策略选择器已经删除。下文保留启用前的试验结论、命令与数据,其“默认 dense / 显式启用”描述仅对应试验阶段。当前运行方式与正式网页核验见 [正式启用报告](雅可比算法正式启用与网页验收-2026-09-11.md)。
**交付定位:可运行的试验版,默认继续使用 CVODE 原有逐列稠密差分。** 当前八路试验显著减少了构造雅可比所需的系统求值,但较严格积分结果的交叉比较仍发现温度局部误差略增,因此不能宣称已经通过等精度替换验收。CLI 和独立预览服务可显式启用着色模式;模型文件及通常网页/API 默认行为保持原有 `dense` 策略。
**正式结果:** 八路原生求解中位 5.7915 → 2.4926 s;网页点击到结果可查看 7.0185 → 3.4556 s,浏览器保存 7.1597 → 3.5793 s。16 次网页/CSV/恢复核对通过。相对严格数值参考的最大温度误差 0.0468 → 0.0543 K,试验版保留显式启用。
## 1. 固定案例与优化对象
主案例为 `tests/data/test-mql-8-corrected.json`,SHA-256 为 `670977bef67e62d9c66e8af497bada208bd72a7301be45128d185d47282cf288`。使用 SUNDIALS 7.4.0 的 CVODE/BDF,时间范围 0–10 s,输出间隔 0.01 s,`rtol=1e-8`、`maxStep=1e30`。状态绝对容差沿用现有按物理量设置的向量:质量 `1e-14 kg`、能量 `1e-8 J`、机械位置和速度 `1e-12`(各自单位)。这些配置、密集矩阵存储、Dense LU、物理方程和管流局部求根均未因本试验调整。
本轮只优化系统雅可比 `J=∂f/∂y` 的差分构造。基线八路有 132 个状态;一次默认雅可比构造需要逐列扰动 132 次,每次都求值整个系统 RHS。初测基线的 475 次雅可比构造产生 `475×132=62,700` 次线性求解器差分 RHS,占 `nfev=74,265` 的大部分。**这是调用次数占比,不是 CPU 时间占比。**
本轮仍把完整矩阵交给原来的 Dense LU。结构稀疏性在这里用于合并互不影响的差分扰动,尚未引入稀疏矩阵分解或更换积分方法。
## 2. 官方默认算法与保留内容
CVODE/BDF 每步通过非线性迭代求解离散方程,Newton 线性系统使用近似矩阵 `M=I−γJ`。提供自定义 `CVLsJacFn` 时,应返回 `J`,后续矩阵变换和线性求解仍由 CVODE 完成。本项目保留其矩阵更新、步长和误差控制流程。[SUNDIALS 7.4 数学说明](https://sundials.readthedocs.io/en/v7.4.0/cvode/Mathematics_link.html#nonlinear-solve)、[雅可比回调接口](https://sundials.readthedocs.io/en/v7.4.0/cvode/Usage/index.html#c.CVLsJacFn)
本地核对版本为 `sundials-7.4.0/src/cvode/cvode_ls.c` 的 `cvLsDenseDQJac`。设 `u=SUN_UNIT_ROUNDOFF`、当前误差权重为 `W`、步长为 `h`、状态维数为 `N`,默认前向差分使用:
```text
fnorm = WRMS(fy, W)
minInc = fnorm != 0 ? 1000 × |h| × u × N × fnorm : 1
inc[j] = max(sqrt(u) × |y[j]|, minInc / W[j])
J[i,j] = (1 / inc[j]) × (f_i(t, y + inc[j] e_j) − fy[i])
```
原始源码见 [SUNDIALS v7.4.0 cvode_ls.c](https://github.com/LLNL/sundials/blob/v7.4.0/src/cvode/cvode_ls.c)。候选通过公开接口获取实际 `W` 和 `h`,保留上述扰动公式、原 `inc[j]` 分母以及先求倒数再乘差值的浮点运算顺序,没有把分母改成浮点加法后实际得到的 `y_trial−y`。
当前运行时没有向 CVODE 设置 inequality constraints,因此默认差分中的约束翻转规则不触发。若未来添加 `CVodeSetConstraints`,必须同时向着色上下文传入约束并实现同一翻转规则;现有实现不能据此宣称已支持任意约束配置。
CVODE 非线性收敛系数的默认值为 `0.1`,它控制非线性迭代停止条件,并不等同于用户的 `rtol`。本轮生产代码没有调整该系数;隔离的 `0.01` 探索见后文。[官方非线性求解器选项](https://sundials.readthedocs.io/en/v7.4.0/cvode/Usage/index.html#c.CVodeSetNonlinConvCoef)
## 3. 从生成器获得保守结构
新增 [jacobian.py](../../app/simulation/native_codegen/jacobian.py),由生成器显式记录当前状态到每个导数的依赖,再计算闭包、列冲突和着色。它处理生成器控制的表达式与既有计算条目,不尝试解析任意外部 C 程序。
| 模型 | 状态数 | 保守结构非零数 | 结构密度 | 颜色数 | 路径 |
| --- | ---: | ---: | ---: | ---: | --- |
| 八路 corrected | 132 | 952 | 5.464% | 27 | 可显式启用着色 |
| 四路 corrected | 64 | 468 | 11.426% | 15 | 可显式启用着色 |
| 紧凑 native-skill fixture | 12 | 144 | 100% | 12 | 原默认逐列差分 |
这里的“非零”是结构上可能非零的位置,包含保守增加的依赖;不是某个采样状态下数值非零项的计数。八路结构哈希为 `a4761c4a71c30eef37f126ec85567ff25efd197728f7f7d1e0e124378a41127a`。构建清单记录结构、策略、颜色、是否具有运行时收益及回退原因,便于复核。
生成器将以下依赖纳入闭包:
- 储气物性对质量、内能、容积的依赖,以及移动气缸容积对机械位置的依赖。
- 管路、阀口等多输出调用的全部输入,压力和焓的传播,以及局部循环块对外部状态的依赖。
- 条件判断及各分支的依赖,覆盖正反流和零流量附近的切换。
- 接触/限位对位置、速度及原导数的联合依赖,以及耦合状态投影和导数重分配。
同一颜色中的任意两列不得作用于同一 RHS 行,因此可同时扰动这些列,再按结构位置分别提取导数。漏掉真实依赖会得到错误的雅可比,过度保守则增加颜色数。遇到无法解析的可达输入,整模型回退默认差分;紧凑路径和无合并收益的结构同样使用默认差分。C 启动时还检查 CSC 边界、行索引顺序、颜色范围和同色行冲突。
八路当前依赖排序包含 0 个循环块,没有耦合投影组。因此本案例的完整轨迹验证不能替代对新循环模型、新投影组合或新元件的验证。详见 [生成结构审计](../../test/jacobian-20260911/generation-audit.md) 和 [结构汇总](../../test/jacobian-20260911/generated-structure-summary.json)。
## 4. 共享物性缓存造成的差分伪耦合
直接在原 RHS 上应用 27 色分组的原型,在第 17 次雅可比核对中发现结构外非零项。追踪到的原因是气体状态准备时向共享物性缓存预先登记了已经求出的温度、焓和密度。后续相同参数查询可能取预登记值,也可能从另一条数学等价的物性表达式重新计算;两条路径存在舍入差异。另一支路的扰动改变缓存命中路径后,该差异被很小的差分增量放大,看起来像额外的跨支路依赖。
具体探针在 `t=5.5155845013992836e-05 s`:扰动列 80(`PNL0001_17.m`)时,行 69(`PNL0002_7.U`)的旧逐列差分出现约 `3918.1763` 的结构外导数。仅关闭气体预登记后,该探针项精确归零;关闭全部物性缓存的独立探针也得到零。这里证明的是所定位缓存路径的舍入耦合,不能把它解释为物理模型新增了支路连接。[探针结果](../../test/jacobian-20260911/cache-probe/summary.json)
正式候选采用专用于雅可比的 `model_eval_jacobian`,以下称 canonical RHS:
1. 普通 `model_eval` 继续使用原有气体物性预登记,积分 RHS 和结果输出保持原求值路径。
2. canonical RHS 仅关闭气体物性的预登记;以完整显式输入为键的其他物性缓存及管流缓存继续保留。缓存仍在每次系统求值内重新建立,不跨扰动状态复用。
3. 每次雅可比回调先用 CVODE 传入的普通 `fy` 计算默认差分增量,再额外调用一次 canonical RHS 重算基准值。所有分组扰动、逐列验证和回退都减去这个 canonical 基准。
第三步不可省略。若用 canonical 扰动结果减去普通 `fy`,两条求值路径的舍入差异仍会被 `1/inc[j]` 放大。新增 `MODEL_JACOBIAN_CANONICAL_RHS` 宏明确这一策略;未启用该路径的模型不额外计算基准 RHS。
这使候选成为**同一数学函数、固定缓存求值路径上的差分近似**。它不再承诺与旧共享缓存路径的全部逐列差分项一致。普通 RHS 不变、雅可比近似改变,也会改变 Newton 迭代、步长接受和最终轨迹;两者必须分别验证。
## 5. 回退、取消与计数
实现位于 [cvode_solver.c](../../native/runtime/cvode_solver.c) 和 [common.c](../../native/runtime/common.c)。
| 情况 | 行为 |
| --- | --- |
| 模型结构不支持、无着色收益,或显式 `dense` | 不安装自定义回调,使用原 CVODE 默认逐列差分 |
| 合并扰动得到可恢复的 RHS 失败 | 从原状态重新逐列计算完整 canonical 矩阵 |
| 单列扰动或基准 RHS 仍可恢复失败 | 向 CVODE 返回失败,交由其恢复流程处理 |
| 取消、超时等不可恢复退出 | 立即返回,不因回退继续增加求值 |
| `verify` 检出任意矩阵项失配 | 使用当次完整 canonical 逐列矩阵,并在本次运行后续及事件重启后关闭分组 |
`verify` 每次比较全部 `132×132=17,424` 项,包括结构外零项;不是采样子矩阵。实现采用 C 数值精确比较 `!=`,没有设置误差阈值,但不会区分 `+0` 与 `−0`。因此“矩阵零失配”应按此口径理解,不能自动写成带符号零也逐位一致。
结果新增 `jacobianMode`、`jacobianRhsCalls`、`jacobianColoredEvals`、`jacobianFallbacks`、`jacobianChecks`、`jacobianMismatches`、`cvodeRhsCalls` 和 `cvodeLinearRhsCalls`。总计数关系为:
```text
nfev = cvodeRhsCalls + cvodeLinearRhsCalls + jacobianRhsCalls
```
自定义回调中的 RHS 由项目自行计入 `jacobianRhsCalls`,其中包括 canonical 基准、验证和失败尝试。SUNDIALS 的 `CVodeGetNumLinRhsEvals` 只统计其内部默认差分调用,不会代记用户回调的 RHS。[官方计数接口](https://sundials.readthedocs.io/en/v7.4.0/cvode/Usage/index.html#c.CVodeGetNumLinRhsEvals) 各 CVODE 实例/重启区间释放前累计库计数,项目计数直接跨区间累加,不能把这些包含关系重复相加。
回归中还发现了独立的取消竞态:准备阶段已经收到取消请求时,快速原生进程可能在 Python 监控首次轮询前完成。[runner.py](../../app/simulation/native_codegen/runner.py) 现于启动进程前检查取消标记并提前写出取消文件,保留部分接受状态及公共任务状态合同。该修复没有改变数值公式。
## 6. 已完成验证及其覆盖范围
### 6.1 默认公式的独立校验
[test_native_jacobian_runtime.py](../../tests/test_native_jacobian_runtime.py) 的 8 项小型 C harness 测试已通过。测试直接调用本地 SUNDIALS 7.4.0 库的 `cvLsDenseDQJac` 作为独立默认算法 oracle;私有头文件仅用于测试,不进入生产编译依赖。
覆盖 25 组状态、权重和步长组合,包括零 RHS 范数、正负步长、异量级分量,以及“实际舍入后的扰动不等于原增量”的情形。未启用 canonical 路径的矩阵与实际库默认差分按位比较。另覆盖结构边界、合并扰动失败后的完整回退、逐列失败、取消、失配后跨重启禁用分组和多段事件计数。
canonical 专项故意令普通 `fy` 与 canonical 基准不同,证明:增量仍来自普通 `fy`,差分基准确实重新求值,普通输入向量未被改写,所有基准/探针调用均进入计数。该专项不把 canonical 矩阵冒称为旧缓存默认矩阵。
### 6.2 结构与普通 RHS 保持
[test_native_jacobian_structure.py](../../tests/test_native_jacobian_structure.py) 已完成 8 项结构测试,覆盖 50 个冻结目录组合的结构、未知输入关闭优化、循环闭包、投影与限位、紧凑路径回退,以及固定八路状态的完整 canonical 矩阵比较。
另以旧保留共享库和候选程序比较同一时间点的 5 组固定状态,每组检查 132 个 RHS 值和 1,784 个输出值,共 9,580 个 binary64 数值,全部逐位一致。该证据支持普通求值路径保持,不是完整积分轨迹逐位相同的声明。[普通 RHS 位比较记录](../../test/jacobian-20260911/ordinary-rhs-bit-parity.json)
### 6.3 完整八路初测
下表为 `canonical-jac-smoke` 中 0–10 s 的单次运行,所有模式均正常完成。它用于记录调用关系和验证行为,**不是正式性能验收中位数**。
| 指标 | 默认 dense | 候选 auto | 诊断 verify |
| --- | ---: | ---: | ---: |
| 求解墙钟时间 / s | 6.049942 | 2.575630 | 9.236601 |
| `nfev` | 74,265 | 22,853 | 80,009 |
| `cvodeRhsCalls` | 11,565 | 10,729 | 10,729 |
| `cvodeLinearRhsCalls` | 62,700 | 0 | 0 |
| `jacobianRhsCalls` | 0 | 12,124 | 69,280 |
| `njev` | 475 | 433 | 433 |
| 接受步数 | 6,974 | 6,660 | 6,660 |
| 拒绝步数 | 454 | 359 | 359 |
| `nlu` | 1,656 | 1,404 | 1,404 |
| 状态转换 / solver starts | 1 / 4 | 1 / 4 | 1 / 4 |
| 分组核对次数 / 失配 | 不适用 | 未启用核对 | 433 / 0 |
| 分组回退次数 | 0 | 0 | 0 |
候选的 `12,124=433×(27+1)`,其中每次额外的 1 是 canonical 基准。诊断的 `69,280=433×(27+1+132)`,每次还计算完整逐列矩阵。`verify` 的额外工作不应混入生产候选性能。
433 次雅可比的全矩阵核对均无失配,支持该完整轨迹上分组计算与 canonical 逐列计算一致;两种模式的输出/最终状态比较也一致。默认 dense 与候选的 `njev` 和接受步数已经变化,说明不能把总调用下降全部归因于固定次数的 `132→27` 替换,更不能要求候选轨迹和基线逐位相同。
证据目录:[完整八路初测](../../test/jacobian-20260911/canonical-jac-smoke/),[初始轨迹差异](../../test/jacobian-20260911/canonical-jac-smoke/initial-differences.json)。
### 6.4 回归与取消专项
首轮后端回归记录为 40 项、39 通过、1 项取消状态竞态失败;不能把该原始日志写成全部通过。修复预启动取消后,原生部分结果、raw stream 取消和任务 stop 的 3 项专项复测通过。[首轮日志](../../test/jacobian-20260911/regression.log)、[取消专项复测](../../test/jacobian-20260911/cancellation-regression.log)
随后在最终默认 `dense` / 环境开关代码上重跑完整 6 项结果传输测试和 2 项原生/任务停止测试,8 项均通过(7.037 s)。命令与 [最终日志](../../test/jacobian-20260911/transport-final.log):
```sh
.venv/bin/python -m unittest tests.test_native_result_transport tests.test_native_codegen.NativeExecutionTests.test_cancellation_returns_partial_accepted_state tests.test_generic_system_xml_simulation.GenericSystemXmlSimulationTests.test_streaming_task_stop_returns_partial_result -v
```
首轮通过的 39 项包括默认 `dense` 的四路 72 条 AME 曲线回归,沿用压力 250 Pa、温度 0.015 K、位移 2e-6 m、速度 1e-5 m/s、质量流量 3e-5 kg/s 的原门槛。本轮没有扩大门槛;这不能代替八路试验版的外部曲线验收。修复后只复测受影响的传输/取消路径,没有重复无关的完整求解。
## 7. 精度边界与保留默认 dense 的原因
雅可比逐项核对验证的是差分合并是否正确,不是积分全局误差。相同 `rtol` 控制局部误差,并不要求不同雅可比近似产生相同接受步、事件插值或整个轨迹。[CVODE 容差选择说明](https://sundials.readthedocs.io/en/v7.4.0/cvode/Usage/index.html#tolerance-selection)
以 `dense, rtol=1e-10` 的较严格结果为数值参考,初步交叉比较发现:默认 `dense, rtol=1e-8` 的最大温差约 `0.046797 K`,候选 `auto, rtol=1e-8` 约 `0.054348 K`。压力及多数机械状态指标改善,温度局部指标略退。更严格容差的交叉比较支持收敛趋势,但这一参考本身仍是数值解,不能当作解析真值,也不足以把候选称为等精度替换。
为检查非线性停止条件的影响,另做了 `NonlinConvCoef=0.01` 的隔离原型。该次运行约 `7.905 s`、1,907 次雅可比构造,明显增加工作量;没有纳入生产代码,也没有与普通候选正式性能混合。现有生产仍沿用默认系数 `0.1`。
以下比较全部 1,784 条输出的 1,001 个精确共同普通采样时间,不跨事件插值;额外事件点单列。各组为相同容差下 `dense` 与 `auto` 的最大绝对差:
| 量 | `rtol=1e-8` | `1e-9` | `1e-10` |
| --- | ---: | ---: | ---: |
| 压力 / Pa | 19.32135 | 1.42791 | 0.059363 |
| 温度 / K | 0.0228371 | 0.00130767 | 0.000245508 |
| 气体质量 / kg | 1.26604e-8 | 1.07764e-9 | 2.53289e-11 |
| 气体内能 / J | 0.0194956 | 0.000800470 | 2.97881e-5 |
| 限位机械 1~8/10 速度 / m/s | 3.84792e-8 | 2.31905e-9 | 5.56235e-10 |
| 限位机械 1~8/10 位移 / m | 3.84793e-8 | 1.52101e-9 | 1.36450e-10 |
| 事件时间 / s | 8.86875e-9 | 4.34638e-10 | 4.89192e-11 |
| 极端机械 9 位移 / m | 48,794,961 | 156 | 118 |
相对 `dense, 1e-10` 的参考,旧/新默认温度组最大误差为 **0.0467973 → 0.0543480 K(+16.13%)**,汇总 RMS 为 **0.0111825 → 0.0131265 K(+17.39%)**。56 条唯一温度曲线中有 15 条的最大误差和 RMS 同时增加。`PNL0002_4/8.T` 在 0.06 s 附近参考约 4368.8398 K,最大误差从约 0.040975 K 增到 0.054348 K。两份 `1e-10` 参考之间最大温差仅 0.000245508 K,该退化不能用参考策略之间的小差异消除。
相对同一参考,压力组最大误差 91.2276 → 87.2302 Pa,质量/内能整体指标、限位机械 1~8/10 的全部 9 条速度和 9 条位移曲线均改善。整体改善仍不代表每条压力或能量曲线都改善。上述局部容差只用于诊断,不被解释成轨迹全局误差上界。
事件与异常保留如下:
- 六份结果均有 1 次状态跳变、4 次求解器启动。旧/新默认额外事件时间为 0.9833956321732664 / 0.9833956233045202 s;机械 10 到达 0.37 m 后速度清零。事件峰力约 4.035e11 N,前后差约 2345 N(相对 5.81e-9),没有用普通采样点掩盖该窄峰。
- 56 个唯一气体质量状态使用 `math.fsum` 累加;六份全采样总质量最大漂移为 7.99e-15~2.31e-14 kg。守恒不能替代每条曲线的精度检查。
- 机械 9 的原模型含 `UD00=1e17` 极端信号,位移可达约 7.68e15 m。默认前后 4.8795e7 m 的最大位移差相对约 1.09e-8,直接来自连续状态,不能归为辅助输出舍入;这类巨大绝对数值和 AME 差异在 [此前八路核查](test-mql-8当前AME归档与完整曲线核查-2026-09-11.md) 已存在。两份紧容差参考之间机械 9 速度仍可差 26.25 m/s,暂不对其精度排序。
- 近零流的摩擦因子和节点返回焓仍敏感。`PNL00R_5` 的流量在 3.41 s 从约 -6.09e-6 变为 -1.93e-22 kg/s,摩擦因子从约 2.26 变为 6.4e7;`P4NODE2_6.port_2` 在 5.82 s 流量跨过零和混合正则化阈值,返回焓差约 1.4e8 J/kg。两份 `1e-10` 之间返回焓最大差仍约 1.91e7 J/kg,不能把全部辅助输出判为已充分收敛。
完整逐曲线、极值时刻、总质量、事件和最终状态记录见 [轨迹与收敛审阅](../../test/jacobian-20260911/convergence-review.md)、[可复现汇总](../../test/jacobian-20260911/convergence/convergence-summary.json);使用 [compare_jacobian_trajectories.py](../../tests/manual/compare_jacobian_trajectories.py) 保留来源 SHA 和每条输出差异。
本轮据此作为显式启用的试验功能交付,默认继续 `dense`。对新元件、新结构和不同工况,结构声明仍需独立审查;`auto` 并不会在每次运行中自动做完整逐列核对,只有 `verify` 提供该诊断。
本报告不构成八路 AMESim 物理验收。较严格 native 数值结果、canonical 矩阵 oracle、普通 RHS 位比较和外部 AMESim 曲线分别回答不同问题;既有四路 AMESim 回归门槛也不能直接作为八路已验收的证据。
## 8. 使用方式
原生程序默认等同 `--jacobian dense`。下面的 `path/to/model` 替换为本轮生成的八路可执行文件;显式参数避免混用原生 CLI 的其他默认值。
```sh
path/to/model --method BDF --start 0 --stop 10 --sample-step 0.01 --max-step 1e30 --rtol 1e-8 --jacobian dense --output dense.json
path/to/model --method BDF --start 0 --stop 10 --sample-step 0.01 --max-step 1e30 --rtol 1e-8 --jacobian auto --output auto.json
path/to/model --method BDF --start 0 --stop 10 --sample-step 0.01 --max-step 1e30 --rtol 1e-8 --jacobian verify --output verify.json
```
`dense` 保留原默认差分;`auto` 在结构受支持且有收益时启用分组,否则回退默认差分;`verify` 在支持分组时额外逐次核对完整 canonical 矩阵。RK45 不使用这些雅可比路径,结果标记为 `not-used`。
Python runner 接受环境变量 `SIMULATION_NATIVE_JACOBIAN=dense|auto|verify`,默认 `dense`。独立预览服务启动前设置 `auto` 即可试用;该设置作用于该服务进程,不写入模型 JSON。环境变量值非法会报错,不能静默猜测模式。
## 9. 正式原生与网页对照
原生正式对照由 [benchmark_native_jacobian.py](../../tests/manual/benchmark_native_jacobian.py) 在同一可执行文件上显式切换 `dense/auto`,每组 1 次预热 + 3 次正式运行,配对顺序交替且全部串行。`verify` 单独运行,不进入速度统计。Linux x86_64、GCC 13.3、SUNDIALS 7.4.0,模型、容差、编译浮点选项及输出不变。
```sh
.venv/bin/python tests/manual/benchmark_native_jacobian.py --input tests/data/test-mql-8-corrected.json --output-dir test/jacobian-20260911/benchmark --warmups 1 --repeats 3 --verify --record-differences --run
```
构建键 `9f38485cdedb422c74226311dfdd3838036f39bc9e238b4358e46275a1bedab4`,首次构建单次 3.903 s。完整命令、来源 SHA、配置和计数保存在 [正式原生 summary](../../test/jacobian-20260911/benchmark/summary.json)。最后只补充 manifest 中默认 `dense` / 显式启用的说明字段,八路与 compact 的 `model.c/h` 前后 SHA 完全一致;[检查记录](../../test/jacobian-20260911/default-policy-metadata-check.json) 解释了说明字段改变可能造成的缓存键更新。
`--record-differences` 的含义是保留不等价结果并完成计时,**不是放宽验收**。本次 `complete=true`、`passed=false`、`allPayloadBitsEqual=false`:后两者如实记录 `dense/auto` 轨迹及事件时间不同。相同模式重复运行保持数值结果一致;`auto/verify` 的完整输出和最终状态一致,433 次矩阵核对零失配。第 7 节单独评估这些差异。
| 正式原生指标 / s | dense 中位 | auto 中位 | 两组中位数之比:减少 |
| --- | ---: | ---: | ---: |
| C 求解墙钟 | 5.791500 | 2.492559 | 56.96% |
| C 求解 CPU | 5.790168 | 2.481718 | 57.14% |
| 子进程完整墙钟(含结果写出) | 6.091389 | 2.827177 | 53.59% |
三次求解墙钟逐对降幅为 56.80%、57.12%、56.96%,其中位数 56.96%;上表使用组中位数之比。完整进程逐对降幅中位为 53.88%,与组中位数之比 53.59% 的口径不同。正式计数与第 6.3 节一致:RHS 总数 74,265 → 22,853(-69.23%),雅可比差分 RHS 62,700 → 12,124(-80.66%),`njev` 475 → 433,接受步 6,974 → 6,660,误差检验拒绝步 454 → 359。
### 9.1 正式网页端到端
基线网页服务使用 `git archive 3bc4be3` 冻结的后端源码,候选服务显式启用 `auto`。同一份生产 `frontend/dist` 分别复制后提供服务,实际加载的主线程及 worker 资源集合 SHA 均为 `f089bfc67e38ab5a4a0f7649d94f711642d4ab08b690be50b8ef075d8422a1c2`。两版各运行一组 control 和一组 profiled;每组 1 次预热 + 3 次正式,16 次全部串行,未与其他求解/大结果分析并行。测试使用真实 Chromium 和真实 HTTP,并完成模型导入、运行、查看曲线、保存、下载 CSV/结果文件及刷新恢复。
每次导入后通过公开导出检查元件、参数、端口连接。浏览器及 CLI 的 XML 字节序列化不同;9 份 XML 经同一生成器得到完全相同的 C 源码和头文件,[核对记录](../../test/jacobian-20260911/xml-generated-program-parity.json)。未把不同 XML SHA 冒称为相同字节,也未为提速改变模型。
以下为**未插桩 control** 三次中位;范围保存在便携摘要中。
| 用户过程 | 基线 / s | 试验 / s | 变化 |
| --- | ---: | ---: | ---: |
| 点击运行 → 结果可查看(就绪 DOM) | 7.0185 | 3.4556 | 减少 50.76% |
| 点击运行 → 就绪后绘制机会(两帧) | 7.0800 | 3.4692 | 减少 51.00% |
| 点击运行 → 浏览器保存完成(观察值) | 7.1597 | 3.5793 | 减少 50.01% |
| 点击 CSV → 下载保存完成 | 1.0173 | 1.1193 | 增加 10.03% |
| 点击结果文件 → 下载保存完成 | 1.3590 | 1.2876 | 减少 5.25% |
| 刷新 → 已保存结果 DOM 可见 | 0.2721 | 0.2673 | 接近 |
![原生与网页正式中位数](assets/2026-09-11/jacobian-time-comparison.svg)
CSV 的三次范围为旧 0.9066~1.2685 s、新 1.0386~1.2845 s,重叠明显;本轮未修改前端,不能把这一小样本差异解释成稳定的导出退化或优化。它独立于本轮求解速度收益,不宣称改善。浏览器“保存完成”指 IndexedDB 持久化的提交及指针可见;control 通过最多约 16 ms 间隔轮询观察,另有调度延迟。CSV/结果文件下载完成包含浏览器通知与自动化 `saveAs` 的本地文件成本。两帧是绘制机会,不是 GPU 完成证明。
**冷编译单列:** control 首轮基线编译 3.8785 s、点击到可查看 10.9099 s;候选编译 3.9581 s、点击到可查看 7.4655 s。每种只有一次,不是冷启动中位数;正式三轮全部缓存命中。候选额外生成保守结构,在已命中缓存的 profiled 请求中 C 生成中位从约 62.8 增至 93.0 ms,已算入端到端结果。
### 9.2 前后端阶段
下面来自独立 profiled 组,用于定位成本。各时间存在嵌套或异步重叠,不能相加;这些组的绝对耗时不替代 9.1 的 control。插桩组就绪时间相对 control 的组中位差为基线 -2.02%、候选 +2.36%,同时含组间调度和缓存波动,不能视为纯插桩开销。
| 阶段 / ms | 基线中位 | 试验中位 |
| --- | ---: | ---: |
| 点击到发起请求(校验/快照/XML 等) | 18.800 | 22.100 |
| 结果 JSON.parse | 108.700 | 103.400 |
| 流式 TextDecoder 同步工作 | 30.600 | 28.000 |
| parse 结束到结果就绪 DOM(含调度) | 56.700 | 38.500 |
| 结果页签到 DOM 可见 | 119.500 | 126.400 |
| 曲线选择到 DOM 可见 | 21.200 | 19.600 |
| CSV 点击到下载锚点 | 487.100 | 506.600 |
| CSV worker 启动到完成消息(含重叠工作) | 459.700 | 476.700 |
就绪 DOM 后到 IndexedDB 全部提交的逐次差值中位为 98.7 → 107.7 ms,仍含异步调度,不能当作纯存储 CPU。
| 阶段 / ms | 基线中位 | 试验中位 |
| --- | ---: | ---: |
| XML 校验 | 23.138 | 22.740 |
| 网络编译 | 40.268 | 38.930 |
| C 生成与结构分析 | 62.825 | 92.987 |
| 编译缓存校验(命中) | 34.641 | 34.772 |
| C 积分 | 6022.966 | 2662.376 |
| C 输出投影 | 80.622 | 80.972 |
| C 编码与写出 | 166.097 | 167.640 |
| Python 索引结果读取(含原始字节) | 41.523 | 45.054 |
| 其中小型元数据 JSON.parse | 1.155 | 1.342 |
| 响应 JSON 元数据编码/拼装 | 32.837 | 24.171 |
| ASGI send 等待窗口(非纯网络) | 48.446 | 53.691 |
| 整个后端 HTTP 请求 | 6582.457 | 3293.631 |
候选 C 输出投影 CPU 中位 0.080972 s、编码写出 CPU 0.167599 s,与对应墙钟接近。HTTP 读等待包含后端生成、传输和浏览器调度,不将其整体归为网络;解析后的 DOM 等待也不整体归为绘图。Ryu/批量写出、原始数值片段直传、Float64 保存和 worker CSV 均沿用已同步基线;本轮主要减少积分等待。
### 9.3 完整数值传输核对及复现
计时结束后再解析大结果。旧网页两组共 8 次与正式 native `dense` 比较,新网页两组 8 次与 native `auto` 比较:每次 1,002 点、1,784 条输出、1,788,570 个含时间列的 series/CSV 数值及 1,784 个 final 值全部一致。总计核对 **28,617,120 个 CSV 单元**;每组刷新恢复后的完整结果保持不变。旧版网页对新代码 `dense` 的一致性,还独立支持默认路径没有改变。比较使用解析数字 `==`,不区分正负零;它不是旧版与试验版轨迹相等的声明。[旧组核对](../../test/jacobian-20260911/equality-baseline.json)、[新组核对](../../test/jacobian-20260911/equality-optimized.json)
轻量结果随文档保留在 [便携成本摘要](assets/2026-09-11/jacobian-cost-summary.json),包含 n/min/median/max、缓存状态、来源 SHA 和关键计数。完整细节在 Git 忽略的 [cost-summary.json](../../test/jacobian-20260911/cost-summary.json),由 [summarize_jacobian_cost.py](../../tests/manual/summarize_jacobian_cost.py) 只读取小型 metadata 重建:
```sh
.venv/bin/python tests/manual/summarize_jacobian_cost.py --root test/jacobian-20260911
```
网页原始目录为 `test/jacobian-20260911/browser-{baseline,optimized,baseline-profiled,optimized-profiled}/`。每个 profiled 请求按 `simulationId` 关联后端 `requests/<id>/stages.json`,保存实际命令、C 分阶段时钟及 ASGI 时序,避免错配不同运行。
## 10. 新版积分成本与后续优化
使用同一正式原生缓存和相同运行参数,在隔离源码副本中加嵌套时钟;control 和 profiled 各预热 1 次、正式 3 次,串行配对。8 次运行的完整 `series/final/finalState` 和求解计数精确相等(仅排除两个求解计时字段)。计数核对同时包含项目自计的 canonical RHS,不把它遗漏在 CVODE 库的计数之外。[诊断记录](../../test/jacobian-20260911/native-compute-profile/summary.json)
| 新版积分阶段 | 排他墙钟中位 / s |
| --- | ---: |
| 系统 RHS 求值 | 2.161145 |
| Dense 矩阵分解 | 0.153113 |
| Dense 线性回代 | 0.102039 |
| CVODE 其余内部工作 | 0.050597 |
| 雅可比分组/填充自身(扣除 RHS/轮询) | 0.007622 |
| 轮询 | 0.002934 |
| 积分外层、接受处理、采样与插值 | 分别约 0.001549 / 0.001366 / 0.000783 / 0.000280 |
RHS 约占同次积分的 87%;完整雅可比回调含 RHS 的中位时间 1.326561 s,约 53%;二者嵌套,不能相加。矩阵分解与回代约占 10%。正式控制组中位 2.438663 s,插桩组 2.481265 s,两组中位数之比开销约 1.75%;这些诊断时间不代替前述无插桩基准。表中的各列中位数也不应相加冒充某次运行总数。
CVODE 常规 RHS 10,729、非线性迭代 10,721、非线性收敛失败 365。此前基线为 11,565 / 11,557 / 414,收敛失败减少约 11.84%;这不是管路局部求根耗尽迭代的次数,也不能把误差检验拒绝步 359 混称为同一指标。本轮管流局部算法没有改动,未重新记录其逐次迭代直方图。
下一步先处理两项:一是稳定近零流和共享物性求值路径带来的导数/精度敏感性,给八路建立明确的全局曲线精度目标;二是在可靠依赖结构上尝试组件局部导数、局部扰动求值或部分解析雅可比,减少仍占约一半积分成本的雅可比构造。单独替换稀疏 LU 的收益受到当前约 10% 代数占比的限制,不能根据矩阵稀疏率直接预测总加速。
## 11. 交付状态
先前结果处理优化及报告已提交并推送到 `origin/system-optimization`,提交 `3bc4be3`。本轮雅可比试验代码、测试和报告保留为该基线之上的本地改动,默认仍为 `dense`;独立试验预览为 `http://127.0.0.1:8030`,其服务显式设置 `SIMULATION_NATIVE_JACOBIAN=auto`。若重启该服务,请沿用第 8 节的环境设置。
没有新增运行依赖。现有 Python 和 SUNDIALS 位于 `.venv/` 与 `.venv/native/`,浏览器辅助环境位于忽略的 `.tools/` / `.venv/native/`;所有大结果、下载、缓存、冻结基线和临时原型保存在 Git 忽略的 `test/jacobian-20260911/`。源代码、轻量回归 fixture 和文档可审阅,环境及大结果未上传。
该版本完成八路运行、性能测量、矩阵构造验证与端到端结果处理核对;温度局部误差退化和近零辅助量敏感性仍公开保留,不标记为等精度生产默认替换或八路 AMESim 曲线验收。没有可比较的可信 AMESim 运行耗时,外部速度对比继续跳过。