接入test_mql大质量块约束
This commit is contained in:
1 parent
bb4a71c612
commit
65cdd2284e
3 files changed
+103
-3
No files matched your search
@@ -3921,6 +3921,9 @@ class TestMqlFullStateClosure:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def rhs(self, state_vector: list[float]) -> list[float]:
|
def rhs(self, state_vector: list[float]) -> list[float]:
|
||||||
|
return self.rhs_at(0.0, state_vector)
|
||||||
|
|
||||||
|
def rhs_at(self, time_s: float, state_vector: list[float]) -> list[float]:
|
||||||
pneumatic_state, mechanical_state = self._split_state(list(state_vector))
|
pneumatic_state, mechanical_state = self._split_state(list(state_vector))
|
||||||
pneumatic_snapshot = self.pneumatic_closure.snapshot(pneumatic_state)
|
pneumatic_snapshot = self.pneumatic_closure.snapshot(pneumatic_state)
|
||||||
mechanical_snapshot = self.mechanical_closure.snapshot(mechanical_state)
|
mechanical_snapshot = self.mechanical_closure.snapshot(mechanical_state)
|
||||||
@@ -3929,14 +3932,20 @@ class TestMqlFullStateClosure:
|
|||||||
*self.mechanical_closure.rhs(
|
*self.mechanical_closure.rhs(
|
||||||
mechanical_state,
|
mechanical_state,
|
||||||
force_by_mass_alias=self._force_by_mass_alias(
|
force_by_mass_alias=self._force_by_mass_alias(
|
||||||
|
time_s,
|
||||||
pneumatic_snapshot,
|
pneumatic_snapshot,
|
||||||
mechanical_snapshot,
|
mechanical_snapshot,
|
||||||
),
|
),
|
||||||
|
constrained_mass_aliases={
|
||||||
|
"mass_friction_endstops_18",
|
||||||
|
"mass_friction_endstops_19",
|
||||||
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
def _force_by_mass_alias(
|
def _force_by_mass_alias(
|
||||||
self,
|
self,
|
||||||
|
time_s: float,
|
||||||
pneumatic_snapshot: object,
|
pneumatic_snapshot: object,
|
||||||
mechanical_snapshot: object,
|
mechanical_snapshot: object,
|
||||||
) -> dict[str, float]:
|
) -> dict[str, float]:
|
||||||
@@ -3948,6 +3957,13 @@ class TestMqlFullStateClosure:
|
|||||||
force_by_mass_alias[mass_alias] = (
|
force_by_mass_alias[mass_alias] = (
|
||||||
force_by_mass_alias.get(mass_alias, 0.0) - contact_force
|
force_by_mass_alias.get(mass_alias, 0.0) - contact_force
|
||||||
)
|
)
|
||||||
|
force_by_mass_alias.update(
|
||||||
|
self._large_mass_force_by_alias(
|
||||||
|
time_s,
|
||||||
|
pneumatic_snapshot,
|
||||||
|
mechanical_snapshot,
|
||||||
|
)
|
||||||
|
)
|
||||||
return force_by_mass_alias
|
return force_by_mass_alias
|
||||||
|
|
||||||
def _mechanical_node_total_force_by_alias(
|
def _mechanical_node_total_force_by_alias(
|
||||||
@@ -3964,6 +3980,30 @@ class TestMqlFullStateClosure:
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _large_mass_force_by_alias(
|
||||||
|
self,
|
||||||
|
time_s: float,
|
||||||
|
pneumatic_snapshot: object,
|
||||||
|
mechanical_snapshot: object,
|
||||||
|
) -> dict[str, float]:
|
||||||
|
node_force = self._mechanical_node_total_force_by_alias(
|
||||||
|
pneumatic_snapshot,
|
||||||
|
mechanical_snapshot,
|
||||||
|
)
|
||||||
|
forcecon_1 = self.mechanical_closure.assembly.force_connectors["forcecon_1"]
|
||||||
|
forcecon_2 = self.mechanical_closure.assembly.force_connectors["forcecon_2"]
|
||||||
|
signals = self.mechanical_closure.assembly.piecewise_signals
|
||||||
|
return {
|
||||||
|
"mass_friction_endstops_18": (
|
||||||
|
node_force["dynamic_mechanical_node_alternative_2"]
|
||||||
|
- forcecon_2.force_at(time_s, signals)
|
||||||
|
),
|
||||||
|
"mass_friction_endstops_19": (
|
||||||
|
forcecon_1.force_at(time_s, signals)
|
||||||
|
- node_force["dynamic_mechanical_node_alternative_3"]
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
def _piston_force_by_mass_alias(self, pneumatic_snapshot: object) -> dict[str, float]:
|
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
|
||||||
|
|
||||||
@@ -4342,7 +4382,7 @@ class TestMqlSystem:
|
|||||||
resistance_boundary_temperature_k=resistance_boundary_temperature_k,
|
resistance_boundary_temperature_k=resistance_boundary_temperature_k,
|
||||||
)
|
)
|
||||||
return integrate_ode(
|
return integrate_ode(
|
||||||
rhs=lambda t, state: closure.rhs(state),
|
rhs=lambda t, state: closure.rhs_at(t, state),
|
||||||
initial_state=closure.initial_state_vector(),
|
initial_state=closure.initial_state_vector(),
|
||||||
config=config or SolveIVPConfig(t_stop=1.0e-4, max_step=1.0e-5),
|
config=config or SolveIVPConfig(t_stop=1.0e-4, max_step=1.0e-5),
|
||||||
t_eval=t_eval,
|
t_eval=t_eval,
|
||||||
|
|||||||
@@ -274,17 +274,28 @@ class TestMqlMechanicalMassClosure:
|
|||||||
state_vector: list[float],
|
state_vector: list[float],
|
||||||
*,
|
*,
|
||||||
force_by_mass_alias: dict[str, float] | None = None,
|
force_by_mass_alias: dict[str, float] | None = None,
|
||||||
|
constrained_mass_aliases: set[str] | None = None,
|
||||||
) -> list[float]:
|
) -> list[float]:
|
||||||
snapshot = self.snapshot(state_vector)
|
snapshot = self.snapshot(state_vector)
|
||||||
force_by_mass_alias = force_by_mass_alias or {}
|
force_by_mass_alias = force_by_mass_alias or {}
|
||||||
|
constrained_mass_aliases = constrained_mass_aliases or set()
|
||||||
derivatives: list[float] = []
|
derivatives: list[float] = []
|
||||||
for state in snapshot.states:
|
for state in snapshot.states:
|
||||||
mass = self.assembly.masses[state.alias].endstop()
|
spec = self.assembly.masses[state.alias]
|
||||||
|
mass = spec.endstop()
|
||||||
|
applied_force = force_by_mass_alias.get(state.alias, 0.0)
|
||||||
acceleration, velocity = mass.derivatives(
|
acceleration, velocity = mass.derivatives(
|
||||||
velocity_m_s=state.velocity_m_s,
|
velocity_m_s=state.velocity_m_s,
|
||||||
displacement_m=state.displacement_m,
|
displacement_m=state.displacement_m,
|
||||||
port_1_force_n=force_by_mass_alias.get(state.alias, 0.0),
|
port_1_force_n=applied_force,
|
||||||
)
|
)
|
||||||
|
if state.alias in constrained_mass_aliases and _limit_constraint_holds(
|
||||||
|
spec,
|
||||||
|
state,
|
||||||
|
applied_force,
|
||||||
|
):
|
||||||
|
acceleration = 0.0
|
||||||
|
velocity = 0.0
|
||||||
derivatives.extend([acceleration, velocity])
|
derivatives.extend([acceleration, velocity])
|
||||||
return derivatives
|
return derivatives
|
||||||
|
|
||||||
@@ -414,6 +425,20 @@ def _build_mechanical_node(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _limit_constraint_holds(
|
||||||
|
spec: TestMqlMassEndstopSpec,
|
||||||
|
state: TestMqlMechanicalMassState,
|
||||||
|
applied_force_n: float,
|
||||||
|
) -> bool:
|
||||||
|
if abs(state.velocity_m_s) > spec.stick_velocity_threshold_m_s:
|
||||||
|
return False
|
||||||
|
at_lower_limit = state.displacement_m <= spec.xmin_m + spec.min_penetration_m
|
||||||
|
at_upper_limit = state.displacement_m >= spec.xmax_m - spec.max_penetration_m
|
||||||
|
return (at_lower_limit and applied_force_n <= 0.0) or (
|
||||||
|
at_upper_limit and applied_force_n >= 0.0
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _build_piecewise_signal(
|
def _build_piecewise_signal(
|
||||||
component: TestMqlResolvedComponent,
|
component: TestMqlResolvedComponent,
|
||||||
variable_catalog: TestMqlVariableCatalog | None,
|
variable_catalog: TestMqlVariableCatalog | None,
|
||||||
|
|||||||
@@ -597,6 +597,41 @@ class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase):
|
|||||||
expected_contact_force,
|
expected_contact_force,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_full_state_closure_constrains_large_masses_at_active_limits(self) -> None:
|
||||||
|
closure = self.system.full_state_closure_from_spec(
|
||||||
|
self.spec,
|
||||||
|
inlet_node_pressure_pa=15.31e6,
|
||||||
|
resistance_boundary_pressure_pa=15.29e6,
|
||||||
|
)
|
||||||
|
|
||||||
|
rhs = closure.rhs(closure.initial_state_vector())
|
||||||
|
|
||||||
|
self.assertAlmostEqual(rhs[128], 0.0)
|
||||||
|
self.assertAlmostEqual(rhs[129], 0.0)
|
||||||
|
self.assertAlmostEqual(rhs[130], 0.0)
|
||||||
|
self.assertAlmostEqual(rhs[131], 0.0)
|
||||||
|
|
||||||
|
def test_full_state_closure_releases_large_mass_when_node_force_points_inward(self) -> None:
|
||||||
|
closure = self.system.full_state_closure_from_spec(
|
||||||
|
self.spec,
|
||||||
|
inlet_node_pressure_pa=15.31e6,
|
||||||
|
resistance_boundary_pressure_pa=15.29e6,
|
||||||
|
)
|
||||||
|
state = closure.initial_state_vector()
|
||||||
|
state[113] = 1.0e-3
|
||||||
|
|
||||||
|
rhs = closure.rhs_at(0.8000000000000009, state)
|
||||||
|
endstop = closure.mechanical_closure.assembly.elastic_endstops[
|
||||||
|
"elasticendstop_8"
|
||||||
|
].endstop()
|
||||||
|
expected_contact_force = endstop.contact_force(-1.0, 0.0)
|
||||||
|
support_mass = closure.mechanical_closure.assembly.masses[
|
||||||
|
"mass_friction_endstops_18"
|
||||||
|
].mass_kg
|
||||||
|
|
||||||
|
self.assertAlmostEqual(rhs[128], expected_contact_force / support_mass)
|
||||||
|
self.assertAlmostEqual(rhs[129], 0.0)
|
||||||
|
|
||||||
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(
|
||||||
self.spec,
|
self.spec,
|
||||||
|
|||||||
Reference in new issue
Block a user