Fix pneumatic node zero-flow reversal

This commit is contained in:
huojiarong committed 2026-08-17 09:24:35 +00:00
1 parent 16a7eb2d6c
commit 0fa166c8e5
3 files changed
+159 -3

No files matched your search

@@ -123,6 +123,37 @@ class AmesimPneumaticNodeComponentTests(unittest.TestCase):
)
self.assertAlmostEqual(energy_flow, 0.0, places=10)
def test_port_2_outflow_enthalpy_remains_finite_through_flow_reversal(self) -> None:
node = AmesimP4Node2("p4_1")
connected_h = {
"port_1": 300.0,
"port_2": 300.0,
"port_3": 200.0,
"port_4": 100.0,
}
outflow_enthalpies: list[float] = []
for reference_flow in (-1.0e-6, 0.0, 1.0e-6):
node.port_1.m_flow = -1.0
node.port_2.m_flow = reference_flow
node.port_3.m_flow = -reference_flow
node.port_4.m_flow = 1.0
node.update_stream_outflows(connected_h)
self.assertAlmostEqual(
sum(port.m_flow for port in node.ports.values()),
0.0,
places=15,
)
outflow_enthalpies.append(node.port_2.h_outflow)
self.assertTrue(all(abs(value) < 1.0e4 for value in outflow_enthalpies))
self.assertLess(
max(outflow_enthalpies) - min(outflow_enthalpies),
1.0,
)
if __name__ == "__main__":
unittest.main()
+87 -1
View File
@@ -1,6 +1,6 @@
from __future__ import annotations
from math import exp
from math import exp, isfinite
import unittest
from app.simulation.components.amesim.mechanical.translational import (
@@ -130,7 +130,93 @@ def _single_mass_system(
return GenericFluidSystem(network), mass
def _high_stiffness_contact_impact_system() -> GenericFluidSystem:
"""Return the reduced mechanical core of the four-branch stop impact.
The production model has four 50 kg piston groups coupled through LSTP00A
contacts to one 170000 kg support group. When the support reaches its
ideal upper stop, its velocity is reset while each contact still carries
the finite, extremely fast LSTP damping transient. One branch is enough
to retain that stiffness and state-transition interaction in a fast test.
"""
medium = IdealGasMedium()
zero_left = AmesimF000("zero_left")
moving_mass = AmesimMecmas21(
"moving_mass",
medium,
mass=50.0,
useFriction=1.0,
stoptype=4.0,
x0=0.0090025,
v0=1.0,
)
contact = AmesimLstp00a(
"contact",
medium,
gap0=0.0,
kcont=1.0e11,
rcont=1.0e11,
Pdis=1.0e-7,
discContactOption=1.0,
)
support_mass = AmesimMecmas21(
"support_mass",
medium,
mass=170000.0,
useFriction=1.0,
stoptype=1.0,
xmin=0.0,
xmax=0.01,
x0=0.009,
v0=1.0,
)
zero_right = AmesimF000("zero_right")
network = SimulationNetwork("high-stiffness-contact-impact")
for component in (
zero_left,
moving_mass,
contact,
support_mass,
zero_right,
):
network.add_component(component)
network.connect("zero_left", "port_1", "moving_mass", "port_1")
network.connect("moving_mass", "port_2", "contact", "port_1")
network.connect("contact", "port_2", "support_mass", "port_1")
network.connect("support_mass", "port_2", "zero_right", "port_1")
return GenericFluidSystem(network)
class MechanicalSolverCausalizationTests(unittest.TestCase):
def test_high_stiffness_lstp_survives_ideal_stop_transition(self) -> None:
system = _high_stiffness_contact_impact_system()
result = system.simulate(
SolveIVPConfig(
t_start=0.0,
t_stop=0.002,
max_step=0.002,
method="BDF",
rtol=1.0e-6,
),
sample_step=0.00025,
)
self.assertTrue(result.success, result.message)
totals = result.diagnostics["integration"]["totals"]
self.assertEqual(totals["stateTransitionCount"], 1)
self.assertEqual(totals["solverStartCount"], 2)
self.assertEqual(totals["recoverableRetryCount"], 0)
self.assertAlmostEqual(result.series["support_mass.x"][-1], 0.01)
self.assertAlmostEqual(result.series["support_mass.v"][-1], 0.0, delta=1.0e-9)
self.assertAlmostEqual(result.series["moving_mass.v"][-1], 0.0, delta=1.0e-4)
self.assertGreater(max(result.series["contact.force"]), 1.0e10)
for values in result.series.values():
self.assertTrue(all(isfinite(value) for value in values))
def test_lstp_contact_uses_exponential_damping_ramp_and_negative_force_option(
self,
) -> None: