Usd examples parsing tests#572
Conversation
📝 WalkthroughWalkthroughAdds a USD physics validation test suite ( Changes
Sequence Diagram(s)sequenceDiagram
participant Test as TestImportSampleAssets
participant USD as UsdPhysics.LoadUsdPhysicsFromRange
participant Newton as NewtonModel
Test->>USD: LoadUsdPhysicsFromRange(file)
USD-->>Test: physics prims (bodies, shapes, joints, materials)
Test->>Newton: load/reference Newton model
Test->>Test: verify_usdphysics_parser(file, model, ...)
loop per-entity
Test->>Test: map Newton keys ↔ USD paths
Test->>Test: compare counts, transforms, mass/inertia
Test->>Test: validate joint types/DOFs/drives
Test->>Test: validate shapes, collision flags, morphs
end
Test-->>Test: assertions produce pass/fail
sequenceDiagram
participant Parser as import_usd.parse_usd
participant USD as USDStage
Parser->>USD: iterate physics prims (materials, bodies, articulations, shapes)
loop per-prim
Parser->>Parser: warn_invalid_desc(path, descriptor)
alt descriptor invalid
Parser-->>Parser: warnings.warn(..., stacklevel=2) and skip prim
else descriptor valid
Parser->>Parser: process prim (material/body/joint/shape)
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
📜 Recent review detailsConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (8)
newton/tests/test_import_usd.py (8)
21-21: Movemathimport to maintain import order consistency.The
mathimport should be grouped with the standard library imports at the top of the file.import os +import math import unittest import numpy as np import warp as wp -import math import newton
437-437: Remove unused import and fix import placement.The
UsdGeomimport is unused and the USD imports should be at the top of the file.- from pxr import Sdf, Usd, UsdGeom, UsdPhysics + from pxr import Sdf, Usd, UsdPhysics
526-526: Clean up whitespace issues throughout the method.Multiple lines contain trailing whitespace or blank lines with whitespace that should be cleaned up.
Apply formatting fixes to remove trailing whitespace and blank lines with whitespace throughout the
verify_usdphysics_parsermethod. Use your pre-commit hooks withpre-commit run -aas mentioned in the PR objectives to automatically fix these issues.Also applies to: 537-537, 559-559, 561-561, 566-566, 573-573, 580-580, 583-583, 588-588, 599-599, 608-608, 614-614, 633-633, 638-638, 641-641, 646-646, 648-648, 658-658, 661-661, 671-671, 683-683, 686-686, 690-690, 698-698, 704-704, 708-708, 712-712, 716-716, 726-726, 731-731
653-653: Remove unused variable assignment.
shape_body_arrayis assigned but never used in the function.- shape_body_array = model.shape_body.numpy()
718-718: Fix import placement inside function.The
quat_between_axesimport should be moved to the top of the file or the beginning of the method.Move the import to the beginning of the
verify_usdphysics_parsermethod:def verify_usdphysics_parser(self, file, model): """Verify model based on the UsdPhysics Parsing Utils""" # [1] https://openusd.org/release/api/usd_physics_page_front.html from pxr import Sdf, Usd, UsdPhysics + from newton.core import quat_between_axesAnd remove it from line 718:
- from newton.core import quat_between_axes
467-467: Rename unused loop variables to indicate they're intentionally unused.Loop control variables that aren't used should be prefixed with underscore to indicate intentional non-use.
- for body_path, body_desc in parsed_bodies: + for body_path, _ in parsed_bodies:- for joint_path, joint_desc in list(zip(*parsed.get(joint_objtype, ()))): + for joint_path, _ in list(zip(*parsed.get(joint_objtype, ()))):Also applies to: 506-506
434-744: Consider breaking down the large verification method for better maintainability.The
verify_usdphysics_parsermethod is 310+ lines long with complex nested logic. Consider extracting helper methods for better readability and testability.The method could be broken down into smaller, focused helper methods:
_verify_bodies(stage, parsed, model, body_key_to_idx)_verify_mass_and_inertia(stage, parsed_bodies, model, body_key_to_idx)_verify_joints(stage, parsed, model, joint_key_to_idx, body_key_to_idx)_verify_joint_frames(model, body_positions, body_quaternions)_verify_shapes(stage, parsed, model, shape_key_to_idx)Would you like me to help refactor this into smaller, more maintainable methods?
461-490: Add error handling for USD operations that might fail.The USD parsing operations could fail with various exceptions. Consider adding try-catch blocks to provide better error messages.
For example, wrap USD operations in error handling:
try: stage = Usd.Stage.Open(file) parsed = UsdPhysics.LoadUsdPhysicsFromRange(stage, ["/"]) except Exception as e: self.fail(f"Failed to parse USD file {file}: {e}")
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📥 Commits
Reviewing files that changed from the base of the PR and between 945a55e and 4e82a729b3e662cfccd3472196af49ec8b1585e2.
📒 Files selected for processing (1)
newton/tests/test_import_usd.py(2 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions (lines 109-111 and 1289-1291) rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
📚 Learning: 2025-08-12T18:07:17.267Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Applied to files:
newton/tests/test_import_usd.py
📚 Learning: 2025-08-12T18:07:17.267Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions (lines 109-111 and 1289-1291) rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Applied to files:
newton/tests/test_import_usd.py
🧬 Code Graph Analysis (1)
newton/tests/test_import_usd.py (3)
newton/tests/unittest_utils.py (2)
assert_np_equal(240-246)get_test_devices(98-132)newton/_src/utils/import_usd.py (2)
parse_usd(34-1274)from_gfquat(172-173)newton/_src/sim/builder.py (5)
body_count(499-500)shape_count(495-496)joint_count(503-504)ModelBuilder(68-4061)collapse_fixed_joints(1688-1982)
🪛 Ruff (0.12.2)
newton/tests/test_import_usd.py
437-437: import should be at the top-level of a file
(PLC0415)
437-437: pxr.UsdGeom imported but unused
Remove unused import: pxr.UsdGeom
(F401)
467-467: Loop control variable body_desc not used within loop body
(B007)
506-506: Loop control variable joint_desc not used within loop body
Rename unused joint_desc to _joint_desc
(B007)
526-526: Blank line contains whitespace
Remove whitespace from blank line
(W293)
537-537: Blank line contains whitespace
Remove whitespace from blank line
(W293)
559-559: Blank line contains whitespace
Remove whitespace from blank line
(W293)
561-561: Blank line contains whitespace
Remove whitespace from blank line
(W293)
566-566: Blank line contains whitespace
Remove whitespace from blank line
(W293)
573-573: Blank line contains whitespace
Remove whitespace from blank line
(W293)
580-580: Blank line contains whitespace
Remove whitespace from blank line
(W293)
581-581: Trailing whitespace
Remove trailing whitespace
(W291)
583-583: Blank line contains whitespace
Remove whitespace from blank line
(W293)
588-588: Blank line contains whitespace
Remove whitespace from blank line
(W293)
599-599: Blank line contains whitespace
Remove whitespace from blank line
(W293)
608-608: Blank line contains whitespace
Remove whitespace from blank line
(W293)
614-614: Blank line contains whitespace
Remove whitespace from blank line
(W293)
633-633: Blank line contains whitespace
Remove whitespace from blank line
(W293)
638-638: Blank line contains whitespace
Remove whitespace from blank line
(W293)
641-641: Blank line contains whitespace
Remove whitespace from blank line
(W293)
646-646: Blank line contains whitespace
Remove whitespace from blank line
(W293)
648-648: Blank line contains whitespace
Remove whitespace from blank line
(W293)
653-653: Local variable shape_body_array is assigned to but never used
Remove assignment to unused variable shape_body_array
(F841)
658-658: Blank line contains whitespace
Remove whitespace from blank line
(W293)
661-661: Blank line contains whitespace
Remove whitespace from blank line
(W293)
671-671: Blank line contains whitespace
Remove whitespace from blank line
(W293)
681-681: Trailing whitespace
Remove trailing whitespace
(W291)
683-683: Blank line contains whitespace
Remove whitespace from blank line
(W293)
686-686: Blank line contains whitespace
Remove whitespace from blank line
(W293)
690-690: Blank line contains whitespace
Remove whitespace from blank line
(W293)
698-698: Blank line contains whitespace
Remove whitespace from blank line
(W293)
704-704: Blank line contains whitespace
Remove whitespace from blank line
(W293)
708-708: Blank line contains whitespace
Remove whitespace from blank line
(W293)
712-712: Blank line contains whitespace
Remove whitespace from blank line
(W293)
716-716: Blank line contains whitespace
Remove whitespace from blank line
(W293)
718-718: import should be at the top-level of a file
(PLC0415)
726-726: Blank line contains whitespace
Remove whitespace from blank line
(W293)
731-731: Blank line contains whitespace
Remove whitespace from blank line
(W293)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Run GPU Benchmarks (Pull Request)
- GitHub Check: Run GPU Unit Tests on AWS EC2 (Pull Request)
- GitHub Check: run-newton-tests / newton-unittests (windows-latest)
- GitHub Check: run-newton-tests / newton-unittests (ubuntu-latest)
🔇 Additional comments (2)
newton/tests/test_import_usd.py (2)
433-434: LGTM! Well-structured test class for USD sample assets.The new
TestImportSampleAssetsclass provides comprehensive USD parsing validation capabilities.
760-780: LGTM! Well-implemented test for Anymal asset.The test correctly uses dynamic asset retrieval and proper error handling for missing files.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
newton/tests/test_import_usd.py (2)
609-611: Remove debug print and compute free-joint count robustly.Drop the debug
- print(model.joint_key) - self.assertEqual(len(joints_found) + 1, model.joint_count) + free_count = int((model.joint_type.numpy() == newton.JointType.FREE).sum()) + self.assertEqual(len(joints_found), model.joint_count - free_count)
845-856: Replace hardcoded asset path with dynamic asset resolution (CI-friendly).Hardcoding a local path will break in CI and on other machines. Use the same pattern as
test_anymalto fetch and locate the asset.- asset_path = "/home/chris/Documents/usd-test-assets/isaaclab/g1.usd" + # Resolve G1 asset dynamically; skip if not available + asset_root = newton.utils.download_asset("g1_usd") + asset_path = None + for root, _, files in os.walk(asset_root): + if "g1.usd" in files: + asset_path = os.path.join(root, "g1.usd") + break + if not asset_path or not os.path.exists(asset_path): + raise unittest.SkipTest("G1 asset file not found")
🧹 Nitpick comments (11)
newton/tests/test_import_usd.py (11)
27-27: Avoid mixingJointTypeimports; usenewton.JointTypeconsistently.Currently both
newton.JointTypeand a directJointTypeimport are used. Prefer a single style to avoid confusion and improve readability.Apply this diff:
-from newton import JointType +# Use newton.JointType directly for consistency- joint_mapping = { - JointType.PRISMATIC: UsdPhysics.ObjectType.PrismaticJoint, - JointType.REVOLUTE: UsdPhysics.ObjectType.RevoluteJoint, - JointType.BALL: UsdPhysics.ObjectType.SphericalJoint, - JointType.FIXED: UsdPhysics.ObjectType.FixedJoint, - # JointType.FREE: None, - JointType.DISTANCE: UsdPhysics.ObjectType.DistanceJoint, - JointType.D6: UsdPhysics.ObjectType.D6Joint, - } + joint_mapping = { + newton.JointType.PRISMATIC: UsdPhysics.ObjectType.PrismaticJoint, + newton.JointType.REVOLUTE: UsdPhysics.ObjectType.RevoluteJoint, + newton.JointType.BALL: UsdPhysics.ObjectType.SphericalJoint, + newton.JointType.FIXED: UsdPhysics.ObjectType.FixedJoint, + # newton.JointType.FREE: None, + newton.JointType.DISTANCE: UsdPhysics.ObjectType.DistanceJoint, + newton.JointType.D6: UsdPhysics.ObjectType.D6Joint, + }- if jt == JointType.REVOLUTE: + if jt == newton.JointType.REVOLUTE: self.assertEqual((lin, ang), (0, 1), f"{model.joint_key[j]} DOF dim mismatch") - elif jt == JointType.FIXED: + elif jt == newton.JointType.FIXED: self.assertEqual((lin, ang), (0, 0), f"{model.joint_key[j]} DOF dim mismatch") - elif jt == JointType.FREE: + elif jt == newton.JointType.FREE: self.assertGreater(lin + ang, 0, f"{model.joint_key[j]} expected nonzero DOFs for free joint") - elif jt == JointType.PRISMATIC: + elif jt == newton.JointType.PRISMATIC: self.assertEqual((lin, ang), (1, 0), f"{model.joint_key[j]} DOF dim mismatch") - elif jt == JointType.BALL: + elif jt == newton.JointType.BALL: self.assertEqual((lin, ang), (0, 3), f"{model.joint_key[j]} DOF dim mismatch")Also applies to: 588-596, 624-633
534-537: Keep the in-function USD import (to avoid optional-dep import-time failures), but drop the unused symbol and silence the linter.
UsdGeomis unused. Keeping the import inside the function is appropriate for optional dependencies (aligned with the repo’s lazy-import pattern).- from pxr import Sdf, Usd, UsdGeom, UsdPhysics + from pxr import Sdf, Usd, UsdPhysics # noqa: PLC0415
544-547: Use unittest assertions instead of bareassert.Replace bare
assertwithself.assertInfor clearer failures and consistency with the rest of the test suite.- assert body_key_to_idx.get(str(body_path), None) is not None + self.assertIn(str(body_path), body_key_to_idx)
548-557: Collider equality may be brittle when bodies have descendant shapes.Comment notes a TODO, but the test currently enforces strict equality. For USD assets where shapes are author-authored on descendants (common), this will fail. Consider either:
- comparing only shapes directly attached to the body, or
- aggregating descendant shapes for both USD and Newton before compare, or
- relaxing to subset checks.
Would you like me to propose a helper that gathers colliders attached to the prim and descendants on both sides and compares normalized sets?
564-566: Rename unused loop variable to underscore.
body_descis unused in this loop; rename to_to satisfy linters and improve clarity.- for body_path, body_desc in parsed_bodies: + for body_path, _ in parsed_bodies:
603-607: Rename unusedjoint_descto underscore and guard for empty parsed lists.Minor cleanups for readability and to satisfy the linter.
- for joint_type, joint_objtype in joint_mapping.items(): - for joint_path, joint_desc in list(zip(*parsed.get(joint_objtype, ()))): + for joint_type, joint_objtype in joint_mapping.items(): + for joint_path, _ in list(zip(*parsed.get(joint_objtype, ()))): joint_idx = joint_key_to_idx.get(str(joint_path), None) joints_found.append(joint_idx) - assert joint_key_to_idx.get(str(joint_path), None) is not None + self.assertIn(str(joint_path), joint_key_to_idx) assert model_joint_type[joint_idx] == joint_type
612-617: Usejoint_qd_startfor DOF indexing instead of summing sizes.Rely on the model’s precomputed DOF start indices to avoid off-by-ones and improve clarity.
- body_q_array = model.body_q.numpy() - joint_dof_dim_array = model.joint_dof_dim.numpy() + body_q_array = model.body_q.numpy() + joint_dof_dim_array = model.joint_dof_dim.numpy() + joint_qd_start = model.joint_qd_start.numpy()- dof_index = 0 if j <= 0 else sum(int(joint_dof_dim_array[i][0] + joint_dof_dim_array[i][1]) for i in range(j)) + dof_index = int(joint_qd_start[j])Also applies to: 657-657
678-679: Fix trailing whitespace and make axis assertion clearer.Eliminate trailing whitespace and format the condition for readability.
- self.assertTrue(all(abs(actual_axis[i] - expected_axis[i]) < 1e-6 for i in range(3)) or - all(abs(actual_axis[i] - (-expected_axis[i])) < 1e-6 for i in range(3))) + self.assertTrue( + all(abs(actual_axis[i] - expected_axis[i]) < 1e-6 for i in range(3)) + or all(abs(actual_axis[i] - (-expected_axis[i])) < 1e-6 for i in range(3)) + )
750-750: Remove unused variable.
shape_body_arrayis assigned but never used.- shape_body_array = model.shape_body.numpy()
814-821: Avoid magic numbers for shape type checks; key off USD spec instead.Using
[3, 5]is brittle. Prefer checking if the USD shape has anaxisattribute, which is what drives the rotation correction. Also silence the function-level import linter.- if newton_type in [3, 5]: - from newton.core import quat_between_axes - usd_axis = int(shape_spec.axis) if hasattr(shape_spec, 'axis') else 2 - axis_quat = (quat_between_axes(newton.Axis.Z, newton.Axis.X) if usd_axis == 0 else - quat_between_axes(newton.Axis.Z, newton.Axis.Y) if usd_axis == 1 else - wp.quat_identity()) + if hasattr(shape_spec, "axis"): + from newton.core import quat_between_axes # noqa: PLC0415 + usd_axis = int(shape_spec.axis) + axis_quat = ( + quat_between_axes(newton.Axis.Z, newton.Axis.X) + if usd_axis == 0 + else quat_between_axes(newton.Axis.Z, newton.Axis.Y) + if usd_axis == 1 + else wp.quat_identity() + ) expected_quat = wp.mul(usd_quat, axis_quat) else: expected_quat = usd_quat
623-623: Trailing whitespace and whitespace-only lines.There are multiple instances of trailing whitespace (W291) and whitespace-only blank lines (W293). Please run the project’s pre-commit hooks (ruff/black) to auto-fix.
Run:
- pre-commit run -a
- or: ruff --fix . && black .
Also applies to: 634-634, 656-656, 658-658, 663-663, 670-670, 677-677, 680-680, 685-685, 696-696, 705-705, 711-711, 730-730, 735-735, 738-738, 743-743, 745-745, 755-755, 758-758, 768-768, 780-780, 783-783, 787-787, 795-795, 801-801, 805-805, 809-809, 813-813, 823-823, 828-828
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📥 Commits
Reviewing files that changed from the base of the PR and between 4e82a729b3e662cfccd3472196af49ec8b1585e2 and c438ea4e0d82e233b58df0f82a9a426ca95fe0ae.
📒 Files selected for processing (1)
newton/tests/test_import_usd.py(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions (lines 109-111 and 1289-1291) rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
🧬 Code Graph Analysis (1)
newton/tests/test_import_usd.py (3)
newton/tests/unittest_utils.py (2)
assert_np_equal(240-246)get_test_devices(98-132)newton/_src/utils/import_usd.py (2)
parse_usd(34-1279)from_gfquat(172-173)newton/_src/sim/builder.py (5)
body_count(499-500)shape_count(495-496)joint_count(503-504)ModelBuilder(68-4065)collapse_fixed_joints(1688-1985)
🪛 Ruff (0.12.2)
newton/tests/test_import_usd.py
534-534: import should be at the top-level of a file
(PLC0415)
534-534: pxr.UsdGeom imported but unused
Remove unused import: pxr.UsdGeom
(F401)
564-564: Loop control variable body_desc not used within loop body
(B007)
603-603: Loop control variable joint_desc not used within loop body
Rename unused joint_desc to _joint_desc
(B007)
623-623: Blank line contains whitespace
Remove whitespace from blank line
(W293)
634-634: Blank line contains whitespace
Remove whitespace from blank line
(W293)
656-656: Blank line contains whitespace
Remove whitespace from blank line
(W293)
658-658: Blank line contains whitespace
Remove whitespace from blank line
(W293)
663-663: Blank line contains whitespace
Remove whitespace from blank line
(W293)
670-670: Blank line contains whitespace
Remove whitespace from blank line
(W293)
677-677: Blank line contains whitespace
Remove whitespace from blank line
(W293)
678-678: Trailing whitespace
Remove trailing whitespace
(W291)
680-680: Blank line contains whitespace
Remove whitespace from blank line
(W293)
685-685: Blank line contains whitespace
Remove whitespace from blank line
(W293)
696-696: Blank line contains whitespace
Remove whitespace from blank line
(W293)
705-705: Blank line contains whitespace
Remove whitespace from blank line
(W293)
711-711: Blank line contains whitespace
Remove whitespace from blank line
(W293)
730-730: Blank line contains whitespace
Remove whitespace from blank line
(W293)
735-735: Blank line contains whitespace
Remove whitespace from blank line
(W293)
738-738: Blank line contains whitespace
Remove whitespace from blank line
(W293)
743-743: Blank line contains whitespace
Remove whitespace from blank line
(W293)
745-745: Blank line contains whitespace
Remove whitespace from blank line
(W293)
750-750: Local variable shape_body_array is assigned to but never used
Remove assignment to unused variable shape_body_array
(F841)
755-755: Blank line contains whitespace
Remove whitespace from blank line
(W293)
758-758: Blank line contains whitespace
Remove whitespace from blank line
(W293)
768-768: Blank line contains whitespace
Remove whitespace from blank line
(W293)
778-778: Trailing whitespace
Remove trailing whitespace
(W291)
780-780: Blank line contains whitespace
Remove whitespace from blank line
(W293)
783-783: Blank line contains whitespace
Remove whitespace from blank line
(W293)
787-787: Blank line contains whitespace
Remove whitespace from blank line
(W293)
795-795: Blank line contains whitespace
Remove whitespace from blank line
(W293)
801-801: Blank line contains whitespace
Remove whitespace from blank line
(W293)
805-805: Blank line contains whitespace
Remove whitespace from blank line
(W293)
809-809: Blank line contains whitespace
Remove whitespace from blank line
(W293)
813-813: Blank line contains whitespace
Remove whitespace from blank line
(W293)
815-815: import should be at the top-level of a file
(PLC0415)
823-823: Blank line contains whitespace
Remove whitespace from blank line
(W293)
828-828: Blank line contains whitespace
Remove whitespace from blank line
(W293)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Run GPU Benchmarks (Pull Request)
- GitHub Check: Run GPU Unit Tests on AWS EC2 (Pull Request)
- GitHub Check: run-newton-tests / newton-unittests (ubuntu-latest)
- GitHub Check: run-newton-tests / newton-unittests (windows-latest)
cea2a13 to
dccb303
Compare
14bd1ed to
62bbe3e
Compare
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (7)
newton/_src/utils/import_usd.py (2)
784-792: Makewarn_invalid_descmore robust and classify the warning.Two tweaks improve resilience and debuggability:
- Guard against descriptors that might not expose
isValid(future pxr changes) usinggetattr.- Set the warning category explicitly to
UserWarningso it can be filtered independently.Apply this diff:
- def warn_invalid_desc(path, descriptor) -> bool: - if not descriptor.isValid: - warnings.warn( - f'Warning: Invalid {type(descriptor).__name__} descriptor for prim at path "{path}".', - stacklevel=2, - ) + def warn_invalid_desc(path, descriptor) -> bool: + # Be defensive in case pxr changes the API and .isValid is absent + if not getattr(descriptor, "isValid", True): + warnings.warn( + f'Invalid {type(descriptor).__name__} descriptor for prim at path "{str(path)}".', + category=UserWarning, + stacklevel=2, + ) return True return False
133-139: Case mismatch:meshSimplificationkey won’t match.lower()lookup.You lower the input before the dict lookup (
approximation.lower()), but one dict key is mixed-case. It will never match and will silently disable that remeshing path.Apply this diff:
- approximation_to_remeshing_method = { + approximation_to_remeshing_method = { "convexdecomposition": "coacd", "convexhull": "convex_hull", "boundingsphere": "bounding_sphere", "boundingcube": "bounding_box", - "meshSimplification": "quadratic", + "meshsimplification": "quadratic", }newton/tests/test_import_usd.py (5)
28-29: Dual imports of parse_usd (module and qualified) — consider consistent usage.You import
parse_usddirectly and also callnewton.utils.parse_usdlater. It’s harmless but a bit inconsistent. Prefer one style throughout the file.- from newton.utils import parse_usd, quat_between_axes + from newton.utils import parse_usd, quat_between_axes ... - newton.utils.parse_usd( + parse_usd( str(asset_path), builder,
554-557: Collider set equality should ignore visual-only shapes.
model_collisionsis built from all shapes attached to the body; if visual shapes are present (COLLIDE_SHAPES off), this will over-count and fail equality against USD’scollisions. Filter by the collide flag.Apply this diff:
- model_collisions = {model.shape_key[sk] for sk in model.body_shapes[body_idx]} + # Only compare physics collision shapes, not visuals + flags = model.shape_flags.numpy() + model_collisions = { + model.shape_key[sk] + for sk in model.body_shapes[body_idx] + if (int(flags[sk]) & int(newton.ShapeFlags.COLLIDE_SHAPES)) != 0 + }
603-604: Free-joint accounting is brittle; compute it instead of assuming +1.Assets may have zero or multiple automatically-added free joints (e.g., multiple floating subgraphs). Derive the count from the model.
Apply this diff:
- self.assertEqual(len(joints_found) + 1, model.joint_count) + model_joint_types = model.joint_type.numpy() + num_free = int(np.sum(model_joint_types == JointType.FREE)) + self.assertEqual(len(joints_found) + num_free, model.joint_count)
832-845: Account for prim-local axis scale when validating shape dimensions.The parser multiplies radii/half-heights by the prim’s local scale components (and reorients by axis). The assertions compare against unscaled USD values, which can false-fail when assets use authored scales.
Apply this diff to incorporate per-axis scale:
- if newton_type in [3, 5]: + if newton_type in [3, 5]: usd_axis = int(shape_spec.axis) if hasattr(shape_spec, "axis") else 2 axis_quat = ( quat_between_axes(newton.Axis.Z, newton.Axis.X) if usd_axis == 0 else quat_between_axes(newton.Axis.Z, newton.Axis.Y) if usd_axis == 1 else wp.quat_identity() ) expected_quat = wp.mul(usd_quat, axis_quat) else: expected_quat = usd_quat @@ - if newton_type == newton.GeoType.CAPSULE: - self.assertAlmostEqual(newton_scale[0], shape_spec.radius, places=5) - self.assertAlmostEqual(newton_scale[1], shape_spec.halfHeight, places=5) + # Extract authored local scale (only last authored scale op is used in parser) + from pxr import UsdGeom # noqa: PLC0415 + xf = UsdGeom.Xform(prim) + local_scale = np.ones(3, dtype=np.float32) + for op in xf.GetOrderedXformOps(): + if op.GetOpType() == UsdGeom.XformOp.TypeScale: + local_scale = np.array(op.Get(), dtype=np.float32) + if newton_type == newton.GeoType.CAPSULE: + usd_axis = int(getattr(shape_spec, "axis", 2)) + self.assertAlmostEqual(newton_scale[0], shape_spec.radius * local_scale[(usd_axis + 1) % 3], places=5) + self.assertAlmostEqual(newton_scale[1], shape_spec.halfHeight * local_scale[usd_axis], places=5) elif newton_type == newton.GeoType.BOX: for i, (n_scale, u_extent) in enumerate(zip(newton_scale, shape_spec.halfExtents)): self.assertAlmostEqual( n_scale, u_extent, places=5, msg=f"Box {sid} extent[{i}]: USD={u_extent}, Newton={n_scale}" ) elif newton_type == newton.GeoType.SPHERE: - self.assertAlmostEqual(newton_scale[0], shape_spec.radius, places=5) + self.assertAlmostEqual(newton_scale[0], shape_spec.radius * local_scale[0], places=5) elif newton_type == newton.GeoType.CYLINDER: - self.assertAlmostEqual(newton_scale[0], shape_spec.radius, places=5) - self.assertAlmostEqual(newton_scale[1], shape_spec.halfHeight, places=5) + usd_axis = int(getattr(shape_spec, "axis", 2)) + self.assertAlmostEqual(newton_scale[0], shape_spec.radius * local_scale[(usd_axis + 1) % 3], places=5) + self.assertAlmostEqual(newton_scale[1], shape_spec.halfHeight * local_scale[usd_axis], places=5)Also applies to: 852-865
867-880: Asset tests (g1,anymal) are well-scoped and CI-friendly.
- Uses
newton.utils.download_assetto avoid hardcoded local paths.- Skips gracefully when USD is unavailable.
- Validates via the shared verification harness.
One nit: unify the
parse_usdimport style (see earlier comment).Also applies to: 882-902
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📥 Commits
Reviewing files that changed from the base of the PR and between c438ea4e0d82e233b58df0f82a9a426ca95fe0ae and 7c0b155f088d8d56c1db347e7e9a5d2ce5996616.
📒 Files selected for processing (2)
newton/_src/utils/import_usd.py(5 hunks)newton/tests/test_import_usd.py(3 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: shi-eric
PR: newton-physics/newton#521
File: newton/examples/example_cloth_hanging.py:36-36
Timestamp: 2025-08-12T05:17:34.423Z
Learning: The Newton migration guide (docs/migration.rst) is specifically for documenting how to migrate existing warp.sim functionality to Newton equivalents. New Newton-only features that didn't exist in warp.sim do not need migration documentation.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions (lines 109-111 and 1289-1291) rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
📚 Learning: 2025-08-12T18:07:17.267Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Applied to files:
newton/_src/utils/import_usd.py
📚 Learning: 2025-08-12T18:07:17.267Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions (lines 109-111 and 1289-1291) rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Applied to files:
newton/_src/utils/import_usd.py
🧬 Code graph analysis (1)
newton/tests/test_import_usd.py (1)
newton/_src/utils/import_usd.py (2)
parse_usd(35-1315)from_gfquat(173-174)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Run GPU Benchmarks (Pull Request)
- GitHub Check: Run GPU Unit Tests on AWS EC2 (Pull Request)
- GitHub Check: run-newton-tests / newton-unittests (ubuntu-latest)
- GitHub Check: run-newton-tests / newton-unittests (windows-latest)
🔇 Additional comments (5)
newton/_src/utils/import_usd.py (2)
21-21: Importing warnings is appropriate for parser-level soft failures.Using the warnings subsystem (vs print) is the right call for invalid USD descriptors. No issues here.
795-797: Early-return skip points on invalid descriptors look good.Placing the skip directly at the top of each loop is clear and prevents partial state mutation. This should reduce hard-to-reproduce errors when datasets contain malformed prims.
Also applies to: 808-810, 850-852, 990-992
newton/tests/test_import_usd.py (3)
16-16: Import math for angle/DOF checks — OK.Needed for radians/degrees conversions below.
25-25: ImportingJointTypedirectly simplifies readability.This reduces
newton.JointTypeverbosity in assertions.
531-866: Great end-to-end validation utility for USD assets.The helper cross-validates bodies, shapes, joints, transforms, and properties against pxr’s parsed descriptors. This will catch regressions in both parser and model-building logic. Nice coverage.
Signed-off-by: camevor <camevor@nvidia.com>
Signed-off-by: camevor <camevor@nvidia.com>
Signed-off-by: camevor <camevor@nvidia.com>
Signed-off-by: camevor <camevor@nvidia.com>
Signed-off-by: camevor <camevor@nvidia.com>
Signed-off-by: camevor <camevor@nvidia.com>
Signed-off-by: camevor <camevor@nvidia.com>
Signed-off-by: camevor <camevor@nvidia.com>
Signed-off-by: camevor <camevor@nvidia.com>
43e743e to
4fa219f
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
newton/tests/test_import_usd.py (1)
282-286: Guard USD-dependent test with skipUnlessThis test imports pxr modules and will fail in environments without USD. Add the same guard used elsewhere.
- def test_mesh_approximation(self): + @unittest.skipUnless(USD_AVAILABLE, "Requires usd-core") + def test_mesh_approximation(self): from pxr import Gf, Usd, UsdGeom, UsdPhysics # noqa: PLC0415
♻️ Duplicate comments (1)
newton/tests/test_import_usd.py (1)
714-728: Correct drive gains scaling: use per-joint-type factor (angular vs. linear)Using
math.degrees(drive_gain_scale)treats the scale as an angle and applies the same factor to linear joints. Angular drives should be scaled bydrive_gain_scale * (180/pi), linear drives bydrive_gain_scaleonly.Apply this diff:
- if ke_attr: + if ke_attr: ke_val = ke_attr.Get() if ke_attr.HasAuthoredValue() else None if ke_val is not None: ke = float(ke_val) - self.assertAlmostEqual( - float(model.joint_target_ke.numpy()[dof_index]), ke * math.degrees(drive_gain_scale), places=2 - ) + gain_scale = (math.degrees(1.0) * drive_gain_scale) if prim.IsA(UsdPhysics.RevoluteJoint) else drive_gain_scale + self.assertAlmostEqual( + float(model.joint_target_ke.numpy()[dof_index]), + ke * gain_scale, + places=2, + ) - if kd_attr: + if kd_attr: kd_val = kd_attr.Get() if kd_attr.HasAuthoredValue() else None if kd_val is not None: kd = float(kd_val) - self.assertAlmostEqual( - float(model.joint_target_kd.numpy()[dof_index]), kd * math.degrees(drive_gain_scale), places=2 - ) + gain_scale = (math.degrees(1.0) * drive_gain_scale) if prim.IsA(UsdPhysics.RevoluteJoint) else drive_gain_scale + self.assertAlmostEqual( + float(model.joint_target_kd.numpy()[dof_index]), + kd * gain_scale, + places=2, + )
🧹 Nitpick comments (6)
newton/tests/test_import_usd.py (6)
605-607: Compute expected joint count from model free joints rather than a booleanAssets can have multiple floating bodies; counting free joints directly is more robust than assuming exactly one when
floating=True.- expected_model_joints = len(joints_found) + 1 if floating else len(joints_found) - self.assertEqual(model.joint_count, expected_model_joints) + # Count free joints as imported to avoid assumptions about # of floating bodies. + free_joints = int(np.count_nonzero(model.joint_type.numpy() == JointType.FREE)) + expected_model_joints = len(joints_found) + free_joints + self.assertEqual(model.joint_count, expected_model_joints)
835-846: Prefer enums over magic numbers for shape typesUse
newton.GeoType.CAPSULEandnewton.GeoType.CYLINDERinstead of[3, 5]to improve readability and reduce risk of mismatch if enum values change.- if newton_type in [3, 5]: + if newton_type in (newton.GeoType.CAPSULE, newton.GeoType.CYLINDER):
763-763: Remove no-op call
model.shape_body.numpy()is not used; drop it to reduce noise.- model.shape_body.numpy()
84-87: Normalize bitmask checks for collision flagBitwise checks mix
int(enum)and raw enum usages across the file. For consistency and to avoid surprises with IntFlag vs IntEnum, wrap the enum inint(...)here, as done earlier in Line 57.- collision_shapes = [ - i for i in range(builder.shape_count) if builder.shape_flags[i] & newton.ShapeFlags.COLLIDE_SHAPES - ] + collision_shapes = [ + i for i in range(builder.shape_count) + if builder.shape_flags[i] & int(newton.ShapeFlags.COLLIDE_SHAPES) + ]
27-31: Drop unusedget_test_devicesanddevices
devices = get_test_devices()is never used in this file. Removing the import and assignment avoids lint warnings.-from newton.tests.unittest_utils import USD_AVAILABLE, assert_np_equal, get_test_devices +from newton.tests.unittest_utils import USD_AVAILABLE, assert_np_equal - -devices = get_test_devices()
874-880: Unifyparse_usdusage styleYou import
parse_usdat Line 28 but still callnewton.utils.parse_usdin several places. Pick one style (prefer the imported name) for consistency.Would you like me to submit a follow-up patch to switch all calls in this file to the imported
parse_usd?Also applies to: 896-902, 911-917, 926-932, 941-947
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📥 Commits
Reviewing files that changed from the base of the PR and between 7c0b155f088d8d56c1db347e7e9a5d2ce5996616 and 4fa219f.
📒 Files selected for processing (2)
newton/_src/utils/import_usd.py(6 hunks)newton/tests/test_import_usd.py(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- newton/_src/utils/import_usd.py
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: shi-eric
PR: newton-physics/newton#521
File: newton/examples/example_cloth_hanging.py:36-36
Timestamp: 2025-08-12T05:17:34.423Z
Learning: The Newton migration guide (docs/migration.rst) is specifically for documenting how to migrate existing warp.sim functionality to Newton equivalents. New Newton-only features that didn't exist in warp.sim do not need migration documentation.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions (lines 109-111 and 1289-1291) rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
📚 Learning: 2025-08-12T18:07:17.267Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Applied to files:
newton/tests/test_import_usd.py
📚 Learning: 2025-08-12T18:07:17.267Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions (lines 109-111 and 1289-1291) rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Applied to files:
newton/tests/test_import_usd.py
🧬 Code graph analysis (1)
newton/tests/test_import_usd.py (5)
newton/tests/unittest_utils.py (1)
assert_np_equal(240-246)newton/_src/utils/import_usd.py (2)
parse_usd(35-1315)from_gfquat(173-174)newton/_src/sim/builder.py (2)
ModelBuilder(67-4099)collapse_fixed_joints(1739-2036)newton/_src/geometry/types.py (1)
GeoType(25-36)newton/examples/__init__.py (1)
get_asset(32-33)
eric-heiden
left a comment
There was a problem hiding this comment.
This looks good to me.
@jvonmuralt can you sign the CLA please?
@camevor can you resolve the merge conflicts, then we can get it in.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
newton/tests/test_import_usd.py (1)
272-276: Guard this test with USD availability.This test imports PXR modules but lacks the
@skipUnless(USD_AVAILABLE, ...)guard used elsewhere. Without USD, CI will error instead of skip.+ @unittest.skipUnless(USD_AVAILABLE, "Requires usd-core") def test_mesh_approximation(self): from pxr import Gf, Usd, UsdGeom, UsdPhysics # noqa: PLC0415
♻️ Duplicate comments (2)
newton/tests/test_import_usd.py (2)
701-716: Fix KE/KD scaling: use drive_gain_scale / radians(1) (not degrees(drive_gain_scale)).Current assertions treat the scale as an angle. Expect
scale * (180/π)for angular drives.- self.assertAlmostEqual( - float(model.joint_target_ke.numpy()[dof_index]), ke * math.degrees(drive_gain_scale), places=2 - ) + self.assertAlmostEqual( + float(model.joint_target_ke.numpy()[dof_index]), + ke * drive_gain_scale * math.degrees(1.0), + places=2, + ) ... - self.assertAlmostEqual( - float(model.joint_target_kd.numpy()[dof_index]), kd * math.degrees(drive_gain_scale), places=2 - ) + self.assertAlmostEqual( + float(model.joint_target_kd.numpy()[dof_index]), + kd * drive_gain_scale * math.degrees(1.0), + places=2, + )
559-566: Fix principal-axes quaternion misuse (Gf.Quat.Normalize returns magnitude, not a quaternion).This assigns a float to
principal_axesand produces a wrong inertia rotation. Build a normalized Warp quaternion from the Gf.Quat components (or use GetNormalized) before forming the rotation matrix.- if mass_api.GetDiagonalInertiaAttr().HasAuthoredValue(): - diag_inertia = mass_api.GetDiagonalInertiaAttr().Get() - principal_axes = mass_api.GetPrincipalAxesAttr().Get().Normalize() - p = np.array(wp.quat_to_matrix(wp.quat(*principal_axes.imaginary, principal_axes.real))).reshape( - (3, 3) - ) + if mass_api.GetDiagonalInertiaAttr().HasAuthoredValue(): + diag_inertia = mass_api.GetDiagonalInertiaAttr().Get() + gfq = mass_api.GetPrincipalAxesAttr().Get() + if gfq is not None: + ix, iy, iz = gfq.GetImaginary() + w = gfq.GetReal() + q_wp = wp.normalize(wp.quat(ix, iy, iz, w)) + else: + q_wp = wp.quat_identity() + p = np.array(wp.quat_to_matrix(q_wp)).reshape(3, 3)
🧹 Nitpick comments (4)
newton/tests/test_import_usd.py (4)
822-833: Avoid magic numbers for GeoType; use enum members.Using raw ints [3, 5] is brittle; prefer
newton.GeoType.CAPSULEandnewton.GeoType.CYLINDER.- if newton_type in [3, 5]: + if newton_type in [newton.GeoType.CAPSULE, newton.GeoType.CYLINDER]:
640-643: Use precomputed DOF start to avoid O(n²) summation and off-by-one risks.
model.joint_qd_startis available and clearer.- dof_index = ( - 0 if j <= 0 else sum(int(joint_dof_dim_array[i][0] + joint_dof_dim_array[i][1]) for i in range(j)) - ) + dof_index = int(model.joint_qd_start.numpy()[j])
539-545: Collider set equivalence may fail for bodies with child shapes.Equality assumes all collisions are authored directly on the body prim. USD scenes often attach colliders to children; consider normalizing to the set of all descendant collider paths for comparison or limit the check to bodies without collider children.
30-31: Remove unused variable.
devices = get_test_devices()is never used.-devices = get_test_devices() +# devices = get_test_devices() # Unused; remove if not needed.
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
newton/_src/utils/import_usd.py(6 hunks)newton/tests/test_import_usd.py(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- newton/_src/utils/import_usd.py
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: shi-eric
PR: newton-physics/newton#521
File: newton/examples/example_cloth_hanging.py:36-36
Timestamp: 2025-08-12T05:17:34.423Z
Learning: The Newton migration guide (docs/migration.rst) is specifically for documenting how to migrate existing warp.sim functionality to Newton equivalents. New Newton-only features that didn't exist in warp.sim do not need migration documentation.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions (lines 109-111 and 1289-1291) rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
📚 Learning: 2025-08-12T18:07:17.267Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Applied to files:
newton/tests/test_import_usd.py
📚 Learning: 2025-08-12T18:07:17.267Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions (lines 109-111 and 1289-1291) rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Applied to files:
newton/tests/test_import_usd.py
📚 Learning: 2025-08-18T15:56:26.587Z
Learnt from: adenzler-nvidia
PR: newton-physics/newton#552
File: newton/_src/solvers/mujoco/solver_mujoco.py:0-0
Timestamp: 2025-08-18T15:56:26.587Z
Learning: In Newton's MuJoCo solver, when transforming joint axes from Newton's internal frame to MuJoCo's expected frame, use wp.quat_rotate(joint_rot, axis) not wp.quat_rotate_inv(joint_rot, axis). The joint_rot represents rotation from joint-local to body frame, so forward rotation is correct.
Applied to files:
newton/tests/test_import_usd.py
🧬 Code graph analysis (1)
newton/tests/test_import_usd.py (5)
newton/_src/sim/joints.py (1)
JointType(20-44)newton/_src/core/spatial.py (1)
quat_between_axes(306-329)newton/_src/geometry/types.py (1)
GeoType(25-64)newton/_src/geometry/flags.py (1)
ShapeFlags(30-42)newton/_src/core/types.py (1)
Axis(64-161)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Run GPU Benchmarks (Pull Request)
- GitHub Check: Run GPU Unit Tests on AWS EC2 (Pull Request)
🔇 Additional comments (1)
newton/tests/test_import_usd.py (1)
870-889: Nice: asset resolution is CI-friendly.Switching to
newton.utils.download_asset(...)and walking toanymal_d.usdaremoves machine-specific paths and will work in CI.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
newton/tests/test_import_usd.py (1)
272-279: Add USD guard to prevent failures when USD isn’t installed.This test imports pxr but lacks @skipUnless, unlike the others. It will fail in environments without USD.
+ @unittest.skipUnless(USD_AVAILABLE, "Requires usd-core") def test_mesh_approximation(self): from pxr import Gf, Usd, UsdGeom, UsdPhysics # noqa: PLC0415
♻️ Duplicate comments (2)
newton/tests/test_import_usd.py (2)
559-566: Fix principal-axes quaternion misuse: Normalize() returns magnitude, not a quaternion.This assigns a float to principal_axes and produces wrong inertia rotation.
- principal_axes = mass_api.GetPrincipalAxesAttr().Get().Normalize() - p = np.array(wp.quat_to_matrix(wp.quat(*principal_axes.imaginary, principal_axes.real))).reshape( - (3, 3) - ) + gfq = mass_api.GetPrincipalAxesAttr().Get() + if gfq is not None: + ix, iy, iz = gfq.GetImaginary() + w = gfq.GetReal() + q_wp = wp.normalize(wp.quat(ix, iy, iz, w)) + else: + q_wp = wp.quat_identity() + p = np.array(wp.quat_to_matrix(q_wp)).reshape(3, 3)
701-715: Correct angular drive gain scaling: don’t use degrees(drive_gain_scale).Importer scales angular gains by drive_gain_scale / radians(1) = drive_gain_scale * degrees(1). Current code treats the scale as an angle.
- self.assertAlmostEqual( - float(model.joint_target_ke.numpy()[dof_index]), ke * math.degrees(drive_gain_scale), places=2 - ) + self.assertAlmostEqual( + float(model.joint_target_ke.numpy()[dof_index]), + ke * math.degrees(1.0) * drive_gain_scale, + places=2, + ) ... - self.assertAlmostEqual( - float(model.joint_target_kd.numpy()[dof_index]), kd * math.degrees(drive_gain_scale), places=2 - ) + self.assertAlmostEqual( + float(model.joint_target_kd.numpy()[dof_index]), + kd * math.degrees(1.0) * drive_gain_scale, + places=2, + )
🧹 Nitpick comments (2)
newton/tests/test_import_usd.py (2)
640-643: Use joint_qd_start for O(1) DOF start index.Avoid recomputing prefix sums each loop.
- dof_index = ( - 0 if j <= 0 else sum(int(joint_dof_dim_array[i][0] + joint_dof_dim_array[i][1]) for i in range(j)) - ) + dof_index = int(model.joint_qd_start.numpy()[j])
750-750: Remove unused call.model.shape_body.numpy() return value isn’t used.
- model.shape_body.numpy()
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
newton/_src/utils/import_usd.py(6 hunks)newton/tests/test_import_usd.py(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- newton/_src/utils/import_usd.py
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/utils.py:30-33
Timestamp: 2025-08-12T18:07:17.267Z
Learning: In newton/_src/utils/import_usd.py, the PXR/USD modules are lazily loaded using try-except blocks within the functions (lines 109-111 and 1289-1291) rather than at module import time, making it safe to import parse_usd at the module level without causing import-time failures for users without USD dependencies.
📚 Learning: 2025-08-18T15:56:26.587Z
Learnt from: adenzler-nvidia
PR: newton-physics/newton#552
File: newton/_src/solvers/mujoco/solver_mujoco.py:0-0
Timestamp: 2025-08-18T15:56:26.587Z
Learning: In Newton's MuJoCo solver, when transforming joint axes from Newton's internal frame to MuJoCo's expected frame, use wp.quat_rotate(joint_rot, axis) not wp.quat_rotate_inv(joint_rot, axis). The joint_rot represents rotation from joint-local to body frame, so forward rotation is correct.
Applied to files:
newton/tests/test_import_usd.py
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Run GPU Benchmarks (Pull Request)
- GitHub Check: Run GPU Unit Tests on AWS EC2 (Pull Request)
Signed-off-by: camevor <camevor@nvidia.com> Co-authored-by: jprozorova <jprozorova@nvidia.com>
…s#572) # Description Jax >= 0.6.0 is incompatible with torch 2.7, but is installed by default when running pip install skrl[jax]. We update the installation instructions to override the version of jax to be < 0.6.0 after installing skrl dependencies to avoid the version incompatibilities. ## Type of change - This change requires a documentation update ## Checklist - [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with `./isaaclab.sh --format` - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have updated the changelog and the corresponding version in the extension's `config/extension.toml` file - [ ] I have added my name to the `CONTRIBUTORS.md` or my name already exists there <!-- As you go through the checklist above, you can mark something as done by putting an x character in it For example, - [x] I have done this task - [ ] I have not done this task -->
Signed-off-by: camevor <camevor@nvidia.com> Co-authored-by: jprozorova <jprozorova@nvidia.com>
Description
Newton Migration Guide
Please ensure the migration guide for warp.sim users is up-to-date with the changes made in this MR.
docs/migration.rstis up-to dateBefore your PR is "Ready for review"
newton/tests/test_examples.py)pre-commit run -aSummary by CodeRabbit