merge/model-development-into-main #2
No files matched your search
@@ -63,6 +63,14 @@
|
|||||||
- `tests/test_test_mql_comparison.py`
|
- `tests/test_test_mql_comparison.py`
|
||||||
- 保护 AMESim 原始序列零误差对齐、粗时间步插值、偏移误差统计、缺失变量报错和 CSV 输出。
|
- 保护 AMESim 原始序列零误差对齐、粗时间步插值、偏移误差统计、缺失变量报错和 CSV 输出。
|
||||||
|
|
||||||
|
- `PythonModels/systems/test_mql_pneumatic.py`
|
||||||
|
- 把 AMESim 配置中的 `PNCH023`、`PNCH012`、`PNOR001`、`PNVO001` 装配成 Python 气动对象。
|
||||||
|
- 当前覆盖 4 个固定气室、8 个变容气室、8 个固定孔口、8 个可变孔口,alias 沿用 AMESim 原名。
|
||||||
|
- 初始压力按 AMESim 全局参数 `P0=153 bar` 和大气压 `1.013 bar` 转成 `15198700 Pa`。
|
||||||
|
|
||||||
|
- `tests/test_test_mql_pneumatic.py`
|
||||||
|
- 保护气动装配数量、alias、氦气工质、气室体积、孔口面积/流量系数和基础质量流量计算。
|
||||||
|
|
||||||
## 物性约定
|
## 物性约定
|
||||||
|
|
||||||
AMESim 模型中 `test_mql` 使用氦气,Python 侧当前通过 `HELIUM_PR` 使用 Peng-Robinson 状态方程计算气体压缩因子和密度。当前物性层先覆盖状态方程相关量,完整焓/内能偏差函数后续在接气室能量方程时再补。
|
AMESim 模型中 `test_mql` 使用氦气,Python 侧当前通过 `HELIUM_PR` 使用 Peng-Robinson 状态方程计算气体压缩因子和密度。当前物性层先覆盖状态方程相关量,完整焓/内能偏差函数后续在接气室能量方程时再补。
|
||||||
@@ -109,12 +117,12 @@ AMESim 模型中 `test_mql` 使用氦气,Python 侧当前通过 `HELIUM_PR`
|
|||||||
## 验证方式
|
## 验证方式
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 -m py_compile PythonModels/components/amesim_pneumatic.py PythonModels/core/peng_robinson.py PythonModels/reporting/amesim_results.py PythonModels/reporting/test_mql_comparison.py PythonModels/systems/test_mql.py PythonModels/systems/test_mql_config.py PythonModels/scripts/run_test_mql.py
|
python3 -m py_compile PythonModels/components/amesim_pneumatic.py PythonModels/core/peng_robinson.py PythonModels/reporting/amesim_results.py PythonModels/reporting/test_mql_comparison.py PythonModels/systems/test_mql.py PythonModels/systems/test_mql_config.py PythonModels/systems/test_mql_pneumatic.py PythonModels/scripts/run_test_mql.py
|
||||||
python3 -m PythonModels.scripts.run_test_mql
|
python3 -m PythonModels.scripts.run_test_mql
|
||||||
python3 -m unittest discover -s tests -t .
|
python3 -m unittest discover -s tests -t .
|
||||||
```
|
```
|
||||||
|
|
||||||
当前测试覆盖的是结构、配置解析、气动原语、AMESim 结果读取和 AMESim/Python 时序对齐工具,不代表已经完成 AMESim 物理结果复刻。
|
当前测试覆盖的是结构、配置解析、气动原语、气动件装配、AMESim 结果读取和 AMESim/Python 时序对齐工具,不代表已经完成 AMESim 物理结果复刻。
|
||||||
|
|
||||||
## 后续方向
|
## 后续方向
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,142 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from PythonModels.components.amesim_pneumatic import (
|
||||||
|
HELIUM_PNEUMATIC_GAS,
|
||||||
|
AmesimPneumaticGas,
|
||||||
|
AmesimPneumaticOrifice,
|
||||||
|
AmesimPneumaticVolume,
|
||||||
|
)
|
||||||
|
from PythonModels.systems.test_mql_config import TestMqlConfig, TestMqlResolvedComponent
|
||||||
|
|
||||||
|
|
||||||
|
ATMOSPHERIC_PRESSURE_BAR = 1.013
|
||||||
|
BAR_TO_PA = 1.0e5
|
||||||
|
DEFAULT_TEST_MQL_TEMPERATURE_K = 293.15
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class TestMqlPneumaticAssembly:
|
||||||
|
fixed_chambers: dict[str, AmesimPneumaticVolume]
|
||||||
|
variable_chambers: dict[str, AmesimPneumaticVolume]
|
||||||
|
fixed_orifices: dict[str, AmesimPneumaticOrifice]
|
||||||
|
variable_orifices: dict[str, AmesimPneumaticOrifice]
|
||||||
|
initial_pressure_pa: float
|
||||||
|
|
||||||
|
@property
|
||||||
|
def chamber_count(self) -> int:
|
||||||
|
return len(self.fixed_chambers) + len(self.variable_chambers)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def orifice_count(self) -> int:
|
||||||
|
return len(self.fixed_orifices) + len(self.variable_orifices)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def component_count(self) -> int:
|
||||||
|
return self.chamber_count + self.orifice_count
|
||||||
|
|
||||||
|
@property
|
||||||
|
def aliases(self) -> tuple[str, ...]:
|
||||||
|
return tuple(
|
||||||
|
[
|
||||||
|
*self.fixed_chambers,
|
||||||
|
*self.variable_chambers,
|
||||||
|
*self.fixed_orifices,
|
||||||
|
*self.variable_orifices,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def build_test_mql_pneumatic_assembly(
|
||||||
|
config: TestMqlConfig | None = None,
|
||||||
|
gas: AmesimPneumaticGas = HELIUM_PNEUMATIC_GAS,
|
||||||
|
) -> TestMqlPneumaticAssembly:
|
||||||
|
config = config or TestMqlConfig.from_amesim_specs()
|
||||||
|
initial_pressure_pa = pressure_from_amesim_bar_parameter(config.global_parameters["P0"])
|
||||||
|
fixed_chambers = {
|
||||||
|
component.alias: _build_chamber(
|
||||||
|
component,
|
||||||
|
volume_parameter="cvol",
|
||||||
|
gas=gas,
|
||||||
|
initial_pressure_pa=initial_pressure_pa,
|
||||||
|
)
|
||||||
|
for component in config.components_by_submodel("PNCH023")
|
||||||
|
}
|
||||||
|
variable_chambers = {
|
||||||
|
component.alias: _build_chamber(
|
||||||
|
component,
|
||||||
|
volume_parameter="cvol0",
|
||||||
|
gas=gas,
|
||||||
|
initial_pressure_pa=initial_pressure_pa,
|
||||||
|
)
|
||||||
|
for component in config.components_by_submodel("PNCH012")
|
||||||
|
}
|
||||||
|
fixed_orifices = {
|
||||||
|
component.alias: _build_orifice(
|
||||||
|
component,
|
||||||
|
area_parameter="area",
|
||||||
|
gas=gas,
|
||||||
|
opening=1.0,
|
||||||
|
)
|
||||||
|
for component in config.components_by_submodel("PNOR001")
|
||||||
|
}
|
||||||
|
variable_orifices = {
|
||||||
|
component.alias: _build_orifice(
|
||||||
|
component,
|
||||||
|
area_parameter="area0",
|
||||||
|
gas=gas,
|
||||||
|
opening=1.0,
|
||||||
|
)
|
||||||
|
for component in config.components_by_submodel("PNVO001")
|
||||||
|
}
|
||||||
|
return TestMqlPneumaticAssembly(
|
||||||
|
fixed_chambers=fixed_chambers,
|
||||||
|
variable_chambers=variable_chambers,
|
||||||
|
fixed_orifices=fixed_orifices,
|
||||||
|
variable_orifices=variable_orifices,
|
||||||
|
initial_pressure_pa=initial_pressure_pa,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def pressure_from_amesim_bar_parameter(pressure_bar: float) -> float:
|
||||||
|
return (pressure_bar - ATMOSPHERIC_PRESSURE_BAR) * BAR_TO_PA
|
||||||
|
|
||||||
|
|
||||||
|
def _build_chamber(
|
||||||
|
component: TestMqlResolvedComponent,
|
||||||
|
*,
|
||||||
|
volume_parameter: str,
|
||||||
|
gas: AmesimPneumaticGas,
|
||||||
|
initial_pressure_pa: float,
|
||||||
|
) -> AmesimPneumaticVolume:
|
||||||
|
return AmesimPneumaticVolume.from_liters(
|
||||||
|
name=component.alias,
|
||||||
|
volume_liters=component.parameter_value(volume_parameter),
|
||||||
|
gas=gas,
|
||||||
|
p0=initial_pressure_pa,
|
||||||
|
T0=_component_temperature(component),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _build_orifice(
|
||||||
|
component: TestMqlResolvedComponent,
|
||||||
|
*,
|
||||||
|
area_parameter: str,
|
||||||
|
gas: AmesimPneumaticGas,
|
||||||
|
opening: float,
|
||||||
|
) -> AmesimPneumaticOrifice:
|
||||||
|
return AmesimPneumaticOrifice.from_mm2(
|
||||||
|
name=component.alias,
|
||||||
|
area_mm2=component.parameter_value(area_parameter),
|
||||||
|
flow_coefficient=component.parameter_value("cq"),
|
||||||
|
gas=gas,
|
||||||
|
opening=opening,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _component_temperature(component: TestMqlResolvedComponent) -> float:
|
||||||
|
parameter = component.parameters.get("extemp")
|
||||||
|
if parameter is None or parameter.value is None:
|
||||||
|
return DEFAULT_TEST_MQL_TEMPERATURE_K
|
||||||
|
return parameter.value
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from PythonModels.components.amesim_pneumatic import HELIUM_PNEUMATIC_GAS
|
||||||
|
from PythonModels.systems.test_mql_pneumatic import (
|
||||||
|
build_test_mql_pneumatic_assembly,
|
||||||
|
pressure_from_amesim_bar_parameter,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestMqlPneumaticAssemblyTests(unittest.TestCase):
|
||||||
|
def test_assembles_expected_amesim_pneumatic_component_counts(self) -> None:
|
||||||
|
assembly = build_test_mql_pneumatic_assembly()
|
||||||
|
|
||||||
|
self.assertEqual(len(assembly.fixed_chambers), 4)
|
||||||
|
self.assertEqual(len(assembly.variable_chambers), 8)
|
||||||
|
self.assertEqual(len(assembly.fixed_orifices), 8)
|
||||||
|
self.assertEqual(len(assembly.variable_orifices), 8)
|
||||||
|
self.assertEqual(assembly.component_count, 28)
|
||||||
|
self.assertIn("pn_general_chamber", assembly.aliases)
|
||||||
|
self.assertIn("pn_c1_8", assembly.aliases)
|
||||||
|
self.assertIn("pn_orifice_18", assembly.aliases)
|
||||||
|
self.assertIn("pn_morifice_11", assembly.aliases)
|
||||||
|
|
||||||
|
def test_uses_amesim_global_initial_pressure_convention(self) -> None:
|
||||||
|
assembly = build_test_mql_pneumatic_assembly()
|
||||||
|
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
pressure_from_amesim_bar_parameter(153.0),
|
||||||
|
15198700.0,
|
||||||
|
)
|
||||||
|
self.assertAlmostEqual(assembly.initial_pressure_pa, 15198700.0)
|
||||||
|
|
||||||
|
def test_chamber_parameters_are_resolved_in_si_units(self) -> None:
|
||||||
|
assembly = build_test_mql_pneumatic_assembly()
|
||||||
|
fixed_chamber = assembly.fixed_chambers["pn_general_chamber"]
|
||||||
|
variable_chamber = assembly.variable_chambers["pn_c1_8"]
|
||||||
|
|
||||||
|
self.assertAlmostEqual(fixed_chamber.volume, 0.057)
|
||||||
|
self.assertAlmostEqual(variable_chamber.volume, 0.015)
|
||||||
|
self.assertIs(fixed_chamber.gas, HELIUM_PNEUMATIC_GAS)
|
||||||
|
self.assertIs(variable_chamber.gas, HELIUM_PNEUMATIC_GAS)
|
||||||
|
self.assertAlmostEqual(fixed_chamber.properties().T, 293.15)
|
||||||
|
self.assertAlmostEqual(variable_chamber.properties().T, 293.15)
|
||||||
|
|
||||||
|
def test_orifice_parameters_are_resolved_in_si_units(self) -> None:
|
||||||
|
assembly = build_test_mql_pneumatic_assembly()
|
||||||
|
fixed_orifice = assembly.fixed_orifices["pn_orifice_18"]
|
||||||
|
variable_orifice = assembly.variable_orifices["pn_morifice_11"]
|
||||||
|
|
||||||
|
self.assertAlmostEqual(fixed_orifice.area, 78.5e-6)
|
||||||
|
self.assertAlmostEqual(fixed_orifice.flow_coefficient, 0.9)
|
||||||
|
self.assertAlmostEqual(variable_orifice.area, 78.5e-6)
|
||||||
|
self.assertAlmostEqual(variable_orifice.flow_coefficient, 0.45)
|
||||||
|
self.assertAlmostEqual(variable_orifice.opening, 1.0)
|
||||||
|
|
||||||
|
def test_assembled_orifice_can_compute_helium_mass_flow(self) -> None:
|
||||||
|
assembly = build_test_mql_pneumatic_assembly()
|
||||||
|
fixed_orifice = assembly.fixed_orifices["pn_orifice_18"]
|
||||||
|
|
||||||
|
flow = fixed_orifice.mass_flow(15.0e6, 10.0e6, 293.15)
|
||||||
|
|
||||||
|
self.assertGreater(flow, 0.0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in new issue
Block a user