Skip to content

Add Newton implicit MPM manager and demos#6089

Merged
maxkra15 merged 1 commit into
isaac-sim:developfrom
maxkra15:max/newton-mpm-manager
Jun 11, 2026
Merged

Add Newton implicit MPM manager and demos#6089
maxkra15 merged 1 commit into
isaac-sim:developfrom
maxkra15:max/newton-mpm-manager

Conversation

@maxkra15

@maxkra15 maxkra15 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Description

This PR integrates Newton's implicit MPM solver (newton.solvers.SolverImplicitMPM) into Isaac Lab's
Newton physics-manager abstraction, plus two runnable demos.

What's added

  • MPMSolverCfg (isaaclab_newton.physics.MPMSolverCfg) — a NewtonSolverCfg whose fields map
    one-to-one onto SolverImplicitMPM.Config. to_solver_config() forwards every Newton solver field
    explicitly (no introspection), and class_type resolves to NewtonMPMManager, so users keep the
    standard NewtonCfg(solver_cfg=MPMSolverCfg(...)) shape and SimulationContext dispatches to the
    right manager automatically.
  • NewtonMPMManager (isaaclab_newton.physics.NewtonMPMManager) — a NewtonManager specialization
    that builds SolverImplicitMPM, steps in place on a single State, treats rigid geometry as colliders
    (so it does not consume Newton's rigid-body collision pipeline), and enables CUDA-graph capture only for fixed-grid MPM.
  • Two generic NewtonManager hooks (additive, non-breaking for existing solvers):
    • _register_builder_attributes() / _register_solver_custom_attributes() — lets a solver register
      its Newton builder custom attributes before particles are added or the model is finalized. MPM uses
      this to register mpm:young_modulus, mpm:viscosity, … (a hard SolverImplicitMPM requirement).
      The base implementation is a no-op, so other solvers are unaffected.
    • _supports_cuda_graph_capture() — lets a solver opt out of CUDA-graph capture. _capture_or_defer_graph
      honors it, so sparse/dense-grid MPM falls back to eager execution.
  • Demos (scripts/demos/mpm/):
    • newton_mpm_granular.py — granular (sand-like) particles dropped onto colliders, on a fixed grid by
      default so the MPM step is CUDA-graph captured.
    • particle_pour.py — pouring viscous media into a container.
  • Docs — documents the new _supports_cuda_graph_capture() hook in the Newton manager abstraction page.

Motivation / context for hooks

MPM is the first Isaac Lab Newton solver whose required inputs (per-particle material parameters) are
delivered through Newton's per-solver custom-attribute mechanism rather than built-in model fields, which
is why the two generic hooks above were needed.

Dependencies

Requires a Newton build that ships SolverImplicitMPM (matches the bundled Newton). No new Python deps.

Fixes # (N/A — no tracking issue)

Type of change

  • New feature (non-breaking change which adds functionality)

Screenshots

Granular Pour
Cube Pour

Checklist

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with ./isaaclab.sh --format
  • I have made corresponding changes to the documentation
  • 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

@github-actions github-actions Bot added documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team labels Jun 9, 2026

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot — PR #6089

Summary: Clean, well-structured integration of Newton's implicit MPM solver into the manager abstraction. The two new hooks (_register_builder_attributes, _supports_cuda_graph_capture) are additive and non-breaking. Test coverage is comprehensive with good parametrization. A few lifecycle and API-surface items below.


Findings

🟡 Missing _solver_specific_clear overrideNewtonMPMManager._project_outside_colliders is a class-level flag set in _build_solver. When clear() tears down the manager and a subsequent start_simulation() rebuilds with a different MPMSolverCfg (e.g. project_outside_colliders=False), this flag will correctly be overwritten by the new _build_solver call. However, if clear() is called without a follow-up rebuild (teardown-only path), the stale flag persists on the class. Consider adding a _solver_specific_clear that resets it to False for hygiene, matching what other managers do for their solver-specific state.

🟡 Demos rely on private API _mark_transforms_dirty()particle_pour.py calls NewtonManager._mark_transforms_dirty() directly. Since demos ship as user-facing examples, consumers may copy this pattern. Consider either promoting this to a public method (if the use-case of injecting kinematic poses before stepping is intentional API) or documenting that it's internal.

🔵 TemporaryStore is not retained as a class attribute — The TemporaryStore() created in _build_solver is passed to the solver but not stored on the manager. This works (the solver holds the reference), but if the solver's internal lifetime semantics ever change, the store could be GC'd. A defensive cls._temporary_store = ... line would make ownership explicit.

🔵 test_initialize_solver_populates_canonical_state — MPM particles lack custom_attributes — The add_particle_grid(...) call in the test doesn't pass custom_attributes={...} for MPM material params. This works because the solver apparently handles missing per-particle material data gracefully, but the test would be a more faithful smoke-test of the production path if it included at least mpm:young_modulus.

🔵 Changelog and docs look good — The RST additions clearly describe the new hooks and when they fire. No issues there.


Verdict: Solid work. The architecture cleanly extends the existing manager pattern. The two warnings above are minor lifecycle hygiene items; the suggestions are purely defensive. No blocking issues found.

Reviewed at: 8b76353

NewtonManager._needs_collision_pipeline = False
cls._project_outside_colliders = solver_cfg.project_outside_colliders

@classmethod

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Lifecycle hygiene: Consider adding a override that resets . While will overwrite it on rebuild, a teardown-only leaves this stale. Consistent with how other managers clean up their solver-specific state.

Comment thread scripts/demos/mpm/particle_pour.py Outdated

if not stage.GetPrimAtPath("/World/TableVisual").IsValid():
table_cfg = sim_utils.CuboidCfg(
size=(2.0 * TABLE_HALF_EXTENTS[0], 2.0 * TABLE_HALF_EXTENTS[1], 2.0 * TABLE_HALF_EXTENTS[2]),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Private API in user-facing demo: is a single-underscore private method. Since demos are often copied by users, consider either promoting this to public API or adding a comment explaining it is internal and subject to change.

NewtonManager._solver = SolverImplicitMPM(
model,
solver_cfg.to_solver_config(),
temporary_store=TemporaryStore(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Suggestion: Store the as a class attribute () so ownership is explicit and the object cannot be collected if the solver ever drops its reference.

@greptile-apps

greptile-apps Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR integrates Newton's implicit MPM solver into Isaac Lab's Newton physics-manager abstraction by adding MPMSolverCfg, NewtonMPMManager, two generic hooks on the base NewtonManager (_register_builder_attributes and _supports_cuda_graph_capture), two demo scripts, and accompanying tests.

  • NewtonMPMManager wraps SolverImplicitMPM, sets _use_single_state=True and _needs_collision_pipeline=False, optionally calls project_outside per substep, and gates CUDA-graph capture to fixed-grid configurations; the design follows the existing solver-manager pattern precisely.
  • MPMSolverCfg maps every SolverImplicitMPM.Config field one-to-one via to_solver_config(), intentionally omitting Isaac Lab-only metadata fields, with idempotent custom-attribute registration before particle creation.
  • The two new NewtonManager hooks are no-ops on the base class and are dispatched via _register_solver_custom_attributes from create_builder, instantiate_builder_from_stage, and start_simulation, making the extension fully non-breaking for existing solvers.

Confidence Score: 5/5

Safe to merge; new MPM manager and config are well-isolated, additive, and non-breaking for existing solvers.

The core implementation correctly follows the established Newton manager pattern: shared state lives on the base class, hooks are no-ops by default, and dispatch goes through cfg.class_type. The CUDA-graph gating (sparse/dense opt-out via _supports_cuda_graph_capture) is tested with both monkeypatched unit tests and end-to-end simulation context tests. The only observations are a slightly opaque warning message and a missing mpm:poisson_ratio in the pour demo's fluid material — neither affects correctness of the manager abstraction or other solvers.

particle_pour.py (missing mpm:poisson_ratio in fluid particle attributes, uses private _mark_transforms_dirty) and the SOLVER_MATRIX MPM entry in the test file (add_particle_grid without custom_attributes, flagged in a previous review).

Important Files Changed

Filename Overview
source/isaaclab_newton/isaaclab_newton/physics/mpm_manager.py New NewtonMPMManager: correctly implements _build_solver, _step_solver, _supports_cuda_graph_capture, and _solver_specific_clear following the base-class singleton pattern; in-place project_outside aliasing is intentional and safe given _use_single_state=True.
source/isaaclab_newton/isaaclab_newton/physics/mpm_manager_cfg.py New MPMSolverCfg: explicit one-to-one field forwarding in to_solver_config() correctly excludes Isaac Lab metadata; project_outside_colliders is intentionally kept as a manager-level option.
source/isaaclab_newton/isaaclab_newton/physics/newton_manager.py Added _register_builder_attributes (no-op hook), _register_solver_custom_attributes (dispatcher via cfg.class_type), and _supports_cuda_graph_capture (default True) hooks; all three call-sites for the attribute registration hook are correct; the CUDA graph opt-out check in _capture_or_defer_graph is clean.
scripts/demos/mpm/newton_mpm_granular.py Well-structured granular MPM demo with correct fixed-grid CUDA graph path, proper custom_attributes (including mpm:poisson_ratio), and clean Kit/Newton visualizer dual-backend support.
scripts/demos/mpm/particle_pour.py Particle-pour demo with scripted kinematic teapot collider; calls _mark_transforms_dirty() (private API) and omits mpm:poisson_ratio from particle custom attributes (may be intentional for fluid); previously flagged hardcoded internal Nucleus URL is now user-overridable via --container-usd.
source/isaaclab_newton/test/physics/test_newton_manager_abstraction.py Comprehensive MPM test suite covering cfg wiring, field round-trips, idempotency, CUDA graph gating, and end-to-end stepping; the SOLVER_MATRIX MPM entry uses add_particle_grid without custom_attributes (all material params zero), which was flagged previously as a risk for silent physics failures.
source/isaaclab_newton/isaaclab_newton/physics/newton_manager_cfg.py Minor additive doc update clarifying that MPMSolverCfg does not use the Newton collision pipeline; change is accurate and non-breaking.

Sequence Diagram

sequenceDiagram
    participant User
    participant NewtonManager
    participant NewtonMPMManager
    participant SolverImplicitMPM

    User->>NewtonManager: create_builder()
    NewtonManager->>NewtonMPMManager: _register_builder_attributes(builder)
    NewtonMPMManager->>SolverImplicitMPM: register_custom_attributes(builder)
    Note over NewtonMPMManager: idempotent guard: has_custom_attribute(mpm:young_modulus)
    User->>NewtonManager: "add_particle_grid(custom_attributes={mpm:*})"
    User->>NewtonManager: set_builder(builder)
    User->>NewtonManager: sim.reset() → start_simulation()
    NewtonManager->>NewtonMPMManager: _register_builder_attributes(builder) [no-op]
    NewtonManager->>NewtonMPMManager: initialize_solver → _build_solver(model, cfg)
    NewtonMPMManager->>SolverImplicitMPM: SolverImplicitMPM(model, config, temporary_store)
    NewtonMPMManager->>NewtonManager: "_solver=solver, _use_single_state=True, _needs_collision_pipeline=False"
    NewtonManager->>NewtonMPMManager: _capture_or_defer_graph → _supports_cuda_graph_capture()
    NewtonMPMManager->>SolverImplicitMPM: "check grid_type == fixed"
    Note over NewtonManager: CUDA graph captured (fixed) or eager (sparse/dense)

    loop Each sim.step()
        NewtonManager->>NewtonMPMManager: _step_solver(state_0, state_0, control, None, dt)
        NewtonMPMManager->>SolverImplicitMPM: step(state_0, state_0, control, None, dt)
        opt "project_outside_colliders=True"
            NewtonMPMManager->>SolverImplicitMPM: project_outside(state_0, state_0, dt)
        end
    end
Loading

Reviews (2): Last reviewed commit: "Add Newton implicit MPM manager and demo..." | Re-trigger Greptile

Comment thread scripts/demos/mpm/particle_pour.py Outdated
CONTAINER_LIFT_TIME = 3.0

CONTAINER_BODY_PATH = "/World/ProceduralUtahTeapot"
CONTAINER_USD_URL = "omniverse://isaac-dev.ov.nvidia.com/Isaac/Props/Teapot/utah_teapot.usdc"

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.

P1 Hardcoded internal Omniverse server URL

CONTAINER_USD_URL points to omniverse://isaac-dev.ov.nvidia.com, which is an internal NVIDIA development server inaccessible to external contributors or users. Anyone outside NVIDIA running this "public" demo will get a RuntimeError: Could not open source-container USD at startup. The asset needs to be either bundled locally, published to a publicly accessible Omniverse Nucleus server (e.g. omniverse://localhost/... for a local Nucleus, or an Isaac Sim CDN URL), or the URL must be overridable via a CLI flag so users can point at their own asset.

Comment thread scripts/demos/mpm/particle_pour.py Outdated

.. code-block:: bash

./isaaclab.sh -p scripts/demos/mpm/particle_pour.py --device cuda:0 --viz newton

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.

P2 The docstring CLI example uses --viz newton but the argparse attribute accessed throughout the demo is args_cli.visualizer (matching the full --visualizer flag added by add_launcher_args). The other demo (newton_mpm_granular.py) correctly documents --visualizer newton. While argparse allows unambiguous prefix abbreviations, the inconsistency in documentation is confusing and error-prone if another --viz* argument is added later.

Suggested change
./isaaclab.sh -p scripts/demos/mpm/particle_pour.py --device cuda:0 --viz newton
./isaaclab.sh -p scripts/demos/mpm/particle_pour.py --device cuda:0 --visualizer newton

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@maxkra15 maxkra15 force-pushed the max/newton-mpm-manager branch from 8b76353 to 134f1ab Compare June 10, 2026 01:35
solver to dispatch to.
"""
cfg = PhysicsManager._cfg
if isinstance(cfg, NewtonCfg):

@ooctipus ooctipus Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is it possible this is not newtonCfg? this looks extra defensive

forward it.
"""

def to_solver_config(self) -> SolverImplicitMPM.Config:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

lets try not add function to config class - let the implementation file import SolverImplicitMPM and construct from cfg

"""

@classmethod
def _register_solver_custom_attributes(cls, builder: ModelBuilder) -> None:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this function seems like a shim layer, is this layer removable?

@ooctipus ooctipus left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This looks fine, there are few places could be better thought and refactored together with newton manager perhaps, but that takes thoughts and time, and also doable in follow up prs,

But left a few high level convention comments

@maxkra15 maxkra15 force-pushed the max/newton-mpm-manager branch from 134f1ab to f0a6319 Compare June 11, 2026 18:29
@maxkra15 maxkra15 force-pushed the max/newton-mpm-manager branch from f0a6319 to 974688c Compare June 11, 2026 20:42
@maxkra15 maxkra15 merged commit e5a116d into isaac-sim:develop Jun 11, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants