完善MECMAS21参数配置与分组交互

This commit is contained in:
ljz committed 2026-08-03 23:51:27 +08:00
1 parent 32f21f08ff
commit be54070855
28 files changed
+3418 -202

No files matched your search

@@ -72,7 +72,125 @@ class AmesimMechanicalPublicComponentTests(unittest.TestCase):
self.assertAlmostEqual(mass.port_1.x, 0.1)
self.assertAlmostEqual(mass.port_2.v, 0.2)
def test_mecmas21_uses_amesim_one_two_friction_encoding(self) -> None:
disabled = AmesimMecmas21(
"mass_disabled",
self.medium,
useFriction=1.0,
fcoul=5.0,
v0=2.0,
)
enabled = AmesimMecmas21(
"mass_enabled",
self.medium,
useFriction=2.0,
fcoul=5.0,
v0=2.0,
)
self.assertFalse(disabled.use_friction)
self.assertEqual(disabled._dry_friction_force(), 0.0)
self.assertTrue(enabled.use_friction)
self.assertEqual(enabled._dry_friction_force(), -5.0)
def test_mecmas21_choice_metadata_preserves_amesim_codes(self) -> None:
definitions = {
definition.name: definition
for definition in AmesimMecmas21.PARAMETERS
}
expected_options = {
"useFriction": ((1.0, "否"), (2.0, "是")),
"stoptype": (
(1.0, "理想限位"),
(2.0, "弹性限位"),
(3.0, "恢复碰撞"),
(4.0, "无限位"),
),
"discContactOption": (
(1.0, "允许负接触力"),
(2.0, "不允许负接触力"),
),
"strib": ((1.0, "否"), (2.0, "是")),
"frictionType": ((1.0, "简单"), (2.0, "高级")),
}
for name, options in expected_options.items():
with self.subTest(name=name):
definition = definitions[name]
self.assertEqual(definition.editor, "choice")
self.assertEqual(
tuple((option.value, option.label) for option in definition.options),
options,
)
self.assertIn("尚未实现", definitions["frictionType"].description)
self.assertIn("尚未实现", definitions["strib"].description)
self.assertEqual(definitions["theta"].label, "倾角(度)")
self.assertIn("+90°", definitions["theta"].description)
self.assertIn("-90°", definitions["theta"].description)
self.assertIn("重力分量", definitions["theta"].description)
self.assertEqual(AmesimMecmas21.MODEL_VERSION, "0.2.0")
def test_mecmas21_visibility_matches_amesim_parameter_dependencies(self) -> None:
definitions = {
definition.name: definition
for definition in AmesimMecmas21.PARAMETERS
}
expected_visibility = {
"fstick": (
("stoptype", (1.0, 2.0, 4.0)),
("useFriction", (2.0,)),
),
"fcoul": (
("stoptype", (1.0, 2.0, 4.0)),
("useFriction", (2.0,)),
),
"rvisc": (("useFriction", (2.0,)),),
"wind": (("useFriction", (2.0,)),),
"dvel": (
("stoptype", (1.0, 2.0, 4.0)),
("useFriction", (2.0,)),
("frictionType", (2.0,)),
),
"restdvel": (("stoptype", (3.0,)),),
"restcoeff": (("stoptype", (3.0,)),),
"astrib": (
("stoptype", (1.0, 2.0, 4.0)),
("useFriction", (2.0,)),
("frictionType", (2.0,)),
("strib", (2.0,)),
),
"xmin": (("stoptype", (1.0, 2.0, 3.0)),),
"Kbmin": (("stoptype", (2.0,)),),
"Dbmin": (("stoptype", (2.0,)),),
"Pdmin": (("stoptype", (2.0,)),),
"xmax": (("stoptype", (1.0, 2.0, 3.0)),),
"Kbmax": (("stoptype", (2.0,)),),
"Dbmax": (("stoptype", (2.0,)),),
"Pdmax": (("stoptype", (2.0,)),),
"discContactOption": (("stoptype", (2.0,)),),
"strib": (
("stoptype", (1.0, 2.0, 4.0)),
("useFriction", (2.0,)),
("frictionType", (2.0,)),
),
"frictionType": (
("stoptype", (1.0, 2.0, 4.0)),
("useFriction", (2.0,)),
),
}
for name, expected in expected_visibility.items():
with self.subTest(name=name):
self.assertEqual(
tuple(
(condition.parameter, condition.values)
for condition in definitions[name].visible_when
),
expected,
)
for name in ("mass", "theta", "useFriction", "stoptype", "v0", "x0"):
with self.subTest(always_visible=name):
self.assertEqual(definitions[name].visible_when, ())
def test_lmechn1_ties_active_port_kinematics_and_balances_force(self) -> None:
node = AmesimLmechn1("node_1", self.medium, v1=2.0, sum=1.0)
@@ -136,14 +254,32 @@ class AmesimMechanicalPublicComponentTests(unittest.TestCase):
self.assertAlmostEqual(contact.gap, 0.0005)
self.assertAlmostEqual(contact.contact_force, 0.0)
def test_mecmas21_registry_rejects_fractional_integer_options(self) -> None:
with self.assertRaisesRegex(ValueError, "useFriction must be an integer"):
def test_mecmas21_registry_rejects_fractional_choice_value(self) -> None:
with self.assertRaisesRegex(ValueError, "must be one of"):
COMPONENT_MODEL_REGISTRY["amesim_mecmas21"].create(
"mass_1",
self.medium,
{"useFriction": 0.5},
)
def test_mecmas21_registry_rejects_unknown_integer_options(self) -> None:
invalid_options = {
"useFriction": 0.0,
"stoptype": 0.0,
"discContactOption": 3.0,
"strib": 0.0,
"frictionType": 3.0,
}
for name, value in invalid_options.items():
with self.subTest(name=name):
with self.assertRaisesRegex(ValueError, "must be one of"):
COMPONENT_MODEL_REGISTRY["amesim_mecmas21"].create(
"mass_1",
self.medium,
{name: value},
)
if __name__ == "__main__":
unittest.main()