Files
SystemSimulationApp/native/README.md
T
ljz 7611f13208 修复循环信号与事件采样并接入 LSTP 接触定位,补充八路验证及复用实验
相较上一版 Jacobian 确定性复用更新,本次补齐事件边界一致性、结果两侧采样及接触事件定位;保留已有物性复用和组件力学公式。

- 统一 UD00 信号求值与下一事件查询的绝对时间边界,修复循环边界浮点舍入导致的阶段错位、重复或漏报,并覆盖零时长、多阶段及长周期场景。
- 引入原生输出语义 v2:保留规则网格真实时间,补充内部时间事件和状态事件的左邻及事件后采样,按保存时间、状态和离散模式重放结果。
- 两条代码生成路径均发出 LSTP 接触描述,默认定位间隙过零及非负力模式的力截断;仅在接受事件时更新防重复记录,增加 contactEvents 诊断计数。
- 补充 MASS/LSTP 独立事件实验、八路全曲线与驱动阶段配对评估,以及 Amesim 不连续点输出对照和力差定位报告;MASS 新增释放机制仍保留为独立实验。
- 保存局部 probe、context 访问与回退、shadow replay、R288 real skip/typed replay 及阀门数值尾部诊断工具和报告;未证明净收益的实验不启用为生产默认优化。
- 更新原生运行说明和元件建模规范,补充信号边界、输出语义、接触事件和实验依赖回归测试。

验证:五组专项回归共 34 项全部通过;37 个待提交 Python 文件语法检查通过;git diff --cached --check 通过。
2026-09-17 23:50:13 +08:00

165 lines
25 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 数值后端
MECMAS21 已支持静摩擦保持与脱离、高级低速区间和 Stribeck 过渡;内部摩擦状态随接受的事件更新并保存,BDF/RK45 共用该机制。LSTP00A、MECMAS21 弹性限位和 PNL0001/2/3 的本轮语义及 Amesim 实测范围见 [功能验证报告](../docs/other/Amesim摩擦与管路功能补齐验证-2026-09-13.md)。
后端 Python 校验 XML、检查连接、生成系统专用 C 并编译;独立 EXE 执行完整数值循环。原生运行不调用 Python。当前构建支持 Windows x64 和 Linux x86_64;Linux 使用静态链接的 SUNDIALS。
平台相关修改遵循 [Windows 与 Linux 交付约定](../docs/standard/跨平台交付约定.md)。缓存时间戳更新按 `os.supports_follow_symlinks` 检测运行平台能力,Windows 不支持该可选操作时对已校验的普通缓存目录使用常规 `utime`。缓存集成回归可在两平台使用真实工具链执行:`python -m unittest tests.test_native_cache_storage tests.test_native_cache_platform -v`;设置 `SIMULATION_NATIVE_REQUIRE_TOOLCHAIN=1` 时工具链缺失将失败而不会跳过。
两平台所需 Python 包、GCC、SUNDIALS 库文件和测试/剖析依赖见 [平台依赖说明](../docs/standard/platform-dependencies.md)。本轮 Jacobian 复用继续使用现有五个原生链接库;时间剖析使用同一 SUNDIALS 7.4 公共接口,不需要额外的 Python profiler 或自动微分库。
## 启用网页后端
当前默认使用 `native`。也可在启动后端的 PowerShell 中显式设置:
```powershell
$env:SIMULATION_NUMERIC_ENGINE = 'native'
$env:SIMULATION_NATIVE_CC = 'F:/Projects/mingw64/bin/gcc.exe'
$env:SUNDIALS_ROOT = 'F:/Anaconda/Library'
.venv-win/Scripts/python.exe -m uvicorn app.main:app --host 127.0.0.1 --port 8000
```
Linux 使用现有 Python 虚拟环境,并将 C 依赖独立放在 `.venv/native/`:
```bash
bash bat/setup-native-linux.sh
.venv/bin/python -m uvicorn app.main:app --host 127.0.0.1 --port 8000
```
脚本下载并校验固定版本 SUNDIALS 7.4.0,在本地构建静态库;不会安装系统包。构建器先读取 `SUNDIALS_ROOT`,未指定时查找当前 Python 环境的 `native/sundials-7.4.0`、`/usr/local` 和 `/usr`。Linux 安装需包含静态 `.a` 库;生成的 ELF 程序名为 `model`,不依赖 SUNDIALS 共享库或 Python。`.venv/`、`app/data/` 和 `test/` 均在 Git 忽略范围。
沿用 `/api/system-xml/simulate` 与 `/api/system-xml/simulate-stream`。`native` 遇到不支持的组件或方法时报告错误,不静默切换。旧 Python 后端已退役,显式选择 `python` 会报错。
`bat/start-backend.bat`、`bat/start-backend.sh` 及其 `start-all` 上层入口默认设置 `native`,保留明确指定的环境变量覆盖。直接通过 uvicorn 启动也使用相同的默认选择。启动日志显示所选内核;C 模式只检查工具链与 XML Schema,不再预热 SciPy 积分/代数求解器。工具链检查失败会记录启动诊断,编辑器仍可使用,提交仿真时会明确报错,不会自动调用 Python 数值后端。
通用诊断包含 `stateCount`、`sampleCount`。`pressureFlow`、`stream` 属于 Python 后端的可选诊断;C 后端不报告未计算的方程残差,网页仅在该值存在时显示它。
### 事件输出语义(version 2)
原生结果的 `outputSemantics` 描述采样合同。规则网格保持实际浮点时间,不吸附到附近事件。内部时间事件额外保存 `nextafter(event, -INFINITY)` 和事件时刻:前者是积分段的实际左侧终点,后者沿用连续状态、使用事件后的信号。状态重置事件在可用的积分区间内额外保存左邻时刻的插值状态,再保存事件后的接受状态。同一实际时间仍以后一次接受状态为准;时间序列严格递增,采样总数可能超过规则网格点数。
输出根据保存时间及完整状态重放;已有摩擦离散模式随状态保存。事件左邻样本是有限精度下的左侧样本,不声称保存了同一数学时刻的精确左极限。初始时刻或当前步起点的即时状态重置没有新的左侧区间,不倒填样本。仿真终点不额外制造一个时间事件。纯求解模式不增加采样或模型输出求值;此改动不注册新的机械事件。
与外部结果对照时,必须核验事件侧别。八路评估脚本使用全部 STEP/UD00 输出核验驱动阶段,所有变量共用同一对原始样本行;仅允许在输出间隔的 `1e-7` 范围内匹配时间舍入误差。无法匹配的点明确报告,不跨跳变插值、不根据力或压力误差选择样本。这个规则不代表已验证未注册的接触模式。
原生运行库已在本机 GCC 8.1 / SUNDIALS 7.4.0 验证。构建需要对应 C 头文件、导入库和 DLL,单纯安装 Python 包不能代替这些文件。构建器根据环境变量或当前 Python 基础环境查找 SUNDIALS,根据环境变量或 PATH 查找 GCC。
## 仿真结果分块存储
网页和 Python 原生运行入口将采样结果写入项目根目录的 `simresults/run-<id>/`,不依赖启动时的工作目录。每次运行保存 `manifest.json`、`states.bin` 与 `outputs.bin`;纯求解(`--solve-only`)不创建结果档案。此目录已加入 Git 忽略。
清单和返回诊断中的 `directory` 为相对项目根目录的 `simresults/run-<id>`,统一使用 `/`,`directoryBase` 为 `project`。读取时使用 `result_storage.result_archive_path(id)` 根据当前代码位置定位;旧清单中的绝对目录提示不参与定位。停止应用、移动或复制整个项目(保留 `simresults`)、重新启动后,结果随项目迁移。运行中传给原生进程的绝对路径由当前目录重新计算,不固定盘符或机器路径;不支持运行过程中移动项目目录。
- **容量**:默认 1 GiB(1,073,741,824 字节),通过后端环境变量 `SIMULATION_RESULT_STORAGE_MB` 配置,单位 MiB,必须是正整数。例如 PowerShell 使用 `$env:SIMULATION_RESULT_STORAGE_MB = '1024'`,Linux 使用 `export SIMULATION_RESULT_STORAGE_MB=1024`。按文件逻辑字节计量,不包含文件系统分配单元的额外开销。
- **自动清理**:写每个采样块前,为状态块及其未来输出块一起预留空间。总配额涵盖所有结果档案和元数据;空间不足时依次删除最早结束的非活动档案(异常退出且未结束的档案按创建时间排序)。跨进程锁保护配额分配和正在使用的档案。符号链接、目录联接及用户另外放入的文件不会被自动删除;这些内容仍计入目录用量。活动档案、孤儿但仍存活的工作进程被保留。旧结果属于可淘汰历史,需要长期保留的结果应导出另存。
- **空间仍不足**:停止采样并报告 `storage-quota`,保留此前完整提交的块,不删除当前运行的数据,不悄悄丢样后继续报告成功。结果诊断 `native.resultStorage` 分别记录求解状态、状态/输出样本数、已存储到的时间及有效字节数;已存储时间可能早于求解器最终到达时间。
- **有限缓冲与背压**:采样缓冲最多 1024 行,按状态和输出列数进一步限制到约 1 MiB(单行更大时至少容纳一行)。缓冲写满后复用;采用同步批量写入,磁盘慢时求解线程等待,没有无限增长的异步写入队列。求解结束后逐块计算和写入输出,再分块生成兼容 JSON,原生工作进程不分配完整历史状态或输出数组。
- **数值隔离**:只替换结果记录缓冲,保留 RK45/CVODE 当前状态、稠密输出和事件定位数据。输出计算维持原先的结束后顺序,避免在求解过程中改变模型缓存。相同时间戳沿用原有“后值替换前值”规则,包括块边界。
- **取消与异常**:正常取消、求解失败会补写最后一个不满的块。每块具有 CRC32 校验和提交标记;强制终止后可通过 `result_storage.scan_blocks` 扫描完整前缀,截断尾块和损坏块不计为有效样本。强制终止时尚未计算的输出不会被伪造,已有状态块仍保留。元数据通过临时文件替换发布;块完成执行 `fflush`,不逐块强制物理落盘,因此这不是断电零丢失承诺。
块格式为 `SIMBLK01` + 四个小端 uint64(块序号、行数、列数、CRC32)+ 按列连续的小端 Float64 数据 + `COMMIT01`;每个块的第一列是时间。各文件的完整列顺序由清单的 `metadata.stateColumns`、`metadata.outputColumns` 指定;纯代数模型内部占位状态以 `null` 标记。公开状态和变量元数据仍保存在 `metadata.stateKeys`、`metadata.variables`。Windows/Linux 共用格式和 64 位文件偏移。
本阶段保留现有完整 JSON 传输和浏览器加载契约:后端返回结果和浏览器显示时仍可能加载完整数据。变量/时间范围查询和浏览器按需加载属于后续阶段;现有百万采样点保护仍保留。
回归入口(Windows 和 Linux 使用各自的 Python 环境):
```text
python -W error::ResourceWarning -m unittest tests.test_result_storage tests.test_native_sample_storage tests.test_native_result_transport tests.test_native_worker_control -v
```
## 独立生成与运行
```powershell
.venv-win/Scripts/python.exe -m app.simulation.native_codegen tests/fixtures/native-skill-test.xml --output-dir test/native-v1/example-run --runs 3 --solve-only
```
输入支持 XML,或带普通算术表达式的工程 JSON。JSON 普通数字已经是 SI 值;算术表达式按编辑器所选单位换算,例如 `3.14*10**2/4 mm2` 转为 `0.0000785 m2`。较复杂的表达式应先在网页导出 XML。CLI 不执行任意 Python/JavaScript 表达式。
输出目录包含 `input.xml`、`model-manifest.json`、`program/`、预热和各次运行结果,以及 `summary.json`。`program/` 包含 EXE、生成的模型 C/头文件、SUNDIALS DLL 和依赖声明,可以复制整目录独立运行:
```powershell
test/native-v1/example-run/program/model.exe --method RK45 --start 0 --stop 10 --sample-step 0.02 --max-step 0.001 --rtol 1e-6 --output test/native-v1/standalone-result.json
```
EXE 不需要 Python、SciPy、XML 或原工程文件。DLL 需要与 EXE 一同保留。默认运行设置是 RK45、0–10 s、最大步长 0.001 s;按需要传入运行选项。
`--solve-only` 关闭轨迹采样,只输出最终状态与诊断。`solveSeconds` 是程序内部数值求解墙钟时间,包含求解必需的 RHS 和事件定位,排除模型初始化、求解结束后的结果投影与 JSON 写入;启用采样时包含积分期间分块写盘及等待配额的时间。`processWallSeconds` 另含进程启动与结果处理。预热一次后报告三次求解的中位数。
## 求解器外层终止行为
BDF 外层仅在 CVODE 返回负错误码、返回非法时间/状态或触发取消、实际超时及资源保护时结束。成功返回但时间暂时未变时保留求解器历史继续调用,不以重复次数判失败,也不人为推进时间或重启来跳过该段。持续不推进沿用当前整次求解的墙钟时限;默认 300 秒,Python 进程监控另有 5 秒退出宽限。用户取消后,进程仍不响应且被强制结束时返回取消状态,并明确没有完整结果文件,只保留最后一次进度报告。
独立结果的 `solverControl`(网页位于 `diagnostics.native.solverControl`)记录终止原因、操作、CVODE 返回码、同时间返回次数和最长连续次数,以及最后的内部时间与步长。CVODE 数值诊断仅用于 BDF。正常返回的 `1` 表示到达指定停止边界;非有限诊断数值写为 JSON `null`。取消/超时的原因不会被随后产生的 CVODE 回调错误覆盖。强制取消没有可信轨迹时,`series`/`final` 为空,未知求解统计不填零,`statisticsComplete=false`。
原八路 10.8 秒退出问题的对照复现、50 秒完成验证及异常分支测试见 [封装修复验收报告](../docs/other/求解器外层提前终止修复与验收-2026-09-14.md)。专项回归:`python -m unittest tests.test_native_solver_control tests.test_native_worker_control -v`。
## 雅可比分组差分与诊断
BDF 默认使用结构着色差分,无需环境变量或网页选项。修正八路的 132 个状态合并为 27 个扰动组,每次另算 1 次专用基准 RHS,共 28 次系统求值。普通积分 RHS、`rtol=1e-8` 和 Dense LU 沿用当前设置。用户已接受报告中的数值差异,正式网页与独立 C 程序采用同一默认策略。
旧 `SIMULATION_NATIVE_JACOBIAN` 选择器和 `--jacobian dense|auto|verify` 入口已删除。独立 C 程序仅保留无参数诊断标志 `--verify-jacobian`,它会逐次核对完整 canonical 雅可比矩阵,增加计算量,不用于速度测量。RK45 不构造雅可比。
无法证明结构、没有分组收益的模型继续使用必要的逐列差分;分组扰动失败时也保留 canonical 逐列恢复。这些是当前算法的兼容与恢复路径。当前启用及网页验证见 [正式启用报告](../docs/other/雅可比算法正式启用与网页验收-2026-09-11.md),机制、历史性能与误差见 [试验报告](../docs/other/雅可比结构着色试验与八路验证-2026-09-11.md)。
## 能力与限制
Jacobian 构建内现已按完整输入的浮点位复用储气物性、PH 温度反算、密度及管路求根结果,详见 [确定性复用说明](../docs/standard/native-jacobian-reuse.md)。独立耗时和求解计数调查工具见 [时间剖析说明](../docs/standard/native-solver-profiling.md);正常运行不加入该诊断插桩。
- 已实现当前注册的 27 类组件:22 类 Amesim 公开组件(含空气、氦气两种介质定义)和 5 类实验组件。完整清单及验证说明见 [组件覆盖记录](../docs/other/C内核组件库覆盖记录.md)。介质定义在编译期选择对应的 C 物性函数。
- 管路覆盖 PNL00R、PNL0001/2/3;阀覆盖 PNOR001、固定/信号开度 PNVO001 及面积/Cv/Kv 模式;连接件覆盖 PN3NODE2、P4NODE2、LMECHN1。支持串联阻力的压力求解、节点焓混合及温度参考、刚性质量合并、兼容管路容腔的等密度状态投影。
- MECMAS21 支持现有 Python 方程中的摩擦、风阻、柔性限位和 `stoptype=1/2/3/4`,含反弹系数与速度阈值;气腔和管路支持换热。LSTP00A 接受两种刚度模式及接触力符号模式,严格沿用当前组件方程。已有参数中尚未参与 Python 方程的物理效应不会在 C 端凭空补造,详见覆盖记录。
- 扩展编译器上限 1024 状态、16384 输出;无连续状态的信号系统使用隐藏常量状态驱动输出。气动网络必须有压力状态锚点;独立气腔之间不能无阻力直接相连。兼容固定管路容腔是已实现的合并例外。闭合未收敛或方程欠定时明确失败,不静默回退。
- 支持原生 RK45 与 CVODE BDF。CVODE 默认按可证明的结构启用着色差分,使用稠密线性求解;不支持分组的模型自动保留逐列差分。
- 网页和 Python CLI 默认 `rtol=1e-8`;生成的状态绝对误差限为质量 `1e-14 kg`、内能 `1e-8 J`、速度/位移 `1e-12`(各自 SI 单位)。独立 C 程序默认 `rtol=1e-6`,对照时应显式传入。CLI 可覆盖 rtol;本版不支持自定义 atol 或 first_step。不同积分器相同局部容差不保证全局曲线误差完全相同。
- 时间信号显式分段,塑性/反弹端挡用稠密插值定位并重启。LSTP00A 默认定位间隙过零;非负力模式还定位接触区内的原始力过零。两个生成路径均从机械状态索引发出 `NativeContact` 描述,检测不调用整模型 RHS,接触事件不重置位移/速度。试探 RHS 不修改已接受状态,接触力仍用原分段公式。MASS 弹性限位及连续释放的独立实验没有合入默认路径。
- LSTP 的防重复触发记录仅在接受事件时提交,不参与 RHS、雅可比或输出重放;同一浮点时刻的接触事件合并重启,并沿用输出语义 v2 保存两侧。结果的 `contactEvents` 提供检查、密集插值、二分和接触/力截断计数。相对速度换向时分段检测同号间隙的中间过零;这依赖已解析的积分步,不能保证捕获一步内任意多次未解析振荡。专项见 `tests/test_native_contact_events.py`。
- 每任务独立进程,支持进度、取消及超时。进程崩溃不会作为成功返回,受控失败保留最后接受状态。
- 编译缓存位于 `app/data/native-builds/`:`models/<SHA>/` 保存完整模型,`objects/<SHA>/` 保存可跨模型复用的模块目标文件。按当前模型使用的元件函数及其依赖选择模块,最多并行编译 4 个缺失单元。预处理后的实际 C 内容、工具链和编译选项组成对象键;完整模型键另含生成源码、组件合同及链接依赖。模型数值参数仍特化入 C,但仅重编受到影响的单元;时间、步长、rtol、采样选项仍是运行参数。
- 完整模型默认预算 256 MiB、对象预算 128 MiB,可分别设置非负整数环境变量 `SIMULATION_NATIVE_MODEL_CACHE_MB`、`SIMULATION_NATIVE_OBJECT_CACHE_MB`。按目录最近使用时间执行 LRU;活跃构建/运行及最后一个单独超额的条目保留并报告超额,因此是安全软上限。预算计算受管理文件的逻辑字节,不含旧版根级缓存、锁及文件系统元数据。
- 缓存读写带跨进程使用锁,命中时核验工件和身份,损坏缓存明确失败。对象复制到构建私有目录后再链接;模型使用锁一直保留到进程退出和结果读回。失败正常清理临时文件;进程被杀遗留的新格式构建目录在下一次清理时按锁状态回收。旧格式缓存保留,不自动迁移或删除,避免影响旧服务。
- Python 调用者若长期保留 `NativeBuild`,需在最后一次执行/打包后调用 `build.close()` 释放使用保护并触发清理;网页 runner 自动处理。返回的 `buildDetails` 区分完整命中、目标文件命中/编译次数、预处理、并行编译墙钟、编译任务耗时之和、链接和容量清理结果。
## 代码职责
后端启动后会异步执行原生环境自检,编辑器和 API 无需等待。首次检测失败后最多再重试 5 轮,共最多 6 次检测;每轮失败后等待 0.5 秒再开始下一轮,任一轮成功即停止。自检使用现有 `SIMULATION_NATIVE_CC`/PATH、`SUNDIALS_ROOT` 和默认探测方式,不写入机器专用编译器路径。它与正式构建共用编译选项和链接库,依次预处理、编译、链接并运行一个一状态 BDF 程序,核对已知解和成功标记;每轮都实际编译,不使用模型缓存。
`GET /api/simulation/runtime-check` 只读取本次启动自检的状态,返回当前阶段、轮次、结果和耗时,不触发新的检测。网页仿真控制台显示阶段变化;中间失败只提示未通过及正在重试,不展示报错详情,后端也不立即打印异常堆栈。全部检测失败后才显示最后一次的失败阶段、编译器、命令、工作目录、退出码及错误输出。进程未启动时退出码为 null;stdout/stderr 各保留最后 8000 字符。终态响应中的 `attemptHistory` 保留各轮结果、耗时和失败详情,便于追查首次故障;`durationMs` 是包括重试等待在内的总耗时,`startedAt`/`finishedAt` 使用 UTC 时间。
检测及重试期间每 0.5 秒查询,结束后停止定时查询;切回页面时读取一次结果以识别后端重启。提示明确描述“本次启动自检”,不代表持续的健康监测,也不改动仿真进度或阻断编辑器。检测通过仅表示本次工具链检查通过,不保证任意模型都能仿真成功。
Windows 使用 EXE 和与正式构建相同的 DLL 复制规则;Linux 使用现有静态库及链接分组规则。临时自检程序位于 `app/data/native-runtime-checks/`,正常完成、失败或取消后清理,避免 Linux `/tmp` 的 noexec 挂载产生误报。编译各阶段有 30 秒超时,运行有 10 秒超时;取消/超时会终止本次检测创建的进程树。既有 `SIMULATIONAPP_WARMUP=off` 仍可关闭检测,网页会明确提示已关闭。后台服务不会因普通自检失败而退出,也不会自动修改 PATH 或切换求解内核。
- `app/simulation/native_codegen/input.py`:CLI 输入适配。
- `contracts.py`:逐组件 C 实现版本白名单,新增模型或版本不会自动视为已支持。
- `compiler.py` / `extended.py`:能力检查、状态/输出布局、连接分组、常系数约束消元、C 生成。保留已验证的简单拓扑快速生成路径,两条路径均只运行 C 数值代码。
- `build.py` / `modules.py` / `cache_storage.py`:按需模块、两层编译缓存、完整性校验与有界 LRU;`runner.py`:隔离执行、使用保护与结果适配。
- `native/components/modules/`:物性、孔口、管路、机械和信号模块。`kernels.c` 仅供诊断的聚合入口,生产构建不再将聚合入口与模块重复编译。
- `native/runtime/`:RK45、CVODE 适配、事件定位、采样与 CLI。
- `app/simulation/backends.py` / `results.py`:共用执行入口与结果合同。
执行 `.venv-win/Scripts/python.exe -m unittest tests.test_native_catalog tests.test_native_codegen tests.test_simulation_warmup` 可验证全部注册合同、空气/氦气正反向流、换热/摩擦、节点和串联闭合、刚性与管路状态合并、反弹事件、纯信号系统、缓存、独立 EXE、取消及默认 C 的 XML 接口。新增组件库对照测试需要可用的 C 工具链。
## Python 保留范围
- `app/main.py`、`system_xml.py`:HTTP、XML 校验与结果返回。
- `registry.py`、`core/`、`components/`、`systems/network.py`:参数、端口、介质常量、输出与方程结构声明;不执行模型数值公式。
- `native_codegen/`:生成系统 C、构建缓存、管理独立进程。
- `config.py`、`sampling.py`、`results.py`:配置、进度、采样合法性和结果合同。
- `performance.py`:Python 编排阶段计时,求解耗时读取 C 报告。
`solvers/`、`systems/generic.py`、旧示例、Python 物性/流量/机械公式和物性缓存已删除。数值回归读取 `tests/baselines/native/native-python-reference.json` 的 50 个网络、112 组冻结参考状态,不需要 Python 求解器。旧算法及历史对照资料可从 Git 历史找回。
测试安装:`python -m pip install -r requirements-test.txt`。完整数值测试需要 GCC 与 SUNDIALS;Windows x64 使用导入库/DLL,Linux x86_64 使用静态库。
## AME 对齐后的工程输入
当前用户运行请使用 `tests/data/test-mql-4-corrected.json` 或 `tests/data/test-mql-8-corrected.json`。执行 XML 从当前 JSON 按需生成;原独立四路 XML 和 legacy 八路夹具已删除。历史八路 JSON/XML 在 `tests/baselines/simulation/test_mql_8/sources/`,其 AME 在 `tests/data/AmesimModels/test_mql.ame`,仅用于冻结基准核对,不能与当前 corrected 输入混用。路径、生成方式和测试入口见 [测试文件说明](../tests/data/README.md)。`test-mql-4-amesim-reference.json` 是曲线基准,不是工程输入。模型复核、P4 端口图形修正、默认 `rtol=1e-8` 的验收和速度记录见 [本轮验证报告](../docs/other/牛顿管流求根与四路网页验证-2026-09-11.md)。
后续优化和网页计时默认使用修正后的八路工程;仅当八路无法运行且短期不能解决时退回四路。选择规则见 [优化验证约定](../docs/standard/optimization-benchmark-model.md),当前效率、迭代触顶与网页分阶段记录见 [八路评估报告](../docs/other/八路模型计算效率与网页阶段计时-2026-09-11.md)。
## 结果传输与网页后处理
网页流式请求使用 C 的可选 `--result-index` 字节索引,Python 只解析小元数据,将原有 JSON 的 `series` 原样放入 NDJSON 结果事件;任务结果查询同样支持原样返回。独立 CLI 与默认同步调用仍返回普通 JSON/结果对象,JSON结构、积分和采样保持一致。前端结果保存改为打包 Float64 块的原子事务,CSV 由工作线程本地生成,兼容旧缓存及旧 HTTP CSV 接口。完整结果、取消与刷新回归及八路前后计时见 [结果处理优化报告](../docs/other/八路结果处理与网页保存优化-2026-09-11.md)。
C结果的 `series/final/finalState` 现使用固定版本Ryu binary64编码及64 KiB批量写出;在精确回读前提下选择更短的普通/科学token,负零保留为 `-0.0`,非有限值或写出失败阻止索引发布。数字文本允许变化,索引元数据保持整数。嵌套Ryu头文件参与缓存哈希;源码和Boost许可随项目保留。本轮研究、逐位验证和八路网页前后计时见 [C结果编码优化报告](../docs/other/C端结果编码与写出优化-2026-09-11.md)。