完成求解器雅可比矩阵首轮优化,增加更新目录,整理了文档文件夹,增加了服务启动脚本
This commit is contained in:
1 parent
6bb0591d32
commit
16a7eb2d6c
48 files changed
+8172
-217
No files matched your search
@@ -0,0 +1,228 @@
|
||||
# 后端接口版本与定义规范 v1
|
||||
|
||||
本文统一说明 SystemSimulationApp 后端的接口边界、版本编号和事实来源。规范版本为
|
||||
`1.0.0`。这个编号只表示本文档自身的修订版本,不等同于 HTTP API、System XML、
|
||||
组件目录或单个模型的版本。
|
||||
|
||||
## 1. 当前版本基线
|
||||
|
||||
后端没有一个可以替代所有子版本的“总版本号”。调用方必须按所使用的数据合同读取
|
||||
对应版本:
|
||||
|
||||
| 版本轴 | 当前值 | 作用范围 | 机器可读事实来源 |
|
||||
| --- | --- | --- | --- |
|
||||
| HTTP API | 未版本化 | `/api/...` 路由、请求和响应 | `app/main.py`、FastAPI OpenAPI |
|
||||
| 后端应用发布版本 | 未定义 | 整个后端部署产物 | 当前没有包元数据或运行时常量 |
|
||||
| 组件目录 Schema | `1` | `GET /api/components/catalog` | `schemas/component-catalog-v1.schema.json` |
|
||||
| System XML Schema | `3` | XML 校验、编译和仿真输入 | `schemas/system-simulation-v3.xsd` |
|
||||
| 组件库版本 | 各库独立 | 一个组件库的发布边界 | 各库 `library.py` 的 `version` |
|
||||
| 模型合同版本 | 各模型独立 | 单个 `MODEL_TYPE` 的物理和数据合同 | 模型类的 `MODEL_VERSION` |
|
||||
| ReactFlow 工程 JSON | `1` | 编辑器存档 | `projectSchemaVersion`、`ReactFlowProjectPayload` 和前端读取代码 |
|
||||
| 结果文件格式 | `1` | 前端导入、导出的结果快照 | `SimulationResultsView.tsx` |
|
||||
|
||||
因此,`schemaVersion=3` 只能说明文件是 System XML v3,不能说明“后端 API 是
|
||||
v3”;`MODEL_VERSION=0.2.0` 也只描述对应模型合同。
|
||||
|
||||
FastAPI 自动生成的 OpenAPI 当前可能显示默认 `info.version=0.1.0`;后端没有显式
|
||||
声明这个值,因此它不是正式 API 或应用发布版本。
|
||||
|
||||
## 2. 事实来源和优先级
|
||||
|
||||
接口定义冲突时,按以下优先级处理:
|
||||
|
||||
1. 可执行代码和机器可读 Schema;
|
||||
2. 自动化合同测试;
|
||||
3. 当前版本规范文档;
|
||||
4. 示例、调研记录和历史说明。
|
||||
|
||||
各类合同的唯一事实来源如下:
|
||||
|
||||
| 合同 | 唯一事实来源 |
|
||||
| --- | --- |
|
||||
| 公开模型类型和版本 | 模型类的 `MODEL_TYPE`、`MODEL_VERSION` |
|
||||
| 端口物理合同 | 模型类的 `PORTS` 和 `app/simulation/core/ports.py` |
|
||||
| 参数、结果及单位 | 模型类的 `PARAMETERS`、`RESULT_VARIABLES` |
|
||||
| 组件库及分类 | 各库 `library.py` |
|
||||
| 组件目录 JSON | `build_component_catalog()` 与目录 JSON Schema |
|
||||
| System XML | v3 XSD、`app/system_xml.py` |
|
||||
| 网络最终连接检查 | `SimulationNetwork.connect()` |
|
||||
| HTTP 路由和请求模型 | `app/main.py` |
|
||||
|
||||
前端兜底目录、画布布局和示例 XML 不能反向定义后端物理合同。
|
||||
|
||||
## 3. 组件接口合同
|
||||
|
||||
每个公开组件必须显式声明:
|
||||
|
||||
```python
|
||||
MODEL_TYPE = "example_component"
|
||||
MODEL_VERSION = "1.0.0"
|
||||
PORTS = (...)
|
||||
PARAMETERS = (...)
|
||||
RESULT_VARIABLES = (...)
|
||||
DISPLAY = ...
|
||||
```
|
||||
|
||||
并提供统一的 `create()` 入口。各字段含义如下:
|
||||
|
||||
- `MODEL_TYPE` 是工程、XML、目录和结果元数据共同使用的稳定机器标识;
|
||||
- `MODEL_VERSION` 使用 `主版本.次版本.修订版本`;
|
||||
- `PORTS` 定义端口名称、种类、物理域、名义角色、变量和连接规则;
|
||||
- `PARAMETERS` 定义 SI 单位、默认值、范围和离散选项;
|
||||
- `RESULT_VARIABLES` 定义结构化结果元数据;
|
||||
- `DISPLAY` 只定义前端展示,不得成为物理方程的隐式输入。
|
||||
|
||||
物理流变量统一以进入组件为正。物理连接的两个端点无方向;信号方向由注册端口的
|
||||
`output/input` 合同决定。
|
||||
|
||||
## 4. 组件目录接口
|
||||
|
||||
`GET /api/components/catalog` 返回组件库、分类和模型合同。响应顶层必须为:
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"libraries": []
|
||||
}
|
||||
```
|
||||
|
||||
目录结构由 `schemas/component-catalog-v1.schema.json` 约束。库必须携带
|
||||
`version`,模型必须携带 `modelVersion`。目录 Schema 的整数版本只描述目录 JSON
|
||||
结构;库和模型版本仍分别使用三段式版本号。
|
||||
|
||||
当前三段版本只接受 `数字.数字.数字`,不接受 prerelease 或 build metadata,不能直接
|
||||
等同于完整 SemVer 实现。目录 Schema 对对象使用 `additionalProperties=false`,因此
|
||||
新增字段也必须先评估严格消费者,不能只因字段可选就默认兼容。
|
||||
|
||||
目录响应是前端生成组件面板、参数编辑器和端口快照的来源。修改响应结构时必须同时
|
||||
更新 JSON Schema、前端解析和合同测试。
|
||||
|
||||
## 5. System XML v3
|
||||
|
||||
System XML v3 是当前唯一支持的 XML 求解输入。根元素固定使用:
|
||||
|
||||
```xml
|
||||
<System schemaVersion="3" unitSystem="SI">
|
||||
```
|
||||
|
||||
每个组件必须包含 `id`、`type`、`modelVersion` 和完整 SI 参数;连接只包含两个
|
||||
`Endpoint(component, port)`。端口合同由 `type + port` 从注册表恢复,XML 不保存
|
||||
端口快照和画布布局。
|
||||
|
||||
`modelVersion` 必须与当前注册模型完全一致。版本不一致时返回
|
||||
`COMPONENT_MODEL_VERSION_MISMATCH`,不会静默使用当前模型解释旧输入。完整结构见
|
||||
`docs/standard/system-xml-v3.md` 和 `schemas/system-simulation-v3.xsd`。
|
||||
|
||||
## 6. HTTP API
|
||||
|
||||
FastAPI 当前直接注册未版本化的 `/api/...` 路由,没有 `/api/v1` 命名空间,也没有
|
||||
运行时 `apiVersion`。主要业务接口如下:
|
||||
|
||||
| 方法与路径 | 请求合同 | 响应合同 |
|
||||
| --- | --- | --- |
|
||||
| `GET /api/components/catalog` | 无 | 组件目录 JSON v1 |
|
||||
| `GET /api/reactflow/projects` | 无 | 已保存工程摘要列表 |
|
||||
| `GET /api/reactflow/projects/{id}` | 工程 ID | 严格校验后的工程 JSON v1 |
|
||||
| `POST /api/reactflow/projects/{id}` | `ReactFlowProjectPayload` | 保存摘要 |
|
||||
| `POST /api/reactflow/system-xml` | `ReactFlowProjectPayload` | `application/xml`,System XML v3 |
|
||||
| `POST /api/reactflow/compile-model` | `ReactFlowProjectPayload` | 编译网络 JSON |
|
||||
| `POST /api/system-xml/validate` | 原始 XML v3 | 三层校验报告 |
|
||||
| `POST /api/system-xml/parse` | 原始 XML v3 | 规范化执行模型 |
|
||||
| `POST /api/system-xml/compile-model` | 原始 XML v3 | 校验报告、设置和网络 |
|
||||
| `POST /api/system-xml/simulate` | 原始 XML v3 | 同步仿真结果 |
|
||||
| `POST /api/system-xml/simulate-stream` | 原始 XML v3 | `application/x-ndjson` 事件流 |
|
||||
| `GET /api/system-xml/simulations/{id}` | 路径 ID | 任务快照 |
|
||||
| `POST /api/system-xml/simulations/{id}/cancel` | 取消原因 JSON | 取消受理状态 |
|
||||
| `POST /api/simulation-results/csv` | 结构化结果 JSON | UTF-8 CSV 附件 |
|
||||
|
||||
两个固定算例接口 `simulate-testmodel` 和 `simulate-test-mql` 仍属于测试/基线能力,不能
|
||||
视为任意拓扑仿真合同。
|
||||
|
||||
FastAPI 会生成 `/openapi.json`、`/docs` 和 `/redoc`。Pydantic JSON 请求体能够进入
|
||||
OpenAPI,但当前多数 JSON 响应仍以 `dict[str, object]` 构造,XML、CSV 和 NDJSON
|
||||
也使用原始响应类型。因此 OpenAPI 目前不是完整的响应合同;代码、Schema 和合同测试
|
||||
仍是必要依据。
|
||||
|
||||
## 7. 数据命名、单位和错误
|
||||
|
||||
- XML 属性和目录 JSON 主要使用 `camelCase`;
|
||||
- ReactFlow 仿真设置保留现有 `t_start/t_stop/step/max_step` 名称;
|
||||
- 不允许调用方自行猜测或转换字段命名;
|
||||
- XML 和求解参数统一使用 SI 基准值;
|
||||
- 实例 ID 和机器标识必须稳定,显示名称不能代替机器标识。
|
||||
|
||||
System XML 校验问题统一包含:
|
||||
|
||||
```json
|
||||
{
|
||||
"severity": "error",
|
||||
"layer": "semantic",
|
||||
"code": "ENDPOINT_PORT_UNKNOWN",
|
||||
"message": "...",
|
||||
"path": "...",
|
||||
"line": 1
|
||||
}
|
||||
```
|
||||
|
||||
其中 `severity/layer/code/message` 是核心字段,`path/line` 可选。同步 HTTP 错误目前既
|
||||
可能是 FastAPI 字符串 `detail`,也可能是带 `message/issues/diagnostics` 的结构化
|
||||
`detail`;流式接口则使用 `event=error` 的 NDJSON 事件。统一错误响应模型尚未实现,
|
||||
调用方必须同时处理这三种现有形状。
|
||||
|
||||
## 8. 版本变更规则
|
||||
|
||||
### 8.1 模型和组件库
|
||||
|
||||
- 修订版本:修复实现,不改变输入、端口和结果合同;
|
||||
- 次版本:向后兼容地增加有默认值的参数、结果或能力;
|
||||
- 主版本:删除或改名端口/参数,或者改变既有物理语义。
|
||||
|
||||
修改 `MODEL_TYPE` 视为新模型,不得用原标识承载不兼容合同。
|
||||
|
||||
以上版本含义用于分类变更影响;当前 System XML v3 对 `modelVersion` 执行完整字符串
|
||||
精确匹配。因此即使只是修订或次版本变化,旧 XML 也会被拒绝,不能把“向后兼容”
|
||||
理解成解析器会自动接受旧版本。
|
||||
|
||||
### 8.2 目录和 XML Schema
|
||||
|
||||
- 兼容澄清不改变 Schema 版本;
|
||||
- 新增可选字段前必须验证旧消费者行为;
|
||||
- 删除字段、改名或改变既有语义必须提高 Schema 版本;
|
||||
- Schema、解析器、导出器、文档和合同测试必须在同一修改中更新。
|
||||
|
||||
### 8.3 HTTP API
|
||||
|
||||
当前 HTTP API 未版本化,因此不得在原路径上直接发布破坏性变更。需要破坏现有请求
|
||||
或响应合同前,应先单独设计 API 版本命名空间、兼容周期和下线规则;该机制不在本文
|
||||
本次整理范围内。
|
||||
|
||||
## 9. 旧版本和迁移边界
|
||||
|
||||
当前后端只接受 System XML v3:
|
||||
|
||||
- 不按 `schemaVersion` 自动选择 v1/v2 解析器;
|
||||
- 不提供 v1/v2 到 v3 的自动迁移器;
|
||||
- 不对不匹配的 `modelVersion` 做自动升级;
|
||||
- 旧版本值只用于验证“不受支持输入应被拒绝”的边界测试。
|
||||
|
||||
ReactFlow 工程 JSON 只接受 `projectSchemaVersion: 1` 的当前结构,每个节点必须保存
|
||||
目录给出的 `modelVersion`。执行、编译和 XML 导出前会再次核对节点版本;缺失或不匹配
|
||||
时明确拒绝,不能先补当前默认参数再冒充当前模型。字符串端口、缺失连接 Handle 或
|
||||
已经删除的兼容标记也不会被猜测、补齐或迁移;以后确有升级需求时再为新的工程版本
|
||||
单独设计迁移器。
|
||||
|
||||
MECMAS21 的 `useFriction`、`strib` 等 AMESim 选项统一使用目录声明的原生编码:
|
||||
`1` 表示“否/禁用”,`2` 表示“是/启用”。工程 JSON v1、组件目录、System XML v3
|
||||
和模型构造器不再接受或自动换算旧的 `0/1` 编码,也不再使用
|
||||
`amesimParameterEncodingVersion` 触发猜测式转换。
|
||||
|
||||
## 10. 接口修改完成条件
|
||||
|
||||
任何接口合同变更至少应同时完成:
|
||||
|
||||
1. 更新唯一事实来源;
|
||||
2. 根据兼容性决定是否提高对应版本;
|
||||
3. 更新机器可读 Schema;
|
||||
4. 更新当前规范和示例;
|
||||
5. 增加请求、响应、拒绝边界和前后端联调测试;
|
||||
6. 明确说明未实现的兼容或迁移能力。
|
||||
@@ -0,0 +1,778 @@
|
||||
# 组件库分类、发现与读取规范 v1
|
||||
|
||||
状态:已在 `experimental` 临时组件库实施
|
||||
适用范围:`app/simulation/components`、组件注册中心、System XML 和 React Flow 组件库
|
||||
当前试验库:`experimental`(仅用于注册契约验证,不在前端组件库中显示)
|
||||
|
||||
## 0. 文档定位
|
||||
|
||||
本文档只负责“模型如何被系统发现和读取”。模型方程、状态、参数和结果应如何编写,
|
||||
统一参见[组件模型建模规范 v1](component-model-authoring-spec-v1.md)。
|
||||
|
||||
人工或 AI 排查组件读取问题时,按以下顺序读取:
|
||||
|
||||
1. `app/simulation/registry.py` 中的 `ENABLED_COMPONENT_LIBRARIES`。
|
||||
2. 被启用组件库的 `library.py`。
|
||||
3. `library.py/models` 明确列出的模型类。
|
||||
4. 模型类的 `DISPLAY / PORTS / PARAMETERS`。
|
||||
5. `build_component_catalog()` 的输出。
|
||||
6. 前端 `normalizeComponentCatalog()`。
|
||||
|
||||
当前事实来源优先级:
|
||||
|
||||
| 信息 | 唯一事实来源 | 不能作为事实来源 |
|
||||
| --- | --- | --- |
|
||||
| 启用哪些库 | `ENABLED_COMPONENT_LIBRARIES` | 目录中碰巧存在的文件夹 |
|
||||
| 库分类和模型清单 | 各库 `library.py` | 前端组件列表 |
|
||||
| 模型类型和版本 | 模型类 | 文件名或中文名称 |
|
||||
| 物理端口 | 模型类 `PORTS` | `DISPLAY.ports` 或画布方向 |
|
||||
| 参数默认值和边界 | 模型类 `PARAMETERS` | 前端兜底定义 |
|
||||
| 图标和端口位置 | 模型类 `DISPLAY` | 物理方程 |
|
||||
| 前端运行目录 | `/api/components/catalog` | 手工扫描 Python 包 |
|
||||
|
||||
如果文档、代码和目录响应不一致,应在同一次修改中修复并增加测试,不能通过复制
|
||||
另一份映射临时绕过。
|
||||
|
||||
## 1. 目标
|
||||
|
||||
本规范用于统一以下内容:
|
||||
|
||||
1. 后端组件库如何声明自身信息和分类。
|
||||
2. 单个模型如何声明端口、参数、结果变量和界面显示信息。
|
||||
3. 后端如何发现、校验、注册并实例化模型。
|
||||
4. 前端如何通过统一目录接口自动生成左侧组件库和参数面板。
|
||||
5. System XML 中的模型类型如何稳定映射到 Python 实现。
|
||||
|
||||
目标工作流如下:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["ENABLED_COMPONENT_LIBRARIES"] --> B["library.py"]
|
||||
B --> C["受控导入模型类"]
|
||||
C --> D["启动契约校验"]
|
||||
D --> E["组件注册表"]
|
||||
E --> F["GET /api/components/catalog"]
|
||||
F --> G["React Flow 组件库和参数面板"]
|
||||
E --> H["System XML 模型实例化"]
|
||||
```
|
||||
|
||||
新增一个符合本规范的模型后,前端不应再修改 `App.tsx` 中的组件列表、参数列表
|
||||
或分类列表。只有新增一种前端尚不支持的图形渲染方式时,才需要补充前端图标组件。
|
||||
|
||||
## 2. 术语和层级
|
||||
|
||||
组件目录采用四个相互独立的概念:
|
||||
|
||||
| 层级 | 示例 | 含义 |
|
||||
| --- | --- | --- |
|
||||
| 组件库 Library | `experimental` | 一组具有共同发布、维护和版本边界的模型 |
|
||||
| 界面分类 Category | `storage` | 只用于组件面板分组和排序 |
|
||||
| 物理域 Domain | `pneumatic` | 决定端口能否连接以及采用哪组连接方程 |
|
||||
| 模型 Model | `cylinder` | 可实例化并写入 System XML 的稳定模型类型 |
|
||||
|
||||
分类和物理域禁止混用。例如,`storage` 是界面分类,`pneumatic` 是物理域;
|
||||
一个“储能元件”也可以属于液压域,不能根据分类推断端口连接规则。
|
||||
|
||||
标准层级为:
|
||||
|
||||
```text
|
||||
Library
|
||||
Category
|
||||
Model
|
||||
Port
|
||||
Port variable
|
||||
Parameter
|
||||
Result variable
|
||||
```
|
||||
|
||||
## 3. 推荐目录结构
|
||||
|
||||
每个组件库使用独立 Python 包:
|
||||
|
||||
```text
|
||||
app/simulation/components/
|
||||
experimental/
|
||||
__init__.py
|
||||
library.py
|
||||
storage/
|
||||
__init__.py
|
||||
cylinder.py
|
||||
tank.py
|
||||
flow/
|
||||
__init__.py
|
||||
orifice.py
|
||||
resistive_pipe.py
|
||||
junctions/
|
||||
__init__.py
|
||||
tee.py
|
||||
```
|
||||
|
||||
规则如下:
|
||||
|
||||
- `library.py` 是组件库唯一清单入口。
|
||||
- 分类目录名必须与分类 ID 一致。
|
||||
- 一个公开模型原则上放在一个独立 `.py` 文件中。
|
||||
- 求解器、介质、通用方程和状态对象不得放入组件库目录。
|
||||
- 未准备对外注册的实验类可以保留在库内,但不得加入库清单。
|
||||
- 禁止通过扫描任意 `.py` 文件并执行其中代码来发现模型;必须使用库清单进行受控导入。
|
||||
|
||||
## 4. 标识符和版本
|
||||
|
||||
### 4.1 标识符
|
||||
|
||||
以下字段使用稳定的英文机器标识:
|
||||
|
||||
- `library.id`
|
||||
- `category.id`
|
||||
- `MODEL_TYPE`
|
||||
- 端口名
|
||||
- 参数名
|
||||
- 结果变量名
|
||||
|
||||
标识符应使用 `snake_case`,只允许小写英文字母、数字和下划线,并以字母开头。
|
||||
已有工程约定中的 `T`、`U` 等热力学变量可以保留。
|
||||
|
||||
界面中文名称单独保存在 `label` 中。修改 `label` 不影响工程兼容性;修改机器标识
|
||||
会影响工程文件、System XML、结果文件和后端注册,因此发布后不得直接改名。
|
||||
|
||||
### 4.2 版本
|
||||
|
||||
每个组件库和模型都应具有版本:
|
||||
|
||||
```python
|
||||
LIBRARY_VERSION = "0.1.0"
|
||||
MODEL_VERSION = "1.0.0"
|
||||
```
|
||||
|
||||
版本遵循 `主版本.次版本.修订版本`:
|
||||
|
||||
- 修订版本:只修复实现,不改变输入输出契约。
|
||||
- 次版本:向后兼容地新增参数、结果或能力。
|
||||
- 主版本:端口、参数语义或方程发生不兼容变化。
|
||||
|
||||
当前 System XML v3 要求每个 `Component` 显式保存 `modelVersion`,并与注册模型
|
||||
版本完全一致;不一致时拒绝加载,不做静默升级。v3 不另存 `library`,而由全局唯一的
|
||||
`Component/@type` 定位注册模型。旧模型的自动迁移仍未实现,需要另行提供显式规则。
|
||||
因此当前“修订/次版本向后兼容”只表示合同设计意图,不表示旧 XML 会被解析器自动
|
||||
接受;任意模型版本变化都会使旧 XML 的精确版本检查失败。
|
||||
|
||||
## 5. 组件库清单
|
||||
|
||||
每个库必须提供 `library.py`,并使用有类型的不可变声明:
|
||||
|
||||
```python
|
||||
from app.simulation.core.catalog import (
|
||||
ComponentCategorySpec,
|
||||
ComponentLibrarySpec,
|
||||
)
|
||||
|
||||
LIBRARY = ComponentLibrarySpec(
|
||||
id="experimental",
|
||||
label="临时测试组件库",
|
||||
version="0.1.0",
|
||||
source_package="app.simulation.components.experimental",
|
||||
temporary=True,
|
||||
order=100,
|
||||
categories=(
|
||||
ComponentCategorySpec(
|
||||
id="storage",
|
||||
label="储能元件",
|
||||
order=10,
|
||||
),
|
||||
ComponentCategorySpec(
|
||||
id="flow",
|
||||
label="流动元件",
|
||||
order=20,
|
||||
),
|
||||
ComponentCategorySpec(
|
||||
id="junctions",
|
||||
label="连接元件",
|
||||
order=30,
|
||||
),
|
||||
),
|
||||
models=(
|
||||
"app.simulation.components.experimental.storage.cylinder:Cylinder",
|
||||
"app.simulation.components.experimental.storage.tank:Tank",
|
||||
"app.simulation.components.experimental.flow.resistive_pipe:ResistivePipe",
|
||||
"app.simulation.components.experimental.flow.orifice:Orifice",
|
||||
"app.simulation.components.experimental.junctions.tee:Tee",
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
`models` 是唯一允许注册到系统的模型清单。它同时解决以下问题:
|
||||
|
||||
- 避免导入测试脚本或内部辅助类。
|
||||
- 控制模型加载顺序。
|
||||
- 避免同一个 `MODEL_TYPE` 被多个实现重复注册。
|
||||
- 可以只加载部署环境允许使用的组件库。
|
||||
- 启动错误能明确定位到具体库和模型。
|
||||
|
||||
当前 `experimental/library.py` 已按此格式声明库、分类和五个公开模型;
|
||||
`experimental/__init__.py` 只公开规范化的 `LIBRARY` 清单。
|
||||
|
||||
## 6. 模型类契约
|
||||
|
||||
一个可注册模型必须显式声明:
|
||||
|
||||
```python
|
||||
class ExampleComponent(Component):
|
||||
MODEL_TYPE = "example_component"
|
||||
MODEL_VERSION = "1.0.0"
|
||||
PORTS = (...)
|
||||
PARAMETERS = (...)
|
||||
RESULT_VARIABLES = (...)
|
||||
DISPLAY = ...
|
||||
```
|
||||
|
||||
字段含义:
|
||||
|
||||
| 字段 | 是否必须 | 用途 |
|
||||
| --- | --- | --- |
|
||||
| `MODEL_TYPE` | 必须 | System XML、注册表和结果元数据中的稳定类型 |
|
||||
| `MODEL_VERSION` | 必须 | 模型契约和迁移版本 |
|
||||
| `PORTS` | 必须 | 物理或信号连接契约 |
|
||||
| `PARAMETERS` | 必须,可为空 | 用户输入参数及校验边界 |
|
||||
| `RESULT_VARIABLES` | 必须,可为空 | 组件级可展示结果 |
|
||||
| `DISPLAY` | 必须 | 前端名称、分类、图标、排序和端口布局 |
|
||||
|
||||
模型实现还必须满足:
|
||||
|
||||
1. 构造函数调用 `super().__init__(name)`。
|
||||
2. 使用 `set_parameter_values()` 保存所有规范化后的参数。
|
||||
3. 使用 `register_declared_port()` 创建 `PORTS` 中声明的端口。
|
||||
4. 组件级结果键必须与 `RESULT_VARIABLES` 完全一致。
|
||||
5. 所有内部计算均使用 SI 基准值。
|
||||
6. 模型不能直接依赖 FastAPI、React Flow 或 XML DOM。
|
||||
7. 模型的方程不能依赖图标方向、界面分类或画布位置。
|
||||
|
||||
完整方程示例参见
|
||||
[`app/simulation/components/example.md`](../../app/simulation/components/example.md)。
|
||||
|
||||
## 7. 界面显示声明
|
||||
|
||||
`DISPLAY` 只描述模型在前端的呈现,不参与物理求解:
|
||||
|
||||
```python
|
||||
from app.simulation.core.catalog import (
|
||||
ComponentDisplaySpec,
|
||||
PortDisplaySpec,
|
||||
)
|
||||
|
||||
DISPLAY = ComponentDisplaySpec(
|
||||
label="示例容腔",
|
||||
library_id="experimental",
|
||||
category_id="storage",
|
||||
symbol="cylinder",
|
||||
order=90,
|
||||
ports=(
|
||||
PortDisplaySpec(
|
||||
name="port_a",
|
||||
side="left",
|
||||
order=10,
|
||||
),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
字段规则:
|
||||
|
||||
- `label`:组件库中的显示名称。
|
||||
- `library_id`:必须引用已加载的库。
|
||||
- `category_id`:必须引用该库已声明的分类。
|
||||
- `symbol`:前端图形渲染器的稳定标识。
|
||||
- `order`:同一分类中的排序值。
|
||||
- `ports`:只声明端口在图形中的位置和顺序。
|
||||
|
||||
`DISPLAY.ports` 中的端口名必须与模型的 `PORTS` 完全一致,不能缺少、增加或改名。
|
||||
旋转和镜像只改变前端计算后的视觉方位,不改变端口机器名和物理语义。
|
||||
|
||||
前端遇到未知 `symbol` 时必须显示通用占位图标,同时保留模型拖拽、参数编辑、
|
||||
连线和 XML 生成功能,不能因为缺少专用图形而丢弃整个模型。
|
||||
|
||||
## 8. 端口规范
|
||||
|
||||
端口由 `PortDefinition` 声明:
|
||||
|
||||
```python
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic(
|
||||
"port_a",
|
||||
nominal_role="bidirectional",
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
每个端口必须包含:
|
||||
|
||||
- 稳定端口名。
|
||||
- `kind`:`physical` 或 `signal`。
|
||||
- `domain`:例如 `pneumatic`。
|
||||
- `nominal_role`:用于界面提示,不决定实际流向。
|
||||
- `positive_flow_direction`:物理流量变量的符号约定。
|
||||
- 端口变量及各自连接规则。
|
||||
|
||||
当前气动功率端口包含:
|
||||
|
||||
| 变量 | 角色 | 连接规则 | 单位 |
|
||||
| --- | --- | --- | --- |
|
||||
| `p` | effort | `equal` | `Pa` |
|
||||
| `m_flow` | flow | `sumToZero` | `kg/s` |
|
||||
| `h_outflow` | stream | `streamMix` | `J/kg` |
|
||||
|
||||
气动端口统一约定 `m_flow > 0` 表示质量流入当前组件。`inlet`、`outlet` 是标称角色,
|
||||
不应阻止反向流动;实际方向由求解结果中的流量符号决定。
|
||||
|
||||
连接校验至少包括:
|
||||
|
||||
1. 两个端口均存在。
|
||||
2. 端口不能连接自身。
|
||||
3. `kind` 相同。
|
||||
4. `domain` 相同。
|
||||
5. 端口变量集合及连接规则兼容。
|
||||
6. 同一物理端口的连接数量符合当前网络编译器能力。
|
||||
|
||||
## 9. 参数规范
|
||||
|
||||
参数使用 `ParameterDefinition` 声明:
|
||||
|
||||
```python
|
||||
PARAMETERS = (
|
||||
ParameterDefinition(
|
||||
name="volume",
|
||||
label="容积",
|
||||
quantity="volume",
|
||||
unit="m3",
|
||||
default=0.1,
|
||||
minimum=0.0,
|
||||
minimum_exclusive=True,
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
规则如下:
|
||||
|
||||
- `name` 是模型构造、XML 和工程文件共同使用的稳定名称。
|
||||
- `label` 是界面文案。
|
||||
- `quantity` 是受控物理量标识,用于前端匹配可换算单位。
|
||||
- `unit` 是后端 SI 单位。
|
||||
- `default` 必须能够直接创建合法模型。
|
||||
- 边界必须与方程有效范围一致。
|
||||
- 无量纲量使用 `quantity="dimensionless"` 和 `unit=""`。
|
||||
- 用户输入可以使用其他公制单位,但提交后端前必须换算为 SI。
|
||||
- 文本框编辑中的临时字符串不立即判错,失焦、回车或运行仿真时再执行数值校验。
|
||||
|
||||
后端不得静默忽略未知参数。缺少参数时可使用声明的默认值;出现未知参数时必须
|
||||
返回包含组件 ID 和参数名的明确错误。
|
||||
|
||||
## 10. 结果变量规范
|
||||
|
||||
组件结果和端口结果分开管理:
|
||||
|
||||
- 组件结果来自 `RESULT_VARIABLES`。
|
||||
- 端口结果根据 `PORTS` 中 `result_visible=True` 的端口变量自动生成。
|
||||
- 求解器缓存、残差和调试量默认不进入用户结果。
|
||||
|
||||
每个结果变量必须提供:
|
||||
|
||||
- `name`
|
||||
- `label`
|
||||
- `quantity`
|
||||
- `unit`
|
||||
- `category`
|
||||
- `order`
|
||||
|
||||
仿真结果必须输出结构化元数据,前端禁止拆解结果键或按字符串关键词猜测:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "cylinder_1.port_b.p",
|
||||
"componentId": "cylinder_1",
|
||||
"componentType": "cylinder",
|
||||
"scope": "port",
|
||||
"portName": "port_b",
|
||||
"name": "p",
|
||||
"label": "压力",
|
||||
"quantity": "pressure",
|
||||
"unit": "Pa",
|
||||
"category": "effort",
|
||||
"order": 10
|
||||
}
|
||||
```
|
||||
|
||||
结果页应按 `componentId`、`scope`、`portName`、`quantity` 等结构化字段筛选,
|
||||
而不是从 `key` 中推断组件、端口和变量。
|
||||
|
||||
## 11. 标准模型创建入口
|
||||
|
||||
注册中心通过统一入口创建模型,避免长期维护集中式 `_cylinder_factory`、
|
||||
`_tank_factory` 等适配函数。当前接口为:
|
||||
|
||||
```python
|
||||
@classmethod
|
||||
def create(
|
||||
cls,
|
||||
*,
|
||||
name: str,
|
||||
medium: IdealGasMedium,
|
||||
parameters: Mapping[str, float],
|
||||
) -> Component:
|
||||
...
|
||||
```
|
||||
|
||||
创建流程:
|
||||
|
||||
1. 注册中心按 `PARAMETERS` 填充默认值。
|
||||
2. 校验数值有限性和上下限。
|
||||
3. 拒绝未知参数。
|
||||
4. 调用模型类的 `create()`。
|
||||
5. 验证实例的模型类型、端口和参数快照。
|
||||
6. 将实例交给网络编译器。
|
||||
|
||||
这种方式允许 Python 构造参数保留内部命名,同时对外始终使用规范中的参数名。
|
||||
|
||||
## 12. 自动发现与注册
|
||||
|
||||
后端启动时按以下顺序建立注册表:
|
||||
|
||||
```text
|
||||
读取启用的 library.py
|
||||
-> 校验库 ID、版本和分类
|
||||
-> 按 models 清单导入模型类
|
||||
-> 读取模型静态契约
|
||||
-> 执行跨字段校验
|
||||
-> 建立 library registry
|
||||
-> 建立 model registry
|
||||
-> 构建前端 catalog
|
||||
```
|
||||
|
||||
当前使用显式启用列表:
|
||||
|
||||
```python
|
||||
ENABLED_COMPONENT_LIBRARIES = (
|
||||
"app.simulation.components.experimental.library:LIBRARY",
|
||||
)
|
||||
```
|
||||
|
||||
禁止以下发现方式:
|
||||
|
||||
- 在整个仓库递归导入所有 Python 文件。
|
||||
- 依赖文件名自动推断 `MODEL_TYPE`。
|
||||
- 由前端硬编码后端类路径。
|
||||
- 导入失败后悄悄跳过模型。
|
||||
- 多个实现重复注册同一个模型类型并由加载顺序决定最终结果。
|
||||
|
||||
发现或校验失败时,FastAPI 应拒绝启动并给出库 ID、模型类型、字段和原因。
|
||||
|
||||
## 13. 启动校验规则
|
||||
|
||||
注册表完成前必须执行以下校验:
|
||||
|
||||
### 13.1 库与分类
|
||||
|
||||
- 库 ID 全局唯一。
|
||||
- 库版本格式有效。
|
||||
- 分类 ID 在库内唯一。
|
||||
- 所有排序值为整数。
|
||||
- 所有模型引用已存在的库和分类。
|
||||
|
||||
### 13.2 模型
|
||||
|
||||
- `MODEL_TYPE` 全局唯一,且与注册键一致。
|
||||
- 模型版本格式有效。
|
||||
- 模型继承框架要求的基类。
|
||||
- 模型提供统一创建入口。
|
||||
- 默认参数能够成功创建实例。
|
||||
|
||||
### 13.3 端口
|
||||
|
||||
- 端口名在模型内唯一。
|
||||
- 显示端口集合与物理端口集合完全一致。
|
||||
- 端口物理域、变量角色和连接规则有效。
|
||||
- 实例实际注册的端口与静态声明一致。
|
||||
|
||||
### 13.4 参数
|
||||
|
||||
- 参数名在模型内唯一。
|
||||
- 默认值有限且满足边界。
|
||||
- `minimum <= maximum`。
|
||||
- `quantity` 和 `unit` 的组合已登记。
|
||||
- 实例保留所有规范化参数,不得静默修改或丢失。
|
||||
|
||||
### 13.5 结果
|
||||
|
||||
- 结果变量名在对应作用域内唯一。
|
||||
- `quantity` 和单位有效。
|
||||
- `component_result_values()` 的键与声明一致。
|
||||
- 端口结果只来自声明为可见的端口变量。
|
||||
|
||||
## 14. 前端组件目录协议
|
||||
|
||||
前端只通过以下接口读取组件库:
|
||||
|
||||
```http
|
||||
GET /api/components/catalog
|
||||
```
|
||||
|
||||
目录顶层必须具有版本:
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"libraries": []
|
||||
}
|
||||
```
|
||||
|
||||
单个模型至少包含:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "cylinder",
|
||||
"modelType": "cylinder",
|
||||
"modelVersion": "1.0.0",
|
||||
"label": "气瓶",
|
||||
"symbol": "cylinder",
|
||||
"order": 10,
|
||||
"category": {
|
||||
"id": "storage",
|
||||
"label": "储能元件",
|
||||
"order": 10
|
||||
},
|
||||
"ports": [],
|
||||
"parameters": []
|
||||
}
|
||||
```
|
||||
|
||||
前端读取规则:
|
||||
|
||||
1. 按库 `order`、分类 `order`、模型 `order` 排序。
|
||||
2. 使用 `type` 作为拖拽数据和工程文件中的稳定类型。
|
||||
3. 使用 `label` 显示中文名称。
|
||||
4. 使用 `ports` 生成 React Flow Handle。
|
||||
5. 使用 `parameters` 生成参数输入和单位选择控件。
|
||||
6. 使用 `symbol` 选择图标渲染器。
|
||||
7. 不在前端重新定义参数默认值、边界或端口语义。
|
||||
|
||||
目录协议提供以下可选的参数编辑器与 AMESim 介质扩展字段:
|
||||
|
||||
- 参数的 `editor: "choice"` 表示数值是稳定的离散编码,必须同时提供非空
|
||||
`options: [{"value": 1, "label": "..."}]`。前端显示标签,但工程、XML 与
|
||||
求解器仍保存和接收 `value` 数值,不得把标签写入模型数据。
|
||||
- 参数可通过 `visibleWhen: [{"parameter": "mode", "values": [1, 2]}]`
|
||||
声明显示条件。多个条件之间按 AND 处理,同一条件的多个 `values` 按 OR
|
||||
处理;控制参数必须拥有固定 `options`。隐藏参数的既有值必须保留,不能因
|
||||
界面联动而重置或从工程、XML 中删除。
|
||||
- 模型可通过可选的 `parameterGroups` 声明纯展示用参数分组。每组包含稳定的
|
||||
`id`、显示 `label`、组间 `order`、有序参数名数组 `parameters` 和布尔值
|
||||
`defaultExpanded`;默认应为 `false`。同一参数最多属于一个组,组内参数名
|
||||
必须引用该模型已注册的参数。分组不改变参数默认值、条件显示、工程保存或
|
||||
System XML 语义;无分组的模型不输出该字段。
|
||||
- 参数的 `editor: "amesimGasReference"` 表示该数值不是普通连续量,而是
|
||||
项目介质定义的 `gi` 引用。前端应保留索引 `0`,并从当前画布的介质定义
|
||||
组件生成其余下拉项;索引下拉项只显示数值,不拼接介质名称或中文说明。
|
||||
- 参数的 `editor: "amesimGasPropertyModel"` 表示该参数选择介质定义内部的
|
||||
物性计算模型。参数同时提供 `options: [{"value": 0, "label": "理想气体"}]`
|
||||
一类目录数据,前端据此生成下拉栏;后续增加算法时由介质模型注册新的选项,
|
||||
前端不硬编码算法名称。
|
||||
- 模型的 `role: "amesimGasMediumDefinition"` 表示该模型是项目级介质定义。
|
||||
此类模型允许 `ports: []`,在 System XML v3 中仍按普通零端口
|
||||
`Component` 保存;XML 不写任何 `Port` 快照,只保存模型版本和完整参数。
|
||||
|
||||
这些字段在目录对象中均为可选。宽松读取目录的消费者可以把未知编辑器参数
|
||||
退化为普通数值输入;按本仓库 JSON Schema 严格校验的消费者必须与后端成套
|
||||
升级,才能识别新增的 `editor` 值和 `options` 字段。正式前端必须依据目录字段
|
||||
生成控件,不能硬编码具体 AMESim 模型名。
|
||||
|
||||
`property_model` 是每种介质组件内部的稳定选项编号,不等同于 AMESim 原始
|
||||
`eosType`。例如空气组件的 `property_model=0` 表示理想气体,并映射到
|
||||
`fluidType=2/eosType=1`;氦气组件的 `property_model=0` 表示
|
||||
Peng-Robinson,并映射到 `fluidType=12/eosType=6`。编译层负责保存这种映射,
|
||||
前端只使用目录选项。
|
||||
|
||||
前端不再维护内置兜底目录。后端目录不可用时,组件区保持为空,并在“组件库”
|
||||
标题旁显示红色“加载失败”状态;悬停或聚焦该状态可查看失败范围和详细原因。
|
||||
`experimental` 试验库即使由成功的目录响应返回,也不会出现在组件区。
|
||||
|
||||
### 14.1 前端实际读取步骤
|
||||
|
||||
React Flow 启动时:
|
||||
|
||||
1. 使用 `no-store` 请求 `/api/components/catalog`。
|
||||
2. 检查 `schemaVersion == 1`。
|
||||
3. 检查库、模型、端口和参数结构。
|
||||
4. 检查模型 `type` 是否全局重复。
|
||||
5. 将参数数组转换为参数面板定义。
|
||||
6. 按库、分类和模型的 `order` 排序。
|
||||
7. 过滤仅用于注册验证的 `experimental` 试验库。
|
||||
8. 成功时用绿色状态显示“已加载 X 个组件库”,不追加其他成功说明。
|
||||
9. 请求或格式校验失败时显示红色“加载失败”,不显示任何兜底组件;悬停状态可
|
||||
查看具体库名(目录响应可识别时)或受影响范围、接口地址与错误原因。
|
||||
|
||||
### 14.2 修改后如何生效
|
||||
|
||||
修改 Python 模型、库清单或注册器后必须重启 FastAPI:
|
||||
|
||||
```powershell
|
||||
cd F:\Master\SystemSimulationApp
|
||||
.\.venv-win\Scripts\python.exe -m uvicorn app.main:app --host 127.0.0.1 --port 8000
|
||||
```
|
||||
|
||||
只刷新浏览器无法让已运行的 Python 进程重新导入模型。前端源代码由 Vite 开发服务
|
||||
热更新;普通目录内容变化不需要重启 Vite。
|
||||
|
||||
## 15. System XML 映射
|
||||
|
||||
System XML 中:
|
||||
|
||||
```xml
|
||||
<Component
|
||||
id="cylinder_1"
|
||||
type="cylinder"
|
||||
modelVersion="1.0.0">
|
||||
<Parameter name="volume" value="0.01"/>
|
||||
</Component>
|
||||
```
|
||||
|
||||
映射规则:
|
||||
|
||||
- `id`:工程内唯一的组件实例 ID。
|
||||
- `type`:必须匹配唯一的 `MODEL_TYPE`。
|
||||
- `modelVersion`:必须与该模型当前 `MODEL_VERSION` 完全一致。
|
||||
- `<Parameter name>`:必须完整且只能来自模型的 `PARAMETERS`,数值使用 SI。
|
||||
- XML v3 不保存 `name/componentType/Port` 或画布布局;连接中的
|
||||
`Endpoint/@port` 必须存在于模型的 `PORTS`。
|
||||
|
||||
介质定义组件不通过物理端口连接。编译器先收集目录角色为
|
||||
`amesimGasMediumDefinition` 的零端口组件,再解析带
|
||||
`editor="amesimGasReference"` 参数的组件引用;介质定义组件本身不进入数值
|
||||
仿真网络。System XML 语义校验会在编译前检查介质索引的整数范围、定义唯一
|
||||
性、正索引引用完整性,以及同一气动连通分量的引用一致性。
|
||||
|
||||
XML 解析器只负责结构、引用和契约校验;模型注册中心负责选择 Python 类并创建实例;
|
||||
模型自身负责方程和状态。三层职责不得混合。
|
||||
|
||||
## 16. 测试要求
|
||||
|
||||
每个新模型至少需要:
|
||||
|
||||
1. 元数据测试:模型类型、端口、参数和结果声明合法。
|
||||
2. 目录测试:模型出现在正确库和分类中。
|
||||
3. 默认创建测试:默认参数能构造模型。
|
||||
4. 参数边界测试:非法值被拒绝,错误信息包含组件和参数。
|
||||
5. 端口测试:实例端口与声明完全一致。
|
||||
6. XML 测试:最小系统能解析并映射到正确模型。
|
||||
7. 方程测试:至少验证一个稳态、残差或守恒关系。
|
||||
8. 最小仿真测试:一个短时算例能产生有限结果和结构化结果元数据。
|
||||
|
||||
库级测试还应检查:
|
||||
|
||||
- 库清单中的所有类均可导入。
|
||||
- 所有模型类型全局唯一。
|
||||
- 无遗漏或重复分类。
|
||||
- `GET /api/components/catalog` 满足目录 schema。
|
||||
|
||||
## 17. 新增模型操作清单
|
||||
|
||||
开发者新增模型时只执行以下步骤:
|
||||
|
||||
1. 在目标库的正确分类目录中新建模型文件。
|
||||
2. 实现 `MODEL_TYPE`、`MODEL_VERSION`、`PORTS`、`PARAMETERS`、
|
||||
`RESULT_VARIABLES` 和 `DISPLAY`。
|
||||
3. 实现统一 `create()` 和模型方程。
|
||||
4. 将模型类路径加入该库 `library.py` 的 `models`。
|
||||
5. 添加模型单元测试和最小 XML/仿真测试。
|
||||
6. 运行注册校验和完整测试。
|
||||
7. 重启 FastAPI,刷新前端确认目录来源为“后端目录”。
|
||||
|
||||
正常情况下不需要修改:
|
||||
|
||||
- React Flow 左侧组件列表。
|
||||
- 参数面板字段。
|
||||
- System XML 模型类型分派代码。
|
||||
- 结果变量关键词映射。
|
||||
- 集中式模型工厂表。
|
||||
|
||||
### 17.1 AI 修改约束
|
||||
|
||||
AI 在处理组件库读取任务时必须:
|
||||
|
||||
1. 先确认目标是新增模型、修改模型还是新增库。
|
||||
2. 读取当前启用列表和目标库清单。
|
||||
3. 只把公开模型加入 `library.py/models`。
|
||||
4. 不通过递归扫描替代显式清单。
|
||||
5. 不在前端重新声明后端契约作为正式实现。
|
||||
6. 不静默跳过加载失败的模型。
|
||||
7. 保留未知 `symbol` 的通用图标回退能力。
|
||||
8. 修改后检查目录响应,并运行注册表和前端构建测试。
|
||||
9. 告知用户需要重启 FastAPI。
|
||||
|
||||
AI 不应仅因为某个 `.py` 文件位于组件目录,就假定它是公开模型。公开性的唯一判断
|
||||
依据是该类是否出现在已启用库的 `models` 清单中。
|
||||
|
||||
## 18. 当前实现与目标规范的差异
|
||||
|
||||
| 能力 | 当前状态 | 目标 |
|
||||
| --- | --- | --- |
|
||||
| 库 ID、名称、版本、分类和模型清单 | 已实现 | 由各库 `library.py` 维护 |
|
||||
| 库和模型注册表 | 已实现 | 由已启用库清单自动构建 |
|
||||
| 前端目录接口 | 已实现 | 已包含库版本和模型版本 |
|
||||
| 前端动态分类和参数读取 | 已实现 | 新增已支持图标的模型无需改组件列表 |
|
||||
| 端口与参数契约 | 已实现 | 保持为唯一事实来源 |
|
||||
| 结构化结果元数据 | 已实现 | 保持为唯一事实来源 |
|
||||
| `DISPLAY` | 已实现 | 由公开模型类自行声明 |
|
||||
| 模型工厂 | 已实现 | 模型类统一 `create()` |
|
||||
| 模型发现 | 已实现 | 按库清单受控发现 |
|
||||
| 启动校验 | 已实现首版 | 覆盖版本、分类、端口、参数、单位和默认实例 |
|
||||
| System XML 中的模型版本 | 已实现 | v3 显式保存并严格匹配 `modelVersion` |
|
||||
| 工程 JSON 的整体版本 | 已实现 | 固定为 `projectSchemaVersion: 1`,节点显式锁定 `modelVersion` |
|
||||
| 自动版本迁移 | 未实现 | 当前明确拒绝不匹配版本,本阶段不实现迁移 |
|
||||
| 目录 JSON Schema | 已实现 | `schemas/component-catalog-v1.schema.json` |
|
||||
|
||||
## 19. 推荐实施顺序
|
||||
|
||||
1. 已完成:声明类型已放入独立的 `core/catalog.py`。
|
||||
2. 已完成:`experimental/library.py` 已成为临时库唯一清单入口。
|
||||
3. 已完成:五个公开模型自行声明 `DISPLAY` 和 `MODEL_VERSION`。
|
||||
4. 已完成:公开模型统一实现 `create()`,集中式工厂函数已删除。
|
||||
5. 已完成:注册表由库清单构建,并在导入时执行契约和默认实例校验。
|
||||
6. 已完成:已增加组件目录 JSON Schema。
|
||||
7. 已完成:System XML v3 保存并严格校验模型版本;工程 JSON 使用
|
||||
`projectSchemaVersion: 1`,每个节点保存创建时的 `modelVersion`,当前不实现旧工程迁移。
|
||||
8. 待完成:规范稳定后新建正式组件库,不再向 `experimental` 增加生产模型。
|
||||
|
||||
该顺序可以保证每一步都保持现有前端和 System XML 可用,不需要一次性重写模型、
|
||||
解析器和界面。
|
||||
|
||||
## 20. 改动影响表
|
||||
|
||||
| 想做的改动 | 必须修改 | 通常不需要修改 |
|
||||
| --- | --- | --- |
|
||||
| 新增同库同分类模型 | 模型文件、`library.py/models`、测试 | 注册表、前端参数列表 |
|
||||
| 新增分类 | 库 `categories`、模型 `DISPLAY.category_id`、测试 | 物理端口和求解器 |
|
||||
| 新增组件库 | 新库包和 `library.py`、启用列表、测试 | 已有库清单 |
|
||||
| 修改参数默认值或范围 | 模型 `PARAMETERS`、测试、必要的版本 | 前端参数硬编码 |
|
||||
| 修改端口 | 模型 `PORTS`、`DISPLAY.ports`、主版本、XML/网络拒绝边界测试 | 库分类 |
|
||||
| 新增专用图标 | 模型 `DISPLAY.symbol`、前端图标渲染器 | 参数和物理方程 |
|
||||
| 新增物理域 | 端口协议、网络、求解器、XML、前端兼容规则和测试 | 仅修改分类名称 |
|
||||
| 修改目录响应结构 | 后端序列化、JSON Schema、前端解析、协议版本和测试 | 单个模型方程 |
|
||||
|
||||
## 21. 读取故障排查
|
||||
|
||||
| 现象 | 优先检查 |
|
||||
| --- | --- |
|
||||
| 模型完全没有出现在目录响应 | 模型类路径是否加入已启用库的 `models` |
|
||||
| FastAPI 无法启动 | 启动错误中的库、模型和字段;通常是契约校验失败 |
|
||||
| 接口有模型但前端没有 | `schemaVersion`、前端控制台、目录规范化错误 |
|
||||
| 前端显示红色“加载失败” | 悬停状态查看详情,再检查 8000 端口、`/api/components/catalog`、后端是否重启 |
|
||||
| 分类错误 | `DISPLAY.category_id` 与库 `categories` |
|
||||
| 端口数量或位置错误 | `PORTS` 与 `DISPLAY.ports` 是否完全一致 |
|
||||
| 参数面板缺字段 | 模型 `PARAMETERS` 和目录响应,不先改前端 |
|
||||
| XML 报不支持类型 | XML `type` 是否精确匹配 `MODEL_TYPE` |
|
||||
| 图标是通用图形 | `symbol` 尚无专用前端渲染器,但模型仍应可用 |
|
||||
|
||||
最小诊断命令:
|
||||
|
||||
```powershell
|
||||
.\.venv-win\Scripts\python.exe -c "from app.simulation.registry import build_component_catalog; print(build_component_catalog())"
|
||||
.\.venv-win\Scripts\python.exe -m unittest tests.test_component_registry tests.test_component_catalog
|
||||
```
|
||||
@@ -0,0 +1,725 @@
|
||||
# 组件模型建模规范 v1
|
||||
|
||||
状态:已在 `experimental` 临时组件库实施
|
||||
适用对象:人工开发者、代码生成工具和 AI 编程助手
|
||||
配套读取规范:[组件库分类、发现与读取规范 v1](component-library-spec-v1.md)
|
||||
|
||||
## 1. 文档目标
|
||||
|
||||
本文档规定一个 Python 仿真元件应如何创建、修改、测试和注册。完成后的模型必须
|
||||
同时满足四个使用方:
|
||||
|
||||
1. 求解器能够实例化模型并调用方程。
|
||||
2. System XML 能够根据稳定类型找到模型。
|
||||
3. React Flow 能够自动显示图标、端口和参数。
|
||||
4. 结果页面能够根据结构化元数据展示变量。
|
||||
|
||||
本文档是模型代码的开发合同。若本文档与当前代码行为不一致,应把它视为缺陷:
|
||||
先核对实际实现,再在同一次修改中同步代码、测试和文档,禁止让两套规则长期并存。
|
||||
|
||||
## 2. 开始前先判断任务类型
|
||||
|
||||
### 2.1 新增公开模型
|
||||
|
||||
公开模型会出现在前端组件库中,也能被 System XML 创建。必须:
|
||||
|
||||
- 放入某个组件库的分类目录。
|
||||
- 实现完整模型契约。
|
||||
- 加入该库 `library.py` 的 `models` 清单。
|
||||
- 添加目录、契约、方程和最小仿真测试。
|
||||
|
||||
### 2.2 修改已有公开模型
|
||||
|
||||
必须先判断改动是否破坏已有工程:
|
||||
|
||||
| 改动 | 版本建议 | 兼容性要求 |
|
||||
| --- | --- | --- |
|
||||
| 修复数值实现但不改变契约 | 修订版本 | 若提高 `modelVersion`,既有 XML 会因精确版本不匹配而被拒绝;需明确是否真的变更合同 |
|
||||
| 新增有默认值的参数或结果 | 次版本 | 新 XML 必须写全当前参数;本阶段不提供旧文件自动迁移 |
|
||||
| 修改界面名称或图标 | 库修订版本 | 不修改机器标识 |
|
||||
| 修改方程的物理语义 | 根据影响提高次版本或主版本 | 补充基准和变更说明 |
|
||||
| 删除、改名端口或参数 | 主版本 | 当前格式直接拒绝旧端口或参数;如以后需要兼容,再单独设计迁移器 |
|
||||
| 修改 `MODEL_TYPE` | 视为新模型 | 旧类型必须保留迁移映射 |
|
||||
|
||||
### 2.3 新增内部模型
|
||||
|
||||
仅供固定算例或研究代码使用、不进入前端目录的模型,不加入 `library.py`。这类模型
|
||||
应放在对应 `examples/` 或专用系统目录,不能与公开模型混放后依赖扫描规则排除。
|
||||
|
||||
当前示例是
|
||||
[`app/simulation/examples/testmodel/dynamic_pipe.py`](../../app/simulation/examples/testmodel/dynamic_pipe.py)。
|
||||
|
||||
### 2.4 新增物理域
|
||||
|
||||
仅新增模型类不足以支持新物理域。除了模型,还必须设计:
|
||||
|
||||
- `PortDefinition` 和端口变量。
|
||||
- 变量角色与连接规则。
|
||||
- 网络兼容性检查。
|
||||
- 代数方程和 stream/signal 传播。
|
||||
- XML 端口协议。
|
||||
- 前端连线兼容规则。
|
||||
- 最小闭合系统与求解测试。
|
||||
|
||||
没有完成这些基础能力时,不得仅通过修改 `domain` 字符串宣称支持新物理域。
|
||||
|
||||
## 3. 开发前必须读取的文件
|
||||
|
||||
人工或 AI 在修改模型前,应按顺序读取:
|
||||
|
||||
1. 本文档。
|
||||
2. 目标库的 `library.py`。
|
||||
3. 同分类中物理行为最接近的现有模型。
|
||||
4. [`core/base.py`](../../app/simulation/core/base.py)。
|
||||
5. [`core/ports.py`](../../app/simulation/core/ports.py)。
|
||||
6. [`core/metadata.py`](../../app/simulation/core/metadata.py)。
|
||||
7. [`core/catalog.py`](../../app/simulation/core/catalog.py)。
|
||||
8. [`registry.py`](../../app/simulation/registry.py) 中的启动校验。
|
||||
9. 与目标模型最接近的测试。
|
||||
|
||||
不要只根据文件名、前端图标或旧 XML 猜测模型语义。
|
||||
|
||||
## 4. 文件位置和命名
|
||||
|
||||
公开模型放在:
|
||||
|
||||
```text
|
||||
app/simulation/components/<library_id>/<category_id>/<model_module>.py
|
||||
```
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
app/simulation/components/experimental/storage/cylinder.py
|
||||
app/simulation/components/experimental/flow/orifice.py
|
||||
app/simulation/components/experimental/junctions/tee.py
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
- 一个公开模型原则上对应一个文件和一个主要模型类。
|
||||
- 模块名、`MODEL_TYPE`、端口名和参数名使用稳定机器标识。
|
||||
- `MODEL_TYPE` 使用小写 `snake_case`。
|
||||
- 参数和结果变量允许保留已有热力学惯例,如 `T0`、`T`、`U`。
|
||||
- 中文名称只写入 `label`,不能代替机器标识。
|
||||
- 求解器、介质和网络通用逻辑不得复制到模型文件。
|
||||
|
||||
## 5. 公开模型完整契约
|
||||
|
||||
每个公开模型类必须在自身类体中显式声明:
|
||||
|
||||
```python
|
||||
MODEL_TYPE = "example_component"
|
||||
MODEL_VERSION = "1.0.0"
|
||||
PRESSURE_FLOW_DEPENDS_ON_STREAM = False
|
||||
PORTS = (...)
|
||||
PARAMETERS = (...)
|
||||
RESULT_VARIABLES = (...)
|
||||
DISPLAY = ...
|
||||
```
|
||||
|
||||
同时必须实现:
|
||||
|
||||
```python
|
||||
@classmethod
|
||||
def create(
|
||||
cls,
|
||||
*,
|
||||
name: str,
|
||||
medium: IdealGasMedium,
|
||||
parameters: Mapping[str, float],
|
||||
) -> Component:
|
||||
...
|
||||
```
|
||||
|
||||
注册器要求这些字段直接存在于公开模型类中。不要依赖父类隐式提供
|
||||
`MODEL_TYPE`、`MODEL_VERSION`、`PORTS`、`PARAMETERS`、`RESULT_VARIABLES`、
|
||||
`DISPLAY` 或 `create()`。
|
||||
|
||||
## 6. 基类选择
|
||||
|
||||
### 6.1 `AlgebraicComponent`
|
||||
|
||||
适用于没有积分状态、由当前端口变量和参数直接决定残差的元件,例如:
|
||||
|
||||
- 孔板
|
||||
- 阀门
|
||||
- 阻性管段
|
||||
- 理想三通
|
||||
|
||||
至少实现:
|
||||
|
||||
- 构造函数和端口注册。
|
||||
- `create()`。
|
||||
- `pressure_flow_equation_residuals()`。
|
||||
- 需要传递 stream 变量时实现 `update_stream_outflows()`。
|
||||
|
||||
实现 `update_stream_outflows()` 或 `update_flow_temperature_references()` 的公开模型,
|
||||
还应在该公开类自身显式声明 `PRESSURE_FLOW_DEPENDS_ON_STREAM`:构成压力/流量方程
|
||||
会读取这些 hook 写入的焓或温度引用时设为 `True`,否则设为 `False`。省略声明、
|
||||
声明非法值或由自定义子类仅继承父类声明时,求解器会保守使用全网热流闭合;不要
|
||||
为了获得分块加速而错误声明 `False`。
|
||||
|
||||
`pressure_flow_equation_residuals()` 返回的每条 `EquationResidual.variables` 必须完整
|
||||
列出该残差实际读取的全部代数端口量(`p/m_flow/x/v/f`),不能只写“主要变量”。
|
||||
求解器会用这份声明编译稀疏 Jacobian 和独立方程块;漏写依赖可能让有限差分方向
|
||||
不完整。仓库内置组件会接受结构与数值依赖回归,外部自定义组件当前仍保守使用
|
||||
全网 dense 回退,直到具备同等的依赖验证边界。
|
||||
|
||||
### 6.2 `ThermodynamicVolumeComponent`
|
||||
|
||||
适用于包含质量和能量状态的气体容腔,例如:
|
||||
|
||||
- 气瓶
|
||||
- 贮箱
|
||||
- 有容积的管段
|
||||
|
||||
至少实现:
|
||||
|
||||
- `get_state_vector()`。
|
||||
- `set_state_vector()`。
|
||||
- `refresh_thermodynamic_ports()`。
|
||||
- `state_derivative_from_ports()`。
|
||||
- `pressure_flow_equation_residuals()`。
|
||||
|
||||
该基类已经提供标准热力学组件结果:
|
||||
|
||||
```text
|
||||
m, U, p, T, rho, u, h
|
||||
```
|
||||
|
||||
除非物理含义不同,不要重新复制这组结果声明。
|
||||
|
||||
### 6.3 其他基类
|
||||
|
||||
如果现有基类不能表达模型,应先评估是否缺少一种通用组件能力。不要为了一个模型
|
||||
直接把专用判断塞入 `SimulationNetwork` 或求解器。
|
||||
|
||||
## 7. 端口建模规范
|
||||
|
||||
当前气动模型使用:
|
||||
|
||||
```python
|
||||
PortDefinition.pneumatic(
|
||||
"port_a",
|
||||
nominal_role="bidirectional",
|
||||
)
|
||||
```
|
||||
|
||||
气动端口包含:
|
||||
|
||||
| 变量 | 角色 | 连接规则 | SI 单位 |
|
||||
| --- | --- | --- | --- |
|
||||
| `p` | `effort` | `equal` | `Pa` |
|
||||
| `m_flow` | `flow` | `sumToZero` | `kg/s` |
|
||||
| `h_outflow` | `stream` | `streamMix` | `J/kg` |
|
||||
|
||||
必须遵守:
|
||||
|
||||
- `m_flow > 0` 表示质量流入当前组件。
|
||||
- `nominal_role` 只用于界面和默认布局,不限制实际流向。
|
||||
- 物理连接是非因果的,连接线端点顺序不代表流向。
|
||||
- 所有声明端口必须使用 `register_declared_port()` 创建。
|
||||
- `DISPLAY.ports` 必须与 `PORTS` 名称集合完全一致。
|
||||
- 分支连接使用三通等连接元件,不能让一个物理端口直接连接多条边。
|
||||
|
||||
禁止:
|
||||
|
||||
- 在模型内部根据画布左右方向判断流向。
|
||||
- 为了前端显示另造一套端口名。
|
||||
- 把 `port_a` 固定解释为真实入口、把 `port_b` 固定解释为真实出口。
|
||||
- 直接绕过端口状态读写其他组件对象。
|
||||
|
||||
## 8. 参数建模规范
|
||||
|
||||
所有用户可配置输入必须使用 `ParameterDefinition`:
|
||||
|
||||
```python
|
||||
ParameterDefinition(
|
||||
name="volume",
|
||||
label="容积",
|
||||
quantity="volume",
|
||||
unit="m3",
|
||||
default=0.1,
|
||||
minimum=0.0,
|
||||
minimum_exclusive=True,
|
||||
)
|
||||
```
|
||||
|
||||
字段含义:
|
||||
|
||||
| 字段 | 规则 |
|
||||
| --- | --- |
|
||||
| `name` | 稳定机器名,同时用于 XML、工程文件和 `create()` |
|
||||
| `label` | 前端显示名称,不能为空 |
|
||||
| `quantity` | 受控物理量标识 |
|
||||
| `unit` | 后端 SI 基准单位 |
|
||||
| `default` | 必须能够创建有效模型 |
|
||||
| `minimum` / `maximum` | 必须反映方程有效范围 |
|
||||
| `minimum_exclusive` | 用于直径、容积等严格大于零的量 |
|
||||
|
||||
当前受控单位定义在 `SI_UNIT_BY_QUANTITY`:
|
||||
|
||||
| quantity | SI 单位 |
|
||||
| --- | --- |
|
||||
| `acceleration` | `m/s2` |
|
||||
| `area` | `m2` |
|
||||
| `dimensionless` | 空字符串 |
|
||||
| `density` | `kg/m³` |
|
||||
| `flow_coefficient` | `kg/(s*Pa^0.5)` |
|
||||
| `force` | `N` |
|
||||
| `heat_transfer_coefficient` | `W/(m2*K)` |
|
||||
| `internal_energy` | `J` |
|
||||
| `length` | `m` |
|
||||
| `mass` | `kg` |
|
||||
| `mass_flow` | `kg/s` |
|
||||
| `pressure` | `Pa` |
|
||||
| `specific_enthalpy` | `J/kg` |
|
||||
| `specific_internal_energy` | `J/kg` |
|
||||
| `temperature` | `K` |
|
||||
| `time` | `s` |
|
||||
| `translational_damping` | `N/(m/s)` |
|
||||
| `translational_stiffness` | `N/m` |
|
||||
| `velocity` | `m/s` |
|
||||
| `volume` | `m3` |
|
||||
| `volume_flow` | `m3/s` |
|
||||
| `windage` | `N/(m/s)^2` |
|
||||
|
||||
新增物理量时必须先扩展后端受控单位表,再评估前端是否需要单位换算选项。禁止在
|
||||
单个模型中私自拼写新的同义 `quantity`。
|
||||
|
||||
构造函数必须调用:
|
||||
|
||||
```python
|
||||
self.set_parameter_values(
|
||||
{
|
||||
"volume": volume,
|
||||
"p0": p0,
|
||||
"T0": T0,
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
保存值、方程计算和结果输出都使用 SI。前端显示单位变化不能改变后端参数语义。
|
||||
|
||||
## 9. 结果变量规范
|
||||
|
||||
### 9.1 组件级结果
|
||||
|
||||
组件自身状态或派生量使用 `ResultVariableDefinition`:
|
||||
|
||||
```python
|
||||
ResultVariableDefinition(
|
||||
name="pressure_drop",
|
||||
label="压降",
|
||||
quantity="pressure",
|
||||
unit="Pa",
|
||||
category="derived",
|
||||
order=10,
|
||||
)
|
||||
```
|
||||
|
||||
声明后必须在 `component_result_values()` 返回同名值:
|
||||
|
||||
```python
|
||||
def component_result_values(self) -> Mapping[str, float]:
|
||||
return {
|
||||
"pressure_drop": self.port_a.p - self.port_b.p,
|
||||
}
|
||||
```
|
||||
|
||||
声明集合和返回键必须一致。
|
||||
|
||||
### 9.2 端口结果
|
||||
|
||||
端口结果由 `PORTS` 的端口变量自动产生,不要在 `RESULT_VARIABLES` 中重复声明
|
||||
`port_a.p`、`port_a.m_flow` 等字段。
|
||||
|
||||
### 9.3 禁止暴露的内容
|
||||
|
||||
以下内容默认不能作为用户结果:
|
||||
|
||||
- 非线性求解器内部未知量索引。
|
||||
- 缩放残差和迭代缓存。
|
||||
- 仅用于调试的临时中间值。
|
||||
- 可以由已有结果稳定推导、但没有明确工程用途的重复字段。
|
||||
|
||||
## 10. 显示声明规范
|
||||
|
||||
公开模型必须声明 `DISPLAY`:
|
||||
|
||||
```python
|
||||
DISPLAY = ComponentDisplaySpec(
|
||||
label="示例阻力元件",
|
||||
library_id="experimental",
|
||||
category_id="flow",
|
||||
symbol="generic",
|
||||
ports=(
|
||||
PortDisplaySpec("port_a", "left", order=10),
|
||||
PortDisplaySpec("port_b", "right", order=20),
|
||||
),
|
||||
order=90,
|
||||
)
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
- `library_id` 必须等于所属库 ID。
|
||||
- `category_id` 必须存在于所属库的 `categories`。
|
||||
- `symbol` 是前端图形键,不是模型类型。
|
||||
- 未实现专用图标时使用新的稳定键,前端会回退到通用图形。
|
||||
- 只有确实需要专用工程图标时才修改前端图标渲染器。
|
||||
- `side` 只允许 `left` 或 `right`。
|
||||
- 旋转和镜像不能改变端口名或物理语义。
|
||||
|
||||
## 11. 标准创建入口
|
||||
|
||||
`create()` 是注册器创建模型的唯一入口:
|
||||
|
||||
```python
|
||||
@classmethod
|
||||
def create(
|
||||
cls,
|
||||
*,
|
||||
name: str,
|
||||
medium: IdealGasMedium,
|
||||
parameters: Mapping[str, float],
|
||||
) -> ExampleComponent:
|
||||
return cls(
|
||||
name=name,
|
||||
medium=medium,
|
||||
coefficient=parameters["coefficient"],
|
||||
)
|
||||
```
|
||||
|
||||
注册器会在调用前:
|
||||
|
||||
1. 补齐默认参数。
|
||||
2. 拒绝未知参数。
|
||||
3. 检查有限值和边界。
|
||||
|
||||
调用后还会检查:
|
||||
|
||||
1. 返回对象类型正确。
|
||||
2. 实例 `model_type` 与 `MODEL_TYPE` 一致。
|
||||
3. 实际端口与 `PORTS` 完全一致。
|
||||
4. 实例保存的参数与规范化参数完全一致。
|
||||
|
||||
`create()` 不应重复实现参数默认值和边界校验,也不能静默修改传入参数。
|
||||
|
||||
## 12. 方程实现要求
|
||||
|
||||
模型方程必须满足:
|
||||
|
||||
- 残差形式统一为“期望等式左侧减右侧”。
|
||||
- 每条 `EquationResidual` 使用稳定、可定位的 `id`。
|
||||
- `variables` 列出该残差实际涉及的端口量或状态。
|
||||
- `role` 与方程主要约束的物理角色一致。
|
||||
- 对零压差、零流量和反向流动给出有限结果。
|
||||
- 必要正则化必须有物理解释,并通过边界测试保护。
|
||||
- 不得用画布坐标、连接线方向或组件名称决定方程。
|
||||
|
||||
### 12.1 可因果执行的残差语义
|
||||
|
||||
后端只会对经过结构门控的内置模型启用完全因果执行。除完整声明
|
||||
`variables` 外,这些模型还必须遵守以下可执行语义:
|
||||
|
||||
- `role="effort", relation="state"` 的残差写成
|
||||
`端口 effort - 状态给定值`,被约束的端口量系数必须为 `+1`。
|
||||
- `role="effort", relation="equal"` 的残差写成两个同类 effort 的差。
|
||||
- `role="flow", relation="sumToZero"` 按“流入组件为正”的约定求和,待消元
|
||||
flow 的系数必须为 `+1`。
|
||||
- `role="flow", relation="constitutive"` 写成
|
||||
`待消元 flow - 本构计算值`,待消元 flow 的系数必须为 `+1`。
|
||||
- `pressure_flow_equation_values()` 必须是无副作用的只读计算,返回顺序和长度
|
||||
必须与 `pressure_flow_equation_residuals()` 的编译结果永久一致;不得在求残差时
|
||||
修改端口、状态或活动集缓存。
|
||||
|
||||
求解器仍会在首次闭合、离散事件之后和固定周期执行完整残差审计。结构不满足、
|
||||
运行时覆盖不完整或审计不通过时,会立即熔断到原有残差/非线性求解路径。现场诊断
|
||||
时可在启动进程前设置 `SIMULATION_CAUSAL_FAST_PATH=0`,一键关闭该优化而不改变模型
|
||||
文件。
|
||||
|
||||
动态模型还必须:
|
||||
|
||||
- 状态向量长度稳定。
|
||||
- `get_state_vector()` 和 `set_state_vector()` 互为逆操作。
|
||||
- 状态导数满足质量和能量守恒约定。
|
||||
- 初始化默认值能够产生有限介质状态。
|
||||
|
||||
## 13. 可复制的代数模型模板
|
||||
|
||||
下面是一个符合当前规范的两端口代数阻力模板。复制后必须根据真实物理模型修改
|
||||
类型、参数、方程、名称和测试,不能只改类名就注册。
|
||||
|
||||
```python
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
from math import sqrt
|
||||
|
||||
from app.simulation.core.base import AlgebraicComponent
|
||||
from app.simulation.core.catalog import ComponentDisplaySpec, PortDisplaySpec
|
||||
from app.simulation.core.equations import EquationResidual
|
||||
from app.simulation.core.metadata import ParameterDefinition
|
||||
from app.simulation.core.medium import IdealGasMedium
|
||||
from app.simulation.core.ports import PortDefinition
|
||||
|
||||
|
||||
class ExampleRestriction(AlgebraicComponent):
|
||||
MODEL_TYPE = "example_restriction"
|
||||
MODEL_VERSION = "1.0.0"
|
||||
PRESSURE_FLOW_DEPENDS_ON_STREAM = False
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic("port_a", nominal_role="bidirectional"),
|
||||
PortDefinition.pneumatic("port_b", nominal_role="bidirectional"),
|
||||
)
|
||||
PARAMETERS = (
|
||||
ParameterDefinition(
|
||||
name="K",
|
||||
label="流量系数",
|
||||
quantity="flow_coefficient",
|
||||
unit="kg/(s*Pa^0.5)",
|
||||
default=1e-5,
|
||||
minimum=0.0,
|
||||
),
|
||||
)
|
||||
RESULT_VARIABLES = ()
|
||||
DISPLAY = ComponentDisplaySpec(
|
||||
label="示例阻力元件",
|
||||
library_id="experimental",
|
||||
category_id="flow",
|
||||
symbol="generic",
|
||||
ports=(
|
||||
PortDisplaySpec("port_a", "left", order=10),
|
||||
PortDisplaySpec("port_b", "right", order=20),
|
||||
),
|
||||
order=90,
|
||||
)
|
||||
|
||||
def __init__(self, name: str, K: float = 1e-5) -> None:
|
||||
super().__init__(name)
|
||||
self.set_parameter_values({"K": K})
|
||||
self.K = K
|
||||
self.port_a = self.register_declared_port("port_a")
|
||||
self.port_b = self.register_declared_port("port_b")
|
||||
|
||||
@classmethod
|
||||
def create(
|
||||
cls,
|
||||
*,
|
||||
name: str,
|
||||
medium: IdealGasMedium,
|
||||
parameters: Mapping[str, float],
|
||||
) -> ExampleRestriction:
|
||||
return cls(name=name, K=parameters["K"])
|
||||
|
||||
def pressure_flow_equation_residuals(
|
||||
self,
|
||||
) -> tuple[EquationResidual, ...]:
|
||||
pressure_difference = self.port_a.p - self.port_b.p
|
||||
expected_flow = (
|
||||
self.K
|
||||
* sqrt(abs(pressure_difference))
|
||||
* (1.0 if pressure_difference > 0.0 else -1.0)
|
||||
if pressure_difference != 0.0
|
||||
else 0.0
|
||||
)
|
||||
return (
|
||||
EquationResidual(
|
||||
id=f"{self.name}:mass_flow_balance",
|
||||
owner="component",
|
||||
owner_id=self.name,
|
||||
relation="sumToZero",
|
||||
variables=(
|
||||
f"{self.name}.port_a.m_flow",
|
||||
f"{self.name}.port_b.m_flow",
|
||||
),
|
||||
role="flow",
|
||||
value=self.port_a.m_flow + self.port_b.m_flow,
|
||||
),
|
||||
EquationResidual(
|
||||
id=f"{self.name}:pressure_flow_relation",
|
||||
owner="component",
|
||||
owner_id=self.name,
|
||||
relation="constitutive",
|
||||
variables=(
|
||||
f"{self.name}.port_a.p",
|
||||
f"{self.name}.port_b.p",
|
||||
f"{self.name}.port_a.m_flow",
|
||||
),
|
||||
role="flow",
|
||||
value=self.port_a.m_flow - expected_flow,
|
||||
),
|
||||
)
|
||||
|
||||
def update_stream_outflows(
|
||||
self,
|
||||
connected_h: Mapping[str, float],
|
||||
) -> None:
|
||||
self.port_a.h_outflow = connected_h["port_b"]
|
||||
self.port_b.h_outflow = connected_h["port_a"]
|
||||
```
|
||||
|
||||
真实现有模型可参考:
|
||||
|
||||
- 储能元件:
|
||||
[`cylinder.py`](../../app/simulation/components/experimental/storage/cylinder.py)
|
||||
- 阻性元件:
|
||||
[`orifice.py`](../../app/simulation/components/experimental/flow/orifice.py)
|
||||
- 多端口连接元件:
|
||||
[`tee.py`](../../app/simulation/components/experimental/junctions/tee.py)
|
||||
|
||||
## 14. 注册模型
|
||||
|
||||
模型文件完成后,只修改所属库的 `library.py`:
|
||||
|
||||
```python
|
||||
models=(
|
||||
# 已有模型
|
||||
"app.simulation.components.experimental.flow.example_restriction:ExampleRestriction",
|
||||
)
|
||||
```
|
||||
|
||||
禁止:
|
||||
|
||||
- 直接修改 `COMPONENT_MODEL_REGISTRY`。
|
||||
- 在前端复制参数和端口定义作为正式来源。
|
||||
- 递归扫描组件目录自动导入所有 `.py`。
|
||||
- 同时注册两个相同 `MODEL_TYPE`。
|
||||
- 把测试类、抽象基类或内部算例模型加入公开清单。
|
||||
|
||||
## 15. 测试要求
|
||||
|
||||
每个公开模型至少添加:
|
||||
|
||||
1. 静态契约测试。
|
||||
2. 默认参数创建测试。
|
||||
3. 参数边界测试。
|
||||
4. 端口与显示布局一致性测试。
|
||||
5. 关键方程残差测试。
|
||||
6. 零流量或反向流动测试。
|
||||
7. 目录输出测试。
|
||||
8. 最小 XML 编译测试。
|
||||
9. 能进入通用求解器的模型,再添加短时仿真测试。
|
||||
|
||||
推荐先运行:
|
||||
|
||||
```powershell
|
||||
.\.venv-win\Scripts\python.exe -m unittest `
|
||||
tests.test_component_registry `
|
||||
tests.test_component_catalog `
|
||||
tests.test_component_metadata
|
||||
```
|
||||
|
||||
然后运行完整回归:
|
||||
|
||||
```powershell
|
||||
.\.venv-win\Scripts\python.exe -m unittest discover -s tests
|
||||
```
|
||||
|
||||
目录契约影响前端时还要运行:
|
||||
|
||||
```powershell
|
||||
cd frontend
|
||||
$env:Path = 'F:\Master\SystemSimulationApp\.tools\node-v24.18.0-win-x64;' + $env:Path
|
||||
npm.cmd run build
|
||||
```
|
||||
|
||||
## 16. 修改已有模型的安全步骤
|
||||
|
||||
1. 找到 `MODEL_TYPE` 的所有 XML、工程和测试引用。
|
||||
2. 记录修改前的端口、参数、结果和默认行为。
|
||||
3. 判断版本级别和是否需要迁移。
|
||||
4. 先增加或修改测试,明确预期物理行为。
|
||||
5. 修改模型类,不在注册器和前端复制规则。
|
||||
6. 检查默认实例和旧参数是否仍能创建。
|
||||
7. 检查最小系统是否仍然闭合。
|
||||
8. 运行针对性测试和完整回归。
|
||||
9. 同步本文档或模型专属说明中的物理假设。
|
||||
|
||||
## 17. 人工或 AI 的任务输入卡
|
||||
|
||||
为了减少猜测,新增模型前建议先填写:
|
||||
|
||||
```text
|
||||
模型中文名称:
|
||||
MODEL_TYPE:
|
||||
所属 library_id:
|
||||
所属 category_id:
|
||||
物理域:
|
||||
模型用途和边界:
|
||||
端口列表及含义:
|
||||
参数列表、SI 单位、默认值和范围:
|
||||
状态变量:
|
||||
代数方程或微分方程:
|
||||
正流量约定:
|
||||
需要显示的组件结果:
|
||||
已知参考模型或工程公式:
|
||||
最小测试系统:
|
||||
允许的近似:
|
||||
明确不实现的能力:
|
||||
```
|
||||
|
||||
如果关键物理信息缺失,AI 应先通过现有模型、测试或用户提供的参考补齐;不能仅凭
|
||||
组件名称自行创造方程。
|
||||
|
||||
## 18. AI 修改协议
|
||||
|
||||
AI 创建或修改模型时必须遵守:
|
||||
|
||||
### 修改前
|
||||
|
||||
1. 读取第 3 节列出的文件。
|
||||
2. 检查工作区已有改动,不能覆盖无关修改。
|
||||
3. 明确模型是公开模型还是内部模型。
|
||||
4. 明确端口物理域、状态、参数、方程和结果。
|
||||
5. 找到最接近的现有模型并沿用代码风格。
|
||||
|
||||
### 修改中
|
||||
|
||||
1. 将物理契约保存在模型类中。
|
||||
2. 只在库清单中登记公开模型。
|
||||
3. 不修改集中注册表来加入单个模型。
|
||||
4. 不为了让测试通过而放宽全局校验。
|
||||
5. 不改变现有模型标识,除非任务明确要求迁移。
|
||||
6. 不把前端拖拽方向当作物理流向。
|
||||
7. 不把求解器失败简单隐藏为默认结果。
|
||||
|
||||
### 修改后
|
||||
|
||||
1. 展示涉及的模型、清单和测试文件。
|
||||
2. 报告版本变化和兼容性影响。
|
||||
3. 运行针对性测试、完整后端测试和必要的前端构建。
|
||||
4. 检查 `GET /api/components/catalog` 中的模型、分类、端口和参数。
|
||||
5. 告知用户需要重启 FastAPI 才能加载新的 Python 模块。
|
||||
6. 未执行的校验必须明确说明原因。
|
||||
|
||||
## 19. 常见失败与处理
|
||||
|
||||
| 现象 | 常见原因 | 处理 |
|
||||
| --- | --- | --- |
|
||||
| FastAPI 启动时报模型缺少声明 | 字段继承自父类或漏写 | 在公开模型类中显式声明 |
|
||||
| 模型未出现在前端 | 未加入 `library.py` 或后端未重启 | 检查清单并重启 FastAPI |
|
||||
| 前端显示红色“加载失败” | `/api/components/catalog` 不可用或目录合同无效 | 悬停状态查看详情,再检查 8000 端口和接口响应 |
|
||||
| 显示端口校验失败 | `DISPLAY.ports` 与 `PORTS` 不一致 | 使用相同端口名和完整集合 |
|
||||
| 单位校验失败 | `quantity` 与 SI 单位不匹配 | 使用受控单位表或先扩展规范 |
|
||||
| 默认模型无法注册 | 默认参数越界或构造函数未保存参数 | 修复默认值和 `set_parameter_values()` |
|
||||
| XML 报不支持模型 | XML `type` 与 `MODEL_TYPE` 不一致 | 修正类型或提供迁移 |
|
||||
| 模型可显示但无法仿真 | 只完成目录元数据,方程或物理域求解未实现 | 补齐方程、网络和求解测试 |
|
||||
|
||||
## 20. 完成定义
|
||||
|
||||
一个模型只有同时满足以下条件才算完成:
|
||||
|
||||
- 模型契约完整且启动校验通过。
|
||||
- 默认参数和边界有效。
|
||||
- 端口、参数和结果具有稳定物理含义。
|
||||
- 方程覆盖零流量、正常流动和必要的反向流动。
|
||||
- 模型已加入正确库清单。
|
||||
- 目录接口能自动输出模型。
|
||||
- 前端无需复制参数和端口定义即可使用。
|
||||
- XML 能映射到正确模型。
|
||||
- 最小系统能够编译;声称可仿真的模型必须产生有限结果。
|
||||
- 针对性测试、完整回归和必要的前端构建通过。
|
||||
- 文档记录了模型假设、适用范围和已知限制。
|
||||
@@ -0,0 +1,284 @@
|
||||
# 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,且整个区间最多生成 10001 个采样点 |
|
||||
| `maxStep` | 自适应积分器单个内部步的上限 | 必须大于 0 |
|
||||
| `method` | 积分方法 | `RK45/RK23/DOP853/Radau/BDF/LSODA` |
|
||||
|
||||
`sampleStep` 和 `maxStep` 不是一回事:
|
||||
|
||||
- `sampleStep` 决定结果曲线多久保存一个点;
|
||||
- `maxStep` 限制求解器内部一次最多前进多久;
|
||||
- 自适应求解器可以因为误差、事件或试探状态失败而走得比 `maxStep` 更短。
|
||||
|
||||
采样点数量会在创建时间数组前计算。若区间长度不可表示为有限数、请求超过 10001
|
||||
点,或在当前浮点精度下无法得到包含 `tStart/tStop` 的严格递增时间序列,输入会在
|
||||
仿真前被拒绝,不会把超大或重复的 `t_eval` 交给积分器。
|
||||
|
||||
工程 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`
|
||||
Reference in new issue
Block a user