补充test_mql pneumatic_96候选短窗口对比
This commit is contained in:
1 parent
a8a68f6dd4
commit
e17a952bee
2 files changed
+391
-14
No files matched your search
@@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from bisect import bisect_left
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass, field, replace
|
||||
from datetime import UTC, datetime
|
||||
from math import nextafter, sqrt
|
||||
from pathlib import Path
|
||||
@@ -731,6 +731,30 @@ class TestMqlPnvoEventWindowDiagnostic:
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TestMqlPnvoEventWindowCandidateMetricComparison:
|
||||
time_s: float
|
||||
metric_name: str
|
||||
default_abs_error: float
|
||||
candidate_abs_error: float
|
||||
|
||||
@property
|
||||
def abs_error_delta(self) -> float:
|
||||
return self.candidate_abs_error - self.default_abs_error
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TestMqlPnvoEventWindowCandidateComparisonDiagnostic:
|
||||
orifice_alias: str
|
||||
event_time_s: float
|
||||
final_time_s: float
|
||||
default_diagnostic: TestMqlPnvoEventWindowDiagnostic
|
||||
candidate_diagnostic: TestMqlPnvoEventWindowDiagnostic
|
||||
metric_comparisons: tuple[
|
||||
TestMqlPnvoEventWindowCandidateMetricComparison, ...
|
||||
]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TestMqlFullStateComparisonPathConfig:
|
||||
archive_path: Path = field(
|
||||
@@ -3245,12 +3269,14 @@ def run_test_mql_pnvo_event_window_diagnostic(
|
||||
config: TestMqlFullStateComparisonScriptConfig | None = None,
|
||||
*,
|
||||
orifice_alias: str = "pn_morifice_1",
|
||||
final_time_s: float = 0.05,
|
||||
) -> TestMqlPnvoEventWindowDiagnostic:
|
||||
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
|
||||
final_time_s = 0.05
|
||||
if final_time_s <= event_time_s:
|
||||
raise ValueError("final_time_s must be greater than the PNVO event time")
|
||||
spec = system.discover_pneumatic_branch_topology().chamber_segment_specs[0]
|
||||
closure_kwargs = {
|
||||
"inlet_node_pressure_pa": config.execution.inlet_node_pressure_pa,
|
||||
@@ -3268,7 +3294,7 @@ def run_test_mql_pnvo_event_window_diagnostic(
|
||||
closure = system.full_state_closure_from_spec(spec, **closure_kwargs)
|
||||
state_vector = closure.initial_state_vector()
|
||||
solver_template = config.execution.solver
|
||||
segments = (
|
||||
segment_templates = (
|
||||
SolveIVPConfig(
|
||||
t_start=solver_template.t_start,
|
||||
t_stop=nextafter(event_time_s, 0.0),
|
||||
@@ -3320,13 +3346,18 @@ def run_test_mql_pnvo_event_window_diagnostic(
|
||||
),
|
||||
SolveIVPConfig(
|
||||
t_start=0.048,
|
||||
t_stop=final_time_s,
|
||||
t_stop=0.05,
|
||||
method="BDF",
|
||||
rtol=1.0e-5,
|
||||
atol=1.0e-8,
|
||||
max_step=1.0e-5,
|
||||
),
|
||||
)
|
||||
segments = tuple(
|
||||
replace(segment, t_stop=min(segment.t_stop, final_time_s))
|
||||
for segment in segment_templates
|
||||
if segment.t_start < final_time_s
|
||||
)
|
||||
data_paths = (
|
||||
"press@pn_c1_8",
|
||||
"temp@pn_c1_8",
|
||||
@@ -3342,15 +3373,23 @@ def run_test_mql_pnvo_event_window_diagnostic(
|
||||
f"xv@{orifice_alias}",
|
||||
f"dm2@{orifice_alias}",
|
||||
)
|
||||
sample_times = (
|
||||
nextafter(event_time_s, 0.0),
|
||||
0.0401,
|
||||
0.0402,
|
||||
0.041,
|
||||
0.042,
|
||||
0.045,
|
||||
0.048,
|
||||
final_time_s,
|
||||
sample_times = tuple(
|
||||
sorted(
|
||||
{
|
||||
sample_time
|
||||
for sample_time in (
|
||||
nextafter(event_time_s, 0.0),
|
||||
0.0401,
|
||||
0.0402,
|
||||
0.041,
|
||||
0.042,
|
||||
0.045,
|
||||
0.048,
|
||||
final_time_s,
|
||||
)
|
||||
if sample_time <= final_time_s
|
||||
}
|
||||
)
|
||||
)
|
||||
state_vector_by_sample_time: dict[float, list[float]] = {}
|
||||
segment_diagnostics: list[TestMqlPnvoEventWindowSegmentDiagnostic] = []
|
||||
@@ -3573,6 +3612,214 @@ def run_test_mql_pnvo_event_window_diagnostic(
|
||||
)
|
||||
|
||||
|
||||
|
||||
def _event_window_config_with_pneumatic_96_reference_rhs(
|
||||
config: TestMqlFullStateComparisonScriptConfig | None,
|
||||
*,
|
||||
enabled: bool,
|
||||
) -> TestMqlFullStateComparisonScriptConfig:
|
||||
base = config or TestMqlFullStateComparisonScriptConfig()
|
||||
return replace(
|
||||
base,
|
||||
execution=replace(
|
||||
base.execution,
|
||||
use_pneumatic_96_reference_rhs=enabled,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _pnvo_event_window_sample_by_time(
|
||||
diagnostic: TestMqlPnvoEventWindowDiagnostic,
|
||||
) -> dict[float, TestMqlPnvoEventWindowSampleDiagnostic]:
|
||||
return {sample.time_s: sample for sample in diagnostic.sample_diagnostics}
|
||||
|
||||
|
||||
def _append_metric_comparison(
|
||||
comparisons: list[TestMqlPnvoEventWindowCandidateMetricComparison],
|
||||
*,
|
||||
time_s: float,
|
||||
metric_name: str,
|
||||
default_abs_error: float,
|
||||
candidate_abs_error: float,
|
||||
) -> None:
|
||||
comparisons.append(
|
||||
TestMqlPnvoEventWindowCandidateMetricComparison(
|
||||
time_s=time_s,
|
||||
metric_name=metric_name,
|
||||
default_abs_error=default_abs_error,
|
||||
candidate_abs_error=candidate_abs_error,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _append_pneumatic_96_candidate_metric_comparisons(
|
||||
comparisons: list[TestMqlPnvoEventWindowCandidateMetricComparison],
|
||||
*,
|
||||
time_s: float,
|
||||
default_sample: TestMqlPnvoEventWindowSampleDiagnostic,
|
||||
candidate_sample: TestMqlPnvoEventWindowSampleDiagnostic,
|
||||
) -> None:
|
||||
if (
|
||||
not default_sample.pneumatic_96_inlet_line_diagnostics
|
||||
or not candidate_sample.pneumatic_96_inlet_line_diagnostics
|
||||
):
|
||||
return
|
||||
default_line = default_sample.pneumatic_96_inlet_line_diagnostics[0]
|
||||
candidate_line = candidate_sample.pneumatic_96_inlet_line_diagnostics[0]
|
||||
for metric_name, default_value, candidate_value in (
|
||||
(
|
||||
"p96:p2_abs_error_pa",
|
||||
default_line.python_line_pressure_error_pa,
|
||||
candidate_line.python_line_pressure_error_pa,
|
||||
),
|
||||
(
|
||||
"p96:t2_abs_error_k",
|
||||
default_line.python_line_temperature_error_k,
|
||||
candidate_line.python_line_temperature_error_k,
|
||||
),
|
||||
(
|
||||
"p96:storage_dm_abs_error_g_s",
|
||||
default_line.python_storage_mass_derivative_error_g_s,
|
||||
candidate_line.python_storage_mass_derivative_error_g_s,
|
||||
),
|
||||
(
|
||||
"p96:active_dT_abs_error_k_s",
|
||||
default_line.python_active_temperature_derivative_error_k_s,
|
||||
candidate_line.python_active_temperature_derivative_error_k_s,
|
||||
),
|
||||
(
|
||||
"p96:active_dP_abs_error_pa_s",
|
||||
default_line.python_active_pressure_derivative_eos_error_pa_s,
|
||||
candidate_line.python_active_pressure_derivative_eos_error_pa_s,
|
||||
),
|
||||
):
|
||||
_append_metric_comparison(
|
||||
comparisons,
|
||||
time_s=time_s,
|
||||
metric_name=metric_name,
|
||||
default_abs_error=abs(default_value),
|
||||
candidate_abs_error=abs(candidate_value),
|
||||
)
|
||||
|
||||
|
||||
def _append_pneumatic_87_candidate_metric_comparisons(
|
||||
comparisons: list[TestMqlPnvoEventWindowCandidateMetricComparison],
|
||||
*,
|
||||
time_s: float,
|
||||
default_sample: TestMqlPnvoEventWindowSampleDiagnostic,
|
||||
candidate_sample: TestMqlPnvoEventWindowSampleDiagnostic,
|
||||
) -> None:
|
||||
if (
|
||||
not default_sample.pnl0003_energy_diagnostics
|
||||
or not candidate_sample.pnl0003_energy_diagnostics
|
||||
):
|
||||
return
|
||||
default_line = default_sample.pnl0003_energy_diagnostics[0]
|
||||
candidate_line = candidate_sample.pnl0003_energy_diagnostics[0]
|
||||
for metric_name, default_value, candidate_value in (
|
||||
(
|
||||
"p87:node_to_line_dm_abs_error_g_s",
|
||||
default_line.python_pn3_node_to_line_mass_flow_error_g_s,
|
||||
candidate_line.python_pn3_node_to_line_mass_flow_error_g_s,
|
||||
),
|
||||
(
|
||||
"p87:center_dm_abs_error_g_s",
|
||||
default_line.amesim_center_flow_python_sign_error_g_s,
|
||||
candidate_line.amesim_center_flow_python_sign_error_g_s,
|
||||
),
|
||||
(
|
||||
"p87:sdm1_abs_error_g_s",
|
||||
default_line.python_port_1_storage_mass_derivative_error_g_s,
|
||||
candidate_line.python_port_1_storage_mass_derivative_error_g_s,
|
||||
),
|
||||
(
|
||||
"p87:sdm2_abs_error_g_s",
|
||||
default_line.python_port_2_storage_mass_derivative_error_g_s,
|
||||
candidate_line.python_port_2_storage_mass_derivative_error_g_s,
|
||||
),
|
||||
(
|
||||
"p87:t2_abs_error_k",
|
||||
default_line.python_port_2_temperature_error_to_amesim_k,
|
||||
candidate_line.python_port_2_temperature_error_to_amesim_k,
|
||||
),
|
||||
):
|
||||
_append_metric_comparison(
|
||||
comparisons,
|
||||
time_s=time_s,
|
||||
metric_name=metric_name,
|
||||
default_abs_error=abs(default_value),
|
||||
candidate_abs_error=abs(candidate_value),
|
||||
)
|
||||
|
||||
|
||||
def _pnvo_event_window_candidate_metric_comparisons(
|
||||
default_diagnostic: TestMqlPnvoEventWindowDiagnostic,
|
||||
candidate_diagnostic: TestMqlPnvoEventWindowDiagnostic,
|
||||
) -> tuple[TestMqlPnvoEventWindowCandidateMetricComparison, ...]:
|
||||
candidate_samples = _pnvo_event_window_sample_by_time(candidate_diagnostic)
|
||||
comparisons: list[TestMqlPnvoEventWindowCandidateMetricComparison] = []
|
||||
for default_sample in default_diagnostic.sample_diagnostics:
|
||||
candidate_sample = candidate_samples.get(default_sample.time_s)
|
||||
if candidate_sample is None:
|
||||
continue
|
||||
for data_path in default_sample.data_paths:
|
||||
_append_metric_comparison(
|
||||
comparisons,
|
||||
time_s=default_sample.time_s,
|
||||
metric_name=f"path:{data_path}",
|
||||
default_abs_error=default_sample.abs_error(data_path),
|
||||
candidate_abs_error=candidate_sample.abs_error(data_path),
|
||||
)
|
||||
_append_pneumatic_96_candidate_metric_comparisons(
|
||||
comparisons,
|
||||
time_s=default_sample.time_s,
|
||||
default_sample=default_sample,
|
||||
candidate_sample=candidate_sample,
|
||||
)
|
||||
_append_pneumatic_87_candidate_metric_comparisons(
|
||||
comparisons,
|
||||
time_s=default_sample.time_s,
|
||||
default_sample=default_sample,
|
||||
candidate_sample=candidate_sample,
|
||||
)
|
||||
return tuple(comparisons)
|
||||
|
||||
|
||||
def run_test_mql_pnvo_event_window_candidate_comparison(
|
||||
config: TestMqlFullStateComparisonScriptConfig | None = None,
|
||||
*,
|
||||
orifice_alias: str = "pn_morifice_1",
|
||||
final_time_s: float = 0.041,
|
||||
) -> TestMqlPnvoEventWindowCandidateComparisonDiagnostic:
|
||||
default_diagnostic = run_test_mql_pnvo_event_window_diagnostic(
|
||||
_event_window_config_with_pneumatic_96_reference_rhs(
|
||||
config,
|
||||
enabled=False,
|
||||
),
|
||||
orifice_alias=orifice_alias,
|
||||
final_time_s=final_time_s,
|
||||
)
|
||||
candidate_diagnostic = run_test_mql_pnvo_event_window_diagnostic(
|
||||
_event_window_config_with_pneumatic_96_reference_rhs(
|
||||
config,
|
||||
enabled=True,
|
||||
),
|
||||
orifice_alias=orifice_alias,
|
||||
final_time_s=final_time_s,
|
||||
)
|
||||
return TestMqlPnvoEventWindowCandidateComparisonDiagnostic(
|
||||
orifice_alias=orifice_alias,
|
||||
event_time_s=default_diagnostic.event_time_s,
|
||||
final_time_s=default_diagnostic.final_time_s,
|
||||
default_diagnostic=default_diagnostic,
|
||||
candidate_diagnostic=candidate_diagnostic,
|
||||
metric_comparisons=_pnvo_event_window_candidate_metric_comparisons(
|
||||
default_diagnostic,
|
||||
candidate_diagnostic,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def format_test_mql_pnvo_event_window_summary(
|
||||
diagnostic: TestMqlPnvoEventWindowDiagnostic,
|
||||
) -> str:
|
||||
@@ -4094,6 +4341,38 @@ def format_test_mql_pnvo_event_window_summary(
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
|
||||
def format_test_mql_pnvo_event_window_candidate_comparison_summary(
|
||||
diagnostic: TestMqlPnvoEventWindowCandidateComparisonDiagnostic,
|
||||
) -> str:
|
||||
lines = [
|
||||
"Model: test_mql",
|
||||
f"Mode: PNVO event window candidate comparison ({diagnostic.orifice_alias})",
|
||||
f"Event time: {diagnostic.event_time_s}",
|
||||
f"Final time: {diagnostic.final_time_s}",
|
||||
"Default RHS: current pneumatic_96 internal-energy RHS",
|
||||
"Candidate RHS: pneumatic_96 reference-enthalpy/mass-offset RHS",
|
||||
"Metric comparisons: negative delta means the candidate reduced error",
|
||||
]
|
||||
for comparison in diagnostic.metric_comparisons:
|
||||
lines.append(
|
||||
f" t={comparison.time_s} - {comparison.metric_name}: "
|
||||
f"default_abs_error={comparison.default_abs_error}, "
|
||||
f"candidate_abs_error={comparison.candidate_abs_error}, "
|
||||
f"delta={comparison.abs_error_delta}"
|
||||
)
|
||||
lines.append("Final comparison:")
|
||||
for data_path in diagnostic.default_diagnostic.data_paths:
|
||||
lines.append(
|
||||
f" - {data_path}: "
|
||||
f"default_abs_error={diagnostic.default_diagnostic.abs_error(data_path)}, "
|
||||
f"candidate_abs_error={diagnostic.candidate_diagnostic.abs_error(data_path)}, "
|
||||
f"delta="
|
||||
f"{diagnostic.candidate_diagnostic.abs_error(data_path) - diagnostic.default_diagnostic.abs_error(data_path)}"
|
||||
)
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
def format_test_mql_full_state_comparison_summary(
|
||||
run: TestMqlFullStateComparisonRun,
|
||||
) -> str:
|
||||
@@ -4251,6 +4530,16 @@ def main() -> None:
|
||||
action="store_true",
|
||||
help="run the segmented PNVO opening window through the t=0.05 s save point",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--pnvo-event-window-candidate-comparison",
|
||||
action="store_true",
|
||||
help="compare the PNVO event window with and without the pneumatic_96 RHS candidate",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--pnvo-event-window-final-time",
|
||||
type=float,
|
||||
help="override PNVO event window final time; candidate comparison defaults to 0.041 s",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--amesim-results-archive",
|
||||
type=Path,
|
||||
@@ -4276,8 +4565,26 @@ def main() -> None:
|
||||
diagnostic = run_test_mql_pnvo_event_boundary_diagnostic(config)
|
||||
print(format_test_mql_pnvo_event_boundary_summary(diagnostic), end="")
|
||||
return
|
||||
if args.pnvo_event_window_candidate_comparison:
|
||||
diagnostic = run_test_mql_pnvo_event_window_candidate_comparison(
|
||||
config,
|
||||
final_time_s=args.pnvo_event_window_final_time or 0.041,
|
||||
)
|
||||
print(
|
||||
format_test_mql_pnvo_event_window_candidate_comparison_summary(
|
||||
diagnostic
|
||||
),
|
||||
end="",
|
||||
)
|
||||
return
|
||||
if args.pnvo_event_window:
|
||||
diagnostic = run_test_mql_pnvo_event_window_diagnostic(config)
|
||||
if args.pnvo_event_window_final_time is None:
|
||||
diagnostic = run_test_mql_pnvo_event_window_diagnostic(config)
|
||||
else:
|
||||
diagnostic = run_test_mql_pnvo_event_window_diagnostic(
|
||||
config,
|
||||
final_time_s=args.pnvo_event_window_final_time,
|
||||
)
|
||||
print(format_test_mql_pnvo_event_window_summary(diagnostic), end="")
|
||||
return
|
||||
|
||||
|
||||
Reference in new issue
Block a user