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
2 changed files with 64 additions and 5 deletions
Showing only changes of commit c8de46fac2 - Show all commits

No files matched your search

+45 -5
View File
@@ -3841,6 +3841,7 @@ class TestMqlSimulationResult:
class TestMqlFullStateSnapshot: class TestMqlFullStateSnapshot:
pneumatic: object pneumatic: object
mechanical: object mechanical: object
mechanical_node_total_force_by_alias: dict[str, float]
@property @property
def state_count(self) -> int: def state_count(self) -> int:
@@ -3906,9 +3907,17 @@ class TestMqlFullStateClosure:
def snapshot(self, state_vector: list[float] | None = None) -> TestMqlFullStateSnapshot: def snapshot(self, state_vector: list[float] | None = None) -> TestMqlFullStateSnapshot:
values = self.initial_state_vector() if state_vector is None else list(state_vector) values = self.initial_state_vector() if state_vector is None else list(state_vector)
pneumatic_state, mechanical_state = self._split_state(values) pneumatic_state, mechanical_state = self._split_state(values)
pneumatic_snapshot = self.pneumatic_closure.snapshot(pneumatic_state)
mechanical_snapshot = self.mechanical_closure.snapshot(mechanical_state)
return TestMqlFullStateSnapshot( return TestMqlFullStateSnapshot(
pneumatic=self.pneumatic_closure.snapshot(pneumatic_state), pneumatic=pneumatic_snapshot,
mechanical=self.mechanical_closure.snapshot(mechanical_state), mechanical=mechanical_snapshot,
mechanical_node_total_force_by_alias=(
self._mechanical_node_total_force_by_alias(
pneumatic_snapshot,
mechanical_snapshot,
)
),
) )
def rhs(self, state_vector: list[float]) -> list[float]: def rhs(self, state_vector: list[float]) -> list[float]:
@@ -3931,6 +3940,31 @@ class TestMqlFullStateClosure:
pneumatic_snapshot: object, pneumatic_snapshot: object,
mechanical_snapshot: object, mechanical_snapshot: object,
) -> dict[str, float]: ) -> dict[str, float]:
force_by_mass_alias = self._piston_force_by_mass_alias(pneumatic_snapshot)
elastic_force_by_mass_alias = self._elastic_endstop_force_by_mass_alias(
mechanical_snapshot
)
for mass_alias, contact_force in elastic_force_by_mass_alias.items():
force_by_mass_alias[mass_alias] = (
force_by_mass_alias.get(mass_alias, 0.0) - contact_force
)
return force_by_mass_alias
def _mechanical_node_total_force_by_alias(
self,
pneumatic_snapshot: object,
mechanical_snapshot: object,
) -> dict[str, float]:
return {
"dynamic_mechanical_node_alternative_2": sum(
self._elastic_endstop_force_by_mass_alias(mechanical_snapshot).values()
),
"dynamic_mechanical_node_alternative_3": sum(
self._piston_force_by_mass_alias(pneumatic_snapshot).values()
),
}
def _piston_force_by_mass_alias(self, pneumatic_snapshot: object) -> dict[str, float]:
from PythonModels.systems.test_mql_pneumatic import pressure_to_amesim_gauge_pa from PythonModels.systems.test_mql_pneumatic import pressure_to_amesim_gauge_pa
force_by_mass_alias: dict[str, float] = {} force_by_mass_alias: dict[str, float] = {}
@@ -3940,8 +3974,14 @@ class TestMqlFullStateClosure:
force_by_mass_alias[mass_alias] = ( force_by_mass_alias[mass_alias] = (
pressure_to_amesim_gauge_pa(chamber.p) * piston.annulus_area_m2 pressure_to_amesim_gauge_pa(chamber.p) * piston.annulus_area_m2
) )
return force_by_mass_alias
def _elastic_endstop_force_by_mass_alias(
self,
mechanical_snapshot: object,
) -> dict[str, float]:
state_by_alias = {state.alias: state for state in mechanical_snapshot.states} state_by_alias = {state.alias: state for state in mechanical_snapshot.states}
force_by_mass_alias: dict[str, float] = {}
for mass_alias, support_mass_alias, endstop_alias in _ELASTIC_ENDSTOP_FORCE_BINDINGS: for mass_alias, support_mass_alias, endstop_alias in _ELASTIC_ENDSTOP_FORCE_BINDINGS:
mass_state = state_by_alias[mass_alias] mass_state = state_by_alias[mass_alias]
support_state = state_by_alias[support_mass_alias] support_state = state_by_alias[support_mass_alias]
@@ -3952,9 +3992,9 @@ class TestMqlFullStateClosure:
penetration_velocity_m_s = ( penetration_velocity_m_s = (
mass_state.velocity_m_s - support_state.velocity_m_s mass_state.velocity_m_s - support_state.velocity_m_s
) )
force_by_mass_alias[mass_alias] = ( force_by_mass_alias[mass_alias] = endstop.contact_force(
force_by_mass_alias.get(mass_alias, 0.0) gap_mm,
- endstop.contact_force(gap_mm, penetration_velocity_m_s) penetration_velocity_m_s,
) )
return force_by_mass_alias return force_by_mass_alias
+19
View File
@@ -552,6 +552,18 @@ class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase):
snapshot.mechanical.states[0].alias, snapshot.mechanical.states[0].alias,
"mass_friction_endstops_10", "mass_friction_endstops_10",
) )
self.assertAlmostEqual(
snapshot.mechanical_node_total_force_by_alias[
"dynamic_mechanical_node_alternative_2"
],
0.0,
)
self.assertAlmostEqual(
snapshot.mechanical_node_total_force_by_alias[
"dynamic_mechanical_node_alternative_3"
],
-326.7174678324367,
)
self.assertAlmostEqual(rhs[112], -0.8167936695810917) self.assertAlmostEqual(rhs[112], -0.8167936695810917)
def test_full_state_closure_applies_elastic_endstop_force_to_small_masses(self) -> None: def test_full_state_closure_applies_elastic_endstop_force_to_small_masses(self) -> None:
@@ -563,6 +575,7 @@ class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase):
state = closure.initial_state_vector() state = closure.initial_state_vector()
state[113] = 1.0e-3 state[113] = 1.0e-3
snapshot = closure.snapshot(state)
rhs = closure.rhs(state) rhs = closure.rhs(state)
initial_rhs = closure.rhs(closure.initial_state_vector()) initial_rhs = closure.rhs(closure.initial_state_vector())
endstop = closure.mechanical_closure.assembly.elastic_endstops[ endstop = closure.mechanical_closure.assembly.elastic_endstops[
@@ -577,6 +590,12 @@ class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase):
rhs[112], rhs[112],
initial_rhs[112] - expected_contact_force / mass, initial_rhs[112] - expected_contact_force / mass,
) )
self.assertAlmostEqual(
snapshot.mechanical_node_total_force_by_alias[
"dynamic_mechanical_node_alternative_2"
],
expected_contact_force,
)
def test_simulates_full_132_state_closure(self) -> None: def test_simulates_full_132_state_closure(self) -> None:
solution = self.system.simulate_full_state_from_spec( solution = self.system.simulate_full_state_from_spec(