Improve the logic with njmax and nconmax#787
Conversation
📝 WalkthroughWalkthroughMakes Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Solver as SolverMuJoCo
participant MJ as MuJoCo (model/data)
participant Warp as mujoco_warp
User->>Solver: __init__(..., njmax=None|int, ncon_per_env=None|int)
Solver->>MJ: read mj_data.ncon, mj_data.nefc
note right of Solver #DDEBF7: compute nconmax and njmax\n(use provided values or default to MJ data)\nclamp to MJ limits if needed
alt provided values exceed MJ limits
Solver-->>User: [WARNING] adjusted ncon_per_env or njmax
end
Solver->>Warp: put_data(..., nconmax=clamped_nconmax, njmax=clamped_njmax)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
newton/_src/solvers/mujoco/solver_mujoco.py (1)
2441-2446: Pass total njmax to put_data.After the per‑env fix, pass
njmax_total.Apply this diff:
self.mjw_data = mujoco_warp.put_data( self.mj_model, self.mj_data, nworld=nworld, nconmax=nconmax, - njmax=njmax, + njmax=njmax_total, )
🧹 Nitpick comments (2)
newton/_src/solvers/mujoco/solver_mujoco.py (1)
1214-1214: Doc mismatch: njmax is Optional now.Update the docstring to reflect
njmax: int | Noneand thatNoneuses MuJoCo’s model size. Also clarify whether it’s per‑env or total (see njmax handling below).newton/tests/test_rigid_contact.py (1)
186-186: njmax argument is per‑env (per your comment in solver); test is fine for single‑env but will under‑allocate for multi‑env.If this suite ever runs with multiple envs per model, either multiply by env count or rely on the solver default (MuJoCo model size). Optionally set
ncon_per_envfor deterministic capacity.Optional tweak:
- "mujoco_warp": lambda model: newton.solvers.SolverMuJoCo(model, use_mujoco_cpu=False, njmax=100), + "mujoco_warp": lambda model: newton.solvers.SolverMuJoCo(model, use_mujoco_cpu=False, njmax=100, ncon_per_env=64),
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
newton/_src/solvers/mujoco/solver_mujoco.py(3 hunks)newton/tests/test_rigid_contact.py(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-19T12:27:30.629Z
Learnt from: preist-nvidia
PR: newton-physics/newton#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/tests/test_rigid_contact.pynewton/_src/solvers/mujoco/solver_mujoco.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). (3)
- GitHub Check: Run GPU Benchmarks (Pull Request)
- GitHub Check: run-newton-tests / newton-unittests (windows-latest)
- GitHub Check: run-newton-tests / newton-unittests (ubuntu-latest)
🔇 Additional comments (1)
newton/_src/solvers/mujoco/solver_mujoco.py (1)
2424-2431: Use MjModel.nconmax and warnings.warn (replace Data.ncon / print)Verified: MjModel.nconmax exists and is the runtime maximum number of contacts. Using self.mj_data.ncon can be zero at init — use int(self.mj_model.nconmax) * nworld instead; replace prints with warnings.warn and remove the now-unused rigid_contact_max assignment.
File: newton/_src/solvers/mujoco/solver_mujoco.py Lines: 2424-2431
- # TODO find better heuristics to determine nconmax and njmax - if disable_contacts: - nconmax = 0 - else: - if ncon_per_env is not None: - rigid_contact_max = nworld * ncon_per_env - if rigid_contact_max < self.mj_data.ncon * nworld: - print(f"[WARNING] Value for ncon_per_env is changed from {ncon_per_env} to {self.mj_data.ncon}") - nconmax = self.mj_data.ncon * nworld - else: - nconmax = rigid_contact_max - else: - nconmax = self.mj_data.ncon * nworld - rigid_contact_max = model.rigid_contact_max + # Default nconmax to MuJoCo model size; allow per‑env override with clamping + if disable_contacts: + nconmax = 0 + else: + if ncon_per_env is not None: + rigid_contact_max = nworld * ncon_per_env + mj_nconmax_total = int(self.mj_model.nconmax) * nworld + if rigid_contact_max < mj_nconmax_total: + warnings.warn( + f"ncon_per_env={ncon_per_env} is below MuJoCo nconmax per env ({int(self.mj_model.nconmax)}); clamping to {int(self.mj_model.nconmax)}.", + stacklevel=2, + ) + nconmax = mj_nconmax_total + else: + nconmax = rigid_contact_max + else: + nconmax = int(self.mj_model.nconmax) * nworld
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
newton/examples/selection/example_selection_articulations.py (1)
119-119: Avoid hard‑coding njmax/ncon_per_env in examples; rely on MuJoCo defaults or expose CLI flags.Hard‑coding small caps here can trigger runtime “[WARNING] … is changed to …” when env count or model complexity varies. Let the solver use MuJoCo‑derived defaults (None) or make these user‑tunable via CLI.
Suggested minimal change:
- self.solver = newton.solvers.SolverMuJoCo(self.model, njmax=100, ncon_per_env=50) + self.solver = newton.solvers.SolverMuJoCo(self.model)Optional (outside this hunk): add CLI knobs and pass them through if provided.
newton/examples/robot/example_robot_anymal_d.py (1)
87-93: Prefer defaults (None) or CLI for ncon_per_env; 20 per env is brittle and may warn under load.Keep examples resilient across num‑envs/models by removing the cap or exposing it via CLI.
- self.solver = newton.solvers.SolverMuJoCo( - self.model, - cone=mujoco.mjtCone.mjCONE_ELLIPTIC, - impratio=100, - iterations=100, - ls_iterations=50, - ncon_per_env=20, - ) + self.solver = newton.solvers.SolverMuJoCo( + self.model, + cone=mujoco.mjtCone.mjCONE_ELLIPTIC, + impratio=100, + iterations=100, + ls_iterations=50, + )Note: You currently compute contacts via
self.model.collide(...)for rendering; if using MuJoCo contacts, considerpopulate_contactsto keep visuals consistent with the solver.newton/examples/sensors/example_sensor_contact.py (1)
142-142: Make njmax/ncon_per_env optional or user‑configurable; fixed 100/100 can cause noisy overrides.Defaulting to MuJoCo‑clamped values reduces surprise and warning spam across different env counts.
- self.solver = newton.solvers.SolverMuJoCo(self.model, njmax=100, ncon_per_env=100) + self.solver = newton.solvers.SolverMuJoCo(self.model)If you need deterministic caps for demos, add CLI args (e.g.,
--njmax,--ncon-per-env) and pass them when set.
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
newton/examples/robot/example_robot_anymal_c_walk.py(1 hunks)newton/examples/robot/example_robot_anymal_d.py(1 hunks)newton/examples/robot/example_robot_h1.py(1 hunks)newton/examples/robot/example_robot_humanoid.py(1 hunks)newton/examples/robot/example_robot_policy.py(1 hunks)newton/examples/selection/example_selection_articulations.py(1 hunks)newton/examples/selection/example_selection_materials.py(1 hunks)newton/examples/sensors/example_sensor_contact.py(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-08-19T12:27:30.629Z
Learnt from: preist-nvidia
PR: newton-physics/newton#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/examples/robot/example_robot_anymal_c_walk.pynewton/examples/robot/example_robot_policy.pynewton/examples/selection/example_selection_articulations.pynewton/examples/selection/example_selection_materials.pynewton/examples/sensors/example_sensor_contact.pynewton/examples/robot/example_robot_humanoid.pynewton/examples/robot/example_robot_h1.pynewton/examples/robot/example_robot_anymal_d.py
📚 Learning: 2025-08-19T12:27:30.629Z
Learnt from: preist-nvidia
PR: newton-physics/newton#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/examples/robot/example_robot_anymal_c_walk.pynewton/examples/robot/example_robot_policy.pynewton/examples/selection/example_selection_articulations.pynewton/examples/selection/example_selection_materials.pynewton/examples/sensors/example_sensor_contact.pynewton/examples/robot/example_robot_humanoid.pynewton/examples/robot/example_robot_h1.pynewton/examples/robot/example_robot_anymal_d.py
📚 Learning: 2025-08-27T19:05:44.697Z
Learnt from: Milad-Rakhsha-NV
PR: newton-physics/newton#535
File: newton/tests/test_examples.py:320-414
Timestamp: 2025-08-27T19:05:44.697Z
Learning: In newton/examples/__init__.py, the robot policy example is registered with the key "robot_policy" (not "robot.example_robot_policy"), so tests should reference it as name="robot_policy".
Applied to files:
newton/examples/robot/example_robot_policy.py
🧬 Code graph analysis (2)
newton/examples/selection/example_selection_materials.py (1)
newton/_src/solvers/mujoco/solver_mujoco.py (1)
SolverMuJoCo(1135-2760)
newton/examples/robot/example_robot_humanoid.py (1)
newton/_src/solvers/mujoco/solver_mujoco.py (1)
SolverMuJoCo(1135-2760)
⏰ 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 Unit Tests on AWS EC2 (Pull Request)
- GitHub Check: Run GPU Benchmarks (Pull Request)
- GitHub Check: run-newton-tests / newton-unittests (windows-latest)
- GitHub Check: run-newton-tests / newton-unittests (ubuntu-latest)
🔇 Additional comments (5)
newton/examples/robot/example_robot_policy.py (1)
268-274: LGTM! The explicitnjmaxparameter improves clarity.The addition of
njmax=100to theSolverMuJoCoconstructor is appropriate and aligns with the PR's API changes to make constraint limits explicit rather than relying on implicit defaults.newton/examples/robot/example_robot_anymal_c_walk.py (1)
145-145: LGTM! Appropriate constraint limit for this simulation.Setting
njmax=50is reasonable for a single Anymal robot simulation and aligns with the PR's API changes.newton/examples/robot/example_robot_humanoid.py (1)
70-70: LGTM! Consistent with other multi-environment examples.The
njmax=100value is appropriate for multiple humanoid environments and consistent with other robot examples in the PR.newton/examples/selection/example_selection_materials.py (1)
97-97: Consider ifnjmax=50is sufficient for 16 ant environments.The example defaults to 16 environments with ant robots. Given that other multi-environment examples use
njmax=100, you may want to verify thatnjmax=50provides adequate constraint capacity for all environments, especially if users increase--num-envs.newton/examples/robot/example_robot_h1.py (1)
79-79: LGTM! Comprehensive solver configuration.The addition of
njmax=100alongside the existingiterationsandls_iterationsparameters provides complete control over the solver's constraint handling.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
newton/_src/solvers/mujoco/solver_mujoco.py (1)
1764-1765: Update docstring comment to clarify per-environment units.The comment states "per world" but the parameter represents constraints per environment. This should be clarified to avoid confusion.
- njmax: int | None = None, # number of constraints per world + njmax: int | None = None, # number of constraints per environment
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
newton/_src/solvers/mujoco/solver_mujoco.py(4 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-19T12:27:30.629Z
Learnt from: preist-nvidia
PR: newton-physics/newton#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
⏰ 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 Unit Tests on AWS EC2 (Pull Request)
- GitHub Check: Run GPU Benchmarks (Pull Request)
🔇 Additional comments (4)
newton/_src/solvers/mujoco/solver_mujoco.py (4)
1213-1214: LGTM on the API change.The docstring accurately describes the parameter as optional and mentions that the maximum value is estimated from the model when None is provided.
1239-1240: LGTM on updated docstring and parameter descriptions.The updated docstrings clearly explain that larger of user-provided or default values will be used, which accurately reflects the clamping behavior implemented.
2479-2488: Use model.njmax instead of mj_data.ncon for constraint estimation.The current logic uses
mj_data.nconwhich represents the current number of contacts, but for constraint estimation we should use the model's maximum contact capacity. Also, the scaling bynworldshould happen consistently for both user-provided and default values.Based on the past review comments, this should use
self.mj_data.nconas the per-environment baseline and scale bynworldfor the total constraint capacity.if disable_contacts: nconmax = 0 else: if ncon_per_env is not None: - rigid_contact_max = nworld * ncon_per_env - if rigid_contact_max < self.mj_data.ncon * nworld: + if ncon_per_env < self.mj_data.ncon: warnings.warn( - f"[WARNING] Value for ncon_per_env is changed from {ncon_per_env} to {self.mj_data.ncon} following a MjWarp requirement.", + f"Value for ncon_per_env is changed from {ncon_per_env} to {self.mj_data.ncon} following a MjWarp requirement.", stacklevel=2, ) - nconmax = self.mj_data.ncon * nworld - else: - nconmax = rigid_contact_max + ncon_per_env = self.mj_data.ncon + nconmax = ncon_per_env * nworld else: nconmax = self.mj_data.ncon * nworld
2490-2499: Use model.njmax and scale properly for total constraint allocation.The current implementation uses
mj_data.nefc(current constraint count) instead of the model's maximum constraint capacity. This can under-allocate constraints for vectorized environments.Based on past review feedback, this should be corrected to use
self.mj_model.njmaxand scale bynworld:if njmax is not None: - if njmax < self.mj_data.nefc: + mj_njmax = int(self.mj_model.njmax) + if njmax < mj_njmax: warnings.warn( - f"[WARNING] Value for njmax is changed from {njmax} to {self.mj_data.nefc} following a MjWarp requirement.", + f"njmax={njmax} is below MuJoCo njmax per env ({mj_njmax}); clamping to {mj_njmax}.", stacklevel=2, ) - njmax = self.mj_data.nefc + njmax = mj_njmax + njmax_total = njmax * nworld else: - njmax = self.mj_data.nefc + njmax_total = int(self.mj_model.njmax) * nworld ```Based on the search results, I can see that MuJoCo's Python bindings expose model fields, but let me search for more specific information about njmax field:Let me search more specifically for the njmax field in mjModel:Based on my search results and the existing review comments, I can confirm that the approach should indeed use `mj_model.njmax` instead of `mj_data.nefc`. The search results confirm that MuJoCo preallocates all the memory needed at runtime in mjData, and the model structure contains allocation parameters. However, I need to also consider that the past review comment uses `self.mj_data.nefc` as the baseline. The final approach should pass the correctly scaled total to `put_data`. The key issue is that `njmax` is expected to be a total value for `put_data`, not per-environment, so the final line should pass `njmax_total` instead of `njmax`. ```diff + njmax_total = njmax * nworld self.mjw_data = mujoco_warp.put_data( self.mj_model, self.mj_data, nworld=nworld, nconmax=nconmax, - njmax=njmax, + njmax=njmax_total, )
preist-nvidia
left a comment
There was a problem hiding this comment.
Thanks for the fixes! Minor grammar thing in the warning, otherwise LGTM.
…e_njmax_ncon_logic
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
newton/_src/solvers/mujoco/solver_mujoco.py (1)
1764-1764: Inline comment: “per world” → “per environment (scaled to total)”.Avoid “world” here since it depends on
separate_envs_to_worlds; keep public units per‑env and state scaling explicitly.Apply:
- njmax: int | None = None, # number of constraints per world + njmax: int | None = None, # maximum scalar constraint rows per environment (scaled by nworld)
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
newton/_src/solvers/mujoco/solver_mujoco.py(6 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-19T12:27:30.629Z
Learnt from: preist-nvidia
PR: newton-physics/newton#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-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/_src/solvers/mujoco/solver_mujoco.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 Unit Tests on AWS EC2 (Pull Request)
- GitHub Check: Run GPU Benchmarks (Pull Request)
🔇 Additional comments (5)
newton/_src/solvers/mujoco/solver_mujoco.py (5)
1498-1502: LGTM on clarifying comments.The added comments make the CPU vs Warp branches clearer.
Also applies to: 1503-1507
1543-1547: LGTM on clarifying comments.Clearer distinction between MjWarp Data and MjData paths.
Also applies to: 1551-1558
2478-2489: nconmax derived from runtime ncon — can under‑allocate and trigger put_data errors; clamp to model.nconmax and scale.Using
self.mj_data.ncon(current contact count) as the default/lower bound can be 0 at init and below MuJoCo’s compiled limit;mujoco_warp.put_datawill reject too‑small allocations. Useself.mj_model.nconmaxper‑env, scale bynworld, and warn without the “[WARNING]” prefix.Apply:
- if ncon_per_env is not None: - rigid_contact_max = nworld * ncon_per_env - if rigid_contact_max < self.mj_data.ncon * nworld: - warnings.warn( - f"[WARNING] Value for ncon_per_env is changed from {ncon_per_env} to {self.mj_data.ncon} following an MjWarp requirement.", - stacklevel=2, - ) - nconmax = self.mj_data.ncon * nworld - else: - nconmax = rigid_contact_max - else: - nconmax = self.mj_data.ncon * nworld + if ncon_per_env is not None: + mj_nconmax = int(self.mj_model.nconmax) + if ncon_per_env < mj_nconmax: + warnings.warn( + f"ncon_per_env={ncon_per_env} is below MuJoCo per-env nconmax ({mj_nconmax}); clamping to {mj_nconmax}.", + stacklevel=2, + ) + ncon_per_env = mj_nconmax + nconmax = ncon_per_env * nworld + else: + nconmax = int(self.mj_model.nconmax) * nworld#!/bin/bash rg -nC2 -e '\bncon\b' --type=py
2490-2499: njmax clamped to Data.nefc and not scaled — risks under‑allocation; use model.njmax and scale by nworld.Baseline must be
self.mj_model.njmax(per‑env). Also compute a total (* nworld) forput_data. Current behavior can be below model size and fail; also repeats a previously flagged issue.Apply:
- if njmax is not None: - if njmax < self.mj_data.nefc: - warnings.warn( - f"[WARNING] Value for njmax is changed from {njmax} to {self.mj_data.nefc} following an MjWarp requirement.", - stacklevel=2, - ) - njmax = self.mj_data.nefc - else: - njmax = self.mj_data.nefc + if njmax is not None: + mj_njmax = int(self.mj_model.njmax) + if njmax < mj_njmax: + warnings.warn( + f"njmax={njmax} is below MuJoCo per-env njmax ({mj_njmax}); clamping to {mj_njmax}.", + stacklevel=2, + ) + njmax = mj_njmax + njmax_total = njmax * nworld + else: + njmax_total = int(self.mj_model.njmax) * nworldAnd pass the total to MjWarp:
- njmax=njmax, + njmax=njmax_total,#!/bin/bash rg -n 'nefc|njmax_total|put_data\(.+njmax=' --type=py
1239-1241: Clarify MuJoCo/MjWarp defaults, per‑env scaling, and upward clamping in docstringsReplace the two parameter descriptions so they state defaults come from the MuJoCo/MjWarp model/data limits, are per‑environment and scaled by nworld, and that user values below the model limit are clamped upward with a warning.
- njmax (int): Maximum number of constraints per environment (world). If None, a default value is estimated from the initial state. Note that the larger of the user-provided value or the default value is used. - ncon_per_env (int | None): Number of contact points per environment (world). If None, a default value is estimated from the initial state. Note that the larger of the user-provided value or the default value is used. + njmax (int | None): Maximum number of scalar constraint rows per environment. If None, defaults to the MuJoCo/MjWarp data/model limit (``mj_data.nefc``). The per-env value is scaled by the number of worlds (``nworld``) when allocating in MuJoCo Warp; if a user value is lower than the model limit it is clamped upward and a warning is emitted. + ncon_per_env (int | None): Maximum number of contacts per environment. If None, defaults to the MuJoCo/MjWarp data/model limit (``mj_data.nconmax``). The per-env value is scaled by ``nworld`` for allocation; user values below the model limit are clamped upward with a warning.Also update the Migration Guide (docs/) to mention this behaviour. Quick check command:
rg -n 'njmax|nconmax|ncon_per_env' docs/ -S || true
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/_src/solvers/mujoco/solver_mujoco.py (1)
2501-2506: Pass totals toput_data(per‑env × nworld).Wire up the totals computed above.
- nconmax=nconmax, - njmax=njmax, + nconmax=nconmax_total if not disable_contacts else 0, + njmax=njmax_total,
🧹 Nitpick comments (4)
newton/_src/solvers/mujoco/solver_mujoco.py (4)
1239-1241: Clarify docstrings: per‑env semantics, model‑based defaults, clamp behavior.Current text suggests “estimated from initial state”; defaults should come from MuJoCo model limits and be lower‑bounded to them. Suggested rewrite:
- njmax (int): Maximum number of constraints per environment (world). If None, a default value is estimated from the initial state. Note that the larger of the user-provided value or the default value is used. - ncon_per_env (int | None): Number of contact points per environment (world). If None, a default value is estimated from the initial state. Note that the larger of the user-provided value or the default value is used. + njmax (int | None): Maximum number of scalar constraints per environment. If None, uses the MuJoCo model limit (MjModel.njmax). Values below the model limit are clamped up. Internally multiplied by the number of worlds. + ncon_per_env (int | None): Maximum number of contacts per environment. If None, uses the MuJoCo model limit (MjModel.nconmax). Values below the model limit are clamped up. Internally multiplied by the number of worlds.
1498-1506: Typo: “MuJoCo” capitalization.Use “MuJoCo” in comments for consistency.
- # we have an MjWarp Data object + # we have an MjWarp Data object ... - # we have an MjData object from Mujoco + # we have an MjData object from MuJoCo
1543-1558: Typo: “MuJoCo” capitalization.Same nit here.
- # we have an MjData object from Mujoco + # we have an MjData object from MuJoCo
2481-2483: Warning messages: drop “[WARNING]” prefix; message already comes viawarnings.warn.Optional polish for consistency.
- f"[WARNING] Value for ncon_per_env is changed from {ncon_per_env} to {self.mj_data.ncon} following an MjWarp requirement.", + f"ncon_per_env={ncon_per_env} is below MuJoCo estimate; clamping to {self.mj_data.ncon}.", ... - f"[WARNING] Value for njmax is changed from {njmax} to {self.mj_data.nefc} following an MjWarp requirement.", + f"njmax={njmax} is below MuJoCo estimate; clamping to {self.mj_data.nefc}.",Also applies to: 2493-2495
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
newton/_src/solvers/mujoco/solver_mujoco.py(6 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-19T12:27:30.629Z
Learnt from: preist-nvidia
PR: newton-physics/newton#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-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/_src/solvers/mujoco/solver_mujoco.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 Unit Tests on AWS EC2 (Pull Request)
- GitHub Check: Run GPU Benchmarks (Pull Request)
🔇 Additional comments (4)
newton/_src/solvers/mujoco/solver_mujoco.py (4)
1213-1215: Makingnjmaxoptional is good.Signature change aligns with PR goals; matches
convert_to_mjcparameter. LGTM.
1764-1766: Units mismatch: comment says “per world”. It’s per‑env;put_dataneeds totals.Align comment with per‑env semantics and ensure code multiplies by
nworldbefore passing toput_data.- njmax: int | None = None, # number of constraints per world + njmax: int | None = None, # max scalar constraints per environment (per‑env; scaled by nworld)
2490-2499: njmax clamp must use MjModel.njmax (model limit) and scale per‑env to total; current use of Data.nefc is unsafe.
nefcis the current number of efc rows, not the capacity. This can under‑allocate and crash under different contact/limit configurations.- if njmax is not None: - if njmax < self.mj_data.nefc: - warnings.warn( - f"[WARNING] Value for njmax is changed from {njmax} to {self.mj_data.nefc} following an MjWarp requirement.", - stacklevel=2, - ) - njmax = self.mj_data.nefc - else: - njmax = self.mj_data.nefc + mj_njmax = int(self.mj_model.njmax) + if njmax is not None: + if njmax < mj_njmax: + warnings.warn( + f"njmax={njmax} is below MuJoCo njmax per env ({mj_njmax}); clamping to {mj_njmax}.", + stacklevel=2, + ) + njmax = mj_njmax + njmax_total = njmax * nworld + else: + njmax_total = mj_njmax * nworld
1239-1241: Docs/tests/migration: verify all call sites and docs align with per‑env semantics and clamping.
- Confirmed in code: ncon_per_env is multiplied by number of environments (rigid_contact_max = nworld * ncon_per_env — newton/_src/solvers/mujoco/solver_mujoco.py:2478) and njmax is clamped to MuJoCo limits with warning/assignment logic (newton/_src/solvers/mujoco/solver_mujoco.py:2490–2496). Constructor docstring already refers to "per environment (world)" (newton/_src/solvers/mujoco/solver_mujoco.py:1239–1240).
- Action required: ensure examples/tests and the migration guide explicitly state that njmax and ncon_per_env are per‑env, that ncon_per_env is scaled by num_envs, and that both are clamped to MuJoCo model limits. Check/update call sites such as newton/tests/test_equality_constraints.py:48–49, newton/tests/test_mujoco_solver.py:309, newton/tests/test_rigid_contact.py:185 and newton/examples/sensors/example_sensor_contact.py:142, and add/update docs/migration.rst accordingly.
|
I have 2 additional comments here - not sure if we need to address but here we go:
|
|
@adenzler-nvidia Yeah it's the same issue that with MjWarp, it's quite difficult to get default value that makes sense for all cases. |
Co-authored-by: Philipp Reist <66367163+preist-nvidia@users.noreply.github.com>
Co-authored-by: Philipp Reist <66367163+preist-nvidia@users.noreply.github.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.
docs/migration.rstis up-to dateBefore your PR is "Ready for review"
newton/tests/test_examples.py)pre-commit run -aSummary by CodeRabbit
New Features
Bug Fixes
Tests
Chores