完善 drawio 建模界面与仿真模型集成
This commit is contained in:
1 parent
d6ef842c59
commit
713b32c1b4
28 files changed
+5966
-103
No files matched your search
@@ -1,2 +1,448 @@
|
||||
# SystemSimulationApp
|
||||
|
||||
SystemSimulationApp 是一个面向系统仿真的可视化建模原型。当前项目已经具备两条基础能力:
|
||||
|
||||
- 使用 FastAPI 嵌入 draw.io,提供可视化拖拽建模界面。
|
||||
- 使用 `PythonModels` 中已有的 Python 仿真模型,运行当前固定拓扑的 `TestModelSystem`。
|
||||
|
||||
下一阶段的目标是把这两条能力接起来,先完成一个小 MVP:
|
||||
|
||||
```text
|
||||
draw.io 画图
|
||||
-> 解析 draw.io XML
|
||||
-> 生成 SystemModel
|
||||
-> 映射到 PythonModels.TestModelConfig
|
||||
-> 调用 run_testmodel()
|
||||
-> 返回并展示仿真结果
|
||||
```
|
||||
|
||||
## 当前状态
|
||||
|
||||
### 已有前端和接口基础
|
||||
|
||||
- `app/main.py`: FastAPI 主入口。
|
||||
- `app/static/index.html`: 当前 draw.io iframe 页面。
|
||||
- `/api/component-library.drawiolib`: 当前 draw.io 自定义组件库接口。
|
||||
- `/api/system-xml`: 当前 draw.io XML 到简单系统 XML 的导出接口。
|
||||
- `/drawio/`: FastAPI 到 draw.io Docker 的同源代理入口。
|
||||
|
||||
### 已有 Python 仿真模型
|
||||
|
||||
`PythonModels` 目录里已经有一套 Python 仿真骨架:
|
||||
|
||||
```text
|
||||
PythonModels/components/
|
||||
cylinder.py -> Cylinder,端口 port_b
|
||||
tank.py -> Tank,端口 port_a
|
||||
pipe.py -> Pipe,端口 port_a / port_b
|
||||
orifice.py -> Orifice,端口 port_a / port_b
|
||||
tee.py -> Tee,端口 port_in / port_out1 / port_out2
|
||||
|
||||
PythonModels/core/
|
||||
network.py -> SimulationNetwork / Connection
|
||||
ports.py -> PortState
|
||||
solver.py -> integrate_ode / SolveIVPConfig
|
||||
|
||||
PythonModels/systems/
|
||||
testmodel.py -> 当前唯一可运行系统 TestModelSystem
|
||||
```
|
||||
|
||||
当前 `TestModelSystem` 支持的是固定拓扑:
|
||||
|
||||
```text
|
||||
mycylinder
|
||||
-> mytee
|
||||
-> myorifice -> mypipe
|
||||
-> myorifice1 -> mypipe1
|
||||
-> mytee1
|
||||
-> mytank
|
||||
```
|
||||
|
||||
因此第一版不要做任意拓扑仿真,而是先把 draw.io 中画出的这个固定拓扑映射到现有 `TestModelSystem`。
|
||||
|
||||
## 核心原则
|
||||
|
||||
不要让仿真逻辑直接依赖 draw.io XML。
|
||||
|
||||
推荐分层:
|
||||
|
||||
```text
|
||||
draw.io XML
|
||||
-> SystemModel
|
||||
-> PythonModels adapter
|
||||
-> PythonModels runner
|
||||
-> SimulationResult
|
||||
```
|
||||
|
||||
其中:
|
||||
|
||||
- draw.io XML 只是可视化画布格式。
|
||||
- `SystemModel` 是系统仿真的核心结构化数据。
|
||||
- PythonModels adapter 负责把 `SystemModel` 转成 `TestModelConfig / TestModelRunConfig`。
|
||||
- 仿真器只认结构化模型,不直接解析画布。
|
||||
|
||||
这样后续即使替换 draw.io,仿真层也不用推倒重来。
|
||||
|
||||
## MVP 范围
|
||||
|
||||
第一版只支持当前 `TestModelSystem` 对应的拓扑:
|
||||
|
||||
```text
|
||||
cylinder -> tee -> valve/orifice -> pipe -> tee -> tank
|
||||
-> valve/orifice -> pipe ->
|
||||
```
|
||||
|
||||
第一版支持的组件:
|
||||
|
||||
| draw.io 类型 | PythonModels 类型 | 配置对象 | 端口 |
|
||||
| --- | --- | --- | --- |
|
||||
| `cylinder` | `Cylinder` | `CylinderConfig` | `port_b` |
|
||||
| `tank` | `Tank` | `TankConfig` | `port_a` |
|
||||
| `pipe` | `Pipe` | `PipeConfig` | `port_a`, `port_b` |
|
||||
| `valve` / `orifice` | `Orifice` | `OrificeConfig` | `port_a`, `port_b` |
|
||||
| `tee` | `Tee` | 暂无独立配置 | `port_in`, `port_out1`, `port_out2` |
|
||||
|
||||
前端可以继续显示“阀门”,但底层建议使用:
|
||||
|
||||
```xml
|
||||
modelType="orifice"
|
||||
```
|
||||
|
||||
因为 PythonModels 里实际对应的是 `Orifice`。
|
||||
|
||||
## SystemModel 设计
|
||||
|
||||
建议新增统一结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "testmodel_from_drawio",
|
||||
"components": [
|
||||
{
|
||||
"id": "mycylinder",
|
||||
"type": "cylinder",
|
||||
"role": "cylinder",
|
||||
"parameters": {
|
||||
"volume": 0.01,
|
||||
"p0": 35000000,
|
||||
"T0": 300
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"source": {
|
||||
"component": "mycylinder",
|
||||
"port": "port_b"
|
||||
},
|
||||
"target": {
|
||||
"component": "mytee",
|
||||
"port": "port_in"
|
||||
}
|
||||
}
|
||||
],
|
||||
"simulation": {
|
||||
"t_start": 0,
|
||||
"t_stop": 20,
|
||||
"step": 0.1,
|
||||
"method": "BDF"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## draw.io XML 扩展约定
|
||||
|
||||
组件节点需要补充仿真语义:
|
||||
|
||||
```xml
|
||||
<object
|
||||
id="mycylinder"
|
||||
label="气瓶"
|
||||
componentType="cylinder"
|
||||
modelType="cylinder"
|
||||
role="cylinder"
|
||||
volume="0.01"
|
||||
p0="35000000"
|
||||
T0="300">
|
||||
...
|
||||
</object>
|
||||
```
|
||||
|
||||
管段示例:
|
||||
|
||||
```xml
|
||||
<object
|
||||
id="mypipe"
|
||||
label="上支路管段"
|
||||
componentType="pipe"
|
||||
modelType="pipe"
|
||||
role="upper_branch.pipe"
|
||||
length="5.0"
|
||||
diameter="0.02"
|
||||
lambda_darcy="0.02"
|
||||
p0="100000"
|
||||
T0="300">
|
||||
...
|
||||
</object>
|
||||
```
|
||||
|
||||
孔板 / 阀门示例:
|
||||
|
||||
```xml
|
||||
<object
|
||||
id="myorifice"
|
||||
label="上支路孔板"
|
||||
componentType="valve"
|
||||
modelType="orifice"
|
||||
role="upper_branch.orifice"
|
||||
K="0.00001"
|
||||
opening="1.0">
|
||||
...
|
||||
</object>
|
||||
```
|
||||
|
||||
连接需要从“组件级”升级到“端口级”:
|
||||
|
||||
```xml
|
||||
<object
|
||||
id="edge1"
|
||||
sourcePort="port_b"
|
||||
targetPort="port_in">
|
||||
<mxCell edge="1" source="mycylinder" target="mytee" />
|
||||
</object>
|
||||
```
|
||||
|
||||
如果第一版来不及做端口选择,可以后端按组件类型和拓扑位置推断默认端口,但这只能作为 MVP 兜底。
|
||||
|
||||
## 参数映射
|
||||
|
||||
从 draw.io / SystemModel 解析出的参数映射到 PythonModels 配置对象:
|
||||
|
||||
```text
|
||||
cylinder.volume -> CylinderConfig.volume
|
||||
cylinder.p0 -> CylinderConfig.p0
|
||||
cylinder.T0 -> CylinderConfig.T0
|
||||
|
||||
tank.volume -> TankConfig.volume
|
||||
tank.p0 -> TankConfig.p0
|
||||
tank.T0 -> TankConfig.T0
|
||||
|
||||
pipe.length -> PipeConfig.length
|
||||
pipe.diameter -> PipeConfig.diameter
|
||||
pipe.lambda_darcy -> PipeConfig.lambda_darcy
|
||||
pipe.p0 -> PipeConfig.p0
|
||||
pipe.T0 -> PipeConfig.T0
|
||||
|
||||
orifice.K -> OrificeConfig.K
|
||||
orifice.opening -> OrificeConfig.opening
|
||||
```
|
||||
|
||||
注意:当前 `Orifice` 类支持 `opening`,但 `OrificeConfig` 暂时只有 `K`。建议后续给 `OrificeConfig` 增加 `opening` 字段,这样前端“阀门开度”才有实际落点。
|
||||
|
||||
## 建议新增后端模块
|
||||
|
||||
```text
|
||||
app/models/system.py
|
||||
app/services/drawio_parser.py
|
||||
app/services/model_validator.py
|
||||
app/services/pythonmodels_adapter.py
|
||||
app/services/simulation_runner.py
|
||||
```
|
||||
|
||||
职责:
|
||||
|
||||
```text
|
||||
app/models/system.py
|
||||
定义 SystemModel、ComponentInstance、Connection、SimulationConfig。
|
||||
|
||||
app/services/drawio_parser.py
|
||||
负责 draw.io XML -> SystemModel。
|
||||
|
||||
app/services/model_validator.py
|
||||
检查组件、端口、参数、拓扑是否合法。
|
||||
|
||||
app/services/pythonmodels_adapter.py
|
||||
负责 SystemModel -> TestModelConfig / TestModelRunConfig。
|
||||
|
||||
app/services/simulation_runner.py
|
||||
调用 PythonModels,并把结果整理成前端可消费的 JSON。
|
||||
```
|
||||
|
||||
## 建议新增接口
|
||||
|
||||
```text
|
||||
POST /api/models/from-drawio
|
||||
输入 draw.io XML
|
||||
输出 SystemModel JSON
|
||||
|
||||
POST /api/models/validate
|
||||
输入 SystemModel
|
||||
输出校验结果
|
||||
|
||||
POST /api/simulations/testmodel
|
||||
输入 SystemModel + 仿真配置
|
||||
输出仿真结果
|
||||
|
||||
POST /api/simulations/testmodel/from-drawio
|
||||
输入 draw.io XML
|
||||
一步完成解析、校验、仿真
|
||||
```
|
||||
|
||||
第一版可以优先实现:
|
||||
|
||||
```text
|
||||
POST /api/simulations/testmodel/from-drawio
|
||||
```
|
||||
|
||||
这样页面点击“运行仿真”时可以直接把 draw.io XML 发给后端。
|
||||
|
||||
## 第一版拓扑校验规则
|
||||
|
||||
第一版只支持固定 `TestModelSystem` 拓扑,因此校验可以严格一点:
|
||||
|
||||
- 必须有 1 个 `cylinder`。
|
||||
- 必须有 1 个 `tank`。
|
||||
- 必须有 2 个 `tee`。
|
||||
- 必须有 2 个 `orifice` 或 `valve`。
|
||||
- 必须有 2 个 `pipe`。
|
||||
- 连接必须形成两条支路。
|
||||
- 每条支路必须是 `orifice -> pipe`。
|
||||
- 上游必须从 `cylinder` 到第一个 `tee`。
|
||||
- 下游必须汇入第二个 `tee` 再到 `tank`。
|
||||
|
||||
第一版不支持任意拓扑。
|
||||
|
||||
## 实现步骤和进度
|
||||
|
||||
### A. draw.io 侧建模增强
|
||||
|
||||
- [ ] 扩展组件库,增加 `cylinder / tee / orifice / pipe / tank`。
|
||||
- [ ] 给每个组件写入 `modelType`、`role`、默认参数。
|
||||
- [ ] 给组件补充端口语义。
|
||||
- [ ] 给连接 edge 补充 `sourcePort / targetPort`。
|
||||
- [ ] 前端增加“运行仿真”按钮。
|
||||
|
||||
### B. SystemModel 数据层
|
||||
|
||||
- [ ] 新增 `app/models/system.py`。
|
||||
- [ ] 定义 `SystemModel`。
|
||||
- [ ] 定义 `ComponentInstance`。
|
||||
- [ ] 定义端口级 `Connection`。
|
||||
- [ ] 定义 `SimulationConfig`。
|
||||
|
||||
### C. draw.io 解析
|
||||
|
||||
- [ ] 新增 `app/services/drawio_parser.py`。
|
||||
- [ ] 支持 `mxGraphModel` 输入。
|
||||
- [ ] 支持 `mxfile` 输入。
|
||||
- [ ] 解析 `<object>` 组件。
|
||||
- [ ] 解析 `<mxCell edge="1">` 连接。
|
||||
- [ ] 把 draw.io 参数转换成正确的 Python 类型。
|
||||
- [ ] 输出标准 `SystemModel`。
|
||||
|
||||
### D. 模型校验
|
||||
|
||||
- [ ] 新增 `app/services/model_validator.py`。
|
||||
- [ ] 校验组件类型是否合法。
|
||||
- [ ] 校验必填参数是否存在。
|
||||
- [ ] 校验数值参数范围。
|
||||
- [ ] 校验端口名是否合法。
|
||||
- [ ] 校验连接 source / target 是否存在。
|
||||
- [ ] 校验是否符合固定 TestModel 拓扑。
|
||||
- [ ] 返回结构化错误列表。
|
||||
|
||||
### E. PythonModels 适配层
|
||||
|
||||
- [ ] 新增 `app/services/pythonmodels_adapter.py`。
|
||||
- [ ] 实现 `SystemModel -> CylinderConfig`。
|
||||
- [ ] 实现 `SystemModel -> TankConfig`。
|
||||
- [ ] 实现 `SystemModel -> PipeConfig`。
|
||||
- [ ] 实现 `SystemModel -> OrificeConfig`。
|
||||
- [ ] 实现 `SystemModel -> TestModelConfig`。
|
||||
- [ ] 实现 `SimulationConfig -> SolveIVPConfig`。
|
||||
- [ ] 如需要,给 `OrificeConfig` 增加 `opening` 字段。
|
||||
|
||||
### F. 仿真运行
|
||||
|
||||
- [ ] 新增 `app/services/simulation_runner.py`。
|
||||
- [ ] 调用 `PythonModels.scripts.run_testmodel.run_testmodel()`。
|
||||
- [ ] 整理返回的 `series`。
|
||||
- [ ] 返回 `mytank.p / mytank.T / mycylinder.p / mycylinder.T`。
|
||||
- [ ] 返回 `branch.<name>.p / in / out`。
|
||||
- [ ] 保留初始化诊断和求解诊断。
|
||||
|
||||
### G. FastAPI 接口
|
||||
|
||||
- [ ] 新增 `POST /api/models/from-drawio`。
|
||||
- [ ] 新增 `POST /api/models/validate`。
|
||||
- [ ] 新增 `POST /api/simulations/testmodel`。
|
||||
- [ ] 新增 `POST /api/simulations/testmodel/from-drawio`。
|
||||
|
||||
### H. 前端结果展示
|
||||
|
||||
- [ ] 点击“运行仿真”后导出当前 draw.io XML。
|
||||
- [ ] 调用 `/api/simulations/testmodel/from-drawio`。
|
||||
- [ ] 展示校验错误。
|
||||
- [ ] 展示仿真成功 / 失败状态。
|
||||
- [ ] 展示结果表格。
|
||||
- [ ] 展示压力、温度、流量曲线。
|
||||
- [ ] 支持下载结果 JSON / CSV。
|
||||
|
||||
## MVP 验收标准
|
||||
|
||||
第一版完成后,应能做到:
|
||||
|
||||
- [ ] 打开 FastAPI 页面。
|
||||
- [ ] 在 draw.io 画布中拖入气瓶、三通、阀门/孔板、管段、贮箱。
|
||||
- [ ] 按固定 TestModel 拓扑连接组件。
|
||||
- [ ] 配置主要参数。
|
||||
- [ ] 点击运行仿真。
|
||||
- [ ] 后端解析 draw.io XML。
|
||||
- [ ] 后端生成 `SystemModel`。
|
||||
- [ ] 后端映射到 `TestModelConfig`。
|
||||
- [ ] 后端调用 `run_testmodel()`。
|
||||
- [ ] 前端展示 `mytank.p`、`mytank.T`、`mycylinder.p`、`mycylinder.T`。
|
||||
- [ ] 前端展示两条支路的压力和流量。
|
||||
|
||||
## 后续阶段:通用拓扑仿真
|
||||
|
||||
固定 TestModel 跑通后,再考虑通用拓扑:
|
||||
|
||||
```text
|
||||
SystemModel
|
||||
-> instantiate components
|
||||
-> SimulationNetwork.add_component()
|
||||
-> SimulationNetwork.connect()
|
||||
-> 自动生成 rhs
|
||||
-> integrate_ode()
|
||||
```
|
||||
|
||||
这一步需要新增:
|
||||
|
||||
- 通用 connector / stream 求解。
|
||||
- 通用代数闭合。
|
||||
- 任意 `Tee / Pipe / Orifice` 网络流量求解。
|
||||
- 自动状态向量组装。
|
||||
- 自动 `rhs` 生成。
|
||||
|
||||
当前不建议立刻做这一步,因为 `PythonModels/systems/testmodel_closure.py` 仍然是为 `TestModelSystem` 专门写的闭合器,不是任意拓扑求解器。
|
||||
|
||||
## 当前优先级
|
||||
|
||||
下一步优先做:
|
||||
|
||||
```text
|
||||
draw.io XML
|
||||
-> SystemModel
|
||||
-> TestModelConfig
|
||||
-> run_testmodel()
|
||||
```
|
||||
|
||||
暂时不要直接做:
|
||||
|
||||
```text
|
||||
draw.io XML
|
||||
-> PythonModels 任意网络
|
||||
```
|
||||
|
||||
这样最贴合现有代码,成本最低,技术债也最可控。
|
||||
Reference in new issue
Block a user