Newton Manager Abstraction#
Newton exposes multiple solver families, and Isaac Lab keeps that flexibility by
making each solver an implementation detail of a small
NewtonManager subclass. The simulation context
still sees a normal physics manager; the solver configuration decides which
manager class is used.
For most new Newton solvers, the integration surface is intentionally small:
define a solver config that inherits from
NewtonSolverCfg;point the config’s
class_typeat a manager subclass;implement
_build_solver()in that manager;set the three base-manager slots:
_solver,_use_single_state, and_needs_collision_pipeline.
The existing MuJoCo Warp, XPBD, Featherstone, and Kamino managers are examples of this pattern.
Adding a Solver Manager#
The solver config carries both user-tunable solver parameters and the manager dispatch target:
from isaaclab_newton.physics import NewtonManager, NewtonSolverCfg
from isaaclab.utils.configclass import configclass
@configclass
class MySolverCfg(NewtonSolverCfg):
class_type: type[NewtonManager] | str = "{DIR}.my_solver_manager:NewtonMySolverManager"
solver_type: str = "my_solver"
iterations: int = 16
NewtonCfg copies solver_cfg.class_type into its own class_type in
__post_init__. User code keeps the normal shape:
from isaaclab.sim import SimulationCfg
from isaaclab_newton.physics import NewtonCfg
sim_cfg = SimulationCfg(
physics=NewtonCfg(
solver_cfg=MySolverCfg(iterations=32),
num_substeps=2,
)
)
The manager then owns solver construction:
from newton import Model
from newton.solvers import SolverMySolver
from isaaclab_newton.physics import NewtonManager
class NewtonMySolverManager(NewtonManager):
@classmethod
def _build_solver(cls, model: Model, solver_cfg: MySolverCfg) -> None:
NewtonManager._solver = SolverMySolver(model, iterations=solver_cfg.iterations)
NewtonManager._use_single_state = False
NewtonManager._needs_collision_pipeline = True
_use_single_state tells the base manager whether the solver advances in
place or swaps input/output states. _needs_collision_pipeline tells the base
manager whether to allocate and pass Newton collision-pipeline contacts to the
solver. A solver with its own internal contact detector can set it to False.
Optional Overrides#
Most managers only implement _build_solver(). Override more only when the
solver actually needs it:
_initialize_contacts(): allocate custom contact buffers or support an internal contact detector._step_solver(state_0, state_1, control, contacts, substep_dt): change one substep of solver execution while keeping the base simulation loop._simulate_physics_only(): add per-step work around the base substep loop, such as rebuilding a BVH._reset_solver_internals(world_mask): clear solver-owned state for reset environments.start_simulation()orinstantiate_builder_from_stage(): customize model building or post-finalize setup._register_builder_attributes(builder): register solver-specific Newton custom attributes (particle, shape, body) on the builder before particles or finalize run. The active manager class invokes this hook fromcreate_builder(),start_simulation(), andinstantiate_builder_from_stage().NewtonMPMManageris the in-tree example — it registersmpm:young_modulusand the rest of the implicit MPM particle attributes._prepare_builder_for_finalize(builder): normalize imported or replicated builder data right beforeModelBuilder.finalize().NewtonMPMManageruses this to clear mass and inertia on kinematic bodies so implicit MPM treats them as massless colliders._supports_cuda_graph_capture(): returnFalseto opt the solver out of CUDA graph capture and fall back to eager execution. Defaults toTrue;NewtonMPMManageraccepts fixed and capacity-bounded rebuildable sparse grids._requires_initial_reset_before_graph_capture(): delay headless CUDA graph capture until the first post-reset step when solver resources depend on reset-authored state._solver_specific_clear(): release any class-level state owned by the solver manager.
For implicit MPM, use a fixed grid or follow Newton’s rebuildable-sparse capture
requirements, including a positive max_active_cell_count. Dense and
unbounded sparse grids fall back to eager execution with a warning when
NewtonCfg.use_cuda_graph is enabled.
Keep the manager name prefixed with Newton and the solver config grouped
with the other Newton solver configs so autocomplete and backend discovery stay
predictable.
Custom Coupled Solvers#
Coupled solvers use the same abstraction. Instead of wrapping one Newton solver,
a coupled manager constructs two or more sub-solvers and overrides
_step_solver() to define the substep order.
That means a custom coupling usually needs only a config that stores existing
solver configs plus a manager that defines how data flows between them; the
component solvers can stay unchanged.
The MJWarp + VBD deformable manager is a concrete example:
CoupledMJWarpVBDSolverCfgstores arigid_solver_cfgforMJWarpSolverCfg, asoft_solver_cfgforVBDSolverCfg, and acoupling_mode.NewtonCoupledMJWarpVBDManager._build_solver()constructsSolverMuJoCoandSolverVBDfrom those sub-configs._step_solver()dispatches to either one-way or two-way coupling._reset_solver_internals()and_solver_specific_clear()forward the solver-specific lifecycle to both sub-solvers.The base
NewtonManagerstill owns state allocation, substep iteration, Fabric synchronization, and the outer lifecycle.
The two-way MJWarp + VBD substep stays compact because it is expressed as a short coupling algorithm:
Algorithm: Two-Way MJWarp + VBD Substep
Inputs: rigid body state, deformable particle state, and the shared Newton collision pipeline.
Output: updated rigid body and deformable particle state for one Newton substep.
Clear output force accumulators. Clear the next-state force buffers before evaluating contact.
Detect coupled contacts. Run Newton collision detection once over the current rigid and deformable state.
Apply soft-to-rigid reactions. Inject body-particle contact reactions into
body_fbefore the rigid solve.Advance the rigid solver. Step MJWarp with the coupled contact forces applied.
Advance the deformable solver. Step VBD against the same contacts and the updated rigid poses.
This keeps the custom part focused on the coupling policy. The manager does not need to reimplement scene loading, asset buffers, or the outer simulation loop.
Franka manipulation using MJWarp for rigid bodies and VBD for the deformable object.#
Note
This volume soft-body task requires automatic tetrahedralization. Install its optional dependencies before running it:
uv sync --inexact --extra tetrahedralization
With the legacy installer:
./isaaclab.sh -i tetrahedralization
The opt-in example is registered only when its registration module is imported:
import isaaclab_contrib.custom_coupling.tasks
The import registers IsaacContrib-Lift-Soft-Franka-Custom-Coupling, which
selects the newton_mjwarp_vbd preset and uses coupling_mode="two_way".
The core Isaac-Lift-Soft-Franka and Isaac-Lift-Cloth-Franka tasks default
to the newton_mjwarp_vbd_proxy preset backed by
CouplerProxyCfg instead.
Tuning the Franka Soft-Body Lift#
Tune the coupled contact behavior before training a policy:
Start with
coupling_mode="two_way". Compared with one-way coupling, two-way coupling can prevent clipping more easily because body-particle contact penalties can push the robot back instead of only moving the deformable.Use a small scripted grasp/lift check before training to confirm that grasping is possible and to inspect what clips when the grasp fails.
Lower the arm actuator stiffness enough that the arm can respond to contact penalties. Prefer the arm being pushed back over the gripper clipping into the deformable.
Tune
soft_contact_kefirst. Increase it only as much as needed to prevent clipping, then adjustsoft_contact_muso the gripper can carry the object without requiring an obviously unphysical friction value. Usesoft_contact_kdfor stabilization if contacts chatter. Set this configuration on the outersoft_contact_cfgfield.Tune the
soft_contact_*values together with the rigid shape contact material, because the shape’ske/kd/mualso affect the effective contact. Set shape defaults viaNewtonShapeCfgonNewtonCfg.default_shape_cfg, or override per asset through the asset’s Newton contact material.If
soft_contact_keis not sufficient, orsoft_contact_mumust be unphysically high, tune the Franka arm and hand actuator stiffness and maximum effort. For the gripper command, fully close the fingers and let the actuator maximum effort limit the actual squeeze.If the deformable no longer visibly deforms,
soft_contact_keis likely too high.If contacts are unstable or missed, increase the deformable mesh resolution or increase
particle_radiusin the deformable material so contact is detected earlier from a larger distance.If the rigid shapes still clip through the deformable, increase
iterations; more VBD iterations can improve contact convergence.
When to Add a Coupled Manager#
Add a coupled manager when one solver cannot own the whole model step by itself:
rigid bodies should use one solver while particles or cloth use another;
contact detection is shared, but each solver consumes the contacts differently;
you need a custom force, impulse, or state exchange between solvers;
the substep order is part of the algorithm.
Use a normal single-solver manager when all physics can be advanced by one Newton solver. Use a coupled manager only for the small amount of glue that is truly solver-specific.