同步仿真框架并接入AMESim气动组件
This commit is contained in:
1 parent
420bafeb4e
commit
db4bdb4b70
109 files changed
+26920
-420
No files matched your search
@@ -0,0 +1,730 @@
|
||||
# 组件库分类、发现与读取规范 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 v2 尚未保存模型版本。正式发布组件库前,应在 XML 中增加
|
||||
`library` 和 `modelVersion`,并提供旧工程迁移规则。
|
||||
|
||||
## 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` 只保留旧常量的兼容别名。
|
||||
|
||||
## 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. 不在前端重新定义参数默认值、边界或端口语义。
|
||||
|
||||
当前前端保留内置兜底目录,用于后端未启动时继续打开工程。兜底只是一种开发期
|
||||
容错机制,不能成为新增模型的正式注册方式;正式环境应明确提示目录加载失败。
|
||||
|
||||
### 14.1 前端实际读取步骤
|
||||
|
||||
React Flow 启动时:
|
||||
|
||||
1. 使用 `no-store` 请求 `/api/components/catalog`。
|
||||
2. 检查 `schemaVersion == 1`。
|
||||
3. 检查库、模型、端口和参数结构。
|
||||
4. 检查模型 `type` 是否全局重复。
|
||||
5. 将参数数组转换为参数面板定义。
|
||||
6. 按库、分类和模型的 `order` 排序。
|
||||
7. 成功时显示“后端目录”。
|
||||
8. 请求或格式校验失败时显示“内置兜底”并使用开发期兜底目录。
|
||||
|
||||
前端兜底目录不保证包含新模型。新增公开模型后,只要 FastAPI 正常提供目录,前端
|
||||
就能读取;若要求后端离线时也显示新模型,才需要有意识地同步兜底定义。兜底定义
|
||||
仍不能成为端口、参数或默认值的权威来源。
|
||||
|
||||
### 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"
|
||||
name="cylinder_1"
|
||||
type="cylinder"
|
||||
componentType="cylinder">
|
||||
```
|
||||
|
||||
映射规则:
|
||||
|
||||
- `id`:工程内唯一的组件实例 ID。
|
||||
- `name`:用户可修改的组件实例名称。
|
||||
- `type`:必须匹配唯一的 `MODEL_TYPE`。
|
||||
- `componentType`:当前为兼容字段,应与 `type` 相同。
|
||||
- `<Port name>`:必须存在于模型的 `PORTS`。
|
||||
- `<Parameter name>`:必须存在于模型的 `PARAMETERS`。
|
||||
|
||||
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()` |
|
||||
| 模型发现 | 已实现 | 按库清单受控发现 |
|
||||
| 启动校验 | 已实现首版 | 覆盖版本、分类、端口、参数、单位和默认实例 |
|
||||
| XML/工程中的模型版本与迁移 | 未实现 | 正式库发布前补齐 |
|
||||
| 目录 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 和工程文件中保存模型版本,并设计迁移机制。
|
||||
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
|
||||
```
|
||||
Reference in new issue
Block a user