Extending Newton Solvers
To add a Newton solver or a custom coupled solver, implement a NewtonManager subclass. The sections below explain its hooks, resource ownership, and extension requirements.
If you only need to select and configure a shipped solver, use the user-facing pages instead: /source/concepts/backends_and_presets for backend and preset selection, the solver tuning guides for shipped solvers, and Coupled Solvers for choosing a coupling approach.
When a Solver Manager Is Needed
Each Newton solver is exposed as a NewtonManager subclass. Write a new one when:
- a Newton solver has no Isaac Lab manager yet;
- the solver needs its own contact allocation, builder attributes, or reset handling;
- several solvers must advance one shared model and the substep order is part of the algorithm.
Do not write one when an existing solver can advance the whole model, or when the scene can be partitioned into named solver entries. Partitioning is already covered by CouplerProxyCfg and CouplerAdmmCfg, which NewtonCouplerManager resolves into entry views over a shared model. Prefer that path for mixed rigid and deformable scenes. Write a coupled manager only when contact detection is shared but each solver consumes the contacts differently, or when the exchange between solvers is a custom force, impulse, or state transfer.
Responsibilities and Boundaries
NewtonManager is a class-level singleton: all state lives on the base class and there are no instance methods, so exactly one manager subclass is active per simulation.
NewtonCfg copies solver_cfg.class_type
onto its own class_type, so task
configuration never names the manager directly.
Lifecycle
The public entry points run in this order. Subclass hooks are private; the base class invokes them.
_build_solver() runs after the model is finalized, so it may size solver
resources from the real model. _register_builder_attributes() runs before
particles are added and before finalize(), so it is the only place to
register Newton custom attributes.
step() takes one of two paths, selected by
handles_decimation. When every
actuator is on the graph-safe Newton fast path, actuators and substeps run
together inside one graph and step() runs the whole decimation loop, so
_step_solver() runs decimation x num_substeps times per call. Otherwise
actuators run eagerly, only the substeps are graphed through
_simulate_physics_only(), and the environment drives decimation by calling
step() repeatedly. Both paths reach _step_solver() through the same
substep loop.
Graph capture happens at one of several points. initialize_solver() captures
unless the graph-safe path is active; in that case
set_decimation captures once the
decimation is known, and the RTX path defers capture to the first step().
All routes check _supports_cuda_graph_capture(). The non-RTX route
additionally checks _requires_initial_reset_before_graph_capture().
With _use_single_state = False the base manager ping-pongs
NewtonManager._state_0 and NewtonManager._state_1 after each substep,
except on the final substep of an odd count, where it copies instead. Never
cache a State reference in _build_solver(); read the current state
through the class attribute on each use.
Extension Contract
A subclass must implement _build_solver() and assign four slots on
NewtonManager itself, not on cls.
initialize_solver raises
RuntimeError if _solver is still unset. The other three are not
validated and keep their defaults, so a subclass that forgets them runs with
double-buffered states, no collision pipeline, and no visualizer force input.
Override anything else only when the solver needs it:
_create_solver(): construct a solver without mutating manager state, so a coupler can nest this solver._initialize_contacts(): allocate custom contact buffers._step_solver(state_0, state_1, control, contacts, substep_dt): change one substep while keeping the base simulation loop._simulate_physics_only(): add per-step work around the substep loop._reset_solver_internals(): clear solver-owned state for reset worlds._register_builder_attributes(): register Newton custom particle, shape, or body attributes on the builder._prepare_builder_for_finalize(): normalize imported or replicated builder data immediately beforefinalize()._supports_cuda_graph_capture(): returnFalseto fall back to eager execution._requires_initial_reset_before_graph_capture(): delay headless capture until the first post-reset step._solver_specific_clear(): release class-level state the subclass owns._check_solver_status()and_log_solver_debug(): run after stepping.
NewtonMPMManager overrides both builder hooks.
Raise from _build_solver() on an unsupported configuration rather than
silently degrading. Name the manager Newton<Solver>Manager.
Coupling Paths
The four architectures differ in what drives the substep loop:
A custom shared-model manager bypasses entry ownership resolution, so it cannot reuse the coupler’s selectors or validation. For the proxy and ADMM trade-offs, see Coupled Solvers.
Where to go next
- add_physics_backend: adding a whole physics backend.
- /source/api/lab_newton/isaaclab_newton.physics: manager and solver configuration API reference.