Python内核代码移除,建模界面缩放bug修复

This commit is contained in:
ljz committed 2026-09-10 11:57:39 +08:00
1 parent 743663e3a6
commit 0dcb465d84
27 files changed
+354 -6092

No files matched your search

-264
View File
@@ -1,264 +0,0 @@
# 全系统数值中间表示(System Numeric IR)规范 v2.0
> 2026-09-10 集成说明:保留本规范、schema、签名与静态校验。依赖旧 `GenericFluidSystem` 的 Python 对象导出器已随旧数值内核退役,调用 `compile_system_ir()` 会明确报错。当前可执行 C 路径使用 `native_codegen.compiler.compile_native_program(network)`,尚未按本 v2 结构输出执行计划;不能把当前 C 支持等同于本规范的 native 能力声明。原导出结果固化在 `tests/data/system-ir-v2-reference.json.gz`,继续验证 schema 与复杂计划的错误检查。
状态:C-01 已实现并冻结 v2.0 数据合同;当前编译结果为 `reference_only`,原生 kernel 与执行器属于 C-02/C-03 及后续工作。
适用范围:后端 `GenericFluidSystem` 编译后的整个仿真系统。
机器可读定义:`schemas/system-numeric-ir-v2.schema.json`。
## 1. 定位与边界
System Numeric IR(以下简称 IR)描述“一个已经解析并编译好的系统,数值求解时需要哪些数据、按什么关系执行”。它是系统级合同,不是单个部件的文件。
```text
XML / 建模 JSON
→ 模型解析和连接检查
→ GenericFluidSystem 对象图
→ System IR v2.0
→ 参考执行器 / 未来原生执行器
```
XML 保存用户建立了哪些元件、参数和连线;IR 在此基础上补充求解器真正需要的槽位编号、状态降维、方程块、执行阶段、闭合范围、事务回滚、事件、Jacobian 和输出投影。因此二者看起来相似,但用途和层级不同。
本版本只完成“完整、确定、可校验的数据合同”和从现有系统生成该合同的编译器。它没有替换当前默认 Python 求解路径,不改变现有仿真结果。IR 中禁止保存 Python 函数、闭包、模型对象、对象地址和运行期临时状态。
## 2. 三个权威来源
三份实现共同定义 v2.0:
- `app/simulation/ir/schema.py`:Python 不可变数据类型、枚举、规范序列化和签名算法;
- `schemas/system-numeric-ir-v2.schema.json`:跨语言 JSON 结构合同;
- `app/simulation/ir/validation.py`:仅靠 JSON Schema 无法表达的引用、覆盖、拓扑和数值语义校验。
生产者必须同时满足机器 Schema 和语义校验。字段有增删时必须同步修改三处以及合同测试,不能只更新文档。
## 3. 版本、兼容性和严格读取
版本不是顶层整数,而是 `version` 对象:
```json
{
"$type": "schema_version",
"schema_id": "system-numeric-ir",
"major": 2,
"minor": 0
}
```
- `major` 改变表示不兼容的字段或执行语义变化;读取方必须拒绝未知主版本。
- `minor` 用于同一主版本内向前演进;当前读取方拒绝负数和高于自身能力的次版本。
- JSON Schema 对所有合同对象使用 `additionalProperties: false`,v2.0 读取方不会静默忽略未知字段或枚举值。
- 原生二进制 ABI 不写入 `SystemIR`,而由独立的 `IRNativeBuildIdentity.abi_version` 管理,当前值为 `1`。
- 压力流量中的 `causal_plans.source_schema_version == 1` 只表示其来源是既有 causal IR v1;它不是完整系统 IR 的版本,也不能携带 v1 的 Python 回调。
## 4. 线格式和顶层结构
每个 dataclass 序列化后都带有稳定的 `$type`;操作对象还带有 `opcode`。顶层 `$type` 为 `system_ir`,其字段完整集合如下:
| 字段 | 含义 |
| --- | --- |
| `version` | IR schema 身份与版本 |
| `model_id` / `model_version` | 输入系统的稳定身份和调用方提供的模型版本 |
| `compiler_id` / `compiler_version` | 产生 IR 的编译器身份,当前为 `generic-fluid-system` / `2.0.0` |
| `numeric_dtype` | 主数值类型,v2.0 只接受 `float64` |
| `buffers` / `values` | 连续缓冲区及每一个数值槽位的元数据 |
| `kernels` / `components` | kernel 声明与元件实例绑定 |
| `mediums` | 介质实现、介质常量和使用该介质的元件 |
| `ports` / `connections` | 端口变量和系统拓扑 |
| `state_reducer` | 求解器状态与元件局部状态/导数的线性映射 |
| `causal_plans` / `pressure_flow` | 因果子计划和完整压力流量方程计划 |
| `stream_plans` / `thermofluid` | stream SCC/DAG 与热流体外层闭合计划 |
| `stages` / `blocks` | 无回调操作阶段与复合/迭代执行块 |
| `entry_points` | `rhs`、`events`、`jacobian`、`outputs` 四个入口 |
| `transaction` | 试算快照、流量恢复和参考缓存诊断 |
| `modes` / `events` | 离散模式、根函数、reset 与缓存失效 |
| `jacobian` | 固定 CSR 结构、着色和局部有限差分计划 |
| `outputs` | 结果元数据和投影 |
| `capabilities` | 系统和元件的原生可执行能力及缺口 |
| `required_features` | 读取/执行该程序必须理解的功能 ID |
所有列表的顺序都是合同的一部分。引用统一采用数组索引或稳定 ID,不能依赖哈希表遍历顺序。
## 5. 规范序列化与内容签名
`canonical_json_bytes()` 是跨平台唯一线表示:
- UTF-8,ASCII 转义开启,JSON 键排序,无无意义空白;
- 字符串先做 Unicode NFC 规范化;
- tuple 写成 JSON array,不接受 list、dict、set 或任意对象;
- 浮点数写成 IEEE-754 binary64 大端十六进制对象,例如 `{"$float64":"3ff0000000000000"}`;
- `-0.0` 统一为 `+0.0`,NaN 和正负无穷直接拒绝;
- 枚举写成规范字符串,整数和布尔值保持其 JSON 类型。
`SystemIR.structural_signature` 是上述完整 `SystemIR` 内容字节的 SHA-256 小写十六进制值。它准确回答“这份 IR 内容是否完全相同”,包含参数值和所有计划,因此不声称不同表达形式的数学系统会得到同一签名。操作系统、机器路径、构建时间、编译器和 native flags 不进入这个签名。
## 6. 缓冲区、槽位和值
槽位引用的格式为 `{"$type":"slot_ref","buffer":"...","index":N}`。v2.0 恰好声明以下 16 类缓冲区,每类一次:
| dtype | 缓冲区 |
| --- | --- |
| `float64` | `time`、`state_input`、`derivative_output`、`local_state`、`local_derivative`、`algebraic`、`signal`、`parameter`、`constant`、`work_float`、`event_output`、`jacobian_value`、`result_output`、`runtime_input` |
| `int32` | `mode`、`work_int` |
`time` 的长度必须为 1;`int32` 初值必须在有符号 32 位范围内。每个缓冲区内索引为 `[0, size)`,而且每一个实际槽位必须恰好有一个 `IRValueSpec`。值描述包含稳定 ID、语义、角色、物理量、单位、缩放、可选上下界和可选所属元件。缩放必须为正有限数,边界必须有序且有限。
缓冲区是执行器唯一的数值寻址合同。名称用于诊断,不允许执行器重新用名称查找取代槽位访问。
## 7. Kernel 与元件绑定
`IRKernelSpec` 声明模型类型、模型版本、实现版本、能力、支持的 phase 以及参数/状态/mode/workspace 数量。phase 枚举为:
`primal`、`residual`、`derivative`、`property`、`event`、`reset`、`jacobian`、`output`。
phase 在 C-01 中只是稳定的功能标签。不同模型在同一 phase 下可能有不同输入输出数量,所以不能在 phase 上填写虚假的统一 arity。当前每个 `IRKernelCallOperation` 自身的有序 `read_slots`、`write_slots` 和 `equation_indices` 才是该次调用的权威依赖合同。C-02 将在此基础上冻结每个 `kernel_id + phase` 的纯数值调用签名并验证所有调用实例一致。
`IRComponentInstance` 把一个元件实例绑定到 kernel,并明确列出参数、局部状态、局部导数、mode、端口、输出和两类 workspace。绑定数量必须与 kernel 声明一致;端口和输出必须与其反向所属关系精确一致。
当前编译器把所有既有 Python kernel 标记为 `reference_only`。为便于结构审计,reference kernel 调用声明了保守读集合:可能多读,但不能漏掉模型对象当前可见的数值输入。Python 内部隐藏缓存仍不是原生槽位,因而任何含这类依赖的程序都不得宣称 `native`。
## 8. 介质、端口和连接
介质记录稳定 `medium_id`、名称、实现及其版本、常量槽位和使用它的元件索引。介质参数必须位于 `constant` 缓冲区。
端口分为 `physical` 与 `signal`:
- 物理端口必须声明正流方向,当前统一为 `intoComponent`;
- signal 端口不得声明物理流向;
- 变量角色与连接规则固定对应:`effort → equal`、`flow → sumToZero`、`stream → streamMix`、`signal → directed`。
连接必须引用两个已声明、不同、同 kind/同 domain 的端口,并精确覆盖两个端口的全部同名变量合同。物理端口和 signal 输入最多被一条连接占用;signal 输出允许扇出到多个输入。禁止重复端点对和悬空索引。
## 9. 状态降维与导数汇总
`IRStateReducer` 使求解器的 `state_input` 与各元件 `local_state` 分离。`state_reducer.initial_state` 是状态初值的语义描述,必须与 `state_input` 缓冲区的初值逐项完全相同,避免消费者面对两个不同初值:
- `state_scatter` 用 CSR 矩阵把求解器状态散射到有序局部状态槽位;
- `derivative_gather` 把有序局部导数汇总为 `derivative_output`;
- `initial_state` 与 `absolute_tolerances` 按求解器状态顺序定义。
这能显式表达共享机械坐标和气动储能状态的降维关系。例如同一气动储能状态可以按体积权重散射到多个局部状态,而不是由执行器临时按对象身份猜测。两个矩阵必须满足 CSR 不变量、维度和值数量合同,并覆盖全部组件状态/导数绑定。
## 10. 压力—流量计划与因果元数据
`IRPressureFlowPlan` 包含:
- `unknowns`:未知量的元件、端口、变量角色、槽位、缩放和边界;
- `equations`:元件或连接拥有的方程、关系、涉及槽位、残差槽位和缩放;
- `blocks`:未知量/方程的方块分解及每块 Jacobian CSR 结构;
- `scopes`:全网、敏感物理岛或方程块作用域及求解限制;
- `global_scope_index` 和 `secondary_scope_indices`:第一次全网求解与后续局部重算范围;
- `pressure_lower_bound`:全局压力下界。
全局 scope 必须覆盖完整网络;每个 scope 的未知量和方程必须等于它包含的 blocks 之并集;secondary scope 唯一且不能包含 global scope。每条方程必须拥有唯一的 residual 槽位,防止两个残差互相覆盖。`sparse_pattern_trusted=false` 时必须给出回退原因,可信结构则不得携带回退原因。
`IRCausalPlan` 保存当前 causal IR v1 编译得到的无回调元数据,包括作用域、规范/兼容/重置槽位、外部 effort、effort 阶段和 flow 阶段。它只作为 v2 压力流量计划的一部分,不代替完整系统计划。
## 11. 操作、阶段、执行块和四个入口
v2.0 的无回调 opcode 为:
`fill`、`copy`、`scatter`、`linear_combination`、`state_map`、`kernel_call`、`effort_broadcast`、`flow_assign`、`check_finite`。
`IRStage` 给出 stage kind、操作序列以及声明的读/写集合;声明集合必须与操作读写并集完全一致。`IRExecutionBlock` 可以按顺序引用 stage 或其他 block;引用图必须无环。`fixed_point` 和 `stream_scc` block 必须声明监控槽位、绝对/相对容差、最大迭代、松弛、回滚槽位和失败策略,其他 block 禁止携带收敛合同。
四个入口必须恰好各一个,且入口输入统一按 `time`、完整 `state_input`、完整 `runtime_input` 排列:
| 入口 | 必须到达的结果阶段 | 精确输出缓冲区 | 不允许夹带 |
| --- | --- | --- | --- |
| `rhs` | `derivative_reduce` | 全部 `derivative_output` | event、Jacobian、output、reset |
| `events` | `event` | 按事件顺序的全部 `event_output` 根槽位 | derivative reduce、Jacobian、output、reset |
| `jacobian` | `jacobian` | 按 CSR 顺序的全部 `jacobian_value` | event、output、reset |
| `outputs` | `output` | 按结果顺序的全部 `result_output` | event、Jacobian、reset |
入口可以复用前置 primal 阶段,但不能把四个入口合并成“每次 RHS 都把事件、Jacobian 和全部输出计算一遍”。入口执行不得写入 `state_input`、`parameter`、`constant` 或 `mode` 等持久输入。
## 12. Stream、热流体闭合和事务
`IRStreamPlan` 显式列出 stream 节点、强连通分量(SCC)、SCC 间缩点 DAG 和拓扑顺序。每个 SCC 对应一个 `stream_scc` block,循环只在 SCC 内迭代;监控槽位必须覆盖该 SCC 节点。
`IRThermofluidPlan` 覆盖全部物理端口,关联 stream plan、全局元件集合、敏感元件、secondary 压力 scope、最大迭代和流量相对容差。是否使用保守全网求解及原因必须成对出现,避免执行器静默扩大作用域。
`IRTransactionPlan` 冻结一次试探计算需要快照和恢复的端口变量,并单列实际活动气动端口上的 `m_flow`。当前目标系统中的这部分数量为 232;机械模型对象里没有作为活动端口变量出现的隐藏 `m_flow` 字段不会被误算进该集合。所有失败试算必须恢复快照;正常成功返回即为隐式提交,不另设可被误排序的 commit opcode。
`cache_component_indices`、`cache_attribute_ids` 和 `diagnostic_owner_ids` 只记录当前 Python 参考路径中仍需关注的隐藏副作用,供 C-02/C-03 清除和 Shadow 诊断;它们不是原生内存布局。存在 opaque Python cache 属性的系统不能标记为 `native`。
## 13. 模式、事件和 Reset
每个 `IRModeSpec` 记录 int32 mode 槽位、所属元件、合法值及初值。模式槽位必须全部且只被一个 mode 说明,组件 mode 绑定与 owner 关系必须双向覆盖。
每个 `IREventSpec` 记录稳定事件 ID、事件类型、owner、根槽位、触发方向、终止性、优先级、mode guard、reset steps、失效缓存种类以及是否重启积分器。reset 只能引用 `reset` stage,事件根槽位必须精确覆盖 `event_output` 缓冲区。
当前 IR 已能表达现有元件暴露的事件和模式结构;仍隐藏在 Python 信号求解或机械密集输出逻辑中的行为属于 `reference_only` 能力缺口,必须在 C-02/C-08 显式化后才能原生执行。
## 14. Jacobian 合同
`IRJacobianPlan` 包含固定 CSR pattern、与非零项一一对应的 `value_slots`、颜色组、填充值步骤、解析 value 索引和局部有限差分列。
CSR 必须满足:`row_pointers` 长度为行数加一、首项为 0、单调不减、末项等于非零项数量;每行列索引递增、唯一且在范围内。颜色组中的列不能共享同一潜在非零行,列不能重复着色。解析项和有限差分项不得重复或越界;每个有限差分列只能填写该列在 CSR 中确实存在的 value 索引,步长必须为正有限数。Jacobian 入口的执行步骤必须与 `fill_steps` 完全一致。
结构可以保守地多报潜在非零项,但不能漏报可能依赖。结构、模式布局或 kernel 实现改变会自然改变整份 IR 内容签名。
## 15. 输出合同
每个 `IROutputSpec` 包含稳定 output ID、所属元件、scope、可选端口名、内部名、显示标签、类别、物理量、单位、局部顺序、来源槽位、结果槽位以及线性 scale/offset。
`output_id` 和 `result_output` 槽位在全系统唯一。`order` 只在 `(component_index, scope, port_name)` 内排序,因此不同元件出现相同 `order` 是合法的;全局最终列顺序由 `outputs` 数组顺序确定。组件的 `output_indices` 必须精确反向覆盖其所有输出。
## 16. 能力报告与拒绝规则
能力级别只有:
- `native`:所有 kernel phase、状态、事件、事务和缓存都满足原生合同;
- `reference_only`:数学/结构已描述,但至少一个阶段仍依赖 Python 参考实现;
- `unsupported`:当前 IR 无法安全表达或执行,必须带 error 级能力问题。
每个元件必须恰好有一条 capability,列出支持 phase 与缺失 feature。系统为 `native` 时所有元件和 kernels 都必须是 native,且不能依赖 opaque Python cache;系统含任意 reference-only 元件时不能伪装为 native。能力问题具有 code、severity、scope ID 和消息,相同 code/scope 不得重复。
当前 `compile_system_ir()` 的输出明确为 `reference_only`,原因是 C-02 的纯数值 kernel 签名与 C-03 的扁平参考执行器尚未完成。这不是 IR 编译失败,也不允许 native loader 越过能力报告运行。标为 native 的系统还必须覆盖所有实际调用 phase,并且不得要求 `reference_kernel_dispatch`。
## 17. 原生构建产物键
二进制缓存身份与 IR 内容签名严格分离。`native_artifact_key(program, build)` 对以下信息再次做规范序列化和 SHA-256:
- `program.structural_signature`;
- native ABI 版本;
- target triple;
- 编译器 ID 与版本;
- 有序编译 flags;
- 浮点策略;
- kernel 库 SHA-256 签名。
ABI 必须等于当前支持值,字符串不能为空,flags 不能含空项,kernel 库签名必须为 64 位小写十六进制。这样相同 IR 在 Windows/Linux 上具有相同内容签名,但得到不同且安全的 native artifact key。
## 18. 编译、校验和消费流程
当前公开入口为:
```python
from app.simulation.ir import compile_system_ir, require_valid_system_ir
program = compile_system_ir(system, model_version="...")
require_valid_system_ir(program)
payload = program.canonical_json_bytes()
signature = program.structural_signature
```
`compile_system_ir()` 接收已完成解析和系统构建的 `GenericFluidSystem`,不直接解析 XML。消费者必须先验证,再根据 `capabilities.system_level` 选择参考路径或未来原生路径;不得把“JSON Schema 能读取”误当成“具备 native 执行能力”。
静态校验采用 fail-closed 策略,覆盖:版本与 required feature、全部槽位、数值范围、组件/kernel arity、端口/连接、介质、状态映射、压力流量方程与 scope、阶段读写、block 无环、四入口切片、stream/热流体、事务、mode/event/reset、Jacobian、输出及能力一致性。`require_valid_system_ir()` 聚合错误后拒绝程序。
## 19. C-01 验收边界与后续工作
C-01 的完成标准是:
- 能从当前目标复杂模型和历史 0.81 s 模型生成完整系统级结构;
- 同一系统重复编译得到字节完全相同的 canonical JSON 和签名;
- 换行方式、Python 哈希种子和目标平台不会污染 IR 内容身份;
- 故意破坏引用、覆盖、CSR、事务、入口或能力合同会被拒绝;
- IR 中没有 callback、对象地址或任意 Python 对象;
- 默认 Python 仿真路径保持不变。
C-01 不等于已经拥有可运行的 C 后端。下一步 C-02 要冻结每个 kernel 的纯数值签名、隐藏缓存和错误码;C-03 要用扁平 Python 执行器逐槽 Shadow 对照;完成这两项后,才可以建立 C ABI、原生执行器并逐步把 capability 从 `reference_only` 提升为 `native`。