Files
SystemSimulationApp/docs/system-xml-v2.md
T
ljz bbc88a6bbb 规范仿真模型库并完善前端交互
归档仿真模型并补充组件目录、建模规范与校验。

完善控制台、默认节点、视图适配及前端自动化测试。
2026-07-29 15:44:16 +08:00

217 lines
10 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.
# System XML v2 协议
System XML v2 是 ReactFlow 建模前端与 `app.simulation` 仿真层之间的交换格式。v2 将物理端口与信号端口分开,并移除了物理连接中的方向语义。
## 基本约定
- 根元素 `System` 的 `schemaVersion` 固定为 `2`,`unitSystem` 固定为 `SI`。
- 子元素顺序固定为 `Simulation`、`Components`、`Connections`。
- `Component.id` 是稳定实例 ID,`name` 是用户可编辑名称。
- 参数以 SI 基准值保存;显示单位不改变 XML 中的数值含义。
- 物理端口统一规定 `m_flow > 0` 表示流入组件,`m_flow < 0` 表示流出组件。
- `nominalRole` 只表示设计意图和展示语义,不限制实际流向。
- v2 文档不携带仿真结果;端口实际流向、流量幅值和累计质量由运行结果接口返回。
## 完整示例
```xml
<?xml version="1.0" encoding="UTF-8"?>
<System name="transfer-system" schemaVersion="2" unitSystem="SI">
<Simulation tStart="0" tStop="2" step="0.1" maxStep="0.005" method="BDF"/>
<Components>
<Component id="cylinder_1" name="cylinder_1" type="cylinder" componentType="cylinder" x="90" y="180" rotation="0" mirrored="false">
<Port name="port_b" kind="physical" domain="pneumatic" nominalRole="outlet" positiveFlowDirection="intoComponent" side="right"/>
<Parameter name="volume" value="0.01"/>
<Parameter name="p0" value="35000000"/>
<Parameter name="T0" value="300"/>
</Component>
<Component id="tank_1" name="tank_1" type="tank" componentType="tank" x="420" y="180" rotation="0" mirrored="false">
<Port name="port_a" kind="physical" domain="pneumatic" nominalRole="inlet" positiveFlowDirection="intoComponent" side="left"/>
<Parameter name="volume" value="0.1"/>
<Parameter name="p0" value="100000"/>
<Parameter name="T0" value="300"/>
</Component>
</Components>
<Connections>
<Connection id="edge-1" kind="physical" domain="pneumatic">
<Endpoint component="cylinder_1" port="port_b"/>
<Endpoint component="tank_1" port="port_a"/>
</Connection>
</Connections>
</System>
```
## Port
组件的 `rotation` 只能为 `0/90/180/270`,`mirrored` 表示水平镜像。它们只用于恢复画布布局和端口显示位置,不参与物理方程或流向判断。
| 属性 | 含义 |
|---|---|
| `name` | 组件模型中的稳定端口名 |
| `kind` | `physical` 或 `signal` |
| `domain` | 端口物理域,当前流体组件使用 `pneumatic` |
| `nominalRole` | 物理端口使用 `inlet/outlet/bidirectional`;信号端口使用 `input/output` |
| `positiveFlowDirection` | 物理端口固定为 `intoComponent`;信号端口省略 |
| `side` | 前端图标上的 `left/right` 布局位置,不参与物理求解 |
物理端口的流向由求解结果决定。一个名义出口的 `m_flow > 0` 表示该端口发生实际流入,可在结果层标记为倒流。
三通的三个端口当前保留仿真模型已有名称 `port_in/port_out1/port_out2`,但全部声明为 `bidirectional`,名称不构成方向约束。
## Connection
物理连接包含两个无序 `Endpoint`。第一个端点不代表上游,第二个端点也不代表下游;交换二者顺序不得改变仿真结果。
信号连接也使用两个 `Endpoint`,但必须分别携带 `role="source"` 和 `role="target"`。信号端口只允许 `output` 与 `input` 相连。
连接生成前必须验证:
- 组件和端口存在。
- 两端 `kind` 相同。
- 两端 `domain` 相同。
- 信号连接一端为 `output`,另一端为 `input`。
## v1 迁移
- v1 的字符串端口在加载时按组件注册表迁移成 v2 端口对象。
- v1 的 `source/sourcePort/target/targetPort` 在导出 v2 时转换为两个 `Endpoint`。
- 物理连接不继承 v1 的 source/target 方向。
- v1 文件仍由原 XSD 描述;新生成文件只输出 v2。
XSD 负责结构和基础枚举校验,端口注册、拓扑完整性与可求解性由模型校验层负责。
## 仿真模型编译接口
`POST /api/reactflow/compile-model` 接收与工程保存、XML 导出相同的 ReactFlow 工程 JSON。它会执行以下操作:
1. 按 `node.data.modelType` 创建 `app.simulation` 组件实例,并写入 SI 参数。
2. 将前端端口声明与组件注册端口逐项比对。
3. 按画布实际 `edges` 创建无方向物理连接,而不是按组件类型或拖入顺序推断拓扑。
4. 检查端口存在性、物理域兼容性、重复连接和未连接端口。
成功响应中的物理连接只包含两个 `endpoints`,不包含 `source/target`:
```json
{
"success": true,
"name": "transfer-system",
"components": [
{
"id": "cylinder_1",
"type": "cylinder",
"ports": [
{
"name": "port_b",
"kind": "physical",
"domain": "pneumatic",
"nominalRole": "outlet",
"positiveFlowDirection": "intoComponent",
"variables": [
{"name": "p", "role": "effort", "connectionRule": "equal"},
{"name": "m_flow", "role": "flow", "connectionRule": "sumToZero"},
{"name": "h_outflow", "role": "stream", "connectionRule": "streamMix"}
]
}
]
}
],
"connections": [
{
"id": "edge-1",
"kind": "physical",
"domain": "pneumatic",
"endpoints": [
{"component": "cylinder_1", "port": "port_b"},
{"component": "tank_1", "port": "port_a"}
]
}
],
"unconnectedPorts": []
}
```
一个物理端口当前只允许一条连接;需要分支时必须显式放置 `Tee` 等结点组件。这样拓扑不会通过“一个端口连多条线”隐式产生结点方程。
此接口完成模型实例化、端口契约校验、拓扑编译和压力-流量方程结构组装。编译结果中的 `pressureFlowSystem` 包含未知量、方程、数量及 `isSquare` 状态;方阵只表示结构数量平衡,不代表方程一定可解。
当前组件已提供可执行残差:气瓶和贮箱提供状态-压力约束,孔板提供流量守恒和压差-流量本构关系,三通提供等压零结点和流量守恒。XML 注册表中的管段使用准稳态 Darcy 阻性模型,同时提供流量守恒和双向压降关系。连接层根据端口契约生成 `p` 相等及 `m_flow` 代数和为零的残差。
`/api/reactflow/simulate-testmodel` 继续保留固定 TestModel 和动态管段,用于已有基线对比。XML 驱动仿真使用独立的通用半显式求解链路,不调用固定 TestModel 闭合器。
## 第二阶段:XML 解析与校验
第二阶段已经实现从 System XML v2 回到仿真网络的完整入口。解析过程固定分为三层:
| 层级 | `layer` | 负责内容 |
|---|---|---|
| XML | `xml` | 文档大小、XML 语法、禁止 DTD 和实体声明 |
| XSD | `schema` | v2 版本、元素顺序、必填属性、枚举、基础数值类型 |
| 模型语义 | `semantic` | 组件注册、端口契约、参数集合和范围、端点引用、物理域、连接占用及仿真设置 |
校验诊断统一包含:
```json
{
"severity": "error",
"layer": "semantic",
"code": "ENDPOINT_PORT_UNKNOWN",
"message": "Connection edge-1 references unknown port tank_1.port_x.",
"path": "/System/Connections/Connection[1]/Endpoint[2]",
"line": 18
}
```
未连接端口使用 `PORT_UNCONNECTED` 警告,不会阻止解析和网络编译;结构错误、接口不一致、参数错误和非法拓扑会使 `valid=false`。
### API
四个接口均直接接收 `Content-Type: application/xml` 的原始 XML 请求体:
- `POST /api/system-xml/validate`:无论成功与否都返回校验报告,便于编辑器实时显示问题。
- `POST /api/system-xml/parse`:成功时返回规范化工程 JSON;失败时返回 HTTP `422` 和结构化诊断。
- `POST /api/system-xml/compile-model`:成功时返回仿真网络、仿真设置和校验报告;失败时返回 HTTP `422`。
- `POST /api/system-xml/simulate`:完成校验、编译、仿真准备、代数闭合、stream 传播和时间积分;成功时返回组件与端口时间序列,失败时返回 HTTP `422` 和仿真层诊断。
示例:
```powershell
Invoke-RestMethod `
-Method Post `
-Uri http://127.0.0.1:8000/api/system-xml/validate `
-ContentType application/xml `
-InFile .\test\system.xml
```
组件参数和端口定义集中在 `app/simulation/registry.py`。ReactFlow JSON 编译和 XML 语义校验共用该注册表,新增组件时必须先在这里登记参数范围、默认值和端口契约。
## 第三阶段:XML 驱动仿真 MVP
第三阶段当前已经打通:
1. XML 中的组件、参数和无方向物理连接编译成 `app.simulation` 网络。
2. 仿真准备层检查未连接端口、方程数量、无储能代数孤岛和无阻力储能直连。
3. SciPy 非线性最小二乘求解每个时刻的端口压力与质量流量。
4. 根据求解后的实际流向迭代传播 `h_outflow`,并在三通处执行质量流量加权混合。
5. 动态组件自动拼装质量及内能导数,使用 XML 的 `tStart/tStop/step/maxStep/method` 开展积分。
6. 结果包含动态组件的 `m/U/p/T/rho/u/h`,以及全部物理端口的 `p/m_flow/h_outflow` 时间序列。
当前限制:
- 只支持注册表中的气动物理组件,不支持信号端口仿真。
- 所有物理端口在运行前必须完成连接;分支必须显式使用三通。
- 每个独立物理网络必须包含至少一个气瓶或贮箱作为压力和焓的储能锚点。
- 两个储能组件不能通过理想连接或纯三通直接耦合,必须在中间放置孔板或管段。
- XML 管段当前是准稳态阻性元件,`p0/T0` 用于名义密度和初始代数猜测,不包含管内储气动态。
- 当前 stream 混合是适合 MVP 的正则化近似,还不是 Modelica `inStream/actualStream` 的严格复刻。
- 当前是半显式 ODE/代数求解链路,不支持一般高指数 DAE 和事件系统。
运行示例:
```powershell
Invoke-RestMethod `
-Method Post `
-Uri http://127.0.0.1:8000/api/system-xml/simulate `
-ContentType application/xml `
-InFile .\test\system.xml
```