Import google-deepmind/mujoco_warp from GitHub.

PiperOrigin-RevId: 792201820
Change-Id: Ib7f4a1c28c8e48f91f00878c49e2aafdc169ba9e
This commit is contained in:
Baruch Tabanpour
2025-08-07 09:53:15 -07:00
committed by Copybara-Service
parent bb4aeb44f1
commit 4533129103
27 changed files with 2483 additions and 577 deletions
+3
View File
@@ -64,7 +64,9 @@ from mujoco.mjx.third_party.mujoco_warp._src.solver import solve as solve
from mujoco.mjx.third_party.mujoco_warp._src.support import contact_force as contact_force from mujoco.mjx.third_party.mujoco_warp._src.support import contact_force as contact_force
from mujoco.mjx.third_party.mujoco_warp._src.support import mul_m as mul_m from mujoco.mjx.third_party.mujoco_warp._src.support import mul_m as mul_m
from mujoco.mjx.third_party.mujoco_warp._src.support import xfrc_accumulate as xfrc_accumulate from mujoco.mjx.third_party.mujoco_warp._src.support import xfrc_accumulate as xfrc_accumulate
from mujoco.mjx.third_party.mujoco_warp._src.test_util import BenchmarkSuite as BenchmarkSuite
from mujoco.mjx.third_party.mujoco_warp._src.test_util import benchmark as benchmark from mujoco.mjx.third_party.mujoco_warp._src.test_util import benchmark as benchmark
from mujoco.mjx.third_party.mujoco_warp._src.types import BroadphaseFilter as BroadphaseFilter
from mujoco.mjx.third_party.mujoco_warp._src.types import BroadphaseType as BroadphaseType from mujoco.mjx.third_party.mujoco_warp._src.types import BroadphaseType as BroadphaseType
from mujoco.mjx.third_party.mujoco_warp._src.types import ConeType as ConeType from mujoco.mjx.third_party.mujoco_warp._src.types import ConeType as ConeType
from mujoco.mjx.third_party.mujoco_warp._src.types import Constraint as Constraint from mujoco.mjx.third_party.mujoco_warp._src.types import Constraint as Constraint
@@ -72,6 +74,7 @@ from mujoco.mjx.third_party.mujoco_warp._src.types import Contact as Contact
from mujoco.mjx.third_party.mujoco_warp._src.types import DisableBit as DisableBit from mujoco.mjx.third_party.mujoco_warp._src.types import DisableBit as DisableBit
from mujoco.mjx.third_party.mujoco_warp._src.types import DynType as DynType from mujoco.mjx.third_party.mujoco_warp._src.types import DynType as DynType
from mujoco.mjx.third_party.mujoco_warp._src.types import EnableBit as EnableBit from mujoco.mjx.third_party.mujoco_warp._src.types import EnableBit as EnableBit
from mujoco.mjx.third_party.mujoco_warp._src.types import IntegratorType as IntegratorType
from mujoco.mjx.third_party.mujoco_warp._src.types import JointType as JointType from mujoco.mjx.third_party.mujoco_warp._src.types import JointType as JointType
from mujoco.mjx.third_party.mujoco_warp._src.types import Option as Option from mujoco.mjx.third_party.mujoco_warp._src.types import Option as Option
from mujoco.mjx.third_party.mujoco_warp._src.types import SolverType as SolverType from mujoco.mjx.third_party.mujoco_warp._src.types import SolverType as SolverType
@@ -321,7 +321,8 @@ def ccd_kernel_builder(
x1 += hfield_prism_vertex(geom1.hfprism, i) x1 += hfield_prism_vertex(geom1.hfprism, i)
x1 = x1 / 6.0 x1 = x1 / 6.0
dist, x1, x2 = ccd( dist, count, witness1, witness2 = ccd(
False,
1e-6, 1e-6,
0.0, 0.0,
gjk_iterations, gjk_iterations,
@@ -344,13 +345,13 @@ def ccd_kernel_builder(
epa_map_in[tid], epa_map_in[tid],
epa_horizon_in[tid], epa_horizon_in[tid],
) )
count = 0 if dist >= 0.0:
if dist < 0.0: count = 0
count = 1 return
points[0] = 0.5 * (x1 + x2)
normal = x1 - x2
for i in range(count):
points[i] = 0.5 * (witness1[i] + witness2[i])
normal = witness1[0] - witness2[0]
frame = make_frame(normal) frame = make_frame(normal)
for i in range(count): for i in range(count):
# limit maximum number of contacts with height field # limit maximum number of contacts with height field
@@ -475,7 +475,7 @@ class CollisionTest(parameterized.TestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
register_sdf_plugins(mjwarp._src.collision_sdf) register_sdf_plugins(mjwarp)
@parameterized.parameters(_SDF_SDF.keys()) @parameterized.parameters(_SDF_SDF.keys())
def test_sdf_collision(self, fixture): def test_sdf_collision(self, fixture):
File diff suppressed because it is too large Load Diff
@@ -96,9 +96,11 @@ def _geom_dist(m: Model, d: Data, gid1: int, gid2: int, iterations: int):
( (
dist, dist,
count,
x1, x1,
x2, x2,
) = ccd( ) = ccd(
False,
1e-6, 1e-6,
1.0e30, 1.0e30,
iterations, iterations,
@@ -123,8 +125,8 @@ def _geom_dist(m: Model, d: Data, gid1: int, gid2: int, iterations: int):
) )
dist_out[0] = dist dist_out[0] = dist
pos_out[0] = x1 pos_out[0] = x1[0]
pos_out[1] = x2 pos_out[1] = x2[0]
vert = wp.array(shape=(iterations,), dtype=wp.vec3) vert = wp.array(shape=(iterations,), dtype=wp.vec3)
vert1 = wp.array(shape=(iterations,), dtype=wp.vec3) vert1 = wp.array(shape=(iterations,), dtype=wp.vec3)
@@ -253,8 +255,7 @@ class GJKTest(absltest.TestCase):
""" """
) )
# TODO(kbayes): use margin trick instead of EPA for penetration recovery dist, _, _ = _geom_dist(m, d, 0, 1, 0)
dist, _, _ = _geom_dist(m, d, 0, 1, 500)
self.assertAlmostEqual(-2, dist) self.assertAlmostEqual(-2, dist)
def test_box_box_contact(self): def test_box_box_contact(self):
+69 -21
View File
@@ -65,11 +65,33 @@ def transform_aabb(aabb_pos: wp.vec3, aabb_size: wp.vec3, pos: wp.vec3, ori: wp.
return aabb return aabb
@wp.func
def radial_field(a: wp.vec3, x: wp.vec3, size: wp.vec3) -> wp.vec3:
field = wp.cw_div(-size, a)
field = wp.normalize(field)
field[0] *= wp.sign(x[0])
field[1] *= wp.sign(x[1])
field[2] *= wp.sign(x[2])
return field
@wp.func @wp.func
def sphere(p: wp.vec3, size: wp.vec3) -> float: def sphere(p: wp.vec3, size: wp.vec3) -> float:
return wp.length(p) - size[0] return wp.length(p) - size[0]
@wp.func
def box(p: wp.vec3, size: wp.vec3) -> float:
a = wp.abs(p) - size
if a[0] >= 0 or a[1] >= 0 or a[2] >= 0:
z = wp.vec3(0.0, 0.0, 0.0)
b = wp.max(a, z)
return wp.norm_l2(b) + wp.min(wp.max(a), 0.0)
b = radial_field(a, p, size)
t = -wp.cw_div(a, wp.abs(b))
return -wp.min(t) * wp.norm_l2(b)
@wp.func @wp.func
def ellipsoid(p: wp.vec3, size: wp.vec3) -> float: def ellipsoid(p: wp.vec3, size: wp.vec3) -> float:
scaled_p = wp.vec3(p[0] / size[0], p[1] / size[1], p[2] / size[2]) scaled_p = wp.vec3(p[0] / size[0], p[1] / size[1], p[2] / size[2])
@@ -91,6 +113,24 @@ def grad_sphere(p: wp.vec3) -> wp.vec3:
wp.vec3(0.0) wp.vec3(0.0)
@wp.func
def grad_box(p: wp.vec3, size: wp.vec3) -> wp.vec3:
a = wp.abs(p) - size
if wp.max(a) < 0:
return radial_field(a, p, size)
z = wp.vec3(0.0, 0.0, 0.0)
b = wp.max(a, z)
c = wp.norm_l2(b)
g = wp.cw_mul(wp.div(b, c), wp.cw_div(p, wp.abs(p)))
if a[0] <= 0:
g[0] = 0.0
if a[1] <= 0:
g[1] = 0.0
if a[2] <= 0:
g[2] = 0.0
return g
@wp.func @wp.func
def grad_ellipsoid(p: wp.vec3, size: wp.vec3) -> wp.vec3: def grad_ellipsoid(p: wp.vec3, size: wp.vec3) -> wp.vec3:
a = wp.vec3(p[0] / size[0], p[1] / size[1], p[2] / size[2]) a = wp.vec3(p[0] / size[0], p[1] / size[1], p[2] / size[2])
@@ -128,8 +168,12 @@ def user_sdf_grad(p: wp.vec3, attr: wp.vec3, sdf_type: int) -> wp.vec3:
@wp.func @wp.func
def sdf(type: int, p: wp.vec3, attr: wp.vec3, sdf_type: int) -> float: def sdf(type: int, p: wp.vec3, attr: wp.vec3, sdf_type: int) -> float:
if type == int(GeomType.SPHERE.value): if type == int(GeomType.PLANE.value):
return p[2]
elif type == int(GeomType.SPHERE.value):
return sphere(p, attr) return sphere(p, attr)
elif type == int(GeomType.BOX.value):
return box(p, attr)
elif type == int(GeomType.ELLIPSOID.value): elif type == int(GeomType.ELLIPSOID.value):
return ellipsoid(p, attr) return ellipsoid(p, attr)
elif type == int(GeomType.SDF.value): elif type == int(GeomType.SDF.value):
@@ -140,8 +184,13 @@ def sdf(type: int, p: wp.vec3, attr: wp.vec3, sdf_type: int) -> float:
@wp.func @wp.func
def sdf_grad(type: int, p: wp.vec3, attr: wp.vec3, sdf_type: int) -> wp.vec3: def sdf_grad(type: int, p: wp.vec3, attr: wp.vec3, sdf_type: int) -> wp.vec3:
if type == int(GeomType.SPHERE.value): if type == int(GeomType.PLANE.value):
grad = wp.vec3(0.0, 0.0, 1.0)
return grad
elif type == int(GeomType.SPHERE.value):
return grad_sphere(p) return grad_sphere(p)
elif type == int(GeomType.BOX.value):
return grad_box(p, attr)
elif type == int(GeomType.ELLIPSOID.value): elif type == int(GeomType.ELLIPSOID.value):
return grad_ellipsoid(p, attr) return grad_ellipsoid(p, attr)
elif type == int(GeomType.SDF.value): elif type == int(GeomType.SDF.value):
@@ -444,41 +493,40 @@ def _sdf_narrowphase(
g1_plugin = geom_plugin_index[g1] g1_plugin = geom_plugin_index[g1]
g2_plugin = geom_plugin_index[g2] g2_plugin = geom_plugin_index[g2]
g2_to_g1_rot = wp.transpose(geom2.rot) * geom1.rot g1_to_g2_rot = wp.transpose(geom1.rot) * geom2.rot
g2_to_g1_pos = wp.transpose(geom2.rot) * (geom1.pos - geom2.pos) g1_to_g2_pos = wp.transpose(geom1.rot) * (geom2.pos - geom1.pos)
aabb_pos = geom_aabb[g1, 0] aabb_pos = geom_aabb[g1, 0]
aabb_size = geom_aabb[g1, 1] aabb_size = geom_aabb[g1, 1]
aabb1 = transform_aabb(aabb_pos, aabb_size, g2_to_g1_pos, g2_to_g1_rot) identity = wp.identity(3, dtype=float)
aabb1 = transform_aabb(aabb_pos, aabb_size, wp.vec3(0.0), identity)
aabb_pos = geom_aabb[g2, 0] aabb_pos = geom_aabb[g2, 0]
aabb_size = geom_aabb[g2, 1] aabb_size = geom_aabb[g2, 1]
aabb2 = transform_aabb(aabb_pos, aabb_size, wp.vec3(0.0), wp.mat33(1.0)) aabb2 = transform_aabb(aabb_pos, aabb_size, g1_to_g2_pos, g1_to_g2_rot)
aabb_intersection = AABB() aabb_intersection = AABB()
aabb_intersection.min = wp.max(aabb1.min, aabb2.min) aabb_intersection.min = wp.max(aabb1.min, aabb2.min)
aabb_intersection.max = wp.min(aabb1.max, aabb2.max) aabb_intersection.max = wp.min(aabb1.max, aabb2.max)
geom_pos2 = geom_pos[worldid, g2] pos2 = geom2.pos
quat2 = geom_quat[worldid, g2] rot2 = geom2.rot
geom_mat2 = math.quat_to_mat(quat2) pos1 = geom1.pos
rot2 = math.mul(geom2.rot, math.transpose(geom_mat2)) rot1 = geom1.rot
pos2 = wp.sub(geom2.pos, math.mul(rot2, geom_pos2))
if type1 == int(GeomType.SDF.value): if type1 == int(GeomType.SDF.value):
geom_pos1 = geom_pos[worldid, g1]
quat1 = geom_quat[worldid, g1]
geom_mat1 = math.quat_to_mat(quat1)
rot1 = math.mul(geom1.rot, math.transpose(geom_mat1))
pos1 = wp.sub(geom1.pos, math.mul(rot1, geom_pos1))
attr1 = plugin_attr[g1_plugin] attr1 = plugin_attr[g1_plugin]
g1_plugin_id = plugin[g1_plugin] g1_plugin_id = plugin[g1_plugin]
else: else:
pos1 = geom1.pos
rot1 = geom1.rot
attr1 = geom1.size attr1 = geom1.size
g1_plugin_id = -1 g1_plugin_id = -1
if g2_plugin != -1:
attr2 = plugin_attr[g2_plugin]
g2_plugin_id = plugin[g2_plugin]
else:
attr2 = geom2.size
g2_plugin_id = -1
for i in range(sdf_initpoints): for i in range(sdf_initpoints):
x_g2 = wp.vec3( x_g2 = wp.vec3(
aabb_intersection.min[0] + (aabb_intersection.max[0] - aabb_intersection.min[0]) * halton(i, 2), aabb_intersection.min[0] + (aabb_intersection.max[0] - aabb_intersection.min[0]) * halton(i, 2),
@@ -486,11 +534,11 @@ def _sdf_narrowphase(
aabb_intersection.min[2] + (aabb_intersection.max[2] - aabb_intersection.min[2]) * halton(i, 5), aabb_intersection.min[2] + (aabb_intersection.max[2] - aabb_intersection.min[2]) * halton(i, 5),
) )
x = geom2.rot * x_g2 + geom2.pos x = geom1.rot * x_g2 + geom1.pos
x0_initial = wp.transpose(rot2) * (x - pos2) x0_initial = wp.transpose(rot2) * (x - pos2)
dist, pos, n = gradient_descent( dist, pos, n = gradient_descent(
type1, x0_initial, attr1, plugin_attr[g2_plugin], pos1, rot1, pos2, rot2, g1_plugin_id, plugin[g2_plugin], sdf_iterations type1, x0_initial, attr1, attr2, pos1, rot1, pos2, rot2, g1_plugin_id, g2_plugin_id, sdf_iterations
) )
write_contact( write_contact(
@@ -65,33 +65,32 @@ class ConstraintTest(parameterized.TestCase):
xml = f""" xml = f"""
<mujoco> <mujoco>
<worldbody> <worldbody>
<body pos="0.0 0 0"> <body>
<freejoint/>
<geom type="sphere" size=".1" condim="{condim1}"/> <geom type="sphere" size=".1" condim="{condim1}"/>
</body>
<body pos="0.05 0 0">
<freejoint/> <freejoint/>
</body>
<body>
<geom type="sphere" size=".1" condim="{condim2}"/> <geom type="sphere" size=".1" condim="{condim2}"/>
</body> </body>
<body>
<geom type="ellipsoid" size=".1 .1 .1" condim="{condim2}"/>
</body>
</worldbody> </worldbody>
<keyframe>
<key qpos=".10 .11 .12 .7071 .7071 0 0" />
</keyframe>
</mujoco> </mujoco>
""" """
_, mjd, m, d = test_util.fixture(xml=xml, cone=cone) _, mjd, m, d = test_util.fixture(xml=xml, cone=cone, keyframe=0)
for arr in (
d.efc.D,
d.efc.aref,
d.efc.pos,
d.efc.margin,
):
arr.zero_()
# fill with nan to check whether we are not reading uninitialized values # fill with nan to check whether we are not reading uninitialized values
d.efc.J.fill_(wp.nan) for arr in (d.efc.J, d.efc.D, d.efc.aref, d.efc.pos, d.efc.margin):
arr.fill_(wp.nan)
mjwarp.make_constraint(m, d) mjwarp.make_constraint(m, d)
_assert_eq(d.ncon.numpy()[0], mjd.ncon, "ncon")
_assert_eq(d.efc.J.numpy()[0, : mjd.nefc, :].reshape(-1), mjd.efc_J, "efc_J") _assert_eq(d.efc.J.numpy()[0, : mjd.nefc, :].reshape(-1), mjd.efc_J, "efc_J")
_assert_eq(d.efc.D.numpy()[0, : mjd.nefc], mjd.efc_D, "efc_D") _assert_eq(d.efc.D.numpy()[0, : mjd.nefc], mjd.efc_D, "efc_D")
_assert_eq(d.efc.aref.numpy()[0, : mjd.nefc], mjd.efc_aref, "efc_aref") _assert_eq(d.efc.aref.numpy()[0, : mjd.nefc], mjd.efc_aref, "efc_aref")
@@ -105,21 +104,12 @@ class ConstraintTest(parameterized.TestCase):
def test_constraints(self, cone): def test_constraints(self, cone):
"""Test constraints.""" """Test constraints."""
for key in range(3): for key in range(3):
mjm, mjd, m, d = test_util.fixture("constraints.xml", sparse=False, cone=cone, keyframe=key) _, mjd, m, d = test_util.fixture("constraints.xml", sparse=False, cone=cone, keyframe=key)
for arr in ( for arr in (d.ne, d.nefc, d.nf, d.nl, d.efc.type):
d.efc.D, arr.fill_(-1)
d.efc.aref, for arr in (d.efc.J, d.efc.D, d.efc.aref, d.efc.pos, d.efc.margin):
d.efc.pos, arr.fill_(wp.nan)
d.efc.margin,
d.ne,
d.nefc,
d.nf,
d.nl,
):
arr.zero_()
d.efc.J.fill_(wp.nan)
mjwarp.make_constraint(m, d) mjwarp.make_constraint(m, d)
@@ -140,8 +130,10 @@ class ConstraintTest(parameterized.TestCase):
for keyframe in range(-1, 1): for keyframe in range(-1, 1):
_, mjd, m, d = test_util.fixture("tendon/tendon_limit.xml", sparse=False, keyframe=keyframe) _, mjd, m, d = test_util.fixture("tendon/tendon_limit.xml", sparse=False, keyframe=keyframe)
for arr in (d.nefc, d.nl, d.efc.J, d.efc.D, d.efc.aref, d.efc.pos, d.efc.margin): for arr in (d.nefc, d.nl, d.efc.type):
arr.zero_() arr.fill_(-1)
for arr in (d.efc.J, d.efc.D, d.efc.aref, d.efc.pos, d.efc.margin):
arr.fill_(wp.nan)
mjwarp.make_constraint(m, d) mjwarp.make_constraint(m, d)
@@ -197,9 +189,15 @@ class ConstraintTest(parameterized.TestCase):
<key qpos=".1 .2 .3"/> <key qpos=".1 .2 .3"/>
</keyframe> </keyframe>
</mujoco> </mujoco>
""" """,
keyframe=0,
) )
for arr in (d.nefc, d.ne, d.efc.type):
arr.fill_(-1)
for arr in (d.efc.J, d.efc.D, d.efc.vel, d.efc.aref, d.efc.pos, d.efc.margin):
arr.fill_(wp.nan)
mjwarp.make_constraint(m, d) mjwarp.make_constraint(m, d)
_assert_eq(d.nefc.numpy()[0], mjd.nefc, "nefc") _assert_eq(d.nefc.numpy()[0], mjd.nefc, "nefc")
+1 -1
View File
@@ -1017,9 +1017,9 @@ def forward(m: Model, d: Data):
fwd_actuation(m, d) fwd_actuation(m, d)
fwd_acceleration(m, d, factorize=True) fwd_acceleration(m, d, factorize=True)
sensor.sensor_acc(m, d)
solver.solve(m, d) solver.solve(m, d)
sensor.sensor_acc(m, d)
@event_scope @event_scope
+72 -11
View File
@@ -27,6 +27,9 @@ from mujoco.mjx.third_party.mujoco_warp._src import types
# number of max iterations to run GJK/EPA # number of max iterations to run GJK/EPA
MJ_CCD_ITERATIONS = 12 MJ_CCD_ITERATIONS = 12
# max number of worlds supported
MAX_WORLDS = 2**24
def _hfield_geom_pair(mjm: mujoco.MjModel) -> Tuple[int, np.array]: def _hfield_geom_pair(mjm: mujoco.MjModel) -> Tuple[int, np.array]:
geom1, geom2 = np.triu_indices(mjm.ngeom, k=1) geom1, geom2 = np.triu_indices(mjm.ngeom, k=1)
@@ -115,6 +118,20 @@ def put_model(mjm: mujoco.MjModel) -> types.Model:
if mjm.opt.noslip_iterations > 0: if mjm.opt.noslip_iterations > 0:
raise NotImplementedError(f"noslip solver not implemented.") raise NotImplementedError(f"noslip solver not implemented.")
# contact sensor
is_contact_sensor = mjm.sensor_type == types.SensorType.CONTACT
if is_contact_sensor.any():
# matching
if (
(mjm.sensor_objtype[is_contact_sensor] != types.ObjType.GEOM)
| (mjm.sensor_reftype[is_contact_sensor] != types.ObjType.GEOM)
).any():
raise NotImplementedError("Contact sensor: only geom1-geom2 matching is implemented.")
# reduction
if (mjm.sensor_intprm[is_contact_sensor, 1] != 1).any():
raise NotImplementedError(f"Contact sensor: only mindist reduction is implemented.")
# TODO(team): remove after _update_gradient for Newton uses tile operations for islands # TODO(team): remove after _update_gradient for Newton uses tile operations for islands
nv_max = 60 nv_max = 60
if mjm.nv > nv_max and mjm.opt.jacobian == mujoco.mjtJacobian.mjJAC_DENSE: if mjm.nv > nv_max and mjm.opt.jacobian == mujoco.mjtJacobian.mjJAC_DENSE:
@@ -366,10 +383,11 @@ def put_model(mjm: mujoco.MjModel) -> types.Model:
array._is_batched = True array._is_batched = True
if not expand_dim: if not expand_dim:
array.strides = (0,) + array.strides[1:] array.strides = (0,) + array.strides[1:]
array.shape = (MAX_WORLDS,) + array.shape[1:]
return array return array
array.strides = (0,) + array.strides array.strides = (0,) + array.strides
array.ndim += 1 array.ndim += 1
array.shape = (1,) + array.shape array.shape = (MAX_WORLDS,) + array.shape
return array return array
# rangefinder # rangefinder
@@ -415,6 +433,7 @@ def put_model(mjm: mujoco.MjModel) -> types.Model:
nwrap=mjm.nwrap, nwrap=mjm.nwrap,
nsensor=mjm.nsensor, nsensor=mjm.nsensor,
nsensordata=mjm.nsensordata, nsensordata=mjm.nsensordata,
nsensortaxel=sum(mjm.mesh_vertnum[mjm.sensor_objid[mjm.sensor_type == mujoco.mjtSensor.mjSENS_TACTILE]]),
nmeshvert=mjm.nmeshvert, nmeshvert=mjm.nmeshvert,
nmeshface=mjm.nmeshface, nmeshface=mjm.nmeshface,
nmeshgraph=mjm.nmeshgraph, nmeshgraph=mjm.nmeshgraph,
@@ -595,10 +614,13 @@ def put_model(mjm: mujoco.MjModel) -> types.Model:
mesh_vertadr=wp.array(mjm.mesh_vertadr, dtype=int), mesh_vertadr=wp.array(mjm.mesh_vertadr, dtype=int),
mesh_vertnum=wp.array(mjm.mesh_vertnum, dtype=int), mesh_vertnum=wp.array(mjm.mesh_vertnum, dtype=int),
mesh_vert=wp.array(mjm.mesh_vert, dtype=wp.vec3), mesh_vert=wp.array(mjm.mesh_vert, dtype=wp.vec3),
mesh_normaladr=wp.array(mjm.mesh_normaladr, dtype=int),
mesh_normal=wp.array(mjm.mesh_normal, dtype=wp.vec3),
mesh_faceadr=wp.array(mjm.mesh_faceadr, dtype=int), mesh_faceadr=wp.array(mjm.mesh_faceadr, dtype=int),
mesh_face=wp.array(mjm.mesh_face, dtype=wp.vec3i), mesh_face=wp.array(mjm.mesh_face, dtype=wp.vec3i),
mesh_graphadr=wp.array(mjm.mesh_graphadr, dtype=int), mesh_graphadr=wp.array(mjm.mesh_graphadr, dtype=int),
mesh_graph=wp.array(mjm.mesh_graph, dtype=int), mesh_graph=wp.array(mjm.mesh_graph, dtype=int),
mesh_quat=wp.array(mjm.mesh_quat, dtype=wp.quat),
mesh_polynum=wp.array(mjm.mesh_polynum, dtype=int), mesh_polynum=wp.array(mjm.mesh_polynum, dtype=int),
mesh_polyadr=wp.array(mjm.mesh_polyadr, dtype=int), mesh_polyadr=wp.array(mjm.mesh_polyadr, dtype=int),
mesh_polynormal=wp.array(mjm.mesh_polynormal, dtype=wp.vec3), mesh_polynormal=wp.array(mjm.mesh_polynormal, dtype=wp.vec3),
@@ -709,6 +731,7 @@ def put_model(mjm: mujoco.MjModel) -> types.Model:
sensor_objid=wp.array(mjm.sensor_objid, dtype=int), sensor_objid=wp.array(mjm.sensor_objid, dtype=int),
sensor_reftype=wp.array(mjm.sensor_reftype, dtype=int), sensor_reftype=wp.array(mjm.sensor_reftype, dtype=int),
sensor_refid=wp.array(mjm.sensor_refid, dtype=int), sensor_refid=wp.array(mjm.sensor_refid, dtype=int),
sensor_intprm=wp.array(mjm.sensor_intprm, dtype=int),
sensor_dim=wp.array(mjm.sensor_dim, dtype=int), sensor_dim=wp.array(mjm.sensor_dim, dtype=int),
sensor_adr=wp.array(mjm.sensor_adr, dtype=int), sensor_adr=wp.array(mjm.sensor_adr, dtype=int),
sensor_cutoff=wp.array(mjm.sensor_cutoff, dtype=float), sensor_cutoff=wp.array(mjm.sensor_cutoff, dtype=float),
@@ -776,6 +799,7 @@ def put_model(mjm: mujoco.MjModel) -> types.Model:
mjm.sensor_type, mjm.sensor_type,
[mujoco.mjtSensor.mjSENS_SUBTREELINVEL, mujoco.mjtSensor.mjSENS_SUBTREEANGMOM], [mujoco.mjtSensor.mjSENS_SUBTREELINVEL, mujoco.mjtSensor.mjSENS_SUBTREEANGMOM],
).any(), ).any(),
sensor_contact_adr=wp.array(np.nonzero(mjm.sensor_type == mujoco.mjtSensor.mjSENS_CONTACT)[0], dtype=int),
sensor_rne_postconstraint=np.isin( sensor_rne_postconstraint=np.isin(
mjm.sensor_type, mjm.sensor_type,
[ [
@@ -798,6 +822,24 @@ def put_model(mjm: mujoco.MjModel) -> types.Model:
block_dim=types.BlockDim(), block_dim=types.BlockDim(),
geom_pair_type_count=tuple(geom_type_pair_count), geom_pair_type_count=tuple(geom_type_pair_count),
has_sdf_geom=bool(np.any(mjm.geom_type == mujoco.mjtGeom.mjGEOM_SDF)), has_sdf_geom=bool(np.any(mjm.geom_type == mujoco.mjtGeom.mjGEOM_SDF)),
taxel_vertadr=wp.array(
[
j + mjm.mesh_vertadr[mjm.sensor_objid[i]]
for i in range(mjm.nsensor)
if mjm.sensor_type[i] == mujoco.mjtSensor.mjSENS_TACTILE
for j in range(mjm.mesh_vertnum[mjm.sensor_objid[i]])
],
dtype=int,
),
taxel_sensorid=wp.array(
[
i
for i in range(mjm.nsensor)
if mjm.sensor_type[i] == mujoco.mjtSensor.mjSENS_TACTILE
for j in range(mjm.mesh_vertnum[mjm.sensor_objid[i]])
],
dtype=int,
),
) )
return m return m
@@ -811,11 +853,12 @@ def make_data(mjm: mujoco.MjModel, nworld: int = 1, nconmax: int = -1, njmax: in
mjm (mujoco.MjModel): The model containing kinematic and dynamic information (host). mjm (mujoco.MjModel): The model containing kinematic and dynamic information (host).
nworld (int, optional): Number of worlds. Defaults to 1. nworld (int, optional): Number of worlds. Defaults to 1.
nconmax (int, optional): Maximum number of contacts for all worlds. Defaults to -1. nconmax (int, optional): Maximum number of contacts for all worlds. Defaults to -1.
njmax (int, optional): Maximum number of constraints for all worlds. Defaults to -1. njmax (int, optional): Maximum number of constraints per world. Defaults to -1.
Returns: Returns:
Data: The data object containing the current state and output arrays (device). Data: The data object containing the current state and output arrays (device).
""" """
# TODO(team): move to Model? # TODO(team): move to Model?
if nconmax == -1: if nconmax == -1:
# TODO(team): heuristic for nconmax # TODO(team): heuristic for nconmax
@@ -823,6 +866,16 @@ def make_data(mjm: mujoco.MjModel, nworld: int = 1, nconmax: int = -1, njmax: in
if njmax == -1: if njmax == -1:
# TODO(team): heuristic for njmax # TODO(team): heuristic for njmax
njmax = 20 * 6 njmax = 20 * 6
if nworld < 1 or nworld > MAX_WORLDS:
raise ValueError(f"nworld must be >= 1 and <= {MAX_WORLDS}")
if nconmax < 1:
raise ValueError("nconmax must be >= 1")
if njmax < 1:
raise ValueError("njmax must be >= 1")
condim = np.concatenate((mjm.geom_condim, mjm.pair_dim)) condim = np.concatenate((mjm.geom_condim, mjm.pair_dim))
condim_max = np.max(condim) if len(condim) > 0 else 0 condim_max = np.max(condim) if len(condim) > 0 else 0
@@ -833,6 +886,7 @@ def make_data(mjm: mujoco.MjModel, nworld: int = 1, nconmax: int = -1, njmax: in
qM = wp.zeros((nworld, mjm.nv, mjm.nv), dtype=float) qM = wp.zeros((nworld, mjm.nv, mjm.nv), dtype=float)
qLD = wp.zeros((nworld, mjm.nv, mjm.nv), dtype=float) qLD = wp.zeros((nworld, mjm.nv, mjm.nv), dtype=float)
nsensorcontact = np.sum(mjm.sensor_type == mujoco.mjtSensor.mjSENS_CONTACT)
nrangefinder = sum(mjm.sensor_type == mujoco.mjtSensor.mjSENS_RANGEFINDER) nrangefinder = sum(mjm.sensor_type == mujoco.mjtSensor.mjSENS_RANGEFINDER)
return types.Data( return types.Data(
@@ -841,6 +895,7 @@ def make_data(mjm: mujoco.MjModel, nworld: int = 1, nconmax: int = -1, njmax: in
njmax=njmax, njmax=njmax,
solver_niter=wp.zeros(nworld, dtype=int), solver_niter=wp.zeros(nworld, dtype=int),
ncon=wp.zeros(1, dtype=int), ncon=wp.zeros(1, dtype=int),
ncon_world=wp.zeros(nworld, dtype=int),
ncon_hfield=wp.zeros((nworld, _hfield_geom_pair(mjm)[0]), dtype=int), # warp only ncon_hfield=wp.zeros((nworld, _hfield_geom_pair(mjm)[0]), dtype=int), # warp only
ne=wp.zeros(nworld, dtype=int), ne=wp.zeros(nworld, dtype=int),
ne_connect=wp.zeros(nworld, dtype=int), # warp only ne_connect=wp.zeros(nworld, dtype=int), # warp only
@@ -965,8 +1020,6 @@ def make_data(mjm: mujoco.MjModel, nworld: int = 1, nconmax: int = -1, njmax: in
prev_grad=wp.zeros((nworld, mjm.nv), dtype=float), prev_grad=wp.zeros((nworld, mjm.nv), dtype=float),
prev_Mgrad=wp.zeros((nworld, mjm.nv), dtype=float), prev_Mgrad=wp.zeros((nworld, mjm.nv), dtype=float),
beta=wp.zeros((nworld,), dtype=float), beta=wp.zeros((nworld,), dtype=float),
beta_num=wp.zeros((nworld,), dtype=float),
beta_den=wp.zeros((nworld,), dtype=float),
done=wp.zeros((nworld,), dtype=bool), done=wp.zeros((nworld,), dtype=bool),
# linesearch # linesearch
ls_done=wp.zeros((nworld,), dtype=bool), ls_done=wp.zeros((nworld,), dtype=bool),
@@ -1051,6 +1104,10 @@ def make_data(mjm: mujoco.MjModel, nworld: int = 1, nconmax: int = -1, njmax: in
sensor_rangefinder_vec=wp.zeros((nworld, nrangefinder), dtype=wp.vec3), sensor_rangefinder_vec=wp.zeros((nworld, nrangefinder), dtype=wp.vec3),
sensor_rangefinder_dist=wp.zeros((nworld, nrangefinder), dtype=float), sensor_rangefinder_dist=wp.zeros((nworld, nrangefinder), dtype=float),
sensor_rangefinder_geomid=wp.zeros((nworld, nrangefinder), dtype=int), sensor_rangefinder_geomid=wp.zeros((nworld, nrangefinder), dtype=int),
sensor_contact_nmatch=wp.zeros((nworld, nsensorcontact), dtype=int),
sensor_contact_matchid=wp.zeros((nworld, nsensorcontact, types.MJ_MAXCONPAIR), dtype=int),
sensor_contact_criteria=wp.zeros((nworld, nsensorcontact, types.MJ_MAXCONPAIR), dtype=float),
sensor_contact_direction=wp.zeros((nworld, nsensorcontact, types.MJ_MAXCONPAIR), dtype=float),
# ray # ray
ray_bodyexclude=wp.zeros(1, dtype=int), ray_bodyexclude=wp.zeros(1, dtype=int),
ray_dist=wp.zeros((nworld, 1), dtype=float), ray_dist=wp.zeros((nworld, 1), dtype=float),
@@ -1078,7 +1135,7 @@ def put_data(
mjd (mujoco.MjData): The data object containing current state and output arrays (host). mjd (mujoco.MjData): The data object containing current state and output arrays (host).
nworld (int, optional): The number of worlds. Defaults to 1. nworld (int, optional): The number of worlds. Defaults to 1.
nconmax (int, optional): The maximum number of contacts for all worlds. Defaults to -1. nconmax (int, optional): The maximum number of contacts for all worlds. Defaults to -1.
njmax (int, optional): The maximum number of constraints for all worlds. Defaults to -1. njmax (int, optional): The maximum number of constraints per world. Defaults to -1.
Returns: Returns:
Data: The data object containing the current state and output arrays (device). Data: The data object containing the current state and output arrays (device).
@@ -1089,12 +1146,12 @@ def put_data(
nworld = nworld or 1 nworld = nworld or 1
# TODO(team): better heuristic for nconmax # TODO(team): better heuristic for nconmax
nconmax = nconmax or max(512, mjd.ncon * nworld) nconmax = nconmax or max(512, 4 * mjd.ncon * nworld)
# TODO(team): better heuristic for njmax # TODO(team): better heuristic for njmax
njmax = njmax or max(5, mjd.nefc) njmax = njmax or max(5, 4 * mjd.nefc)
if nworld < 1: if nworld < 1 or nworld > MAX_WORLDS:
raise ValueError("nworld must be >= 1") raise ValueError(f"nworld must be >= 1 and <= {MAX_WORLDS}")
if nconmax < 1: if nconmax < 1:
raise ValueError("nconmax must be >= 1") raise ValueError("nconmax must be >= 1")
@@ -1192,6 +1249,7 @@ def put_data(
efc_force_fill[:, :nefc] = np.tile(mjd.efc_force, (nworld, 1)) efc_force_fill[:, :nefc] = np.tile(mjd.efc_force, (nworld, 1))
efc_margin_fill[:, :nefc] = np.tile(mjd.efc_margin, (nworld, 1)) efc_margin_fill[:, :nefc] = np.tile(mjd.efc_margin, (nworld, 1))
nsensorcontact = np.sum(mjm.sensor_type == mujoco.mjtSensor.mjSENS_CONTACT)
nrangefinder = sum(mjm.sensor_type == mujoco.mjtSensor.mjSENS_RANGEFINDER) nrangefinder = sum(mjm.sensor_type == mujoco.mjtSensor.mjSENS_RANGEFINDER)
# some helper functions to simplify the data field definitions below # some helper functions to simplify the data field definitions below
@@ -1225,6 +1283,7 @@ def put_data(
njmax=njmax, njmax=njmax,
solver_niter=tile(mjd.solver_niter[0]), solver_niter=tile(mjd.solver_niter[0]),
ncon=arr([mjd.ncon * nworld]), ncon=arr([mjd.ncon * nworld]),
ncon_world=wp.zeros(nworld, dtype=int),
ncon_hfield=wp.zeros((nworld, _hfield_geom_pair(mjm)[0]), dtype=int), # warp only ncon_hfield=wp.zeros((nworld, _hfield_geom_pair(mjm)[0]), dtype=int), # warp only
ne=wp.full(shape=(nworld), value=mjd.ne), ne=wp.full(shape=(nworld), value=mjd.ne),
ne_connect=wp.full(shape=(nworld), value=ne_connect), ne_connect=wp.full(shape=(nworld), value=ne_connect),
@@ -1346,8 +1405,6 @@ def put_data(
prev_grad=wp.empty(shape=(nworld, mjm.nv), dtype=float), prev_grad=wp.empty(shape=(nworld, mjm.nv), dtype=float),
prev_Mgrad=wp.empty(shape=(nworld, mjm.nv), dtype=float), prev_Mgrad=wp.empty(shape=(nworld, mjm.nv), dtype=float),
beta=wp.empty(shape=(nworld,), dtype=float), beta=wp.empty(shape=(nworld,), dtype=float),
beta_num=wp.empty(shape=(nworld,), dtype=float),
beta_den=wp.empty(shape=(nworld,), dtype=float),
done=wp.empty(shape=(nworld,), dtype=bool), done=wp.empty(shape=(nworld,), dtype=bool),
ls_done=wp.zeros(shape=(nworld,), dtype=bool), ls_done=wp.zeros(shape=(nworld,), dtype=bool),
p0=wp.empty(shape=(nworld,), dtype=wp.vec3), p0=wp.empty(shape=(nworld,), dtype=wp.vec3),
@@ -1429,6 +1486,10 @@ def put_data(
sensor_rangefinder_vec=wp.zeros((nworld, nrangefinder), dtype=wp.vec3), sensor_rangefinder_vec=wp.zeros((nworld, nrangefinder), dtype=wp.vec3),
sensor_rangefinder_dist=wp.zeros((nworld, nrangefinder), dtype=float), sensor_rangefinder_dist=wp.zeros((nworld, nrangefinder), dtype=float),
sensor_rangefinder_geomid=wp.zeros((nworld, nrangefinder), dtype=int), sensor_rangefinder_geomid=wp.zeros((nworld, nrangefinder), dtype=int),
sensor_contact_nmatch=wp.zeros((nworld, nsensorcontact), dtype=int),
sensor_contact_matchid=wp.zeros((nworld, nsensorcontact, types.MJ_MAXCONPAIR), dtype=int),
sensor_contact_criteria=wp.zeros((nworld, nsensorcontact, types.MJ_MAXCONPAIR), dtype=float),
sensor_contact_direction=wp.zeros((nworld, nsensorcontact, types.MJ_MAXCONPAIR), dtype=float),
# ray # ray
ray_bodyexclude=wp.zeros(1, dtype=int), ray_bodyexclude=wp.zeros(1, dtype=int),
ray_dist=wp.zeros((nworld, 1), dtype=float), ray_dist=wp.zeros((nworld, 1), dtype=float),
+33 -3
View File
@@ -23,10 +23,12 @@ import mujoco
import numpy as np import numpy as np
import warp as wp import warp as wp
from absl.testing import absltest from absl.testing import absltest
from absl.testing import parameterized
import mujoco_warp as mjwarp import mujoco_warp as mjwarp
from mujoco.mjx.third_party.mujoco_warp._src import test_util from mujoco.mjx.third_party.mujoco_warp._src import test_util
from mujoco.mjx.third_party.mujoco_warp._src.io import MAX_WORLDS
def _dims_match(test_obj, d1: Any, d2: Any, prefix: str = ""): def _dims_match(test_obj, d1: Any, d2: Any, prefix: str = ""):
@@ -173,7 +175,7 @@ def _leading_dims_scale_w_nworld(test_obj, d1: Any, d2: Any, nworld1: int, nworl
test_obj.assertEqual(s1, nworld1, full_name + f" has leading dim {s1} with nworld={nworld1}. {msg}") test_obj.assertEqual(s1, nworld1, full_name + f" has leading dim {s1} with nworld={nworld1}. {msg}")
class IOTest(absltest.TestCase): class IOTest(parameterized.TestCase):
def test_make_put_data(self): def test_make_put_data(self):
"""Tests that make_data and put_data are producing the same shapes for all arrays.""" """Tests that make_data and put_data are producing the same shapes for all arrays."""
mjm, _, _, d = test_util.fixture("pendula.xml") mjm, _, _, d = test_util.fixture("pendula.xml")
@@ -295,11 +297,11 @@ class IOTest(absltest.TestCase):
m1 = mjwarp.put_model(mjm) m1 = mjwarp.put_model(mjm)
self.assertTrue(hasattr(m1.geom_pos, "_is_batched")) self.assertTrue(hasattr(m1.geom_pos, "_is_batched"))
self.assertEqual(m1.geom_pos.shape[0], 1) self.assertEqual(m1.geom_pos.shape[0], MAX_WORLDS)
self.assertEqual(m1.geom_pos.strides[0], 0) self.assertEqual(m1.geom_pos.strides[0], 0)
self.assertLen(m1.geom_pos.strides, m1.geom_pos.ndim) self.assertLen(m1.geom_pos.strides, m1.geom_pos.ndim)
self.assertTrue(hasattr(m1.opt.gravity, "_is_batched")) self.assertTrue(hasattr(m1.opt.gravity, "_is_batched"))
self.assertEqual(m1.opt.gravity.shape[0], 1) self.assertEqual(m1.opt.gravity.shape[0], MAX_WORLDS)
self.assertEqual(m1.opt.gravity.strides[0], 0) self.assertEqual(m1.opt.gravity.strides[0], 0)
self.assertLen(m1.opt.gravity.strides, m1.opt.gravity.ndim) self.assertLen(m1.opt.gravity.strides, m1.opt.gravity.ndim)
self.assertFalse(hasattr(m1.body_parentid, "_is_batched")) self.assertFalse(hasattr(m1.body_parentid, "_is_batched"))
@@ -348,6 +350,34 @@ class IOTest(absltest.TestCase):
_dims_match(self, dm2, dp2) _dims_match(self, dm2, dp2)
_dims_match(self, dm3, dp3) _dims_match(self, dm3, dp3)
@parameterized.parameters(
'<contact geom1="plane"/>',
'<contact geom2="plane"/>',
'<contact site="site"/>',
'<contact reduce="maxforce"/>',
'<contact reduce="netforce"/>',
'<contact geom1="plane" geom2="sphere"/>',
)
def test_contact_sensor(self, contact_sensor):
mjm = mujoco.MjModel.from_xml_string(f"""
<mujoco>
<worldbody>
<site name="site"/>
<geom name="plane" type="plane" size="10 10 .001"/>
<body name="body">
<geom name="sphere" size=".1"/>
<joint type="slide" axis="0 0 1"/>
</body>
</worldbody>
<sensor>
{contact_sensor}
</sensor>
</mujoco>
""")
with self.assertRaises(NotImplementedError):
mjwarp.put_model(mjm)
if __name__ == "__main__": if __name__ == "__main__":
wp.init() wp.init()
+10 -10
View File
@@ -26,8 +26,8 @@ from mujoco.mjx.third_party.mujoco_warp._src.test_util import fixture
class JAXTest(parameterized.TestCase): class JAXTest(parameterized.TestCase):
@parameterized.parameters("humanoid/humanoid.xml", "pendula.xml") @parameterized.product(xml=("pendula.xml", "humanoid/humanoid.xml"), graph_conditional=(True, False))
def test_jax(self, xml): def test_jax(self, xml, graph_conditional):
os.environ["XLA_FLAGS"] = "--xla_gpu_graph_min_graph_size=1" os.environ["XLA_FLAGS"] = "--xla_gpu_graph_min_graph_size=1"
# Force JAX to allocate memory on demand and deallocate when not needed (slow) # Force JAX to allocate memory on demand and deallocate when not needed (slow)
os.environ["XLA_PYTHON_CLIENT_ALLOCATOR"] = "platform" os.environ["XLA_PYTHON_CLIENT_ALLOCATOR"] = "platform"
@@ -38,7 +38,7 @@ class JAXTest(parameterized.TestCase):
self.skipTest("JAX not installed") self.skipTest("JAX not installed")
from jax import numpy as jp from jax import numpy as jp
from warp.jax_experimental.ffi import jax_callable from mujoco.mjx.third_party.warp.jax_experimental import ffi
if jax.default_backend() != "gpu": if jax.default_backend() != "gpu":
self.skipTest("JAX default backend is not GPU") self.skipTest("JAX default backend is not GPU")
@@ -51,14 +51,12 @@ class JAXTest(parameterized.TestCase):
xml, xml,
nworld=NWORLDS, nworld=NWORLDS,
nconmax=NWORLDS * NCONTACTS, nconmax=NWORLDS * NCONTACTS,
njmax=NWORLDS * NCONTACTS * 4, njmax=NCONTACTS * 4,
iterations=1, iterations=1,
ls_iterations=4, ls_iterations=4,
kick=True, kick=True,
) )
m.opt.graph_conditional = graph_conditional
# Disable CUDA graph conditional
m.opt.graph_conditional = False
def warp_step( def warp_step(
qpos_in: wp.array(dtype=wp.float32, ndim=2), qpos_in: wp.array(dtype=wp.float32, ndim=2),
@@ -82,14 +80,16 @@ class JAXTest(parameterized.TestCase):
return qpos, qvel return qpos, qvel
warp_step_fn = jax_callable( warp_step_fn = ffi.jax_callable(
warp_step, warp_step,
num_outputs=2, num_outputs=2,
output_dims={"qpos_out": (NWORLDS, mjm.nq), "qvel_out": (NWORLDS, mjm.nv)}, output_dims={"qpos_out": (NWORLDS, mjm.nq), "qvel_out": (NWORLDS, mjm.nv)},
graph_compatible=True, graph_mode=ffi.GraphMode.WARP,
) )
jax_qpos = jp.tile(jp.array(m.qpos0.numpy()), (NWORLDS, 1)) # temp qpos0 array to get the right numpy shape
qpos0_temp = wp.array(ptr=m.qpos0.ptr, shape=(1,) + m.qpos0.shape[1:], dtype=wp.float32)
jax_qpos = jp.tile(jp.array(qpos0_temp), (NWORLDS, 1))
jax_qvel = jp.zeros((NWORLDS, m.nv)) jax_qvel = jp.zeros((NWORLDS, m.nv))
jax_unroll_fn = jax.jit(unroll).lower(jax_qpos, jax_qvel).compile() jax_unroll_fn = jax.jit(unroll).lower(jax_qpos, jax_qvel).compile()
+445 -1
View File
@@ -21,17 +21,21 @@ from mujoco.mjx.third_party.mujoco_warp._src import math
from mujoco.mjx.third_party.mujoco_warp._src import ray from mujoco.mjx.third_party.mujoco_warp._src import ray
from mujoco.mjx.third_party.mujoco_warp._src import smooth from mujoco.mjx.third_party.mujoco_warp._src import smooth
from mujoco.mjx.third_party.mujoco_warp._src import support from mujoco.mjx.third_party.mujoco_warp._src import support
from mujoco.mjx.third_party.mujoco_warp._src.collision_sdf import sdf
from mujoco.mjx.third_party.mujoco_warp._src.types import MJ_MAXCONPAIR
from mujoco.mjx.third_party.mujoco_warp._src.types import MJ_MINVAL from mujoco.mjx.third_party.mujoco_warp._src.types import MJ_MINVAL
from mujoco.mjx.third_party.mujoco_warp._src.types import ConeType from mujoco.mjx.third_party.mujoco_warp._src.types import ConeType
from mujoco.mjx.third_party.mujoco_warp._src.types import ConstraintType from mujoco.mjx.third_party.mujoco_warp._src.types import ConstraintType
from mujoco.mjx.third_party.mujoco_warp._src.types import Data from mujoco.mjx.third_party.mujoco_warp._src.types import Data
from mujoco.mjx.third_party.mujoco_warp._src.types import DataType from mujoco.mjx.third_party.mujoco_warp._src.types import DataType
from mujoco.mjx.third_party.mujoco_warp._src.types import DisableBit from mujoco.mjx.third_party.mujoco_warp._src.types import DisableBit
from mujoco.mjx.third_party.mujoco_warp._src.types import GeomType
from mujoco.mjx.third_party.mujoco_warp._src.types import JointType from mujoco.mjx.third_party.mujoco_warp._src.types import JointType
from mujoco.mjx.third_party.mujoco_warp._src.types import Model from mujoco.mjx.third_party.mujoco_warp._src.types import Model
from mujoco.mjx.third_party.mujoco_warp._src.types import ObjType from mujoco.mjx.third_party.mujoco_warp._src.types import ObjType
from mujoco.mjx.third_party.mujoco_warp._src.types import SensorType from mujoco.mjx.third_party.mujoco_warp._src.types import SensorType
from mujoco.mjx.third_party.mujoco_warp._src.types import TrnType from mujoco.mjx.third_party.mujoco_warp._src.types import TrnType
from mujoco.mjx.third_party.mujoco_warp._src.types import vec5
from mujoco.mjx.third_party.mujoco_warp._src.types import vec6 from mujoco.mjx.third_party.mujoco_warp._src.types import vec6
from mujoco.mjx.third_party.mujoco_warp._src.warp_util import cache_kernel from mujoco.mjx.third_party.mujoco_warp._src.warp_util import cache_kernel
from mujoco.mjx.third_party.mujoco_warp._src.warp_util import event_scope from mujoco.mjx.third_party.mujoco_warp._src.warp_util import event_scope
@@ -1546,6 +1550,7 @@ def _frameangacc(
@wp.kernel @wp.kernel
def _sensor_acc( def _sensor_acc(
# Model: # Model:
opt_cone: int,
body_rootid: wp.array(dtype=int), body_rootid: wp.array(dtype=int),
jnt_dofadr: wp.array(dtype=int), jnt_dofadr: wp.array(dtype=int),
geom_bodyid: wp.array(dtype=int), geom_bodyid: wp.array(dtype=int),
@@ -1555,10 +1560,15 @@ def _sensor_acc(
sensor_datatype: wp.array(dtype=int), sensor_datatype: wp.array(dtype=int),
sensor_objtype: wp.array(dtype=int), sensor_objtype: wp.array(dtype=int),
sensor_objid: wp.array(dtype=int), sensor_objid: wp.array(dtype=int),
sensor_intprm: wp.array2d(dtype=int),
sensor_dim: wp.array(dtype=int),
sensor_adr: wp.array(dtype=int), sensor_adr: wp.array(dtype=int),
sensor_cutoff: wp.array(dtype=float), sensor_cutoff: wp.array(dtype=float),
sensor_acc_adr: wp.array(dtype=int), sensor_acc_adr: wp.array(dtype=int),
sensor_contact_adr: wp.array(dtype=int),
# Data in: # Data in:
njmax_in: int,
ncon_in: wp.array(dtype=int),
xpos_in: wp.array2d(dtype=wp.vec3), xpos_in: wp.array2d(dtype=wp.vec3),
xipos_in: wp.array2d(dtype=wp.vec3), xipos_in: wp.array2d(dtype=wp.vec3),
geom_xpos_in: wp.array2d(dtype=wp.vec3), geom_xpos_in: wp.array2d(dtype=wp.vec3),
@@ -1569,8 +1579,18 @@ def _sensor_acc(
cvel_in: wp.array2d(dtype=wp.spatial_vector), cvel_in: wp.array2d(dtype=wp.spatial_vector),
actuator_force_in: wp.array2d(dtype=float), actuator_force_in: wp.array2d(dtype=float),
qfrc_actuator_in: wp.array2d(dtype=float), qfrc_actuator_in: wp.array2d(dtype=float),
contact_dist_in: wp.array(dtype=float),
contact_pos_in: wp.array(dtype=wp.vec3),
contact_frame_in: wp.array(dtype=wp.mat33),
contact_friction_in: wp.array(dtype=vec5),
contact_dim_in: wp.array(dtype=int),
contact_efc_address_in: wp.array2d(dtype=int),
efc_force_in: wp.array2d(dtype=float),
cacc_in: wp.array2d(dtype=wp.spatial_vector), cacc_in: wp.array2d(dtype=wp.spatial_vector),
cfrc_int_in: wp.array2d(dtype=wp.spatial_vector), cfrc_int_in: wp.array2d(dtype=wp.spatial_vector),
sensor_contact_nmatch_in: wp.array2d(dtype=int),
sensor_contact_matchid_in: wp.array3d(dtype=int),
sensor_contact_direction_in: wp.array3d(dtype=float),
# Data out: # Data out:
sensordata_out: wp.array2d(dtype=float), sensordata_out: wp.array2d(dtype=float),
): ):
@@ -1580,7 +1600,123 @@ def _sensor_acc(
objid = sensor_objid[sensorid] objid = sensor_objid[sensorid]
out = sensordata_out[worldid] out = sensordata_out[worldid]
if sensortype == int(SensorType.ACCELEROMETER.value): if sensortype == int(SensorType.CONTACT.value):
dataspec = sensor_intprm[sensorid, 0]
dim = sensor_dim[sensorid]
objtype = sensor_objtype[sensorid]
# found, force, torque, dist, pos, normal, tangent
# TODO(thowell): precompute slot size
found = False
force = False
torque = False
dist = False
pos = False
normal = False
tangent = False
size = int(0)
for i in range(7):
if dataspec & (1 << i):
if i == 0:
found = True
size += 1
elif i == 1:
force = True
size += 3
elif i == 2:
torque = True
size += 3
elif i == 3:
dist = True
size += 1
elif i == 4:
pos = True
size += 3
elif i == 5:
normal = True
size += 3
elif i == 6:
tangent = True
size += 3
num = dim // size # number of slots
adr = sensor_adr[sensorid]
# TODO(team): precompute sensorid to contactsensorid mapping
contactsensorid = int(0)
for i in range(sensor_contact_adr.size):
if sensorid == sensor_contact_adr[i]:
contactsensorid = i
break
nmatch = sensor_contact_nmatch_in[worldid, contactsensorid]
for i in range(wp.min(nmatch, num)):
# sorted contact id
cid = sensor_contact_matchid_in[worldid, contactsensorid, i]
# contact direction
dir = sensor_contact_direction_in[worldid, contactsensorid, i]
adr_slot = adr + i * size
if found:
out[adr_slot] = float(nmatch)
adr_slot += 1
if force or torque:
contact_forcetorque = support.contact_force_fn(
opt_cone,
njmax_in,
ncon_in,
contact_frame_in,
contact_friction_in,
contact_dim_in,
contact_efc_address_in,
efc_force_in,
worldid,
cid,
False,
)
if force:
out[adr_slot + 0] = contact_forcetorque[0]
out[adr_slot + 1] = contact_forcetorque[1]
out[adr_slot + 2] = dir * contact_forcetorque[2]
adr_slot += 3
if torque:
out[adr_slot + 0] = contact_forcetorque[3]
out[adr_slot + 1] = contact_forcetorque[4]
out[adr_slot + 2] = dir * contact_forcetorque[5]
adr_slot += 3
if dist:
out[adr_slot] = contact_dist_in[cid]
adr_slot += 1
if pos:
contact_pos = contact_pos_in[cid]
out[adr_slot + 0] = contact_pos[0]
out[adr_slot + 1] = contact_pos[1]
out[adr_slot + 2] = contact_pos[2]
adr_slot += 3
if normal:
contact_normal = contact_frame_in[cid][0]
out[adr_slot + 0] = dir * contact_normal[0]
out[adr_slot + 1] = dir * contact_normal[1]
out[adr_slot + 2] = dir * contact_normal[2]
adr_slot += 3
if tangent:
contact_tangent = contact_frame_in[cid][1]
out[adr_slot + 0] = dir * contact_tangent[0]
out[adr_slot + 1] = dir * contact_tangent[1]
out[adr_slot + 2] = dir * contact_tangent[2]
adr_slot += 3
# zero remaining slots
for i in range(nmatch, num):
for j in range(size):
out[adr + i * size + j] = 0.0
elif sensortype == int(SensorType.ACCELEROMETER.value):
vec3 = _accelerometer( vec3 = _accelerometer(
body_rootid, site_bodyid, site_xpos_in, site_xmat_in, subtree_com_in, cvel_in, cacc_in, worldid, objid body_rootid, site_bodyid, site_xpos_in, site_xmat_in, subtree_com_in, cvel_in, cacc_in, worldid, objid
) )
@@ -1726,6 +1862,210 @@ def _sensor_touch(
wp.atomic_add(sensordata_out[worldid], adr, normalforce) wp.atomic_add(sensordata_out[worldid], adr, normalforce)
@wp.kernel
def _sensor_tactile_zero(
# Model:
sensor_type: wp.array(dtype=int),
sensor_dim: wp.array(dtype=int),
sensor_adr: wp.array(dtype=int),
# Data out:
sensordata_out: wp.array2d(dtype=float),
):
worldid, sensorid = wp.tid()
if sensor_type[sensorid] != int(SensorType.TACTILE.value):
return
for i in range(sensor_dim[sensorid]):
sensordata_out[worldid, sensor_adr[sensorid] + i] = 0.0
@wp.func
def _transform_spatial(vec: wp.spatial_vector, dif: wp.vec3) -> wp.vec3:
return wp.spatial_bottom(vec) - wp.cross(dif, wp.spatial_top(vec))
@wp.kernel
def _sensor_tactile(
# Model:
body_rootid: wp.array(dtype=int),
body_weldid: wp.array(dtype=int),
geom_bodyid: wp.array(dtype=int),
mesh_vertadr: wp.array(dtype=int),
mesh_vert: wp.array(dtype=wp.vec3),
mesh_normaladr: wp.array(dtype=int),
mesh_normal: wp.array(dtype=wp.vec3),
mesh_quat: wp.array(dtype=wp.quat),
sensor_objid: wp.array(dtype=int),
sensor_refid: wp.array(dtype=int),
sensor_dim: wp.array(dtype=int),
sensor_adr: wp.array(dtype=int),
plugin: wp.array(dtype=int),
plugin_attr: wp.array(dtype=wp.vec3f),
geom_plugin_index: wp.array(dtype=int),
taxel_vertadr: wp.array(dtype=int),
taxel_sensorid: wp.array(dtype=int),
# Data in:
ncon_in: wp.array(dtype=int),
geom_xpos_in: wp.array2d(dtype=wp.vec3),
geom_xmat_in: wp.array2d(dtype=wp.mat33),
subtree_com_in: wp.array2d(dtype=wp.vec3),
cvel_in: wp.array2d(dtype=wp.spatial_vector),
contact_geom_in: wp.array(dtype=wp.vec2i),
contact_worldid_in: wp.array(dtype=int),
# Data out:
sensordata_out: wp.array2d(dtype=float),
):
conid, taxelid = wp.tid()
if conid >= ncon_in[0]:
return
worldid = contact_worldid_in[conid]
# get sensor_id
sensor_id = taxel_sensorid[taxelid]
# get parent weld id
mesh_id = sensor_objid[sensor_id]
geom_id = sensor_refid[sensor_id]
parent_body = geom_bodyid[geom_id]
parent_weld = body_weldid[parent_body]
# contact geom
body1 = body_weldid[geom_bodyid[contact_geom_in[conid][0]]]
body2 = body_weldid[geom_bodyid[contact_geom_in[conid][1]]]
if body1 == parent_weld:
geom = contact_geom_in[conid][1]
elif body2 == parent_weld:
geom = contact_geom_in[conid][0]
else:
return
body = geom_bodyid[geom]
# vertex local position
vertid = taxel_vertadr[taxelid] - mesh_vertadr[mesh_id]
pos = mesh_vert[vertid + mesh_vertadr[mesh_id]]
# position in global frame
xpos = geom_xmat_in[worldid, geom_id] @ pos
xpos += geom_xpos_in[worldid, geom_id]
# position in other geom frame
tmp = xpos - geom_xpos_in[worldid, geom]
lpos = wp.transpose(geom_xmat_in[worldid, geom]) @ tmp
# compute distance
plugin_id = geom_plugin_index[geom]
depth = wp.min(sdf(int(GeomType.SDF.value), lpos, plugin_attr[plugin_id], plugin[plugin_id]), 0.0)
if depth >= 0.0:
return
# get velocity in global
vel_sensor = _transform_spatial(cvel_in[worldid, parent_weld], xpos - subtree_com_in[worldid, body_rootid[parent_weld]])
vel_other = _transform_spatial(
cvel_in[worldid, body], geom_xpos_in[worldid, geom] - subtree_com_in[worldid, body_rootid[body]]
)
vel_rel = vel_sensor - vel_other
# get contact force/torque, rotate into node frame
offset = mesh_normaladr[mesh_id] + 3 * vertid
normal = math.rot_vec_quat(mesh_normal[offset], mesh_quat[mesh_id])
tang1 = math.rot_vec_quat(mesh_normal[offset + 1], mesh_quat[mesh_id])
tang2 = math.rot_vec_quat(mesh_normal[offset + 2], mesh_quat[mesh_id])
kMaxDepth = 0.05
pressure = depth / wp.max(kMaxDepth - depth, MJ_MINVAL)
force = wp.mul(normal, pressure)
# one row of mat^T * force
forceT = wp.vec3()
forceT[0] = wp.dot(force, normal)
forceT[1] = wp.abs(wp.dot(vel_rel, tang1))
forceT[2] = wp.abs(wp.dot(vel_rel, tang2))
# add to sensor output
dim = sensor_dim[sensor_id] / 3
wp.atomic_add(sensordata_out[worldid], sensor_adr[sensor_id] + 0 * dim + vertid, forceT[0])
wp.atomic_add(sensordata_out[worldid], sensor_adr[sensor_id] + 1 * dim + vertid, forceT[1])
wp.atomic_add(sensordata_out[worldid], sensor_adr[sensor_id] + 2 * dim + vertid, forceT[2])
@wp.kernel
def _contact_match(
# Model:
sensor_objid: wp.array(dtype=int),
sensor_refid: wp.array(dtype=int),
sensor_contact_adr: wp.array(dtype=int),
# Data in:
ncon_in: wp.array(dtype=int),
contact_dist_in: wp.array(dtype=float),
contact_geom_in: wp.array(dtype=wp.vec2i),
contact_worldid_in: wp.array(dtype=int),
# Data out:
sensor_contact_nmatch_out: wp.array2d(dtype=int),
sensor_contact_matchid_out: wp.array3d(dtype=int),
sensor_contact_criteria_out: wp.array3d(dtype=float),
sensor_contact_direction_out: wp.array3d(dtype=float),
):
contactsensorid, contactid = wp.tid()
sensorid = sensor_contact_adr[contactsensorid]
if contactid >= ncon_in[0]:
return
# sensor information
objid = sensor_objid[sensorid]
refid = sensor_refid[sensorid]
# contact information
geom = contact_geom_in[contactid]
# geom-geom match
geom0geom1 = objid == geom[0] and refid == geom[1]
geom1geom0 = objid == geom[1] and refid == geom[0]
if geom0geom1 or geom1geom0:
worldid = contact_worldid_in[contactid]
contactmatchid = wp.atomic_add(sensor_contact_nmatch_out[worldid], contactsensorid, 1)
sensor_contact_matchid_out[worldid, contactsensorid, contactmatchid] = contactid
# TODO(thowell): alternative criteria
sensor_contact_criteria_out[worldid, contactsensorid, contactmatchid] = contact_dist_in[contactid]
# contact direction
if geom1geom0:
sensor_contact_direction_out[worldid, contactsensorid, contactmatchid] = -1.0
else:
sensor_contact_direction_out[worldid, contactsensorid, contactmatchid] = 1.0
return
# TODO(thowell): alternative matching
@wp.kernel
def _contact_sort(
# Data in:
sensor_contact_nmatch_in: wp.array2d(dtype=int),
sensor_contact_matchid_in: wp.array3d(dtype=int),
sensor_contact_criteria_in: wp.array3d(dtype=float),
# Data out:
sensor_contact_matchid_out: wp.array3d(dtype=int),
):
worldid, contactsensorid = wp.tid()
nmatch = sensor_contact_nmatch_in[worldid, contactsensorid]
# skip sort
if nmatch <= 1:
return
criteria_tile = wp.tile_load(sensor_contact_criteria_in[worldid, contactsensorid], shape=MJ_MAXCONPAIR)
matchid_tile = wp.tile_load(sensor_contact_matchid_in[worldid, contactsensorid], shape=MJ_MAXCONPAIR)
wp.tile_sort(criteria_tile, matchid_tile)
wp.tile_store(sensor_contact_matchid_out[worldid, contactsensorid], matchid_tile)
@event_scope @event_scope
def sensor_acc(m: Model, d: Data): def sensor_acc(m: Model, d: Data):
"""Compute acceleration-dependent sensor values.""" """Compute acceleration-dependent sensor values."""
@@ -1772,6 +2112,94 @@ def sensor_acc(m: Model, d: Data):
], ],
) )
wp.launch(
_sensor_tactile_zero,
dim=(d.nworld, m.nsensordata),
inputs=[
m.sensor_type,
m.sensor_dim,
m.sensor_adr,
],
outputs=[
d.sensordata,
],
)
wp.launch(
_sensor_tactile,
dim=(d.nconmax, m.nsensortaxel),
inputs=[
m.body_rootid,
m.body_weldid,
m.geom_bodyid,
m.mesh_vertadr,
m.mesh_vert,
m.mesh_normaladr,
m.mesh_normal,
m.mesh_quat,
m.sensor_objid,
m.sensor_refid,
m.sensor_dim,
m.sensor_adr,
m.plugin,
m.plugin_attr,
m.geom_plugin_index,
m.taxel_vertadr,
m.taxel_sensorid,
d.ncon,
d.geom_xpos,
d.geom_xmat,
d.subtree_com,
d.cvel,
d.contact.geom,
d.contact.worldid,
],
outputs=[
d.sensordata,
],
)
if m.sensor_contact_adr.size:
# match criteria
d.sensor_contact_nmatch.zero_()
d.sensor_contact_matchid.zero_()
d.sensor_contact_criteria.zero_()
wp.launch(
_contact_match,
dim=(m.sensor_contact_adr.size, d.nconmax),
inputs=[
m.sensor_objid,
m.sensor_refid,
m.sensor_contact_adr,
d.ncon,
d.contact.dist,
d.contact.geom,
d.contact.worldid,
],
outputs=[
d.sensor_contact_nmatch,
d.sensor_contact_matchid,
d.sensor_contact_criteria,
d.sensor_contact_direction,
],
)
# sorting
wp.launch_tiled(
_contact_sort,
dim=(d.nworld, m.sensor_contact_adr.size),
inputs=[
d.sensor_contact_nmatch,
d.sensor_contact_matchid,
d.sensor_contact_criteria,
],
outputs=[
d.sensor_contact_matchid,
],
block_dim=m.block_dim.contact_sort,
)
if m.sensor_rne_postconstraint: if m.sensor_rne_postconstraint:
smooth.rne_postconstraint(m, d) smooth.rne_postconstraint(m, d)
@@ -1779,6 +2207,7 @@ def sensor_acc(m: Model, d: Data):
_sensor_acc, _sensor_acc,
dim=(d.nworld, m.sensor_acc_adr.size), dim=(d.nworld, m.sensor_acc_adr.size),
inputs=[ inputs=[
m.opt.cone,
m.body_rootid, m.body_rootid,
m.jnt_dofadr, m.jnt_dofadr,
m.geom_bodyid, m.geom_bodyid,
@@ -1788,9 +2217,14 @@ def sensor_acc(m: Model, d: Data):
m.sensor_datatype, m.sensor_datatype,
m.sensor_objtype, m.sensor_objtype,
m.sensor_objid, m.sensor_objid,
m.sensor_intprm,
m.sensor_dim,
m.sensor_adr, m.sensor_adr,
m.sensor_cutoff, m.sensor_cutoff,
m.sensor_acc_adr, m.sensor_acc_adr,
m.sensor_contact_adr,
d.njmax,
d.ncon,
d.xpos, d.xpos,
d.xipos, d.xipos,
d.geom_xpos, d.geom_xpos,
@@ -1801,8 +2235,18 @@ def sensor_acc(m: Model, d: Data):
d.cvel, d.cvel,
d.actuator_force, d.actuator_force,
d.qfrc_actuator, d.qfrc_actuator,
d.contact.dist,
d.contact.pos,
d.contact.frame,
d.contact.friction,
d.contact.dim,
d.contact.efc_address,
d.efc.force,
d.cacc, d.cacc,
d.cfrc_int, d.cfrc_int,
d.sensor_contact_nmatch,
d.sensor_contact_matchid,
d.sensor_contact_direction,
], ],
outputs=[d.sensordata], outputs=[d.sensordata],
) )
@@ -15,6 +15,8 @@
"""Tests for sensor functions.""" """Tests for sensor functions."""
import itertools
import mujoco import mujoco
import numpy as np import numpy as np
import warp as wp import warp as wp
@@ -405,6 +407,66 @@ class SensorTest(parameterized.TestCase):
_assert_eq(d.energy.numpy()[0][1], mjd.energy[1], "kinetic energy") _assert_eq(d.energy.numpy()[0][1], mjd.energy[1], "kinetic energy")
@parameterized.parameters(
'type="sphere" size=".1"',
'type="capsule" size=".1 .1" euler="0 89 89"',
'type="box" size=".1 .1 .1" euler=".02 .05 .1"',
)
def test_contact_sensor(self, geom):
"""Test contact sensor."""
# create contact sensors
contact_sensor = ""
# data combinations
field = ["found", "force", "torque", "dist", "pos", "normal", "tangent"]
datas = itertools.chain.from_iterable([itertools.combinations(field, i) for i in range(len(field))])
for num in [1, 2, 3, 4, 5]:
for geoms in [
'geom1="plane" geom2="geom"',
'geom1="geom" geom2="plane"',
'geom1="plane" geom2="sphere"',
'geom1="sphere" geom2="plane"',
'geom1="geom" geom2="sphere"',
'geom1="sphere" geom2="geom"',
]:
for data in datas:
data = " ".join(data)
contact_sensor += f'<contact {geoms} num="{num}" reduce="mindist" data="{data}"/>'
_MJCF = f"""
<mujoco>
<compiler angle="degree"/>
<option cone="pyramidal"/>
<worldbody>
<geom name="plane" type="plane" size="10 10 .001"/>
<body>
<geom name="geom" {geom}/>
<joint type="slide" axis="0 0 1"/>
</body>
<body>
<geom name="sphere" type="sphere" size=".1"/>
<joint type="slide" axis="0 0 1"/>
</body>
</worldbody>
<keyframe>
<key qpos=".09 1"/>
</keyframe>
<sensor>
{contact_sensor}
</sensor>
</mujoco>
"""
_, mjd, m, d = test_util.fixture(xml=_MJCF, keyframe=0)
d.sensordata.zero_()
mjwarp.forward(m, d)
sensordata = d.sensordata.numpy()[0]
_assert_eq(sensordata, mjd.sensordata, "sensordata")
self.assertTrue(sensordata.any()) # check that sensordata is not empty
if __name__ == "__main__": if __name__ == "__main__":
wp.init() wp.init()
+3
View File
@@ -1252,6 +1252,7 @@ def _cfrc_ext_contact(
body_rootid: wp.array(dtype=int), body_rootid: wp.array(dtype=int),
geom_bodyid: wp.array(dtype=int), geom_bodyid: wp.array(dtype=int),
# Data in: # Data in:
njmax_in: int,
ncon_in: wp.array(dtype=int), ncon_in: wp.array(dtype=int),
subtree_com_in: wp.array2d(dtype=wp.vec3), subtree_com_in: wp.array2d(dtype=wp.vec3),
contact_pos_in: wp.array(dtype=wp.vec3), contact_pos_in: wp.array(dtype=wp.vec3),
@@ -1282,6 +1283,7 @@ def _cfrc_ext_contact(
# contact force in world frame # contact force in world frame
force = support.contact_force_fn( force = support.contact_force_fn(
opt_cone, opt_cone,
njmax_in,
ncon_in, ncon_in,
contact_frame_in, contact_frame_in,
contact_friction_in, contact_friction_in,
@@ -1351,6 +1353,7 @@ def rne_postconstraint(m: Model, d: Data):
m.opt.cone, m.opt.cone,
m.body_rootid, m.body_rootid,
m.geom_bodyid, m.geom_bodyid,
d.njmax,
d.ncon, d.ncon,
d.subtree_com, d.subtree_com,
d.contact.pos, d.contact.pos,
+98 -121
View File
@@ -14,6 +14,7 @@
# ============================================================================== # ==============================================================================
from math import ceil from math import ceil
from math import sqrt
import warp as wp import warp as wp
@@ -1651,8 +1652,6 @@ def update_constraint_zero_qfrc_constraint(
@wp.kernel @wp.kernel
def update_constraint_init_qfrc_constraint( def update_constraint_init_qfrc_constraint(
# Model:
nv: int,
# Data in: # Data in:
nefc_in: wp.array(dtype=int), nefc_in: wp.array(dtype=int),
efc_J_in: wp.array3d(dtype=float), efc_J_in: wp.array3d(dtype=float),
@@ -1660,48 +1659,59 @@ def update_constraint_init_qfrc_constraint(
efc_done_in: wp.array(dtype=bool), efc_done_in: wp.array(dtype=bool),
# Data out: # Data out:
qfrc_constraint_out: wp.array2d(dtype=float), qfrc_constraint_out: wp.array2d(dtype=float),
):
worldid, efcid = wp.tid()
if efcid >= nefc_in[worldid]:
return
if efc_done_in[worldid]:
return
force = efc_force_in[worldid, efcid]
for i in range(nv):
wp.atomic_add(
qfrc_constraint_out[worldid],
i,
efc_J_in[worldid, efcid, i] * force,
)
@wp.kernel
def update_constraint_gauss_cost(
# Data in:
qacc_in: wp.array2d(dtype=float),
qfrc_smooth_in: wp.array2d(dtype=float),
qacc_smooth_in: wp.array2d(dtype=float),
efc_Ma_in: wp.array2d(dtype=float),
efc_done_in: wp.array(dtype=bool),
# Data out:
efc_gauss_out: wp.array(dtype=float),
efc_cost_out: wp.array(dtype=float),
): ):
worldid, dofid = wp.tid() worldid, dofid = wp.tid()
if efc_done_in[worldid]: if efc_done_in[worldid]:
return return
gauss_cost = ( sum_qfrc = float(0.0)
0.5 for efcid in range(nefc_in[worldid]):
* (efc_Ma_in[worldid, dofid] - qfrc_smooth_in[worldid, dofid]) efc_J = efc_J_in[worldid, efcid, dofid]
* (qacc_in[worldid, dofid] - qacc_smooth_in[worldid, dofid]) force = efc_force_in[worldid, efcid]
) sum_qfrc += efc_J * force
wp.atomic_add(efc_gauss_out, worldid, gauss_cost)
wp.atomic_add(efc_cost_out, worldid, gauss_cost) qfrc_constraint_out[worldid, dofid] += sum_qfrc
@cache_kernel
def update_constraint_gauss_cost(nv: int, dofs_per_thread: int):
@nested_kernel
def kernel(
# Data in:
qacc_in: wp.array2d(dtype=float),
qfrc_smooth_in: wp.array2d(dtype=float),
qacc_smooth_in: wp.array2d(dtype=float),
efc_Ma_in: wp.array2d(dtype=float),
efc_done_in: wp.array(dtype=bool),
# Data out:
efc_gauss_out: wp.array(dtype=float),
efc_cost_out: wp.array(dtype=float),
):
worldid, dofstart = wp.tid()
if efc_done_in[worldid]:
return
gauss_cost = float(0.0)
if wp.static(dofs_per_thread >= nv):
for i in range(wp.static(min(dofs_per_thread, nv))):
gauss_cost += (efc_Ma_in[worldid, i] - qfrc_smooth_in[worldid, i]) * (qacc_in[worldid, i] - qacc_smooth_in[worldid, i])
efc_gauss_out[worldid] += 0.5 * gauss_cost
efc_cost_out[worldid] += 0.5 * gauss_cost
else:
for i in range(wp.static(dofs_per_thread)):
ii = dofstart * wp.static(dofs_per_thread) + i
if ii < nv:
gauss_cost += (efc_Ma_in[worldid, ii] - qfrc_smooth_in[worldid, ii]) * (
qacc_in[worldid, ii] - qacc_smooth_in[worldid, ii]
)
wp.atomic_add(efc_gauss_out, worldid, gauss_cost)
wp.atomic_add(efc_cost_out, worldid, gauss_cost)
return kernel
def _update_constraint(m: types.Model, d: types.Data): def _update_constraint(m: types.Model, d: types.Data):
@@ -1813,15 +1823,24 @@ def _update_constraint(m: types.Model, d: types.Data):
wp.launch( wp.launch(
update_constraint_init_qfrc_constraint, update_constraint_init_qfrc_constraint,
dim=(d.nworld, d.njmax), dim=(d.nworld, m.nv),
inputs=[m.nv, d.nefc, d.efc.J, d.efc.force, d.efc.done], inputs=[d.nefc, d.efc.J, d.efc.force, d.efc.done],
outputs=[d.qfrc_constraint], outputs=[d.qfrc_constraint],
) )
# if we are only using 1 thread, it makes sense to do more dofs and skip the atomics.
# For more than 1 thread, dofs_per_thread is lower for better load balancing.
if m.nv > 50:
dofs_per_thread = 20
else:
dofs_per_thread = 50
threads_per_efc = ceil(m.nv / dofs_per_thread)
# gauss = 0.5 * (Ma - qfrc_smooth).T @ (qacc - qacc_smooth) # gauss = 0.5 * (Ma - qfrc_smooth).T @ (qacc - qacc_smooth)
wp.launch( wp.launch(
update_constraint_gauss_cost, update_constraint_gauss_cost(m.nv, dofs_per_thread),
dim=(d.nworld, m.nv), dim=(d.nworld, threads_per_efc),
inputs=[d.qacc, d.qfrc_smooth, d.qacc_smooth, d.efc.Ma, d.efc.done], inputs=[d.qacc, d.qfrc_smooth, d.qacc_smooth, d.efc.Ma, d.efc.done],
outputs=[d.efc.gauss, d.efc.cost], outputs=[d.efc.gauss, d.efc.cost],
) )
@@ -1927,16 +1946,12 @@ def update_gradient_copy_lower_triangle(
@wp.kernel @wp.kernel
def update_gradient_JTDAJ( def update_gradient_JTDAJ(
# Model:
dof_tri_row: wp.array(dtype=int),
dof_tri_col: wp.array(dtype=int),
# Data in: # Data in:
nefc_in: wp.array(dtype=int), nefc_in: wp.array(dtype=int),
efc_J_in: wp.array3d(dtype=float), efc_J_in: wp.array3d(dtype=float),
efc_D_in: wp.array2d(dtype=float), efc_D_in: wp.array2d(dtype=float),
efc_active_in: wp.array2d(dtype=bool), efc_active_in: wp.array2d(dtype=bool),
efc_done_in: wp.array(dtype=bool), efc_done_in: wp.array(dtype=bool),
# In:
# Data out: # Data out:
efc_h_out: wp.array3d(dtype=float), efc_h_out: wp.array3d(dtype=float),
): ):
@@ -1947,20 +1962,26 @@ def update_gradient_JTDAJ(
nefc = nefc_in[worldid] nefc = nefc_in[worldid]
dofi = dof_tri_row[elementid] dofi = (int(sqrt(float(1 + 8 * elementid))) - 1) // 2
dofj = dof_tri_col[elementid] dofj = elementid - (dofi * (dofi + 1)) // 2
for efcid in range(nefc):
efc_D = efc_D_in[worldid, efcid]
active = efc_active_in[worldid, efcid]
if efc_D == 0.0 or not active:
continue
sum_h = float(0.0)
efc_D = efc_D_in[worldid, 0]
active = efc_active_in[worldid, 0]
efc_Ji = efc_J_in[worldid, 0, dofi]
efc_Jj = efc_J_in[worldid, 0, dofj]
for efcid in range(nefc - 1):
# TODO(team): sparse efc_J # TODO(team): sparse efc_J
value = efc_J_in[worldid, efcid, dofi] * efc_J_in[worldid, efcid, dofj] * efc_D sum_h += efc_Ji * efc_Jj * efc_D * float(active)
if value != 0.0:
wp.atomic_add(efc_h_out[worldid, dofi], dofj, value) jj = efcid + 1
efc_D = efc_D_in[worldid, jj]
active = efc_active_in[worldid, jj]
efc_Ji = efc_J_in[worldid, jj, dofi]
efc_Jj = efc_J_in[worldid, jj, dofj]
sum_h += efc_Ji * efc_Jj * efc_D * float(active)
efc_h_out[worldid, dofi, dofj] += sum_h
@wp.kernel @wp.kernel
@@ -2184,12 +2205,12 @@ def _update_gradient(m: types.Model, d: types.Data):
outputs=[d.efc.h], outputs=[d.efc.h],
) )
lower_triangle_dim = int(m.nv * (m.nv + 1) / 2)
# TODO(team): Investigate whether d.efc.h initialization can be merged into this kernel
wp.launch( wp.launch(
update_gradient_JTDAJ, update_gradient_JTDAJ,
dim=(d.nworld, m.dof_tri_row.size), dim=(d.nworld, lower_triangle_dim),
inputs=[ inputs=[
m.dof_tri_row,
m.dof_tri_col,
d.nefc, d.nefc,
d.efc.J, d.efc.J,
d.efc.D, d.efc.D,
@@ -2295,24 +2316,9 @@ def solve_prev_grad_Mgrad(
@wp.kernel @wp.kernel
def solve_zero_beta_num_den( def solve_beta(
# Data in: # Model:
efc_done_in: wp.array(dtype=bool), nv: int,
# Data out:
efc_beta_num_out: wp.array(dtype=float),
efc_beta_den_out: wp.array(dtype=float),
):
worldid = wp.tid()
if efc_done_in[worldid]:
return
efc_beta_num_out[worldid] = 0.0
efc_beta_den_out[worldid] = 0.0
@wp.kernel
def solve_beta_num_den(
# Data in: # Data in:
efc_grad_in: wp.array2d(dtype=float), efc_grad_in: wp.array2d(dtype=float),
efc_Mgrad_in: wp.array2d(dtype=float), efc_Mgrad_in: wp.array2d(dtype=float),
@@ -2320,30 +2326,6 @@ def solve_beta_num_den(
efc_prev_Mgrad_in: wp.array2d(dtype=float), efc_prev_Mgrad_in: wp.array2d(dtype=float),
efc_done_in: wp.array(dtype=bool), efc_done_in: wp.array(dtype=bool),
# Data out: # Data out:
efc_beta_num_out: wp.array(dtype=float),
efc_beta_den_out: wp.array(dtype=float),
):
worldid, dofid = wp.tid()
if efc_done_in[worldid]:
return
prev_Mgrad = efc_prev_Mgrad_in[worldid][dofid]
wp.atomic_add(
efc_beta_num_out,
worldid,
efc_grad_in[worldid, dofid] * (efc_Mgrad_in[worldid, dofid] - prev_Mgrad),
)
wp.atomic_add(efc_beta_den_out, worldid, efc_prev_grad_in[worldid, dofid] * prev_Mgrad)
@wp.kernel
def solve_beta(
# Data in:
efc_beta_num_in: wp.array(dtype=float),
efc_beta_den_in: wp.array(dtype=float),
efc_done_in: wp.array(dtype=bool),
# Data out:
efc_beta_out: wp.array(dtype=float), efc_beta_out: wp.array(dtype=float),
): ):
worldid = wp.tid() worldid = wp.tid()
@@ -2351,7 +2333,14 @@ def solve_beta(
if efc_done_in[worldid]: if efc_done_in[worldid]:
return return
efc_beta_out[worldid] = wp.max(0.0, efc_beta_num_in[worldid] / wp.max(types.MJ_MINVAL, efc_beta_den_in[worldid])) beta_num = float(0.0)
beta_den = float(0.0)
for dofid in range(nv):
prev_Mgrad = efc_prev_Mgrad_in[worldid][dofid]
beta_num += efc_grad_in[worldid, dofid] * (efc_Mgrad_in[worldid, dofid] - prev_Mgrad)
beta_den += efc_prev_grad_in[worldid, dofid] * prev_Mgrad
efc_beta_out[worldid] = wp.max(0.0, beta_num / wp.max(types.MJ_MINVAL, beta_den))
@wp.kernel @wp.kernel
@@ -2451,24 +2440,10 @@ def _solver_iteration(
# polak-ribiere # polak-ribiere
if m.opt.solver == types.SolverType.CG: if m.opt.solver == types.SolverType.CG:
wp.launch(
solve_zero_beta_num_den,
dim=(d.nworld),
inputs=[d.efc.done],
outputs=[d.efc.beta_num, d.efc.beta_den],
)
wp.launch(
solve_beta_num_den,
dim=(d.nworld, m.nv),
inputs=[d.efc.grad, d.efc.Mgrad, d.efc.prev_grad, d.efc.prev_Mgrad, d.efc.done],
outputs=[d.efc.beta_num, d.efc.beta_den],
)
wp.launch( wp.launch(
solve_beta, solve_beta,
dim=(d.nworld,), dim=(d.nworld,),
inputs=[d.efc.beta_num, d.efc.beta_den, d.efc.done], inputs=[m.nv, d.efc.grad, d.efc.Mgrad, d.efc.prev_grad, d.efc.prev_Mgrad, d.efc.done],
outputs=[d.efc.beta], outputs=[d.efc.beta],
) )
@@ -2539,8 +2514,10 @@ def solve(m: types.Model, d: types.Data):
def _solve(m: types.Model, d: types.Data): def _solve(m: types.Model, d: types.Data):
"""Finds forces that satisfy constraints.""" """Finds forces that satisfy constraints."""
# warmstart if not (m.opt.disableflags & types.DisableBit.WARMSTART):
wp.copy(d.qacc, d.qacc_warmstart) wp.copy(d.qacc, d.qacc_warmstart)
else:
wp.copy(d.qacc, d.qacc_smooth)
# create context # create context
create_context(m, d, grad=True) create_context(m, d, grad=True)
@@ -68,6 +68,63 @@ class SolverTest(parameterized.TestCase):
_assert_eq(mjwarp_cost, mj_cost, name="cost") _assert_eq(mjwarp_cost, mj_cost, name="cost")
@parameterized.parameters(ConeType.PYRAMIDAL, ConeType.ELLIPTIC)
def test_parallel_linesearch(self, cone):
"""Test that iterative and parallel linesearch leads to equivalent results."""
# TODO(team): Enable this case when elliptic/parallel linesearch is working
if cone == ConeType.ELLIPTIC:
return
_, _, m, d = test_util.fixture(
"humanoid/humanoid.xml",
cone=cone,
ls_parallel=False,
iterations=50,
ls_iterations=50,
)
# One step to obtain more non-zeros results
mjwarp.step(m, d)
# Preparing for linesearch
m.opt.iterations = 0
mjwarp.fwd_velocity(m, d)
mjwarp.fwd_acceleration(m, d, factorize=True)
solver.solve(m, d)
# Storing some initial values
d_efc_Ma = d.efc.Ma.numpy().copy()
d_efc_Jaref = d.efc.Jaref.numpy().copy()
d_qacc = d.qacc.numpy().copy()
# Launching iterative linesearch
m.opt.ls_parallel = False
solver._linesearch(m, d)
alpha_iterative = d.efc.alpha.numpy().copy()
# Launching parallel linesearch with 10 testing points
m.nlsp = 10
d.efc.Ma = wp.array2d(d_efc_Ma)
d.efc.Jaref = wp.array(d_efc_Jaref)
d.qacc = wp.array2d(d_qacc)
m.opt.ls_parallel = True
solver._linesearch(m, d)
alpha_parallel_10 = d.efc.alpha.numpy().copy()
# Launching parallel linesearch with 50 testing points
m.nlsp = 50
d.efc.Ma = wp.array2d(d_efc_Ma)
d.efc.Jaref = wp.array(d_efc_Jaref)
d.qacc = wp.array2d(d_qacc)
solver._linesearch(m, d)
alpha_parallel_50 = d.efc.alpha.numpy().copy()
# Checking that iterative and parallel linesearch lead to similar results
# and that increasing ls_iterations leads to better results
_assert_eq(alpha_iterative, alpha_parallel_50, name="linesearch alpha")
self.assertLessEqual(abs(alpha_iterative - alpha_parallel_50), abs(alpha_iterative - alpha_parallel_10))
@parameterized.parameters( @parameterized.parameters(
(ConeType.PYRAMIDAL, SolverType.CG, 5, 5, False, False), (ConeType.PYRAMIDAL, SolverType.CG, 5, 5, False, False),
(ConeType.ELLIPTIC, SolverType.CG, 5, 5, False, False), (ConeType.ELLIPTIC, SolverType.CG, 5, 5, False, False),
+19 -4
View File
@@ -298,7 +298,9 @@ def any_different(v0: wp.vec3, v1: wp.vec3) -> wp.bool:
@wp.func @wp.func
def _decode_pyramid(pyramid: wp.array(dtype=float), efc_address: int, mu: vec5, condim: int) -> wp.spatial_vector: def _decode_pyramid(
njmax_in: int, pyramid: wp.array(dtype=float), efc_address: int, mu: vec5, condim: int
) -> wp.spatial_vector:
"""Converts pyramid representation to contact force.""" """Converts pyramid representation to contact force."""
force = wp.spatial_vector() force = wp.spatial_vector()
@@ -308,8 +310,15 @@ def _decode_pyramid(pyramid: wp.array(dtype=float), efc_address: int, mu: vec5,
force[0] = float(0.0) force[0] = float(0.0)
for i in range(condim - 1): for i in range(condim - 1):
dir1 = pyramid[2 * i + efc_address] adr = 2 * i + efc_address
dir2 = pyramid[2 * i + efc_address + 1] if adr < njmax_in:
dir1 = pyramid[adr]
else:
dir1 = 0.0
if adr + 1 < njmax_in:
dir2 = pyramid[adr + 1]
else:
dir2 = 0.0
force[0] += dir1 + dir2 force[0] += dir1 + dir2
force[i + 1] = (dir1 - dir2) * mu[i] force[i + 1] = (dir1 - dir2) * mu[i]
@@ -321,6 +330,7 @@ def contact_force_fn(
# Model: # Model:
opt_cone: int, opt_cone: int,
# Data in: # Data in:
njmax_in: int,
ncon_in: wp.array(dtype=int), ncon_in: wp.array(dtype=int),
contact_frame_in: wp.array(dtype=wp.mat33), contact_frame_in: wp.array(dtype=wp.mat33),
contact_friction_in: wp.array(dtype=vec5), contact_friction_in: wp.array(dtype=vec5),
@@ -340,6 +350,7 @@ def contact_force_fn(
if contact_id >= 0 and contact_id <= ncon_in[0] and efc_address >= 0: if contact_id >= 0 and contact_id <= ncon_in[0] and efc_address >= 0:
if opt_cone == int(ConeType.PYRAMIDAL.value): if opt_cone == int(ConeType.PYRAMIDAL.value):
force = _decode_pyramid( force = _decode_pyramid(
njmax_in,
efc_force_in[worldid], efc_force_in[worldid],
efc_address, efc_address,
contact_friction_in[contact_id], contact_friction_in[contact_id],
@@ -347,7 +358,8 @@ def contact_force_fn(
) )
else: else:
for i in range(condim): for i in range(condim):
force[i] = efc_force_in[worldid, contact_efc_address_in[contact_id, i]] if contact_efc_address_in[contact_id, i] < njmax_in:
force[i] = efc_force_in[worldid, contact_efc_address_in[contact_id, i]]
if to_world_frame: if to_world_frame:
# Transform both top and bottom parts of spatial vector by the full contact frame matrix # Transform both top and bottom parts of spatial vector by the full contact frame matrix
@@ -363,6 +375,7 @@ def contact_force_kernel(
# Model: # Model:
opt_cone: int, opt_cone: int,
# Data in: # Data in:
njmax_in: int,
ncon_in: wp.array(dtype=int), ncon_in: wp.array(dtype=int),
contact_frame_in: wp.array(dtype=wp.mat33), contact_frame_in: wp.array(dtype=wp.mat33),
contact_friction_in: wp.array(dtype=vec5), contact_friction_in: wp.array(dtype=vec5),
@@ -387,6 +400,7 @@ def contact_force_kernel(
out[tid] = contact_force_fn( out[tid] = contact_force_fn(
opt_cone, opt_cone,
njmax_in,
ncon_in, ncon_in,
contact_frame_in, contact_frame_in,
contact_friction_in, contact_friction_in,
@@ -421,6 +435,7 @@ def contact_force(
dim=(contact_ids.size,), dim=(contact_ids.size,),
inputs=[ inputs=[
m.opt.cone, m.opt.cone,
d.njmax,
d.ncon, d.ncon,
d.contact.frame, d.contact.frame,
d.contact.friction, d.contact.friction,
+88 -4
View File
@@ -15,6 +15,8 @@
"""Utilities for testing.""" """Utilities for testing."""
import importlib
import os
import time import time
from typing import Callable, Optional, Tuple from typing import Callable, Optional, Tuple
@@ -23,6 +25,7 @@ import numpy as np
import warp as wp import warp as wp
from etils import epath from etils import epath
from mujoco.mjx.third_party.mujoco_warp._src import forward
from mujoco.mjx.third_party.mujoco_warp._src import io from mujoco.mjx.third_party.mujoco_warp._src import io
from mujoco.mjx.third_party.mujoco_warp._src import warp_util from mujoco.mjx.third_party.mujoco_warp._src import warp_util
from mujoco.mjx.third_party.mujoco_warp._src.types import ConeType from mujoco.mjx.third_party.mujoco_warp._src.types import ConeType
@@ -242,26 +245,107 @@ def benchmark(
m.actuator_ctrllimited, m.actuator_ctrlrange, i, 0.01 m.actuator_ctrllimited, m.actuator_ctrlrange, i, 0.01
], ],
outputs=[d.ctrl]) # fmt: skip outputs=[d.ctrl]) # fmt: skip
wp.synchronize()
run_beg = time.perf_counter() run_beg = time.perf_counter()
wp.capture_launch(graph) wp.capture_launch(graph)
wp.synchronize() wp.synchronize()
run_end = time.perf_counter()
run_end = time.perf_counter()
time_vec[i] = run_end - run_beg time_vec[i] = run_end - run_beg
if trace: if trace:
trace = _sum(trace, tracer.trace()) trace = _sum(trace, tracer.trace())
else: else:
trace = tracer.trace() trace = tracer.trace()
if measure_alloc or measure_solver_niter:
wp.synchronize()
if measure_alloc: if measure_alloc:
ncon.append(d.ncon.numpy()[0]) ncon.append(d.ncon.numpy()[0])
nefc.append(np.sum(d.nefc.numpy())) nefc.append(np.sum(d.nefc.numpy()))
if measure_solver_niter: if measure_solver_niter:
solver_niter.append(d.solver_niter.numpy()) solver_niter.append(d.solver_niter.numpy())
wp.synchronize()
run_duration = np.sum(time_vec) run_duration = np.sum(time_vec)
return jit_duration, run_duration, trace, ncon, nefc, solver_niter return jit_duration, run_duration, trace, ncon, nefc, solver_niter
class BenchmarkSuite:
"""Base suite for all model benchmarks."""
path = ""
batch_size = -1
nconmax = -1
njmax = -1
param_names = ("function",)
params = (
"jit_duration",
"solver_niter_mean",
"solver_niter_p95",
"device_memory_allocated",
"step",
"step.forward",
"step.forward.fwd_position",
"step.forward.fwd_position.kinematics",
"step.forward.fwd_position.com_pos",
"step.forward.fwd_position.camlight",
"step.forward.fwd_position.crb",
"step.forward.fwd_position.tendon_armature",
"step.forward.fwd_position.collision",
"step.forward.fwd_position.make_constraint",
"step.forward.fwd_position.transmission",
"step.forward.sensor_pos",
"step.forward.fwd_velocity",
"step.forward.fwd_velocity.com_vel",
"step.forward.fwd_velocity.passive",
"step.forward.fwd_velocity.rne",
"step.forward.fwd_velocity.tendon_bias",
"step.forward.sensor_vel",
"step.forward.fwd_actuation",
"step.forward.fwd_acceleration",
"step.forward.fwd_acceleration.xfrc_accumulate",
"step.forward.sensor_acc",
"step.forward.solve",
)
number = 1
rounds = 1
sample_time = 0
repeat = 1
def setup_cache(self):
module = importlib.import_module(self.__module__)
path = os.path.join(os.path.realpath(os.path.dirname(module.__file__)), self.path)
mjm = mujoco.MjModel.from_xml_path(path)
mjd = mujoco.MjData(mjm)
if mjm.nkey > 0:
mujoco.mj_resetDataKeyframe(mjm, mjd, 0)
# TODO(team): mj_forward call shouldn't be necessary, but it is
mujoco.mj_forward(mjm, mjd)
wp.init()
free_before = wp.get_device().free_memory
m = io.put_model(mjm)
d = io.put_data(mjm, mjd, self.batch_size, self.nconmax, self.njmax)
jit_duration, _, trace, _, _, solver_niter = benchmark(forward.step, m, d, 1000, True, False, True)
metrics = {
"jit_duration": jit_duration,
"solver_niter_mean": np.mean(solver_niter),
"solver_niter_p95": np.quantile(solver_niter, 0.95),
"device_memory_allocated": free_before - wp.get_device().free_memory,
}
def tree_flatten(d, parent_k=""):
ret = {}
steps = self.batch_size * 1000
for k, v in d.items():
k = parent_k + "." + k if parent_k else k
ret = ret | {k: 1e6 * v[0][0] / steps} | tree_flatten(v[1], k)
return ret
metrics = metrics | tree_flatten(trace)
return metrics
def track_metric(self, metrics, fn):
return metrics[fn]
+77 -52
View File
@@ -48,6 +48,7 @@ class BlockDim:
# ray # ray
ray: int = 64 ray: int = 64
# sensor # sensor
contact_sort: int = 64
energy_vel_kinetic: int = 256 energy_vel_kinetic: int = 256
# smooth # smooth
cholesky_factorize: int = 256 cholesky_factorize: int = 256
@@ -59,6 +60,20 @@ class BlockDim:
mul_m_dense: int = 256 mul_m_dense: int = 256
class BroadphaseType(enum.IntEnum):
"""Type of broadphase algorithm.
Attributes:
NXN: Broad phase checking all pairs
SAP_TILE: Sweep and prune broad phase using tile sort
SAP_SEGMENTED: Sweep and prune broad phase using segment sort
"""
NXN = 0
SAP_TILE = 1
SAP_SEGMENTED = 2
class BroadphaseFilter(enum.IntFlag): class BroadphaseFilter(enum.IntFlag):
"""Bitmask specifying which collision functions to run during broadphase. """Bitmask specifying which collision functions to run during broadphase.
@@ -133,12 +148,13 @@ class DisableBit(enum.IntFlag):
PASSIVE = mujoco.mjtDisableBit.mjDSBL_PASSIVE PASSIVE = mujoco.mjtDisableBit.mjDSBL_PASSIVE
GRAVITY = mujoco.mjtDisableBit.mjDSBL_GRAVITY GRAVITY = mujoco.mjtDisableBit.mjDSBL_GRAVITY
CLAMPCTRL = mujoco.mjtDisableBit.mjDSBL_CLAMPCTRL CLAMPCTRL = mujoco.mjtDisableBit.mjDSBL_CLAMPCTRL
WARMSTART = mujoco.mjtDisableBit.mjDSBL_WARMSTART
ACTUATION = mujoco.mjtDisableBit.mjDSBL_ACTUATION ACTUATION = mujoco.mjtDisableBit.mjDSBL_ACTUATION
REFSAFE = mujoco.mjtDisableBit.mjDSBL_REFSAFE REFSAFE = mujoco.mjtDisableBit.mjDSBL_REFSAFE
EULERDAMP = mujoco.mjtDisableBit.mjDSBL_EULERDAMP EULERDAMP = mujoco.mjtDisableBit.mjDSBL_EULERDAMP
FILTERPARENT = mujoco.mjtDisableBit.mjDSBL_FILTERPARENT FILTERPARENT = mujoco.mjtDisableBit.mjDSBL_FILTERPARENT
SENSOR = mujoco.mjtDisableBit.mjDSBL_SENSOR SENSOR = mujoco.mjtDisableBit.mjDSBL_SENSOR
# unsupported: MIDPHASE, WARMSTART # unsupported: MIDPHASE
class EnableBit(enum.IntFlag): class EnableBit(enum.IntFlag):
@@ -371,6 +387,7 @@ class SensorType(enum.IntEnum):
SUBTREELINVEL: subtree linear velocity SUBTREELINVEL: subtree linear velocity
SUBTREEANGMOM: subtree angular momentum SUBTREEANGMOM: subtree angular momentum
TOUCH: scalar contact normal forces summed over sensor zone TOUCH: scalar contact normal forces summed over sensor zone
CONTACT: contacts which occurred during the simulation
ACCELEROMETER: accelerometer ACCELEROMETER: accelerometer
FORCE: force FORCE: force
TORQUE: torque TORQUE: torque
@@ -381,6 +398,7 @@ class SensorType(enum.IntEnum):
TENDONLIMITFRC: tendon limit force TENDONLIMITFRC: tendon limit force
FRAMELINACC: 3D linear acceleration FRAMELINACC: 3D linear acceleration
FRAMEANGACC: 3D angular acceleration FRAMEANGACC: 3D angular acceleration
TACTILE: tactile sensor
""" """
MAGNETOMETER = mujoco.mjtSensor.mjSENS_MAGNETOMETER MAGNETOMETER = mujoco.mjtSensor.mjSENS_MAGNETOMETER
@@ -414,6 +432,7 @@ class SensorType(enum.IntEnum):
SUBTREELINVEL = mujoco.mjtSensor.mjSENS_SUBTREELINVEL SUBTREELINVEL = mujoco.mjtSensor.mjSENS_SUBTREELINVEL
SUBTREEANGMOM = mujoco.mjtSensor.mjSENS_SUBTREEANGMOM SUBTREEANGMOM = mujoco.mjtSensor.mjSENS_SUBTREEANGMOM
TOUCH = mujoco.mjtSensor.mjSENS_TOUCH TOUCH = mujoco.mjtSensor.mjSENS_TOUCH
CONTACT = mujoco.mjtSensor.mjSENS_CONTACT
ACCELEROMETER = mujoco.mjtSensor.mjSENS_ACCELEROMETER ACCELEROMETER = mujoco.mjtSensor.mjSENS_ACCELEROMETER
FORCE = mujoco.mjtSensor.mjSENS_FORCE FORCE = mujoco.mjtSensor.mjSENS_FORCE
TORQUE = mujoco.mjtSensor.mjSENS_TORQUE TORQUE = mujoco.mjtSensor.mjSENS_TORQUE
@@ -424,6 +443,7 @@ class SensorType(enum.IntEnum):
TENDONLIMITFRC = mujoco.mjtSensor.mjSENS_TENDONLIMITFRC TENDONLIMITFRC = mujoco.mjtSensor.mjSENS_TENDONLIMITFRC
FRAMELINACC = mujoco.mjtSensor.mjSENS_FRAMELINACC FRAMELINACC = mujoco.mjtSensor.mjSENS_FRAMELINACC
FRAMEANGACC = mujoco.mjtSensor.mjSENS_FRAMEANGACC FRAMEANGACC = mujoco.mjtSensor.mjSENS_FRAMEANGACC
TACTILE = mujoco.mjtSensor.mjSENS_TACTILE
class ObjType(enum.IntEnum): class ObjType(enum.IntEnum):
@@ -502,20 +522,6 @@ vec10 = vec10f
vec11 = vec11f vec11 = vec11f
class BroadphaseType(enum.IntEnum):
"""Type of broadphase algorithm.
Attributes:
NXN: Broad phase checking all pairs
SAP_TILE: Sweep and prune broad phase using tile sort
SAP_SEGMENTED: Sweep and prune broad phase using segment sort
"""
NXN = 0
SAP_TILE = 1
SAP_SEGMENTED = 2
@dataclasses.dataclass @dataclasses.dataclass
class Option: class Option:
"""Physics options. """Physics options.
@@ -527,9 +533,9 @@ class Option:
ls_tolerance: CG/Newton linesearch tolerance ls_tolerance: CG/Newton linesearch tolerance
gravity: gravitational acceleration gravity: gravitational acceleration
magnetic: global magnetic flux magnetic: global magnetic flux
integrator: integration mode (mjtIntegrator) integrator: integration mode (IntegratorType)
cone: type of friction cone (mjtCone) cone: type of friction cone (ConeType)
solver: solver algorithm (mjtSolver) solver: solver algorithm (SolverType)
iterations: number of main solver iterations iterations: number of main solver iterations
ls_iterations: maximum number of CG/Newton linesearch iterations ls_iterations: maximum number of CG/Newton linesearch iterations
disableflags: bit flags for disabling standard features disableflags: bit flags for disabling standard features
@@ -542,8 +548,8 @@ class Option:
has_fluid: True if wind, density, or viscosity are non-zero at put_model time has_fluid: True if wind, density, or viscosity are non-zero at put_model time
density: density of medium density: density of medium
viscosity: viscosity of medium viscosity: viscosity of medium
broadphase: broadphase type, 0: nxn, 1: sap_tile, 2: sap_segmented broadphase: broadphase type (BroadphaseType)
broadphase_filter: broadphase filter bitflag broadphase_filter: broadphase filter bitflag (BroadphaseFilter)
graph_conditional: flag to use cuda graph conditional, should be False when JAX is used graph_conditional: flag to use cuda graph conditional, should be False when JAX is used
sdf_initpoints: number of starting points for gradient descent sdf_initpoints: number of starting points for gradient descent
sdf_iterations: max number of iterations for gradient descent sdf_iterations: max number of iterations for gradient descent
@@ -597,7 +603,7 @@ class Constraint:
"""Constraint data. """Constraint data.
Attributes: Attributes:
type: constraint type (mjtConstraint) (nworld, njmax) type: constraint type (ConstraintType) (nworld, njmax)
id: id of object of specific type (nworld, njmax) id: id of object of specific type (nworld, njmax)
J: constraint Jacobian (nworld, njmax, nv) J: constraint Jacobian (nworld, njmax, nv)
pos: constraint position (equality, contact) (nworld, njmax) pos: constraint position (equality, contact) (nworld, njmax)
@@ -628,8 +634,6 @@ class Constraint:
prev_grad: previous grad (nworld, nv) prev_grad: previous grad (nworld, nv)
prev_Mgrad: previous Mgrad (nworld, nv) prev_Mgrad: previous Mgrad (nworld, nv)
beta: polak-ribiere beta (nworld,) beta: polak-ribiere beta (nworld,)
beta_num: numerator of beta (nworld,)
beta_den: denominator of beta (nworld,)
done: solver done (nworld,) done: solver done (nworld,)
ls_done: linesearch done (nworld,) ls_done: linesearch done (nworld,)
p0: initial point (nworld, 3) p0: initial point (nworld, 3)
@@ -684,8 +688,6 @@ class Constraint:
prev_grad: wp.array2d(dtype=float) prev_grad: wp.array2d(dtype=float)
prev_Mgrad: wp.array2d(dtype=float) prev_Mgrad: wp.array2d(dtype=float)
beta: wp.array(dtype=float) beta: wp.array(dtype=float)
beta_num: wp.array(dtype=float)
beta_den: wp.array(dtype=float)
done: wp.array(dtype=bool) done: wp.array(dtype=bool)
# linesearch # linesearch
ls_done: wp.array(dtype=bool) ls_done: wp.array(dtype=bool)
@@ -752,6 +754,7 @@ class Model:
nwrap: number of wrap objects in all tendon paths nwrap: number of wrap objects in all tendon paths
nsensor: number of sensors nsensor: number of sensors
nsensordata: number of elements in sensor data vector nsensordata: number of elements in sensor data vector
nsensortaxel: number of taxels in all tactile sensors
nmeshvert: number of vertices for all meshes nmeshvert: number of vertices for all meshes
nmeshface: number of faces for all meshes nmeshface: number of faces for all meshes
nmeshgraph: number of ints in mesh auxiliary data nmeshgraph: number of ints in mesh auxiliary data
@@ -771,8 +774,6 @@ class Model:
qM_mulm_i: sparse mass matrix addressing qM_mulm_i: sparse mass matrix addressing
qM_mulm_j: sparse mass matrix addressing qM_mulm_j: sparse mass matrix addressing
qM_madr_ij: sparse mass matrix addressing qM_madr_ij: sparse mass matrix addressing
qLD_update_tree: dof tree ordering for qLD updates
qLD_update_treeadr: index of each dof tree level
M_rownnz: number of non-zeros in each row of qM (nv,) M_rownnz: number of non-zeros in each row of qM (nv,)
M_rowadr: index of each row in qM (nv,) M_rowadr: index of each row in qM (nv,)
M_colind: column indices of non-zeros in qM (nM,) M_colind: column indices of non-zeros in qM (nM,)
@@ -801,7 +802,7 @@ class Model:
body_contype: OR over all geom contypes (nbody,) body_contype: OR over all geom contypes (nbody,)
body_conaffinity: OR over all geom conaffinities (nbody,) body_conaffinity: OR over all geom conaffinities (nbody,)
body_gravcomp: antigravity force, units of body weight (nworld, nbody) body_gravcomp: antigravity force, units of body weight (nworld, nbody)
jnt_type: type of joint (mjtJoint) (njnt,) jnt_type: type of joint (JointType) (njnt,)
jnt_qposadr: start addr in 'qpos' for joint's data (njnt,) jnt_qposadr: start addr in 'qpos' for joint's data (njnt,)
jnt_dofadr: start addr in 'qvel' for joint's data (njnt,) jnt_dofadr: start addr in 'qvel' for joint's data (njnt,)
jnt_bodyid: id of joint's body (njnt,) jnt_bodyid: id of joint's body (njnt,)
@@ -830,7 +831,7 @@ class Model:
dof_solref: constraint solver reference: frictionloss (nworld, nv, NREF) dof_solref: constraint solver reference: frictionloss (nworld, nv, NREF)
dof_tri_row: np.tril_indices (mjm.nv)[0] dof_tri_row: np.tril_indices (mjm.nv)[0]
dof_tri_col: np.tril_indices (mjm.nv)[1] dof_tri_col: np.tril_indices (mjm.nv)[1]
geom_type: geometric type (mjtGeom) (ngeom,) geom_type: geometric type (GeomType) (ngeom,)
geom_contype: geom contact type (ngeom,) geom_contype: geom contact type (ngeom,)
geom_conaffinity: geom contact affinity (ngeom,) geom_conaffinity: geom contact affinity (ngeom,)
geom_condim: contact dimensionality (1, 3, 4, 6) (ngeom,) geom_condim: contact dimensionality (1, 3, 4, 6) (ngeom,)
@@ -856,11 +857,11 @@ class Model:
hfield_ncol: number of columns in grid (nhfield,) hfield_ncol: number of columns in grid (nhfield,)
hfield_size: (x, y, z_top, z_bottom) (nhfield, 4) hfield_size: (x, y, z_top, z_bottom) (nhfield, 4)
hfield_data: elevation data (nhfielddata,) hfield_data: elevation data (nhfielddata,)
site_type: geom type for rendering (mjtGeom) (nsite,) site_type: geom type for rendering (GeomType) (nsite,)
site_bodyid: id of site's body (nsite,) site_bodyid: id of site's body (nsite,)
site_pos: local position offset rel. to body (nworld, nsite, 3) site_pos: local position offset rel. to body (nworld, nsite, 3)
site_quat: local orientation offset rel. to body (nworld, nsite, 4) site_quat: local orientation offset rel. to body (nworld, nsite, 4)
cam_mode: camera tracking mode (mjtCamLight) (ncam,) cam_mode: camera tracking mode (CamLightType) (ncam,)
cam_bodyid: id of camera's body (ncam,) cam_bodyid: id of camera's body (ncam,)
cam_targetbodyid: id of targeted body; -1: none (ncam,) cam_targetbodyid: id of targeted body; -1: none (ncam,)
cam_pos: position rel. to body frame (nworld, ncam, 3) cam_pos: position rel. to body frame (nworld, ncam, 3)
@@ -872,7 +873,7 @@ class Model:
cam_resolution: resolution: pixels [width, height] (ncam, 2) cam_resolution: resolution: pixels [width, height] (ncam, 2)
cam_sensorsize: sensor size: length [width, height] (ncam, 2) cam_sensorsize: sensor size: length [width, height] (ncam, 2)
cam_intrinsic: [focal length; principal point] (ncam, 4) cam_intrinsic: [focal length; principal point] (ncam, 4)
light_mode: light tracking mode (mjtCamLight) (nlight,) light_mode: light tracking mode (CamLightType) (nlight,)
light_bodyid: id of light's body (nlight,) light_bodyid: id of light's body (nlight,)
light_targetbodyid: id of targeted body; -1: none (nlight,) light_targetbodyid: id of targeted body; -1: none (nlight,)
light_pos: position rel. to body frame (nworld, nlight, 3) light_pos: position rel. to body frame (nworld, nlight, 3)
@@ -883,10 +884,14 @@ class Model:
mesh_vertadr: first vertex address (nmesh,) mesh_vertadr: first vertex address (nmesh,)
mesh_vertnum: number of vertices (nmesh,) mesh_vertnum: number of vertices (nmesh,)
mesh_vert: vertex positions for all meshes (nmeshvert, 3) mesh_vert: vertex positions for all meshes (nmeshvert, 3)
mesh_normal: normals for all meshes (nmeshnormal, 3)
mesh_faceadr: first face address (nmesh,) mesh_faceadr: first face address (nmesh,)
mesh_face: face indices for all meshes (nface, 3) mesh_face: face indices for all meshes (nface, 3)
mesh_normaladr: first normal address (nmesh,)
mesh_normal: normals for all meshes (nmeshnormal x 3)
mesh_graphadr: graph data address; -1: no graph (nmesh,) mesh_graphadr: graph data address; -1: no graph (nmesh,)
mesh_graph: convex graph data (nmeshgraph,) mesh_graph: convex graph data (nmeshgraph,)
mesh_quat: rotation applied to asset vertices (nmesh, 4)
mesh_polynum: number of polygons per mesh (nmesh,) mesh_polynum: number of polygons per mesh (nmesh,)
mesh_polyadr: first polygon address per mesh (nmesh,) mesh_polyadr: first polygon address per mesh (nmesh,)
mesh_polynormal: all polygon normals (nmeshpoly, 3) mesh_polynormal: all polygon normals (nmeshpoly, 3)
@@ -896,10 +901,10 @@ class Model:
mesh_polymapadr: first polygon address per vertex (nmeshvert,) mesh_polymapadr: first polygon address per vertex (nmeshvert,)
mesh_polymapnum: number of polygons per vertex (nmeshvert,) mesh_polymapnum: number of polygons per vertex (nmeshvert,)
mesh_polymap: vertex to polygon map (nmeshpolymap,) mesh_polymap: vertex to polygon map (nmeshpolymap,)
eq_type: constraint type (mjtEq) (neq,) eq_type: constraint type (EqType) (neq,)
eq_obj1id: id of object 1 (neq,) eq_obj1id: id of object 1 (neq,)
eq_obj2id: id of object 2 (neq,) eq_obj2id: id of object 2 (neq,)
eq_objtype: type of both objects (mjtObj) (neq,) eq_objtype: type of both objects (ObjType) (neq,)
eq_active0: initial enable/disable constraint state (neq,) eq_active0: initial enable/disable constraint state (neq,)
eq_solref: constraint solver reference (nworld, neq, mjNREF) eq_solref: constraint solver reference (nworld, neq, mjNREF)
eq_solimp: constraint solver impedance (nworld, neq, mjNIMP) eq_solimp: constraint solver impedance (nworld, neq, mjNIMP)
@@ -911,10 +916,10 @@ class Model:
actuator_moment_tiles_nv: tiling configuration actuator_moment_tiles_nv: tiling configuration
actuator_moment_tiles_nu: tiling configuration actuator_moment_tiles_nu: tiling configuration
actuator_affine_bias_gain: affine bias/gain present actuator_affine_bias_gain: affine bias/gain present
actuator_trntype: transmission type (mjtTrn) (nu,) actuator_trntype: transmission type (TrnType) (nu,)
actuator_dyntype: dynamics type (mjtDyn) (nu,) actuator_dyntype: dynamics type (DynType) (nu,)
actuator_gaintype: gain type (mjtGain) (nu,) actuator_gaintype: gain type (GainType) (nu,)
actuator_biastype: bias type (mjtBias) (nu,) actuator_biastype: bias type (BiasType) (nu,)
actuator_trnid: transmission id: joint, tendon, site (nu, 2) actuator_trnid: transmission id: joint, tendon, site (nu, 2)
actuator_actadr: first activation address; -1: stateless (nu,) actuator_actadr: first activation address; -1: stateless (nu,)
actuator_actnum: number of activation variables (nu,) actuator_actnum: number of activation variables (nu,)
@@ -971,7 +976,7 @@ class Model:
tendon_invweight0: inv. weight in qpos0 (nworld, ntendon) tendon_invweight0: inv. weight in qpos0 (nworld, ntendon)
wrap_objid: object id: geom, site, joint (nwrap,) wrap_objid: object id: geom, site, joint (nwrap,)
wrap_prm: divisor, joint coef, or site id (nwrap,) wrap_prm: divisor, joint coef, or site id (nwrap,)
wrap_type: wrap object type (mjtWrap) (nwrap,) wrap_type: wrap object type (WrapType) (nwrap,)
tendon_jnt_adr: joint tendon address (<=nwrap,) tendon_jnt_adr: joint tendon address (<=nwrap,)
tendon_site_pair_adr: site pair tendon address (<=nwrap,) tendon_site_pair_adr: site pair tendon address (<=nwrap,)
tendon_geom_adr: geom tendon address (<=nwrap,) tendon_geom_adr: geom tendon address (<=nwrap,)
@@ -982,12 +987,13 @@ class Model:
wrap_site_pair_adr: first address for site wrap pair (<=nwrap,) wrap_site_pair_adr: first address for site wrap pair (<=nwrap,)
wrap_geom_adr: addresses for geom tendon wrap object (<=nwrap,) wrap_geom_adr: addresses for geom tendon wrap object (<=nwrap,)
wrap_pulley_scale: pulley scaling (nwrap,) wrap_pulley_scale: pulley scaling (nwrap,)
sensor_type: sensor type (mjtSensor) (nsensor,) sensor_type: sensor type (SensorType) (nsensor,)
sensor_datatype: numeric data type (mjtDataType) (nsensor,) sensor_datatype: numeric data type (DataType) (nsensor,)
sensor_objtype: type of sensorized object (mjtObj) (nsensor,) sensor_objtype: type of sensorized object (ObjType) (nsensor,)
sensor_objid: id of sensorized object (nsensor,) sensor_objid: id of sensorized object (nsensor,)
sensor_reftype: type of reference frame (mjtObj) (nsensor,) sensor_reftype: type of reference frame (ObjType) (nsensor,)
sensor_refid: id of reference frame; -1: global frame (nsensor,) sensor_refid: id of reference frame; -1: global frame (nsensor,)
sensor_intprm: sensor parameters (nsensor, mjNSENS)
sensor_dim: number of scalar outputs (nsensor,) sensor_dim: number of scalar outputs (nsensor,)
sensor_adr: address in sensor array (nsensor,) sensor_adr: address in sensor array (nsensor,)
sensor_cutoff: cutoff for real and positive; 0: ignore (nsensor,) sensor_cutoff: cutoff for real and positive; 0: ignore (nsensor,)
@@ -1007,6 +1013,7 @@ class Model:
sensor_e_kinetic: evaluate energy_vel sensor_e_kinetic: evaluate energy_vel
sensor_tendonactfrc_adr: address for tendonactfrc sensor (<=nsensor,) sensor_tendonactfrc_adr: address for tendonactfrc sensor (<=nsensor,)
sensor_subtree_vel: evaluate subtree_vel sensor_subtree_vel: evaluate subtree_vel
sensor_contact_adr: addresses for contact sensors
sensor_rne_postconstraint: evaluate rne_postconstraint sensor_rne_postconstraint: evaluate rne_postconstraint
sensor_rangefinder_bodyid: bodyid for rangefinder (nrangefinder,) sensor_rangefinder_bodyid: bodyid for rangefinder (nrangefinder,)
plugin: globally registered plugin slot number (nplugin,) plugin: globally registered plugin slot number (nplugin,)
@@ -1048,6 +1055,7 @@ class Model:
nwrap: int nwrap: int
nsensor: int nsensor: int
nsensordata: int nsensordata: int
nsensortaxel: int
nmeshvert: int nmeshvert: int
nmeshface: int nmeshface: int
nmeshgraph: int nmeshgraph: int
@@ -1193,10 +1201,13 @@ class Model:
mesh_vertadr: wp.array(dtype=int) mesh_vertadr: wp.array(dtype=int)
mesh_vertnum: wp.array(dtype=int) mesh_vertnum: wp.array(dtype=int)
mesh_vert: wp.array(dtype=wp.vec3) mesh_vert: wp.array(dtype=wp.vec3)
mesh_normaladr: wp.array(dtype=int)
mesh_normal: wp.array(dtype=wp.vec3)
mesh_faceadr: wp.array(dtype=int) mesh_faceadr: wp.array(dtype=int)
mesh_face: wp.array(dtype=wp.vec3i) mesh_face: wp.array(dtype=wp.vec3i)
mesh_graphadr: wp.array(dtype=int) mesh_graphadr: wp.array(dtype=int)
mesh_graph: wp.array(dtype=int) mesh_graph: wp.array(dtype=int)
mesh_quat: wp.array(dtype=wp.quat)
mesh_polynum: wp.array(dtype=int) mesh_polynum: wp.array(dtype=int)
mesh_polyadr: wp.array(dtype=int) mesh_polyadr: wp.array(dtype=int)
mesh_polynormal: wp.array(dtype=wp.vec3) mesh_polynormal: wp.array(dtype=wp.vec3)
@@ -1295,6 +1306,7 @@ class Model:
sensor_objid: wp.array(dtype=int) sensor_objid: wp.array(dtype=int)
sensor_reftype: wp.array(dtype=int) sensor_reftype: wp.array(dtype=int)
sensor_refid: wp.array(dtype=int) sensor_refid: wp.array(dtype=int)
sensor_intprm: wp.array2d(dtype=int)
sensor_dim: wp.array(dtype=int) sensor_dim: wp.array(dtype=int)
sensor_adr: wp.array(dtype=int) sensor_adr: wp.array(dtype=int)
sensor_cutoff: wp.array(dtype=float) sensor_cutoff: wp.array(dtype=float)
@@ -1311,6 +1323,7 @@ class Model:
sensor_e_kinetic: bool # warp only sensor_e_kinetic: bool # warp only
sensor_tendonactfrc_adr: wp.array(dtype=int) # warp only sensor_tendonactfrc_adr: wp.array(dtype=int) # warp only
sensor_subtree_vel: bool # warp only sensor_subtree_vel: bool # warp only
sensor_contact_adr: wp.array(dtype=int) # warp only
sensor_rne_postconstraint: bool # warp only sensor_rne_postconstraint: bool # warp only
sensor_rangefinder_bodyid: wp.array(dtype=int) # warp only sensor_rangefinder_bodyid: wp.array(dtype=int) # warp only
plugin: wp.array(dtype=int) plugin: wp.array(dtype=int)
@@ -1323,6 +1336,8 @@ class Model:
block_dim: BlockDim # warp only block_dim: BlockDim # warp only
geom_pair_type_count: tuple[int, ...] # warp only geom_pair_type_count: tuple[int, ...] # warp only
has_sdf_geom: bool # warp only has_sdf_geom: bool # warp only
taxel_vertadr: wp.array(dtype=int) # warp only
taxel_sensorid: wp.array(dtype=int) # warp only
@dataclasses.dataclass @dataclasses.dataclass
@@ -1365,18 +1380,19 @@ class Data:
Attributes: Attributes:
nworld: number of worlds nworld: number of worlds
nconmax: maximum number of contacts nconmax: maximum number of contacts
njmax: maximum number of constraints njmax: maximum number of constraints per world
solver_niter: number of solver iterations (nworld,) solver_niter: number of solver iterations (nworld,)
ncon: number of detected contacts ncon: number of detected contacts
ncon_world: number of detected contacts per world (nworld,)
ncon_hfield: number of contacts per geom pair with hfield (nworld, nhfieldgeompair) ncon_hfield: number of contacts per geom pair with hfield (nworld, nhfieldgeompair)
ne: number of equality constraints ne: number of equality constraints (nworld,)
ne_connect: number of equality connect constraints ne_connect: number of equality connect constraints (nworld,)
ne_weld: number of equality weld constraints ne_weld: number of equality weld constraints (nworld,)
ne_jnt: number of equality joint constraints ne_jnt: number of equality joint constraints (nworld,)
ne_ten: number of equality tendon constraints ne_ten: number of equality tendon constraints (nworld,)
nf: number of friction constraints nf: number of friction constraints (nworld,)
nl: number of limit constraints nl: number of limit constraints (nworld,)
nefc: number of constraints (1,) nefc: number of constraints (nworld,)
nsolving: number of unconverged worlds (1,) nsolving: number of unconverged worlds (1,)
time: simulation time (nworld,) time: simulation time (nworld,)
energy: potential, kinetic energy (nworld, 2) energy: potential, kinetic energy (nworld, 2)
@@ -1498,6 +1514,10 @@ class Data:
sensor_rangefinder_vec: directions for rangefinder (nworld, nrangefinder, 3) sensor_rangefinder_vec: directions for rangefinder (nworld, nrangefinder, 3)
sensor_rangefinder_dist: distances for rangefinder (nworld, nrangefinder) sensor_rangefinder_dist: distances for rangefinder (nworld, nrangefinder)
sensor_rangefinder_geomid: geomids for rangefinder (nworld, nrangefinder) sensor_rangefinder_geomid: geomids for rangefinder (nworld, nrangefinder)
sensor_contact_nmatch: match count for each world-sensor (nworld, <=nsensor)
sensor_contact_matchid: id for matching contact (nworld, <=nsensor, MJ_MAXCONPAIR)
sensor_contact_criteria: critera for reduction (nworld, <=nsensor, MJ_MAXCONPAIR)
sensor_contact_direction: direction of contact (nworld, <=nsensor, MJ_MAXCONPAIR)
ray_bodyexclude: id of body to exclude from ray computation ray_bodyexclude: id of body to exclude from ray computation
ray_dist: ray distance to nearest geom (nworld, 1) ray_dist: ray distance to nearest geom (nworld, 1)
ray_geomid: id of geom that intersects with ray (nworld, 1) ray_geomid: id of geom that intersects with ray (nworld, 1)
@@ -1510,6 +1530,7 @@ class Data:
njmax: int # warp only njmax: int # warp only
solver_niter: wp.array(dtype=int) solver_niter: wp.array(dtype=int)
ncon: wp.array(dtype=int) ncon: wp.array(dtype=int)
ncon_world: wp.array(dtype=int) # warp only
ncon_hfield: wp.array2d(dtype=int) # warp only ncon_hfield: wp.array2d(dtype=int) # warp only
ne: wp.array(dtype=int) ne: wp.array(dtype=int)
ne_connect: wp.array(dtype=int) # warp only ne_connect: wp.array(dtype=int) # warp only
@@ -1653,6 +1674,10 @@ class Data:
sensor_rangefinder_vec: wp.array2d(dtype=wp.vec3) # warp only sensor_rangefinder_vec: wp.array2d(dtype=wp.vec3) # warp only
sensor_rangefinder_dist: wp.array2d(dtype=float) # warp only sensor_rangefinder_dist: wp.array2d(dtype=float) # warp only
sensor_rangefinder_geomid: wp.array2d(dtype=int) # warp only sensor_rangefinder_geomid: wp.array2d(dtype=int) # warp only
sensor_contact_nmatch: wp.array2d(dtype=int) # warp only
sensor_contact_matchid: wp.array3d(dtype=int) # warp only
sensor_contact_criteria: wp.array3d(dtype=float) # warp only
sensor_contact_direction: wp.array3d(dtype=float) # warp only
# ray # ray
ray_bodyexclude: wp.array(dtype=int) # warp only ray_bodyexclude: wp.array(dtype=int) # warp only
@@ -14,6 +14,7 @@
# ============================================================================== # ==============================================================================
import functools import functools
import inspect
from typing import Callable, Optional from typing import Callable, Optional
import warp as wp import warp as wp
@@ -97,6 +98,11 @@ def event_scope(fn, name: str = ""):
global _STACK global _STACK
if _STACK is None: if _STACK is None:
return fn(*args, **kwargs) return fn(*args, **kwargs)
for frame_info in inspect.stack():
if frame_info.function in ("capture_while", "capture_if"):
return fn(*args, **kwargs)
# push into next level of stack # push into next level of stack
saved_stack, _STACK = _STACK, {} saved_stack, _STACK = _STACK, {}
beg = wp.Event(enable_timing=True) beg = wp.Event(enable_timing=True)
@@ -0,0 +1,144 @@
import warp as wp
@wp.func
def Subtraction(a: float, b: float) -> float:
return wp.max(a, -b)
@wp.func
def Intersection(a: float, b: float) -> float:
return wp.max(a, b)
@wp.func
def circle(rho: float, r: float) -> float:
return rho - r
@wp.func
def smoothUnion(a: float, b: float, k: float) -> float:
h = wp.min(wp.max(0.5 + 0.5 * (b - a) / k, 0.0), 1.0)
return b * (1.0 - h) + a * h - k * h * (1.0 - h)
@wp.func
def smoothIntersection(a: float, b: float, k: float) -> float:
return Subtraction(Intersection(a, b), smoothUnion(Subtraction(a, b), Subtraction(b, a), k))
@wp.func
def extrusion(p: wp.vec3, sdf_2d: float, h: float) -> float:
w = wp.vec2()
w[0] = sdf_2d
w[1] = wp.abs(p[2]) - h
w_abs = wp.vec2()
w_abs[0] = wp.max(w[0], 0.0)
w_abs[1] = wp.max(w[1], 0.0)
return wp.min(wp.max(w[0], w[1]), 0.0) + wp.sqrt(w_abs[0] * w_abs[0] + w_abs[1] * w_abs[1])
@wp.func
def mod(x: float, y: float) -> float:
return x - y * wp.floor(x / y)
@wp.func
def distance2D(p: wp.vec3, attributes: wp.vec3) -> float:
# see https://www.shadertoy.com/view/3lG3WR
D = 2.8
N = 25.0
psi = 3.096e-5 * N * N - 6.557e-3 * N + 0.551 # pressure angle
alpha = 0.0
innerdiameter = -1.0
R = D / 2.0
rho = wp.sqrt(p[0] * p[0] + p[1] * p[1])
Pd = N / D # Diametral Pitch: teeth per unit length of diameter
P = wp.PI / Pd # Circular Pitch
a = 1.0 / Pd # Addendum: radial length of a tooth from the pitch
# circle to the tip of the tooth.
Do = D + 2.0 * a # Outside Diameter
Ro = Do / 2.0
h = 2.2 / Pd
innerR = Ro - h - 0.14 * D
if innerdiameter >= 0.0:
innerR = innerdiameter / 2.0
# Early exit
if innerR - rho > 0.0:
return innerR - rho
# Early exit
if Ro - rho < -0.2:
return rho - Ro
Db = D * wp.cos(psi) # Base Diameter
Rb = Db / 2.0
fi = wp.atan2(p[1], p[0]) + alpha
alphaStride = P / R
invAlpha = wp.acos(Rb / R)
invPhi = wp.tan(invAlpha) - invAlpha
shift = alphaStride / 2.0 - 2.0 * invPhi
fia = mod(fi + shift / 2.0, alphaStride) - shift / 2.0
fib = mod(-fi - shift + shift / 2.0, alphaStride) - shift / 2.0
dista = -1.0e6
distb = -1.0e6
if Rb < rho:
acos_rbRho = wp.acos(Rb / rho)
thetaa = fia + acos_rbRho
thetab = fib + acos_rbRho
ta = wp.sqrt(rho * rho - Rb * Rb)
# https://math.stackexchange.com/questions/1266689/distance-from-a-point-to-the-involute-of-a-circle
dista = ta - Rb * thetaa
distb = ta - Rb * thetab
gearOuter = circle(rho, Ro)
gearLowBase = circle(rho, Ro - h)
crownBase = circle(rho, innerR)
cogs = Intersection(dista, distb)
baseWalls = Intersection(fia - (alphaStride - shift), fib - (alphaStride - shift))
cogs = Intersection(baseWalls, cogs)
cogs = smoothIntersection(gearOuter, cogs, 0.0035 * D)
cogs = smoothUnion(gearLowBase, cogs, Rb - Ro + h)
cogs = Subtraction(cogs, crownBase)
return cogs
@wp.func
def gear(p: wp.vec3, attr: wp.vec3) -> float:
thickness = 0.2
return extrusion(p, distance2D(p, attr), thickness / 2.0)
@wp.func
def gear_sdf_grad(p: wp.vec3, attr: wp.vec3) -> wp.vec3:
grad = wp.vec3()
eps = 1e-6
f_original = gear(p, attr)
x_plus = wp.vec3(p[0] + eps, p[1], p[2])
f_plus = gear(x_plus, attr)
grad[0] = (f_plus - f_original) / eps
x_plus = wp.vec3(p[0], p[1] + eps, p[2])
f_plus = gear(x_plus, attr)
grad[1] = (f_plus - f_original) / eps
x_plus = wp.vec3(p[0], p[1], p[2] + eps)
f_plus = gear(x_plus, attr)
grad[2] = (f_plus - f_original) / eps
return grad
@@ -0,0 +1,66 @@
<mujoco model="touchtest">
<compiler autolimits="true"/>
<option sdf_initpoints="20"/>
<extension>
<plugin plugin="mujoco.sdf.gear">
<instance name="gear">
<config key="alpha" value="0"/>
</instance>
</plugin>
</extension>
<asset>
<texture name="grid" type="2d" builtin="checker" rgb1=".1 .2 .3" rgb2=".2 .3 .4"
width="300" height="300" mark="edge" markrgb=".2 .3 .4"/>
<material name="grid" texture="grid" texrepeat="3 1" texuniform="true"/>
<mesh name="gear">
<plugin instance="gear"/>
</mesh>
<mesh name="sphere" builtin="wedge" params="37 37 45 45 0" scale=".3 .3 .3"/>
<mesh name="box" builtin="plate" params="37 37" scale=".3 .5 .2"/>
</asset>
<visual>
<headlight ambient=".7 .7 .7" diffuse=".2 .2 .2" specular="0.1 0.1 0.1"/>
<map znear="0.01"/>
<scale contactwidth=".02" contactheight=".5"/>
</visual>
<default>
<geom friction="0.4" solimp="0 0.95 0.02"/>
</default>
<statistic center="0 0 1" extent="1" meansize=".1"/>
<worldbody>
<light pos="1 0 .3" dir="-1 0 -.3"/>
<light pos="-1 0 .3" dir="1 0 -.3"/>
<geom name="floor" pos="0 0 -0.01" type="plane" size="3 3 .01"/>
<geom type="sdf" name="gear" mesh="gear" rgba="0.4 0.4 0.4 1" pos="-1.3 0 0">
<plugin instance="gear"/>
</geom>
<body name="ball" pos="-1 1 1">
<joint name="x" type="slide" axis="1 0 0" damping="1"/>
<joint name="y" type="slide" axis="0 1 0" damping="1"/>
<joint name="z" type="slide" axis="0 0 1"/>
<joint name="rx" axis="1 0 0" springdamper="0.2 1"/>
<joint name="ry" axis="0 1 0" springdamper="0.2 1"/>
<geom type="sphere" size=".3" mass="0.1" rgba=".5 .5 .5 .3"/>
<geom name="ball" type="mesh" mesh="sphere" mass="0" contype="0" conaffinity="0" rgba=".5 .5 .5 0"/>
</body>
<body name="finger" pos="0 0 1">
<freejoint/>
<geom type="box" size=".3 .5 .2" mass="0.1" rgba=".5 .5 .5 .3"/>
<geom name="finger" type="mesh" mesh="box" mass="0" contype="0" conaffinity="0" rgba=".5 .5 .5 0"/>
</body>
</worldbody>
<sensor>
<tactile geom="ball" mesh="sphere"/>
<tactile geom="finger" mesh="box"/>
</sensor>
</mujoco>
@@ -22,6 +22,8 @@ import warp as wp
from .bolt import bolt from .bolt import bolt
from .bolt import bolt_sdf_grad from .bolt import bolt_sdf_grad
from .gear import gear
from .gear import gear_sdf_grad
from .nut import nut from .nut import nut
from .nut import nut_sdf_grad from .nut import nut_sdf_grad
@@ -31,21 +33,25 @@ class SDFType(enum.Enum):
NUT = "NUT" NUT = "NUT"
BOLT = "BOLT" BOLT = "BOLT"
GEAR = "GEAR"
def register_sdf_plugins(collision_sdf) -> Dict[str, int]: def register_sdf_plugins(mjwarp) -> Dict[str, int]:
xml = """<mujoco> xml = """<mujoco>
<extension> <extension>
<plugin plugin="mujoco.sdf.nut"><instance name="n"/></plugin> <plugin plugin="mujoco.sdf.nut"><instance name="n"/></plugin>
<plugin plugin="mujoco.sdf.bolt"><instance name="b"/></plugin> <plugin plugin="mujoco.sdf.bolt"><instance name="b"/></plugin>
<plugin plugin="mujoco.sdf.gear"><instance name="g"/></plugin>
</extension> </extension>
<asset> <asset>
<mesh name="nm"><plugin instance="n"/></mesh> <mesh name="nm"><plugin instance="n"/></mesh>
<mesh name="bm"><plugin instance="b"/></mesh> <mesh name="bm"><plugin instance="b"/></mesh>
<mesh name="gm"><plugin instance="g"/></mesh>
</asset> </asset>
<worldbody> <worldbody>
<body><geom type="sdf" name="ng" mesh="nm"><plugin instance="n"/></geom></body> <body><geom type="sdf" name="ng" mesh="nm"><plugin instance="n"/></geom></body>
<body><geom type="sdf" name="bg" mesh="bm"><plugin instance="b"/></geom></body> <body><geom type="sdf" name="bg" mesh="bm"><plugin instance="b"/></geom></body>
<body><geom type="sdf" name="gg" mesh="gm"><plugin instance="g"/></geom></body>
</worldbody> </worldbody>
</mujoco>""" </mujoco>"""
@@ -62,6 +68,8 @@ def register_sdf_plugins(collision_sdf) -> Dict[str, int]:
sdf_types[SDFType.NUT.value] = int(m.plugin[i]) sdf_types[SDFType.NUT.value] = int(m.plugin[i])
elif name == "bg": elif name == "bg":
sdf_types[SDFType.BOLT.value] = int(m.plugin[i]) sdf_types[SDFType.BOLT.value] = int(m.plugin[i])
elif name == "gg":
sdf_types[SDFType.GEAR.value] = int(m.plugin[i])
@wp.func @wp.func
def user_sdf(p: wp.vec3, attr: wp.vec3, sdf_type: int) -> float: def user_sdf(p: wp.vec3, attr: wp.vec3, sdf_type: int) -> float:
@@ -70,6 +78,8 @@ def register_sdf_plugins(collision_sdf) -> Dict[str, int]:
result = nut(p, attr) result = nut(p, attr)
elif sdf_type == wp.static(sdf_types[SDFType.BOLT.value]): elif sdf_type == wp.static(sdf_types[SDFType.BOLT.value]):
result = bolt(p, attr) result = bolt(p, attr)
elif sdf_type == wp.static(sdf_types[SDFType.GEAR.value]):
result = gear(p, attr)
return result return result
@wp.func @wp.func
@@ -78,9 +88,11 @@ def register_sdf_plugins(collision_sdf) -> Dict[str, int]:
return nut_sdf_grad(p, attr) return nut_sdf_grad(p, attr)
elif sdf_type == wp.static(sdf_types[SDFType.BOLT.value]): elif sdf_type == wp.static(sdf_types[SDFType.BOLT.value]):
return bolt_sdf_grad(p, attr) return bolt_sdf_grad(p, attr)
elif sdf_type == wp.static(sdf_types[SDFType.GEAR.value]):
return gear_sdf_grad(p, attr)
return wp.vec3() return wp.vec3()
collision_sdf.user_sdf = user_sdf mjwarp._src.collision_sdf.user_sdf = user_sdf
collision_sdf.user_sdf_grad = user_sdf_grad mjwarp._src.collision_sdf.user_sdf_grad = user_sdf_grad
return sdf_types return sdf_types
-3
View File
@@ -42,7 +42,6 @@ _e = mjwarp.Constraint(
**{f.name: None for f in dataclasses.fields(mjwarp.Constraint) if f.init} **{f.name: None for f in dataclasses.fields(mjwarp.Constraint) if f.init}
) )
@ffi.format_args_for_warp @ffi.format_args_for_warp
def _collision_shim( def _collision_shim(
# Model # Model
@@ -489,8 +488,6 @@ def _collision_jax_impl(m: types.Model, d: types.Data):
@ffi.marshal_jax_warp_callable @ffi.marshal_jax_warp_callable
def collision(m: types.Model, d: types.Data): def collision(m: types.Model, d: types.Data):
return _collision_jax_impl(m, d) return _collision_jax_impl(m, d)
@collision.def_vmap @collision.def_vmap
@ffi.marshal_custom_vmap @ffi.marshal_custom_vmap
def collision_vmap(unused_axis_size, is_batched, m, d): def collision_vmap(unused_axis_size, is_batched, m, d):
+302 -222
View File
@@ -195,6 +195,8 @@ def _forward_shim(
mesh_faceadr: wp.array(dtype=int), mesh_faceadr: wp.array(dtype=int),
mesh_graph: wp.array(dtype=int), mesh_graph: wp.array(dtype=int),
mesh_graphadr: wp.array(dtype=int), mesh_graphadr: wp.array(dtype=int),
mesh_normal: wp.array(dtype=wp.vec3),
mesh_normaladr: wp.array(dtype=int),
mesh_polyadr: wp.array(dtype=int), mesh_polyadr: wp.array(dtype=int),
mesh_polymap: wp.array(dtype=int), mesh_polymap: wp.array(dtype=int),
mesh_polymapadr: wp.array(dtype=int), mesh_polymapadr: wp.array(dtype=int),
@@ -204,6 +206,7 @@ def _forward_shim(
mesh_polyvert: wp.array(dtype=int), mesh_polyvert: wp.array(dtype=int),
mesh_polyvertadr: wp.array(dtype=int), mesh_polyvertadr: wp.array(dtype=int),
mesh_polyvertnum: wp.array(dtype=int), mesh_polyvertnum: wp.array(dtype=int),
mesh_quat: wp.array(dtype=wp.quat),
mesh_vert: wp.array(dtype=wp.vec3), mesh_vert: wp.array(dtype=wp.vec3),
mesh_vertadr: wp.array(dtype=int), mesh_vertadr: wp.array(dtype=int),
mesh_vertnum: wp.array(dtype=int), mesh_vertnum: wp.array(dtype=int),
@@ -224,6 +227,8 @@ def _forward_shim(
nlsp: int, nlsp: int,
nmeshface: int, nmeshface: int,
nmocap: int, nmocap: int,
nsensordata: int,
nsensortaxel: int,
nsite: int, nsite: int,
ntendon: int, ntendon: int,
nu: int, nu: int,
@@ -252,10 +257,13 @@ def _forward_shim(
rangefinder_sensor_adr: wp.array(dtype=int), rangefinder_sensor_adr: wp.array(dtype=int),
sensor_acc_adr: wp.array(dtype=int), sensor_acc_adr: wp.array(dtype=int),
sensor_adr: wp.array(dtype=int), sensor_adr: wp.array(dtype=int),
sensor_contact_adr: wp.array(dtype=int),
sensor_cutoff: wp.array(dtype=float), sensor_cutoff: wp.array(dtype=float),
sensor_datatype: wp.array(dtype=int), sensor_datatype: wp.array(dtype=int),
sensor_dim: wp.array(dtype=int),
sensor_e_kinetic: bool, sensor_e_kinetic: bool,
sensor_e_potential: bool, sensor_e_potential: bool,
sensor_intprm: wp.array2d(dtype=int),
sensor_limitfrc_adr: wp.array(dtype=int), sensor_limitfrc_adr: wp.array(dtype=int),
sensor_limitpos_adr: wp.array(dtype=int), sensor_limitpos_adr: wp.array(dtype=int),
sensor_limitvel_adr: wp.array(dtype=int), sensor_limitvel_adr: wp.array(dtype=int),
@@ -278,6 +286,8 @@ def _forward_shim(
site_size: wp.array(dtype=wp.vec3), site_size: wp.array(dtype=wp.vec3),
site_type: wp.array(dtype=int), site_type: wp.array(dtype=int),
subtree_mass: wp.array2d(dtype=float), subtree_mass: wp.array2d(dtype=float),
taxel_sensorid: wp.array(dtype=int),
taxel_vertadr: wp.array(dtype=int),
tendon_actfrclimited: wp.array(dtype=bool), tendon_actfrclimited: wp.array(dtype=bool),
tendon_actfrcrange: wp.array2d(dtype=wp.vec2), tendon_actfrcrange: wp.array2d(dtype=wp.vec2),
tendon_adr: wp.array(dtype=int), tendon_adr: wp.array(dtype=int),
@@ -418,6 +428,10 @@ def _forward_shim(
sap_range: wp.array2d(dtype=int), sap_range: wp.array2d(dtype=int),
sap_segment_index: wp.array2d(dtype=int), sap_segment_index: wp.array2d(dtype=int),
sap_sort_index: wp.array3d(dtype=int), sap_sort_index: wp.array3d(dtype=int),
sensor_contact_criteria: wp.array3d(dtype=float),
sensor_contact_direction: wp.array3d(dtype=float),
sensor_contact_matchid: wp.array3d(dtype=int),
sensor_contact_nmatch: wp.array2d(dtype=int),
sensor_rangefinder_dist: wp.array2d(dtype=float), sensor_rangefinder_dist: wp.array2d(dtype=float),
sensor_rangefinder_geomid: wp.array2d(dtype=int), sensor_rangefinder_geomid: wp.array2d(dtype=int),
sensor_rangefinder_pnt: wp.array2d(dtype=wp.vec3), sensor_rangefinder_pnt: wp.array2d(dtype=wp.vec3),
@@ -471,8 +485,6 @@ def _forward_shim(
efc__alpha: wp.array(dtype=float), efc__alpha: wp.array(dtype=float),
efc__aref: wp.array2d(dtype=float), efc__aref: wp.array2d(dtype=float),
efc__beta: wp.array(dtype=float), efc__beta: wp.array(dtype=float),
efc__beta_den: wp.array(dtype=float),
efc__beta_num: wp.array(dtype=float),
efc__cholesky_L_tmp: wp.array3d(dtype=float), efc__cholesky_L_tmp: wp.array3d(dtype=float),
efc__cholesky_y_tmp: wp.array2d(dtype=float), efc__cholesky_y_tmp: wp.array2d(dtype=float),
efc__condim: wp.array2d(dtype=int), efc__condim: wp.array2d(dtype=int),
@@ -669,6 +681,8 @@ def _forward_shim(
_m.mesh_faceadr = mesh_faceadr _m.mesh_faceadr = mesh_faceadr
_m.mesh_graph = mesh_graph _m.mesh_graph = mesh_graph
_m.mesh_graphadr = mesh_graphadr _m.mesh_graphadr = mesh_graphadr
_m.mesh_normal = mesh_normal
_m.mesh_normaladr = mesh_normaladr
_m.mesh_polyadr = mesh_polyadr _m.mesh_polyadr = mesh_polyadr
_m.mesh_polymap = mesh_polymap _m.mesh_polymap = mesh_polymap
_m.mesh_polymapadr = mesh_polymapadr _m.mesh_polymapadr = mesh_polymapadr
@@ -678,6 +692,7 @@ def _forward_shim(
_m.mesh_polyvert = mesh_polyvert _m.mesh_polyvert = mesh_polyvert
_m.mesh_polyvertadr = mesh_polyvertadr _m.mesh_polyvertadr = mesh_polyvertadr
_m.mesh_polyvertnum = mesh_polyvertnum _m.mesh_polyvertnum = mesh_polyvertnum
_m.mesh_quat = mesh_quat
_m.mesh_vert = mesh_vert _m.mesh_vert = mesh_vert
_m.mesh_vertadr = mesh_vertadr _m.mesh_vertadr = mesh_vertadr
_m.mesh_vertnum = mesh_vertnum _m.mesh_vertnum = mesh_vertnum
@@ -698,6 +713,8 @@ def _forward_shim(
_m.nlsp = nlsp _m.nlsp = nlsp
_m.nmeshface = nmeshface _m.nmeshface = nmeshface
_m.nmocap = nmocap _m.nmocap = nmocap
_m.nsensordata = nsensordata
_m.nsensortaxel = nsensortaxel
_m.nsite = nsite _m.nsite = nsite
_m.ntendon = ntendon _m.ntendon = ntendon
_m.nu = nu _m.nu = nu
@@ -752,10 +769,13 @@ def _forward_shim(
_m.rangefinder_sensor_adr = rangefinder_sensor_adr _m.rangefinder_sensor_adr = rangefinder_sensor_adr
_m.sensor_acc_adr = sensor_acc_adr _m.sensor_acc_adr = sensor_acc_adr
_m.sensor_adr = sensor_adr _m.sensor_adr = sensor_adr
_m.sensor_contact_adr = sensor_contact_adr
_m.sensor_cutoff = sensor_cutoff _m.sensor_cutoff = sensor_cutoff
_m.sensor_datatype = sensor_datatype _m.sensor_datatype = sensor_datatype
_m.sensor_dim = sensor_dim
_m.sensor_e_kinetic = sensor_e_kinetic _m.sensor_e_kinetic = sensor_e_kinetic
_m.sensor_e_potential = sensor_e_potential _m.sensor_e_potential = sensor_e_potential
_m.sensor_intprm = sensor_intprm
_m.sensor_limitfrc_adr = sensor_limitfrc_adr _m.sensor_limitfrc_adr = sensor_limitfrc_adr
_m.sensor_limitpos_adr = sensor_limitpos_adr _m.sensor_limitpos_adr = sensor_limitpos_adr
_m.sensor_limitvel_adr = sensor_limitvel_adr _m.sensor_limitvel_adr = sensor_limitvel_adr
@@ -779,6 +799,8 @@ def _forward_shim(
_m.site_type = site_type _m.site_type = site_type
_m.stat.meaninertia = stat__meaninertia _m.stat.meaninertia = stat__meaninertia
_m.subtree_mass = subtree_mass _m.subtree_mass = subtree_mass
_m.taxel_sensorid = taxel_sensorid
_m.taxel_vertadr = taxel_vertadr
_m.tendon_actfrclimited = tendon_actfrclimited _m.tendon_actfrclimited = tendon_actfrclimited
_m.tendon_actfrcrange = tendon_actfrcrange _m.tendon_actfrcrange = tendon_actfrcrange
_m.tendon_adr = tendon_adr _m.tendon_adr = tendon_adr
@@ -850,8 +872,6 @@ def _forward_shim(
_d.efc.alpha = efc__alpha _d.efc.alpha = efc__alpha
_d.efc.aref = efc__aref _d.efc.aref = efc__aref
_d.efc.beta = efc__beta _d.efc.beta = efc__beta
_d.efc.beta_den = efc__beta_den
_d.efc.beta_num = efc__beta_num
_d.efc.cholesky_L_tmp = efc__cholesky_L_tmp _d.efc.cholesky_L_tmp = efc__cholesky_L_tmp
_d.efc.cholesky_y_tmp = efc__cholesky_y_tmp _d.efc.cholesky_y_tmp = efc__cholesky_y_tmp
_d.efc.condim = efc__condim _d.efc.condim = efc__condim
@@ -957,6 +977,10 @@ def _forward_shim(
_d.sap_range = sap_range _d.sap_range = sap_range
_d.sap_segment_index = sap_segment_index _d.sap_segment_index = sap_segment_index
_d.sap_sort_index = sap_sort_index _d.sap_sort_index = sap_sort_index
_d.sensor_contact_criteria = sensor_contact_criteria
_d.sensor_contact_direction = sensor_contact_direction
_d.sensor_contact_matchid = sensor_contact_matchid
_d.sensor_contact_nmatch = sensor_contact_nmatch
_d.sensor_rangefinder_dist = sensor_rangefinder_dist _d.sensor_rangefinder_dist = sensor_rangefinder_dist
_d.sensor_rangefinder_geomid = sensor_rangefinder_geomid _d.sensor_rangefinder_geomid = sensor_rangefinder_geomid
_d.sensor_rangefinder_pnt = sensor_rangefinder_pnt _d.sensor_rangefinder_pnt = sensor_rangefinder_pnt
@@ -1077,6 +1101,10 @@ def _forward_jax_impl(m: types.Model, d: types.Data):
'sap_range': d._impl.sap_range.shape, 'sap_range': d._impl.sap_range.shape,
'sap_segment_index': d._impl.sap_segment_index.shape, 'sap_segment_index': d._impl.sap_segment_index.shape,
'sap_sort_index': d._impl.sap_sort_index.shape, 'sap_sort_index': d._impl.sap_sort_index.shape,
'sensor_contact_criteria': d._impl.sensor_contact_criteria.shape,
'sensor_contact_direction': d._impl.sensor_contact_direction.shape,
'sensor_contact_matchid': d._impl.sensor_contact_matchid.shape,
'sensor_contact_nmatch': d._impl.sensor_contact_nmatch.shape,
'sensor_rangefinder_dist': d._impl.sensor_rangefinder_dist.shape, 'sensor_rangefinder_dist': d._impl.sensor_rangefinder_dist.shape,
'sensor_rangefinder_geomid': d._impl.sensor_rangefinder_geomid.shape, 'sensor_rangefinder_geomid': d._impl.sensor_rangefinder_geomid.shape,
'sensor_rangefinder_pnt': d._impl.sensor_rangefinder_pnt.shape, 'sensor_rangefinder_pnt': d._impl.sensor_rangefinder_pnt.shape,
@@ -1130,8 +1158,6 @@ def _forward_jax_impl(m: types.Model, d: types.Data):
'efc__alpha': d._impl.efc__alpha.shape, 'efc__alpha': d._impl.efc__alpha.shape,
'efc__aref': d._impl.efc__aref.shape, 'efc__aref': d._impl.efc__aref.shape,
'efc__beta': d._impl.efc__beta.shape, 'efc__beta': d._impl.efc__beta.shape,
'efc__beta_den': d._impl.efc__beta_den.shape,
'efc__beta_num': d._impl.efc__beta_num.shape,
'efc__cholesky_L_tmp': d._impl.efc__cholesky_L_tmp.shape, 'efc__cholesky_L_tmp': d._impl.efc__cholesky_L_tmp.shape,
'efc__cholesky_y_tmp': d._impl.efc__cholesky_y_tmp.shape, 'efc__cholesky_y_tmp': d._impl.efc__cholesky_y_tmp.shape,
'efc__condim': d._impl.efc__condim.shape, 'efc__condim': d._impl.efc__condim.shape,
@@ -1178,7 +1204,7 @@ def _forward_jax_impl(m: types.Model, d: types.Data):
} }
jf = ffi.jax_callable_variadic_tuple( jf = ffi.jax_callable_variadic_tuple(
_forward_shim, _forward_shim,
num_outputs=180, num_outputs=182,
output_dims=output_dims, output_dims=output_dims,
vmap_method=None, vmap_method=None,
graph_compatible=True, graph_compatible=True,
@@ -1265,6 +1291,10 @@ def _forward_jax_impl(m: types.Model, d: types.Data):
'sap_range', 'sap_range',
'sap_segment_index', 'sap_segment_index',
'sap_sort_index', 'sap_sort_index',
'sensor_contact_criteria',
'sensor_contact_direction',
'sensor_contact_matchid',
'sensor_contact_nmatch',
'sensor_rangefinder_dist', 'sensor_rangefinder_dist',
'sensor_rangefinder_geomid', 'sensor_rangefinder_geomid',
'sensor_rangefinder_pnt', 'sensor_rangefinder_pnt',
@@ -1318,8 +1348,6 @@ def _forward_jax_impl(m: types.Model, d: types.Data):
'efc__alpha', 'efc__alpha',
'efc__aref', 'efc__aref',
'efc__beta', 'efc__beta',
'efc__beta_den',
'efc__beta_num',
'efc__cholesky_L_tmp', 'efc__cholesky_L_tmp',
'efc__cholesky_y_tmp', 'efc__cholesky_y_tmp',
'efc__condim', 'efc__condim',
@@ -1515,6 +1543,8 @@ def _forward_jax_impl(m: types.Model, d: types.Data):
m.mesh_faceadr, m.mesh_faceadr,
m.mesh_graph, m.mesh_graph,
m.mesh_graphadr, m.mesh_graphadr,
m.mesh_normal,
m.mesh_normaladr,
m._impl.mesh_polyadr, m._impl.mesh_polyadr,
m._impl.mesh_polymap, m._impl.mesh_polymap,
m._impl.mesh_polymapadr, m._impl.mesh_polymapadr,
@@ -1524,6 +1554,7 @@ def _forward_jax_impl(m: types.Model, d: types.Data):
m._impl.mesh_polyvert, m._impl.mesh_polyvert,
m._impl.mesh_polyvertadr, m._impl.mesh_polyvertadr,
m._impl.mesh_polyvertnum, m._impl.mesh_polyvertnum,
m.mesh_quat,
m.mesh_vert, m.mesh_vert,
m.mesh_vertadr, m.mesh_vertadr,
m.mesh_vertnum, m.mesh_vertnum,
@@ -1544,6 +1575,8 @@ def _forward_jax_impl(m: types.Model, d: types.Data):
m._impl.nlsp, m._impl.nlsp,
m.nmeshface, m.nmeshface,
m.nmocap, m.nmocap,
m.nsensordata,
m._impl.nsensortaxel,
m.nsite, m.nsite,
m.ntendon, m.ntendon,
m.nu, m.nu,
@@ -1572,10 +1605,13 @@ def _forward_jax_impl(m: types.Model, d: types.Data):
m._impl.rangefinder_sensor_adr, m._impl.rangefinder_sensor_adr,
m._impl.sensor_acc_adr, m._impl.sensor_acc_adr,
m.sensor_adr, m.sensor_adr,
m._impl.sensor_contact_adr,
m.sensor_cutoff, m.sensor_cutoff,
m.sensor_datatype, m.sensor_datatype,
m.sensor_dim,
m._impl.sensor_e_kinetic, m._impl.sensor_e_kinetic,
m._impl.sensor_e_potential, m._impl.sensor_e_potential,
m.sensor_intprm,
m._impl.sensor_limitfrc_adr, m._impl.sensor_limitfrc_adr,
m._impl.sensor_limitpos_adr, m._impl.sensor_limitpos_adr,
m._impl.sensor_limitvel_adr, m._impl.sensor_limitvel_adr,
@@ -1598,6 +1634,8 @@ def _forward_jax_impl(m: types.Model, d: types.Data):
m.site_size, m.site_size,
m.site_type, m.site_type,
m._impl.subtree_mass, m._impl.subtree_mass,
m._impl.taxel_sensorid,
m._impl.taxel_vertadr,
m.tendon_actfrclimited, m.tendon_actfrclimited,
m.tendon_actfrcrange, m.tendon_actfrcrange,
m.tendon_adr, m.tendon_adr,
@@ -1737,6 +1775,10 @@ def _forward_jax_impl(m: types.Model, d: types.Data):
d._impl.sap_range, d._impl.sap_range,
d._impl.sap_segment_index, d._impl.sap_segment_index,
d._impl.sap_sort_index, d._impl.sap_sort_index,
d._impl.sensor_contact_criteria,
d._impl.sensor_contact_direction,
d._impl.sensor_contact_matchid,
d._impl.sensor_contact_nmatch,
d._impl.sensor_rangefinder_dist, d._impl.sensor_rangefinder_dist,
d._impl.sensor_rangefinder_geomid, d._impl.sensor_rangefinder_geomid,
d._impl.sensor_rangefinder_pnt, d._impl.sensor_rangefinder_pnt,
@@ -1790,8 +1832,6 @@ def _forward_jax_impl(m: types.Model, d: types.Data):
d._impl.efc__alpha, d._impl.efc__alpha,
d._impl.efc__aref, d._impl.efc__aref,
d._impl.efc__beta, d._impl.efc__beta,
d._impl.efc__beta_den,
d._impl.efc__beta_num,
d._impl.efc__cholesky_L_tmp, d._impl.efc__cholesky_L_tmp,
d._impl.efc__cholesky_y_tmp, d._impl.efc__cholesky_y_tmp,
d._impl.efc__condim, d._impl.efc__condim,
@@ -1919,104 +1959,106 @@ def _forward_jax_impl(m: types.Model, d: types.Data):
'_impl.sap_range': out[79], '_impl.sap_range': out[79],
'_impl.sap_segment_index': out[80], '_impl.sap_segment_index': out[80],
'_impl.sap_sort_index': out[81], '_impl.sap_sort_index': out[81],
'_impl.sensor_rangefinder_dist': out[82], '_impl.sensor_contact_criteria': out[82],
'_impl.sensor_rangefinder_geomid': out[83], '_impl.sensor_contact_direction': out[83],
'_impl.sensor_rangefinder_pnt': out[84], '_impl.sensor_contact_matchid': out[84],
'_impl.sensor_rangefinder_vec': out[85], '_impl.sensor_contact_nmatch': out[85],
'sensordata': out[86], '_impl.sensor_rangefinder_dist': out[86],
'site_xmat': out[87], '_impl.sensor_rangefinder_geomid': out[87],
'site_xpos': out[88], '_impl.sensor_rangefinder_pnt': out[88],
'_impl.solver_niter': out[89], '_impl.sensor_rangefinder_vec': out[89],
'_impl.subtree_angmom': out[90], 'sensordata': out[90],
'_impl.subtree_bodyvel': out[91], 'site_xmat': out[91],
'subtree_com': out[92], 'site_xpos': out[92],
'_impl.subtree_linvel': out[93], '_impl.solver_niter': out[93],
'_impl.ten_J': out[94], '_impl.subtree_angmom': out[94],
'_impl.ten_Jdot': out[95], '_impl.subtree_bodyvel': out[95],
'_impl.ten_actfrc': out[96], 'subtree_com': out[96],
'_impl.ten_bias_coef': out[97], '_impl.subtree_linvel': out[97],
'_impl.ten_length': out[98], '_impl.ten_J': out[98],
'_impl.ten_velocity': out[99], '_impl.ten_Jdot': out[99],
'_impl.ten_wrapadr': out[100], '_impl.ten_actfrc': out[100],
'_impl.ten_wrapnum': out[101], '_impl.ten_bias_coef': out[101],
'time': out[102], '_impl.ten_length': out[102],
'_impl.wrap_geom_xpos': out[103], '_impl.ten_velocity': out[103],
'_impl.wrap_obj': out[104], '_impl.ten_wrapadr': out[104],
'_impl.wrap_xpos': out[105], '_impl.ten_wrapnum': out[105],
'xanchor': out[106], 'time': out[106],
'xaxis': out[107], '_impl.wrap_geom_xpos': out[107],
'xfrc_applied': out[108], '_impl.wrap_obj': out[108],
'ximat': out[109], '_impl.wrap_xpos': out[109],
'xipos': out[110], 'xanchor': out[110],
'xmat': out[111], 'xaxis': out[111],
'xpos': out[112], 'xfrc_applied': out[112],
'xquat': out[113], 'ximat': out[113],
'_impl.contact__dim': out[114], 'xipos': out[114],
'_impl.contact__dist': out[115], 'xmat': out[115],
'_impl.contact__efc_address': out[116], 'xpos': out[116],
'_impl.contact__frame': out[117], 'xquat': out[117],
'_impl.contact__friction': out[118], '_impl.contact__dim': out[118],
'_impl.contact__geom': out[119], '_impl.contact__dist': out[119],
'_impl.contact__includemargin': out[120], '_impl.contact__efc_address': out[120],
'_impl.contact__pos': out[121], '_impl.contact__frame': out[121],
'_impl.contact__solimp': out[122], '_impl.contact__friction': out[122],
'_impl.contact__solref': out[123], '_impl.contact__geom': out[123],
'_impl.contact__solreffriction': out[124], '_impl.contact__includemargin': out[124],
'_impl.contact__worldid': out[125], '_impl.contact__pos': out[125],
'_impl.efc__D': out[126], '_impl.contact__solimp': out[126],
'_impl.efc__J': out[127], '_impl.contact__solref': out[127],
'_impl.efc__Jaref': out[128], '_impl.contact__solreffriction': out[128],
'_impl.efc__Ma': out[129], '_impl.contact__worldid': out[129],
'_impl.efc__Mgrad': out[130], '_impl.efc__D': out[130],
'_impl.efc__active': out[131], '_impl.efc__J': out[131],
'_impl.efc__alpha': out[132], '_impl.efc__Jaref': out[132],
'_impl.efc__aref': out[133], '_impl.efc__Ma': out[133],
'_impl.efc__beta': out[134], '_impl.efc__Mgrad': out[134],
'_impl.efc__beta_den': out[135], '_impl.efc__active': out[135],
'_impl.efc__beta_num': out[136], '_impl.efc__alpha': out[136],
'_impl.efc__cholesky_L_tmp': out[137], '_impl.efc__aref': out[137],
'_impl.efc__cholesky_y_tmp': out[138], '_impl.efc__beta': out[138],
'_impl.efc__condim': out[139], '_impl.efc__cholesky_L_tmp': out[139],
'_impl.efc__cost': out[140], '_impl.efc__cholesky_y_tmp': out[140],
'_impl.efc__cost_candidate': out[141], '_impl.efc__condim': out[141],
'_impl.efc__done': out[142], '_impl.efc__cost': out[142],
'_impl.efc__force': out[143], '_impl.efc__cost_candidate': out[143],
'_impl.efc__frictionloss': out[144], '_impl.efc__done': out[144],
'_impl.efc__gauss': out[145], '_impl.efc__force': out[145],
'_impl.efc__grad': out[146], '_impl.efc__frictionloss': out[146],
'_impl.efc__grad_dot': out[147], '_impl.efc__gauss': out[147],
'_impl.efc__gtol': out[148], '_impl.efc__grad': out[148],
'_impl.efc__h': out[149], '_impl.efc__grad_dot': out[149],
'_impl.efc__hi': out[150], '_impl.efc__gtol': out[150],
'_impl.efc__hi_alpha': out[151], '_impl.efc__h': out[151],
'_impl.efc__hi_next': out[152], '_impl.efc__hi': out[152],
'_impl.efc__hi_next_alpha': out[153], '_impl.efc__hi_alpha': out[153],
'_impl.efc__id': out[154], '_impl.efc__hi_next': out[154],
'_impl.efc__jv': out[155], '_impl.efc__hi_next_alpha': out[155],
'_impl.efc__lo': out[156], '_impl.efc__id': out[156],
'_impl.efc__lo_alpha': out[157], '_impl.efc__jv': out[157],
'_impl.efc__lo_next': out[158], '_impl.efc__lo': out[158],
'_impl.efc__lo_next_alpha': out[159], '_impl.efc__lo_alpha': out[159],
'_impl.efc__ls_done': out[160], '_impl.efc__lo_next': out[160],
'_impl.efc__margin': out[161], '_impl.efc__lo_next_alpha': out[161],
'_impl.efc__mid': out[162], '_impl.efc__ls_done': out[162],
'_impl.efc__mid_alpha': out[163], '_impl.efc__margin': out[163],
'_impl.efc__mv': out[164], '_impl.efc__mid': out[164],
'_impl.efc__p0': out[165], '_impl.efc__mid_alpha': out[165],
'_impl.efc__pos': out[166], '_impl.efc__mv': out[166],
'_impl.efc__prev_Mgrad': out[167], '_impl.efc__p0': out[167],
'_impl.efc__prev_cost': out[168], '_impl.efc__pos': out[168],
'_impl.efc__prev_grad': out[169], '_impl.efc__prev_Mgrad': out[169],
'_impl.efc__quad': out[170], '_impl.efc__prev_cost': out[170],
'_impl.efc__quad_gauss': out[171], '_impl.efc__prev_grad': out[171],
'_impl.efc__search': out[172], '_impl.efc__quad': out[172],
'_impl.efc__search_dot': out[173], '_impl.efc__quad_gauss': out[173],
'_impl.efc__type': out[174], '_impl.efc__search': out[174],
'_impl.efc__u': out[175], '_impl.efc__search_dot': out[175],
'_impl.efc__uu': out[176], '_impl.efc__type': out[176],
'_impl.efc__uv': out[177], '_impl.efc__u': out[177],
'_impl.efc__vel': out[178], '_impl.efc__uu': out[178],
'_impl.efc__vv': out[179], '_impl.efc__uv': out[179],
'_impl.efc__vel': out[180],
'_impl.efc__vv': out[181],
}) })
return d return d
@@ -2025,8 +2067,6 @@ def _forward_jax_impl(m: types.Model, d: types.Data):
@ffi.marshal_jax_warp_callable @ffi.marshal_jax_warp_callable
def forward(m: types.Model, d: types.Data): def forward(m: types.Model, d: types.Data):
return _forward_jax_impl(m, d) return _forward_jax_impl(m, d)
@forward.def_vmap @forward.def_vmap
@ffi.marshal_custom_vmap @ffi.marshal_custom_vmap
def forward_vmap(unused_axis_size, is_batched, m, d): def forward_vmap(unused_axis_size, is_batched, m, d):
@@ -2207,6 +2247,8 @@ def _step_shim(
mesh_faceadr: wp.array(dtype=int), mesh_faceadr: wp.array(dtype=int),
mesh_graph: wp.array(dtype=int), mesh_graph: wp.array(dtype=int),
mesh_graphadr: wp.array(dtype=int), mesh_graphadr: wp.array(dtype=int),
mesh_normal: wp.array(dtype=wp.vec3),
mesh_normaladr: wp.array(dtype=int),
mesh_polyadr: wp.array(dtype=int), mesh_polyadr: wp.array(dtype=int),
mesh_polymap: wp.array(dtype=int), mesh_polymap: wp.array(dtype=int),
mesh_polymapadr: wp.array(dtype=int), mesh_polymapadr: wp.array(dtype=int),
@@ -2216,6 +2258,7 @@ def _step_shim(
mesh_polyvert: wp.array(dtype=int), mesh_polyvert: wp.array(dtype=int),
mesh_polyvertadr: wp.array(dtype=int), mesh_polyvertadr: wp.array(dtype=int),
mesh_polyvertnum: wp.array(dtype=int), mesh_polyvertnum: wp.array(dtype=int),
mesh_quat: wp.array(dtype=wp.quat),
mesh_vert: wp.array(dtype=wp.vec3), mesh_vert: wp.array(dtype=wp.vec3),
mesh_vertadr: wp.array(dtype=int), mesh_vertadr: wp.array(dtype=int),
mesh_vertnum: wp.array(dtype=int), mesh_vertnum: wp.array(dtype=int),
@@ -2236,6 +2279,8 @@ def _step_shim(
nlsp: int, nlsp: int,
nmeshface: int, nmeshface: int,
nmocap: int, nmocap: int,
nsensordata: int,
nsensortaxel: int,
nsite: int, nsite: int,
ntendon: int, ntendon: int,
nu: int, nu: int,
@@ -2264,10 +2309,13 @@ def _step_shim(
rangefinder_sensor_adr: wp.array(dtype=int), rangefinder_sensor_adr: wp.array(dtype=int),
sensor_acc_adr: wp.array(dtype=int), sensor_acc_adr: wp.array(dtype=int),
sensor_adr: wp.array(dtype=int), sensor_adr: wp.array(dtype=int),
sensor_contact_adr: wp.array(dtype=int),
sensor_cutoff: wp.array(dtype=float), sensor_cutoff: wp.array(dtype=float),
sensor_datatype: wp.array(dtype=int), sensor_datatype: wp.array(dtype=int),
sensor_dim: wp.array(dtype=int),
sensor_e_kinetic: bool, sensor_e_kinetic: bool,
sensor_e_potential: bool, sensor_e_potential: bool,
sensor_intprm: wp.array2d(dtype=int),
sensor_limitfrc_adr: wp.array(dtype=int), sensor_limitfrc_adr: wp.array(dtype=int),
sensor_limitpos_adr: wp.array(dtype=int), sensor_limitpos_adr: wp.array(dtype=int),
sensor_limitvel_adr: wp.array(dtype=int), sensor_limitvel_adr: wp.array(dtype=int),
@@ -2290,6 +2338,8 @@ def _step_shim(
site_size: wp.array(dtype=wp.vec3), site_size: wp.array(dtype=wp.vec3),
site_type: wp.array(dtype=int), site_type: wp.array(dtype=int),
subtree_mass: wp.array2d(dtype=float), subtree_mass: wp.array2d(dtype=float),
taxel_sensorid: wp.array(dtype=int),
taxel_vertadr: wp.array(dtype=int),
tendon_actfrclimited: wp.array(dtype=bool), tendon_actfrclimited: wp.array(dtype=bool),
tendon_actfrcrange: wp.array2d(dtype=wp.vec2), tendon_actfrcrange: wp.array2d(dtype=wp.vec2),
tendon_adr: wp.array(dtype=int), tendon_adr: wp.array(dtype=int),
@@ -2443,6 +2493,10 @@ def _step_shim(
sap_range: wp.array2d(dtype=int), sap_range: wp.array2d(dtype=int),
sap_segment_index: wp.array2d(dtype=int), sap_segment_index: wp.array2d(dtype=int),
sap_sort_index: wp.array3d(dtype=int), sap_sort_index: wp.array3d(dtype=int),
sensor_contact_criteria: wp.array3d(dtype=float),
sensor_contact_direction: wp.array3d(dtype=float),
sensor_contact_matchid: wp.array3d(dtype=int),
sensor_contact_nmatch: wp.array2d(dtype=int),
sensor_rangefinder_dist: wp.array2d(dtype=float), sensor_rangefinder_dist: wp.array2d(dtype=float),
sensor_rangefinder_geomid: wp.array2d(dtype=int), sensor_rangefinder_geomid: wp.array2d(dtype=int),
sensor_rangefinder_pnt: wp.array2d(dtype=wp.vec3), sensor_rangefinder_pnt: wp.array2d(dtype=wp.vec3),
@@ -2496,8 +2550,6 @@ def _step_shim(
efc__alpha: wp.array(dtype=float), efc__alpha: wp.array(dtype=float),
efc__aref: wp.array2d(dtype=float), efc__aref: wp.array2d(dtype=float),
efc__beta: wp.array(dtype=float), efc__beta: wp.array(dtype=float),
efc__beta_den: wp.array(dtype=float),
efc__beta_num: wp.array(dtype=float),
efc__cholesky_L_tmp: wp.array3d(dtype=float), efc__cholesky_L_tmp: wp.array3d(dtype=float),
efc__cholesky_y_tmp: wp.array2d(dtype=float), efc__cholesky_y_tmp: wp.array2d(dtype=float),
efc__condim: wp.array2d(dtype=int), efc__condim: wp.array2d(dtype=int),
@@ -2695,6 +2747,8 @@ def _step_shim(
_m.mesh_faceadr = mesh_faceadr _m.mesh_faceadr = mesh_faceadr
_m.mesh_graph = mesh_graph _m.mesh_graph = mesh_graph
_m.mesh_graphadr = mesh_graphadr _m.mesh_graphadr = mesh_graphadr
_m.mesh_normal = mesh_normal
_m.mesh_normaladr = mesh_normaladr
_m.mesh_polyadr = mesh_polyadr _m.mesh_polyadr = mesh_polyadr
_m.mesh_polymap = mesh_polymap _m.mesh_polymap = mesh_polymap
_m.mesh_polymapadr = mesh_polymapadr _m.mesh_polymapadr = mesh_polymapadr
@@ -2704,6 +2758,7 @@ def _step_shim(
_m.mesh_polyvert = mesh_polyvert _m.mesh_polyvert = mesh_polyvert
_m.mesh_polyvertadr = mesh_polyvertadr _m.mesh_polyvertadr = mesh_polyvertadr
_m.mesh_polyvertnum = mesh_polyvertnum _m.mesh_polyvertnum = mesh_polyvertnum
_m.mesh_quat = mesh_quat
_m.mesh_vert = mesh_vert _m.mesh_vert = mesh_vert
_m.mesh_vertadr = mesh_vertadr _m.mesh_vertadr = mesh_vertadr
_m.mesh_vertnum = mesh_vertnum _m.mesh_vertnum = mesh_vertnum
@@ -2724,6 +2779,8 @@ def _step_shim(
_m.nlsp = nlsp _m.nlsp = nlsp
_m.nmeshface = nmeshface _m.nmeshface = nmeshface
_m.nmocap = nmocap _m.nmocap = nmocap
_m.nsensordata = nsensordata
_m.nsensortaxel = nsensortaxel
_m.nsite = nsite _m.nsite = nsite
_m.ntendon = ntendon _m.ntendon = ntendon
_m.nu = nu _m.nu = nu
@@ -2779,10 +2836,13 @@ def _step_shim(
_m.rangefinder_sensor_adr = rangefinder_sensor_adr _m.rangefinder_sensor_adr = rangefinder_sensor_adr
_m.sensor_acc_adr = sensor_acc_adr _m.sensor_acc_adr = sensor_acc_adr
_m.sensor_adr = sensor_adr _m.sensor_adr = sensor_adr
_m.sensor_contact_adr = sensor_contact_adr
_m.sensor_cutoff = sensor_cutoff _m.sensor_cutoff = sensor_cutoff
_m.sensor_datatype = sensor_datatype _m.sensor_datatype = sensor_datatype
_m.sensor_dim = sensor_dim
_m.sensor_e_kinetic = sensor_e_kinetic _m.sensor_e_kinetic = sensor_e_kinetic
_m.sensor_e_potential = sensor_e_potential _m.sensor_e_potential = sensor_e_potential
_m.sensor_intprm = sensor_intprm
_m.sensor_limitfrc_adr = sensor_limitfrc_adr _m.sensor_limitfrc_adr = sensor_limitfrc_adr
_m.sensor_limitpos_adr = sensor_limitpos_adr _m.sensor_limitpos_adr = sensor_limitpos_adr
_m.sensor_limitvel_adr = sensor_limitvel_adr _m.sensor_limitvel_adr = sensor_limitvel_adr
@@ -2806,6 +2866,8 @@ def _step_shim(
_m.site_type = site_type _m.site_type = site_type
_m.stat.meaninertia = stat__meaninertia _m.stat.meaninertia = stat__meaninertia
_m.subtree_mass = subtree_mass _m.subtree_mass = subtree_mass
_m.taxel_sensorid = taxel_sensorid
_m.taxel_vertadr = taxel_vertadr
_m.tendon_actfrclimited = tendon_actfrclimited _m.tendon_actfrclimited = tendon_actfrclimited
_m.tendon_actfrcrange = tendon_actfrcrange _m.tendon_actfrcrange = tendon_actfrcrange
_m.tendon_adr = tendon_adr _m.tendon_adr = tendon_adr
@@ -2879,8 +2941,6 @@ def _step_shim(
_d.efc.alpha = efc__alpha _d.efc.alpha = efc__alpha
_d.efc.aref = efc__aref _d.efc.aref = efc__aref
_d.efc.beta = efc__beta _d.efc.beta = efc__beta
_d.efc.beta_den = efc__beta_den
_d.efc.beta_num = efc__beta_num
_d.efc.cholesky_L_tmp = efc__cholesky_L_tmp _d.efc.cholesky_L_tmp = efc__cholesky_L_tmp
_d.efc.cholesky_y_tmp = efc__cholesky_y_tmp _d.efc.cholesky_y_tmp = efc__cholesky_y_tmp
_d.efc.condim = efc__condim _d.efc.condim = efc__condim
@@ -2996,6 +3056,10 @@ def _step_shim(
_d.sap_range = sap_range _d.sap_range = sap_range
_d.sap_segment_index = sap_segment_index _d.sap_segment_index = sap_segment_index
_d.sap_sort_index = sap_sort_index _d.sap_sort_index = sap_sort_index
_d.sensor_contact_criteria = sensor_contact_criteria
_d.sensor_contact_direction = sensor_contact_direction
_d.sensor_contact_matchid = sensor_contact_matchid
_d.sensor_contact_nmatch = sensor_contact_nmatch
_d.sensor_rangefinder_dist = sensor_rangefinder_dist _d.sensor_rangefinder_dist = sensor_rangefinder_dist
_d.sensor_rangefinder_geomid = sensor_rangefinder_geomid _d.sensor_rangefinder_geomid = sensor_rangefinder_geomid
_d.sensor_rangefinder_pnt = sensor_rangefinder_pnt _d.sensor_rangefinder_pnt = sensor_rangefinder_pnt
@@ -3128,6 +3192,10 @@ def _step_jax_impl(m: types.Model, d: types.Data):
'sap_range': d._impl.sap_range.shape, 'sap_range': d._impl.sap_range.shape,
'sap_segment_index': d._impl.sap_segment_index.shape, 'sap_segment_index': d._impl.sap_segment_index.shape,
'sap_sort_index': d._impl.sap_sort_index.shape, 'sap_sort_index': d._impl.sap_sort_index.shape,
'sensor_contact_criteria': d._impl.sensor_contact_criteria.shape,
'sensor_contact_direction': d._impl.sensor_contact_direction.shape,
'sensor_contact_matchid': d._impl.sensor_contact_matchid.shape,
'sensor_contact_nmatch': d._impl.sensor_contact_nmatch.shape,
'sensor_rangefinder_dist': d._impl.sensor_rangefinder_dist.shape, 'sensor_rangefinder_dist': d._impl.sensor_rangefinder_dist.shape,
'sensor_rangefinder_geomid': d._impl.sensor_rangefinder_geomid.shape, 'sensor_rangefinder_geomid': d._impl.sensor_rangefinder_geomid.shape,
'sensor_rangefinder_pnt': d._impl.sensor_rangefinder_pnt.shape, 'sensor_rangefinder_pnt': d._impl.sensor_rangefinder_pnt.shape,
@@ -3181,8 +3249,6 @@ def _step_jax_impl(m: types.Model, d: types.Data):
'efc__alpha': d._impl.efc__alpha.shape, 'efc__alpha': d._impl.efc__alpha.shape,
'efc__aref': d._impl.efc__aref.shape, 'efc__aref': d._impl.efc__aref.shape,
'efc__beta': d._impl.efc__beta.shape, 'efc__beta': d._impl.efc__beta.shape,
'efc__beta_den': d._impl.efc__beta_den.shape,
'efc__beta_num': d._impl.efc__beta_num.shape,
'efc__cholesky_L_tmp': d._impl.efc__cholesky_L_tmp.shape, 'efc__cholesky_L_tmp': d._impl.efc__cholesky_L_tmp.shape,
'efc__cholesky_y_tmp': d._impl.efc__cholesky_y_tmp.shape, 'efc__cholesky_y_tmp': d._impl.efc__cholesky_y_tmp.shape,
'efc__condim': d._impl.efc__condim.shape, 'efc__condim': d._impl.efc__condim.shape,
@@ -3229,7 +3295,7 @@ def _step_jax_impl(m: types.Model, d: types.Data):
} }
jf = ffi.jax_callable_variadic_tuple( jf = ffi.jax_callable_variadic_tuple(
_step_shim, _step_shim,
num_outputs=192, num_outputs=194,
output_dims=output_dims, output_dims=output_dims,
vmap_method=None, vmap_method=None,
graph_compatible=True, graph_compatible=True,
@@ -3328,6 +3394,10 @@ def _step_jax_impl(m: types.Model, d: types.Data):
'sap_range', 'sap_range',
'sap_segment_index', 'sap_segment_index',
'sap_sort_index', 'sap_sort_index',
'sensor_contact_criteria',
'sensor_contact_direction',
'sensor_contact_matchid',
'sensor_contact_nmatch',
'sensor_rangefinder_dist', 'sensor_rangefinder_dist',
'sensor_rangefinder_geomid', 'sensor_rangefinder_geomid',
'sensor_rangefinder_pnt', 'sensor_rangefinder_pnt',
@@ -3381,8 +3451,6 @@ def _step_jax_impl(m: types.Model, d: types.Data):
'efc__alpha', 'efc__alpha',
'efc__aref', 'efc__aref',
'efc__beta', 'efc__beta',
'efc__beta_den',
'efc__beta_num',
'efc__cholesky_L_tmp', 'efc__cholesky_L_tmp',
'efc__cholesky_y_tmp', 'efc__cholesky_y_tmp',
'efc__condim', 'efc__condim',
@@ -3579,6 +3647,8 @@ def _step_jax_impl(m: types.Model, d: types.Data):
m.mesh_faceadr, m.mesh_faceadr,
m.mesh_graph, m.mesh_graph,
m.mesh_graphadr, m.mesh_graphadr,
m.mesh_normal,
m.mesh_normaladr,
m._impl.mesh_polyadr, m._impl.mesh_polyadr,
m._impl.mesh_polymap, m._impl.mesh_polymap,
m._impl.mesh_polymapadr, m._impl.mesh_polymapadr,
@@ -3588,6 +3658,7 @@ def _step_jax_impl(m: types.Model, d: types.Data):
m._impl.mesh_polyvert, m._impl.mesh_polyvert,
m._impl.mesh_polyvertadr, m._impl.mesh_polyvertadr,
m._impl.mesh_polyvertnum, m._impl.mesh_polyvertnum,
m.mesh_quat,
m.mesh_vert, m.mesh_vert,
m.mesh_vertadr, m.mesh_vertadr,
m.mesh_vertnum, m.mesh_vertnum,
@@ -3608,6 +3679,8 @@ def _step_jax_impl(m: types.Model, d: types.Data):
m._impl.nlsp, m._impl.nlsp,
m.nmeshface, m.nmeshface,
m.nmocap, m.nmocap,
m.nsensordata,
m._impl.nsensortaxel,
m.nsite, m.nsite,
m.ntendon, m.ntendon,
m.nu, m.nu,
@@ -3636,10 +3709,13 @@ def _step_jax_impl(m: types.Model, d: types.Data):
m._impl.rangefinder_sensor_adr, m._impl.rangefinder_sensor_adr,
m._impl.sensor_acc_adr, m._impl.sensor_acc_adr,
m.sensor_adr, m.sensor_adr,
m._impl.sensor_contact_adr,
m.sensor_cutoff, m.sensor_cutoff,
m.sensor_datatype, m.sensor_datatype,
m.sensor_dim,
m._impl.sensor_e_kinetic, m._impl.sensor_e_kinetic,
m._impl.sensor_e_potential, m._impl.sensor_e_potential,
m.sensor_intprm,
m._impl.sensor_limitfrc_adr, m._impl.sensor_limitfrc_adr,
m._impl.sensor_limitpos_adr, m._impl.sensor_limitpos_adr,
m._impl.sensor_limitvel_adr, m._impl.sensor_limitvel_adr,
@@ -3662,6 +3738,8 @@ def _step_jax_impl(m: types.Model, d: types.Data):
m.site_size, m.site_size,
m.site_type, m.site_type,
m._impl.subtree_mass, m._impl.subtree_mass,
m._impl.taxel_sensorid,
m._impl.taxel_vertadr,
m.tendon_actfrclimited, m.tendon_actfrclimited,
m.tendon_actfrcrange, m.tendon_actfrcrange,
m.tendon_adr, m.tendon_adr,
@@ -3814,6 +3892,10 @@ def _step_jax_impl(m: types.Model, d: types.Data):
d._impl.sap_range, d._impl.sap_range,
d._impl.sap_segment_index, d._impl.sap_segment_index,
d._impl.sap_sort_index, d._impl.sap_sort_index,
d._impl.sensor_contact_criteria,
d._impl.sensor_contact_direction,
d._impl.sensor_contact_matchid,
d._impl.sensor_contact_nmatch,
d._impl.sensor_rangefinder_dist, d._impl.sensor_rangefinder_dist,
d._impl.sensor_rangefinder_geomid, d._impl.sensor_rangefinder_geomid,
d._impl.sensor_rangefinder_pnt, d._impl.sensor_rangefinder_pnt,
@@ -3867,8 +3949,6 @@ def _step_jax_impl(m: types.Model, d: types.Data):
d._impl.efc__alpha, d._impl.efc__alpha,
d._impl.efc__aref, d._impl.efc__aref,
d._impl.efc__beta, d._impl.efc__beta,
d._impl.efc__beta_den,
d._impl.efc__beta_num,
d._impl.efc__cholesky_L_tmp, d._impl.efc__cholesky_L_tmp,
d._impl.efc__cholesky_y_tmp, d._impl.efc__cholesky_y_tmp,
d._impl.efc__condim, d._impl.efc__condim,
@@ -4008,104 +4088,106 @@ def _step_jax_impl(m: types.Model, d: types.Data):
'_impl.sap_range': out[91], '_impl.sap_range': out[91],
'_impl.sap_segment_index': out[92], '_impl.sap_segment_index': out[92],
'_impl.sap_sort_index': out[93], '_impl.sap_sort_index': out[93],
'_impl.sensor_rangefinder_dist': out[94], '_impl.sensor_contact_criteria': out[94],
'_impl.sensor_rangefinder_geomid': out[95], '_impl.sensor_contact_direction': out[95],
'_impl.sensor_rangefinder_pnt': out[96], '_impl.sensor_contact_matchid': out[96],
'_impl.sensor_rangefinder_vec': out[97], '_impl.sensor_contact_nmatch': out[97],
'sensordata': out[98], '_impl.sensor_rangefinder_dist': out[98],
'site_xmat': out[99], '_impl.sensor_rangefinder_geomid': out[99],
'site_xpos': out[100], '_impl.sensor_rangefinder_pnt': out[100],
'_impl.solver_niter': out[101], '_impl.sensor_rangefinder_vec': out[101],
'_impl.subtree_angmom': out[102], 'sensordata': out[102],
'_impl.subtree_bodyvel': out[103], 'site_xmat': out[103],
'subtree_com': out[104], 'site_xpos': out[104],
'_impl.subtree_linvel': out[105], '_impl.solver_niter': out[105],
'_impl.ten_J': out[106], '_impl.subtree_angmom': out[106],
'_impl.ten_Jdot': out[107], '_impl.subtree_bodyvel': out[107],
'_impl.ten_actfrc': out[108], 'subtree_com': out[108],
'_impl.ten_bias_coef': out[109], '_impl.subtree_linvel': out[109],
'_impl.ten_length': out[110], '_impl.ten_J': out[110],
'_impl.ten_velocity': out[111], '_impl.ten_Jdot': out[111],
'_impl.ten_wrapadr': out[112], '_impl.ten_actfrc': out[112],
'_impl.ten_wrapnum': out[113], '_impl.ten_bias_coef': out[113],
'time': out[114], '_impl.ten_length': out[114],
'_impl.wrap_geom_xpos': out[115], '_impl.ten_velocity': out[115],
'_impl.wrap_obj': out[116], '_impl.ten_wrapadr': out[116],
'_impl.wrap_xpos': out[117], '_impl.ten_wrapnum': out[117],
'xanchor': out[118], 'time': out[118],
'xaxis': out[119], '_impl.wrap_geom_xpos': out[119],
'xfrc_applied': out[120], '_impl.wrap_obj': out[120],
'ximat': out[121], '_impl.wrap_xpos': out[121],
'xipos': out[122], 'xanchor': out[122],
'xmat': out[123], 'xaxis': out[123],
'xpos': out[124], 'xfrc_applied': out[124],
'xquat': out[125], 'ximat': out[125],
'_impl.contact__dim': out[126], 'xipos': out[126],
'_impl.contact__dist': out[127], 'xmat': out[127],
'_impl.contact__efc_address': out[128], 'xpos': out[128],
'_impl.contact__frame': out[129], 'xquat': out[129],
'_impl.contact__friction': out[130], '_impl.contact__dim': out[130],
'_impl.contact__geom': out[131], '_impl.contact__dist': out[131],
'_impl.contact__includemargin': out[132], '_impl.contact__efc_address': out[132],
'_impl.contact__pos': out[133], '_impl.contact__frame': out[133],
'_impl.contact__solimp': out[134], '_impl.contact__friction': out[134],
'_impl.contact__solref': out[135], '_impl.contact__geom': out[135],
'_impl.contact__solreffriction': out[136], '_impl.contact__includemargin': out[136],
'_impl.contact__worldid': out[137], '_impl.contact__pos': out[137],
'_impl.efc__D': out[138], '_impl.contact__solimp': out[138],
'_impl.efc__J': out[139], '_impl.contact__solref': out[139],
'_impl.efc__Jaref': out[140], '_impl.contact__solreffriction': out[140],
'_impl.efc__Ma': out[141], '_impl.contact__worldid': out[141],
'_impl.efc__Mgrad': out[142], '_impl.efc__D': out[142],
'_impl.efc__active': out[143], '_impl.efc__J': out[143],
'_impl.efc__alpha': out[144], '_impl.efc__Jaref': out[144],
'_impl.efc__aref': out[145], '_impl.efc__Ma': out[145],
'_impl.efc__beta': out[146], '_impl.efc__Mgrad': out[146],
'_impl.efc__beta_den': out[147], '_impl.efc__active': out[147],
'_impl.efc__beta_num': out[148], '_impl.efc__alpha': out[148],
'_impl.efc__cholesky_L_tmp': out[149], '_impl.efc__aref': out[149],
'_impl.efc__cholesky_y_tmp': out[150], '_impl.efc__beta': out[150],
'_impl.efc__condim': out[151], '_impl.efc__cholesky_L_tmp': out[151],
'_impl.efc__cost': out[152], '_impl.efc__cholesky_y_tmp': out[152],
'_impl.efc__cost_candidate': out[153], '_impl.efc__condim': out[153],
'_impl.efc__done': out[154], '_impl.efc__cost': out[154],
'_impl.efc__force': out[155], '_impl.efc__cost_candidate': out[155],
'_impl.efc__frictionloss': out[156], '_impl.efc__done': out[156],
'_impl.efc__gauss': out[157], '_impl.efc__force': out[157],
'_impl.efc__grad': out[158], '_impl.efc__frictionloss': out[158],
'_impl.efc__grad_dot': out[159], '_impl.efc__gauss': out[159],
'_impl.efc__gtol': out[160], '_impl.efc__grad': out[160],
'_impl.efc__h': out[161], '_impl.efc__grad_dot': out[161],
'_impl.efc__hi': out[162], '_impl.efc__gtol': out[162],
'_impl.efc__hi_alpha': out[163], '_impl.efc__h': out[163],
'_impl.efc__hi_next': out[164], '_impl.efc__hi': out[164],
'_impl.efc__hi_next_alpha': out[165], '_impl.efc__hi_alpha': out[165],
'_impl.efc__id': out[166], '_impl.efc__hi_next': out[166],
'_impl.efc__jv': out[167], '_impl.efc__hi_next_alpha': out[167],
'_impl.efc__lo': out[168], '_impl.efc__id': out[168],
'_impl.efc__lo_alpha': out[169], '_impl.efc__jv': out[169],
'_impl.efc__lo_next': out[170], '_impl.efc__lo': out[170],
'_impl.efc__lo_next_alpha': out[171], '_impl.efc__lo_alpha': out[171],
'_impl.efc__ls_done': out[172], '_impl.efc__lo_next': out[172],
'_impl.efc__margin': out[173], '_impl.efc__lo_next_alpha': out[173],
'_impl.efc__mid': out[174], '_impl.efc__ls_done': out[174],
'_impl.efc__mid_alpha': out[175], '_impl.efc__margin': out[175],
'_impl.efc__mv': out[176], '_impl.efc__mid': out[176],
'_impl.efc__p0': out[177], '_impl.efc__mid_alpha': out[177],
'_impl.efc__pos': out[178], '_impl.efc__mv': out[178],
'_impl.efc__prev_Mgrad': out[179], '_impl.efc__p0': out[179],
'_impl.efc__prev_cost': out[180], '_impl.efc__pos': out[180],
'_impl.efc__prev_grad': out[181], '_impl.efc__prev_Mgrad': out[181],
'_impl.efc__quad': out[182], '_impl.efc__prev_cost': out[182],
'_impl.efc__quad_gauss': out[183], '_impl.efc__prev_grad': out[183],
'_impl.efc__search': out[184], '_impl.efc__quad': out[184],
'_impl.efc__search_dot': out[185], '_impl.efc__quad_gauss': out[185],
'_impl.efc__type': out[186], '_impl.efc__search': out[186],
'_impl.efc__u': out[187], '_impl.efc__search_dot': out[187],
'_impl.efc__uu': out[188], '_impl.efc__type': out[188],
'_impl.efc__uv': out[189], '_impl.efc__u': out[189],
'_impl.efc__vel': out[190], '_impl.efc__uu': out[190],
'_impl.efc__vv': out[191], '_impl.efc__uv': out[191],
'_impl.efc__vel': out[192],
'_impl.efc__vv': out[193],
}) })
return d return d
@@ -4114,8 +4196,6 @@ def _step_jax_impl(m: types.Model, d: types.Data):
@ffi.marshal_jax_warp_callable @ffi.marshal_jax_warp_callable
def step(m: types.Model, d: types.Data): def step(m: types.Model, d: types.Data):
return _step_jax_impl(m, d) return _step_jax_impl(m, d)
@step.def_vmap @step.def_vmap
@ffi.marshal_custom_vmap @ffi.marshal_custom_vmap
def step_vmap(unused_axis_size, is_batched, m, d): def step_vmap(unused_axis_size, is_batched, m, d):
-3
View File
@@ -42,7 +42,6 @@ _e = mjwarp.Constraint(
**{f.name: None for f in dataclasses.fields(mjwarp.Constraint) if f.init} **{f.name: None for f in dataclasses.fields(mjwarp.Constraint) if f.init}
) )
@ffi.format_args_for_warp @ffi.format_args_for_warp
def _kinematics_shim( def _kinematics_shim(
# Model # Model
@@ -282,8 +281,6 @@ def _kinematics_jax_impl(m: types.Model, d: types.Data):
@ffi.marshal_jax_warp_callable @ffi.marshal_jax_warp_callable
def kinematics(m: types.Model, d: types.Data): def kinematics(m: types.Model, d: types.Data):
return _kinematics_jax_impl(m, d) return _kinematics_jax_impl(m, d)
@kinematics.def_vmap @kinematics.def_vmap
@ffi.marshal_custom_vmap @ffi.marshal_custom_vmap
def kinematics_vmap(unused_axis_size, is_batched, m, d): def kinematics_vmap(unused_axis_size, is_batched, m, d):
+38 -21
View File
@@ -13,7 +13,6 @@
# limitations under the License. # limitations under the License.
# ============================================================================== # ==============================================================================
"""MJX Warp types. """MJX Warp types.
DO NOT EDIT. This file is auto-generated. DO NOT EDIT. This file is auto-generated.
""" """
import dataclasses import dataclasses
@@ -23,10 +22,8 @@ from jax import tree_util
from jax.interpreters import batching from jax.interpreters import batching
from mujoco.mjx._src import dataclasses as mjx_dataclasses from mujoco.mjx._src import dataclasses as mjx_dataclasses
import numpy as np import numpy as np
PyTreeNode = mjx_dataclasses.PyTreeNode PyTreeNode = mjx_dataclasses.PyTreeNode
@dataclasses.dataclass(frozen=True) @dataclasses.dataclass(frozen=True)
@tree_util.register_pytree_node_class @tree_util.register_pytree_node_class
class TileSet: class TileSet:
@@ -38,7 +35,6 @@ class TileSet:
adr: address of each tile in the set adr: address of each tile in the set
size: size of all the tiles in this set size: size of all the tiles in this set
""" """
adr: np.ndarray adr: np.ndarray
size: int size: int
@@ -59,11 +55,11 @@ class BlockDim:
TODO(team): experimental and may be removed TODO(team): experimental and may be removed
""" """
actuator_velocity: int actuator_velocity: int
cholesky_factorize: int cholesky_factorize: int
cholesky_factorize_solve: int cholesky_factorize_solve: int
cholesky_solve: int cholesky_solve: int
contact_sort: int
energy_vel_kinetic: int energy_vel_kinetic: int
euler_dense: int euler_dense: int
mul_m_dense: int mul_m_dense: int
@@ -87,13 +83,10 @@ class BlockDim:
class StatisticWarp(PyTreeNode): class StatisticWarp(PyTreeNode):
"""Derived fields from Statistic.""" """Derived fields from Statistic."""
meaninertia: float meaninertia: float
class OptionWarp(PyTreeNode): class OptionWarp(PyTreeNode):
"""Derived fields from Option.""" """Derived fields from Option."""
broadphase: int broadphase: int
broadphase_filter: int broadphase_filter: int
epa_iterations: int epa_iterations: int
@@ -106,10 +99,8 @@ class OptionWarp(PyTreeNode):
sdf_initpoints: int sdf_initpoints: int
sdf_iterations: int sdf_iterations: int
class ModelWarp(PyTreeNode): class ModelWarp(PyTreeNode):
"""Derived fields from Model.""" """Derived fields from Model."""
M_colind: np.ndarray M_colind: np.ndarray
M_rowadr: np.ndarray M_rowadr: np.ndarray
M_rownnz: np.ndarray M_rownnz: np.ndarray
@@ -168,6 +159,7 @@ class ModelWarp(PyTreeNode):
nmeshpoly: int nmeshpoly: int
nmeshpolymap: int nmeshpolymap: int
nmeshpolyvert: int nmeshpolyvert: int
nsensortaxel: int
nxn_geom_pair: np.ndarray nxn_geom_pair: np.ndarray
nxn_geom_pair_filtered: np.ndarray nxn_geom_pair_filtered: np.ndarray
nxn_pairid: np.ndarray nxn_pairid: np.ndarray
@@ -183,6 +175,7 @@ class ModelWarp(PyTreeNode):
qM_tiles: Tuple[TileSet, ...] qM_tiles: Tuple[TileSet, ...]
rangefinder_sensor_adr: np.ndarray rangefinder_sensor_adr: np.ndarray
sensor_acc_adr: np.ndarray sensor_acc_adr: np.ndarray
sensor_contact_adr: np.ndarray
sensor_e_kinetic: bool sensor_e_kinetic: bool
sensor_e_potential: bool sensor_e_potential: bool
sensor_limitfrc_adr: np.ndarray sensor_limitfrc_adr: np.ndarray
@@ -197,6 +190,8 @@ class ModelWarp(PyTreeNode):
sensor_touch_adr: np.ndarray sensor_touch_adr: np.ndarray
sensor_vel_adr: np.ndarray sensor_vel_adr: np.ndarray
subtree_mass: jax.Array subtree_mass: jax.Array
taxel_sensorid: np.ndarray
taxel_vertadr: np.ndarray
ten_wrapadr_site: np.ndarray ten_wrapadr_site: np.ndarray
ten_wrapnum_site: np.ndarray ten_wrapnum_site: np.ndarray
tendon_geom_adr: np.ndarray tendon_geom_adr: np.ndarray
@@ -209,10 +204,8 @@ class ModelWarp(PyTreeNode):
wrap_site_adr: np.ndarray wrap_site_adr: np.ndarray
wrap_site_pair_adr: np.ndarray wrap_site_pair_adr: np.ndarray
class DataWarp(PyTreeNode): class DataWarp(PyTreeNode):
"""Derived fields from Data.""" """Derived fields from Data."""
act_dot_rk: jax.Array act_dot_rk: jax.Array
act_t0: jax.Array act_t0: jax.Array
act_vel_integration: jax.Array act_vel_integration: jax.Array
@@ -252,8 +245,6 @@ class DataWarp(PyTreeNode):
efc__alpha: jax.Array efc__alpha: jax.Array
efc__aref: jax.Array efc__aref: jax.Array
efc__beta: jax.Array efc__beta: jax.Array
efc__beta_den: jax.Array
efc__beta_num: jax.Array
efc__cholesky_L_tmp: jax.Array efc__cholesky_L_tmp: jax.Array
efc__cholesky_y_tmp: jax.Array efc__cholesky_y_tmp: jax.Array
efc__condim: jax.Array efc__condim: jax.Array
@@ -321,6 +312,7 @@ class DataWarp(PyTreeNode):
ncollision: jax.Array ncollision: jax.Array
ncon: jax.Array ncon: jax.Array
ncon_hfield: jax.Array ncon_hfield: jax.Array
ncon_world: jax.Array
nconmax: int nconmax: int
ne: jax.Array ne: jax.Array
ne_connect: jax.Array ne_connect: jax.Array
@@ -357,6 +349,10 @@ class DataWarp(PyTreeNode):
sap_range: jax.Array sap_range: jax.Array
sap_segment_index: jax.Array sap_segment_index: jax.Array
sap_sort_index: jax.Array sap_sort_index: jax.Array
sensor_contact_criteria: jax.Array
sensor_contact_direction: jax.Array
sensor_contact_matchid: jax.Array
sensor_contact_nmatch: jax.Array
sensor_rangefinder_dist: jax.Array sensor_rangefinder_dist: jax.Array
sensor_rangefinder_geomid: jax.Array sensor_rangefinder_geomid: jax.Array
sensor_rangefinder_pnt: jax.Array sensor_rangefinder_pnt: jax.Array
@@ -377,8 +373,6 @@ class DataWarp(PyTreeNode):
wrap_obj: jax.Array wrap_obj: jax.Array
wrap_xpos: jax.Array wrap_xpos: jax.Array
shape = property(lambda self: self.cacc.shape) shape = property(lambda self: self.cacc.shape)
DATA_NON_VMAP = { DATA_NON_VMAP = {
'collision_hftri_index', 'collision_hftri_index',
'collision_pair', 'collision_pair',
@@ -421,7 +415,6 @@ DATA_NON_VMAP = {
'ray_bodyexclude', 'ray_bodyexclude',
} }
def _to_elt(cont, _, d, axis): def _to_elt(cont, _, d, axis):
return DataWarp(**{ return DataWarp(**{
f.name: ( f.name: (
@@ -494,8 +487,6 @@ NDIM = {
'efc__alpha': 1, 'efc__alpha': 1,
'efc__aref': 2, 'efc__aref': 2,
'efc__beta': 1, 'efc__beta': 1,
'efc__beta_den': 1,
'efc__beta_num': 1,
'efc__cholesky_L_tmp': 3, 'efc__cholesky_L_tmp': 3,
'efc__cholesky_y_tmp': 2, 'efc__cholesky_y_tmp': 2,
'efc__condim': 2, 'efc__condim': 2,
@@ -568,6 +559,7 @@ NDIM = {
'ncollision': 1, 'ncollision': 1,
'ncon': 1, 'ncon': 1,
'ncon_hfield': 2, 'ncon_hfield': 2,
'ncon_world': 1,
'nconmax': 0, 'nconmax': 0,
'ne': 1, 'ne': 1,
'ne_connect': 1, 'ne_connect': 1,
@@ -618,6 +610,10 @@ NDIM = {
'sap_range': 2, 'sap_range': 2,
'sap_segment_index': 2, 'sap_segment_index': 2,
'sap_sort_index': 3, 'sap_sort_index': 3,
'sensor_contact_criteria': 3,
'sensor_contact_direction': 3,
'sensor_contact_matchid': 3,
'sensor_contact_nmatch': 2,
'sensor_rangefinder_dist': 2, 'sensor_rangefinder_dist': 2,
'sensor_rangefinder_geomid': 2, 'sensor_rangefinder_geomid': 2,
'sensor_rangefinder_pnt': 3, 'sensor_rangefinder_pnt': 3,
@@ -684,6 +680,7 @@ NDIM = {
'block_dim__cholesky_factorize': 0, 'block_dim__cholesky_factorize': 0,
'block_dim__cholesky_factorize_solve': 0, 'block_dim__cholesky_factorize_solve': 0,
'block_dim__cholesky_solve': 0, 'block_dim__cholesky_solve': 0,
'block_dim__contact_sort': 0,
'block_dim__energy_vel_kinetic': 0, 'block_dim__energy_vel_kinetic': 0,
'block_dim__euler_dense': 0, 'block_dim__euler_dense': 0,
'block_dim__mul_m_dense': 0, 'block_dim__mul_m_dense': 0,
@@ -829,6 +826,8 @@ NDIM = {
'mesh_faceadr': 1, 'mesh_faceadr': 1,
'mesh_graph': 1, 'mesh_graph': 1,
'mesh_graphadr': 1, 'mesh_graphadr': 1,
'mesh_normal': 2,
'mesh_normaladr': 1,
'mesh_polyadr': 1, 'mesh_polyadr': 1,
'mesh_polymap': 1, 'mesh_polymap': 1,
'mesh_polymapadr': 1, 'mesh_polymapadr': 1,
@@ -838,6 +837,7 @@ NDIM = {
'mesh_polyvert': 1, 'mesh_polyvert': 1,
'mesh_polyvertadr': 1, 'mesh_polyvertadr': 1,
'mesh_polyvertnum': 1, 'mesh_polyvertnum': 1,
'mesh_quat': 2,
'mesh_vert': 2, 'mesh_vert': 2,
'mesh_vertadr': 1, 'mesh_vertadr': 1,
'mesh_vertnum': 1, 'mesh_vertnum': 1,
@@ -872,6 +872,7 @@ NDIM = {
'nq': 0, 'nq': 0,
'nsensor': 0, 'nsensor': 0,
'nsensordata': 0, 'nsensordata': 0,
'nsensortaxel': 0,
'nsite': 0, 'nsite': 0,
'ntendon': 0, 'ntendon': 0,
'nu': 0, 'nu': 0,
@@ -931,11 +932,13 @@ NDIM = {
'rangefinder_sensor_adr': 1, 'rangefinder_sensor_adr': 1,
'sensor_acc_adr': 1, 'sensor_acc_adr': 1,
'sensor_adr': 1, 'sensor_adr': 1,
'sensor_contact_adr': 1,
'sensor_cutoff': 1, 'sensor_cutoff': 1,
'sensor_datatype': 1, 'sensor_datatype': 1,
'sensor_dim': 1, 'sensor_dim': 1,
'sensor_e_kinetic': 0, 'sensor_e_kinetic': 0,
'sensor_e_potential': 0, 'sensor_e_potential': 0,
'sensor_intprm': 2,
'sensor_limitfrc_adr': 1, 'sensor_limitfrc_adr': 1,
'sensor_limitpos_adr': 1, 'sensor_limitpos_adr': 1,
'sensor_limitvel_adr': 1, 'sensor_limitvel_adr': 1,
@@ -959,6 +962,8 @@ NDIM = {
'site_type': 1, 'site_type': 1,
'stat__meaninertia': 0, 'stat__meaninertia': 0,
'subtree_mass': 2, 'subtree_mass': 2,
'taxel_sensorid': 1,
'taxel_vertadr': 1,
'ten_wrapadr_site': 1, 'ten_wrapadr_site': 1,
'ten_wrapnum_site': 1, 'ten_wrapnum_site': 1,
'tendon_actfrclimited': 1, 'tendon_actfrclimited': 1,
@@ -1071,8 +1076,6 @@ BATCH_DIM = {
'efc__alpha': True, 'efc__alpha': True,
'efc__aref': True, 'efc__aref': True,
'efc__beta': True, 'efc__beta': True,
'efc__beta_den': True,
'efc__beta_num': True,
'efc__cholesky_L_tmp': True, 'efc__cholesky_L_tmp': True,
'efc__cholesky_y_tmp': True, 'efc__cholesky_y_tmp': True,
'efc__condim': True, 'efc__condim': True,
@@ -1145,6 +1148,7 @@ BATCH_DIM = {
'ncollision': False, 'ncollision': False,
'ncon': False, 'ncon': False,
'ncon_hfield': True, 'ncon_hfield': True,
'ncon_world': True,
'nconmax': False, 'nconmax': False,
'ne': True, 'ne': True,
'ne_connect': True, 'ne_connect': True,
@@ -1195,6 +1199,10 @@ BATCH_DIM = {
'sap_range': True, 'sap_range': True,
'sap_segment_index': True, 'sap_segment_index': True,
'sap_sort_index': True, 'sap_sort_index': True,
'sensor_contact_criteria': True,
'sensor_contact_direction': True,
'sensor_contact_matchid': True,
'sensor_contact_nmatch': True,
'sensor_rangefinder_dist': True, 'sensor_rangefinder_dist': True,
'sensor_rangefinder_geomid': True, 'sensor_rangefinder_geomid': True,
'sensor_rangefinder_pnt': True, 'sensor_rangefinder_pnt': True,
@@ -1261,6 +1269,7 @@ BATCH_DIM = {
'block_dim__cholesky_factorize': False, 'block_dim__cholesky_factorize': False,
'block_dim__cholesky_factorize_solve': False, 'block_dim__cholesky_factorize_solve': False,
'block_dim__cholesky_solve': False, 'block_dim__cholesky_solve': False,
'block_dim__contact_sort': False,
'block_dim__energy_vel_kinetic': False, 'block_dim__energy_vel_kinetic': False,
'block_dim__euler_dense': False, 'block_dim__euler_dense': False,
'block_dim__mul_m_dense': False, 'block_dim__mul_m_dense': False,
@@ -1406,6 +1415,8 @@ BATCH_DIM = {
'mesh_faceadr': False, 'mesh_faceadr': False,
'mesh_graph': False, 'mesh_graph': False,
'mesh_graphadr': False, 'mesh_graphadr': False,
'mesh_normal': False,
'mesh_normaladr': False,
'mesh_polyadr': False, 'mesh_polyadr': False,
'mesh_polymap': False, 'mesh_polymap': False,
'mesh_polymapadr': False, 'mesh_polymapadr': False,
@@ -1415,6 +1426,7 @@ BATCH_DIM = {
'mesh_polyvert': False, 'mesh_polyvert': False,
'mesh_polyvertadr': False, 'mesh_polyvertadr': False,
'mesh_polyvertnum': False, 'mesh_polyvertnum': False,
'mesh_quat': False,
'mesh_vert': False, 'mesh_vert': False,
'mesh_vertadr': False, 'mesh_vertadr': False,
'mesh_vertnum': False, 'mesh_vertnum': False,
@@ -1449,6 +1461,7 @@ BATCH_DIM = {
'nq': False, 'nq': False,
'nsensor': False, 'nsensor': False,
'nsensordata': False, 'nsensordata': False,
'nsensortaxel': False,
'nsite': False, 'nsite': False,
'ntendon': False, 'ntendon': False,
'nu': False, 'nu': False,
@@ -1508,11 +1521,13 @@ BATCH_DIM = {
'rangefinder_sensor_adr': False, 'rangefinder_sensor_adr': False,
'sensor_acc_adr': False, 'sensor_acc_adr': False,
'sensor_adr': False, 'sensor_adr': False,
'sensor_contact_adr': False,
'sensor_cutoff': False, 'sensor_cutoff': False,
'sensor_datatype': False, 'sensor_datatype': False,
'sensor_dim': False, 'sensor_dim': False,
'sensor_e_kinetic': False, 'sensor_e_kinetic': False,
'sensor_e_potential': False, 'sensor_e_potential': False,
'sensor_intprm': False,
'sensor_limitfrc_adr': False, 'sensor_limitfrc_adr': False,
'sensor_limitpos_adr': False, 'sensor_limitpos_adr': False,
'sensor_limitvel_adr': False, 'sensor_limitvel_adr': False,
@@ -1536,6 +1551,8 @@ BATCH_DIM = {
'site_type': False, 'site_type': False,
'stat__meaninertia': False, 'stat__meaninertia': False,
'subtree_mass': True, 'subtree_mass': True,
'taxel_sensorid': False,
'taxel_vertadr': False,
'ten_wrapadr_site': False, 'ten_wrapadr_site': False,
'ten_wrapnum_site': False, 'ten_wrapnum_site': False,
'tendon_actfrclimited': False, 'tendon_actfrclimited': False,