791 lines
33 KiB
Markdown
791 lines
33 KiB
Markdown
# 组件库分类、发现与读取规范 v1
|
||
|
||
文档版本:1.2.0
|
||
修订日期:2026-09-12
|
||
核对代码基线:`22579e5` 加本次输入合同实现;配套工程 JSON v2,XML v3 和模型版本不变。
|
||
|
||
状态:已在 `experimental` 与 `amesim` 组件库实施;本版按注册演练校正
|
||
适用范围:`app/simulation/components`、组件注册中心、System XML 和 React Flow 组件库
|
||
当前启用库:`experimental`(前端按库 ID 隐藏)、`amesim`(前端可见)。完整接入顺序见[新组件注册流程](component-registration-workflow-v1.md),实际演练见[注册示例与验证](component-registration-example-v1.md)。
|
||
|
||
## 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 模型实例化"]
|
||
```
|
||
|
||
普通固定端口、已有参数编辑器和单位的模型由目录生成组件列表及参数面板,无需再复制型号定义。新图形、动态端口、新编辑器、新单位或物理域仍须补齐对应前端支持,见注册流程的条件修改表。上图只表示元数据发现;模型参与仿真还需原生发现、支持版本、方程生成及 C 模块链接。
|
||
|
||
## 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`
|
||
- 端口名
|
||
- 参数名
|
||
- 结果变量名
|
||
|
||
库 ID、分类 ID、模型类型及端口名使用小写字母开头的小写字母、数字和下划线。参数和结果变量按成员标识符规则允许大小写字母,以字母开头,例如 `T0`、`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` 中 `visible=True` 的项;端口结果对应活动端口的可见变量。
|
||
5. 所有内部计算均使用 SI 基准值。
|
||
6. 模型不能直接依赖 FastAPI、React Flow 或 XML DOM。
|
||
7. 模型的方程不能依赖图标方向、界面分类或画布位置。
|
||
|
||
完整方程示例参见
|
||
[注册示例与验证](component-registration-example-v1.md)。
|
||
|
||
## 7. 界面显示声明
|
||
|
||
`DISPLAY` 的图形、布局和分组描述前端呈现,不定义物理公式。例外是已实现的介质 `role`:前端及 XML 使用它做引用识别;后端网络另按介质定义基类判断,新增介质必须同步二者。普通显示声明示例:
|
||
|
||
```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` |
|
||
| `volume` | signal | `directed` | `m3` |
|
||
| `volume_flow` | signal | `directed` | `m3/s` |
|
||
|
||
气动端口统一约定 `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。
|
||
- 文本框编辑中的临时字符串不立即判错,失焦、回车或运行仿真时再执行数值校验。
|
||
|
||
后端不得静默忽略未知参数。Python 工厂可补齐声明默认值,XML 本身必须写全参数;出现未知参数时必须
|
||
返回包含组件 ID 和参数名的明确错误。
|
||
|
||
## 10. 结果变量规范
|
||
|
||
组件结果和端口结果分开管理:
|
||
|
||
- 组件结果来自 `RESULT_VARIABLES` 中 `visible=True` 的项。
|
||
- 端口结果根据活动端口中 `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",
|
||
"app.simulation.components.amesim.library:LIBRARY",
|
||
)
|
||
```
|
||
|
||
禁止以下发现方式:
|
||
|
||
- 在整个仓库递归导入所有 Python 文件。
|
||
- 依赖文件名自动推断 `MODEL_TYPE`。
|
||
- 由前端硬编码后端类路径。
|
||
- 导入失败后悄悄跳过模型。
|
||
- 多个实现重复注册同一个模型类型并由加载顺序决定最终结果。
|
||
|
||
发现或校验失败时,FastAPI 应拒绝启动并给出库 ID、模型类型、字段和原因。
|
||
|
||
此启用列表仅控制注册中心。当前 `native_codegen/extended.py::catalog_contracts()` 另外显式读取两个内置库;新增第三个库必须同步该入口。`contracts.py::SUPPORTED_VERSIONS` 是独立的原生支持承诺,加入清单和支持版本后仍需实现状态、方程及输出映射。缓存不会替代这些接入步骤。
|
||
|
||
## 13. 启动校验规则
|
||
|
||
注册表完成前必须执行以下校验:
|
||
|
||
### 13.1 库与分类
|
||
|
||
- 库 ID 全局唯一。
|
||
- 库版本格式有效。
|
||
- 分类 ID 在库内唯一。
|
||
- 所有排序值为整数。
|
||
- 所有模型引用已存在的库和分类。
|
||
|
||
### 13.2 模型
|
||
|
||
- `MODEL_TYPE` 全局唯一,且与注册键一致。
|
||
- 模型版本格式有效。
|
||
- 模型继承框架要求的基类。
|
||
- 模型提供统一创建入口。
|
||
- 默认参数能够成功创建实例。
|
||
|
||
### 13.3 端口
|
||
|
||
- 端口名在模型内唯一。
|
||
- 显示端口集合与 `PORTS` 声明集合完全一致,包含物理端口与信号端口。
|
||
- 端口物理域、变量角色和连接规则有效。
|
||
- 实例实际注册的端口与静态声明一致。
|
||
|
||
### 13.4 参数
|
||
|
||
- 参数名在模型内唯一。
|
||
- 默认值有限且满足边界。
|
||
- `minimum <= maximum`。
|
||
- `quantity` 和 `unit` 的组合已登记。
|
||
- 实例保留所有规范化参数,不得静默修改或丢失。
|
||
|
||
### 13.5 结果
|
||
|
||
- 结果变量名在对应作用域内唯一。
|
||
- `quantity` 和单位有效。
|
||
- 检查组件结果声明的名称、物理量、单位和分类;启动时不执行数值求解。
|
||
- 端口结果只来自活动端口中声明为可见的变量。
|
||
|
||
Python `component_result_values()` 已移除。生成器须为 `result_variable_metadata()` 中全部可见键提供 C 输出映射;映射完整性和实际数值分别在原生生成、EXE 运行测试中验证,不应写成启动校验已覆盖。
|
||
|
||
## 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` 快照,只保存模型版本和完整参数。
|
||
|
||
这些字段在目录对象中为可选,但 `editor` 值是受控枚举。注册器和 Schema 当前只支持上述三类;新增编辑器必须成套扩展元数据、校验和前端控件,不能将未知编辑器退化为普通输入作为正式支持。已有型号仍有专用动态端口/迁移逻辑,新增普通参数控件继续以目录为来源。
|
||
|
||
`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。
|
||
|
||
### 14.3 目录对象与工程快照不是同一协议
|
||
|
||
目录经 `normalizeComponentCatalog()` 转为前端模型定义;工程 JSON 经 `parseProjectPayload()` 校验后才与当前目录合并。后端能够从 JSON 生成合法 XML,不代表该 JSON 能被浏览器导入。 当前工程连线还必须有 `data.isContactEdge` 布尔字段,仅有两端点不足以通过浏览器解析。
|
||
|
||
例如目录中的信号端口可能含 `"positiveFlowDirection": null`,当前工程解析器仅接受该字段缺省或值为 `"intoComponent"`,因此信号端口快照应省略它:
|
||
|
||
```json
|
||
{"name":"out","kind":"signal","domain":"signal","nominalRole":"output","side":"right"}
|
||
```
|
||
|
||
人工或脚本生成工程应采用实际浏览器导出的结构,保留节点版本、按对应格式约定存储的参数、布局与真实连线端点;不要原样复制目录端口对象。物理供需规则仍来自注册表,快照不能覆盖它们。导入后检查模型、导出 XML、运行以及再次导出 JSON 都是必要验证。
|
||
|
||
当前前端要求所有显示端口恰好连接一次。后端独立信号算例可以只有未接端口警告,浏览器会将其视为运行前错误;网页验收须使用完整接线工程。
|
||
|
||
## 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`。
|
||
|
||
介质定义组件不通过物理端口连接。XML 和前端通过目录角色
|
||
`amesimGasMediumDefinition` 识别,网络构造则通过 `AmesimGasMediumDefinitionComponent` 基类识别并收集介质定义,再解析带
|
||
`editor="amesimGasReference"` 参数的组件引用;介质定义组件本身不进入数值
|
||
仿真网络。System XML 语义校验会在编译前检查介质索引的整数范围、定义唯一
|
||
性、正索引引用完整性,以及同一气动连通分量的引用一致性。
|
||
|
||
XML 解析器只负责结构、引用和契约校验;模型注册中心负责选择 Python 类并创建实例;
|
||
Python 模型负责声明与约束;原生生成器分配状态、生成方程和输出,公共 C 模块执行数值计算。目录注册不能替代原生实现。
|
||
|
||
## 16. 测试要求
|
||
|
||
每个新模型至少需要:
|
||
|
||
1. 元数据测试:模型类型、端口、参数和结果声明合法。
|
||
2. 目录测试:模型出现在正确库和分类中。
|
||
3. 默认创建测试:默认参数能构造模型。
|
||
4. 参数边界测试:非法值被拒绝,错误信息包含组件和参数。
|
||
5. 端口测试:实例端口与声明完全一致。
|
||
6. XML 测试:最小系统能解析并映射到正确模型。
|
||
7. 方程测试:至少验证一个稳态、残差或守恒关系。
|
||
8. 最小仿真测试:一个短时算例能产生有限结果和结构化结果元数据。
|
||
|
||
库级测试还应检查:
|
||
|
||
- 库清单中的所有类均可导入。
|
||
- 所有模型类型全局唯一。
|
||
- 无遗漏或重复分类。
|
||
- `GET /api/components/catalog` 满足目录 schema。
|
||
|
||
## 17. 新增模型操作清单
|
||
|
||
按[注册流程](component-registration-workflow-v1.md)执行以下步骤:
|
||
|
||
1. 明确模型依据,列出参数、端口供需、状态、结果和支持边界。
|
||
2. 在目标库声明六个公共字段与类自身的 `create()`,校验默认值和参数边界。
|
||
3. 加入库清单;新库还需启用列表及原生 `catalog_contracts()` 入口。
|
||
4. 实现或复用 C 模块,新增导出函数时同步 `kernels.h`、`modules.py` 的导出及依赖。
|
||
5. 接入具体生成路径的状态、初始化、方程、输出、事件,核对求值依赖、雅可比与误差尺度;登记原生支持版本。
|
||
6. 完成独立数值对照、错误输入、最小完整网络、构建与缓存检查。
|
||
7. 重启后端,验证浏览器发现、编辑、导入导出、接线、运行、结果保存和 CSV;需要的新图形或交互能力同步实现。
|
||
8. 记录 Windows/Linux 的实际验证状态,交付接入说明与可复现实例。
|
||
|
||
普通型号通常不改通用 XML 分派、目录列表或参数面板字段;新协议、编辑器、单位及动态端口等按需修改。只通过目录和 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 的整体版本 | 已实现 | v2 统一所选单位语义,兼容读取 v1;节点保留来源版本并在兼容导出时更新 |
|
||
| 自动版本迁移 | 无通用框架,部分型号有前端专用迁移 | JSON 版本差异警告后生成当前 XML,XML 精确匹配;新型号明确语义兼容边界 |
|
||
| 目录 JSON Schema | 已实现 | `schemas/component-catalog-v1.schema.json` |
|
||
|
||
## 19. 维护与版本同步
|
||
|
||
新增模型按第 17 节逐层验证,不再把“建立正式库”列为未来任务:`amesim` 已是启用的公开库。当前目录加载有缓存,修改 Python 声明、清单或原生发现代码后须重启服务。前端发布包有变更时须重新构建;仅刷新页面不会重新导入后端模块。
|
||
|
||
模型版本修改时同时核对原生支持表、工程/XML 示例和兼容处理。原生内容缓存根据内容和构建环境失效,不以删除用户全部缓存作为新增模型的常规步骤。文档修订版本独立于库版本、模型版本、目录 schema 版本和工程格式版本。
|
||
|
||
## 20. 改动影响表
|
||
|
||
| 想做的改动 | 必须修改 | 通常不需要修改 |
|
||
| --- | --- | --- |
|
||
| 新增同库同分类模型 | 模型声明、库清单、原生支持版本、代码生成及数值实现/复用、测试 | 注册中心启用表、普通前端参数列表 |
|
||
| 新增分类 | 库 `categories`、模型 `DISPLAY.category_id`、测试 | 物理端口和求解器 |
|
||
| 新增组件库 | 新库包和清单、启用列表、原生 `catalog_contracts()`、逐型号数值接入和测试 | 已有库清单 |
|
||
| 修改参数默认值或范围 | 模型 `PARAMETERS`、测试、必要的版本 | 前端参数硬编码 |
|
||
| 修改端口 | 模型 `PORTS`、`DISPLAY.ports`、主版本、XML/网络拒绝边界测试 | 库分类 |
|
||
| 新增 C 导出函数/模块 | 数值模块、`kernels.h`、`modules.py` 导出/依赖、生成调用、适用的雅可比依赖与测试 | 前端分类 |
|
||
| 新增专用图标 | 模型 `DISPLAY.symbol`、前端图标渲染器 | 参数和物理方程 |
|
||
| 新增物理域 | 端口协议、网络、求解器、XML、前端兼容规则和测试 | 仅修改分类名称 |
|
||
| 修改目录响应结构 | 后端序列化、JSON Schema、前端解析、协议版本和测试 | 单个模型方程 |
|
||
|
||
## 21. 读取故障排查
|
||
|
||
| 现象 | 优先检查 |
|
||
| --- | --- |
|
||
| 模型完全没有出现在目录响应 | 模型类路径是否加入已启用库的 `models` |
|
||
| FastAPI 无法启动 | 启动错误中的库、模型和字段;通常是契约校验失败 |
|
||
| 接口有模型但前端没有 | `schemaVersion`、目录规范化、库是否为隐藏的 `experimental` |
|
||
| 前端显示红色“加载失败” | 悬停状态查看详情,再检查 8000 端口、`/api/components/catalog`、后端是否重启 |
|
||
| 分类错误 | `DISPLAY.category_id` 与库 `categories` |
|
||
| 端口数量或位置错误 | `PORTS` 与 `DISPLAY.ports` 是否完全一致 |
|
||
| 参数面板缺字段 | 模型 `PARAMETERS` 和目录响应,不先改前端 |
|
||
| XML 报不支持类型 | XML `type` 是否精确匹配 `MODEL_TYPE` |
|
||
| 导入 JSON 失败但后端 XML 正常 | 工程解析器要求与目录对象的差异,尤其信号端口的 `null` 字段 |
|
||
| 目录可见但原生失败 | 原生发现入口、支持版本、C 输出映射和模块导出是否逐层齐全 |
|
||
| 图标是通用图形 | `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
|
||
```
|
||
|
||
## 22. 本轮代码核对(2026-09-12)
|
||
|
||
1.1.1 修正了 DISPLAY 介质角色的实际用途、结果可见性和未知编辑器支持边界。工程存储/执行、HTTP/CLI 表达式和网页结果保存差异统一见[接口规范](backend-interface-version-spec-v1.md),本规范不重复声明一套实现。
|