1111import numpy as np
1212import warp as wp
1313
14- from newton . _src . sim import Model
14+ from newton import BodyFlags , Model
1515from newton ._src .solvers .kamino ._src .core .bodies import convert_body_com_to_origin
1616from newton ._src .solvers .kamino ._src .core .control import ControlKamino
1717from newton ._src .solvers .kamino ._src .core .joints import JointActuationType
@@ -174,17 +174,16 @@ def _assert_model_bodies_conversion_consistency(
174174
175175 # Pure aliases: mass, inertia, COM, and initial velocity.
176176 aliases = [
177- ("m_i" , "body_mass" ),
178- ("inv_m_i" , "body_inv_mass" ),
179177 ("i_r_com_i" , "body_com" ),
180- ("i_I_i" , "body_inertia" ),
181- ("inv_i_I_i" , "body_inv_inertia" ),
182178 ("u_i_0" , "body_qd" ),
183179 ]
184180 for kamino_attr , newton_attr in aliases :
185181 if kamino_attr not in excluded :
186182 _assert_array_is_alias (test , bodies , kamino_attr , model_newton , newton_attr )
187183
184+ if model_newton .body_count == 0 :
185+ return
186+
188187 # `wid` may be renumbered for single-world models with global (-1) entities,
189188 # so it is compared against the expected post-renumbering value.
190189 if "wid" not in excluded :
@@ -194,9 +193,47 @@ def _assert_model_bodies_conversion_consistency(
194193 err_msg = "RigidBodiesModel.wid does not match the expected Model.body_world." ,
195194 )
196195
196+ # Inverse transformation: `m_i` and `inv_m_i` are near-identical copies,
197+ # except for bodies with
198+ if "m_i" not in excluded or "inv_m_i" not in excluded or "i_I_i" not in excluded or "inv_i_I_i" not in excluded :
199+ body_flags = model_newton .body_flags .numpy ()
200+ is_kinematic = body_flags != BodyFlags .DYNAMIC
201+ if "m_i" not in excluded :
202+ m_i_expected = model_newton .body_mass .numpy ()
203+ m_i_expected [is_kinematic ] = 0.0
204+ np .testing .assert_array_equal (
205+ bodies .m_i .numpy (),
206+ m_i_expected ,
207+ err_msg = "RigidBodiesModel.m_i does not match expected masked Model.body_mass" ,
208+ )
209+ if "inv_m_i" not in excluded :
210+ inv_m_i_expected = model_newton .body_inv_mass .numpy ()
211+ inv_m_i_expected [is_kinematic ] = 0.0
212+ np .testing .assert_array_equal (
213+ bodies .inv_m_i .numpy (),
214+ inv_m_i_expected ,
215+ err_msg = "RigidBodiesModel.inv_m_i does not match expected masked Model.body_inv_mass" ,
216+ )
217+ if "i_I_i" not in excluded :
218+ i_I_i_expected = model_newton .body_inertia .numpy ()
219+ i_I_i_expected [is_kinematic , :, :] = 0.0
220+ np .testing .assert_array_equal (
221+ bodies .i_I_i .numpy (),
222+ i_I_i_expected ,
223+ err_msg = "RigidBodiesModel.i_I_i does not match expected masked Model.body_inertia" ,
224+ )
225+ if "inv_i_I_i" not in excluded :
226+ inv_i_I_i_expected = model_newton .body_inv_inertia .numpy ()
227+ inv_i_I_i_expected [is_kinematic , :, :] = 0.0
228+ np .testing .assert_array_equal (
229+ bodies .inv_i_I_i .numpy (),
230+ inv_i_I_i_expected ,
231+ err_msg = "RigidBodiesModel.m_inv_i_I_i does not match expected masked Model.body_inv_inertia" ,
232+ )
233+
197234 # Inverse transformation: `q_i_0` stores COM-frame world poses; inverting it
198235 # back to body-origin frame must recover `Model.body_q` exactly.
199- if "q_i_0" not in excluded and model_newton . body_count > 0 :
236+ if "q_i_0" not in excluded :
200237 body_q_recovered = wp .empty_like (bodies .q_i_0 )
201238 convert_body_com_to_origin (bodies .i_r_com_i , bodies .q_i_0 , body_q_recovered )
202239 np .testing .assert_allclose (
0 commit comments