Solvers#

Solvers are used to integrate the dynamics of a Newton model. The typical workflow is to construct a Model and a State object, then use a solver to advance the state forward in time via the step() method:

        ---
config:
  theme: forest
  themeVariables:
    lineColor: '#76b900'

---
flowchart LR
    subgraph Input["Input Data"]
        M[newton.Model]
        S[newton.State]
        C[newton.Control]
        K[newton.Contacts]
        DT[Time step dt]
    end

    STEP["solver.step()"]

    subgraph Output["Output Data"]
        SO["newton.State (updated)"]
    end

    %% Connections
    M --> STEP
    S --> STEP
    C --> STEP
    K --> STEP
    DT --> STEP
    STEP --> SO
    

See the solver API reference for constructor and method details. For symptom-driven diagnosis and parameter tuning, start with Simulation Tuning.

Choosing a Solver#

MuJoCo, Kamino, and VBD currently have dedicated backend guides:

  • MuJoCo — generalized-coordinate rigid-body simulation and MuJoCo or MJCF workflows.

  • Kamino — constrained rigid mechanisms with kinematic loops and hard frictional contacts; experimental.

  • VBD — unified simulation of cloth, soft bodies, and rigid bodies in a single VBD-based solver; experimental.

The other solver backends are documented through their linked API references and the comparison tables below.

For a rigid articulated robot, first decide which coordinate representation fits the application. SolverMuJoCo, SolverFeatherstone, and SolverSteel use generalized coordinates, while SolverXPBD, SolverSemiImplicit, and SolverKamino use maximal coordinates. For deformable bodies, particles, or differentiable simulation, use the feature matrix below to narrow the choice, then follow the linked API documentation.

Supported Features#

Solver

Integration

Rigid bodies

Articulations

Particles

Cloth

Soft bodies

Differentiable

Deterministic 3

SolverFeatherstone

Semi-implicit

✅

✅ generalized coordinates

✅

🟨 no self-collision

✅

🟨 basic 2

✅

SolverImplicitMPM

Implicit

❌

❌

✅

❌

❌

❌

❌

SolverKamino

Semi-implicit: Euler, Moreau-Jean

✅ maximal coordinates

✅ maximal coordinates

❌

❌

❌

❌

❌

SolverMuJoCo

Explicit, Semi-implicit, Implicit-in-velocity

✅ 1

✅ generalized coordinates

❌

❌

❌

❌

🟨 CPU only

SolverSemiImplicit

Semi-implicit

✅

✅ maximal coordinates

✅

🟨 no self-collision

✅

🟨 basic 2

✅

SolverSteel

Semi-implicit, implicit drives

✅

✅ generalized coordinates

❌

❌

❌

❌

✅

SolverStyle3D

Implicit

❌

❌

✅

✅

❌

❌

❌

SolverVBD

Implicit

✅

🟨 limited joint support

✅

✅

✅

❌

✅

SolverXPBD

Implicit

✅

✅ maximal coordinates

✅

🟨 no self-collision

🟨 experimental

❌

✅

1 Uses MuJoCo’s built-in collision pipeline by default. Set use_mujoco_contacts=False to use Newton’s collision pipeline.
2 basic means Newton includes several examples that use these solvers in diffsim workflows, see Differentiability for further details.
3 Run-to-run determinism with deterministic=wp.DeterministicMode.RUN_TO_RUN (MuJoCo’s CPU backend is deterministic regardless of that argument); see Deterministic Simulation for limitations and performance trade-offs.

Experimental

SolverSteel’s public API and behavior may change without prior notice. Its matrix-free solve runs on CPU and CUDA; contact torsion, contact compliance, joint friction, the non-default friction_mode values and sleeping with solve_mode="colored" require CUDA, and solve_mode="colored" runs the serial propagation sweep on CPU.

Experimental

SolverKamino’s public API and behavior may change without prior notice.

Experimental

SolverVBD’s public API and behavior may change without prior notice.

Contact Material Support#

ShapeConfig and the matching Model shape material arrays store solver-neutral contact data. This section documents which fields are currently used by Newton’s built-in solvers. External solvers may use different subsets or interpret these fields according to their own formulation.

Joint Feature Support#

Not every solver supports every joint type or joint property. The tables below document which joint features each solver handles.

SolverFeatherstone, SolverSteel, and SolverMuJoCo operate on articulations (generalized/reduced coordinates). The maximal-coordinate solvers (SolverSemiImplicit, SolverXPBD, and SolverKamino) enforce joints as pairwise body constraints but do not use the articulation kinematic-tree structure. SolverVBD supports a subset of joint types through maximal-coordinate constraints, with unified compliant ALM by default and a deprecated legacy AVBD path. SolverStyle3D and SolverImplicitMPM do not support joints.

Joint types

Joint type

SolverFeatherstone

SolverSteel

SolverSemiImplicit

SolverXPBD

SolverMuJoCo

SolverVBD

SolverKamino

PRISMATIC

✅

✅

✅

✅

✅

✅

✅

REVOLUTE

✅

✅

✅

✅

✅

✅

✅

BALL

✅

✅

✅

✅

✅

✅

✅

FIXED

✅

✅

✅

✅

✅

✅

✅

FREE

✅

✅

✅

✅

✅

✅

✅

DISTANCE

🟨 1

🟨 1

🟨 1

✅

❌

❌

❌

D6

✅

✅

✅

✅

✅

✅

❌

ROD

❌

❌

❌

❌

❌

✅

❌

1 DISTANCE joints are treated as FREE (no distance constraint enforcement).

Joint properties

Property

SolverFeatherstone

SolverSteel

SolverSemiImplicit

SolverXPBD

SolverMuJoCo

SolverVBD

SolverKamino

joint_enabled

❌

❌ 8

✅

✅

❌

✅

❌

joint_armature

✅

✅

❌

❌

✅

❌

✅

joint_stiffness / joint_rest_q

REVOLUTE, PRISMATIC, D6

❌

REVOLUTE, PRISMATIC, D6

❌

Scalar joints and isotropic BALL springs

ROD joint_rest_q only

❌

joint_friction

❌

✅ 9

❌

❌

✅

❌

✅

joint_limit_lower / joint_limit_upper

✅

✅ 10

✅ 2

✅

✅

✅

✅

joint_limit_ke / joint_limit_kd

✅

❌

✅ 2

❌

✅

✅ 7

❌

joint_effort_limit

❌

✅ 11

❌

❌

✅

❌

✅

joint_velocity_limit

❌

✅ 12

❌

❌

❌

❌

❌

2 Not enforced for BALL joints in SemiImplicit.

SemiImplicit angular springs use principal coordinates in [-pi, pi). Crossing that boundary produces a force jump of 2*pi*stiffness and can destabilize motion near it. Use Featherstone or MuJoCo for boundary-crossing or multi-turn motion; see Passive joint springs for details.

Actuation and control

Feature

SolverFeatherstone

SolverSteel

SolverSemiImplicit

SolverXPBD

SolverMuJoCo

SolverVBD

SolverKamino

joint_target_ke / joint_target_kd

✅

✅

✅ 2

✅

✅

✅ 7

✅

joint_target_mode

❌

❌

❌

❌

✅

❌

✅

joint_f (feedforward forces)

✅

✅

✅

✅

✅

✅

✅

Constraints

Feature

SolverFeatherstone

SolverSteel

SolverSemiImplicit

SolverXPBD

SolverMuJoCo

SolverVBD

SolverKamino

Equality constraints (CONNECT, WELD, JOINT)

❌

❌

❌

❌

✅

❌

❌

Mimic joints

✅ 3

✅ 13

✅ 4

✅ 5

✅ 6

✅ 5

❌

Particle-body attachments

❌

❌

❌

❌

❌

✅ 14

❌

3 Featherstone eliminates follower degrees of freedom from its reduced dynamics and transfers follower forces and inertia to the reference joint.
4 SemiImplicit enforces joint-owned mimic relationships with penalty springs configured by joint_mimic_ke and joint_mimic_kd.
5 XPBD and VBD enforce joint-owned mimic relationships through coupled maximal-coordinate corrections. Both apply one mimic correction per solver iteration.
6 MuJoCo lowers each joint-owned relationship to joint equality constraints. Multi-axis D6 relationships produce one equality constraint per axis.
7 VBD interprets joint_target_kd and joint_limit_kd as absolute damping coefficients in physical units.
8 Steel rejects models with disabled articulation joints instead of ignoring them; a disabled loop-closing joint starts as a released closure.
9 Steel enforces dry joint friction of PRISMATIC, REVOLUTE, BALL, and D6 DOFs as one bounded constraint row per DOF when constructed with enable_joint_friction=True on CUDA (off by default, experimental); steel:joint_friction_load_coefficient adds the load-proportional joint friction of PhysX articulations before PhysX 5.6.
10 Steel enforces joint limits as hard unilateral constraint rows when constructed with enable_joint_limits=True (off by default).
11 Steel clamps the explicit joint drive force to the effort limit. With the default drive_mode="augmented" the implicit stiffness and damping response is unbounded, so under a large external load the drive reaction can exceed the limit; the PGS drive rows of drive_mode="rows" bound the complete reaction.
12 Steel enforces velocity limits of PRISMATIC, REVOLUTE, and D6 DOFs when constructed with enable_joint_velocity_limits=True. With drive_mode="rows", driven DOFs are clamped at the end of every solver iteration instead of using velocity-limit rows (fuse_joint_velocity_limits).
13 Steel enforces each mimic relationship within one articulation as one bilateral constraint row per follower coordinate; mimics of BALL, FREE, and DISTANCE joints and mimics across articulations are rejected. It also enforces loop-closing BALL joints as point constraints, loop-closing REVOLUTE joints as point constraints plus two hinge-axis constraints, and loop-closing FIXED joints as point constraints plus three rotation constraints. The propagation contact response (articulated_contact_response="propagation") rejects loop-closing joints and solves mimic rows iteratively.
14 See Particle-Body Attachments for authoring and semantics. Attachments spanning two solvers are coupled by SolverCoupledADMM instead.

Particle-Body Attachments#

A particle-body attachment ties one cloth or solid particle to a point in a rigid body’s local frame. Author attachments with newton.ModelBuilder.add_attachment_particle_body(). They are stored on the Model and do not require a coupled solver.

SolverVBD applies an attachment whenever it integrates both endpoints. It solves every attachment as a compliant augmented-Lagrangian (ALM) row, with the same formulation as the VBD joint rows: a reaction multiplier carries the attachment force, and a numerical penalty chosen from the endpoint masses and the particle’s surrounding material helps the iterations converge. The penalty is chosen like the joint limit rows, so a finite attachment reaches its spring over several iterations. The penalty affects convergence only, not physical compliance. A finite stiffness [N/m] converges to a spring with damping [N·s/m], so a loaded attachment keeps a physical offset. Set stiffness=math.inf to request a hard point constraint; damping is ignored for hard attachments. Multipliers are retained across steps, scaled by rigid_avbd_gamma. A finite iteration budget can leave constraint error, especially for heavy free bodies at large time steps; more iterations or smaller steps reduce it. Incompatible hard attachments cannot all be satisfied. Separated initial anchors can cause large correction impulses. The constraint is translational, similar to the positional part of a ball joint; a single particle has no orientation, so there is no angular counterpart. Forces are equal and opposite, including the torque about the body’s center of mass, and the path is independent of contact, so it stays active without penetration.

Both endpoints must be integrated by the same solver, so SolverVBD rejects attachments when it is constructed with integrate_with_external_rigid_solver=True.

When the endpoints of a finite-stiffness attachment belong to two different solvers in a coupled simulation, SolverCoupledADMM turns the same model rows into cross-solver interface constraints; see ADMM Coupling. The two cases are mutually exclusive, so no attachment is applied twice, and a row whose body or particle is owned by no solver applies no force at all. The coupler also warns when both endpoints belong to one entry whose solver does not support attachments. Hard attachments require both endpoints in one VBD entry; the coupler raises an error for other ownership arrangements.

Differentiability#

Differentiable simulation in Newton typically runs a forward rollout inside wp.Tape(), computes a scalar loss from the simulated state, and then calls tape.backward(loss) to populate gradients on differentiable state, control, or model arrays. In practice, this starts by calling finalize() with requires_grad=True.

import warp as wp
import newton

@wp.kernel
def loss_kernel(particle_q: wp.array[wp.vec3], target: wp.vec3, loss: wp.array[float]):
    delta = particle_q[0] - target
    loss[0] = wp.dot(delta, delta)

builder = newton.ModelBuilder()
builder.add_particle(pos=wp.vec3(0.0, 0.0, 0.0), vel=wp.vec3(1.0, 0.0, 0.0), mass=1.0)

model = builder.finalize(requires_grad=True)
solver = newton.solvers.SolverSemiImplicit(model)

state_in = model.state(requires_grad=True)
state_out = model.state(requires_grad=True)
control = model.control()
loss = wp.zeros(1, dtype=float, requires_grad=True)
target = wp.vec3(0.25, 0.0, 0.0)

tape = wp.Tape()
with tape:
    state_in.clear_forces()
    solver.step(state_in, state_out, control, None, 1.0 / 60.0)
    wp.launch(
        loss_kernel,
        dim=1,
        inputs=[state_out.particle_q, target],
        outputs=[loss],
    )

tape.backward(loss)
initial_velocity_grad = state_in.particle_qd.grad.numpy()
assert float(initial_velocity_grad[0, 0]) < 0.0

See the DiffSim examples on GitHub for the current reference workflows.