Files
SystemSimulationApp/docs/standard/component-registration-example-v1.md

166 lines
11 KiB
Markdown
Raw Permalink 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.0.0;修订日期:2026-09-12;代码基线:`22579e5`。
本文由原 `app/simulation/components/example.md` 迁入并重写,配合[注册流程](component-registration-workflow-v1.md)、[建模规范](component-model-authoring-spec-v1.md)和[库读取规范](component-library-spec-v1.md)使用。示例在隔离源码副本中实际执行,正式组件库不增加演练型号。它验证当前接入流程,不是待发布的新物理模型。
## 1. 示例合同
新建第三个库 `registration_demo`、分类 `signals`、型号 `registration_demo_ramp`,类名 `DemoRamp`,模型版本 `1.0.0`。复用图形键 `amesim_step0`,增加 C 模块 `demo_signal`;图形键不决定数值行为。
公式为:
```text
y(t) = offset + amplitude × t / duration
```
| 参数 | SI / 默认值 | 约束 |
| --- | --- | --- |
| `offset` | 无量纲 / 2 | 有限值 |
| `amplitude` | 无量纲 / 3 | 有限值 |
| `duration` | s / 1 | 有限且严格大于零 |
唯一端口 `out` 是信号输出,显示在右侧。组件输出 `y` 与端口输出 `out.signal` 相同。模型无积分状态、无事件、无气动参考口。Python 类显式声明 `MODEL_TYPE/MODEL_VERSION/PORTS/PARAMETERS/RESULT_VARIABLES/DISPLAY/create`;构造函数保存参数并注册端口。完整可执行类及各处接入代码保存在[后端演练脚本](../../tests/manual/rehearse_component_registration.py),不再维护另一份易过期的代码副本。
C 函数是:
```c
#include "kernels.h"
double native_demo_ramp(double t, double offset, double amplitude, double duration) {
return offset + amplitude * t / duration;
}
```
`duration > 0` 由组件参数合同检查。本演练用已校验的参数生成 C 常量,不能据此认为任意外部输入都已校验,或任意有限幅值不会溢出;它是受限输入的接入示例。
## 2. 分阶段注册:有意遗漏与实际失败
每阶段使用新 Python 进程,避免已导入模块掩盖发现入口变化。脚本在对应失败处断言错误原因,最终阶段要求成功。
| 阶段 | 已完成的步骤 | 实际结果 / 规范含义 |
| --- | --- | --- |
| `unlisted` | 新类和库文件存在,未启用库 | 注册表没有新型号;目录扫描不会自动注册 |
| `catalog_only` | 启用新库与清单 | 目录、参数和 XML 校验通过;原生生成报 `no native contract` |
| `native_discovery_only` | 将新库加入 `extended.catalog_contracts()` | 原生版本与模型合同不匹配;还需 `SUPPORTED_VERSIONS` |
| `contract_only` | 补支持版本 | 报 `Native output mapping incomplete`,缺少 `ramp_1.y` 和 `ramp_1.out.signal`;版本白名单不会实现方程 |
| `lowered_without_module_export` | 扩展生成器输出分支、C 函数和公共头文件 | 链接报 `undefined reference to native_demo_ramp`;模块未纳入按需导出 |
| `complete` | 补 `modules.py::EXPORTS`、诊断聚合包含清单、经核对的函数识别 | 构建与 RK45/BDF 运行通过 |
实际修改仅发生在生成的 `sandbox/`:新库的四个 Python 文件、`registry.py`、`extended.py`、`contracts.py`、`modules.py`、`jacobian.py`、`kernels.h`、新 C 模块及诊断聚合入口。生产源码没有新增该类型。
该函数只读取时间和参数,没有状态依赖。将其纳入受控函数识别集不等于验证了任意多输出函数、投影或新动态模型的雅可比结构;这些仍按专项规范审查。
## 3. 浏览器导入过程中发现的额外边界
| 初次尝试 | 实际行为 | 已采用的处理与规范修订 |
| --- | --- | --- |
| 把目录 `ports` 原样写入工程 | 信号端口带 `positiveFlowDirection: null`,浏览器拒绝;后端仍可转出有效 XML | 工程快照按前端结构规范化,信号端口省略该字段;保留错误导入检查 |
| 连线只写端点 | 缺 `data.isContactEdge`,浏览器拒绝 | 普通连线显式保存 `data: {"isContactEdge": false}` |
| 尝试把时长从 s 切到 ms | 当前只有 s 选项 | 验证已有 SI 参数编辑;不把新增单位描述成目录自动支持 |
| 使用未接线的独立信号源点击运行 | 后端是未接端口警告,前端检查为错误并阻止仿真 | 网页改用完整接线网络;区分单元件后端测试与网页系统测试 |
合法信号端口快照示例:
```json
{"name":"out","kind":"signal","domain":"signal","nominalRole":"output","side":"right"}
```
网页案例使用四个元件、三条连接:
```text
ramp_1.out -> force_1.res
force_1.port_2 -- mass_1.port_2
mass_1.port_1 -- zero_1.port_1
```
`force_1` 使用 FORC 的正向信号转力,`mass_1` 使用 MECMAS21(质量 10 kg、零初始位移/速度、禁用摩擦和限位),`zero_1` 是 F000。网页把 `duration` 从 1 s 改为 2 s,因此 `F(t)=2+1.5t` N,质量块的独立解析参考为:
```text
v(t) = 0.2t + 0.075t²
x(t) = 0.1t² + 0.025t³
```
## 4. 本版规范的逐项校正
| 旧规范不匹配之处 | 本版处理 |
| --- | --- |
| 仅描述 experimental,仍计划未来建立正式库 | 核对当前 experimental/amesim 两库;临时隐藏由库 ID 决定 |
| “加入 library 就完成注册/无需其他修改” | 明确元数据发现与原生发现、版本、方程和模块链接四个独立检查点 |
| C 公式仍要求放 `kernels.c` | 改为 `modules/*.c`、`kernels.h` 和模块导出/依赖;聚合文件仅用于诊断 |
| 启动校验要求 Python `component_result_values()` | 删除过期要求,改为元数据校验、C 输出映射及 EXE 输出的分层检查 |
| Python 状态声明容易被理解为自动得到 C 状态 | 明确索引、初值、导数和结果由具体生成路径实现 |
| 前端新增能力仅需图标 | 补齐动态端口、新编辑器、新物理量/单位、介质和连线规则的条件修改范围 |
| 目录、工程和 XML 合同被混用 | 补信号端口 null、连线 data 字段、SI 参数、完整参数、网页必接端口要求 |
| 无原生模块缓存、雅可比、新状态尺度要求 | 新增导出/依赖、缓存失效、状态依赖和容差量纲检查项 |
| “不支持迁移”的表述过于绝对 | 区分 XML 精确版本、前端型号专用处理和未实现的通用迁移框架 |
| 未区分跨平台适配与实际验收 | 分别记录 Linux/Windows 状态,新 C/构建/缓存能力同样适用 |
修改发生在现行规范正文,不只在本表列出待办。文件分工和迁移位置见[规范索引](README.md)。
## 5. 验证结果与范围
最终可复现记录放在本地 `test/component-registration-20260912-verified/`,该目录被 Git 忽略。
| 验证 | 结果与边界 |
| --- | --- |
| 六阶段发现、版本、输出、链接检查 | 全部符合阶段预期,最终构建成功 |
| 后端独立元件,RK45 与 BDF | 0~1 s,0.1 s 采样,各 11 点;`y` 解析误差为 0,端口输出与组件输出相同 |
| 重复构建 | 完整模型命中,对象编译 0 次 |
| 参数 duration 1→2 | 模型对象重编译 1 次,其余 8 个对象复用,最终输出 3.5 |
| 失败输入 | 错误 modelVersion、零 duration、XML 缺 duration 均被拒绝 |
| 浏览器 | 真实 Chromium、真实目录/API/C 程序;发现、拖入、错误 JSON 拒绝、完整工程导入、参数编辑、JSON/XML 导出、两次 BDF、曲线显示、结果文件/CSV、刷新恢复 |
| 网页解析对照 | 信号与输出力逐点误差 < 1e-12;质量块最大位移差 `1.26236e-11 m`、速度差 `2.36616e-13 m/s`(门槛分别为 1e-7) |
| 网页缓存与保存 | 第二次运行完整模型缓存命中;CSV 中新元件两列符合解析值;刷新恢复与保存结果完全一致 |
| 生产目录回归 | 注册、目录、元数据共 23 项测试通过;生产仍为 27 类,原生版本一致,演练类型未进入生产库 |
| Windows | 未实际执行;本机无 Windows 运行环境,不宣称双平台验收完成 |
第一轮缺导出的链接失败已生成部分共享对象,因此 `firstCompleteBuild` 不是全空缓存耗时;本演练不作性能优化结论。目录结构、失败阶段、函数接入在 Linux 得到实证,Windows 仍需用现有工具链执行复现与对应回归。
本案例不覆盖新物理域、动态端口、新编辑器、非平凡的雅可比着色、新非线性环或气动固定参考口,也不代表完成了 Amesim 等价性验证。此次修改仅为规范和演练工具,未修改共享求解行为,因此没有再次运行八路性能基准。
主要证据文件:`summary.json`、各阶段 `*.json/*.log`、`input.xml`、`project.json`(后端独立案例)、`browser-project.json`(网页完整网络)、`browser/summary.json`、网页导出与截图。探索中的失败记录在旁边的 `test/component-registration-20260912/` 和 `test/component-registration-20260912-final/`;最终结论以 `-verified` 目录为准。
## 6. 复现方法
前提:仓库 Python 依赖、现有 C/SUNDIALS 工具链和前端依赖可用。前端源代码变化后先在 `frontend/` 执行 `npm run build`,演练会复制现有 `frontend/dist/`。环境、工具链和浏览器不随 Git 提交。
Linux,从仓库根目录生成全新目录(已存在会拒绝覆盖):
```bash
.venv/bin/python tests/manual/rehearse_component_registration.py --output-dir test/registration-replay
```
另开终端启动隔离后端,使用同一 Python 环境:
```bash
registration_repo="$PWD"
cd test/registration-replay/sandbox
"$registration_repo/.venv/bin/python" -m uvicorn app.main:app --host 127.0.0.1 --port 8036
```
回到仓库根目录运行浏览器脚本:
```bash
node tests/manual/browser_component_registration.mjs test/registration-replay/browser-project.json test/registration-replay/browser http://127.0.0.1:8036
```
本机采用 `.tools/node-v24.18.0-linux-x64/bin/node`。若使用此前补充的浏览器动态库,在命令前设置:
```bash
export LD_LIBRARY_PATH="$PWD/.venv/native/browser-libs/usr/lib/x86_64-linux-gnu${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
```
Windows PowerShell 对应入口(须先配置现有 Windows C/SUNDIALS 工具链及 Playwright 浏览器,以下不是已通过记录):
```powershell
$registrationRepo = (Get-Location).Path
$registrationPython = Join-Path $registrationRepo '.venv-win\Scripts\python.exe'
& $registrationPython tests/manual/rehearse_component_registration.py --output-dir test/registration-replay-win
Set-Location test/registration-replay-win/sandbox
& $registrationPython -m uvicorn app.main:app --host 127.0.0.1 --port 8036
```
在另一个 PowerShell 终端回到仓库,运行同一 `.mjs` 脚本,输入换成 `test/registration-replay-win/browser-project.json`,Node 使用本机 Windows 路径。浏览器与 Python 均使用原平台环境,不复制 Linux 动态库。
完成后在启动 uvicorn 的终端按 `Ctrl+C`。演练使用临时端口 8036;本次未启动用户已停止的 5173/8000。删除生成目录即可清理演练源码、结果与缓存;生产组件及现行规范不依赖这些生成物。