newton.solvers.SolverSteel#

class newton.solvers.SolverSteel(model, *, solve_mode='serial', iterations=12, baumgarte=0.2, cfm=1.0e-6, relaxation=1.0, update_mass_matrix_interval=1, enable_joint_limits=False, joint_limit_activation_gap=float('inf'), enable_joint_velocity_limits=False, velocity_limit_activation_fraction=0.0, enable_joint_friction=False, articulation_constraint_max=32, free_body_constraint_max=512, propagation_constraint_max=None, warn_constraint_overflow=True, row_watermark=False, drive_mode='augmented', fuse_joint_velocity_limits=True, enable_bilateral_preelimination=False, bilateral_preelimination_include_mimics=True, parallel_tree=False, reuse_kinematics=False, use_parallel_streams=False, double_buffer=False, friction_anchor_beta=None, contact_regularization=0.0, velocity_iterations=0, velocity_drive_mode='freeze', row_schedule='interleaved', friction_mode='fixed_normal', contact_warmstart=False, contact_warmstart_decay=1.0, enable_restitution=True, restitution_velocity_threshold=0.5, contact_speculative_scale=1.0, contact_gap_gate=None, contact_friction_scale=1.0, contact_friction_position_iterations=-1, contact_friction_gap_max=None, contact_shared_anchor=False, contact_friction_shared_anchor=False, contact_torsion_device=False, contact_compliance=False, enable_sleeping=False, sleep_linear_threshold=0.05, sleep_angular_threshold=0.15, sleep_quiet_time=0.5, sleep_skip_constraints=True, articulated_contact_response='immediate', propagation_same_articulation_rows=False, propagation_cached_response=True, propagation_cached_response_body_max=8, propagation_color_order='contact', deterministic=None)[source]#

Bases: SolverBase, CouplingInterface

Reduced-coordinate articulated dynamics with a projected Gauss-Seidel constraint solve.

Experimental

SolverSteel, its constructor options and its solver-specific attributes may change without the normal deprecation period.

Each step evaluates forward kinematics and inverse dynamics on the articulation tree, builds the joint-space mass matrix with the composite rigid body algorithm (CRBA) and factors it, and integrates an unconstrained velocity prediction (Featherstone, Rigid Body Dynamics Algorithms, Springer, 2014). Contacts, joint position limits and joint velocity limits then become constraint rows solved by projected Gauss-Seidel (PGS) in impulse space. Rows of articulated bodies use the response Y = H^-1 J^T; contacts between free rigid bodies (a single body with a world-rooted free joint) and the ground or other free bodies use per-body inverse inertia. Positions are integrated from the solved velocities with symplectic Euler.

The solve is matrix-free: for each row the solver keeps Y and the diagonal J Y and recomputes J v every iteration instead of assembling a Delassus matrix. Every row applies its impulse to one world-local velocity vector immediately. solve_mode selects the Gauss-Seidel sweep order:

  • "serial" (default): one fused kernel sweeps all rows of a world in order.

  • "colored": the contact rows of each world are colored so that no two rows of a color share a responding body, and each color is solved in parallel. It requires articulated_contact_response="propagation".

articulated_contact_response selects how contacts of articulated bodies are solved. The default "immediate" response uses the generalized rows above. "propagation" instead solves them as fixed-size rows of the touched bodies with each body’s response from the articulated-body factorization of its tree, and propagates the impulses of each iteration through the tree to the joint velocities.

Deprecated since version 1.8: solve_mode="matrix_free" maps to "serial"; solve_mode="split", whose dense Delassus solve was removed, runs "serial"; and articulated_contact_response="propagation_colored" maps to solve_mode="colored" with "propagation". Each emits a NewtonDeprecationWarning.

Like SolverFeatherstone, the solver uses joint_q and joint_qd as its state and does not simulate bodies that are not connected through joints. Floating bases and free bodies need an explicit free joint, see add_joint_free() (add_body() adds one). Free-joint joint_qd is (v_com, omega) in the frame of the joint’s parent anchor (joint_X_p), which is the world frame for an identity anchor, the convention of newton.eval_fk().

Supported features:

  • Joints: PRISMATIC, REVOLUTE, BALL, FIXED, D6 and root FREE / DISTANCE joints.

  • Joint drives: joint_target_ke and joint_target_kd on PRISMATIC, REVOLUTE and D6 DOFs. By default (drive_mode="augmented") they are integrated implicitly by folding dt * kd + dt^2 * ke into the mass matrix; only the explicit drive force is clamped to joint_effort_limit, and the implicit stiffness and damping response is unbounded, so under a large external load the drive reaction can exceed the limit. drive_mode="rows" instead solves one PGS row per driven DOF with the PhysX articulation force-drive update and clamps its impulse, which bounds the complete reaction. joint_armature and joint_damping are applied.

  • Passive joint springs: joint_stiffness and joint_rest_q on PRISMATIC, REVOLUTE and D6 DOFs, applied explicitly as stiffness * (rest_q - q) like SolverFeatherstone, independently of drives and joint limits. Unlike the implicit drives, explicit springs stay stable only for roughly dt * sqrt(stiffness / m_eff) < 2 per DOF.

  • Joint limits: with enable_joint_limits=True, every finite joint_limit_lower / joint_limit_upper of a PRISMATIC, REVOLUTE or D6 DOF is a unilateral row. Joint limits are not enforced by default. Joint velocity limits (joint_velocity_limit) are enforced as rows when enable_joint_velocity_limits is set.

  • Experimental dry joint friction: with enable_joint_friction=True, joint_friction of PRISMATIC, REVOLUTE, BALL and D6 DOFs bounds one row per DOF.

  • Mimic joints (set_joint_mimic(), and the deprecated mimic constraints) within one articulation: one bilateral row per follower coordinate enforces q_follower = coeffs[0] + coeffs[1] * q_leader. The coefficients are read every step.

  • Loop-closing BALL, REVOLUTE and FIXED joints (joints outside the articulation tree whose child belongs to an articulation): three bilateral rows pin the joint’s parent and child anchors together, a REVOLUTE closure adds two rows that keep the child’s hinge axis on the parent’s hinge line, and a FIXED (weld) closure adds three rows that hold the two anchor frames’ relative rotation at zero. A closure has no joint coordinate, so the limits, drive gains, damping, armature, velocity limit and joint_f of a loop-closing REVOLUTE joint’s DOF are ignored. The solver warns at construction, and on an eager joint or joint DOF notification, if limits, drive gains, damping or armature are set, or if the hinge axis is zero or non-finite. The parent is in the child’s articulation, a kinematic body, or the world. The closure rows read joint_enabled, joint_X_p / joint_X_c and, for a REVOLUTE closure, joint_axis every step, so a closure is released, engaged, re-anchored or re-aimed by editing those arrays in place, also from a kernel between CUDA graph replays. An eager step reads a replaced array; a captured graph keeps the arrays it was captured with, so recapture after replacing one. With enable_bilateral_preelimination the mimic and connect rows are eliminated before the sweep through a regularized Schur complement; this is not exact elimination, see the option.

  • Contacts: rigid contacts from CollisionPipeline, one normal row per contact, with Coulomb friction from the mean of the two shapes’ mu. By default friction acts through persistent friction patches: compatible contacts of a body pair form a region whose friction is applied at up to two anchors that share the region’s normal load and carry their tangential displacement across steps, so static friction holds without creep (friction_anchor_beta). Setting friction_anchor_beta=0 selects point friction, two coupled tangent rows per contact. Restitution follows the shapes’ restitution. Optional contact regularization, warm start from the previous step’s impulses, velocity-only iterations and gap gates for speculative contacts are configured on the constructor. Experimental contact torsion (per-shape steel:min_torsional_patch_radius) adds a load-bounded spin-friction row per contact group, and experimental implicit compliance of hydroelastic contacts is opt-in (contact_compliance).

  • Kinematic bodies (KINEMATIC) and heterogeneous worlds. A body outside every articulation, such as a link without a joint, enters contacts, including the friction-patch slide check, with its pose and zero velocity; step() passes its input body_q and body_qd through to the output.

  • CUDA graph capture of step() and reset().

  • Experimental passive-island sleeping (enable_sleeping): settled, supported islands of articulations freeze their published state and skip their rows and dynamics until a wake event.

Limitations:

  • On a CPU device both solve modes run world-serial portable kernels ("colored" sweeps in serial order). Features with only CUDA rows (contact compliance, a friction_mode other than "fixed_normal" and joint friction) raise NotImplementedError there, as does sleeping with solve_mode="colored"; contact torsion raises ValueError.

  • Mimic relationships across articulations or on joints whose position and velocity coordinates differ (BALL, FREE, DISTANCE), loop-closing joints of other types, and loop closures between two dynamic articulations raise NotImplementedError. joint_enabled is supported only for loop-closing joints: construction raises for a disabled tree joint, and a tree joint disabled later is reported by check_constraint_capacity(). Enabled MuJoCo equality constraints (model.mujoco.equality_constraint_*) are enforced through the loop joint or mimic constraint the importer converted them to; an enabled row without such a conversion raises NotImplementedError, also when it is enabled later and notify_model_changed() is called with CONSTRAINT_PROPERTIES. A row counts as converted only when its target_kind / target link names a loop joint or mimic constraint between the row’s own bodies or joints. Particles are not simulated.

  • Gradients are not supported.

On CUDA, branched articulations use sparse mass factors when every articulated (non-free-body) response group shares one joint topology with at most 64 DOFs, joint velocity-limit and joint friction rows are disabled, the model has no mimic or loop-closing joints, drives are augmented and contacts use hard point friction or persistent friction patches (no warm start, regularization, velocity-only iterations, friction gap threshold, restitution, contact torsion or compliance): the mass matrix is assembled and factored in the fill-free pattern of the kinematic tree, and constraint rows keep only the DOFs that support them. Otherwise, and for free bodies, dense factors are used. Both give the same dynamics up to floating-point rounding. The selection follows the model’s structure only; it is not a performance prediction. Sparse factors take longer to set up and, depending on the articulation and the number of worlds, can run faster or markedly slower than dense factors. Articulations whose DOFs are not coupled at all, for example independent single-DOF branches of a fixed base, have a diagonal mass matrix; they skip the factorization and solve each DOF by division, bitwise identical to the dense loop kernels and equal to the tiled kernels up to float32 rounding, and take precedence over sparse factors. parallel_tree=True additionally traverses the independent branches of each tree in parallel.

Constraint rows are stored per world with fixed capacities (articulation_constraint_max for rows of articulated bodies, free_body_constraint_max for free-body contacts, and propagation_constraint_max for propagation rows, by default the sum of the other two, see articulated_contact_response). Rows that do not fit are dropped and the world is flagged in constraint_overflow, a device boolean array with one entry per world plus a final entry for global (world -1) articulations. It also records contact-buffer overflow and contacts dropped by global contact reduction. The flags persist until reset(). Read them in a device kernel (for example an RL termination term) or call check_constraint_capacity() outside graph capture.

Global articulations are solved together with world 0. A kinematic global free body (for example a moving platform) contacts the bodies of every world.

Known limitation: a contact between an articulated body of another world and a dynamic global body, or a kinematic global articulation with joints, cannot be solved, because it would couple two worlds’ solves. Such a contact is dropped, counted, reported once by a device-side warning (unless warn_constraint_overflow is off) and flagged in constraint_overflow. The constructor warns once if the model’s shape flags and collision groups allow such contacts. Use world geometry or a kinematic free body for scenery shared by all worlds, or add the body to every world.

Solver observables:

body_parent_f is populated when BODY_PARENT_F is requested from observables(). It is the wrench the parent applies to each body through its inbound joint, accounted from the step’s solved motion: inverse dynamics with the post-solve joint accelerations (taken from the velocities the dynamics start from, after any velocity-limit prescaling), less gravity, body_f, and the solved impulses divided by dt of the subtree’s contact normal, friction and spin rows and its loop-closure rows. Joint-space rows (drives, limits, joint friction, mimic) enter through the accelerations. Linear force [N] first, torque [N·m] about the body’s center of mass second, world frame. Bodies outside every articulation report zero.

Like SolverMuJoCo, the reconstruction uses the bodies’ rigid mass and inertia, not joint_armature. For a dynamic DOF the wrench projected onto the joint’s motion subspace is therefore its generalized load (joint_f, explicit passive spring and damping forces and joint-space rows) less armature * qdd. Kinematic DOFs report the rigid-body load of carrying their subtree along the prescribed motion.

The accounting has these limits:

  • With enable_bilateral_preelimination the loop-closure reactions are left out; requesting the wrench warns once.

  • A body whose inbound joint is FREE reports the residual of its discrete momentum balance, its FREE joint_f less armature * qdd; with neither, its force part is zero up to solver tolerance. The stabilized gyroscopic update of single-body FREE articulations is not the inverse dynamics’ v x* (I v) term, so a spinning body with anisotropic inertia can report a torque residual.

  • Contact wrenches are summed with atomics, so the last bits can differ run to run.

With sleeping enabled the solver keeps a computed wrench for each sleeping body, also while the wrench is not requested, and reports it in whichever output the caller passes. It is the wrench of the step before the body fell asleep, or of the step it fell asleep in when the step before was not computed.

contact_f is populated when CONTACT_F is requested. Each live rigid contact row holds the force [N] on shape 0’s body, in world frame, from the solved normal and friction impulses of the step divided by dt; the torque part is zero (torsional friction is not reported). Contacts whose rows were dropped for capacity, and contacts of sleeping islands whose rows are skipped (sleep_skip_constraints), report zero, as do rows beyond the contact count or the rigid capacity and the soft-contact rows. A zero force under a sleeping body does not mean the contact was lost: force-threshold logic and SensorContact see an apparent unloading while the island sleeps; pass sleep_skip_constraints=False (or leave sleeping off) to keep the solved forces.

With enable_sleeping, SolverSteel.Observables.body_awake reports per-body sleep flags; see Steel sleep flags.

Example

solver = newton.solvers.SolverSteel(model)
pipeline = newton.CollisionPipeline(model)
contacts = pipeline.contacts()

for i in range(100):
    pipeline.collide(state_in, contacts)
    solver.step(state_in, state_out, control, contacts, dt)
    state_in, state_out = state_out, state_in
class ObservableKind#

Bases: ObservableKind

Standard and Steel-specific observable kinds.

See Solver Observables for solver-specific kinds.

Experimental

Experimental feature. API, behavior, defaults, and supported use cases may change without prior notice.

BODY_AWAKE = 'body_awake'#

Per-body awake flags, True for awake and False for sleeping bodies; requires enable_sleeping.

class Observables#

Bases: Observables

Standard and Steel-specific observable arrays.

Experimental

The solver observable API may change without prior notice.

__init__()#
body_awake: wp.array[wp.bool] | None = None#

Per-body awake flags, shape (body_count,); see Steel sleep flags.

classmethod register_custom_attributes(builder)#

Register the body, shape and joint DOF attributes consumed by Steel in the steel namespace.

Each body and shape attribute maps to the matching PhysX USD attribute:

  • steel:rigid_body_angular_damping [1/s] damps the angular velocity of free bodies and floating bases as w *= max(1 - d dt, 0) each step (physxRigidBody:angularDamping, default 0.05, as SolverFeatherstone); joints with a parent body are not damped. Fill the attribute for one value on every body.

  • steel:rigid_body_linear_damping [1/s] damps the COM velocity of the same bodies as v *= max(1 - d dt, 0) each step (physxRigidBody:linearDamping, default 0). Keep it nonnegative.

  • steel:rigid_body_max_linear_velocity [m/s] and steel:rigid_body_max_angular_velocity [rad/s] bound the velocity of free bodies (physxRigidBody:maxLinearVelocity and physxRigidBody:maxAngularVelocity, default unbounded).

  • steel:rigid_body_max_depenetration_velocity [m/s] bounds the contact correction velocity of free bodies (physxRigidBody:maxDepenetrationVelocity, default unbounded).

One per-shape attribute enables contact torsion, see contact_torsion_device:

  • steel:min_torsional_patch_radius [m] is the effective spin radius of the shape’s contacts (physxCollision:minTorsionalPatchRadius, default 0, no torsion). PhysX also scales a radius with the penetration depth through physxCollision:torsionalPatchRadius; this solver does not.

One per-DOF attribute makes joint friction grow with the load the joint transmits, see enable_joint_friction:

  • steel:joint_friction_load_coefficient adds c (|F| + |T|) to the DOF’s joint_friction (default 0). F [N] and T [N·m] are the force and the torque about the child body’s center of mass that the joint transmits to its child’s subtree under the step’s free dynamics: gravity, applied body and joint forces, velocity-dependent terms and the resulting accelerations, before contacts, limits, friction and drive_mode="rows" drives act. T keeps its component about the joint axis, so a joint’s own applied effort raises its friction. This is the joint friction law of PhysX articulations before PhysX 5.6, and the sum mixes units as it does there. USD reads it only from an explicitly authored newton:steel:jointFrictionLoadCoefficient, not from physxJoint:jointFriction, because the rows interact with drives differently from PhysX.

    Experimental

    steel:joint_friction_load_coefficient, its USD name newton:steel:jointFrictionLoadCoefficient and its load law may change without the normal deprecation period.

The solver reads them from the model at every step, for example model.steel.rigid_body_angular_damping. Models built without these attributes use the defaults.

Parameters:

builder (ModelBuilder) – Model builder to register the attributes with.

__init__(model, *, solve_mode='serial', iterations=12, baumgarte=0.2, cfm=1.0e-6, relaxation=1.0, update_mass_matrix_interval=1, enable_joint_limits=False, joint_limit_activation_gap=float('inf'), enable_joint_velocity_limits=False, velocity_limit_activation_fraction=0.0, enable_joint_friction=False, articulation_constraint_max=32, free_body_constraint_max=512, propagation_constraint_max=None, warn_constraint_overflow=True, row_watermark=False, drive_mode='augmented', fuse_joint_velocity_limits=True, enable_bilateral_preelimination=False, bilateral_preelimination_include_mimics=True, parallel_tree=False, reuse_kinematics=False, use_parallel_streams=False, double_buffer=False, friction_anchor_beta=None, contact_regularization=0.0, velocity_iterations=0, velocity_drive_mode='freeze', row_schedule='interleaved', friction_mode='fixed_normal', contact_warmstart=False, contact_warmstart_decay=1.0, enable_restitution=True, restitution_velocity_threshold=0.5, contact_speculative_scale=1.0, contact_gap_gate=None, contact_friction_scale=1.0, contact_friction_position_iterations=-1, contact_friction_gap_max=None, contact_shared_anchor=False, contact_friction_shared_anchor=False, contact_torsion_device=False, contact_compliance=False, enable_sleeping=False, sleep_linear_threshold=0.05, sleep_angular_threshold=0.15, sleep_quiet_time=0.5, sleep_skip_constraints=True, articulated_contact_response='immediate', propagation_same_articulation_rows=False, propagation_cached_response=True, propagation_cached_response_body_max=8, propagation_color_order='contact', deterministic=None)#

Create a Steel solver for a finalized model.

The options below configure this solver instance at runtime; they are not model or USD attributes. Per-body physical parameters are model attributes, see register_custom_attributes().

Parameters:
  • model (Model) – Model to simulate.

  • solve_mode (Literal['serial', 'colored']) –

    Gauss-Seidel sweep order of the matrix-free solve, which never assembles the Delassus matrix: it recomputes J v every iteration and uses only the diagonal for preconditioning. "serial" (default) sweeps each world’s rows in order in one fused kernel. "colored" colors the propagation contact rows every step so that no two rows of a color share a responding body (a kinematic free body has no response and may be shared) and solves each color as one parallel launch across all worlds; contacts left without a color run last, in the order set by propagation_color_order. "colored" covers free bodies as well as articulations and requires articulated_contact_response="propagation"; any other response raises ValueError. On CPU both modes run world-serial portable kernels ("colored" sweeps in serial order), and the CUDA-only features listed in the class description raise NotImplementedError.

    Deprecated since version 1.8: "matrix_free" maps to "serial", and "split", whose dense Delassus solve was removed, runs "serial"; each emits a NewtonDeprecationWarning.

  • iterations (int) – Number of projected Gauss-Seidel iterations per step.

  • baumgarte (float) – Baumgarte position-correction factor of contact and joint-limit rows, as a fraction of the position error removed per step.

  • cfm (float) – Constraint force mixing added to every row’s effective-mass diagonal, which regularizes redundant rows. Drive rows of drive_mode="rows" use their exact unit response instead, and the coupled contact solves of a friction_mode other than "fixed_normal" leave it off their contact blocks.

  • relaxation (float) – Successive over-relaxation factor of the PGS sweep.

  • update_mass_matrix_interval (int) – Rebuild and refactor the mass matrix every this many calls to step(); 1 rebuilds it every step. Larger values reuse a stale factorization between rebuilds. A change of dt, reset() and notify_model_changed() still request a refresh of the affected articulations. Under CUDA graph capture the host-side cadence is baked into the graph, so the interval should divide the number of steps captured per graph.

  • enable_joint_limits (bool) – Enforce joint_limit_lower and joint_limit_upper of PRISMATIC, REVOLUTE and D6 DOFs as unilateral rows. When False (the default), no joint-limit rows are created, joint position limits are not enforced, and limits use no articulation_constraint_max capacity. The default matches the Steel reference implementation this solver is ported from.

  • joint_limit_activation_gap (float) – Distance from a finite position limit [m or rad] at which its row is created, when enable_joint_limits is set. inf creates the rows of every finite limit each step; a smaller gap creates a row only when q <= lower + gap or q >= upper - gap. Every finite bound is enforced, however large: the builder’s default limits (+/-1e10) are finite, so with inf each such DOF uses two rows of articulation_constraint_max in every step. Use a finite gap or unbounded (+/-inf) limits to avoid these rows; the constructor warns when the finite limits alone exceed the capacity. The value is validated even when joint limits are disabled.

  • enable_joint_velocity_limits (bool) – Enforce joint_velocity_limit of PRISMATIC, REVOLUTE and D6 DOFs with one row pair per limited DOF, after scaling articulation velocities that already exceed a limit. The free-body limits of register_custom_attributes() are enforced whenever those attributes are registered, independently of this option.

  • velocity_limit_activation_fraction (float) – Create the velocity-limit rows of a DOF only when |qd| >= velocity_limit_activation_fraction * limit. 0 creates them for every limited DOF each step; inf never creates them. The gate samples the velocity before the solve, so a DOF that crosses the threshold during a step is clamped one step later. Must be in [0, 1] or inf.

  • enable_joint_friction (bool) –

    Enforce joint_friction [N or N·m] as dry joint friction (MuJoCo frictionloss). Each PRISMATIC, REVOLUTE, BALL or D6 DOF with positive friction adds one row whose impulse is bounded by joint_friction * dt around a zero-velocity target, so the DOF sticks until the required effort exceeds the friction and then slides against it. A BALL joint’s three DOFs are separate boxes about the axes of its angular velocity coordinates. The rows use the articulated response, so coupled inertia, armature, drives, limits and contacts act jointly; their impulses cold-start each step and count against articulation_constraint_max. The coefficients are read and checked on the device every step, also on graph replay, so in-place edits take effect on the next step. An eager step reads a replaced array; a captured graph keeps the array it was captured with, so recapture after replacing it. After editing or replacing the coefficients, call notify_model_changed with JOINT_DOF_PROPERTIES (or the narrower JOINT_DOF_FORCE_PROPERTIES) to wake sleeping islands whose friction changed. Non-finite or negative values, and nonzero friction on other joint types or loop-closing joints, are invalid: such a DOF builds no row, construction and eager notifications raise ValueError, and steps flag the owning world for check_constraint_capacity(). Requires CUDA and is not supported with contact_compliance or enable_bilateral_preelimination; those combinations raise NotImplementedError. Enabling it disables the articulation-local, paired factor-coordinate and sparse-diagonal solves and sparse mass factors at construction, even when every coefficient is zero, so enable it only for models that need friction. When False, joint_friction is ignored.

    A positive steel:joint_friction_load_coefficient at construction (see register_custom_attributes()) adds load-proportional friction: each step, a DOF’s bound grows by its coefficient times the load its joint transmits under that step’s free dynamics. The row is solved together with the drives, so it resists a drive up to its bound, whereas PhysX applies the friction before each DOF’s drive in every iteration and a stiff drive largely overrides it. With drive_mode="augmented" the implicit drive forces are part of the free dynamics and count toward the load; drive_mode="rows" leaves them out, as PhysX does. The coefficients follow the validity rules and notify contract of joint_friction. A model built with every coefficient zero must keep them zero; to randomize coefficients after construction, make at least one positive beforehand.

    Experimental

    enable_joint_friction and its supported combinations may change without the normal deprecation period.

  • articulation_constraint_max (int) – Capacity of rows involving articulated bodies (mimic and connect rows, contacts, enabled joint limits, joint velocity limits, joint friction and, with drive_mode="rows", joint drives) per world. Rows beyond it are dropped and reported, see constraint_overflow.

  • free_body_constraint_max (int) – Capacity of free-body rows per world: free-body contact rows and free-body velocity-limit rows. Under the "propagation" response free-body contacts use the propagation rows, so it sizes only the velocity-limit rows. Rows beyond it are dropped and reported, see constraint_overflow.

  • propagation_constraint_max (int | None) – Capacity of the propagation row family per world in the "propagation" response, which holds every contact row except those between two links of one articulation; these stay dense unless propagation_same_articulation_rows is set. None (default) uses free_body_constraint_max + articulation_constraint_max. Setting it lets free_body_constraint_max shrink to the free-body velocity-limit rows. At least 1; rejected with articulated_contact_response="immediate".

  • warn_constraint_overflow (bool) – Print a device-side warning the first time a world exceeds a row capacity. The warning does not synchronize the host and is compatible with CUDA graph capture. The host contact torsion preparation emits its overflow warning as a NewtonWarning through warnings instead.

  • row_watermark (bool) – Accumulate the high-water marks of the per-world row counts of every row family and of the contact count on the device in every step, including captured ones; read them with constraint_row_watermarks().

  • drive_mode (Literal['augmented', 'rows']) – Joint drive formulation. "augmented" integrates drives implicitly in the mass matrix. "rows" adds one dense PGS row per driven DOF (positive joint_target_ke or joint_target_kd) whose impulse follows the PhysX articulation force-drive update in every iteration, so drives are solved together with contacts and limits instead of before them. Without contacts or limits and below the effort limit, the converged row reproduces the implicit drive of "augmented". Under effort saturation the two differ: "augmented" clamps the explicit drive force before the implicit solve, while the row clamps its accumulated impulse at joint_effort_limit * dt. Drive rows are allocated first in each world, count against articulation_constraint_max, and a drive whose row does not fit is not applied (the world is flagged in constraint_overflow).

  • fuse_joint_velocity_limits (bool) – With drive_mode="rows" and enable_joint_velocity_limits, enforce the velocity limit of each driven DOF with a clamp of its velocity at the end of every iteration (after the contact rows, like the velocity-limit rows it replaces) instead of two velocity-limit rows, and exclude it from the pre-solve velocity scaling. Limited DOFs without a drive row keep their rows. In every other configuration, including velocity_limit_activation_fraction=inf, the option has no effect; velocity_limits_fused reports whether the clamp is active.

  • enable_bilateral_preelimination (bool) – Eliminate the mimic and connect rows of each articulation before the iterative sweep with a Schur complement of the bilateral block S = J_B H^-1 J_B^T: the predicted velocity is projected once and the responses of the other rows are corrected, so closures and mimic couplings depend much less on iterations. The block is factored with a diagonal regularization R of 1e-3 times each row’s diagonal plus a floor of max(cfm, 1e-7), which keeps nearly dependent closure axes positive definite. The elimination is therefore not exact: a bilateral velocity residual of R (S + R)^-1 (J_B v + b_B) remains after the projection, and the corrected responses of other rows still couple into the bilateral rows by the same factor. The rows stay allocated and in the sweep, which reduces this residual further. If any articulation owns more than eight bilateral rows (a FIXED loop closure, such as a link-break weld, takes six), any loop closure has a kinematic or world parent, or velocity_iterations is positive, elimination is disabled for the whole solver (every articulation keeps iterative rows) with a warning at construction.

  • bilateral_preelimination_include_mimics (bool) – With pre-elimination enabled, also eliminate mimic rows. False eliminates only the connect rows and keeps mimic rows iterative, which avoids a singular block when a mimic row is nearly dependent on a closure.

  • parallel_tree (bool) – Traverse the independent branches of each articulation tree in parallel (forward kinematics and dynamics, the inverse-dynamics backward pass and state publication), with up to 32 threads per articulation instead of one. Results match the serial traversal up to floating-point summation order. Unbranched articulations, models whose joints are not ordered parent before child, and CPU devices keep the serial traversal. Broad trees can benefit; narrow trees can be slower, so measure the full step before enabling it.

  • reuse_kinematics (bool) – Opt in to carrying the kinematics and inverse-dynamics terms the solver forms when it publishes a step’s body state into the next step, instead of re-deriving them from the joint coordinates. The carry runs on CUDA only and stays off with gradients, joint velocity limits, sleeping, the parallel tree, or a FREE or DISTANCE joint that is not the first joint of its articulation; the attribute of the same name reports whether it runs. Off by default: every step then re-derives the kinematics from its input state and publishes through newton.eval_fk(), as before. With the carry on, the terms belong to the state object they were published into: reset() drops them for the selected worlds, notify_model_changed() drops them for joint, body and model property changes, a coupler’s input-state notice drops them, and a step whose input state is another object recomputes them; a caller that overwrites or replaces joint_q, joint_qd or body_q of that state outside step() must call notify_state_changed() (or reset() with a world mask) first. The published body poses and velocities then come from the solver’s own kinematics and can differ from newton.eval_fk()’s in their last bit.

  • use_parallel_streams (bool) – Run the factorization, unconstrained solve and response kernels of each articulation-size group on a CUDA stream of its own, so groups of different sizes overlap. Results are unchanged; CPU devices and models with one size group ignore it.

  • double_buffer (bool) – Keep two sets of the grouped mass-matrix and Jacobian buffers and clear the set a step used on a separate CUDA stream, which the step joins before it returns. Results are unchanged; CPU devices and the sparse mass factors ignore it. Steps and graph launches of one solver must be ordered on one stream (or through explicit stream dependencies).

  • friction_anchor_beta (float | None) – Position-correction gain of persistent friction patches; 0 selects point friction. None selects 0.2, and point friction when contact_compliance is enabled or friction_mode is not "fixed_normal". With a positive gain, the contacts of a body pair whose normals, contact planes and friction coefficients agree and whose shapes touch form a region. Each region’s friction acts at up to two anchors along its principal extent, which share the region’s total normal impulse; every contact keeps its own normal row. An anchor carries its tangential displacement across steps, following the pose increments of both bodies, and the tangent rows add friction_anchor_beta * displacement / dt, so a held object does not creep under a static load. Anchors are released when their region is unloaded or slides at the Coulomb limit; history is matched by body pair and geometry, independently of collision contact matching. A one-anchor region has no torsional friction of its own. Call reset() after teleporting a body to discard its history.

  • contact_regularization (float) – Dimensionless regularization g of penetrating contact rows (friction_mode="fixed_normal" only). Each iteration moves a row’s impulse toward the rigid solution with weight 1 / (1 + g) and toward zero with weight g / (1 + g), the update of an implicitly integrated contact spring. It makes statically indeterminate normal-force splits unique and damps the sweep, at the cost of a resting penetration: a row at rest settles at baumgarte * phi / dt = -g * d * lambda (d its unsplit inverse effective mass, lambda its impulse), about g * a * dt^2 / baumgarte for a body under acceleration a resting on one row. Propagation rows whose response is split across coupled contact bodies, with split diagonal d_s, take weight w * d_s / (w * d_s + (1 - w) * d) with w = 1 / (1 + g), which reaches the same rest state. Speculative (positive-gap) rows, rows whose rebound fires and the velocity-only iterations stay rigid. 0 is the rigid law; at most 1e6.

  • velocity_iterations (int) – Number of velocity-only iterations after the position solve. Positions are integrated from the position solve; these iterations then refine the velocity without the position bias, so stabilization does not add velocity to the bodies. A positive-gap contact whose linearized gap at the end of the step stays open keeps its speculative allowance, and an impacting contact keeps its rebound target.

  • velocity_drive_mode (Literal['freeze', 'active']) – Treatment of PGS joint-drive rows during the velocity-only iterations: "freeze" keeps the drive impulses of the position solve, "active" keeps solving the drive rows. Implicit (mass-matrix) drives have no rows, so the option has no effect for them.

  • friction_mode (Literal['fixed_normal', 'bisection', 'bisection_desaxce', 'coulomb_newton']) – Experimental Coulomb friction update of the matrix-free solve. "fixed_normal" updates both tangent impulses together on the friction disk of the current normal impulse: sticking uses the inverse of their 2x2 block, sliding a bounded scalar solve that keeps isotropic maximum dissipation. "bisection" bisects the normal impulse of each contact and re-solves the 2x2 tangent problem at every probe, so normal and friction impulses are updated together. "bisection_desaxce" adds the de Saxce maximum-dissipation bias mu * |c_T| to the normal target velocity of free-body contacts (Le Lidec and Carpentier, 2024). "coulomb_newton" solves each free-body contact’s Coulomb cone exactly with a bracketed scalar Newton iteration on the tangential-force ratio; articulated contacts keep the "fixed_normal" update. The other modes replace each contact’s normal and friction impulses with their coupled solution, which relaxation does not scale, and use point friction: an omitted friction_anchor_beta selects it with a warning, and friction patches, contact torsion, contact compliance, contact_regularization and articulated_contact_response="propagation" with solve_mode="serial" require "fixed_normal". The free-body and articulated rules above apply to articulated_contact_response="immediate". solve_mode="colored" solves every contact on a propagation row, articulated ones included, with the free-body update of the selected mode; contacts between two links of one articulation stay on dense rows and keep the articulated update. This option may change without the normal deprecation period.

  • row_schedule (Literal['interleaved', 'contact_then_internal', 'phased']) – Row order of the matrix-free sweeps. "interleaved" sweeps every row family in each iteration: the dense rows, the free-body contact rows, then the velocity limits. "contact_then_internal" runs every iteration of the contact rows first, then every iteration of the internal rows (drive, mimic, connect, joint-limit and joint-friction rows) and the velocity limits. "phased" approximates the order PhysX uses for grasping: each iteration solves the internal rows, then the contact rows, then the velocity limits, each in a launch of its own; the propagation responses use this order with "interleaved" as well. Contact torsion and contact compliance require "interleaved", and the sparse mass factors are selected only with "interleaved".

  • contact_warmstart (bool) – Start each step from the previous step’s contact impulses, matched by contact identity through rigid_contact_match_index, so the CollisionPipeline must be created with contact matching enabled. Substeps that reuse a contact set without a collision pass seed each contact from its own previous substep. History carries across one collision pass into the same Contacts buffer when that pass matched against the solved contact set (rigid_contact_match_generation); a different buffer, skipped passes, or a pass after the pipeline wrote another buffer start cold. Carried impulses are scaled by the ratio of the step to the previous one, including under graph replay; tangent impulses are rotated into the current tangent frame and clamped to the current friction cone; other rows start cold.

  • contact_warmstart_decay (float) – Non-negative scale applied to the carried impulses.

  • enable_restitution (bool) – Apply contact restitution, the only restitution switch. The default True leaves the shapes’ coefficients in charge; they default to zero, so a model that authors no restitution does not bounce. False turns restitution off for every contact regardless of the coefficients, and lets contact_compliance accept shapes with positive restitution.

  • restitution_velocity_threshold (float) – Minimum closing speed [m/s] of a contact at the start of the step for a rebound. Contacts bounce with the arithmetic mean of the two shapes’ restitution coefficients (restitution, clamped to [0, 1]; zero gives no rebound): an impacting contact replaces its position bias by the rebound target -e * u_start, where u_start is its relative normal velocity at the start of the step, as a lower bound on its separating velocity. The contact must also touch, or be predicted to reach the surface during the step. Slower contacts keep the ordinary contact law, so a resting contact pressed by gravity, a drive or an applied force does not bounce, and this step’s forces do not enlarge a rebound. Finite and non-negative.

  • contact_speculative_scale (float) – Fraction of a positive contact gap that the contact may close during the step (rhs = scale * phi / dt). 0 removes the speculative allowance; penetration correction is unchanged.

  • contact_gap_gate (float | None) – Contacts of the collision pipeline whose gap [m] exceeds this distance get no rows; 0 keeps touching contacts only. None (the default) keeps every contact. gap decides which contacts the pipeline reports (also to sensors and other solvers); this gate only decides which of them this solver solves. Finite and non-negative.

  • contact_friction_scale (float) – Non-negative factor applied to every shape’s friction coefficient (shape_material_mu) in the solver’s copy of the materials, refreshed at construction and by notify_model_changed() with SHAPE_PROPERTIES. It scales the friction rows, patches and the torsion budget; the model’s coefficients are unchanged.

  • contact_friction_position_iterations (int) – Number of position iterations that solve tangential friction rows. -1 (the default) solves them in every position iteration; k >= 0 solves them only in the last k position iterations (0 never), and holds their impulses at zero before that. Velocity-only iterations always solve friction. Values other than -1 reject contact_warmstart and contact_compliance.

  • contact_friction_gap_max (float | None) – Contacts with a gap [m] above this distance get a normal row only. None (the default) gives every contact friction rows; -inf gives none of them friction rows, which saves the rows that zero friction coefficients would keep. A finite negative value keeps friction rows for contacts that penetrate deeper than it. Switching between None (or inf) and a finite or -inf value requires a new solver.

  • contact_shared_anchor (bool) – Apply every contact row at the midpoint of the two witness points instead of at each body’s own witness point, as PhysX applies a contact at one point. phi still comes from the witness points. Friction patch rows keep their patch anchors, so with patches this moves only the normal rows.

  • contact_friction_shared_anchor (bool) – Apply the friction rows at the witness midpoint, which removes the tangential force couple of witness points separated along the normal. It has no effect on friction patch rows, which act at their anchors.

  • contact_torsion_device (bool) – Experimental contact torsion is enabled at construction when any shape has a positive steel:min_torsional_patch_radius (see register_custom_attributes()). It adds one angular row per contact group of an articulated body, about the group’s normal, bounded by r * (mu * N - sliding): sliding and spin share one Coulomb budget, N is the final solved load of the group’s normal rows, and r is the largest radius of the group’s shapes (a patch region can span several shape pairs; contacts whose pair has no positive radius get no torsion). With point friction a group is a coplanar cluster of touching contacts of one shape pair; with friction patches it is one patch region, budgeted by its pooled load and undivided friction coefficient. The radius is an effective footprint, not derived from the geometry: for uniform pressure on a disk of radius R it is 2 * R / 3. Rows are rebuilt every step and carry no spin history; free-body contacts get none. Supported geometry is sphere, box, capsule, cylinder, cone, ellipsoid, plane and convex mesh. Requires contact_warmstart=False; contacts with hydroelastic stiffness are rejected. Dense torsion rows count against articulation_constraint_max after the world’s other dense rows. A world whose groups do not all fit keeps the rows that fit, and a world that dropped dense rows gets no dense torsion rows; both set the world’s constraint_overflow entry and warn when warn_constraint_overflow is set, and other worlds step unaffected. contact_torsion_device prepares the torsion rows on the device instead of on the host. The host preparation is the reference implementation; it reads the contacts back every step and cannot be captured in a CUDA graph. The device preparation builds the same groups and rows with preallocated buffers and supports CUDA graph capture of step(). Invalid torsion input (contact-buffer overflow, hydroelastic contacts, or a friction-patch load ring that does not match its group) makes an eager step raise before it applies torsion rows. In a captured step the error is deferred: the failing step restores its output motion arrays (joint_q, joint_qd, body_q, body_qd, body_qdd) to the input values, while other outputs, observables and solver history still advance, and check_constraint_capacity() raises after the replays. Check before using replay results, discard failed output, fix the cause and reset(). The input error is solver-wide: any reset clears it, and a cause that persists latches it again on the next step. Grouping runs serially per world with worst-case quadratic cost in the contacts of a world. No effect without contact torsion. With articulated_contact_response="propagation", every positive-radius contact on an articulated body that is routed to propagation reserves one more propagation row for torsion (same-articulation contacts stay dense unless propagation_same_articulation_rows is set), so size propagation_constraint_max, or articulation_constraint_max and free_body_constraint_max when it is unset, for it. A group’s torsion row takes that row of its last member. The serial sweep solves the torsion rows after the other rows; the colored sweep solves each in its last member’s contact unit, after the rows of the group’s other members. Both use the same budget, and both solve modes require contact_torsion_device=True and velocity_iterations=0. solve_mode="colored" rejects contact torsion with contact_compliance, whose contacts are hydroelastic. When propagation rows overflow, a group keeps the contacts that received rows and the step does not raise: it sets constraint_overflow, warns when warn_constraint_overflow is set, and check_constraint_capacity() raises.

  • contact_compliance (bool) – Experimental: solve contacts that carry a positive rigid_contact_stiffness [N/m] with an implicit unilateral spring-damper law instead of the rigid normal law. The material comes from the contacts (per-shape hydroelastic stiffness, the contact damping [N s/m], zero staying zero, and the friction weight, applied once to the pair friction); contacts with zero stiffness stay rigid. A compliant row’s force is max(0, -k phi_next - c u_next), solved with the residual u + k phi / (dt k + c) + lambda / (dt (dt k + c)) in every sweep; the damping term is dropped while the gap is open. Requires point friction (None or 0 for friction_anchor_beta; None warns), positive iterations, no warm start, no velocity-only iterations, no contact regularization, no shared anchors and zero shape restitution. With solve_mode="colored" the colored sweep solves the compliant rows, without contact torsion; "propagation" with solve_mode="serial" rejects it. The contacts must carry the hydroelastic material arrays. The rows are prepared on the device, so step() can be captured in a CUDA graph. Invalid input (for example a compliant contact lost to a row capacity, even with warn_constraint_overflow off, or a positive shape restitution) makes an eager step raise. In a captured step the error is deferred: check_constraint_capacity() raises after the replays, until reset(), and their results are invalid; eager steps do not report it. Contacts the allocator excludes on purpose are counted in compliance_skipped_contact_count and compliant contacts in compliance_contact_count. This option may change without the normal deprecation period.

  • enable_sleeping (bool) – Experimental passive-island sleeping. Articulations in contact are joined into islands every step. Static geometry and articulations with no responding degrees of freedom (such as a body welded to the world) support an island without joining it. A fixed-base articulation with responding joints, such as a robot arm, joins the island of everything it touches, so it can connect them into one island; its fixed root supports that island. A supported island whose bodies stay below sleep_linear_threshold and sleep_angular_threshold for sleep_quiet_time falls asleep, and its published state (joint_q, joint_qd, body_q, body_qd and, when requested, body_parent_f) is frozen until a wake event: a nonzero or nonfinite external force (body_f, joint_f), a changed state or gravity, a contact with an awake or moving body, lost support or row capacity, a reset() of its world, or notify_model_changed() for properties of its joints, DOFs, bodies or shapes (other notifications and changes to static or kinematic owners wake every island). Driven articulations (nonzero drive gains) and articulations with passive springs (nonzero joint_stiffness on a PRISMATIC, REVOLUTE or D6 tree joint) stay awake. Sleeping is configured at construction; rebuild captured graphs to change it. Construction raises ValueError with contact_warmstart or velocity_iterations, or for a model without articulations, and NotImplementedError with articulated_contact_response="propagation" and solve_mode="serial", and with solve_mode="colored" on CPU, where the colored mode runs the serial propagation sweep; with solve_mode="colored" on CUDA skipped islands are left out of the coloring, the colored sweep and the propagation trees, and, where CUDA conditional graph nodes are supported, a captured step in which every articulation that can sleep sleeps skips the propagation solve. step() raises ValueError for a nonpositive or nonfinite dt and when state_in and state_out share arrays. The sleeping options are runtime solver settings with no USD schema.

  • sleep_linear_threshold (float) – Body center-of-mass speed below which a body is quiet [m/s], finite and positive.

  • sleep_angular_threshold (float) – Body angular speed below which a body is quiet [rad/s], finite and positive.

  • sleep_quiet_time (float) – Quiet, supported interval after which an island sleeps [s], finite and positive.

  • sleep_skip_constraints (bool) – Skip the work of sleeping islands: their contact and joint-limit rows (collision still runs, so wake events are complete), the rebuild of their friction-patch history (carried instead), and their articulated dynamics (kinematics, inverse dynamics, drives, mass matrix and factorization, velocity prediction and integration). False keeps the rows and dynamics of sleeping islands and only freezes their published state.

  • articulated_contact_response (Literal['immediate', 'propagation']) –

    How contacts touching an articulation that is not a free body are solved.

    • "immediate": dense rows of the articulation’s generalized coordinates, Y = H^-1 J^T per row.

    • "propagation": fixed-size rows of the touched bodies at their centers of mass, with each body’s 6x6 response from the articulated-body factorization of its tree. Each iteration solves these rows and then propagates the accumulated body impulses through the trees to the joint velocities. All contacts, including those of free bodies, use these rows, whose capacity per world is propagation_constraint_max, or free_body_constraint_max + articulation_constraint_max when that is None. With solve_mode="colored" each sweep solves the contacts of a world in batches of contacts that share no responding body, one batch after the other.

    The propagation response avoids the per-row H^-1 J^T of contact rows at the cost of tree passes over every articulation in each iteration; which response is faster depends on the model. They keep joint-limit and velocity-limit rows dense, and contacts between two links of the same articulation dense unless propagation_same_articulation_rows is set. The tree factorization is rebuilt every step, independently of update_mass_matrix_interval.

    Deprecated since version 1.8: "propagation_colored" maps to solve_mode="colored" with "propagation" and emits a NewtonDeprecationWarning.

  • propagation_same_articulation_rows (bool) – Solve contacts between two links of the same articulation as propagation rows, with the exact cross response of the two links, instead of dense rows. Requires articulated_contact_response="propagation" (either solve_mode).

  • propagation_cached_response (bool) – With articulated_contact_response="propagation" (either solve_mode), replace the per-iteration tree walk by cached responses: the setup extracts, for each contact-active body, its joint-space response R (DOFs x 6) and the 6x6 response blocks between active bodies, from the tree factorization that is fixed for the step, and each iteration applies them as a small matrix-vector product. The result equals the tree walk up to float reassociation. It applies to articulation groups with 0- or 1-DOF joints (optionally under a free root); other groups, and worlds with more cache-eligible active bodies than propagation_cached_response_body_max, keep the tree walk, selected per world on the device. Which is faster depends on the model.

  • propagation_cached_response_body_max (int) – Capacity of the cached responses in contact-active bodies of cache-eligible articulations per world; free bodies do not count. At least 1.

  • propagation_color_order (Literal['contact', 'longest_first']) – Order in which solve_mode="colored" colors a world’s contacts and runs those left without a batch: "contact" (default) by contact index, or "longest_first" by row count, longest first, then contact index. A batch takes as long as its longest contact, so "longest_first" puts long contacts together, which shortens the sweep where one body carries many contacts with different row counts; on some stacked scenes it converges more slowly at a fixed iteration count. solve_mode="serial" ignores it.

  • deterministic (DeterministicMode | None) – Run-to-run determinism of the solve. Pass a warp.DeterministicMode, or None (default) to inherit wp.config.deterministic, which defaults to NOT_GUARANTEED. With RUN_TO_RUN the solver reserves its constraint rows in a fixed order instead of the order in which GPU threads reach the per-world row counters: joint rows in articulation order, contact rows in contact-buffer order within each world. Given identical inputs, including identically ordered contacts, repeated runs are then bitwise identical on the same GPU model, driver and Warp build, eagerly and under CUDA graph replay; combine it with CollisionPipeline(deterministic=True) for a reproducible contact order (see Deterministic Contact Ordering). A world that overflows a row capacity keeps the rows of its earliest contacts and drops the rest, so unchanged inputs drop the same contacts every step; overflowed steps remain flagged in constraint_overflow. The mode adds a per-step sort of the contacts by world and row family and 24 bytes of storage per contact slot. With the "propagation" response it also lists each world’s contact-active bodies by body index and sums each body’s warm-start seed in row order. The seed walks a world’s rows serially, so its cost grows with the contact rows in one world; solve_mode="colored" regroups a world’s contact rows by color, an order fixed by the contact set. GPU_TO_GPU is not supported: passing it raises ValueError, and an inherited one emits a NewtonWarning and runs RUN_TO_RUN. deterministic reports the mode that runs, after any fallback. BODY_PARENT_F sums contact wrenches with atomics, so it is outside this guarantee. Steel’s kernel modules always opt out of Warp’s deterministic module option, so a process-wide wp.config.deterministic only selects this mode.

check_constraint_capacity(*, snapshot=False)#

Raise if any world or the global entry lost contacts or rows, or rejected input, since its last reset.

Also raises if a step saw a joint of an articulation tree disabled in joint_enabled; only loop-closing joints can be disabled. That error is not a capacity loss: the flagged steps ignored the disabled joint, so discard their output, re-enable the joint and reset() the affected worlds. A check that passes after the reset does not validate the earlier output. With enable_joint_friction, also raises if a step read invalid joint_friction or steel:joint_friction_load_coefficient; DOFs with invalid friction built no friction row and invalid load coefficients were ignored, so discard the output, repair the coefficients and reset(). With contact_torsion_device, also raises if contact torsion rejected its input since the last reset(); a failing captured step restored its output motion arrays to the input, while a failing eager step raised from step(). Torsion rows dropped for capacity are a capacity loss of their worlds. With contact_compliance, also raises if a captured step rejected its compliant contacts since the last reset(); discard the output of the replays since the last check.

Reads the status on the host, so call it outside CUDA graph capture, for example at an observation boundary. Kernels can read constraint_overflow directly without host synchronization; it holds only the capacity flags. Recovering from a capacity loss requires larger capacities, a new solver (and newly captured graphs) and a reset() of the affected worlds. Contacts that couple a dynamic global body, or a kinematic global articulation with joints, with another world are flagged too; no capacity can solve them.

Parameters:

snapshot (bool) – Report the status copied by the last snapshot_constraint_status(), as it was after the work enqueued before that call, instead of reading the live status synchronously.

Raises:

RuntimeError – If called during graph capture, if snapshot is set before any snapshot, or if any entry is flagged.

constraint_row_watermarks()#

Return the row high-water marks accumulated since construction (row_watermark only).

Per row family (articulation, free_body, propagation): the largest retained and requested row count of any world and step, the largest number of dropped contact rows, the largest excess over the capacity, and the number of overflowing world-steps; and contact_high_water, the largest contact count. With row_watermark, reads the device on the host and raises RuntimeError during CUDA graph capture. Every value is 0 when row_watermark is off.

coupling_effective_mass_refresh_flags()#

Return the model flags after which the articulated effective masses change.

coupling_eval_effective_mass(endpoint_kind, endpoint_index, endpoint_local_pos, out)#

Evaluate articulated effective masses for coupling endpoints.

See coupling_eval_effective_mass_block(). Evaluated on the host; call outside graph capture.

Parameters:
  • endpoint_kind (wp.array[wp.int32]) – Endpoint kinds.

  • endpoint_index (wp.array[wp.int32]) – Endpoint-local body or particle ids.

  • endpoint_local_pos (wp.array[wp.vec3f]) – Body-frame endpoint offsets from the body COM [m].

  • out (wp.array[wp.float32]) – Output effective masses [kg].

coupling_eval_effective_mass_block(endpoint_kind, endpoint_index, endpoint_local_pos, out_mass, out_inertia=None)#

Evaluate articulated effective mass and inertia for coupling endpoints.

A body endpoint’s mass is the inverse of the axis mean of J_p H^-1 J_p^T: J_p is the point Jacobian at endpoint_local_pos and H the tree-only joint-space mass matrix with armature at model.joint_q, where kinematic DOFs take the large armature of the solve; loop-closing joints, drives, limits and contacts are excluded. The inertia scales the body inertia by the ratio of free to articulated mean angular compliance, and is never smaller than the body inertia. Bodies without mobile joint DOFs, and points that the joints cannot translate, keep the generic estimate. Evaluated on the host; call outside graph capture.

Parameters:
  • endpoint_kind (wp.array[wp.int32]) – Endpoint kinds.

  • endpoint_index (wp.array[wp.int32]) – Endpoint-local body or particle ids.

  • endpoint_local_pos (wp.array[wp.vec3f]) – Body-frame endpoint offsets from the body COM [m].

  • out_mass (wp.array[wp.float32]) – Output effective masses [kg].

  • out_inertia (wp.array[wp.mat33f] | None) – Optional output body inertia tensors [kg m^2].

coupling_harvest_proxy_wrenches(body_local_to_proxy_global, out_body_f, *, body_qd_before, state, state_out, contacts, dt)#

Reject use as a proxy destination.

coupling_notify_input_state_update(state, flags, *, iteration_restart=False, dt=0.0)#

Schedule a save or rewind of the carried friction-patch history for the next step.

A kinematic write (joint or body state flags) also drops the carried kinematics of every articulation with reuse_kinematics on. When the coupler may restart a step, the next step after a kinematic write saves the history and the next step after an iteration restart restores the saved copy, so repeated solves of one coupled step start from the same history.

Parameters:
  • state (State) – Entry input state written by the coupler.

  • flags (StateFlags | int) – StateFlags of the arrays the coupler wrote.

  • iteration_restart (bool) – Whether the coupler is repeating the solve of the current step.

  • dt (float) – Step duration [s], or 0 for a reset distribution.

coupling_notify_iteration_restarts(enabled)#

Reject unsupported coupled options, and save the patch history only when a restart can follow.

A coupler that can restart a step requires update_mass_matrix_interval=1.

Parameters:

enabled (bool) – Whether the coupler may restart a step’s solve.

coupling_prepare_proxy_contacts(state, contacts, *, contacts_freshly_detected=False)#

Reject use as a proxy destination.

coupling_rewind_proxy_body(body_local_to_proxy_global, state, coupling_forces, body_gravity_acceleration, dt)#

Reject use as a proxy destination.

notify_model_changed(flags, *, world_mask=None)#

Refresh cached solver data after model changes.

Joint (frames), joint DOF, DOF force (drive gains), DOF inertial (armature), body (kinematic flags) and inertial changes request a mass-matrix refresh of every articulation on the next step, independent of update_mass_matrix_interval. Body flags (kinematic membership), armature, joint damping and spring stiffness (joint DOF or DOF force changes), spring rest coordinates (joint DOF or reference-pose changes) and shape friction and restitution coefficients are re-read. Shape type and source changes, as made by select_body_variants(), refresh which shapes device contact torsion supports. Other model data, such as gravity, limits and shape transforms, is read every step; with reuse_kinematics on, a gravity change reaches the carried bias wrench one step later unless MODEL_PROPERTIES is notified. A kinematic free body that was removed from the response at construction cannot become dynamic again; reconstruct the solver in that case. Constraint changes re-check the MuJoCo equality rows: enabling one that is not converted to a Newton loop joint or mimic constraint raises NotImplementedError. Capacity status in constraint_overflow is not cleared, see reset().

Body, inertial, joint DOF, DOF inertial and shape changes discard the warm-start impulses of the worlds selected by world_mask. With friction patches, shape changes also discard the anchors of the bodies whose collision geometry changed, in every world.

Joint, joint DOF (including the DOF inertial, force and reference-pose flags), body inertial and shape notifications run on the device without host synchronization, so they can be captured in a CUDA graph and replayed after the model arrays are edited in place. A captured notification reads the arrays it was captured with; after replacing a model array, notify eagerly or recapture. Body notifications read body_flags on the host. Sleeping, and the positive-restitution check of sparse mass factors (with restitution enabled), also read model data on the host, so issue those notifications outside CUDA graph capture.

With enable_joint_friction, an eager joint DOF or DOF force notification also reads joint_friction and steel:joint_friction_load_coefficient on the host and raises ValueError for invalid values, after applying every other update. With loop-closing REVOLUTE joints, an eager joint, joint DOF, DOF force or DOF inertial notification also reads their DOF inputs and axes on the host to warn about the ones a closure ignores. A captured notification skips both checks.

Parameters:
  • flags (ModelFlags | int) – Bit-mask of ModelFlags indicating which model properties changed.

  • world_mask (wp.array[wp.bool] | None) – Optional boolean mask of shape (world_count + 1,) in the reset() layout, selecting the worlds whose model data changed. Only their warm-start impulses are discarded; cached model data is refreshed for every world. None discards the warm-start impulses of every world.

notify_state_changed(state, *, world_mask=None)#

Drop the carried kinematics of the selected worlds after writing state outside step().

With reuse_kinematics on, the solver keeps the kinematics and inverse-dynamics terms it formed when publishing a step, for the next step’s input state. Overwriting or replacing that state’s joint_q, joint_qd or body_q makes them stale; call this so the next step re-derives them for the selected worlds. reset() does the same for its worlds beside its other clears. Without the carry this is a no-op.

Parameters:
  • state (State) – The state the next step reads, whose joint or body arrays were written.

  • world_mask (wp.array[wp.bool] | None) – Boolean device array of shape (world_count + 1,) selecting the worlds whose state changed, in the layout reset() and notify_model_changed() use and validated as they validate it (dtype, device and length) before anything else; None selects every world.

observables(kinds, *, contacts=None, requires_grad=None)#

Allocate observable arrays; body_awake starts with the solver’s current flags.

See SolverBase.observables() for the shared allocation contract. Allocating BODY_AWAKE launches a kernel, so call this before graph capture.

Parameters:
Returns:

The solver-owned observable container with the requested arrays allocated.

Raises:

ValueError – If BODY_AWAKE is requested without enable_sleeping. SolverBase.observables() lists the other TypeError and ValueError cases.

Return type:

Observables

Experimental

The solver observable API may change while additional solvers and observable categories are migrated to it.

reset(state, world_mask=None, flags=None)#

Clear solver-owned state of the selected worlds.

The simulation state is not modified. For the selected worlds this clears the capacity status in constraint_overflow, discards the warm-start impulses and the friction-patch anchors, requests a mass-matrix refresh on the next step and, with reuse_kinematics on, drops their carried kinematics, so a teleported articulation does not reuse a stale factorization, anchor or pose; other worlds keep their refresh cadence and history. An anchor between bodies of two entries (for example a global body and a world body) is discarded when either is selected. Global articulations share world 0’s rows, so selecting the global entry also discards world 0’s warm-start impulses while a dynamic global articulation exists. Any reset, whatever its mask, also clears the solver-wide contact torsion input error; it clears the disabled-tree-joint and invalid-joint-friction status of the selected worlds. The reset is launched on the device without host synchronization and can be captured in a CUDA graph. A full reset (world_mask=None) also restarts the host-side step cadence (mass-matrix refresh interval, dt change detection, double-buffer schedule and warm-start history) for subsequent eager step() calls; CUDA graphs captured before the reset keep the cadence captured into them.

Parameters:
  • state (State) – Simulation state; left unchanged. With enable_sleeping, a masked reset restarts the selected worlds’ sleep state-change history from it. The pose history of a kinematic or prescribed body is kept while a shape of an unselected island can collide with one of its shapes, so a move of that body made before the reset still wakes the islands resting on it. Collision follows shape worlds, which can differ from body worlds: a global shape collides with every shape, a world shape with the shapes of its world and the global shapes.

  • world_mask (wp.array[wp.bool] | None) – Optional boolean mask of shape (world_count + 1,). The first world_count entries select worlds; the final entry selects global articulations (world -1) and the final entry of constraint_overflow. None resets everything.

  • flags (StateFlags | int | None) – Unused; the solver’s history is cleared regardless of the state flags.

snapshot_constraint_status()#

Copy the status that check_constraint_capacity() reports on the device, without waiting.

Call outside capture, on the stream that steps the solver, after the steps to observe. check_constraint_capacity(snapshot=True) then raises from this copy, waiting only for the work enqueued on that stream before this call. A new snapshot replaces the previous one, so check it first, and check the last one when stepping stops. A reset() outside capture retakes a checked snapshot and keeps an unchecked one, so a check after the reset still reports the steps before it.

Raises:

RuntimeError – If called during CUDA graph capture.

step(state_in, state_out, control, contacts, dt, *, observables=None)#

Advance the simulation by one time step.

Parameters:
  • state_in (State) – Input state. Its maximal coordinates (body_q) are refreshed from joint_q by forward kinematics during the step; with reuse_kinematics on, a state the previous step published into keeps its carried kinematics, so a caller that overwrote or replaced its joint_q, joint_qd or body_q calls notify_state_changed() first. Bodies outside every articulation keep their body_q and body_qd, which pass through to state_out; contacts treat their velocity as zero.

  • state_out (State) – Output state receiving joint_q, joint_qd, body_q, body_qd and, when requested, body_parent_f.

  • control (Control | None) – Control input; None uses the model’s default control.

  • contacts (Contacts | None) – Rigid contacts from CollisionPipeline, or None. The buffer must not hold more contacts than model.rigid_contact_max allowed when the solver was constructed.

  • dt (float) – Time step [s].

  • observables (Observables | None) – Optional solver observable arrays allocated by observables().

Returns:

state_out.

Return type:

State

SUPPORTED_OBSERVABLES: ClassVar[frozenset[str]] = frozenset({'body_awake', 'body_parent_f', 'contact_f'})#

Names of observables supported by this solver class.

Entries are string identifiers, such as ObservableKind.BODY_QDD. Query supported_observables for the capabilities of an instance.

articulated_contact_response#

The articulated_contact_response constructor option. Set at construction; construct a new solver to change it.

articulation_constraint_max#

The articulation_constraint_max constructor option. Set at construction; construct a new solver to change it.

baumgarte#

The baumgarte constructor option, read at every step. A captured CUDA graph keeps the value it was captured with.

bilateral_preelimination_include_mimics#

The bilateral_preelimination_include_mimics constructor option. Set at construction; construct a new solver to change it.

cfm#

The cfm constructor option. Set at construction; construct a new solver to change it.

property compliance_contact_count: int#

Compliant contacts prepared by the last step (contact_compliance only).

With contact_compliance, reads the device on the host and raises RuntimeError during CUDA graph capture.

property compliance_skipped_contact_count: int#

Positive-stiffness contacts the row allocator excluded in the last step (contact_compliance only).

With contact_compliance, reads the device on the host and raises RuntimeError during CUDA graph capture.

constraint_overflow#

Capacity failure flags, shape [model.world_count + 1], dtype bool.

One entry per world plus a final entry for global (world -1) articulations: the layout of the reset() mask, so entry i is cleared exactly when mask entry i is selected. An entry is set when a step drops constraint rows of that world (articulation_constraint_max, free_body_constraint_max or the propagation-row capacity exceeded) or drops a contact that couples a dynamic global body with another world. Global articulations share world 0’s row storage, so a row loss in world 0 also sets the global entry while a dynamic global articulation exists. Receiving more contacts than the contact buffer holds, or contacts from which global contact reduction dropped candidates, sets every entry. Flags persist until reset() clears them.

contact_compliance#

The contact_compliance constructor option. Set at construction; construct a new solver to change it.

contact_friction_gap_max#

The contact_friction_gap_max constructor option, read at every step. A captured CUDA graph keeps the value it was captured with. Switching to or from None (or inf) requires a new solver.

contact_friction_position_iterations#

The contact_friction_position_iterations constructor option. Set at construction; construct a new solver to change it.

contact_friction_scale#

The contact_friction_scale constructor option. Set at construction; construct a new solver to change it.

contact_friction_shared_anchor#

The contact_friction_shared_anchor constructor option. Set at construction; construct a new solver to change it.

contact_gap_gate#

The contact_gap_gate constructor option, read at every step. A captured CUDA graph keeps the value it was captured with.

contact_regularization#

The contact_regularization constructor option. Set at construction; construct a new solver to change it.

contact_shared_anchor#

The contact_shared_anchor constructor option. Set at construction; construct a new solver to change it.

contact_speculative_scale#

The contact_speculative_scale constructor option, read at every step. A captured CUDA graph keeps the value it was captured with.

contact_torsion_device#

The contact_torsion_device constructor option. Set at construction; construct a new solver to change it.

contact_warmstart#

The contact_warmstart constructor option. Set at construction; construct a new solver to change it.

contact_warmstart_decay#

The contact_warmstart_decay constructor option, read at every step. A captured CUDA graph keeps the value it was captured with.

deterministic#

The deterministic constructor option. Set at construction; construct a new solver to change it.

double_buffer#

The double_buffer constructor option. Set at construction; construct a new solver to change it.

drive_mode#

The drive_mode constructor option. Set at construction; construct a new solver to change it.

enable_bilateral_preelimination#

The enable_bilateral_preelimination constructor option. Set at construction; construct a new solver to change it.

enable_joint_friction#

The enable_joint_friction constructor option. Set at construction; construct a new solver to change it.

enable_joint_limits#

The enable_joint_limits constructor option. Set at construction; construct a new solver to change it.

enable_joint_velocity_limits#

The enable_joint_velocity_limits constructor option. Set at construction; construct a new solver to change it.

enable_restitution#

The enable_restitution constructor option. Set at construction; construct a new solver to change it.

enable_sleeping#

The enable_sleeping constructor option. Set at construction; construct a new solver to change it.

free_body_constraint_max#

The free_body_constraint_max constructor option. Set at construction; construct a new solver to change it.

friction_anchor_beta#

The friction_anchor_beta constructor option. Set at construction; construct a new solver to change it.

friction_mode#

The friction_mode constructor option. Set at construction; construct a new solver to change it.

fuse_joint_velocity_limits#

The fuse_joint_velocity_limits constructor option. Set at construction; construct a new solver to change it.

iterations#

The iterations constructor option. Set at construction; construct a new solver to change it.

joint_limit_activation_gap#

The joint_limit_activation_gap constructor option. Set at construction; construct a new solver to change it.

parallel_tree#

The parallel_tree constructor option. Set at construction; construct a new solver to change it.

propagation_cached_response#

The propagation_cached_response constructor option. Set at construction; construct a new solver to change it.

propagation_cached_response_body_max#

The propagation_cached_response_body_max constructor option. Set at construction; construct a new solver to change it.

propagation_color_order#

The propagation_color_order constructor option. Set at construction; construct a new solver to change it.

propagation_constraint_max#

The propagation_constraint_max constructor option. Set at construction; construct a new solver to change it.

propagation_same_articulation_rows#

The propagation_same_articulation_rows constructor option. Set at construction; construct a new solver to change it.

relaxation#

The relaxation constructor option, read at every step. A captured CUDA graph keeps the value it was captured with.

restitution_velocity_threshold#

The restitution_velocity_threshold constructor option, read at every step. A captured CUDA graph keeps the value it was captured with.

reuse_kinematics#

The reuse_kinematics constructor option. Set at construction; construct a new solver to change it.

row_schedule#

The row_schedule constructor option. Set at construction; construct a new solver to change it.

row_watermark#

The row_watermark constructor option. Set at construction; construct a new solver to change it.

sleep_angular_threshold#

The sleep_angular_threshold constructor option. Set at construction; construct a new solver to change it.

sleep_linear_threshold#

The sleep_linear_threshold constructor option. Set at construction; construct a new solver to change it.

sleep_quiet_time#

The sleep_quiet_time constructor option. Set at construction; construct a new solver to change it.

sleep_skip_constraints#

The sleep_skip_constraints constructor option. Set at construction; construct a new solver to change it.

solve_mode#

The solve_mode constructor option. Set at construction; construct a new solver to change it.

property supported_observables: frozenset[str]#

Return the observables available for this configuration; BODY_AWAKE requires enable_sleeping.

supports_body_pair_reduced_contacts: bool = True#

step() accepts body-pair-reduced contacts, except with contact_compliance=True, where it raises.

The compliant contact law is validated only on unreduced contacts.

Experimental

Experimental feature. API, behavior, defaults, and supported use cases may change without prior notice.

update_mass_matrix_interval#

The update_mass_matrix_interval constructor option. Set at construction; construct a new solver to change it.

use_parallel_streams#

The use_parallel_streams constructor option. Set at construction; construct a new solver to change it.

velocity_drive_mode#

The velocity_drive_mode constructor option, read at every step. A captured CUDA graph keeps the value it was captured with.

velocity_iterations#

The velocity_iterations constructor option. Set at construction; construct a new solver to change it.

velocity_limit_activation_fraction#

The velocity_limit_activation_fraction constructor option. Set at construction; construct a new solver to change it.

property velocity_limits_fused: bool#

fuse_joint_velocity_limits applies only with drive rows and joint velocity limits.

Type:

Whether the fused velocity-limit clamp is active

warn_constraint_overflow#

The warn_constraint_overflow constructor option, read at every step. A captured CUDA graph keeps the value it was captured with.