Files

286 lines
12 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.
# System XML v3 协议
System XML v3 是 SystemSimulationApp 当前唯一的 XML 求解输入格式。它只描述可执行模型,不再承担 ReactFlow 画布存档职责。
机器可读结构见 [`schemas/system-simulation-v3.xsd`](../../schemas/system-simulation-v3.xsd)。当前校验、解析、编译和仿真接口固定按 v3 处理,不会根据 `schemaVersion` 自动切换到 v1 或 v2。
## 1. 设计边界
v3 遵循一条简单规则:
> XML 保存“求解什么”,工程 JSON 保存“怎样编辑和显示”。
因此 XML 保留:
- 仿真起止时间、结果采样间隔、内部最大步长和积分方法;
- 组件实例 ID、后端模型类型、模型版本和完整 SI 参数;
- 每条连接的两个端点。
XML 不保存:
- 组件显示名称、画布坐标、旋转、镜像;
- 图标、端口显示侧和显示顺序;
- 端口的 `kind/domain/nominalRole/positiveFlowDirection/variables` 快照;
- 参数表达式、显示单位、科学记数法偏好;
- ReactFlow 的选择状态、撤销历史或仿真结果。
这些信息中,编辑器状态留在工程 JSON;端口物理合同由 `Component.type + Endpoint.port` 从后端组件注册表恢复。
## 2. 完整结构示例
下面的例子包含一条信号连接和一条机械连接,展示 v3 的全部结构元素:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<System name="signal-force-demo" schemaVersion="3" unitSystem="SI">
<Simulation
tStart="0"
tStop="1"
sampleStep="0.01"
maxStep="0.001"
method="BDF"/>
<Components>
<Component id="step_1" type="amesim_step0" modelVersion="0.1.0">
<Parameter name="initial" value="0"/>
<Parameter name="final" value="0"/>
<Parameter name="time" value="0.5"/>
</Component>
<Component id="force_1" type="amesim_forc" modelVersion="0.2.0">
<Parameter name="direction" value="1"/>
</Component>
<Component id="zero_1" type="amesim_f000" modelVersion="0.1.0"/>
</Components>
<Connections>
<Connection id="signal-1">
<Endpoint component="step_1" port="out"/>
<Endpoint component="force_1" port="res"/>
</Connection>
<Connection id="mechanical-1">
<Endpoint component="force_1" port="port_2"/>
<Endpoint component="zero_1" port="port_1"/>
</Connection>
</Connections>
</System>
```
XML 的外形是一棵树,模型本身仍是一张连接图。组件平铺在 `Components` 中,`Connections` 再用 `(component, port)` 地址建立拓扑。
固定骨架为:
```text
System
├─ Simulation
├─ Components
│ └─ Component *
│ └─ Parameter *
└─ Connections
└─ Connection *
├─ Endpoint
└─ Endpoint
```
顶层顺序固定为 `Simulation → Components → Connections`。每条 `Connection` 恰好包含两个 `Endpoint`。
## 3. `System` 根元素
| 属性 | 是否必填 | 规则 |
| --- | --- | --- |
| `schemaVersion` | 是 | 固定为 `3` |
| `unitSystem` | 是 | 固定为 `SI` |
| `name` | 否 | 非空工程名称;省略后解析模型使用 `untitled` |
`schemaVersion="3"` 已经表示唯一的介质引用和 AMESim 离散参数编码语义。根元素不接受额外的版本提示字段,也不会据此触发兼容猜测。
## 4. `Simulation`
| 属性 | 含义 | 主要校验 |
| --- | --- | --- |
| `tStart` | 仿真开始时刻 | 必须是有限数值 |
| `tStop` | 仿真结束时刻 | 必须有限且大于 `tStart` |
| `sampleStep` | 结果相邻采样点的时间间隔 | 必须大于 0;不设置固定的采样点数上限 |
| `maxStep` | 自适应积分器单个内部步的上限 | 必须大于 0 |
| `method` | 积分方法 | `RK45/RK23/DOP853/Radau/BDF/LSODA` |
`sampleStep` 和 `maxStep` 不是一回事:
- `sampleStep` 决定结果曲线多久保存一个点;
- `maxStep` 限制求解器内部一次最多前进多久;
- 自适应求解器可以因为误差、事件或试探状态失败而走得比 `maxStep` 更短。
采样点数量会在创建时间数组前计算。若区间长度不可表示为有限数、点数超过当前
运行时可表示的集合大小,或在当前浮点精度下无法得到包含 `tStart/tStop` 的严格
递增时间序列,输入会在仿真前被拒绝。采样点不再受固定业务上限约束,但结果内存、
序列化体积和浏览器负载仍会随“采样点数 × 输出变量数”线性增长。
工程 JSON 为兼容现有前端仍把采样字段命名为 `simulation.step`;导出 v3 时必须映射为 `Simulation/@sampleStep`。
## 5. `Component` 与 `Parameter`
### 5.1 `Component`
| 属性 | 是否必填 | 含义 |
| --- | --- | --- |
| `id` | 是 | 当前系统内唯一的实例 ID;连接通过它引用组件 |
| `type` | 是 | 后端组件注册键,例如 `amesim_forc` |
| `modelVersion` | 是 | 该 `type` 的模型合同版本 |
语义校验要求 `modelVersion` 与当前注册表完全一致。版本不匹配时返回 `COMPONENT_MODEL_VERSION_MISMATCH`,不会静默套用新模型默认值或自动改写旧参数。
v3 不保存 `name/componentType/x/y/rotation/mirrored`。其中:
- 显示名称和画布位置只属于工程 JSON;
- `componentType` 在当前系统中与后端 `type` 重复;
- 旋转和镜像只属于画面布局,不再改变求解方程。
### 5.2 `Parameter`
```xml
<Parameter name="direction" value="-1"/>
```
每个参数只保存稳定参数名和已经换算到 SI 基准单位的数值。v3 要求组件显式列出当前模型注册表中的全部参数:
- 参数名重复会报错;
- 缺少注册参数会报 `PARAMETER_REQUIRED_MISSING`;
- 出现未知参数会报 `PARAMETER_UNSUPPORTED`;
- 超范围或不在枚举集合内会报 `PARAMETER_VALUE_INVALID`。
前端和后端导出器会先用注册默认值补齐工程 JSON 中省略的参数,再写入 XML。XML 解析器本身不替缺失参数猜默认值。
### 5.3 AMESim 介质引用
介质仍用普通参数表达,不增加额外 XML 层级:
- `gi=0`:内置理想空气;
- 对普通气动组件,`gi=1..99` 引用同一 XML 中显式介质定义组件的索引;
- 对介质定义组件自身,`gi=1..99` 表示它所定义的索引;
- 介质定义的 `gi` 必须唯一;
- 一个连通气动网络只能使用同一 `gi`;
- `property_model` 也是普通必填参数,由对应介质模型注册表解释。
## 6. 端口与连接
### 6.1 为什么 v3 没有 `Port` 元素
端口不是组件实例的自由数据,而是组件模型合同的一部分。后端根据:
```text
Component.type + Endpoint.port
```
从注册表恢复:
- `kind`:物理或信号;
- `domain`:气动、机械或信号;
- `nominalRole`:输入、输出或物理名义角色;
- `positiveFlowDirection`:物理流变量统一以进入组件为正;
- 端口变量、单位和 `equal/sumToZero/streamMix/directed` 连接规则。
XML 不能通过写一个新端口名来扩展组件,也不能通过修改字符串把气动口变成机械口。
### 6.2 `Connection`
`Connection/@id` 可省略。省略时解析器按文档顺序生成 `connection_1`、`connection_2` 等内部 ID;显式 ID 和生成 ID 都必须唯一。
连接本身不再保存 `kind` 或 `domain`。语义层解析两个端点的注册端口后检查:
- 组件和端口存在;
- 两端同为物理端口或同为信号端口;
- 两端 `domain` 和完整变量合同一致;
- 信号连接恰好连接一个 `output` 和一个 `input`;
- 一个信号输出可以驱动多个输入,但每个信号输入只能有一个驱动;
- 同一物理端口只使用一次;分支必须使用显式 Tee/节点组件;
- 不允许自连接或重复端点对。
### 6.3 两个 `Endpoint` 的顺序
物理连接的两个端点无序,交换顺序不改变方程或实际流向。
信号连接也不写 `role="source"` 或 `role="target"`。发送方和接收方由注册端口的 `output/input` 合同确定,而不是由 XML 中的先后顺序决定。导出器可以为了便于阅读把输出端写在前面,但求解器不能依赖这一顺序。
## 7. `AmesimForc.direction`
`amesim_forc` 从模型版本 `0.2.0` 开始使用显式物理参数:
```xml
<Parameter name="direction" value="1"/>
```
它只允许:
- `+1`:默认方向,方程为 `port_2.f + inputForce = 0`;
- `-1`:反向,方程为 `port_2.f - inputForce = 0`。
组件的图标旋转和镜像不会改变该参数,也不会改变求解结果。用户要反转施力方向时必须修改 `direction`,而不是旋转图标。
### 7.1 MECMAS21 离散选项编码
`amesim_mecmas21` 只使用 AMESim 原生的 `1/2` 编码。以两个布尔选项为例:
| 参数 | `1` | `2` |
| --- | --- | --- |
| `useFriction` | 不启用摩擦 | 启用摩擦 |
| `strib` | 不使用 Stribeck 效应 | 使用 Stribeck 效应 |
工程 JSON v1 和 System XML v3 都直接保存上述值。后端不会把 `0/1` 自动换算成
`1/2`,也不会根据缺失的兼容标记猜测工程含义;不在目录选项集合内的值会被拒绝。
## 8. 工程 JSON 与 System XML 的分工
| 信息 | 工程 JSON | System XML v3 |
| --- | --- | --- |
| 组件实例 ID、模型类型 | 保存 | 保存 |
| 模型版本 | 每个节点显式保存并与目录核对 | 每个组件显式保存 |
| 数值参数 | 保存编辑值及显示信息 | 保存完整 SI 数值 |
| 组件显示名、坐标、旋转、镜像 | 保存 | 不保存 |
| 端口快照、`side/order` | 保存供编辑器使用 | 不保存 |
| ReactFlow `source/target/handle` | 保存 | 转成两个 `Endpoint` |
| 端口物理合同 | 目录快照用于前端检查 | 不重复保存,由注册表恢复 |
| 参数表达式、显示单位 | 保存 | 不保存 |
| 仿真结果 | 不作为模型输入 | 不保存 |
因此 `/api/system-xml/parse` 返回的是规范化执行模型,不是可无损恢复原画布的 ReactFlow 工程文件。需要继续编辑时,应保存和打开工程 JSON;需要校验、交换或求解时,使用 System XML v3。
## 9. 校验与 API
校验固定分三层:
| 层级 | 负责内容 |
| --- | --- |
| XML | 5 MiB 大小限制、语法、安全解析、禁止 DTD/实体和网络访问 |
| XSD | 元素顺序、必填属性、数量、基础数值类型、`schemaVersion=3`、`unitSystem=SI` |
| semantic | 模型及版本、完整参数、端点引用、注册端口兼容性、介质引用和拓扑占用 |
当前相关接口都直接接收 `Content-Type: application/xml` 的原始 v3 XML:
- `POST /api/system-xml/validate`:返回三层校验报告;
- `POST /api/system-xml/parse`:返回规范化执行模型;
- `POST /api/system-xml/compile-model`:返回编译后的网络和仿真设置;
- `POST /api/system-xml/simulate`:同步运行并返回完整结果;
- `POST /api/system-xml/simulate-stream`:通过 NDJSON 返回心跳、进度和最终结果。
`POST /api/reactflow/system-xml` 可将工程 JSON 导出为 v3;当前前端也能在浏览器中直接生成同一结构。
通过 XML/XSD/语义校验只说明输入合同正确。完整仿真前仍会检查动态储能锚点、未连接物理端口、方程结构和不允许的理想储能直连等可求解条件。物理连通岛只由物理组件和物理连接构成;控制信号扇出不会把两个独立气路或机械网络合并成一个物理岛。
## 10. 旧版本处理边界
当前 API 不读取或自动转换 System XML v1/v2,也不会为不匹配的
`Component/@modelVersion` 选择旧模型实现。旧输入会在 XSD 或语义层被明确拒绝。
本阶段不定义转换步骤、迁移注册表或兼容承诺。仓库不再保存旧版 XSD、规范或示例;
需要进入当前系统的模型必须由来源端重新导出为 v3,不能只修改版本号。
## 11. 事实来源
- XSD:`schemas/system-simulation-v3.xsd`
- XML 数据类、解析和三层校验:`app/system_xml.py`
- 后端 JSON→XML 导出及 XML 仿真路由:`app/main.py`
- 前端 XML 生成:`frontend/src/App.tsx` 中的 `buildSystemXml()`
- 组件和端口事实来源:`app/simulation/registry.py`、`app/simulation/core/ports.py`
- 网络最终兼容检查:`app/simulation/systems/network.py`