前端进度条性能优化、仿真结束后后处理优化;后端C代码生成流程优化:先识别来源,再按照已知未知量需求排序,最后局部求解

This commit is contained in:
ljz committed 2026-09-11 11:27:54 +08:00
1 parent 0dcb465d84
commit 91bd9fb252
77 files changed
+11223 -551

No files matched your search

@@ -0,0 +1,135 @@
# Amesim 与 C 计算顺序差异核查
日期:2026-09-10。分支:`system-optimization`;核查时提交:`0dcb465`。
本次对照当前 `tests/data/test-mql-8.json`、Amesim 2404 的生成代码和本机组件源码,并在 `test/amesim-order-study/` 中进行独立实验。正式模型、C 生成器、数值内核、积分器和雅可比策略均未修改。
## 结论与先前判断的修正
1. **这个 JSON 没有执行节点压力二分循环。** 实际编译得到 48 个压力组、48 个储气状态压力锚点,待求节点压力为 0。此前从通用生成器看到的“256 轮压力协调 × 每节点 48 次二分”分支不适用于本例。
2. **四通节点的参考口连接语义与 Amesim 存在偏差。** 8 个四通节点中只有 1 个直接接到相应储气状态端,另外 7 个的参考口接法不同,其中 3 个会引入流量与比焓的相互依赖。单纯把这些循环算快,不能解决与 Amesim 模型语义不一致的问题。
3. **当前生成器缺少热力变量的依赖排序。** 即使参考口修正,原生成器仍然运行全网流量/焓传播循环。实验中可以在编译时排好顺序,将全网流量计算降至每次状态求值 1 次,并移除该副本的全网焓迭代。
4. **管道内部的数值迭代是另一层问题。** 诊断中常见的是 PNL0001/2 流量函数的 16 次迭代耗尽;全网焓迭代并未耗尽上限。
## Amesim 为什么可以顺序计算
生成文件 `F:/CO2Project/Amesim/test_maql/test_mql_.c` 声明 132 个显式状态,声明隐式状态和生成隐式状态均为 0。文件第 10427 行说明部件按照满足输入依赖的顺序调用;三通、四通节点没有运行时计算函数调用,它们通过变量复用和加法展开。
其气动部件主要交换两类量:
- 储气部件提供当前压力、温度;管道和阀门据此计算质量流率、能量流率。
- 节点从参考口取得压力、温度并传给其他端口,把其他端口的质量流率和能量流率相加后送回参考口。
PN3NODE2/P4NODE2 的参考口是 **port 2**。这是一项固定的计算接口关系,与气体当时向哪个方向流动是两回事;交换参考口与其他口可能改变模型。
在该 Amesim 模型中,8 个四通节点的参考温度、压力全部直接复用 PNL0001 的储气状态。已将 `.var` 中的共享变量位置与生成代码 `GcontStateVarNum` 核对,确认对应项属于连续状态,而非仅根据图形位置推测。
| Amesim 节点 | 参考温度/压力所属管道 |
| --- | --- |
| pnnode4_16 | pneumatic_69 的 t2/p2 |
| pnnode4_17 | pneumatic_68 的 t2/p2 |
| pnnode4_18 | pneumatic_66 的 t2/p2 |
| pnnode4_19 | pneumatic_65 的 t2/p2 |
| pnnode4_20 | pneumatic_72 的 t2/p2 |
| pnnode4_21 | pneumatic_73 的 t2/p2 |
| pnnode4_22 | pneumatic_74 的 t2/p2 |
| pnnode4_23 | pneumatic_71 的 t2/p2 |
此时,温度/压力向支路传递,质量/能量流率向储气部件汇总,最后计算状态变化率。通过储气状态隔开了不同计算阶段,不需要先迭代求出所有连接量。
这里的显式系统仍可使用 BDF 等隐式积分方法;零系统隐式状态也不表示物性函数、管流函数或积分器内部绝无迭代。
## 当前 JSON 的具体偏差
当前网络有 156 个运行部件、178 条连接、132 个状态、1784 个输出、232 个气动端口。Amesim 部件与管线展开后,各数值组件类型数量与该 JSON 一致;数量一致不足以保证参考口关系一致。
| JSON 四通节点 | 当前 port_2 接到 | 独立实验中接到的对应储气端 |
| --- | --- | --- |
| amesim_p4node2_1 | amesim_pnl0001_13.port_2 | 原连接已满足 |
| amesim_p4node2_2 | amesim_pnvo001_2.port_2 | amesim_pnl0001_14.port_2 |
| amesim_p4node2_3 | amesim_pnvo001_3.port_2 | amesim_pnl0001_15.port_2 |
| amesim_p4node2_4 | amesim_pnvo001_4.port_2 | amesim_pnl0001_16.port_2 |
| amesim_p4node2_5 | amesim_pnl0001_21.port_1 | amesim_pnl0001_17.port_2 |
| amesim_p4node2_6 | amesim_pnl0001_25.port_1 | amesim_pnl0001_18.port_2 |
| amesim_p4node2_7 | amesim_pnl0001_26.port_1 | amesim_pnl0001_19.port_2 |
| amesim_p4node2_8 | amesim_pnl0001_27.port_1 | amesim_pnl0001_20.port_2 |
实验只在工程副本中交换后 7 个节点的 port_2/port_3 连线,让参考口连接到同一压力组中的储气状态端。物理支路数量、参数和动态状态没有增加。
对于 `_2/_3/_4`,当前 C 计算存在以下潜在反馈:
```text
阀门流量需要入口比焓
↓
入口比焓来自四通节点 port_2 的能量平衡
↓
该能量平衡又用到阀门流量
```
是否实际激活反馈还与流向有关。给低压侧供气时,阀门可使用另一侧已知比焓;反向流时则可能需要节点返回的比焓。本次反向流诊断使当前全网焓迭代从通常的 3 轮升至 10 轮。
编译时追踪显示:当前流量表达式读取 48 个端口比焓,其中 3 个无法仅由储气状态和简单赋值提前确定,正是 `_2/_3/_4.port_2`。调整参考口后的副本中,这 48 个输入全部可提前确定。
Python 元数据把这些气动端口都声明为 `bidirectional`。目前连接校验主要检查领域、端口占用和物理连接合同,没有针对该 Amesim 子模型检查“参考温度应由谁提供”的因果关系,因此能够接受这种与原 Amesim 接法不同的工程。
## 即使连接修正,为什么旧循环仍然存在
`extended.py` 先把无储气状态端口的比焓初始化为默认气体比焓,再按部件在网络中的顺序执行:
```text
计算全网流量 → 更新全部端口比焓 → 检查变化 → 必要时重复
```
它没有先区分:哪些比焓只需要复制已知状态,哪些流量依赖这些复制结果,哪些能量输出应在流量确定后再计算。全网焓循环结束后还额外计算一次全网流量。
在独立副本中,提前排序这些关系即可生成:
```text
恢复储气状态的物性
→ 传递流量计算所需的参考比焓
→ 计算一次全网流量
→ 按依赖顺序计算其余比焓和节点能量输出
→ 计算导数与展示输出
```
这说明质量/内能状态和比焓端口形式本身并不必然要求全网迭代。它们会增加局部物性反解的成本,但正确的连接和计算顺序仍可以消除本例的全网闭合循环。
## 独立实验结果
三个版本均为独立编译的 C 诊断程序:原模型及原生成器、仅调整参考口的模型及原生成器、调整参考口并按依赖顺序生成的模型。管道公式、误差阈值与物性函数保持相同。
使用初始状态、12 组质量/内能扰动状态,以及 1 组反向阀流状态,共 14 组。它们是用于检验依赖关系的状态点,不能作为完整 10 s 轨迹或 Amesim 曲线对齐的替代品。
| 每次状态求值的工作量 | 原模型 | 仅调整参考口 | 调整参考口并顺序计算 |
| --- | ---: | ---: | ---: |
| 常规诊断状态:全网焓循环 | 3 | 3 | 0 |
| 常规诊断状态:全网流量调用 | 4 | 4 | 1 |
| 反向流诊断:全网焓循环 | 10 | 3 | 0 |
| 反向流诊断:全网流量调用 | 11 | 4 | 1 |
后两个版本在全部 14 组状态的 **132 个导数与 1784 个输出上逐值完全一致**。这项对照隔离了计算顺序变化的影响。它没有比较“修正前后应该相同”:参考口修正确实会改变多个状态点的数值结果,必须按模型修正处理。
本次未进行新的 Amesim/EXE 全程速度或曲线比较。诊断文件中的单次微秒计时含计数开销,不能外推为完整仿真的加速倍数。
## 真正达到迭代上限的地方
本例生成的全网焓循环上限是 928 轮。本次 14 组状态中,原模型最多执行 10 轮,触顶次数为 0;节点压力二分没有生成。
在 12 组普通扰动状态中,每次原模型求值调用 PNL0001/2 支路流量 144 次,144 次均执行满内部 16 轮。顺序版本将该调用数降至 36 次,但这 36 次仍执行满 16 轮。当前函数耗尽循环后返回最后的近似流量,没有将其标记为不收敛错误。
PNL0003 两个储气状态之间的 Darcy 流量则使用固定 48 次二分。本例每次状态求值有 8 次此类管流计算,压力差非零时执行这些局部二分;这与“未知节点压力二分”不同。
因此,优化顺序应是:先对齐节点参考口语义并增加相应检查,再生成正确的静态计算顺序,随后单独检查管道内部的收敛判据和求根算法。管流近似对 BDF 数值差分和小步推进的影响仍需进一步量化;本次不对其贡献比例作结论。
## 证据与复现
- 结构快照和源文件哈希:`test/amesim-order-study/structure.json`。
- Amesim 状态索引与四通节点参考来源:`test/amesim-order-study/amesim-evidence.json`。
- 独立模型副本:`test/amesim-order-study/reference-port-experiment.json`;正式测试输入未覆盖。
- 14 组状态、计数和逐值差异:`probe-cases.json`、`probe-comparison.json`、`*-probes.jsonl`。
- 复现脚本:`.venv-win/Scripts/python.exe test/amesim-order-study/study.py`。
- 当前生成器:`app/simulation/native_codegen/extended.py:261`(物性)、`:362`(未知压力)、`:386`(焓传播)、`:409`(全网循环)。
- 当前管流:`native/components/kernels.c:246` 起;固定 48 次二分和 16/64 轮固定点迭代分别处理不同管流模型。
- Amesim 组件依据:`F:/amesim2404/amesim/libpn/submodels/PN3NODE2.c`、`P4NODE2.c`、`PNL0001.c`、`PNL0002.c`、`PNL0003.c`、`PNVO001.c`。
实验输出保存在 Git 忽略的 `/test/` 下。报告不复制 Siemens 组件实现;相关文件需使用本机已有 Amesim 安装读取。
@@ -0,0 +1,88 @@
# C 计算依赖排序验证(2026-09-10)
在 `system-optimization` 分支完成已知来源识别、依赖排序和局部循环划分,接入默认 C 编译入口使用的扩展生成路径。未修改管路内部求根、积分器、雅可比策略或用户模型接线。
## 本轮实现
| 原有处理 | 当前处理 |
| --- | --- |
| 对非储气端口先填默认焓,靠全网循环传递已知量 | 记录当前状态/已准备信号和物性的来源,参考量按依赖传递;初始猜测不作为已知来源 |
| 全网流量与端口焓反复更新 | 将流量、连接方程和焓传递拆为计算条目,按实际输入输出关系排序 |
| 一个未知量试算会刷新全网流量 | 自动划分局部循环;压力试算只刷新本块残差所需的关系 |
| 压力范围和焓初值使用全网信息 | 局部块使用自身已有压力边界和外部已知焓来源 |
图算法不依赖模型名称、组件实例顺序、画布方向或固定气体流向。节点参考别名与能量返回计算分离;常系数流量约束消元得到的表达式也参加排序。构建清单新增 `evaluationSchedule`,列出来源、计算条目和循环块,便于核查。
当前机械、信号、容积与气体物性准备阶段继续执行原有确定顺序;新图处理的是扩展生成器原先需要全网闭合的气动计算。紧凑储气拓扑原本已顺序计算,继续保留。没有恢复旧 Python 数值实现或旧 IR。
## 修正参考口模型
输入使用已有独立副本 `test/amesim-order-study/reference-port-experiment.json`。正式 `tests/data/test-mql-8.json` 和浏览器工程均未覆盖。对照 EXE 是上一轮已经包含管流精确输入缓存与粗糙度常量预计算的版本,因此本轮比较隔离了计算排序的影响。
- 132 个状态、1784 个输出;编译后形成 484 条气动计算关系,系统代数循环块为 0。
- 使用原有 14 组初始/扰动/反向状态,再逆序重访并重复前两组,共 30 次求值。两版全部成功,每次的全部导数与输出逐值一致。
- 独立插入执行计数后,30 次求值中每条计算关系均执行一次;计数不进入生产代码或计时版本。
### 相同时段的 BDF 对照
两版均使用 CVODE BDF、相对误差限 1e-7、最大积分步长 1e30 s。保持已有绝对误差策略,不绘图、不调用网页端。
| 指标 | 排序前 | 排序后 |
| --- | ---: | ---: |
| 完成的仿真时段 | 0~0.02 s | 0~0.02 s |
| 采样间隔 | 0.002 s | 0.002 s |
| 纯求解耗时(单次验证) | 2.368098 s | 1.645752 s |
| 求值次数 | 5123 | 5123 |
| 接受步数 | 169 | 169 |
| 拒绝步数 | 5 | 5 |
两版最终状态和完整采样序列逐值一致,单次耗时减少约 30.5%。这是相同时段的功能与耗时对照;当时另有回归验证任务运行,因此另用下述独立微基准检查提速幅度。
更短的 0~0.002 s 对照同样逐值一致,均为 304 次求值、25 个接受步和 1 个拒绝步。
### 独立 C 状态求值计时
使用同一批 14 组状态,在 C 内重复 200 次,共 2800 次系统求值;输入读取、进程启动、编译与输出写出不在计时内。两版各预热一次,交替计时 5 轮,取中位数:
| 排序前 | 排序后 | 加速倍数 |
| ---: | ---: | ---: |
| 1.686816 s | 1.156371 s | 1.459 |
计时版本不含诊断计数,校验和一致。这是状态求值的局部基准,不能直接代表任何模型的完整仿真倍数。
### 长时段验证的边界
尝试仿真到 10 s,每版限制执行 30 s:排序前推进到 0.0741618 s,排序后推进到 1.8645395 s,两版均返回执行超时。共同的 0、0.02、0.04、0.06 s 采样点逐值一致,但本轮没有取得完整 10 s 曲线对照。
另一次仿真终点为 0.06 s、采样间隔 0.002 s 的检查中,排序前在 30 s 限额内推进到 0.0487527 s,排序后用 25.022361 s 完成。共同的 25 个采样点逐值一致;将排序后该段全部 31 个采样状态分别送入两版 EXE,全部导数与输出也逐值一致。该次两版完成范围不同,不作为整段加速倍数。
上述不同采样/终点设置会影响积分运行,不能把两次计时直接混用,也不能用相同执行时间推进的仿真时长之比宣称提速。管流内部迭代及刚性积分的成本仍在,本轮未处理这两项。
## 通用性验证
- 2000 层逆序输入的依赖链正确排序并追溯到状态来源,不使用 Python 递归。
- 缺失来源、重复提供者、无来源的纯别名环均拒绝编译。
- 两个独立串联阻力压力循环与一个直算支路组合后,循环内各流量计算次数与独立运行相同;直算支路每次只执行一次。正反流及状态重访的结果均逐值一致。
- 打乱四通节点模型的组件和连接顺序后,仍无系统循环,各条目仅执行一次。常系数消元的求和顺序变化只产生浮点舍入级差异,使用远严于冻结基准的容差验证。
- 三支路的压力与混合焓耦合模型保留一个局部块;正反流、零压差与状态重访均通过质量/能量守恒检查。
- 现有 50 个冻结网络通过 C 数值对照;管流缓存、两种积分器、接口供需及编译入口的定向回归通过。
- `tests/data/native-skill-test.xml` 的 `skill-test` 回归完整完成 10 s,RK45 最大步长 0.001 s、rtol 1e-7,预热后单次纯求解 0.450283 s。它走原有紧凑路径,作为兼容性检查,不用于声称排序收益。
定向回归共 29 项通过。后端全量运行 276 项:首次 274 项通过、1 项锁定环境检查跳过、1 项因编译器版本查询返回空输出出错。重跑冻结网络时又有一次 EXE 初始化返回空输出;这两次均未触发数值不一致断言。受影响的网络 5 和 40 随后使用原冻结期望值单独复核通过。没有为此改动生产进程处理、冻结基准或数值容差;本次全量运行不能表述为一次全部通过,原始限制在此保留。
源文件与模型接入要求见 [C 求值排序规范](../standard/native-evaluation-schedule.md)。本轮条件表达式按所有可能分支保守记录依赖,尚未进行运行时流向特化;局部压力/焓求解保留既有方法,未宣称支持任意新非线性方程。
## 复现材料
`test/dependency-schedule-study/` 按仓库约定被 Git 忽略,包含:
- `baseline-build.json`、`scheduled-build.json`:两版 EXE 与构建清单。
- `schedule.json`、`model.c`:正式生成器输出的依赖清单与 C 源码。
- `verification.json`、`*-probes.jsonl`:30 次逐值验证。
- `benchmark.json`:5 轮交替计时及校验和。
- `integration-comparison*.json`、`bdf-*/result.json`:积分统计与原始序列,包括未完成的超时运行。
- `trajectory-probe-check.json`:长段共同采样及采样状态的求值对照。
- `skill-test/summary.json`:完整 `skill-test` 回归结果。
- `study.py`:`verify`、`benchmark`、`integrate`(0.002 s)、`short`(0.02 s)、`matched`(0.06 s)、`full`(10 s)模式;积分复现需选择新的输出目录,不能覆盖已有运行结果。
自动回归位于 `tests/test_native_schedule.py`,不依赖上述临时材料;纯依赖图测试已加入 Linux 合同检查,完整 C 执行测试由 Windows 数值回归自动发现。
@@ -0,0 +1,92 @@
**test-mql-4 仿真对照与耗时分析(2026-09-11)**
后续状态:本报告所述 C 修正已于 2026-09-11 合入正式网页后端,并完成重启及 HTTP 仿真核验,详见 [合入记录](../update-log/更新日志-2026-09-11.md)。以下正文保留合入前的实验过程与结论;其中“未合入正式内核”描述的是当时状态。
新增核查:后续直接查看网页 LSTP00A 接口力时,在额外保存的碰撞事件点发现约 1.50×10¹¹ N 的纳秒级瞬态峰。它不在本报告的 0.01 s 共同采样点对照范围内;不能把下面的曲线接近结论扩展为所有事件点输出一致。完整曲线、采样差异与内部步诊断见 [网页接口力对比报告](test-mql-4网页仿真与LSTP00A接口力对比-2026-09-11.md)。
在 `system-optimization` 分支工作区开展测试。原始 JSON 不能直接运行;修正参考口后,现有 C 内核仍在后半段陷入极小步长。测试副本经过参数对齐、管路计算修正和质量绝对误差限调整后,能够完整算到 10 s。最终验证版与 Amesim 的主要曲线接近,但仍有下面列出的局部差值,不能称为逐点完全一致。
本次只在 `/test/mql4-20260910` 中生成实验程序和数据;未将实验修改并入正式 C 内核,未改网页,未改雅各比矩阵算法,也未提交或推送。原始两个输入文件的 SHA256 复核通过,均未修改。
测试来源为 `F:/Downloads/test-mql-4.json` 和 `tests/data/test_mql_4.ame`。模型均为四支路气动机械系统;按元件类型和连接拓扑匹配后,均为 81 个元件、90 条连接、64 个动态状态。其中 26 个气体容腔产生 52 个状态,6 个质量块产生 12 个状态。Amesim 采用压力、温度状态,C 采用质量、内能状态;比较时转换到相同物理量。全部分支的元件对应关系保存在 `topology-mapping.json`。
**先解决输入和测试条件。** 原 JSON 的 `amesim_p4node2_2/3/4` 分别把 2 号参考口接到了阀门,3 号支路口接到了储气管端。供需校验报告 `CONNECTION_VARIABLE_SUPPLY_MISSING`,这是实际模型接线错误。仅在副本交换这三个节点的 2、3 号口,共修正六个端点;详见 `connection-corrections.json`。
AME 包内带有旧八支路结果和 C 源文件缓存。通过本机 Amesim 官方 API 重新编译运行四支路图纸后,EXE 日志确认 `64 unknowns`,新结果包含 0~10 s。对比采用这批新结果,未使用旧结果。归档 `.c` 缓存没有随本次保存更新,不能用它证明本次运行的代码结构;本次 Amesim 侧的依据是官方重编译、EXE 运行日志和新变量/结果文件。
AME 实际保存的积分设置为固定步长。测试副本已通过官方 API 改为 Standard 变步长、误差限 1e-7、最大步长 1e30、动态运行、不接续旧状态。JSON 的 BDF/max_step=1e30 被保留,rtol 显式设为 1e-7;当前网页后端默认 rtol=1e-6,因此不能用默认值冒充已对齐设置。两边输出间隔均为 0.01 s。Amesim 实际使用的自动算法和统计仅记录,不将复现 Amesim 求解算法作为本次目标。
此外有五处参数差异,按 AME 当前实际参数/初始值修正 JSON 副本:
| JSON 元件 | 参数 | 原 JSON | AME 对应值 |
|---|---|---:|---:|
| amesim_pnl00r_4 | 直径 | 14 mm | 10 mm |
| amesim_pnl0002_10 | 直径 | 20 mm | 10 mm |
| amesim_pnl0002_10 | 长度 | 2 m | 1 m |
| amesim_pnl0002_10 | 相对粗糙度 | 0.00225 | 0.00001 |
| amesim_pnl0002_10 | 初始绝对压力 | 100000 Pa | 101301.013 Pa |
最后一项不是 1.013 bar:AME 实际保存的 `pctr` 是表压 1.013 Pa,加环境压力 101300 Pa 得到 101301.013 Pa。交付文件为 `test-mql-4-corrected.json`,与实验输入 `test-mql-4-amesim-aligned.json` 和最终打包副本 `final/input.json` 内容相同。该 JSON 包含接线及参数修正,C 公式与质量绝对误差限的修改保存在实验程序中,不属于 JSON 内容。初次只比较气罐、气缸和机械量时未发现该差异;扩大到全部 64 个状态量后识别并修正。
**运行失败与其原因。** 仅修正接线、保留原 C 算法及 JSON 参数,BDF/rtol=1e-7 运行 120 s 后停在 4.926982415 s;已接受 285780 步、调用模型 651838 次。它是超时退出,并非已完成或进程崩溃。另一次 30 s 的诊断运行显示,约 4.9 s 后步长降至 7.23e-8~1.59e-7 s,主要控制误差的状态是 PNL0003 管内气体质量/内能。超时回调使 RHS 返回失败后,CVODE 会附带线性系统/Jacobian 失败日志;不能把这种派生日志误判为另一个独立的雅各比崩溃。
把五处参数中的前四处对齐,但保留原管路算法,40 s 内也只推进到 4.720248930 s,说明参数差异与慢速问题并不是同一件事。此阶段初始压力差异尚未修正,原始记录保留在 `matched-original`。
C 的 `PNL0003` 用了独立 Darcy 压降反求、固定 48 次二分;现有其他气体管路采用可压缩流量关系。在接近平衡时,前者的流量对很小的压差过于敏感,给积分器造成很快的局部动态。只把 PNL0003 切到项目已有可压缩流量关系的实验中,同一份只修正接线的模型便在 18.03 s 墙钟内跑完 10 s,接受步数降至 9074;这验证了管路公式是主要卡顿来源之一,并不表示只减少二分次数就能获得相同效果。
最终 C 验证版还让 PNL0001 按流动方向选择上游温度,并统一氦气管路流量计算和诊断使用的黏度表达式。原实现存在“一个用途使用 Sutherland,另一个用途使用 NASA 表达式”的不一致。它们是物理输入/计算一致性修正,不是全局求解顺序调整。各项实验的源文件和统计均保留;没有据单次速度变化声称某一项具有普遍的固定加速比。
另一个已验证问题是小管腔质量状态的绝对误差限。旧 C 对所有气体质量和内能状态都给 1e-8(各自 SI 单位)。对质量只有约 1e-5~1e-3 kg 的小容腔,1e-8 kg 会盖过 rtol=1e-7,允许的相对质量误差远大于 1e-7。两边名义 rtol 相同,不代表压力/温度精度相同。
在相同已对齐模型和管路公式上,仅把质量绝对误差限调为 1e-14 kg,保留能量 1e-8 J、速度/位移 1e-12,模型调用从 61246 降到 24941,线性化触发的模型调用从 48960 降到 16768。阀流量最大差从 0.1652 g/s 降至约 0.0160 g/s,9.53~9.58 s 附近的异常小流量尖峰明显降低。更严格的容腔质量控制在此模型上改善了稳定性,反而更快;1e-14 kg 是本次试验值,不能直接作为任意尺寸新模型的统一默认值,应按容腔尺度定义误差权重。
**曲线对比。** 在共同的 1001 个采样时间点比较 64 个状态对应的物理量,并补充 8 条孔口/阀流量,共 72 条曲线。压力统一为绝对压力;AME 的 g/s 转为 kg/s,并按端口流入/流出约定处理符号。没有绘图。最终验证版的最大绝对差为:
| 量 | 最大绝对差 | 对应量 | 时间 |
|---|---:|---|---:|
| 位移 | 0.646855 μm | `amesim_mecmas21_9.x` | 1.22 s |
| 速度 | 3.41015 μm/s | `amesim_mecmas21_9.v` | 1.22 s |
| 压力 | 198.27 Pa | `amesim_pnl0001_14.p` | 0.05 s |
| 温度 | 0.00962632 K | `amesim_pnl0002_1.T` | 0.08 s |
| 质量流量 | 0.0160272 g/s | `amesim_pnvo001_3.port_2.m_flow` | 1.89 s |
主要储气罐和气缸的压力差比表中管路局部压力峰值更小。位移末值停在规定的 -0.72 m 和 0.37 m。882 个输出序列全部有限,完整输出含两个碰撞事件点共 1003 点;闭合气路总质量初值为 2.78334124184 kg,全程最大漂移 8.44e-15 kg。三次重复 C 运行的完整序列及最终状态逐值相同。
原来主要腔室约 50 kPa 的差异,在参数对齐后降到几十 Pa,主要差异可归因于输入参数。仍有约 198 Pa 的管内短时偏差;收紧质量绝对误差限后这一峰值基本没有变化,因此不能用质量容差解释所有剩余偏差。两边还有管路阻力近似、物性计算和积分/事件处理的差别;本次没有逐项证明这 198 Pa 的唯一来源,也未建立“所有输出逐点满足 1e-7 相对差”的验收结论。接近零流量时应使用绝对误差或工作范围归一化,不能只看瞬时相对百分比。
还做了一次针对管内迭代上限的独立检查:在最终版本基础上,把相应管流求解的最大迭代次数从 16 提高到 64,仍得到约 200 Pa 的最大压力差、0.00991 K 的最大温度差。增加迭代次数没有消除该局部偏差,不能把剩余差异直接归因于这个迭代上限。该诊断保存在 `matched-v4-pnl3-compressible-upstream-viscosity-nasa-mass-atol-tight-pipe`,最终交付和计时仍采用 v3。
**速度对比。** 最终版本与 Amesim 在同一台机器交错运行各三次,取中位数。下表的主要速度指标是各程序报告的求解 CPU 时间,编译和进程启动不计入;另外列出进程墙钟供核对。结果序列保存一致,未涉及网页或绘图。
| 项目 | Amesim 当前图纸重编译版 | 最终 C 验证版 |
|---|---:|---:|
| 完成仿真时间 | 10 s | 10 s |
| 求解 CPU 中位数 | 1.14062 s | 4.01562 s |
| 进程墙钟中位数 | 4.1550 s | 6.5606 s |
| 接受积分步数 | 2456 | 5137 |
| 程序报告的模型/函数计算次数 | 33143 | 24941 |
| 程序报告的 Jacobian 计算次数(仅记录) | 382 | 262 |
C 的纯求解墙钟中位数为 4.4412 s;求解 CPU 比值约为 3.52。进程墙钟包含启动、授权、结果整理与写文件,不能拿它替代求解时间。两套程序的函数统计口径并不保证一次调用执行同样多的工作,不直接用调用数相除推导单函数性能。原 C 没有完成全程,因此不报告“原 C 完整运行耗时”或从仿真推进比例外推完整速度。
**C 内部的耗时证据。** 另编译一个只加计数/计时的版本,按嵌套调用排除重复计时;以下占比的分母是 C 模型 RHS 计算时间。该诊断运行不作为上述正式计时结果。
| 计算 | 次数 | 模型 RHS 时间占比 |
|---|---:|---:|
| model_eval | 24,941 | 5.72% |
| native_pipe_flow | 548,702 | 49.39% |
| native_medium_orifice | 199,528 | 8.22% |
| native_medium_gas | 648,466 | 9.21% |
| native_temperature_ph | 608,716 | 20.13% |
| native_pipe_diagnostics | 548,702 | 7.18% |
| native_contact | 99,764 | 0.16% |
这里 `model_eval` 一行指去掉列出的子函数后的模型调度、赋值及机械平衡等剩余工作。模型 RHS 合计约占诊断求解墙钟的 96.4%。C 求解器线性化共触发 16768 次 RHS,占全部 24941 次的 67.2%;这是“为何重复计算”的另一种切分,与上表不能相加。
本模型生成的 236 项流体运算组成零循环依赖块,已经按依赖顺序一次执行;当前主要开销不能再解释为 Python 数值积分或多层全局压力/焓值循环。真正重的是一次 RHS 内反复算管流、反算温度、求氦气物性,以及积分器在试算/线性化时反复调用整套计算。
后续优先事项是:先把本次确认的物理公式和误差权重修正做成通用内核变更并补独立部件验证;再消除同一 RHS 内的重复物性换算、共享管流所需物性;把只用于显示的雷诺数、流速、摩擦系数等从每次 RHS 移到采样输出阶段;最后改进管内阻力方程的收敛策略和未收敛诊断。雅各比相关实现暂不改。
Amesim 算法信息仅留档:当前 Standard 自动运行统计为 Adams 727 步、BDF 1729 步,处理 8 次不连续事件;日志记录启用了其自适应 Jacobian 计算。按用户最新要求,不将 Amesim 的具体算法作为后续实现标准。
**可复现文件。** 全部位于 `test/mql4-20260910`:`final/` 是本次 C 验证包,包含模型 C、公共计算 C、运行时快照、EXE、DLL、输入 JSON、哈希清单和运行脚本;`final/run-bdf.ps1` 显式指定本次求解参数;`final/input.json` 导入现有网页时仍由正式旧版 C 内核运行,不等同于此实验 EXE。`run_ame.py` 使用本机 Amesim 官方 API,`experiment.py` 保留各阶段实验,`compare.py` 生成比较指标,`benchmark-v3/` 保存三次对照计时,`cost-profile-v3/` 保存函数计时,`verification-final.json` 保存基本验证,`amesim-fresh/test_mql_4.ame` 保存重新计算的 Amesim 参考结果。
@@ -0,0 +1,70 @@
# test-mql-4 网页仿真与 LSTP00A 接口力对比
2026-09-11,在网页导入 `test-mql-4-corrected.json`,点击“运行仿真”,完整算到 10 s,再通过“下载结果文件”导出本次原始结果。网页显示 1003 个采样点,未发生仿真失败。
**结论:常规采样点的接触力很接近,但完整网页曲线与 Amesim 已保存曲线不一致。网页额外保存的一个碰撞事件点有约 1.50×10¹¹ N 的瞬时峰值。** 不能仅凭常规采样点上的小误差,宣称整条力曲线一致。
## 本次仿真时间
| 口径 | 本次结果 |
|---|---:|
| 点击运行后至结果可查看 | 约 7 s |
| C 纯求解墙钟 | 3.650152 s |
| C 求解 CPU | 3.515625 s |
| 原生子进程墙钟(含结果整理等) | 5.238736 s |
| 构建缓存检查 | 0.167409 s(命中缓存) |
| 模型计算次数 / 接受步数 | 24941 / 5137 |
页面控制台“开始仿真”为 01:53:06,“仿真完成”为 01:53:13;前端日志只显示整秒,因此约 7 s 不是毫秒精度测量,也不包含用户后来打开曲线窗口的时间。纯求解时间直接来自本次网页导出文件。网页全程与纯求解之差包含准备、子进程启动、结果生成、传输和前端接收,不能全部归于进度条。
设置为 BDF、相对误差限 1e-7、最大积分步长 1e30 s、输出间隔 0.01 s、仿真区间 0~10 s。初始 5173 开发页面未完成渲染,实际成功测试使用后端提供的 `http://127.0.0.1:8000/` 页面。一次先前标签页在任务启动后不可用,其时间不计入本次结果。
## 部件与接口对应
用户所称 `lstp001` 在当前模型中对应 `LSTP00A` 第 1 个实例,即 JSON 的 `amesim_lstp00a_1`,网页显示名为 `elasticendstop_9_副本`。根据连接拓扑,它对应 Amesim 的 `elasticendstop_8`,不是仅按显示名中的数字匹配。
| 网页变量 | 对照 Amesim 变量 | 方向处理 |
|---|---|---|
| `amesim_lstp00a_1.port_1.f` | `f1@elasticendstop_8` | 同号直接比较 |
| `amesim_lstp00a_1.port_2.f` | `f2@elasticendstop_8` | Amesim 值取负后比较 |
本系统端口力统一取流入元件为正,两个端口的力相反。Amesim 变量清单明确将此模型的 f2 标为 f1 的重复量,已保存的两个数组也完全相同。因此第二接口符号不同本身不能判定为力计算错误。
## 完整曲线与常规采样对照
![接口力曲线对比](../../test/mql4-web-force-20260911/lstp00a-force-comparison.png)
第 1 实例在 1001 个共同的 0.01 s 采样点上:网页峰值为 272620.924818 N,Amesim 已保存峰值为 272621.136490 N;最大绝对差 0.577026 N,均方根差 0.135705 N。最大差相当于 Amesim 峰值的 0.000212%,该百分比是按峰值归一化,不是接近零力时的瞬时相对误差。
顺带核对全部四个接触元件的接口 1;接口 2 统一方向后有同样的误差:
| JSON 实例 | Amesim 对应实例 | 共同采样点最大差 | 均方根差 | 最大差 / Amesim 峰值 |
|---|---|---:|---:|---:|
| 1 | `elasticendstop_8` | 0.577026 N | 0.135705 N | 0.000212% |
| 2 | `elasticendstop_9` | 0.578578 N | 0.136276 N | 0.000212% |
| 3 | `elasticendstop_10` | 1.134175 N | 0.140897 N | 0.000416% |
| 4 | `elasticendstop_11` | 0.729195 N | 0.136876 N | 0.000267% |
但是网页还保存了 1.201137556938643 s 和 1.225339087445038 s 两个事件点。第一个事件点,四个接触元件均出现约 1.49859×10¹¹ N 的力;Amesim 本次保存的曲线没有这一时刻的数据,其相邻采样为 1.20 s 和 1.21 s。上图左上保留网页原始事件点,右上只用于展示共同采样点的一致程度,两者不可混为一个比较口径。
## 尖峰来源与持续时间
在 t = 1.201137556938643 s,170000 kg 的负载到达 0.37 m 理想限位。本系统将该负载速度置零;与它相接触的 50 kg 活塞一侧仍为 1.498587803347 m/s。接触参数为刚度 1e11 N/m、阻尼 1e11 N/(m/s),当时穿透量约 1.47291297e-06 m,阻尼已经几乎全量参与。
按当前公式,弹性项为 147291.297 N,阻尼项为 149858720230.815 N,合计 149858867522.112 N。这个数值直接对应网页上的尖峰,并非力单位换算造成。
另编译一个仅记录事件附近内部接受步的诊断程序,使用同一输入、公式和容差。记录开关不改变已有 1003 个输出点,已逐值核验。碰撞后力值约 0.348 ns 降到一半、1.154 ns 降到 10%、2.336 ns 降到 1%;这与 50 kg / 1e11 N·s/m ≈ 0.5 ns 的阻尼时间尺度吻合。
因此有两个叠加因素:理想限位突然改变速度,配合极大阻尼形成纳秒级瞬态;网页结果保存了瞬态最高事件点,却没有保存紧接着的纳秒级回落点。用直线把该点连接到 1.20 s、1.21 s,会把非常窄的峰画成毫秒级宽峰。
目前只能证明 Amesim 的**已保存曲线**没有采到该峰,不能据此断言 Amesim 内部没有同类瞬态,也不能把两者完整力曲线的差异简单归因于 C 语言或积分器精度。按此前要求,本次不以 Amesim 的内部算法作为实现标准。
此前的 72 条曲线对照主要覆盖状态量和阀流量,且只比较共同采样点,没有验证这两个新增事件点处的接触力。这是此次网页检查新增发现的覆盖缺口。
下一步应先明确碰撞时刻输出采用哪一侧的状态,并保存事件前后及必要的快速衰减点,让曲线按真实时间分辨率表达瞬态;常规采样比较仍可保留,但不能靠删去峰值来宣称物理问题已经解决。如果要消除模型本身的极短冲击,应再评估理想刚性限位及接触阻尼参数的物理取值。
## 数据与复核
本次导出的原始结果为 `test/mql4-web-force-20260911/web-result.simresult`,可在网页“加载结果文件”中复现。核对了其中所有元件参数和连接端点,均与交付 JSON 相同。Amesim 数据来自上一轮对 `tests/data/test_mql_4.ame` 官方重新编译所得的 `test/mql4-20260910/amesim-fresh/test_mql_4.ame`,未使用原归档内旧八支路缓存。
同目录 `summary.json` 保存计时、逐部件误差及源文件哈希;`force-series.json` 保存原始和共同采样力数据;`event-trace/accepted-event.jsonl` 保存内部步诊断;`lstp00a-force-comparison.svg` 提供矢量图。生产求解代码及两个用户原始输入文件本次均未修改。
@@ -0,0 +1,61 @@
# 管路重复计算优化核查(2026-09-10)
本轮减少管流的重复求值,并检查原内部迭代的数值误差。它不替代编译阶段的通用计算排序,也没有解决管流迭代耗尽上限后仍返回近似结果的问题。
## 修改范围
- `native/components/kernels.c`:将只依赖相对粗糙度的摩擦系数项提到内部循环外;其余公式、运算顺序、误差阈值和 16/64/48 轮限制保持不变。
- `native/include/kernels.h`:增加管流输入与结果缓存。键包含两端压力、温度、几何参数、管流类型和全部介质常量,逐项完全相同才复用结果;不保存非有限结果。
- `app/simulation/native_codegen/extended.py`:每个需要参与全网流量计算的管流支路分配一个缓存,在每次 `model_eval` 内重新清零。不同积分器试算之间不复用,不改变压力、流量或焓传播顺序。PNL0003 原本在全网循环外计算,保持直接调用。
这轮减少的是同一次系统状态求值中的重复管流计算。积分器、雅可比策略、物理模型及用户工程未调整。
## 原管流方法的误差
从已修正参考口的独立模型副本 `test/amesim-order-study/reference-port-experiment.json`,在初始、扰动和反向流等 14 组状态中捕获 2352 次调用、432 组不同管流输入。用相同摩擦关系的 80 轮二分求根作为独立精度参照,得到:
| 管流类型 | 不同输入数 | 流量相对误差中位数 | 最大相对误差 |
| --- | ---: | ---: | ---: |
| PNL00R(保留原层流捷径) | 49 | 4.92×10⁻¹³ | 6.67×10⁻¹² |
| PNL0001/2 支路 | 333 | 2.36×10⁻⁶ | 3.22×10⁻⁵ |
| PNL0003 内部支路 | 50 | 2.42×10⁻¹⁵ | 1.09×10⁻¹⁴ |
PNL0001/2 的 333 组输入中,有 330 组的相对误差超过 10⁻⁷。这里比较的是本项目的同一标量方程,不是 Amesim 曲线,也不能把积分器误差限直接等同于允许的管流误差。结果说明原 16 轮方法的收敛性需要单独修正,不能以维持旧数值结果作为最终精度标准。
## 一致性与工作量
保留本轮修改前的已编译 EXE,与修改后 EXE 对照。14 组原状态顺序、14 组逆序及前 2 组重访,共 30 次求值,全部成功;每次 132 个导数和 1784 个输出逐值完全一致。重访用于检查缓存不会引入跨试算的历史依赖。
最终运行 `python -m unittest tests.test_native_pipe_cache tests.test_native_catalog tests.test_native_codegen tests.test_native_only_backend -q`,14 项全部通过,包含 50 个冻结网络的数值对照及 RK45/BDF 执行。回归发现并修正了无气动端口模型中的多余缓存声明;这些模型不再生成该局部变量。初次运行存在编译子进程超时,最终使用本机工具链环境完成验证。
另用独立计数版本统计原 14 组状态,计数逻辑不进入计时程序:
| 实际调用 | 修改前 | 修改后 |
| --- | ---: | ---: |
| PNL00R 求解 | 224 | 56 |
| PNL0001/2 支路求解 | 2016 | 504 |
| PNL0003 内部支路求解 | 112 | 112 |
| 管流求解合计 | 2352 | 672 |
| 摩擦系数计算(含展示输出) | 42743 | 15794 |
这相当于管流求解调用减少 71.4%,但全网流量函数本身的执行次数没有减少。
本机 C 状态求值微基准:输入读取在计时外,每轮 2800 次求值;预热后交替测量各 5 轮,中位数从 2.868505 s 降至 1.490497 s,约 1.92 倍。计时期间另有回归编译任务,数据只用于观察局部收益;调用计数不受此影响。没有进行本轮完整 10 s 轨迹、网页端或 Amesim 对照,不能将该倍数解释为整机加速。
## 后续优先顺序
已完成的端口供需合同主要负责连接校验,不能等同于已经生成最合适的计算顺序。系统层面应先把每个输出的依赖列清楚,提前传递可由当前状态确定的量,按依赖执行能直接计算的表达式,仅将真正互相依赖的部分组成局部求解块。排序依据是变量依赖,不是画布位置或气体流向;反向流也必须覆盖。
此前独立排序实验已在修正参考口的该模型中,把通常每次状态求值的全网流量调用从 4 次降到 1 次,并保持 14 组状态的导数和输出一致。该实验尚不是生产中的通用排序器,也没有证明全部复杂模型都能消除迭代。
因此,应优先开发通用依赖排序和局部循环识别,再解决管流内部求根的收敛判据与算法,并用完整积分轨迹检查时间、步数和数值误差。缓存可以作为保留局部迭代时的补充,不能承担系统计算组织的职责。
## 复现材料
- `test/pipe-flow-study/baseline_kernels.c`、`baseline_kernels.h`、`baseline-build.json`:修改前快照和 EXE 清单。
- `study.py`、`residual-audit.jsonl`:原始调用捕获与标量求根审计。`study.py` 的捕获阶段应使用修改前生成器;已有快照不要覆盖。
- `verify.py`、`*-verification.jsonl`:修改前后 EXE 的 30 次逐值对照。
- `benchmark.py`、`benchmark-results.json`:独立计数及纯 C 状态求值微基准。
- `tests/test_native_pipe_cache.py`:缓存命中、每项输入失效、反向流、介质值变更、独立缓存与非有限结果校验。
`test/` 诊断材料按仓库约定被 Git 忽略;生产代码与回归测试不依赖这些临时材料。