Skip to content

Commit 008ba20

Browse files
committed
Reduce tendon schema implementation redundancy
1 parent a85c242 commit 008ba20

5 files changed

Lines changed: 153 additions & 579 deletions

File tree

source/isaaclab/isaaclab/sim/schemas/schemas.py

Lines changed: 47 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,27 +1629,49 @@ def modify_joint_drive_properties(
16291629
"""
16301630

16311631

1632-
def _applied_schema_instance(applied_schema, schema_type: str) -> str | None:
1633-
"""Return an applied multiple-apply schema's instance when its type matches exactly."""
1634-
applied_type, instance = Usd.SchemaRegistry.GetTypeNameAndInstance(str(applied_schema))
1635-
return instance if applied_type == schema_type and instance else None
1632+
_FIXED_TENDON_SCHEMAS = ("PhysxTendonAxisRootAPI", "PhysxTendonAxisAPI")
1633+
_SPATIAL_TENDON_SCHEMAS = ("PhysxTendonAttachmentRootAPI",)
16361634

16371635

1638-
def _is_fixed_tendon_target(prim: Usd.Prim) -> bool:
1639-
"""Whether a prim carries a fixed-tendon representation."""
1640-
if prim.GetTypeName() == "MjcTendon":
1641-
return True
1642-
fixed_types = {"PhysxTendonAxisRootAPI", "PhysxTendonAxisAPI"}
1643-
return any(
1644-
_applied_schema_instance(schema, schema_type)
1645-
for schema in prim.GetAppliedSchemas()
1646-
for schema_type in fixed_types
1647-
)
1636+
def _write_tendon_properties(prim, values, schema_type):
1637+
authored = False
1638+
for schema in prim.GetAppliedSchemas():
1639+
applied_type, instance = Usd.SchemaRegistry.GetTypeNameAndInstance(str(schema))
1640+
if applied_type != schema_type or not instance:
1641+
continue
1642+
authored = True
1643+
for name, value in values.items():
1644+
attribute = f"physxTendon:{instance}:{to_camel_case(name, 'cC')}"
1645+
safe_set_attribute_on_usd_prim(prim, attribute, value, camel_case=False)
1646+
return authored
16481647

16491648

1650-
def _is_spatial_tendon_target(prim: Usd.Prim) -> bool:
1651-
"""Whether a prim carries a spatial-tendon root instance."""
1652-
return any(_applied_schema_instance(schema, "PhysxTendonAttachmentRootAPI") for schema in prim.GetAppliedSchemas())
1649+
def _apply_tendon_fragments(prim_path_expr, fragments, schema_types, prim_types, family, stage):
1650+
fragments = list(fragments)
1651+
if stage is None:
1652+
stage = get_current_stage()
1653+
if not fragments:
1654+
return True
1655+
targets, _, any_skipped = _match_fragment_targets(
1656+
prim_path_expr,
1657+
lambda prim: prim.GetTypeName() in prim_types
1658+
or any(
1659+
Usd.SchemaRegistry.GetTypeNameAndInstance(str(schema))[0] in schema_types
1660+
for schema in prim.GetAppliedSchemas()
1661+
),
1662+
stage,
1663+
)
1664+
if not targets:
1665+
logger.warning("No %s-tendon targets matched expression '%s'; nothing was authored.", family, prim_path_expr)
1666+
return False
1667+
success = not any_skipped
1668+
for cfg in fragments:
1669+
func = cfg.func if callable(cfg.func) else string_to_callable(cfg.func)
1670+
fragment_hit = False
1671+
for target in targets:
1672+
fragment_hit |= bool(func(cfg, target.GetPath().pathString, stage))
1673+
success = fragment_hit and success
1674+
return success
16531675

16541676

16551677
def apply_fixed_tendon_properties(
@@ -1684,26 +1706,7 @@ def apply_fixed_tendon_properties(
16841706
Returns:
16851707
True if every fragment tuned at least one target and no instanced prim was skipped.
16861708
"""
1687-
fragments = list(fragments)
1688-
if stage is None:
1689-
stage = get_current_stage()
1690-
if not fragments:
1691-
return True
1692-
targets, _, any_skipped = _match_fragment_targets(prim_path_expr, _is_fixed_tendon_target, stage)
1693-
if not targets:
1694-
logger.warning("No fixed-tendon targets matched expression '%s'; nothing was authored.", prim_path_expr)
1695-
return False
1696-
# per-fragment any-target aggregation: a fragment fails only when it tuned no target at all,
1697-
# since each backend's func legitimately no-ops on the other backend's tendon prims.
1698-
success = not any_skipped
1699-
for cfg in fragments:
1700-
func = cfg.func if callable(cfg.func) else string_to_callable(cfg.func)
1701-
fragment_hit = False
1702-
for target in targets:
1703-
if func(cfg, target.GetPath().pathString, stage):
1704-
fragment_hit = True
1705-
success = fragment_hit and success
1706-
return success
1709+
return _apply_tendon_fragments(prim_path_expr, fragments, _FIXED_TENDON_SCHEMAS, ("MjcTendon",), "fixed", stage)
17071710

17081711

17091712
@apply_nested
@@ -1744,42 +1747,12 @@ def modify_fixed_tendon_properties(
17441747
if stage is None:
17451748
stage = get_current_stage()
17461749

1747-
# get USD prim
17481750
tendon_prim = stage.GetPrimAtPath(prim_path)
1749-
# check if prim has fixed tendon applied on it or if the mjc tendon prim exiss
1750-
applied_schemas = tendon_prim.GetAppliedSchemas()
1751-
prim_type = tendon_prim.GetTypeName()
1752-
if (
1753-
not any(_applied_schema_instance(schema, "PhysxTendonAxisRootAPI") for schema in applied_schemas)
1754-
and prim_type != "MjcTendon"
1755-
):
1756-
return False
1757-
1758-
# resolve all available instances of the schema since it is multi-instance
1759-
cfg = cfg.to_dict()
1760-
if prim_type != "MjcTendon":
1761-
for schema_name in applied_schemas:
1762-
instance_name = _applied_schema_instance(schema_name, "PhysxTendonAxisRootAPI")
1763-
if instance_name is None:
1764-
continue
1765-
for attr_name, value in cfg.items():
1766-
template = f"physxTendon:__INSTANCE_NAME__:{to_camel_case(attr_name, 'cC')}"
1767-
attribute = Usd.SchemaRegistry.MakeMultipleApplyNameInstance(template, instance_name)
1768-
safe_set_attribute_on_usd_prim(
1769-
tendon_prim,
1770-
attribute,
1771-
value,
1772-
camel_case=False,
1773-
)
1774-
else:
1775-
# NOTE: ``mjc:*`` branch (``MjcTendon`` prim) kept inline; future split candidate into isaaclab_newton.
1776-
# only stiffness and damping in the cfg map to mjc attributes
1777-
for attr_name in ("stiffness", "damping"):
1778-
value = cfg.get(attr_name)
1779-
safe_set_attribute_on_usd_prim(
1780-
tendon_prim, f"mjc:{to_camel_case(attr_name, 'cC')}", value, camel_case=False
1781-
)
1782-
# success
1751+
values = cfg.to_dict()
1752+
if tendon_prim.GetTypeName() != "MjcTendon":
1753+
return _write_tendon_properties(tendon_prim, values, "PhysxTendonAxisRootAPI")
1754+
for name in ("stiffness", "damping"):
1755+
safe_set_attribute_on_usd_prim(tendon_prim, f"mjc:{name}", values.get(name), camel_case=False)
17831756
return True
17841757

17851758

@@ -1819,26 +1792,7 @@ def apply_spatial_tendon_properties(
18191792
Returns:
18201793
True if every fragment tuned at least one target and no instanced prim was skipped.
18211794
"""
1822-
fragments = list(fragments)
1823-
if stage is None:
1824-
stage = get_current_stage()
1825-
if not fragments:
1826-
return True
1827-
targets, _, any_skipped = _match_fragment_targets(prim_path_expr, _is_spatial_tendon_target, stage)
1828-
if not targets:
1829-
logger.warning("No spatial-tendon targets matched expression '%s'; nothing was authored.", prim_path_expr)
1830-
return False
1831-
# per-fragment any-target aggregation: a fragment fails only when it tuned no target at all,
1832-
# since each backend's func legitimately no-ops on the other backend's tendon prims.
1833-
success = not any_skipped
1834-
for cfg in fragments:
1835-
func = cfg.func if callable(cfg.func) else string_to_callable(cfg.func)
1836-
fragment_hit = False
1837-
for target in targets:
1838-
if func(cfg, target.GetPath().pathString, stage):
1839-
fragment_hit = True
1840-
success = fragment_hit and success
1841-
return success
1795+
return _apply_tendon_fragments(prim_path_expr, fragments, _SPATIAL_TENDON_SCHEMAS, (), "spatial", stage)
18421796

18431797

18441798
@apply_nested
@@ -1878,30 +1832,8 @@ def modify_spatial_tendon_properties(
18781832
# obtain stage
18791833
if stage is None:
18801834
stage = get_current_stage()
1881-
# get USD prim
18821835
tendon_prim = stage.GetPrimAtPath(prim_path)
1883-
# check if prim has spatial tendon applied on it
1884-
applied_schemas = tendon_prim.GetAppliedSchemas()
1885-
has_spatial = any(_applied_schema_instance(schema, "PhysxTendonAttachmentRootAPI") for schema in applied_schemas)
1886-
if not has_spatial:
1887-
return False
1888-
1889-
cfg = cfg.to_dict()
1890-
for schema_name in applied_schemas:
1891-
instance_name = _applied_schema_instance(schema_name, "PhysxTendonAttachmentRootAPI")
1892-
if instance_name is None:
1893-
continue
1894-
for attr_name, value in cfg.items():
1895-
template = f"physxTendon:__INSTANCE_NAME__:{to_camel_case(attr_name, 'cC')}"
1896-
attribute = Usd.SchemaRegistry.MakeMultipleApplyNameInstance(template, instance_name)
1897-
safe_set_attribute_on_usd_prim(
1898-
tendon_prim,
1899-
attribute,
1900-
value,
1901-
camel_case=False,
1902-
)
1903-
# success
1904-
return True
1836+
return _write_tendon_properties(tendon_prim, cfg.to_dict(), "PhysxTendonAttachmentRootAPI")
19051837

19061838

19071839
"""

0 commit comments

Comments
 (0)