from __future__ import annotations import csv import tempfile import unittest from pathlib import Path from app.simulation.reporting.amesim_results import ( AmesimResults, load_test_mql_amesim_results, ) from app.simulation.reporting.test_mql_comparison import ( DEFAULT_TEST_MQL_ALIGNMENT_PATHS, TestMqlComparisonError, compare_test_mql_series, interpolate_series_value, write_test_mql_amesim_baseline_csv, write_test_mql_comparison_csv, ) REPO_ROOT = Path(__file__).resolve().parents[1] TEST_MQL_AME = REPO_ROOT / "AmesimModels" / "test_mql.ame" class TestMqlComparisonTests(unittest.TestCase): @classmethod def setUpClass(cls) -> None: cls.amesim_results = load_test_mql_amesim_results(TEST_MQL_AME) def test_exact_amesim_series_compare_with_zero_error(self) -> None: data_paths = ("temp3@pn_c1_8", "press3@pn_c1_8") python_series = { data_path: self.amesim_results.series(data_path) for data_path in data_paths } comparison = compare_test_mql_series( python_times=self.amesim_results.times, python_series_by_data_path=python_series, amesim_results=self.amesim_results, data_paths=data_paths, ) self.assertEqual(len(comparison.metrics), 2) self.assertEqual(comparison.max_abs_error, 0.0) self.assertEqual(comparison.metric("temp3@pn_c1_8").sample_count, 1002) def test_coarse_python_times_are_interpolated_against_amesim(self) -> None: data_path = "temp3@pn_c1_8" python_times = self.amesim_results.times[::100] python_series = { data_path: tuple( interpolate_series_value( self.amesim_results.times, self.amesim_results.series(data_path), time_value, ) for time_value in python_times ) } comparison = compare_test_mql_series( python_times=python_times, python_series_by_data_path=python_series, amesim_results=self.amesim_results, data_paths=(data_path,), ) self.assertEqual(comparison.metric(data_path).sample_count, len(python_times)) self.assertEqual(comparison.max_abs_error, 0.0) def test_offset_series_reports_abs_and_relative_error(self) -> None: data_path = "temp3@pn_c1_8" python_series = { data_path: tuple(value + 1.0 for value in self.amesim_results.series(data_path)) } comparison = compare_test_mql_series( python_times=self.amesim_results.times, python_series_by_data_path=python_series, amesim_results=self.amesim_results, data_paths=(data_path,), ) metric = comparison.metric(data_path) self.assertAlmostEqual(metric.max_abs_error, 1.0) self.assertAlmostEqual(metric.mean_abs_error, 1.0) self.assertGreater(metric.max_rel_error, 0.0) def test_zero_amesim_baseline_does_not_invent_a_relative_denominator(self) -> None: amesim_results = AmesimResults( times=(0.0, 1.0), variables=(), saved_variable_indices=(), series_by_data_path={"zero@baseline": (0.0, -0.0)}, final_values_by_data_path={"zero@baseline": -0.0}, ) comparison = compare_test_mql_series( python_times=(0.0, 1.0), python_series_by_data_path={"zero@baseline": (0.0, 1.0e-6)}, amesim_results=amesim_results, data_paths=("zero@baseline",), ) metric = comparison.metric("zero@baseline") self.assertEqual(metric.max_abs_error, 1.0e-6) self.assertEqual(metric.undefined_rel_error_count, 2) self.assertEqual(metric.near_zero_baseline_count, 2) self.assertEqual(comparison.undefined_rel_error_count, 2) self.assertEqual(metric.max_rel_error, 0.0) with tempfile.TemporaryDirectory() as temp_dir: comparison_path, _summary_path, _comparison = ( write_test_mql_comparison_csv( output_dir=Path(temp_dir), python_times=(0.0, 1.0), python_series_by_data_path={ "zero@baseline": (0.0, 1.0e-6) }, amesim_results=amesim_results, data_paths=("zero@baseline",), ) ) with comparison_path.open(newline="", encoding="utf-8") as handle: rows = list(csv.reader(handle)) self.assertEqual(rows[1][-1], "") self.assertEqual(rows[2][-1], "") def test_missing_data_path_is_rejected(self) -> None: with self.assertRaises(TestMqlComparisonError): compare_test_mql_series( python_times=self.amesim_results.times, python_series_by_data_path={"missing@component": (1.0,) * 1002}, amesim_results=self.amesim_results, ) def test_writes_baseline_and_comparison_csv_files(self) -> None: data_paths = DEFAULT_TEST_MQL_ALIGNMENT_PATHS[:2] python_series = { data_path: self.amesim_results.series(data_path) for data_path in data_paths } with tempfile.TemporaryDirectory() as temp_dir: output_dir = Path(temp_dir) baseline_path = write_test_mql_amesim_baseline_csv( output_dir, self.amesim_results, data_paths=data_paths, ) comparison_path, summary_path, comparison = write_test_mql_comparison_csv( output_dir=output_dir, python_times=self.amesim_results.times, python_series_by_data_path=python_series, amesim_results=self.amesim_results, data_paths=data_paths, ) self.assertTrue(baseline_path.exists()) self.assertTrue(comparison_path.exists()) self.assertTrue(summary_path.exists()) self.assertIn("time_s,temp3@pn_c1_8,press3@pn_c1_8", baseline_path.read_text(encoding="utf-8")) self.assertEqual(comparison.max_abs_error, 0.0) if __name__ == "__main__": unittest.main()