诊断test_mql总闭包对比端点

This commit is contained in:
huojiarong committed 2026-07-20 10:04:43 +00:00
1 parent 3951bc372c
commit a6e1faa2d8
2 files changed
+92

No files matched your search

@@ -8,6 +8,7 @@ from PythonModels.core.solver import SolveIVPConfig
from PythonModels.reporting.amesim_results import AmesimResults, load_test_mql_amesim_results
from PythonModels.reporting.test_mql_comparison import (
TestMqlComparisonResult,
interpolate_series_value,
write_test_mql_comparison_csv,
)
from PythonModels.reporting.test_mql_output_schema import (
@@ -36,6 +37,19 @@ DEFAULT_FULL_STATE_COMPARISON_DATA_PATHS = (
)
@dataclass(frozen=True)
class TestMqlFullStateSignalDiagnostic:
data_path: str
initial_time_s: float
final_time_s: float
initial_python_value: float
initial_amesim_value: float
initial_abs_error: float
final_python_value: float
final_amesim_value: float
final_abs_error: float
@dataclass(frozen=True)
class TestMqlFullStateComparisonRun:
system: TestMqlSystem
@@ -67,6 +81,53 @@ class TestMqlFullStateComparisonRun:
metrics = self.metrics_by_max_abs_error()
return metrics[0] if metrics else None
def signal_diagnostic(self, data_path: str) -> TestMqlFullStateSignalDiagnostic:
times = self.output.times
python_values = self.output.series_by_data_path[data_path]
amesim_values = self.amesim_results.series(data_path)
initial_time = float(times[0])
final_time = float(times[-1])
initial_python = float(python_values[0])
final_python = float(python_values[-1])
initial_amesim = interpolate_series_value(
self.amesim_results.times,
amesim_values,
initial_time,
)
final_amesim = interpolate_series_value(
self.amesim_results.times,
amesim_values,
final_time,
)
return TestMqlFullStateSignalDiagnostic(
data_path=data_path,
initial_time_s=initial_time,
final_time_s=final_time,
initial_python_value=initial_python,
initial_amesim_value=initial_amesim,
initial_abs_error=abs(initial_python - initial_amesim),
final_python_value=final_python,
final_amesim_value=final_amesim,
final_abs_error=abs(final_python - final_amesim),
)
def diagnostics_by_final_abs_error(self):
return tuple(
sorted(
(
self.signal_diagnostic(data_path)
for data_path in self.output.data_paths
),
key=lambda diagnostic: diagnostic.final_abs_error,
reverse=True,
)
)
@property
def largest_final_abs_error_diagnostic(self):
diagnostics = self.diagnostics_by_final_abs_error()
return diagnostics[0] if diagnostics else None
@dataclass(frozen=True)
class TestMqlFullStateComparisonPathConfig:
@@ -195,12 +256,28 @@ def format_test_mql_full_state_comparison_summary(
"Largest absolute error: "
f"{largest_metric.data_path}={largest_metric.max_abs_error}"
)
largest_diagnostic = run.largest_final_abs_error_diagnostic
if largest_diagnostic is not None:
lines.append(
"Largest final endpoint error: "
f"{largest_diagnostic.data_path}={largest_diagnostic.final_abs_error}"
)
lines.append("Metrics by max absolute error:")
for metric in run.metrics_by_max_abs_error():
lines.append(
f" - {metric.data_path}: max_abs_error={metric.max_abs_error}, "
f"final_abs_error={metric.final_abs_error}"
)
lines.append("Endpoint diagnostics by final absolute error:")
for diagnostic in run.diagnostics_by_final_abs_error():
lines.append(
f" - {diagnostic.data_path}: "
f"initial_python={diagnostic.initial_python_value}, "
f"initial_amesim={diagnostic.initial_amesim_value}, "
f"final_python={diagnostic.final_python_value}, "
f"final_amesim={diagnostic.final_amesim_value}, "
f"final_abs_error={diagnostic.final_abs_error}"
)
return "\n".join(lines) + "\n"
@@ -50,11 +50,24 @@ class RunTestMqlFullStateComparisonScriptTests(unittest.TestCase):
run.metrics_by_max_abs_error()[0].data_path,
"press@pn_c1_8",
)
diagnostic = run.signal_diagnostic("press@pn_c1_8")
self.assertEqual(diagnostic.data_path, "press@pn_c1_8")
self.assertAlmostEqual(diagnostic.initial_python_value, -1300.0)
self.assertAlmostEqual(diagnostic.final_python_value, -1300.0)
self.assertAlmostEqual(diagnostic.final_abs_error, 0.0, delta=1.0e-8)
self.assertEqual(
run.diagnostics_by_final_abs_error()[0].data_path,
"press@pn_c1_8",
)
self.assertTrue(csv_summary_exists)
self.assertIn("Mode: Python 132 full-state closure comparison", summary)
self.assertIn("Compared signals: 2", 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)
self.assertIn("Endpoint diagnostics by final absolute error:", summary)
self.assertIn("final_python=", summary)
self.assertIn("final_amesim=", summary)
self.assertIn("python.press@pn_c1_8", csv_header)
self.assertIn("amesim.vol1@pn_brp2_8", csv_header)
@@ -102,7 +115,9 @@ class RunTestMqlFullStateComparisonScriptTests(unittest.TestCase):
self.assertIn("Output schema signals: 858", summary)
self.assertIn("Compared signals: 1", 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)
self.assertIn("Endpoint diagnostics by final absolute error:", summary)
self.assertTrue(summary.endswith("\n"))