Replace Python numerical kernels with native C execution
This commit is contained in:
1 parent
48da6be21c
commit
3b38f73fe0
227 files changed
+16801
-75499
No files matched your search
@@ -1,15 +1,15 @@
|
||||
# 组件模型建模规范 v1
|
||||
|
||||
状态:已在 `experimental` 临时组件库实施
|
||||
适用对象:人工开发者、代码生成工具和 AI 编程助手
|
||||
状态:2026-09-10 更新为 Python 声明、C 数值实现
|
||||
适用对象:人工开发者、代码生成工具和 AI 编程助手
|
||||
配套读取规范:[组件库分类、发现与读取规范 v1](component-library-spec-v1.md)
|
||||
|
||||
## 1. 文档目标
|
||||
|
||||
本文档规定一个 Python 仿真元件应如何创建、修改、测试和注册。完成后的模型必须
|
||||
本文档规定采用 Python 元数据与 C 数值内核的元件应如何创建、修改、测试和注册。完成后的模型必须
|
||||
同时满足四个使用方:
|
||||
|
||||
1. 求解器能够实例化模型并调用方程。
|
||||
1. C 编译器能够读取模型声明、生成系统代码并调用 C 方程。
|
||||
2. System XML 能够根据稳定类型找到模型。
|
||||
3. React Flow 能够自动显示图标、端口和参数。
|
||||
4. 结果页面能够根据结构化元数据展示变量。
|
||||
@@ -43,11 +43,7 @@
|
||||
|
||||
### 2.3 新增内部模型
|
||||
|
||||
仅供固定算例或研究代码使用、不进入前端目录的模型,不加入 `library.py`。这类模型
|
||||
应放在对应 `examples/` 或专用系统目录,不能与公开模型混放后依赖扫描规则排除。
|
||||
|
||||
当前示例是
|
||||
[`app/simulation/examples/testmodel/dynamic_pipe.py`](../../app/simulation/examples/testmodel/dynamic_pipe.py)。
|
||||
不进入前端目录的研究模型不加入 `library.py`。需要执行时仍应编写 C 内核并显式纳入编译器支持合同;不要恢复旧 Python 求解路径。
|
||||
|
||||
### 2.4 新增物理域
|
||||
|
||||
@@ -111,7 +107,6 @@ app/simulation/components/experimental/junctions/tee.py
|
||||
```python
|
||||
MODEL_TYPE = "example_component"
|
||||
MODEL_VERSION = "1.0.0"
|
||||
PRESSURE_FLOW_DEPENDS_ON_STREAM = False
|
||||
PORTS = (...)
|
||||
PARAMETERS = (...)
|
||||
RESULT_VARIABLES = (...)
|
||||
@@ -138,62 +133,11 @@ def create(
|
||||
|
||||
## 6. 基类选择
|
||||
|
||||
### 6.1 `AlgebraicComponent`
|
||||
`AlgebraicComponent` 表示没有积分状态的元件;`DynamicComponent` 表示有积分状态的元件;`ThermodynamicVolumeComponent` 提供标准 `m,U,p,T,rho,u,h` 结果声明。这些基类只描述模型,不再实现数值求值方法。
|
||||
|
||||
适用于没有积分状态、由当前端口变量和参数直接决定残差的元件,例如:
|
||||
构造函数负责参数校验、几何预处理和端口注册。介质对象保存物性常量与模型选择。状态初值、流量、焓、受力和导数必须在 C 中计算。
|
||||
|
||||
- 孔板
|
||||
- 阀门
|
||||
- 阻性管段
|
||||
- 理想三通
|
||||
|
||||
至少实现:
|
||||
|
||||
- 构造函数和端口注册。
|
||||
- `create()`。
|
||||
- `pressure_flow_equation_residuals()`。
|
||||
- 需要传递 stream 变量时实现 `update_stream_outflows()`。
|
||||
|
||||
实现 `update_stream_outflows()` 或 `update_flow_temperature_references()` 的公开模型,
|
||||
还应在该公开类自身显式声明 `PRESSURE_FLOW_DEPENDS_ON_STREAM`:构成压力/流量方程
|
||||
会读取这些 hook 写入的焓或温度引用时设为 `True`,否则设为 `False`。省略声明、
|
||||
声明非法值或由自定义子类仅继承父类声明时,求解器会保守使用全网热流闭合;不要
|
||||
为了获得分块加速而错误声明 `False`。
|
||||
|
||||
`pressure_flow_equation_residuals()` 返回的每条 `EquationResidual.variables` 必须完整
|
||||
列出该残差实际读取的全部代数端口量(`p/m_flow/x/v/f`),不能只写“主要变量”。
|
||||
求解器会用这份声明编译稀疏 Jacobian 和独立方程块;漏写依赖可能让有限差分方向
|
||||
不完整。仓库内置组件会接受结构与数值依赖回归,外部自定义组件当前仍保守使用
|
||||
全网 dense 回退,直到具备同等的依赖验证边界。
|
||||
|
||||
### 6.2 `ThermodynamicVolumeComponent`
|
||||
|
||||
适用于包含质量和能量状态的气体容腔,例如:
|
||||
|
||||
- 气瓶
|
||||
- 贮箱
|
||||
- 有容积的管段
|
||||
|
||||
至少实现:
|
||||
|
||||
- `get_state_vector()`。
|
||||
- `set_state_vector()`。
|
||||
- `refresh_thermodynamic_ports()`。
|
||||
- `state_derivative_from_ports()`。
|
||||
- `pressure_flow_equation_residuals()`。
|
||||
|
||||
该基类已经提供标准热力学组件结果:
|
||||
|
||||
```text
|
||||
m, U, p, T, rho, u, h
|
||||
```
|
||||
|
||||
除非物理含义不同,不要重新复制这组结果声明。
|
||||
|
||||
### 6.3 其他基类
|
||||
|
||||
如果现有基类不能表达模型,应先评估是否缺少一种通用组件能力。不要为了一个模型
|
||||
直接把专用判断塞入 `SimulationNetwork` 或求解器。
|
||||
用 `EQUATIONS` 或 `equation_definitions()` 声明结构化连接约束,返回 `EquationDefinition`,包括关系、变量和归属,不包含运行时残差值。`__MODEL__` 占位符由基类替换为实例名。该声明供网络结构展示与检查使用,不替代 C 方程或构建支持白名单。
|
||||
|
||||
## 7. 端口建模规范
|
||||
|
||||
@@ -319,16 +263,7 @@ ResultVariableDefinition(
|
||||
)
|
||||
```
|
||||
|
||||
声明后必须在 `component_result_values()` 返回同名值:
|
||||
|
||||
```python
|
||||
def component_result_values(self) -> Mapping[str, float]:
|
||||
return {
|
||||
"pressure_drop": self.port_a.p - self.port_b.p,
|
||||
}
|
||||
```
|
||||
|
||||
声明集合和返回键必须一致。
|
||||
声明的每个输出必须在 C 生成器的输出布局中有对应值。测试应核对实际 EXE 输出键与 `result_variable_metadata()` 一致,不再实现 Python `component_result_values()`。
|
||||
|
||||
### 9.2 端口结果
|
||||
|
||||
@@ -407,168 +342,20 @@ def create(
|
||||
|
||||
`create()` 不应重复实现参数默认值和边界校验,也不能静默修改传入参数。
|
||||
|
||||
## 12. 方程实现要求
|
||||
## 12. C 方程实现要求
|
||||
|
||||
模型方程必须满足:
|
||||
1. 在 `native/components/kernels.c` 及 `native/include/kernels.h` 实现物性或元件数值公式。
|
||||
2. 在 `native_codegen/extended.py` 注册状态、端口、参数、初始化与输出映射;符合简单拓扑的模型还应核对 `compiler.py` 快速路径。
|
||||
3. 在 `native_codegen/contracts.py` 声明支持版本,不允许仅注册 Python 模型就声称具备 C 求解能力。
|
||||
4. 当前状态与试探状态分离,求值不能覆盖已接受状态。无效物性、欠定连接和不收敛必须明确失败。
|
||||
5. 信号跳变和限位事件接入 C 运行库;不能改动刚度、阻尼或容差来隐藏数值错误。
|
||||
6. 保持 SI 单位和端口流入为正,核对逆流、质量/能量守恒及边界状态。
|
||||
|
||||
- 残差形式统一为“期望等式左侧减右侧”。
|
||||
- 每条 `EquationResidual` 使用稳定、可定位的 `id`。
|
||||
- `variables` 列出该残差实际涉及的端口量或状态。
|
||||
- `role` 与方程主要约束的物理角色一致。
|
||||
- 对零压差、零流量和反向流动给出有限结果。
|
||||
- 必要正则化必须有物理解释,并通过边界测试保护。
|
||||
- 不得用画布坐标、连接线方向或组件名称决定方程。
|
||||
## 13. 模型实现示例
|
||||
|
||||
### 12.1 可因果执行的残差语义
|
||||
可参照 [气瓶声明](../../app/simulation/components/experimental/storage/cylinder.py)、[气腔声明](../../app/simulation/components/amesim/storage/chambers.py)、[C 内核](../../native/components/kernels.c) 与 [系统 C 生成器](../../app/simulation/native_codegen/extended.py)。完整开发顺序见 [组件目录说明](../../app/simulation/components/example.md)。
|
||||
|
||||
后端只会对经过结构门控的内置模型启用完全因果执行。除完整声明
|
||||
`variables` 外,这些模型还必须遵守以下可执行语义:
|
||||
|
||||
- `role="effort", relation="state"` 的残差写成
|
||||
`端口 effort - 状态给定值`,被约束的端口量系数必须为 `+1`。
|
||||
- `role="effort", relation="equal"` 的残差写成两个同类 effort 的差。
|
||||
- `role="flow", relation="sumToZero"` 按“流入组件为正”的约定求和,待消元
|
||||
flow 的系数必须为 `+1`。
|
||||
- `role="flow", relation="constitutive"` 写成
|
||||
`待消元 flow - 本构计算值`,待消元 flow 的系数必须为 `+1`。
|
||||
- `pressure_flow_equation_values()` 必须是无副作用的只读计算,返回顺序和长度
|
||||
必须与 `pressure_flow_equation_residuals()` 的编译结果永久一致;不得在求残差时
|
||||
修改端口、状态或活动集缓存。
|
||||
|
||||
求解器仍会在首次闭合、离散事件之后和固定周期执行完整残差审计。结构不满足、
|
||||
运行时覆盖不完整或审计不通过时,会立即熔断到原有残差/非线性求解路径。现场诊断
|
||||
时可在启动进程前设置 `SIMULATION_CAUSAL_FAST_PATH=0`,一键关闭该优化而不改变模型
|
||||
文件。
|
||||
|
||||
动态模型还必须:
|
||||
|
||||
- 状态向量长度稳定。
|
||||
- `get_state_vector()` 和 `set_state_vector()` 互为逆操作。
|
||||
- 状态导数满足质量和能量守恒约定。
|
||||
- 初始化默认值能够产生有限介质状态。
|
||||
|
||||
## 13. 可复制的代数模型模板
|
||||
|
||||
下面是一个符合当前规范的两端口代数阻力模板。复制后必须根据真实物理模型修改
|
||||
类型、参数、方程、名称和测试,不能只改类名就注册。
|
||||
|
||||
```python
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
from math import sqrt
|
||||
|
||||
from app.simulation.core.base import AlgebraicComponent
|
||||
from app.simulation.core.catalog import ComponentDisplaySpec, PortDisplaySpec
|
||||
from app.simulation.core.equations import EquationResidual
|
||||
from app.simulation.core.metadata import ParameterDefinition
|
||||
from app.simulation.core.medium import IdealGasMedium
|
||||
from app.simulation.core.ports import PortDefinition
|
||||
|
||||
|
||||
class ExampleRestriction(AlgebraicComponent):
|
||||
MODEL_TYPE = "example_restriction"
|
||||
MODEL_VERSION = "1.0.0"
|
||||
PRESSURE_FLOW_DEPENDS_ON_STREAM = False
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic("port_a", nominal_role="bidirectional"),
|
||||
PortDefinition.pneumatic("port_b", nominal_role="bidirectional"),
|
||||
)
|
||||
PARAMETERS = (
|
||||
ParameterDefinition(
|
||||
name="K",
|
||||
label="流量系数",
|
||||
quantity="flow_coefficient",
|
||||
unit="kg/(s*Pa^0.5)",
|
||||
default=1e-5,
|
||||
minimum=0.0,
|
||||
),
|
||||
)
|
||||
RESULT_VARIABLES = ()
|
||||
DISPLAY = ComponentDisplaySpec(
|
||||
label="示例阻力元件",
|
||||
library_id="experimental",
|
||||
category_id="flow",
|
||||
symbol="generic",
|
||||
ports=(
|
||||
PortDisplaySpec("port_a", "left", order=10),
|
||||
PortDisplaySpec("port_b", "right", order=20),
|
||||
),
|
||||
order=90,
|
||||
)
|
||||
|
||||
def __init__(self, name: str, K: float = 1e-5) -> None:
|
||||
super().__init__(name)
|
||||
self.set_parameter_values({"K": K})
|
||||
self.K = K
|
||||
self.port_a = self.register_declared_port("port_a")
|
||||
self.port_b = self.register_declared_port("port_b")
|
||||
|
||||
@classmethod
|
||||
def create(
|
||||
cls,
|
||||
*,
|
||||
name: str,
|
||||
medium: IdealGasMedium,
|
||||
parameters: Mapping[str, float],
|
||||
) -> ExampleRestriction:
|
||||
return cls(name=name, K=parameters["K"])
|
||||
|
||||
def pressure_flow_equation_residuals(
|
||||
self,
|
||||
) -> tuple[EquationResidual, ...]:
|
||||
pressure_difference = self.port_a.p - self.port_b.p
|
||||
expected_flow = (
|
||||
self.K
|
||||
* sqrt(abs(pressure_difference))
|
||||
* (1.0 if pressure_difference > 0.0 else -1.0)
|
||||
if pressure_difference != 0.0
|
||||
else 0.0
|
||||
)
|
||||
return (
|
||||
EquationResidual(
|
||||
id=f"{self.name}:mass_flow_balance",
|
||||
owner="component",
|
||||
owner_id=self.name,
|
||||
relation="sumToZero",
|
||||
variables=(
|
||||
f"{self.name}.port_a.m_flow",
|
||||
f"{self.name}.port_b.m_flow",
|
||||
),
|
||||
role="flow",
|
||||
value=self.port_a.m_flow + self.port_b.m_flow,
|
||||
),
|
||||
EquationResidual(
|
||||
id=f"{self.name}:pressure_flow_relation",
|
||||
owner="component",
|
||||
owner_id=self.name,
|
||||
relation="constitutive",
|
||||
variables=(
|
||||
f"{self.name}.port_a.p",
|
||||
f"{self.name}.port_b.p",
|
||||
f"{self.name}.port_a.m_flow",
|
||||
),
|
||||
role="flow",
|
||||
value=self.port_a.m_flow - expected_flow,
|
||||
),
|
||||
)
|
||||
|
||||
def update_stream_outflows(
|
||||
self,
|
||||
connected_h: Mapping[str, float],
|
||||
) -> None:
|
||||
self.port_a.h_outflow = connected_h["port_b"]
|
||||
self.port_b.h_outflow = connected_h["port_a"]
|
||||
```
|
||||
|
||||
真实现有模型可参考:
|
||||
|
||||
- 储能元件:
|
||||
[`cylinder.py`](../../app/simulation/components/experimental/storage/cylinder.py)
|
||||
- 阻性元件:
|
||||
[`orifice.py`](../../app/simulation/components/experimental/flow/orifice.py)
|
||||
- 多端口连接元件:
|
||||
[`tee.py`](../../app/simulation/components/experimental/junctions/tee.py)
|
||||
Python `create()` 只创建经校验的描述对象;C `model_init()` 生成质量、能量及机械状态,`model_eval()` 计算导数和输出。两者通过生成的状态/参数布局关联。
|
||||
|
||||
## 14. 注册模型
|
||||
|
||||
@@ -597,11 +384,11 @@ models=(
|
||||
2. 默认参数创建测试。
|
||||
3. 参数边界测试。
|
||||
4. 端口与显示布局一致性测试。
|
||||
5. 关键方程残差测试。
|
||||
5. C 方程与独立解析解或冻结参考值对照。
|
||||
6. 零流量或反向流动测试。
|
||||
7. 目录输出测试。
|
||||
8. 最小 XML 编译测试。
|
||||
9. 能进入通用求解器的模型,再添加短时仿真测试。
|
||||
9. 使用 C RK45/BDF 的短时仿真与事件测试。
|
||||
|
||||
推荐先运行:
|
||||
|
||||
|
||||
Reference in new issue
Block a user