完成求解器雅可比矩阵首轮优化,增加更新目录,整理了文档文件夹,增加了服务启动脚本

This commit is contained in:
lujingze committed 2026-08-17 07:33:31 +00:00
1 parent 6bb0591d32
commit 16a7eb2d6c
48 files changed
+8172 -217

No files matched your search

+778
View File
@@ -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
```