Files
SystemSimulationApp/docs/standard/component-registration-workflow-v1.md
T

238 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 新组件注册流程与交付规范
文档版本:1.1.0
修订日期:2026-09-12
核对代码基线:`22579e5`(缓存功能 Windows 平台适配)。本文是新增网页建模与原生仿真组件的总流程;专项字段规则见[规范索引](README.md),执行证据见[注册示例与验证](component-registration-example-v1.md)。文档版本独立于模型和协议版本。
本版通过隔离源码中的斜坡信号源注册演练校正现有规范。演练组件和编译缓存不加入正式组件库;可复现脚本保留在 `tests/manual/`。
## 1. 当前架构与完成边界
当前有两条接入链路。元数据注册控制组件发现和编辑;原生支持控制能否生成并执行数值模型。注册类不会自动获得 C 求解能力。
```mermaid
flowchart TD
A[组件物理定义与 Python 声明] --> B[library.py 与注册校验]
B --> C[组件目录 API]
C --> D[前端组件库、参数面板和端口]
D --> E[工程 JSON 与执行 XML]
E --> F[校验并构造网络]
B --> F
F --> G[C 支持合同与系统代码生成]
H[公共 C 数值模块] --> I[按需编译、缓存和链接]
G --> I
I --> J[独立 C 程序积分与输出]
J --> K[网页结果、保存和 CSV]
```
源码依据:
- [注册中心](../../app/simulation/registry.py):`ENABLED_COMPONENT_LIBRARIES` → `library.py` → `validate_component_model_class()` / `create()` → 注册表。
- [目录 API 与网络构造](../../app/main.py):`/api/components/catalog`、`compile_system_xml_network()`、`_compile_solver_network()`。
- [原生入口](../../app/simulation/native_codegen/compiler.py):`compile_native_program()` 检查类型和版本,再选择紧凑路径或扩展路径。
- [扩展生成器](../../app/simulation/native_codegen/extended.py):按具体模型实现状态、方程与输出映射。
- [前端工作台](../../frontend/src/App.tsx):`normalizeComponentCatalog()`、工程读写及通用参数处理。
本次直接加载注册目录核对:`experimental` 5 类、`amesim` 22 类,共 27 类;原生版本表与注册版本一致。这是当前快照,不应成为未来新增组件后的固定数量要求。
以下标识不可混为一谈:
| 标识 | 作用 | 示例 |
| --- | --- | --- |
| `library.id` | 发布和发现边界 | `amesim` |
| `category.id` | 前端组件面板分组 | `flow` |
| `MODEL_TYPE` | 工程/XML/原生支持的模型类型 | `amesim_pnor001` |
| `DISPLAY.symbol` | 前端图形渲染键 | 可以与 MODEL_TYPE 相同,也可以复用已有图形 |
| C 功能模块 | 数值代码组织及对象缓存粒度 | `orifice`、`pipe` |
界面分类与 C 功能模块没有自动的一一映射。不同型号可以调用同一个公共 C 函数;同一型号也可以依赖多个模块。
## 2. 新增组件的实际步骤
### 第一步:确定物理合同和接入范围(必做)
先整理模型依据、适用介质/物理域、计算公式、符号约定、有效范围和未支持能力。明确它是无状态代数组件、动态组件,还是编译期介质定义。若是新增物理域或新种类的介质,须单独评估网络、XML、前端连线、物性和原生生成支持,不能只新增一个 `domain` 或类型字符串。
建议首先形成四张表:
- 参数:机器名、物理意义、SI 单位、默认值、范围、枚举、显示条件和是否影响端口/状态数量。
- 端口:稳定名称、物理域、连接类型、各变量含义、正方向、供需关系、参考来源及是否必须连接。
- 状态:名称、含义、单位、初值公式、导数公式、允许范围、绝对误差尺度及相关事件。
- 输出:稳定名称、含义、单位、显示名称、计算公式和所属组件/端口。
### 第二步:编写 Python 组件声明(必做)
文件放在 `app/simulation/components/<library>/<category>/`,参照同类模型。现有代码存在一个文件容纳多个相关型号的情况;“每模型单文件”是整理建议,不是注册器的硬性要求。
公开模型类必须在自己的类体显式声明:
```python
MODEL_TYPE
MODEL_VERSION
PORTS
PARAMETERS
RESULT_VARIABLES
DISPLAY
@classmethod
def create(cls, *, name, medium, parameters):
...
```
这七项由 [registry.py](../../app/simulation/registry.py) 检查,不能只从父类隐式继承。可以显式引用已有声明,例如 `RESULT_VARIABLES = Parent.RESULT_VARIABLES`。
构造过程调用 `set_parameter_values()` 保存完整规范化参数,使用 `register_declared_port()` 注册声明的端口,并保存介质和常量。参数合法性包括单字段范围和跨参数约束;默认参数必须能够创建描述对象。公共创建入口填充缺省值后还会核对实例类型、端口和参数是否与声明一致。
Python 可以做参数验证和常量几何换算;运行时物性、流量、力和状态导数由 C 计算。`EQUATIONS` / `equation_definitions()` 是结构化约束声明,不会被自动翻译成完整 C 数值方程。仅设置 `DynamicComponent.state_size` 也不会自动分配原生积分状态。
### 第三步:落实端口语义(必做,静态与数值两侧一致)
`PORTS` 是物理接口来源,`DISPLAY.ports` 是显示布局,两者的名称集合必须一致。当前显示端口基础声明支持 `left/right`,旋转和镜像由前端处理,不能直接写未经实现的显示边。
气动端口需要区分:
- 名义入口/出口及实际正反流。
- 哪些量由本端提供,哪些量由对端提供。
- 是否是固定供需的参考口或支路口;`reference_port` 指向哪个真实参考来源。
使用 [port_computation.py](../../app/simulation/core/port_computation.py) 的既有合同或声明准确的新合同。参考关系不会随流向反转而自动改变;不能从图标左右位置推断物理参考口。端口流量遵守现有“流入组件为正”的合同。
参数决定端口启停时,同时实现类级和实例级有效端口查询,并核对必须连接的端口。前端目前对 LMECHN1 的动态端口还有专门逻辑,尚无统一的参数化端口目录协议;新动态端口模型要明确补齐前端规则及变更参数后旧连线的处理。
### 第四步:加入受控组件清单(必做)
在所属库 `library.py` 的 `models` 中加入 `完整模块路径:类名`。如新增界面分类,同步该库 `categories` 和 `DISPLAY.category_id`。不要直接修改运行时 `COMPONENT_MODEL_REGISTRY`,也不要扫描目录执行任意 Python 文件。
新库需增加 `ComponentLibrarySpec`,并加入 `registry.py` 的 `ENABLED_COMPONENT_LIBRARIES`。另外,当前 `extended.py::catalog_contracts()` 仍显式读取 `amesim` 和 `experimental` 两个库,**新增第三个库还必须扩展这一原生发现入口**。
前端当前按库 ID 隐藏 `experimental`。加入实验库的模型可以被后端发现,但不会出现在左侧公开组件列表;`temporary` 标记不是现有隐藏规则。
### 第五步:实现或复用 C 数值内核(数值接入必做,新增 C 文件按需)
先判断现有公共函数是否已经满足方程。如果只需已有内核加不同参数或组合,可以复用,避免按元件实例复制内核。
新增函数应放在 `native/components/modules/` 的合适模块,公共接口在 [kernels.h](../../native/include/kernels.h) 声明;新增独立模块时再建立新的 `.c`。当前五模块为物性、孔口、管路、机械和信号。
按需构建由 [modules.py](../../app/simulation/native_codegen/modules.py) 的 `EXPORTS` 和 `DEPENDENCIES` 决定。增加新导出函数或模块依赖时应同步这里;只在头文件写声明不会保证模块进入链接。新模块如需参与聚合诊断,还要加入 `native/components/kernels.c` 的包含清单。
`kernels.c` 现在是诊断聚合入口,生产构建不直接编译它;不能同时链接聚合入口与各模块,否则产生重复定义。
内核应说明非法状态、非有限值及迭代失败的处理。新气动计算优先传递现有 `NativePropertyCache` 上下文;试算不能污染已接受状态,也不能把跨状态的旧物性无条件复用。沿用 C11、严格浮点和已有 Windows/Linux 构建约定。
### 第六步:接入系统代码生成、依赖和数值精度(必做)
在 `native_codegen/extended.py` 接入该具体型号的:
1. 有效端口、连接组及介质选择。
2. 状态编号、初值、必要的状态约束/投影。
3. 代数关系、流量、焓和力计算。
4. 状态导数及全部可见输出赋值。
5. 分段信号、限位或其他事件(适用时)。
目前这些逻辑包含具体类型集合与分支,例如 `GAS_TYPES`、`NODES`、`RESISTORS`;简单地把新型号塞进某个集合,不能保证后续分支正确处理它。
计算输入/输出通过 `Computation` / `EvaluationSchedule` 接入 [求值排序](../../app/simulation/native_codegen/schedule.py)。多输出函数要准确声明读取量和写出量;参考值复制与依赖流量的混合计算应分开;正流、逆流、零流量和各离散模式的依赖均需覆盖。新增不被当前局部求解器支持的非线性环,要实现对应求解或明确拒绝。
还需核对 [雅可比结构](../../app/simulation/native_codegen/jacobian.py) 的状态依赖。新的多输出调用、投影和分支不能遗漏依赖;无法证明时允许使用保守逐列差分,不能为保持着色而把未知依赖当作常量。适用时给生成的 `model`/`model.exe` 传入 `--verify-jacobian` 核对;Python 包装 CLI 没有同名选项。
新增状态量需要检查 [绝对误差尺度](../../app/simulation/native_codegen/tolerances.py)。当前按状态字段名区分质量、位移/速度,其余默认 `1e-8`;新物理量不能未经量纲评估直接套默认值。
`compiler.py` 保留紧凑生成路径,但新型号不一定需要同步实现第二套路径。正确做法是确认它被路由到已支持的生成路径;只有纳入紧凑路径或改变两路径共享行为时,才同步实现并做路径对照。不要只扩充 `_STORAGE_ANCHORED_TYPES` 却漏掉对应计算。
实现并验证后,将 `MODEL_TYPE: MODEL_VERSION` 加入 [contracts.py](../../app/simulation/native_codegen/contracts.py)。这是支持承诺,不能用加入白名单代替真正的数值实现。
### 第七步:核对前端图形与交互(必查,代码修改按需)
对普通固定端口、现有编辑器和现有单位的模型,组件库列表、参数名称/默认值/边界/枚举/显隐条件通过目录自动生成。通常不用在 `App.tsx` 再添加一份型号参数表或新建仿真 API。
需要新图形时,在 `frontend/src/componentSymbols/` 实现渲染,并加入 [ComponentSymbol.tsx](../../frontend/src/ComponentSymbol.tsx) 的 `symbolRegistry`。完整图形定义包含 `viewBox`、图标尺寸、节点占地、端口锚点;按参数变化的图形还需相应布局函数。没有专用图形时当前有通用边框回退,但它不代表专用图形已经验收。
以下情况需额外前端工作:
| 新能力 | 需要核对的入口 |
| --- | --- |
| 新图形/锚点 | `componentSymbols/*`、`ComponentSymbol.tsx` |
| 新参数编辑器 | `core/metadata.py` / 注册校验、目录解析、`ParameterTable.tsx` / `App.tsx` |
| 新单位或物理量的单位切换 | 后端 `SI_UNIT_BY_QUANTITY`、共享参数 `schemas/parameter-units.json`、结果 `RESULT_UNIT_OPTIONS`;三入口回归 |
| 动态端口 | 后端有效端口接口、前端端口显示/连线处理和参数变更逻辑 |
| 新物理域/连接规则 | `core/ports.py`、网络/XML 校验、前端连线检查及 C 生成 |
| 特殊介质定义/引用 | XML/前端的目录角色、网络识别的介质定义基类、介质注册与引用选择逻辑 |
浏览器检查应覆盖端口号、实际连线端点、旋转/镜像、参数改变后的布局及导入导出。图形变了不能偷偷改变物理端口名称或参考关系。
### 第八步:核对工程文件、版本和输出(必做)
普通已有协议下的模型通过注册表即可被通用 XML 流程识别,通常不需要修改 XSD 或添加型号专用 API。
- XML 要求精确匹配 `modelVersion`,参数集合完整且没有未知字段;Python 工厂可填默认值不等于 XML 可以任意缺参数。
- 外部工程 JSON v2 的数值和表达式统一按所选单位解释,网页/HTTP/CLI 预处理后才进入 SI 数值边界。旧 v1 数值不能重复换算。组件版本差异提示后允许执行;型号、端口、参数错误继续拒绝。导出时只对通过校验的节点升级版本,按[输入合同](backend-interface-version-spec-v1.md#61-工程存储与执行入口)验收旧文件和重新导出的文件。
- 采用实际浏览器导出的工程结构,不直接复制目录对象。例如信号端口快照须省略 `positiveFlowDirection: null`;连线须保存 `data.isContactEdge` 布尔字段;后端转 XML 成功不能代替浏览器导入检查,见[目录与快照差异](component-library-spec-v1.md#143-目录对象与工程快照不是同一协议)。
- 网页当前要求所有显示端口恰好连接一次。后端单元件算例的未接端口警告不能替代网页完整网络验收。
- 发布后保持模型/端口/参数/结果机器名稳定。提高版本可能使旧 XML 被拒绝;当前没有通用自动迁移框架,前端仅存在部分特定型号迁移逻辑。
- `RESULT_VARIABLES` 中可见项与活动端口的可见变量必须在实际 C 输出中全部赋值,结果键/单位应与网页、缓存恢复、CSV 一致。
### 第九步:分层测试和双平台验收(必做,按物理适用性选择案例)
| 层次 | 最少核验内容 | 现有入口示例 |
| --- | --- | --- |
| 声明与注册 | 全局类型唯一、版本、默认可创建、非法/边界参数、端口/显示/结果一致 | `test_component_registry`、`test_component_catalog`、`test_component_metadata` |
| 接口与文件 | 正确连接、缺口/错误参考被拒绝、JSON/XML 往返、版本不兼容 | `test_port_computation`、`test_system_xml_v3`、型号专项 |
| 元件数值 | 独立公式或可信参考、正常/零值/边界/逆向、守恒和明确失败 | 型号 C 专项、`--init` / `--probe` |
| 系统求解 | 包含新元件的最小闭合网络,RK45/BDF(适用时),事件、顺序打乱与输出完整 | `test_native_codegen`、`test_native_schedule`、`test_native_catalog` |
| 雅可比 | 状态依赖覆盖、模式切换、必要的完整矩阵核对 | `test_native_jacobian_structure`、`test_native_jacobian_runtime` |
| 编译与缓存 | 空缓存构建、完整命中、参数/模块变化后正确失效、缺失模块链接失败能被发现 | `test_native_build_cache`、`test_native_cache_platform` |
| 浏览器 | 发现/拖入/编辑/连线/旋转镜像、运行、结果可查看、IndexedDB 保存、下载/CSV/刷新恢复分别核查 | `frontend/tests/e2e/` 的相关测试 |
| 双平台 | Windows 与 Linux 实际构建和运行;Windows `.exe` / DLL / 路径 / 文件系统能力 | `native-windows` CI、跨平台集成测试 |
新增模型要有自己的可执行案例,不能只改变“现有 27 类”的数量断言。已有测试包含固定类型清单/数量,新增后需合理更新覆盖期望,并证明新型号确实执行。
数值参考来自独立解析结果、可信外部结果或经过审查的冻结基准;不能从待验实现自动生成“预期值”来证明自身正确。保留原有参考,不直接覆盖历史基线掩盖差异。
对共享内核/求解器的修改,沿用修正八路作为系统回归与性能案例;新元件自身仍需最小闭合案例。只有八路无法运行且短期无解,才退回四路。性能对照分别记录构建、求解、结果处理与网页可查看/保存;无可信 Amesim 曲线或耗时则明确跳过相应对比。
Windows 验收遵循 [跨平台交付约定](跨平台交付约定.md)。模拟测试与代码适配不能代称 Windows 实机运行通过。
## 3. 常见修改范围
| 文件/区域 | 新增普通型号时是否必改 |
| --- | --- |
| 所属组件库中的 Python 声明 | 必改 |
| 所属库 `library.py` | 必改 |
| `native_codegen/extended.py` 或已确定的生成适配入口 | 必须接入;当前通常需修改 |
| `native_codegen/contracts.py` | 必改 |
| `native/components/modules/*.c` / `kernels.h` | 新数值函数才改;已有内核可复用 |
| `native_codegen/modules.py` | 新导出函数或新模块依赖时改 |
| `native_codegen/compiler.py` 紧凑路径 | 新型号纳入该路径或共享行为受影响时改 |
| `schedule.py` / `jacobian.py` / `tolerances.py` | 核对生成器接入;现有机制不足、新函数依赖或新状态尺度需要时改 |
| 前端图形注册与渲染 | 需要专用图形或布局时改 |
| `App.tsx` / `ParameterTable.tsx` | 动态端口、新编辑器、新单位等现有元数据能力不足时改 |
| `app/main.py` / `app/system_xml.py` / XSD | 普通型号通常不改;新协议/物理域/介质机制时改 |
| 注册、型号数值、系统和浏览器测试 | 增加相应案例并更新受影响的覆盖期望 |
## 4. 组件接入交付资料
每个拟交付的新型号提供“组件接入说明”,按适用性填写以下栏目;未涉及的能力写明不适用:
1. **身份与版本**:类型、类路径、所属库/分类、模型版本、图形键、关联已有型号及兼容性处理。
2. **物理依据**:参考来源、完整方程、假设、适用范围、未支持功能。
3. **参数表**:SI 值、默认值、边界、枚举、条件显示、几何常量预处理。
4. **端口表与标号图**:变量、正方向、供需、参考口、动态启停和必接要求。
5. **状态/事件/结果表**:初值、导数、误差尺度、事件行为、输出键和单位。
6. **原生接入表**:C 函数、所属模块、依赖、生成路径、计算顺序、雅可比依赖与缓存失效范围。
7. **前端/文件合同**:图形及锚点、单位和编辑器、JSON/XML 示例、旧工程处理。
8. **验证记录**:最小算例、独立参考来源、误差门槛、失败路径、Windows/Linux 实际结果和网页验证;性能数据按阶段区分。
验证记录区分三个完成状态:
- **已注册**:目录/工厂/XML 类型与参数校验通过。
- **可求解**:原生构建、独立数值对照、闭合网络运行和输出检查通过。
- **可交付**:浏览器交互/文件往返/保存及 Windows/Linux 验证通过,兼容性和资料齐全。
这些是文档中的验收状态,当前目录 API 尚未提供对应的统一字段;不要向工程 JSON 添加未实现的状态协议。
## 5. 本版修订与维护
本版已在专项规范中修正:旧 C 文件入口、移除的 Python 结果接口、新库的两条发现入口、原生版本与方程的独立接入、前端条件能力、目录与工程快照差异、网页完整接线要求、精确版本和专用迁移的边界,以及模块缓存、雅可比依赖和 Windows 验证要求。
具体逐项对照、失败阶段和最终测试结果见[注册示例与验证](component-registration-example-v1.md)。后续代码架构变更时更新对应专项规范及本流程;不在文档中维护第二份可执行型号参数表。