Skip to content

Adding geom_gap as custom mujoco variable#1228

Merged
adenzler-nvidia merged 6 commits into
newton-physics:mainfrom
gyeomannvidia:dev/gyeoman/geom_gap
Dec 10, 2025
Merged

Adding geom_gap as custom mujoco variable#1228
adenzler-nvidia merged 6 commits into
newton-physics:mainfrom
gyeomannvidia:dev/gyeoman/geom_gap

Conversation

@gyeomannvidia

@gyeomannvidia gyeomannvidia commented Dec 9, 2025

Copy link
Copy Markdown
Member

Signed-off-by: Gordon Yeoman gyeoman@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 PR.

  • [~ ] The migration guide in docs/migration.rst is up-to date

Before your PR is "Ready for review"

  • Necessary tests have been added and new examples are tested (see newton/tests/test_examples.py)
  • [~ ] Documentation is up-to-date
  • [x ] Code passes formatting and linting checks with pre-commit run -a

Summary by CodeRabbit

  • New Features

    • Added per-shape geometry "gap" support in the MuJoCo solver, including import from MJCF and USD, registration as a custom shape attribute, model field expansion, and runtime synchronization with the solver.
  • Tests

    • Added unit tests validating geom_gap parsing from MJCF and USD, conversion into the solver, and dynamic updates across multiple simulation worlds.

✏️ Tip: You can customize this high-level summary in your review settings.

Signed-off-by: Gordon Yeoman <gyeoman@nvidia.com>
@coderabbitai

coderabbitai Bot commented Dec 9, 2025

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a per-shape MuJoCo custom attribute geom_gap, threads it from importers into SolverMuJoCo, passes it into the MuJoCo update kernel, and surfaces it in per-world MuJoCo geom arrays; includes MJCF, USD, and solver tests validating parsing and propagation.

Changes

Cohort / File(s) Summary
Kernel
newton/_src/solvers/mujoco/kernels.py
Adds shape_geom_gap: wp.array(dtype=float) input and geom_gap: wp.array2d(dtype=float) output to update_geom_properties_kernel, propagating per-shape gap values into per-geom arrays alongside existing per-shape attributes.
Solver integration
newton/_src/solvers/mujoco/solver_mujoco.py
Registers geom_gap as a shape-level MuJoCo custom attribute; reads shape_geom_gap in get_custom_attribute; includes gap in geom_params within add_geoms; expands geom_gap in expand_model_fields; passes shape_geom_gap into the kernel and writes mjw_model.geom_gap from kernel output.
MJCF tests
newton/tests/test_import_mjcf.py
Adds test_geom_gap_parsing to verify MJCF parsing of per-shape gap into model.mujoco.geom_gap, shape counts, and per-shape values.
USD tests
newton/tests/test_import_usd.py
Adds test_geom_gap_parsing (guarded on USD availability) to validate USD mjc:gap parsing into model.mujoco.geom_gap and per-shape values (explicit and defaults).
Solver tests
newton/tests/test_mujoco_solver.py
Adds test_geom_gap_conversion_and_update to check conversion of per-shape geom_gap into MuJoCo per-world arrays and runtime update propagation via SolverMuJoCo APIs.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Importer as Importer (MJCF/USD)
    participant ModelBuilder as ModelBuilder / SolverMuJoCo.register_custom_attributes
    participant Solver as SolverMuJoCo
    participant Kernel as update_geom_properties_kernel
    participant MJW as mjw_model (per-world arrays)

    Note over Importer,ModelBuilder: Import phase
    Importer->>ModelBuilder: produce shape-level attribute `geom_gap` (shape_geom_gap)
    ModelBuilder->>Solver: store `shape_geom_gap` in model.mujoco fields

    Note over Solver,Kernel: Conversion/update phase
    Solver->>Kernel: call update_geom_properties_kernel(..., shape_geom_gap, ...)
    Kernel-->>Solver: return geom_gap (per-geom 2D array)
    Solver->>MJW: write mjw_model.geom_gap from kernel output

    Note over Solver,MJW: Runtime update
    Solver->>Solver: notify_model_changed -> re-run kernel with updated shape_geom_gap
    Kernel-->>MJW: updated geom_gap values propagated to per-world arrays
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas to review closely:
    • Kernel signature, data layout, and all call sites in kernels.py / solver_mujoco.py
    • Indexing and defaulting behavior when shape_geom_gap is absent or shorter than expected
    • Correct registration and retrieval of the geom_gap custom attribute
    • Tests for per-shape ordering and default values in MJCF, USD, and solver update tests

Possibly related PRs

Suggested reviewers

  • adenzler-nvidia
  • eric-heiden
  • vreutskyy

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Adding geom_gap as custom mujoco variable' directly and clearly describes the main change in the pull request, which involves adding a new geom_gap custom attribute throughout the MuJoCo solver.
Docstring Coverage ✅ Passed Docstring coverage is 81.25% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1bbdcf6 and 492d7a5.

📒 Files selected for processing (3)
  • newton/_src/solvers/mujoco/kernels.py (3 hunks)
  • newton/_src/solvers/mujoco/solver_mujoco.py (7 hunks)
  • newton/tests/test_import_mjcf.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • newton/_src/solvers/mujoco/kernels.py
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-08-19T12:27:30.629Z
Learnt from: preist-nvidia
Repo: newton-physics/newton PR: 579
File: newton/examples/example_mujoco.py:350-354
Timestamp: 2025-08-19T12:27:30.629Z
Learning: In Newton examples, Example.use_mujoco is a high-level attribute that controls whether to use MuJoCo solver vs other solvers (like XPBD), while SolverMuJoCo.use_mujoco_cpu controls the backend within MuJoCo (CPU vs Warp). These are separate concepts serving different purposes - the PR rename only applies to the solver parameter, not the Example class attributes.

Applied to files:

  • newton/_src/solvers/mujoco/solver_mujoco.py
📚 Learning: 2025-11-24T08:05:21.390Z
Learnt from: adenzler-nvidia
Repo: newton-physics/newton PR: 1107
File: newton/_src/solvers/mujoco/kernels.py:973-974
Timestamp: 2025-11-24T08:05:21.390Z
Learning: In Newton's MuJoCo solver integration (newton/_src/solvers/mujoco/), the mapping between Newton joints and MuJoCo joints is not 1-to-1. Instead, each Newton DOF maps to a distinct MuJoCo joint. This means that for multi-DOF joints (like D6 with 6 DOFs), there will be 6 corresponding MuJoCo joints, each with its own properties (margin, solimp, solref, etc.). The mapping is done via dof_to_mjc_joint array, ensuring each DOF's properties are written to its own MuJoCo joint without overwriting.

Applied to files:

  • newton/_src/solvers/mujoco/solver_mujoco.py
📚 Learning: 2025-08-19T12:27:30.629Z
Learnt from: preist-nvidia
Repo: newton-physics/newton PR: 579
File: newton/examples/example_mujoco.py:350-354
Timestamp: 2025-08-19T12:27:30.629Z
Learning: In Newton examples, there's a distinction between solver parameters and Example class attributes. The Example class can have its own use_mujoco attribute for controlling example-level behavior (like CUDA graphs, rendering logic), while the solver uses use_mujoco_cpu for backend selection. These serve different purposes and should not be conflated during API renames.

Applied to files:

  • newton/_src/solvers/mujoco/solver_mujoco.py
🧬 Code graph analysis (2)
newton/_src/solvers/mujoco/solver_mujoco.py (1)
newton/_src/sim/model.py (2)
  • ModelAttributeFrequency (49-70)
  • ModelAttributeAssignment (31-46)
newton/tests/test_import_mjcf.py (2)
newton/tests/test_import_usd.py (1)
  • test_geom_gap_parsing (1312-1426)
newton/_src/solvers/mujoco/solver_mujoco.py (2)
  • SolverMuJoCo (80-2490)
  • register_custom_attributes (154-311)
⏰ 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 Tests / Run GPU Unit Tests on AWS EC2
  • GitHub Check: Run GPU Benchmarks / Run GPU Benchmarks on AWS EC2
🔇 Additional comments (5)
newton/_src/solvers/mujoco/solver_mujoco.py (5)

207-218: LGTM: Custom attribute registration for geom_gap.

The registration follows the established pattern for shape-level MuJoCo custom attributes and correctly specifies:

  • Frequency: SHAPE (per-geometry)
  • Assignment: MODEL
  • Type: float32 with default 0.0 (no gap)
  • USD/MJCF attribute names matching MuJoCo conventions

1121-1121: LGTM: Retrieval of geom_gap custom attribute.

The retrieval follows the same pattern as other geometry custom attributes (geom_solimp, geom_solmix) and correctly uses the get_custom_attribute helper function.


1359-1360: LGTM: Setting geom_gap when creating MuJoCo geometries.

The code correctly applies the gap parameter to MuJoCo geom parameters when the custom attribute is available, following the established pattern for other geometry attributes.


1985-1985: LGTM: Including geom_gap in multi-world expansion.

Correctly includes geom_gap in the set of model fields that need to be replicated across multiple worlds, ensuring each world maintains independent gap values.


2241-2274: LGTM: Update path for geom_gap properties.

The implementation correctly:

  1. Retrieves the custom attribute from the Newton model (line 2241)
  2. Passes it as input to the update kernel (line 2263)
  3. Receives the updated values as output (line 2274)

This follows the established pattern for updating per-geometry properties and ensures gap values flow from Newton to MuJoCo correctly.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…ding it back.

Signed-off-by: Gordon Yeoman <gyeoman@nvidia.com>
@codecov

codecov Bot commented Dec 9, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@gyeomannvidia

Copy link
Copy Markdown
Member Author

@coderabbitai help

@coderabbitai

coderabbitai Bot commented Dec 9, 2025

Copy link
Copy Markdown
Contributor

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
    • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
    • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00a5086 and 40238f3.

📒 Files selected for processing (5)
  • newton/_src/solvers/mujoco/kernels.py (3 hunks)
  • newton/_src/solvers/mujoco/solver_mujoco.py (7 hunks)
  • newton/tests/test_import_mjcf.py (1 hunks)
  • newton/tests/test_import_usd.py (1 hunks)
  • newton/tests/test_mujoco_solver.py (3 hunks)
🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
Learnt from: adenzler-nvidia
Repo: newton-physics/newton PR: 1107
File: newton/_src/solvers/mujoco/kernels.py:973-974
Timestamp: 2025-11-24T08:05:21.390Z
Learning: In Newton's MuJoCo solver integration (newton/_src/solvers/mujoco/), the mapping between Newton joints and MuJoCo joints is not 1-to-1. Instead, each Newton DOF maps to a distinct MuJoCo joint. This means that for multi-DOF joints (like D6 with 6 DOFs), there will be 6 corresponding MuJoCo joints, each with its own properties (margin, solimp, solref, etc.). The mapping is done via dof_to_mjc_joint array, ensuring each DOF's properties are written to its own MuJoCo joint without overwriting.
Learnt from: dylanturpin
Repo: newton-physics/newton PR: 806
File: newton/_src/sim/ik/ik_lbfgs_optimizer.py:739-752
Timestamp: 2025-09-22T21:03:39.624Z
Learning: The L-BFGS optimizer in newton/_src/sim/ik/ik_lbfgs_optimizer.py currently intentionally only supports additive updates (assuming n_coords == n_dofs). Velocity space integration for joints with mismatched coordinate/DOF dimensions (like free/ball joints) is planned for future work and should not be flagged as an issue in current reviews.
Learnt from: dylanturpin
Repo: newton-physics/newton PR: 806
File: newton/_src/sim/ik/ik_lbfgs_optimizer.py:638-648
Timestamp: 2025-09-22T21:03:18.367Z
Learning: The L-BFGS optimizer in newton/_src/sim/ik/ik_lbfgs_optimizer.py currently only supports additive updates, meaning it assumes n_coords == n_dofs. Velocity space integration for joints with mismatched coordinate/DOF dimensions (like free/ball joints) is planned for future work.
📚 Learning: 2025-08-12T18:07:17.267Z
Learnt from: nvlukasz
Repo: newton-physics/newton PR: 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-12T18:07:17.267Z
Learnt from: nvlukasz
Repo: newton-physics/newton PR: 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-12T17:51:37.474Z
Learnt from: nvlukasz
Repo: newton-physics/newton PR: 519
File: newton/geometry.py:16-22
Timestamp: 2025-08-12T17:51:37.474Z
Learning: In the Newton public API refactor, common geometry symbols like ParticleFlags and ShapeFlags are now exposed at the top level in newton/__init__.py rather than through newton.geometry. The newton/geometry.py module is intentionally focused only on broad-phase collision detection classes (BroadPhaseAllPairs, BroadPhaseExplicit, BroadPhaseSAP).

Applied to files:

  • newton/_src/solvers/mujoco/kernels.py
  • newton/tests/test_mujoco_solver.py
  • newton/_src/solvers/mujoco/solver_mujoco.py
📚 Learning: 2025-08-25T20:10:59.536Z
Learnt from: dylanturpin
Repo: newton-physics/newton PR: 634
File: newton/examples/ik/example_ik_franka.py:0-0
Timestamp: 2025-08-25T20:10:59.536Z
Learning: In Newton's IK examples, when creating solver arrays with `wp.array(source_array, shape=new_shape)`, this creates a view into the same underlying memory rather than a copy. This means updates to the reshaped array are automatically reflected in the original array without needing explicit copy operations like `wp.copy()`.

Applied to files:

  • newton/_src/solvers/mujoco/kernels.py
📚 Learning: 2025-11-24T08:05:21.390Z
Learnt from: adenzler-nvidia
Repo: newton-physics/newton PR: 1107
File: newton/_src/solvers/mujoco/kernels.py:973-974
Timestamp: 2025-11-24T08:05:21.390Z
Learning: In Newton's MuJoCo solver integration (newton/_src/solvers/mujoco/), the mapping between Newton joints and MuJoCo joints is not 1-to-1. Instead, each Newton DOF maps to a distinct MuJoCo joint. This means that for multi-DOF joints (like D6 with 6 DOFs), there will be 6 corresponding MuJoCo joints, each with its own properties (margin, solimp, solref, etc.). The mapping is done via dof_to_mjc_joint array, ensuring each DOF's properties are written to its own MuJoCo joint without overwriting.

Applied to files:

  • newton/_src/solvers/mujoco/kernels.py
  • newton/tests/test_mujoco_solver.py
  • newton/_src/solvers/mujoco/solver_mujoco.py
📚 Learning: 2025-08-19T12:27:30.629Z
Learnt from: preist-nvidia
Repo: newton-physics/newton PR: 579
File: newton/examples/example_mujoco.py:350-354
Timestamp: 2025-08-19T12:27:30.629Z
Learning: In Newton examples, there's a distinction between solver parameters and Example class attributes. The Example class can have its own use_mujoco attribute for controlling example-level behavior (like CUDA graphs, rendering logic), while the solver uses use_mujoco_cpu for backend selection. These serve different purposes and should not be conflated during API renames.

Applied to files:

  • newton/tests/test_mujoco_solver.py
  • newton/_src/solvers/mujoco/solver_mujoco.py
📚 Learning: 2025-10-10T10:47:41.082Z
Learnt from: nvtw
Repo: newton-physics/newton PR: 899
File: newton/tests/test_rigid_contact.py:214-268
Timestamp: 2025-10-10T10:47:41.082Z
Learning: In `newton/tests/test_rigid_contact.py`, using `add_shape_plane(width=0, length=0)` for an infinite plane works correctly with the collision system and does not cause degenerate AABB issues in the test scenario `test_shape_collisions_gjk_mpr_multicontact`.

Applied to files:

  • newton/tests/test_mujoco_solver.py
📚 Learning: 2025-10-24T07:56:14.792Z
Learnt from: nvtw
Repo: newton-physics/newton PR: 981
File: newton/_src/geometry/collision_convex.py:180-289
Timestamp: 2025-10-24T07:56:14.792Z
Learning: In newton/_src/geometry/collision_convex.py, the single-contact solver (create_solve_convex_single_contact) intentionally returns count=1 even when shapes are separated (signed_distance > contact_threshold). The calling code is responsible for deciding whether to accept the contact based on the signed distance value. This design pushes filtering responsibility to the caller.

Applied to files:

  • newton/tests/test_mujoco_solver.py
📚 Learning: 2025-08-19T12:27:30.629Z
Learnt from: preist-nvidia
Repo: newton-physics/newton PR: 579
File: newton/examples/example_mujoco.py:350-354
Timestamp: 2025-08-19T12:27:30.629Z
Learning: In Newton examples, Example.use_mujoco is a high-level attribute that controls whether to use MuJoCo solver vs other solvers (like XPBD), while SolverMuJoCo.use_mujoco_cpu controls the backend within MuJoCo (CPU vs Warp). These are separate concepts serving different purposes - the PR rename only applies to the solver parameter, not the Example class attributes.

Applied to files:

  • newton/_src/solvers/mujoco/solver_mujoco.py
🧬 Code graph analysis (3)
newton/tests/test_import_usd.py (2)
newton/tests/test_import_mjcf.py (2)
  • test_geom_gap_parsing (1431-1472)
  • test_geom_margin_parsing (1474-1515)
newton/_src/solvers/mujoco/solver_mujoco.py (2)
  • SolverMuJoCo (80-2504)
  • register_custom_attributes (154-323)
newton/tests/test_import_mjcf.py (2)
newton/tests/test_import_usd.py (2)
  • test_geom_gap_parsing (1312-1426)
  • test_geom_margin_parsing (1429-1543)
newton/_src/solvers/mujoco/solver_mujoco.py (2)
  • SolverMuJoCo (80-2504)
  • register_custom_attributes (154-323)
newton/tests/test_mujoco_solver.py (1)
newton/_src/solvers/mujoco/solver_mujoco.py (1)
  • register_custom_attributes (154-323)
🪛 Ruff (0.14.8)
newton/tests/test_import_usd.py

1314-1314: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


1431-1431: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

⏰ 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 Tests / Run GPU Unit Tests on AWS EC2
  • GitHub Check: Run GPU Benchmarks / Run GPU Benchmarks on AWS EC2
🔇 Additional comments (7)
newton/_src/solvers/mujoco/kernels.py (2)

1194-1195: LGTM! Kernel signature properly extended for geom_gap and geom_margin.

The additions follow the established pattern for custom MuJoCo shape attributes (matching the shape_geom_solimp/shape_geom_solmix convention).

Also applies to: 1205-1206


1249-1256: LGTM! Attribute propagation logic is correct.

The conditional blocks properly propagate shape-level gap and margin attributes to per-geom outputs, following the same pattern as the existing solimp/solmix handling.

newton/tests/test_import_usd.py (2)

1311-1427: LGTM! USD geom_gap parsing test is correct.

The test properly validates that the mjc:gap USD attribute is parsed and exposed via model.mujoco.geom_gap, with both explicit values (0.8, 0.7) and defaults (0.0) being verified.

Note: The static analysis hint about unused noqa directive on line 1314 can be safely ignored - this is a common pattern for conditional imports throughout the file.


1428-1544: LGTM! USD geom_margin parsing test is correct.

The test properly validates that the mjc:margin USD attribute is parsed and exposed via model.mujoco.geom_margin, with both explicit values (0.8, 0.7) and defaults (0.0) being verified.

Note: The static analysis hint about unused noqa directive on line 1431 can be safely ignored - this is a common pattern for conditional imports throughout the file.

newton/tests/test_mujoco_solver.py (2)

2401-2477: Geom-gap test correctly exercises multi-world mapping and runtime updates

The test_geom_gap_conversion_and_update flow (per-world initialization via shape_world, verification through mjc_geom_to_newton_shape, and notify_model_changed(SHAPE_PROPERTIES) updates) is consistent with existing solimp/solmix tests and should robustly catch mapping/indexing bugs for geom_gap. No issues spotted.

Also applies to: 2481-2497


2499-2595: Geom-margin test mirrors the gap coverage and looks sound

test_geom_margin_conversion_and_update mirrors the gap test structure with per-world initialization, conversion verification, and runtime update checks for geom_margin. The use of shape_world and mjc_geom_to_newton_shape keeps it robust for multi-world setups. Implementation looks correct.

newton/_src/solvers/mujoco/solver_mujoco.py (1)

207-230: geom_gap/geom_margin integration is consistent across registration, conversion, expansion, and updates

The new geom_gap/geom_margin attributes are:

  • Declared as SHAPE/MODEL custom attributes with appropriate defaults and USD/MJCF names.
  • Pulled via get_custom_attribute and threaded into geom_params as gap/margin during _convert_to_mjc, matching MuJoCo’s per-geom fields.
  • Included in expand_model_fields so they tile correctly across nworld.
  • Read in update_geom_properties as optional per-shape arrays and written into mjw_model.geom_gap/geom_margin alongside existing friction and solimp/solmix properties.

This matches the existing solimp/solmix patterns and should behave correctly for multi-world models, as exercised by the new tests. No issues found.

Also applies to: 1133-1134, 1372-1375, 1995-1997, 2252-2253, 2275-2277, 2287-2288

Comment thread newton/tests/test_import_mjcf.py
Comment thread newton/tests/test_import_mjcf.py Outdated
Comment thread newton/tests/test_mujoco_solver.py Outdated
Comment thread newton/_src/solvers/mujoco/solver_mujoco.py Outdated
This was linked to issues Dec 10, 2025
Signed-off-by: Gordon Yeoman <gyeoman@nvidia.com>
Signed-off-by: Gordon Yeoman <gyeoman@nvidia.com>
… a separate PR.

Signed-off-by: Gordon Yeoman <gyeoman@nvidia.com>
@gyeomannvidia gyeomannvidia changed the title Adding geom_gap and geom_margin as custom mujoco variables Adding geom_gap as custom mujoco variable Dec 10, 2025

@adenzler-nvidia adenzler-nvidia left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one small nitpick, thanks a lot.

Comment thread newton/tests/test_import_mjcf.py
@adenzler-nvidia

Copy link
Copy Markdown
Member

also, the failing tests are not your fault, looks like they have been flaky. I hope a retry fixes this.

@gyeomannvidia

Copy link
Copy Markdown
Member Author

I removed everything related to geom_margin and renamed the PR. I'll need to work out what work needs to be done for geom_margin.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
newton/tests/test_import_mjcf.py (1)

1431-1473: Minor: update comment to mention gap rather than solimp

The test logic looks correct, but the inline comment above expected_values still talks about “solimp” values; it should describe the gap attribute and the default of 0.0 for shapes without an explicit gap to avoid confusion for future readers.

newton/tests/test_import_usd.py (1)

1314-1314: Clean up unused noqa directive.

The static analysis tool flags this noqa directive as unused. Remove it for cleaner code.

Apply this diff:

-        """Test that geom_gap attribute is parsed correctly from USD."""
-        from pxr import Usd  # noqa: PLC0415
+        """Test that geom_gap attribute is parsed correctly from USD."""
+        from pxr import Usd
📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 40238f3 and 1bbdcf6.

📒 Files selected for processing (5)
  • newton/_src/solvers/mujoco/kernels.py (3 hunks)
  • newton/_src/solvers/mujoco/solver_mujoco.py (7 hunks)
  • newton/tests/test_import_mjcf.py (1 hunks)
  • newton/tests/test_import_usd.py (1 hunks)
  • newton/tests/test_mujoco_solver.py (1 hunks)
🧰 Additional context used
🧠 Learnings (10)
📚 Learning: 2025-08-12T18:07:17.267Z
Learnt from: nvlukasz
Repo: newton-physics/newton PR: 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-12T18:07:17.267Z
Learnt from: nvlukasz
Repo: newton-physics/newton PR: 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-12T17:51:37.474Z
Learnt from: nvlukasz
Repo: newton-physics/newton PR: 519
File: newton/geometry.py:16-22
Timestamp: 2025-08-12T17:51:37.474Z
Learning: In the Newton public API refactor, common geometry symbols like ParticleFlags and ShapeFlags are now exposed at the top level in newton/__init__.py rather than through newton.geometry. The newton/geometry.py module is intentionally focused only on broad-phase collision detection classes (BroadPhaseAllPairs, BroadPhaseExplicit, BroadPhaseSAP).

Applied to files:

  • newton/_src/solvers/mujoco/kernels.py
📚 Learning: 2025-08-25T20:10:59.536Z
Learnt from: dylanturpin
Repo: newton-physics/newton PR: 634
File: newton/examples/ik/example_ik_franka.py:0-0
Timestamp: 2025-08-25T20:10:59.536Z
Learning: In Newton's IK examples, when creating solver arrays with `wp.array(source_array, shape=new_shape)`, this creates a view into the same underlying memory rather than a copy. This means updates to the reshaped array are automatically reflected in the original array without needing explicit copy operations like `wp.copy()`.

Applied to files:

  • newton/_src/solvers/mujoco/kernels.py
📚 Learning: 2025-09-22T21:08:31.901Z
Learnt from: dylanturpin
Repo: newton-physics/newton PR: 806
File: newton/examples/ik/example_ik_franka.py:121-123
Timestamp: 2025-09-22T21:08:31.901Z
Learning: In the newton physics framework, when creating warp arrays for IK solver joint variables using wp.array(self.model.joint_q, shape=(1, coord_count)), the resulting array acts as a reference/pointer to the original model's joint coordinates, so updates from the IK solver automatically reflect in the model's joint_q buffer used for rendering.

Applied to files:

  • newton/_src/solvers/mujoco/kernels.py
📚 Learning: 2025-09-22T21:08:31.901Z
Learnt from: dylanturpin
Repo: newton-physics/newton PR: 806
File: newton/examples/ik/example_ik_franka.py:121-123
Timestamp: 2025-09-22T21:08:31.901Z
Learning: In the newton physics framework, when creating warp arrays for IK solver joint variables using wp.array(self.model.joint_q, shape=(1, coord_count)), the resulting array acts as a reference/pointer to the original model's joint coordinates, so updates from the IK solver automatically reflect in the model's joint_q buffer used for rendering, despite the general warp documentation suggesting copies are made by default.

Applied to files:

  • newton/_src/solvers/mujoco/kernels.py
📚 Learning: 2025-08-18T15:56:26.587Z
Learnt from: adenzler-nvidia
Repo: newton-physics/newton PR: 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/_src/solvers/mujoco/kernels.py
📚 Learning: 2025-11-24T08:05:21.390Z
Learnt from: adenzler-nvidia
Repo: newton-physics/newton PR: 1107
File: newton/_src/solvers/mujoco/kernels.py:973-974
Timestamp: 2025-11-24T08:05:21.390Z
Learning: In Newton's MuJoCo solver integration (newton/_src/solvers/mujoco/), the mapping between Newton joints and MuJoCo joints is not 1-to-1. Instead, each Newton DOF maps to a distinct MuJoCo joint. This means that for multi-DOF joints (like D6 with 6 DOFs), there will be 6 corresponding MuJoCo joints, each with its own properties (margin, solimp, solref, etc.). The mapping is done via dof_to_mjc_joint array, ensuring each DOF's properties are written to its own MuJoCo joint without overwriting.

Applied to files:

  • newton/_src/solvers/mujoco/kernels.py
  • newton/_src/solvers/mujoco/solver_mujoco.py
📚 Learning: 2025-08-19T12:27:30.629Z
Learnt from: preist-nvidia
Repo: newton-physics/newton PR: 579
File: newton/examples/example_mujoco.py:350-354
Timestamp: 2025-08-19T12:27:30.629Z
Learning: In Newton examples, Example.use_mujoco is a high-level attribute that controls whether to use MuJoCo solver vs other solvers (like XPBD), while SolverMuJoCo.use_mujoco_cpu controls the backend within MuJoCo (CPU vs Warp). These are separate concepts serving different purposes - the PR rename only applies to the solver parameter, not the Example class attributes.

Applied to files:

  • newton/_src/solvers/mujoco/solver_mujoco.py
📚 Learning: 2025-08-19T12:27:30.629Z
Learnt from: preist-nvidia
Repo: newton-physics/newton PR: 579
File: newton/examples/example_mujoco.py:350-354
Timestamp: 2025-08-19T12:27:30.629Z
Learning: In Newton examples, there's a distinction between solver parameters and Example class attributes. The Example class can have its own use_mujoco attribute for controlling example-level behavior (like CUDA graphs, rendering logic), while the solver uses use_mujoco_cpu for backend selection. These serve different purposes and should not be conflated during API renames.

Applied to files:

  • newton/_src/solvers/mujoco/solver_mujoco.py
🧬 Code graph analysis (2)
newton/tests/test_import_usd.py (1)
newton/_src/solvers/mujoco/solver_mujoco.py (1)
  • register_custom_attributes (154-311)
newton/_src/solvers/mujoco/solver_mujoco.py (2)
newton/_src/sim/builder.py (3)
  • add_custom_attribute (640-685)
  • ModelBuilder (70-5934)
  • CustomAttribute (312-402)
newton/_src/sim/model.py (2)
  • ModelAttributeFrequency (49-70)
  • ModelAttributeAssignment (31-46)
🪛 Ruff (0.14.8)
newton/tests/test_import_usd.py

1314-1314: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

⏰ 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 Tests / Run GPU Unit Tests on AWS EC2
  • GitHub Check: Run GPU Benchmarks / Run GPU Benchmarks on AWS EC2
🔇 Additional comments (7)
newton/tests/test_mujoco_solver.py (1)

2401-2497: geom_gap conversion/update test is consistent and well-scoped

This test mirrors the existing per‑shape geom_solimp/geom_solmix coverage, correctly exercises multi‑world mapping via mjc_geom_to_newton_shape, and validates both initial conversion and notify_model_changed(SHAPE_PROPERTIES) updates into geom_gap. I don’t see any functional issues here.

newton/_src/solvers/mujoco/kernels.py (1)

1194-1205: geom_gap wiring in update_geom_properties_kernel matches existing patterns; verify call sites

Adding shape_geom_gap as an input and writing it into per‑world geom_gap mirrors how shape_geom_solimp/shape_geom_solmix are handled, and it lines up with contact_params/convert_newton_contacts_to_mjwarp_kernel using geom_gap to compute margin - gap for contact_includemargin. The kernel logic itself looks sound; the main thing to double‑check is that every launch of update_geom_properties_kernel has been updated to pass the new shape_geom_gap and geom_gap arguments in the correct order so you don’t hit runtime signature mismatches.

You can quickly list the call sites with:

#!/bin/bash
# List all calls to update_geom_properties_kernel to verify their argument lists.
rg -n "update_geom_properties_kernel" newton -S

Also applies to: 1247-1249

newton/_src/solvers/mujoco/solver_mujoco.py (5)

207-218: Verify that custom attribute is the correct approach for geom_gap.

Based on a past review comment, geom_margin should be populated from shape_contact_margin rather than as a custom attribute. Before finalizing this PR, confirm whether geom_gap should similarly be populated from an existing Newton shape property, or if the custom attribute approach is intentional and correct.

As per past review comments, verify that custom attribute registration is the intended approach for this property.


1121-1121: LGTM!

Correctly retrieves the custom attribute following the established pattern.


1359-1360: LGTM!

Correctly passes geom_gap to MuJoCo geom parameters when available, following the established pattern.


1981-1981: LGTM!

Correctly adds geom_gap to the expansion list for multi-world support.


2237-2237: LGTM!

Correctly wires geom_gap through the update_geom_properties flow, maintaining consistency with other shape-level custom attributes (geom_solimp, geom_solmix).

Also applies to: 2259-2259, 2270-2270

@adenzler-nvidia adenzler-nvidia added this pull request to the merge queue Dec 10, 2025
Merged via the queue into newton-physics:main with commit d66ef03 Dec 10, 2025
24 of 28 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Dec 16, 2025
3 tasks
eric-heiden pushed a commit to eric-heiden/newton that referenced this pull request Jan 28, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Feb 26, 2026
5 tasks
mmacklin pushed a commit to mmacklin/newton that referenced this pull request Apr 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for geom_gap Add support for geom_margin

2 participants