Files
SystemSimulationApp/docs/other/物性与管流分段性能分析-2026-09-11.md
T

204 lines
20 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.
# 物性与管流分段性能分析(2026-09-11)
后续实现已完成:见 [物性复用与管流求根实现及验证](物性复用与管流求根实现及验证-2026-09-11.md)。本文保留为实施前的剖析与隔离实验记录;最新生产实现、计时和回归结论以实现报告为准。
本次沿用网页端已验证的 `test-mql-4-corrected.json`,直接测试网页后端使用的 C 求解程序。结论是:两个方向都值得优化,但物性应优先减少重复反算,管流则应改进收敛方法并检查残差。把迭代次数直接调小,不能可靠地解决问题。
隔离试验中,完整 10 秒仿真的纯求解耗时从 **3.119 秒降至 2.102 秒,中位耗时缩短 32.6%**。这些是 `/test` 内的实验结果;本次没有更改网页后端的生产内核,也没有修改系统雅各比矩阵。
**测试对象与测量口径**
- 输入:`test/mql4-20260910/test-mql-4-corrected.json`,与上一轮网页端对照使用同一模型。
- 配置:真实氦气 Peng–Robinson 物性;CVODE/BDF;仿真 0~10 s;相对误差限 `1e-7`;最大积分步长 `1e30`;状态绝对误差限沿用生产配置。
- 规模:64 个状态,882 个输出;本模型的编译计算顺序已经形成,无代数环。当前检查的是这个顺序内部的成本。
- 代码:`system-optimization` 分支,构建标识 `a23de3b825eaacc2df5b61f524df66ec3f92da943acb5a9a98aaf4ba479fb02f`。试验脚本首先核验生产 C 源文件与构建清单的哈希一致。
- 性能比较:每个方案独立进程运行三轮,交错执行,报告中位数。只统计 C 求解阶段,使用 `--solve-only`,不含 Python 前处理、编译、进程启动、曲线输出、网页交互和绘图。
- 正确性比较另跑完整输出,保存 0.01 s 网格及事件点;对组合方案另外记录碰撞附近内部积分点。
- 分段测试是在一次连续求解中计数,按方程试算的时间归入区间,**没有在分段边界重启求解器**。试算可能回退、拒绝或越过区间边界,因此这些数据表示“为该区间试算花了多少成本”,不是各段独立启动的时间。
- 计时探针和详细计数、输入采集分两次执行;二者的全部输出序列均与未插桩基准逐点完全一致。插桩运行总耗时为 3.600 s,同批完整输出基准为 3.211 s,探针约增加 12% 耗时。因此下面函数时间用于定位成本,最终加速比使用无探针程序测量。
本次没有重跑 Amesim;数值对照读取此前官方重新编译运行的 `amesim-fresh/test_mql_4.ame`。不将历史 Amesim 耗时与本次机器负载不同的测量混合计算加速比。
**1.时间花在哪个阶段**
基准共执行 24,941 次系统方程计算,接受 5,137 个积分步,发生 2 次状态切换。下表中的时间是探针测得的方程计算时间,不包括方程外的求解器工作。
| 仿真时间区间 / s | 方程计算次数 | 方程计算耗时 / s | 占全部方程计算时间 |
|---|---:|---:|---:|
| 0~0.01 | 760 | 0.068 | 1.9% |
| 0.01~0.8 | 12,042 | 1.757 | 49.9% |
| 0.8~1.20 | 2,165 | 0.272 | 7.7% |
| 1.20~1.202,包含首次碰撞 | 1,186 | 0.146 | 4.1% |
| 1.202~1.23,包含第二次限位事件 | 2,451 | 0.313 | 8.9% |
| 1.23~2 | 4,333 | 0.668 | 19.0% |
| 2~10 | 2,004 | 0.299 | 8.5% |
| 合计 | 24,941 | 3.522 | 100% |
接近一半的工作发生在 0.01~0.8 s。最后 8 秒仿真只占约 8.5% 的方程计算时间。碰撞附近确实需要处理很快的变化,但本次测量不支持“主要时间都花在碰撞瞬间”的判断。
另有 16,768 次方程计算来自线性求解器估算数值导数,占全部方程调用的 67.2%。这部分已经包含在表内,不能另加一次。它意味着物性和管流计算会随系统试算反复执行。本轮保留现有雅各比矩阵处理方式,只降低每次试算成本。
**2.把物性和管流迭代分开后,结论发生了什么变化**
下表按互不重复的函数耗时分类:例如管路内部调用的可压缩流动计算,记在“可压缩流动系数”中,不再记入“管流摩擦迭代”。
| 计算内容 | 插桩耗时 / s | 占方程计算时间 | 调用次数 |
|---|---:|---:|---:|
| 可压缩流动系数:等熵修正、密度、临界/亚音速关系等 | 1.009 | 28.6% | 728,296 |
| 管流摩擦迭代 | 0.945 | 26.8% | 483,678 次进入循环 |
| 用压力、焓反求温度 | 0.728 | 20.7% | 646,040 |
| 从质量、内能恢复气体状态 | 0.328 | 9.3% | 648,466 |
| 管路诊断量:雷诺数、速度、摩擦系数等 | 0.252 | 7.2% | 548,702 |
| 管路其余准备工作 | 0.093 | 2.6% | 548,702 次管流调用 |
| 系统组装、阀口剩余计算、接触力等 | 0.166 | 4.7% | — |
因此,不能把整个 `native_pipe_flow` 函数的时间都解释成“内部摩擦迭代太慢”。它首先还要计算黏度、真实气体修正以及可压缩流动系数。表中 28.6% 的项目也包含流量公式中的幂函数等,不是全部都属于物性查询。
本次计数还发现:一次完整求解累计调用约 **620 万次气体状态方程求根**、348 万次焓偏差计算和829万次摩擦系数计算。现在这些均运行在 C 内核中,当前问题已经是物理计算量和重复调用量,不能继续归因于 Python 语言开销。
**3.物性为什么贵,应该怎样优化**
当前真实氦气的 `p,h → T` 过程大致如下:先用理想气体关系猜温度,再代入真实气体关系计算焓,看是否吻合,然后更新温度。每次更新又要解一次气体状态方程,并计算对数等函数。
| 反算对象 | 次数 | 平均迭代次数 | 观察到的最多次数 | 达到16次上限且未收敛 |
|---|---:|---:|---:|---:|
| 质量、内能恢复温度 | 648,466 | 4.41 | 5 | 0 |
| 压力、焓恢复温度 | 646,040 | 4.38 | 5 | 0 |
物性反算在这个工况下并不存在迭代失控;主要问题是一次略贵的计算被调用了很多遍。C 输入重放试验中,`p,h → T` 平均约 **1.065 μs/次**,几十万次累加后就成为明显成本。
更重要的是,这 646,040 次调用,在同一次方程计算中,都能找到压力、焓完全相同的上游气体状态。温度此前已经算出来了。其中 369,553 次还是对相同压力、焓的重复请求,占 57.2%。
通俗地说,目前有些路径在做:“先算出温度,把它换成焓传给下一个部件,下一个部件又把同一压力下的焓反算成温度。”这个模型中,优先消除这条往返路径,比单独把反算公式加快更有价值。
已验证的两个层次:
1. **同一次试算中,相同输入只反算一次。** 完全相同的介质、压力、焓使用同一个结果。纯求解耗时减少 11.0%,全部882个输出及时间序列逐点完全一致,方程调用数也不变。
2. **传递与压力、焓对应的已知温度。** 如果气体状态已经提供了同一组压力、焓,直接使用其温度;找不到时仍调用原来的反算。单独使用这一方案,纯求解耗时减少 16.7%。采集的17,527个气体状态中,源温度与反算温度最大只差 `1.08e-10 K`,但微小数值变化仍会改变 BDF 的后续试算路径,所以不能承诺逐位相同。
通用实现建议是建立一个“本次方程计算的物性状态”结构,保存介质身份、压力、焓、温度及已经算出的密度、黏度等。编译器知道量来自哪个状态时,直接传递状态引用;不知道时再查询或反算。缓存由求解上下文持有,不依赖整个进程中的可变全局状态。
必须遵守物理含义:**相同焓并不代表相同温度**。节流后的压力改变了,或者支路发生焓混合,就不能直接沿用原来的温度。缓存必须核对介质与完整输入,未来两相介质还需要区分物性区域。每次试算更新或失效缓存;本轮实验不采用“数值差不多就复用”,以免把求解器正在估算的细小变化抹掉。
还有两个次级机会:
- `valve → isentropic → local_isentropic` 已经求过上游密度,返回阀口后又按相同 `p,T` 求了一遍。可以让一次物性更新同时提供密度、热容和所需导数,把公共中间量复用。该方向还未纳入本轮完整系统加速结果。
- 已知内能、压力、密度时,可以利用 `h = u + p/ρ` 得到焓,避免再从 `p,T` 求一遍真实气体焓。对采集状态的微基准,气体状态恢复从 **0.484 降至 0.247 μs/次**,约减少49%;与原式的最大焓差为 `1.67e-7 J/kg`。这是物性定义层面的通用机会,但必须先核对各介质的能量参考点与实现一致性。本轮只完成了单项验证,没有把该收益算进完整系统的32.6%。
对于确实需要反算的状态,后续再考虑使用上一次温度作初始猜测、利用局部热容改善更新、加区间保护与失败回退。初始猜测只能帮助收敛,不能绕过结果残差检查。查表、插值等近似方案暂不作为第一步,因为本轮已经找到无需近似的重复计算。
**4.管流为什么反复迭代,而且到上限仍没有收敛**
当前过程是:猜流量 → 算雷诺数 → 算摩擦系数 → 用新摩擦系数重新算流量 → 新旧流量各取一半 → 重复。每次调用又从“摩擦系数等于0.02”的固定猜测开始。
| 管路类别 | 调用次数 | 未进入循环的次数 | 达到上限且未收敛 | 占全部调用 |
|---|---:|---:|---:|---:|
| PNL00R(kind 0) | 49,882 | 49,644 | 0 | 0% |
| PNL0001/2(kind 1) | 399,056 | 8,028 | 390,268 | 97.8% |
| PNL0003(kind 3) | 99,764 | 7,352 | 92,412 | 92.6% |
PNL00R 大多走层流公式,确实进入迭代的少量调用最多需要62次,但都在其64次上限内收敛。PNL0003 的92,412次循环全部走满16次;PNL0001/2 的非零流动调用也几乎如此。
代码达到上限后直接返回当前流量,没有要求最终残差合格。这不只是速度问题,还意味着当前局部流量并未都达到代码宣称的收敛精度。
“新旧各取一半”虽然温和,却会限制收敛速度。例如层流关系下,在解附近一次更新大约只把误差缩至原来的75%;16次后仍可能剩下初始误差的约1%。充分粗糙的湍流区,即使摩擦系数已经近似恒定,仍然反复取平均,也会继续消耗循环。真实过渡区更不能依靠固定次数保证精度。
对实际仿真每37次调用抽取一组输入,重放得到14,830组管流输入,覆盖正流7,362组、反流6,951组、等压517组。压力约0.1~15.3 MPa,温度约173~526 K。
本次把相同的管流关系写成 `Re² × f(Re) = K`,以左右两边的相对差衡量残差。`K` 来自原来的物性、压力、温度及几何关系,没有换用新的物理流量公式。
| 类别 | 旧方法残差中位数 | 旧方法残差90分位 | 旧方法残差99分位 | 新方法最大残差 |
|---|---:|---:|---:|---:|
| PNL0001/2 | `7.51e-6` | 3.07% | 15.9% | `9.59e-10` |
| PNL0003 | `2.82e-6` | `1.85e-5` | 2.19% | `6.38e-11` |
相对残差在流量接近零时会很大,不能直接当成系统流量误差。即使只看新流量绝对值大于 `1e-8 kg/s` 的输入,旧方法的最大方程残差仍分别为21.6%和12.3%。在全部重放输入上,新旧流量的最大绝对差分别为 **`2.91e-6 kg/s`、`1.93e-6 kg/s`**。因此既要看残差,也要看流量的绝对变化和系统曲线。
针对这一点,实验采用带区间保护的局部 Newton 求根:根据当前偏差决定下一次改多少;如果下一次估计越界,则用区间二分回退。保留原有摩擦系数公式、层流分支、流向、可压缩修正及近平衡平滑。这里计算的是管路内部一个量的斜率,没有修改系统雅各比矩阵。
| 同一批输入的 C 微基准 | 旧方法 / μs每次 | 实验方法 / μs每次 | 时间减少 |
|---|---:|---:|---:|
| 只计算摩擦迭代,物性和几何系数提前准备 | 1.619 | 0.555 | 65.7% |
| 整个管流计算,包含物性准备 | 3.369 | 2.043 | 39.4% |
PNL0001/2 真正进入新迭代时平均4.40次,PNL0003平均4.08次,最多6次。用独立的100次二分求解同一方程作参照,新流量最大差约 `1.1e-13 kg/s`。
另测906组独立工况,覆盖雷诺数 `1e-6~1e9`、相对粗糙度 `0~0.1`:无非有限结果,最多7次迭代,与二分结果最大相对差 `3.62e-11`。部分工况确实触发了区间回退,最多2次。这个标量求根部分通过 `K` 与介质物性分离,因此可以复用于采用同一阻力方程的不同气体与几何参数。其他阻力模型应提供自己的残差函数和物理适用区间,不能直接套用氦气物性公式。
正式实现还应返回 `converged / iterations / residual / fallback` 等状态;超过上限时继续可靠回退或报告失败,不能静默返回未经检查的数值。
**5.完整系统能节省多少时间**
下表全部使用无性能探针的可执行程序,三轮交错运行。每个方案都运行到10 s。
| 方案 | 求解墙钟中位数 / s | 三轮范围 / s | CPU中位数 / s | 比基准减少 | 方程计算次数 |
|---|---:|---|---:|---:|---:|
| 当前生产算法基准 | 3.119 | 3.111~3.165 | 3.172 | — | 24,941 |
| 只复用完全相同输入的物性反算结果 | 2.775 | 2.772~2.807 | 2.844 | 11.0% | 24,941 |
| 直接使用对应气体状态的已知温度 | 2.599 | 2.573~2.607 | 2.672 | 16.7% | 25,493 |
| 只替换管流内部求根方法 | 2.500 | 2.496~2.508 | 2.578 | 19.8% | 24,626 |
| 已知温度复用+管流求根 | 2.102 | 2.091~2.108 | 2.172 | 32.6% | 28,164 |
组合方案虽然单次计算明显加快,方程调用次数却增加约12.9%。它改变了局部流量精度与微小舍入,BDF在这个敏感模型上的步长选择随之变化。因此,“单次管流快39%”不等于“整个系统快39%”,两个单项收益也不能直接相加。真实的完整系统收益应以上表为准。
相同输入复用方案和直接传递温度的方案是两个层次,不应叠加计算11.0%与16.7%。组合实验包含的是后一种物性方案。
**6.是否牺牲了仿真结果**
只复用相同反算输入的方案,包含事件点在内的全部输出完全一致。其余方案保持同一物理方程,但不会逐位相同,必须检查结果差异。
组合方案与基准在0.01 s公共网格上的比较,针对此前对照的72条压力、温度、位移、速度和阀口流量曲线:
| 量 | 最大绝对差 |
|---|---:|
| 压力 | 19.3 Pa |
| 温度 | 0.00586 K |
| 位移 | `2.06e-7 m` |
| 速度 | `1.78e-6 m/s` |
| 阀口质量流量 | `9.36e-5 kg/s` |
流量最大差可能发生在短暂变化附近,不能只拿最后时刻或少量输出点作结论。上述72条量的完整公共网格已经比较;与存档Amesim的回归对照另外采用原有57个指定时间点,不能将其称为每个内部积分点均一致。
与Amesim在这57个指定时间点的对照中,组合方案最大压力差约199.8 Pa、最大温度差0.01154 K;基准对应约198.3 Pa、0.00963 K。位移、速度、阀口流量差仍在同一数量级。新方案没有消除原有模型/数值差异,也没有显示出数量级上的恶化。详情按曲线存入 `accuracy.json`。
此前关注的第一个 LSTP 接口力单独比较:
- 1001个公共网格点,与Amesim存档力曲线的最大差:基准0.5770 N,组合方案0.5766 N。
- 第一次碰撞时间相对基准变化约 `−4.32e-8 s`,第二次约 `−1.52e-7 s`。
- 第一次事件的瞬时峰值从 `1.498588675e11 N` 变为 `1.498588441e11 N`,相对变化约 `−1.56e-7`。
- 另行记录内部接受的积分点后,峰值降至一半的时间均约0.348 ns,降至1%的时间均约2.336 ns。记录探针也未改变组合方案原有输出。
所以本轮加速没有跳过或删除此前发现的纳秒级力脉冲。Amesim存档在这附近没有相同密度的内部采样,仍不能据此判断其内部是否存在同样脉冲。这项既有对照限制继续保留。
这些验证支持方案继续进入正式开发,并不等价于所有模型、所有介质均已通过生产回归。
**7.建议的通用实施顺序**
1. **先补可观测性和收敛判据。** 把本轮的调用次数、迭代分布、未收敛次数、最大残差做成可选诊断,默认关闭详细计时。每条管路分别累计,便于新增模型后直接定位。改变流量算法前保存基准。
2. **将物性复用做进编译与运行上下文。** 第一步采用完整输入一致的缓存,获得本轮已证明的低风险收益;随后让编译器沿供需关系传递物性状态引用,跳过已有温度的反算。焓混合、压力改变、介质改变时重新构造状态。未来介质各自实现 `pT / ph / rho-u` 更新及可复用的派生量。
3. **统一管路标量求根器。** 将介质与几何计算形成的系数交给局部求根器,保留各管路已有的物理分支;以流量绝对误差和相对残差共同验收。区间保护、失败回退和统计接口作为公共能力,不按具体实例编号写特例。局部斜率可由阻力模型提供,缺少时仍有不依赖斜率的区间方法。
4. **合并物性中间量,再分离仅用于显示的诊断量。** 复用上游密度、热容和等熵计算中间量;验证 `h=u+p/ρ` 快路径。对雷诺数、显示速度等,编译器检查是否被其他模型或控制器使用;只有确认为纯输出时才移到采样阶段。不能一律关闭,因为新增模型可能把这些量接入反馈。
5. **逐项做系统回归,再合并收益。** 检查不同气体、正反流、等压、层流、过渡区、粗糙管、限位事件和小体积储气模型;同时保存稳态输出和事件附近内部点。每个方案单独测,再测组合,接受与拒绝步数也要记录。保持本轮所用系统雅各比矩阵策略,避免混入其他变化。
优先顺序上,建议尽快处理管流“达到上限仍返回”的行为,同时先落地完全一致输入的物性复用。前者关系到局部方程是否真的解好,后者已有逐点一致和约11%完整系统收益的证据。更进一步的状态传递与管流求根组合,已有约32.6%的隔离试验收益,可以作为第一轮正式优化的目标;不把这一百分比保证给其他模型。
**复现与文件**
所有原始记录与实验程序位于:`F:/Master/SystemSimulationApp/test/property-pipe-profile-20260911/`。
| 文件 | 内容 |
|---|---|
| `profile.py` | 核验源码哈希,构建基准、分段计时、独立计数和输入采集程序 |
| `timed/profile.json` | 各阶段独占耗时、调用次数、迭代直方图 |
| `counters/profile.json`、`counters/replay.txt` | 缓存命中机会及49,818条气体/反算/管流采集输入 |
| `experiments.py` | 完全相同输入缓存、已知温度复用、管流求根及组合方案生成器 |
| `microbench.py`、`micro-summary.json` | C重放微基准、残差、906组独立工况检查 |
| `benchmark.py`、`benchmark.json` | 无探针的三轮交错纯求解测量及逐次结果 |
| `analyze.py`、`accuracy.json` | 公共网格、Amesim存档及事件点的数值比较 |
| `trace_combined.py`、`event-validation.json` | 组合方案碰撞附近内部积分点检查 |
| `baseline/`、`cache_exact/`、`known_temperature/`、`pipe_root/`、`combined/` | 各自的C源文件、可执行程序、完整结果及日志 |
在仓库根目录,用 `.venv-win/Scripts/python.exe` 依次运行上述 `profile.py`、`experiments.py`、`microbench.py`、`benchmark.py`、`analyze.py` 可复现主结果。需要本机现有GCC及SUNDIALS开发环境。事件记录脚本会拒绝向既有记录追加,避免混合两次结果;重跑时应指定新的实验输出目录。
`/test` 按现有仓库规则被Git忽略;本报告进入文档目录。正式合入时需把通用实现和必要回归测试迁入对应源码目录,本轮实验代码不作为已经上线的功能。