Files
SystemSimulationApp/docs/other/求解器外层提前终止修复与验收-2026-09-14.md

95 lines
8.7 KiB
Markdown
Raw Permalink 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-14。分支:`system-optimization`。
## 结论
原先在 10.8 秒退出的八路模型,使用新封装完成 50 秒,纯求解墙钟时间 9.082 秒。旧封装在同一输入及当前组件实现下仍于 10.8 秒退出,确认本次修复针对外层判定,而非通过改模型参数避开问题。
新旧结果在前 10.8 秒的 1,082 个共同采样时刻、1,785 条序列(包括时间)上逐项完全一致。新封装共遇到 12 次成功返回但时间未变,最长连续 6 次,均自行恢复。当前四路、八路 corrected JSON 也均完成 50 秒。22 项相关自动测试通过。
## 处理规则
旧代码将 `flag < 0` 和 `next <= t` 合并为失败。两者含义不同:负返回码表示 CVODE 报告错误;成功的内部步可能小于当前时间的浮点分辨率,因此外部读取的时间暂时不变。
| 情况 | 新行为 |
| --- | --- |
| CVODE 成功返回且时间增加 | 正常处理接受步、采样和事件 |
| CVODE 成功返回但时间相同 | 保存 CVODE 当前状态与历史,继续调用;记录次数,不做零长度采样/事件处理 |
| 连续时间相同 | 不设置次数门槛;继续检查取消与当前整次求解的实际墙钟时限 |
| 超时发生且仍在上述停滞阶段 | 失败原因 `time-stagnation` |
| 其他实际求解超时 | 失败原因 `timeout` |
| CVODE 返回负错误码 | 立即报告 `solver-error`,保存失败操作、原始返回码和最后接受时间 |
| 时间倒退、越过请求边界或非有限时间/状态 | 分别报告 `time-regression`、`time-overshoot`、`nonfinite-time`、`nonfinite-state` |
| 接受步或状态切换超过既有保护上限 | 报告 `resource-limit`,明确具体上限类型 |
| 用户取消 | 保持取消状态;不会被后续 CVODE 回调错误覆盖为求解失败 |
| 积分器声称完成但未到请求终点 | 报告 `incomplete-result` |
时间相同的恢复路径不增加容差、不设置最小步长、不人为令时间增加,也不调用 `CVodeReInit` 跳过困难区间。既有信号分段边界和物理事件重启流程保留。
默认求解时限仍是 300 秒,Python 进程监控保留 5 秒退出宽限;这不是“某次停滞开始后再计 300 秒”。测试中的原模型使用 180 秒时限,实际远未触及。独立运行可通过已有 `--timeout` 设置时限。
CVODE 初始化、资源分配、配置 API,以及 BDF 步内采样与事件处理失败有独立操作/原因信息。CVODE 的正常停止返回码 `1` 不视为失败。返回码语义参见 [SUNDIALS 官方 CVODE 文档](https://sundials.readthedocs.io/en/latest/cvode/Usage/index.html)。
## Python 进程封装
同时修正进程监控中的分类问题:此前取消后进程不响应,被强制结束时也抛出“超过时间限制”的异常。
现在,取消后不响应且达到退出宽限的进程仍返回 `cancelled`,网页任务映射为 `stopped`。如果强制结束导致没有完整结果文件,则明确返回空轨迹和空最终量,只保留最后收到的时间及进度计数,标记 `resultAvailable=false`、`statisticsComplete=false`;不读取可能写了一半的结果,也不伪造未知的最终统计。
真正超出进程时限且没有取消请求,仍报告进程超时;自行崩溃则报告退出码。已经退出的进程不会仅因监控线程尚在读取日志而被误判超时。
正常结果新增 `solverControl` 字段,网页后端保存在 `diagnostics.native.solverControl`。包含原因、操作、返回码、同时间返回次数、最长连续次数及结束时 CVODE 内部时间与步长;这些 CVODE 数值字段只对 BDF 有意义。非有限诊断数字使用 JSON `null`,受控失败输出保留最后有效的接受状态。
## 模型验收
共同设置:BDF/CVODE 7.4.0,时长 50 秒,最大步长 `1e30` 秒,`rtol=1e-8`,采样间隔 0.01 秒,状态绝对误差限沿用生成器。原输入文件未修改;当前 corrected 文件仅在运行配置中延长时长。
旧封装对照使用临时 native 目录,仅将 `cvode_solver.c` 恢复为本轮修改前的 HEAD 内容;组件、生成器和其他当前运行库一致。因此该对照不是拿不同历史组件实现作比较。
| 输入与入口 | 结果 | 最终仿真时间 | 纯求解墙钟时间 | 同时间返回总数 / 最长连续数 |
| --- | --- | ---: | ---: | ---: |
| 原触发模型,旧 CVODE 封装 | 提前失败 | 10.8 s | 4.805 s | 旧封装不记录 |
| 原触发模型,新封装独立进程 | 完成 | 50 s | 9.082 s | 12 / 6 |
| 原触发模型,新封装网页后端入口 | 完成 | 50 s | 9.006 s | 12 / 6 |
| 当前八路 corrected,新封装独立进程 | 完成 | 50 s | 6.792 s | 0 / 0 |
| 当前四路 corrected,新封装独立进程 | 完成 | 50 s | 1.011 s | 0 / 0 |
上述时间是各次单次验收测量,不是速度基准测试;尤其旧封装只完成 10.8 秒,不能据此计算新旧加速比。纯求解计时包括积分、采样和事件处理,不含编译、进程启动及结果投影/文件写入。
原触发输入为 `test/mql8-50s-20260913/model-50s.json`,SHA-256:
`7c48a380e465ba5ee8a15610586325d14ac36a8cda5b3caa02053a8efc27fe47`
当前输入为 `tests/data/test-mql-8-corrected.json`、`tests/data/test-mql-4-corrected.json`。原触发模型保留历史循环信号,以覆盖旧故障;它与当前 corrected 模型用途不同,不拿它直接判定与 Amesim 的一致性。
独立进程三组完整输出均为有限数,采样时间严格递增。按输出气体质量相加核对闭合系统总质量漂移:原触发模型 `4.53e-14 kg`,当前八路 `2.58e-14 kg`,当前四路 `2.75e-14 kg`。网页后端入口走 JSON→XML→模型生成→原生进程→原始序列传输,返回 5,010 个采样点,接受步统计与独立进程一致。
本轮没有重新启动 Amesim 或新增组件语义对照;摩擦及管路的既有 Amesim 数值基准回归已通过。本次验收目标是封装正确终止及不扰动已有轨迹。
## 自动测试与故障注入
| 测试模块 | 方法数 | 验证范围 |
| --- | ---: | --- |
| `tests.test_native_solver_control` | 4 | 实际 CVODE + 临时注入:连续 1,000 次同时间成功返回后完整轨迹不变;负错误码、倒退、非有限时间/状态;持续停滞实际超时与取消;普通超时及既有资源保护 |
| `tests.test_native_worker_control` | 3 | 实际子进程拒绝退出时的强制取消、普通/原始序列两种传输、网页 stopped 合同、超时与崩溃分类;半写入文件不作为结果 |
| `tests.test_native_codegen` | 8 | RK45/BDF 完成与最大步长、取消、独立进程、缓存及默认 C 后端 XML 接口等 |
| `tests.test_native_result_transport` | 6 | 实际 HTTP/流式结果合同、取消、序列与索引完整性等 |
| `tests.test_native_friction` | 1 | 既有 8 组 Amesim 冻结数值基准,共 10 次 RK45/BDF 积分 |
| 合计 | 22 | 全部通过 |
注入代码只存在于测试创建的临时 C 源码副本,生产运行库没有注入开关。连续 1,000 次恢复测试同时核对轨迹、接受步、事件和重启次数,防止以隐蔽重启或丢失事件的方式“跑完”。
实测平台为 Windows、GCC 8.1、SUNDIALS 7.4.0。本轮遇到既有 GCC 子进程启动偶发故障,重试构建后完成测试,没有改编译器路径或工具链配置。新增测试采用公共 SUNDIALS API、Python 可移植子进程接口和路径处理;已加入 Linux 原生 CI,Windows CI 的完整发现也会包含它们。本机没有执行 Linux 实测,Linux 通过情况待 CI 验证。
## 交付与复现
- 运行库修改:`native/runtime/cvode_solver.c`、`common.c`、`main.c` 和 `native/include/runtime.h`。
- 进程封装:`app/simulation/native_codegen/runner.py`。
- 新增自动测试:`tests/test_native_solver_control.py`、`tests/test_native_worker_control.py`。
- 本机验收脚本:`test/verify_solver_wrapper_20260914.py`、`test/verify_solver_wrapper_backend_20260914.py`。
- 模型结果与摘要:`test/solver-wrapper-20260914/`;前缀逐项对照见 `prefix-comparison.json`。
- 测试日志:`test/solver-wrapper-control-20260914.log`、`solver-wrapper-worker-20260914.log`、`solver-wrapper-regression-20260914.log`、`solver-wrapper-friction-20260914.log`、`solver-wrapper-backend-20260914.log`。
`test/` 是本机忽略目录,包含大体积运行结果,不进入 Git;正式自动测试与本报告进入源码交付范围。重启后端后,新请求会使用更新的 Python 封装;C 运行库内容变化参与构建缓存键,正常构建会自动生成对应的新程序,无需手动清空缓存。此次未提交或推送远端,也未处理工作区已有的 Amesim 文件变更。