merge/model-development-into-main #2

Merged
lujingze merged 126 commits from merge/model-development-into-main into main 2026-07-31 09:52:44 +08:00
5 changed files with 345 additions and 35 deletions
Showing only changes of commit a0855018d5 - Show all commits

No files matched your search

+39 -30
View File
@@ -60,43 +60,46 @@ Python 输出只有通过 AMESim baseline 对比后才能作为数值一致性
## 当前对比结果
默认 comparison 仍使用 `0 -> 1e-5 s` 的短时域,并已新增
`dm1@pneumatic_69` 流量诊断。
默认 comparison 已从区间内插值的 `t=1e-5 s` 改为与 AMESim
首个保存时刻精确对齐的 `t=0.01 s`,当前比较 13 个关键信号,并
新增 `xv@pn_morifice_1`、`dm2@pn_morifice_1` 的结构化 PNVO 诊断。
本轮确认原最大偏差的主因不是 PNL0001 Darcy 阻力,而是 8 个
`PNVO001` 在 Python 中被固定为 `opening=1`,忽略了各自的
`STEP0` 控制。AMESim baseline 显示 `step_8..15` 均在
`t=0.04 s` 从 0 跳到 1,对应 PNVO 在此前保持关闭。
事件前 `t=0.01 s` 对比:
接入 STEP0 控制后的默认短时对比:
- `press@pn_c1_8`:Python `-1286.601221 Pa`,AMESim
`-1288.253185 Pa`,绝对误差约 `1.651964 Pa`。
- `dm1@pneumatic_69`:Python `-0.002485112 g/s`,AMESim
`-0.002054255 g/s`;换算后的 canonical 流量绝对误差约
`4.30857e-7 kg/s`。
- `xv@pn_morifice_1` 和 `dm2@pn_morifice_1` 在两侧均为 0,确认
STEP0 事件前 PNVO 保持关闭。
- `vol1@pn_brp2_8` 绝对误差约 `8.76e-5`,机械位移、速度和加速度
仍保持较小误差;当前较明显的累计差异集中在 PNL0001 流量和
PNCH012 压力/能量链路。
- `press@pn_c1_8` 末值误差从约 `9.22849 Pa` 降为
`0.0117249 Pa`。
- Python `dm1@pneumatic_69` 末值约
`-4.97737e-7 g/s`,AMESim 线性插值约
`-2.05425e-6 g/s`。
- canonical chamber-to-line flow 定义为
`-dm1 * 1e-3`,因此两者分别约为
`4.97737e-10 kg/s` 和 `2.05425e-9 kg/s`,绝对误差约
`1.55652e-9 kg/s`。
- AMESim 首个 `0.01 s` 区间的 `mgas1@pn_c1_8` 有限差分约
`-9.86349e-7 kg/s`;用该区间首末 `dm1` 做梯形平均得到的
chamber 质量变化率约 `-1.02713e-6 kg/s`,符号和量级一致。
新增 `--pnvo-event-boundary` 诊断:先积分到 `0.04 s` 的左极限,
再按 STEP0 的右连续语义在事件时刻读取开度和流量。结果为:
当前剩余 `1e-5 s` 误差不能直接解释为物理方程误差:AMESim
baseline 只按 `0.01 s` 保存,而 comparison 在首个保存区间内做
线性插值;位移、体积和压力的初始响应并不一定是线性的。
- `xv@pn_morifice_1`:Python/AMESim 均为 `1`。
- `dm2@pn_morifice_1`:Python `502.945005 g/s`,AMESim
`497.823823 g/s`,绝对误差约 `5.121182 g/s`,相对约 `1.03%`。
- `press@pn_c1_8` 绝对误差约 `55.4815 Pa`;
`dm1@pneumatic_69` 绝对误差约 `0.00281880 g/s`。
这说明 PNVO 开启瞬间的开度语义和主流量量级已经对齐,但事件前
累积压力/支路流量仍有偏差。常规积分直接跨越事件到 `0.05 s` 时,
当前进程会被系统终止,尚未形成可信的事件后结果;不能据此声明
完整 `0.04 -> 0.05 s` 窗口已经可运行。
## 下一步
1. 增加 AMESim 保存时刻对齐的诊断,优先比较事件前的
`t=0.01 s`,避免把 `1e-5 s` 线性插值误差当成物理偏差。
2. 导出 `xv@pn_morifice_1` 和 `dm2@pn_morifice_1`,检查
`t=0.04 -> 0.05 s` 开启窗口的 PNVO 流量及事件传播。
3. 在控制时序对齐后,再判断是否需要校准 PNVO 流量系数、
`pneumatic_69` 的 PNL0001 阻力或 PNCH012 能量方程。
4. 继续保留 `press@pn_c1_8`、`dm1@pneumatic_69` 和 chamber
RHS breakdown 作为同一条诊断链。
1. 优先定位 `0 -> 0.04 s` 累积的 `pneumatic_69` 流量与
`pn_c1_8` 压力偏差,区分 PNL0001 阻力和 PNCH012 能量方程。
2. 采用显式事件分段或针对事件后的局部数值策略,解决跨越
`t=0.04 s` 后积分进程被终止的问题,再验证 `t=0.05 s` 保存点。
3. 保留 `press@pn_c1_8`、`dm1@pneumatic_69`、PNVO `xv/dm2`
和 chamber RHS breakdown 作为同一条诊断链。
4. 在完整开启窗口稳定后,再判断是否需要校准 PNVO 流量系数。
`pn_c1_8` 的直接主线是 `pneumatic_69`;`pneumatic_96`
属于另一条固定气室支路,不是该诊断对象。
@@ -109,6 +112,12 @@ baseline 只按 `0.01 s` 保存,而 comparison 在首个保存区间内做
python3 -m PythonModels.scripts.run_test_mql_full_state_comparison
```
运行 PNVO 事件边界诊断:
```bash
python3 -m PythonModels.scripts.run_test_mql_full_state_comparison --pnvo-event-boundary
```
运行相关测试:
```bash
@@ -1,7 +1,9 @@
from __future__ import annotations
import argparse
from dataclasses import dataclass, field
from datetime import UTC, datetime
from math import nextafter
from pathlib import Path
from PythonModels.core.solver import SolveIVPConfig
@@ -35,6 +37,8 @@ DEFAULT_FULL_STATE_COMPARISON_DATA_PATHS = (
"v1@mass_friction_endstops_18",
"acc1@mass_friction_endstops_18",
"dm1@pneumatic_69",
"xv@pn_morifice_1",
"dm2@pn_morifice_1",
)
@@ -68,6 +72,22 @@ class TestMqlFullStateFlowDiagnostic:
final_canonical_abs_error_kg_s: float
@dataclass(frozen=True)
class TestMqlFullStatePnvoDiagnostic:
alias: str
initial_time_s: float
final_time_s: float
initial_python_opening: float
initial_amesim_opening: float
final_python_opening: float
final_amesim_opening: float
initial_python_mass_flow_kg_s: float
initial_amesim_mass_flow_kg_s: float
final_python_mass_flow_kg_s: float
final_amesim_mass_flow_kg_s: float
final_mass_flow_abs_error_kg_s: float
@dataclass(frozen=True)
class TestMqlFullStateComparisonRun:
system: TestMqlSystem
@@ -159,6 +179,33 @@ class TestMqlFullStateComparisonRun:
),
)
def pnvo_diagnostic(
self,
alias: str = "pn_morifice_1",
) -> TestMqlFullStatePnvoDiagnostic:
opening = self.signal_diagnostic(f"xv@{alias}")
mass_flow = self.signal_diagnostic(f"dm2@{alias}")
initial_python_mass_flow = mass_flow.initial_python_value * 1.0e-3
initial_amesim_mass_flow = mass_flow.initial_amesim_value * 1.0e-3
final_python_mass_flow = mass_flow.final_python_value * 1.0e-3
final_amesim_mass_flow = mass_flow.final_amesim_value * 1.0e-3
return TestMqlFullStatePnvoDiagnostic(
alias=alias,
initial_time_s=opening.initial_time_s,
final_time_s=opening.final_time_s,
initial_python_opening=opening.initial_python_value,
initial_amesim_opening=opening.initial_amesim_value,
final_python_opening=opening.final_python_value,
final_amesim_opening=opening.final_amesim_value,
initial_python_mass_flow_kg_s=initial_python_mass_flow,
initial_amesim_mass_flow_kg_s=initial_amesim_mass_flow,
final_python_mass_flow_kg_s=final_python_mass_flow,
final_amesim_mass_flow_kg_s=final_amesim_mass_flow,
final_mass_flow_abs_error_kg_s=abs(
final_python_mass_flow - final_amesim_mass_flow
),
)
def diagnostics_by_final_abs_error(self):
return tuple(
sorted(
@@ -185,6 +232,22 @@ class TestMqlFullStateComparisonRun:
)
@dataclass(frozen=True)
class TestMqlPnvoEventBoundaryDiagnostic:
orifice_alias: str
event_time_s: float
integration_stop_time_s: float
data_paths: tuple[str, ...]
python_values_by_data_path: dict[str, float]
amesim_values_by_data_path: dict[str, float]
def abs_error(self, data_path: str) -> float:
return abs(
self.python_values_by_data_path[data_path]
- self.amesim_values_by_data_path[data_path]
)
@dataclass(frozen=True)
class TestMqlFullStateComparisonPathConfig:
archive_path: Path = field(
@@ -201,9 +264,9 @@ class TestMqlFullStateComparisonExecutionConfig:
write_comparison_csv: bool = True
data_paths: tuple[str, ...] | None = DEFAULT_FULL_STATE_COMPARISON_DATA_PATHS
solver: SolveIVPConfig = field(
default_factory=lambda: SolveIVPConfig(t_stop=1.0e-5, max_step=1.0e-6)
default_factory=lambda: SolveIVPConfig(t_stop=1.0e-2, max_step=1.0e-3)
)
t_eval: tuple[float, ...] | None = (0.0, 1.0e-5)
t_eval: tuple[float, ...] | None = (0.0, 1.0e-2)
inlet_node_pressure_pa: float = 15.31e6
resistance_boundary_pressure_pa: float = 15.29e6
inlet_node_temperature_k: float = 293.15
@@ -306,6 +369,94 @@ def run_test_mql_full_state_comparison(
return run, output_dir
def run_test_mql_pnvo_event_boundary_diagnostic(
config: TestMqlFullStateComparisonScriptConfig | None = None,
*,
orifice_alias: str = "pn_morifice_1",
) -> TestMqlPnvoEventBoundaryDiagnostic:
config = config or TestMqlFullStateComparisonScriptConfig()
system = TestMqlSystem(archive_path=config.paths.archive_path)
control = system.pneumatic_assembly.variable_orifice_controls[orifice_alias]
event_time_s = control.step.step_time_s
integration_stop_time_s = nextafter(event_time_s, 0.0)
solver_template = config.execution.solver
solver = SolveIVPConfig(
t_start=solver_template.t_start,
t_stop=integration_stop_time_s,
method=solver_template.method,
rtol=solver_template.rtol,
atol=solver_template.atol,
max_step=solver_template.max_step,
)
spec = system.discover_pneumatic_branch_topology().chamber_segment_specs[0]
closure_kwargs = {
"inlet_node_pressure_pa": config.execution.inlet_node_pressure_pa,
"resistance_boundary_pressure_pa": (
config.execution.resistance_boundary_pressure_pa
),
"inlet_node_temperature_k": config.execution.inlet_node_temperature_k,
"resistance_boundary_temperature_k": (
config.execution.resistance_boundary_temperature_k
),
}
solution = system.simulate_full_state_from_spec(
spec,
config=solver,
t_eval=[solver.t_start, integration_stop_time_s],
**closure_kwargs,
)
state_vector = [row[-1] for row in solution.y]
closure = system.full_state_closure_from_spec(spec, **closure_kwargs)
data_paths = (
"press@pn_c1_8",
"dm1@pneumatic_69",
f"xv@{orifice_alias}",
f"dm2@{orifice_alias}",
)
python_values = closure.data_path_values(
time_s=event_time_s,
state_vector=state_vector,
data_paths=data_paths,
)
amesim_results = load_test_mql_amesim_results(config.paths.archive_path)
amesim_values = {
data_path: interpolate_series_value(
amesim_results.times,
amesim_results.series(data_path),
event_time_s,
)
for data_path in data_paths
}
return TestMqlPnvoEventBoundaryDiagnostic(
orifice_alias=orifice_alias,
event_time_s=event_time_s,
integration_stop_time_s=integration_stop_time_s,
data_paths=data_paths,
python_values_by_data_path=python_values,
amesim_values_by_data_path=amesim_values,
)
def format_test_mql_pnvo_event_boundary_summary(
diagnostic: TestMqlPnvoEventBoundaryDiagnostic,
) -> str:
lines = [
"Model: test_mql",
f"Mode: PNVO event boundary diagnostic ({diagnostic.orifice_alias})",
f"Event time: {diagnostic.event_time_s}",
f"Integrated left limit: {diagnostic.integration_stop_time_s}",
"Observation side: right-continuous STEP0 opening",
]
for data_path in diagnostic.data_paths:
lines.append(
f" - {data_path}: "
f"python={diagnostic.python_values_by_data_path[data_path]}, "
f"amesim={diagnostic.amesim_values_by_data_path[data_path]}, "
f"abs_error={diagnostic.abs_error(data_path)}"
)
return "\n".join(lines) + "\n"
def format_test_mql_full_state_comparison_summary(
run: TestMqlFullStateComparisonRun,
) -> str:
@@ -315,6 +466,10 @@ def format_test_mql_full_state_comparison_summary(
f"Samples: {run.sample_count}",
f"Compared signals: {run.signal_count}",
f"Output schema signals: {run.output_schema.signal_count}",
f"AMESim first saved interval: "
f"{run.amesim_results.times[1] - run.amesim_results.times[0]}",
f"Final time aligns with AMESim sample: "
f"{_matches_amesim_sample(run, run.output.times[-1])}",
f"Max absolute error: {run.comparison.max_abs_error}",
f"Max relative error: {run.comparison.max_rel_error}",
]
@@ -368,6 +523,27 @@ def format_test_mql_full_state_comparison_summary(
f"{flow_diagnostic.final_canonical_abs_error_kg_s}",
]
)
pnvo_diagnostic = _pn_morifice_1_diagnostic(run)
if pnvo_diagnostic is not None:
lines.append(f"PNVO diagnostic: {pnvo_diagnostic.alias}")
lines.extend(
[
f" - initial_python_opening="
f"{pnvo_diagnostic.initial_python_opening}",
f" - initial_amesim_opening="
f"{pnvo_diagnostic.initial_amesim_opening}",
f" - final_python_opening="
f"{pnvo_diagnostic.final_python_opening}",
f" - final_amesim_opening="
f"{pnvo_diagnostic.final_amesim_opening}",
f" - final_python_mass_flow_kg_s="
f"{pnvo_diagnostic.final_python_mass_flow_kg_s}",
f" - final_amesim_mass_flow_kg_s="
f"{pnvo_diagnostic.final_amesim_mass_flow_kg_s}",
f" - final_mass_flow_abs_error_kg_s="
f"{pnvo_diagnostic.final_mass_flow_abs_error_kg_s}",
]
)
chamber_diagnostic = _largest_chamber_rhs_diagnostic(run)
if chamber_diagnostic is not None:
lines.append(
@@ -389,6 +565,16 @@ def format_test_mql_full_state_comparison_summary(
return "\n".join(lines) + "\n"
def _matches_amesim_sample(
run: TestMqlFullStateComparisonRun,
time_s: float,
) -> bool:
return any(
abs(float(sample_time) - float(time_s)) <= 1.0e-12
for sample_time in run.amesim_results.times
)
def _pneumatic_69_flow_diagnostic(run: TestMqlFullStateComparisonRun):
try:
return run.pnl0001_mass_flow_diagnostic()
@@ -396,6 +582,13 @@ def _pneumatic_69_flow_diagnostic(run: TestMqlFullStateComparisonRun):
return None
def _pn_morifice_1_diagnostic(run: TestMqlFullStateComparisonRun):
try:
return run.pnvo_diagnostic()
except KeyError:
return None
def _largest_chamber_rhs_diagnostic(run: TestMqlFullStateComparisonRun):
diagnostic = run.largest_final_abs_error_diagnostic
if diagnostic is None or "@" not in diagnostic.data_path:
@@ -408,6 +601,18 @@ def _largest_chamber_rhs_diagnostic(run: TestMqlFullStateComparisonRun):
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument(
"--pnvo-event-boundary",
action="store_true",
help="compare the STEP0 left-state/right-opening boundary at t=0.04 s",
)
args = parser.parse_args()
if args.pnvo_event_boundary:
diagnostic = run_test_mql_pnvo_event_boundary_diagnostic()
print(format_test_mql_pnvo_event_boundary_summary(diagnostic), end="")
return
run, output_dir = run_test_mql_full_state_comparison()
print(format_test_mql_full_state_comparison_summary(run), end="")
print(f"Output directory: {output_dir}")
+27 -1
View File
@@ -3909,7 +3909,14 @@ def _default_full_state_data_paths() -> tuple[str, ...]:
for signal in ("x1", "v1", "acc1")
]
return tuple(
[*chamber_paths, *piston_paths, *mass_paths, "dm1@pneumatic_69"]
[
*chamber_paths,
*piston_paths,
*mass_paths,
"dm1@pneumatic_69",
"xv@pn_morifice_1",
"dm2@pn_morifice_1",
]
)
@@ -3973,6 +3980,10 @@ _PNL0001_MASS_FLOW_DIAGNOSTIC_FIELDS = {
"pneumatic_69": "p4_port3_remote_chamber_to_line_flow",
}
_VARIABLE_ORIFICE_MASS_FLOW_DIAGNOSTIC_FIELDS = {
"pn_morifice_1": "p4_port3_remote_orifice_to_node_flow",
}
class TestMqlFullStateClosure:
def __init__(
@@ -4162,6 +4173,21 @@ class TestMqlFullStateClosure:
_PNL0001_MASS_FLOW_DIAGNOSTIC_FIELDS[alias],
)
values_by_data_path[data_path] = -canonical_flow_kg_s * 1.0e3
elif alias in self.pneumatic_assembly.variable_orifices:
orifice = self.pneumatic_assembly.variable_orifices[alias]
if signal == "xv":
values_by_data_path[data_path] = orifice.opening
elif (
signal == "dm2"
and alias in _VARIABLE_ORIFICE_MASS_FLOW_DIAGNOSTIC_FIELDS
):
flow_kg_s = getattr(
snapshot.pneumatic,
_VARIABLE_ORIFICE_MASS_FLOW_DIAGNOSTIC_FIELDS[alias],
)
values_by_data_path[data_path] = flow_kg_s * 1.0e3
else:
raise KeyError(data_path)
elif alias in chamber_properties_by_alias:
chamber_properties = chamber_properties_by_alias[alias]
chamber = chamber_by_alias[alias]
@@ -9,7 +9,9 @@ from PythonModels.scripts.run_test_mql_full_state_comparison import (
TestMqlFullStateComparisonExecutionConfig,
TestMqlFullStateComparisonPathConfig,
TestMqlFullStateComparisonScriptConfig,
TestMqlPnvoEventBoundaryDiagnostic,
format_test_mql_full_state_comparison_summary,
format_test_mql_pnvo_event_boundary_summary,
run_test_mql_full_state_comparison,
)
@@ -33,6 +35,8 @@ class RunTestMqlFullStateComparisonScriptTests(unittest.TestCase):
"press@pn_c1_8",
"vol1@pn_brp2_8",
"dm1@pneumatic_69",
"xv@pn_morifice_1",
"dm2@pn_morifice_1",
),
solver=SolveIVPConfig(t_start=0.0, t_stop=0.0),
t_eval=(0.0,),
@@ -48,7 +52,7 @@ class RunTestMqlFullStateComparisonScriptTests(unittest.TestCase):
self.assertEqual(returned_output_dir, output_dir)
self.assertEqual(run.sample_count, 1)
self.assertEqual(run.signal_count, 3)
self.assertEqual(run.signal_count, 5)
self.assertAlmostEqual(run.comparison.max_abs_error, 0.0, delta=1.0e-8)
self.assertEqual(
run.metrics_by_max_abs_error()[0].data_path,
@@ -71,6 +75,12 @@ class RunTestMqlFullStateComparisonScriptTests(unittest.TestCase):
flow_diagnostic.initial_python_canonical_kg_s,
-flow_diagnostic.initial_python_dm1_g_s * 1.0e-3,
)
pnvo_diagnostic = run.pnvo_diagnostic()
self.assertEqual(pnvo_diagnostic.alias, "pn_morifice_1")
self.assertAlmostEqual(pnvo_diagnostic.initial_python_opening, 0.0)
self.assertAlmostEqual(pnvo_diagnostic.initial_amesim_opening, 0.0)
self.assertAlmostEqual(pnvo_diagnostic.initial_python_mass_flow_kg_s, 0.0)
self.assertAlmostEqual(pnvo_diagnostic.initial_amesim_mass_flow_kg_s, 0.0)
chamber_diagnostic = run.chamber_rhs_diagnostic("pn_c1_8")
self.assertEqual(chamber_diagnostic.chamber_alias, "pn_c1_8")
self.assertEqual(chamber_diagnostic.piston_alias, "pn_brp2_8")
@@ -83,7 +93,9 @@ class RunTestMqlFullStateComparisonScriptTests(unittest.TestCase):
)
self.assertTrue(csv_summary_exists)
self.assertIn("Mode: Python 132 full-state closure comparison", summary)
self.assertIn("Compared signals: 3", summary)
self.assertIn("Compared signals: 5", summary)
self.assertIn("AMESim first saved interval: 0.010000000000000023", summary)
self.assertIn("Final time aligns with AMESim sample: True", summary)
self.assertIn("Largest absolute error: press@pn_c1_8=", summary)
self.assertIn("Largest final endpoint error: press@pn_c1_8=", summary)
self.assertIn("Metrics by max absolute error:", summary)
@@ -93,6 +105,9 @@ class RunTestMqlFullStateComparisonScriptTests(unittest.TestCase):
summary,
)
self.assertIn("equals -AMESim dm1 * 1e-3", summary)
self.assertIn("PNVO diagnostic: pn_morifice_1", summary)
self.assertIn("final_python_opening=", summary)
self.assertIn("final_python_mass_flow_kg_s=", summary)
self.assertIn("Largest endpoint chamber RHS breakdown: pn_c1_8", summary)
self.assertIn("piston_alias=pn_brp2_8", summary)
self.assertIn("mass_derivative_kg_s=", summary)
@@ -102,6 +117,55 @@ class RunTestMqlFullStateComparisonScriptTests(unittest.TestCase):
self.assertIn("python.press@pn_c1_8", csv_header)
self.assertIn("amesim.vol1@pn_brp2_8", csv_header)
self.assertIn("python.dm1@pneumatic_69", csv_header)
self.assertIn("python.xv@pn_morifice_1", csv_header)
self.assertIn("python.dm2@pn_morifice_1", csv_header)
def test_default_execution_aligns_first_amesim_saved_sample(self) -> None:
execution = TestMqlFullStateComparisonExecutionConfig()
self.assertEqual(execution.solver.t_stop, 0.01)
self.assertEqual(execution.solver.max_step, 1.0e-3)
self.assertEqual(execution.t_eval, (0.0, 0.01))
self.assertIn("xv@pn_morifice_1", execution.data_paths)
self.assertIn("dm2@pn_morifice_1", execution.data_paths)
def test_formats_pnvo_event_boundary_diagnostic(self) -> None:
data_paths = (
"press@pn_c1_8",
"dm1@pneumatic_69",
"xv@pn_morifice_1",
"dm2@pn_morifice_1",
)
diagnostic = TestMqlPnvoEventBoundaryDiagnostic(
orifice_alias="pn_morifice_1",
event_time_s=0.04,
integration_stop_time_s=0.039999999999999994,
data_paths=data_paths,
python_values_by_data_path={
"press@pn_c1_8": -1090.9,
"dm1@pneumatic_69": -0.00949,
"xv@pn_morifice_1": 1.0,
"dm2@pn_morifice_1": 502.945,
},
amesim_values_by_data_path={
"press@pn_c1_8": -1146.38,
"dm1@pneumatic_69": -0.00667,
"xv@pn_morifice_1": 1.0,
"dm2@pn_morifice_1": 497.824,
},
)
self.assertEqual(diagnostic.orifice_alias, "pn_morifice_1")
self.assertLess(diagnostic.integration_stop_time_s, diagnostic.event_time_s)
self.assertEqual(diagnostic.abs_error("xv@pn_morifice_1"), 0.0)
self.assertAlmostEqual(
diagnostic.abs_error("dm2@pn_morifice_1"),
5.121,
)
summary = format_test_mql_pnvo_event_boundary_summary(diagnostic)
self.assertIn("PNVO event boundary diagnostic (pn_morifice_1)", summary)
self.assertIn("Observation side: right-continuous STEP0 opening", summary)
self.assertTrue(summary.endswith("\n"))
def test_full_state_script_can_skip_artifact_files(self) -> None:
with tempfile.TemporaryDirectory() as tmpdir:
+6
View File
@@ -757,6 +757,9 @@ class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase):
"x1@mass_friction_endstops_18",
"v1@mass_friction_endstops_18",
"acc1@mass_friction_endstops_18",
"dm1@pneumatic_69",
"xv@pn_morifice_1",
"dm2@pn_morifice_1",
)
result = self.system.simulate_full_state_series_from_spec(
@@ -788,6 +791,9 @@ class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase):
-0.8167936695810917,
)
self.assertAlmostEqual(result.series["acc1@mass_friction_endstops_18"][0], 0.0)
self.assertAlmostEqual(result.series["dm1@pneumatic_69"][0], 0.0)
self.assertAlmostEqual(result.series["xv@pn_morifice_1"][0], 0.0)
self.assertAlmostEqual(result.series["dm2@pn_morifice_1"][0], 0.0)
def test_simulates_full_132_state_closure(self) -> None:
solution = self.system.simulate_full_state_from_spec(