Files
SystemSimulationApp/tests/test_mql_full_branches_regression.py
T
lujingze b435daecf2 完善通用求解器回归与前端交互
- 引入因果坐标内核、热流体恢复和递进长时回归\n- 完善正交连线、线桥、视图保持与结果曲线缩放\n- 补充依赖约束、CI、测试基线和北京时间更新日志
2026-08-18 06:42:07 +00:00

115 lines
4.5 KiB
Python

from __future__ import annotations
import hashlib
import os
from pathlib import Path
import unittest
from app.main import compile_system_xml_network
from app.simulation.benchmark_regression import (
load_regression_manifest,
run_regression_suite,
source_simulation_config,
)
from app.simulation.systems.generic import GenericFluidSystem
from app.system_xml import validate_system_xml_document
MANIFEST_PATH = Path(
"tests/baselines/simulation/test_mql_full_branches/manifest.json"
)
LONG_RUN_ENVIRONMENT = "RUN_TEST_MQL_FULL_BRANCHES_LONG_REGRESSION"
class MqlFullBranchesStaticRegressionTests(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.manifest = load_regression_manifest(MANIFEST_PATH)
cls.source_path = Path(cls.manifest["_sourcePath"])
cls.source_payload = cls.source_path.read_bytes()
cls.validation = validate_system_xml_document(cls.source_payload)
def test_authoritative_xml_hash_and_simulation_settings_are_fixed(self) -> None:
source = self.manifest["source"]
self.assertEqual(
hashlib.sha256(self.source_payload).hexdigest(), source["sha256"]
)
self.assertEqual(len(self.source_payload), source["bytes"])
self.assertEqual(
source_simulation_config(self.source_payload), source["simulation"]
)
def test_structure_snapshot_covers_the_historical_solver_shape(self) -> None:
self.assertTrue(self.validation.valid, self.validation.as_dict())
assert self.validation.document is not None
network = compile_system_xml_network(self.validation.document)
system = GenericFluidSystem(network)
expected = self.manifest["structure"]
pressure_flow = network.pressure_flow_structure_dict()
causal_execution = system.pressure_flow_solver.causal_execution_diagnostics()
jacobian = system.jacobian_sparsity_diagnostics()
self.assertEqual(len(network.components), expected["componentCount"])
self.assertEqual(len(network.connections), expected["connectionCount"])
self.assertEqual(
len(network.dynamic_components()), expected["dynamicComponentCount"]
)
self.assertEqual(
sum(component.state_size for component in network.dynamic_components()),
expected["stateCount"],
)
self.assertEqual(
len(network.result_variable_metadata()), expected["resultVariableCount"]
)
self.assertEqual(
pressure_flow["unknownCount"], expected["pressureFlowUnknownCount"]
)
self.assertEqual(
pressure_flow["equationCount"], expected["pressureFlowEquationCount"]
)
self.assertEqual(pressure_flow["isSquare"], expected["pressureFlowIsSquare"])
for key in (
"logicalEffortCoordinateCount",
"eliminatedEffortAliasCount",
"canonicalCoordinateCount",
"compatibilityScatterCount",
):
self.assertEqual(causal_execution[key], expected[key])
self.assertEqual(jacobian["nonzeroCount"], expected["jacobianNonzeroCount"])
self.assertEqual(
jacobian["colorGroupCount"], expected["jacobianColorGroupCount"]
)
self.assertEqual(
system.mechanical_state_reducer.has_state_events,
expected["hasMechanicalStateEvents"],
)
def test_both_horizons_have_the_expected_signal_schedule(self) -> None:
assert self.validation.document is not None
system = GenericFluidSystem(
compile_system_xml_network(self.validation.document)
)
for case_id in self.manifest["sequence"]:
variant = self.manifest["variants"][case_id]
actual = system.signal_resolver.event_times(
0.0, float(variant["stopTime"])
)
self.assertEqual(actual, tuple(variant["expectedSignalEventTimes"]))
@unittest.skipUnless(
os.getenv(LONG_RUN_ENVIRONMENT, "").strip().lower() in {"1", "true", "yes"},
f"Set {LONG_RUN_ENVIRONMENT}=1 to run bounded 0.81/2.10 s integration.",
)
class MqlFullBranchesLongRegressionTests(unittest.TestCase):
def test_both_horizons_complete_within_their_safety_budgets(self) -> None:
report = run_regression_suite(MANIFEST_PATH, lane="solver-only")
outcomes = [case["outcome"] for case in report["cases"]]
self.assertEqual(outcomes, ["completed", "completed"], report["cases"])
if __name__ == "__main__":
unittest.main()