# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
"""Configuration for Newton physics manager."""
from __future__ import annotations
import logging
from typing import TYPE_CHECKING, Literal
from isaaclab.physics import PhysicsCfg
from isaaclab.utils.configclass import configclass
from isaaclab_newton.physics.newton_collision_cfg import NewtonCollisionPipelineCfg
if TYPE_CHECKING:
from isaaclab_newton.physics import NewtonManager
logger = logging.getLogger(__name__)
[docs]
@configclass
class NewtonSolverCfg:
"""Configuration for Newton solver-related parameters.
These parameters are used to configure the Newton solver. For more information, see the `Newton documentation`_.
Subclasses set :attr:`class_type` to their matching :class:`NewtonManager`
subclass; :class:`NewtonCfg` propagates that to its own
:attr:`NewtonCfg.class_type` in :meth:`NewtonCfg.__post_init__` so that
``SimulationContext`` resolves the correct manager via the existing
dispatch path.
.. _Newton documentation: https://newton.readthedocs.io/en/latest/
"""
class_type: type[NewtonManager] | str = "{DIR}.newton_manager:NewtonManager"
"""Manager class for this solver.
Default points at the abstract :class:`NewtonManager`; concrete subclasses
override it.
"""
solver_type: str = "None"
"""Solver type metadata (deprecated).
.. deprecated::
Manager dispatch is now driven by :attr:`class_type`; this field is
retained as metadata for logging and debugging only. Do not branch on
``solver_type`` in new code.
"""
[docs]
@configclass
class NewtonShapeCfg:
"""Default per-shape collision properties applied to all shapes in a Newton scene.
Mirrors Newton's :attr:`ModelBuilder.default_shape_cfg`. Fields that Isaac
Lab overrides or exposes for user overrides are declared here; fields not
represented keep Newton's upstream defaults. The struct is forwarded onto
Newton's upstream ``ShapeConfig`` via
:func:`~isaaclab.utils.checked_apply` at builder construction.
"""
margin: float = 0.0
"""Default per-shape collision margin [m].
A nonzero margin (e.g. ``0.01``) is required for stable contact on
triangle-mesh terrain — without it, lightweight robots fail to learn
rough-terrain locomotion on Newton. Newton's upstream default is ``0.0``.
"""
gap: float = 0.01
"""Default per-shape contact gap [m]. Newton's upstream default is ``None``."""
# Defaults mirror Newton's ShapeConfig defaults so an unspecified field is a no-op.
ke: float = 2.5e3
"""Default per-shape normal contact stiffness [N/m].
Applied to shapes that lack an explicit material; per-asset materials
override it. Mirrors Newton's ``ShapeConfig.ke`` default.
"""
kd: float = 100.0
"""Default per-shape normal contact damping [N*s/m].
Applied to shapes that lack an explicit material; per-asset materials
override it. Mirrors Newton's ``ShapeConfig.kd`` default.
"""
mu: float = 1.0
"""Default per-shape friction coefficient [dimensionless].
Applied to shapes that lack an explicit material; per-asset materials
override it. Mirrors Newton's ``ShapeConfig.mu`` default.
"""
[docs]
@configclass
class NewtonCfg(PhysicsCfg):
"""Configuration for Newton physics manager.
This configuration includes Newton-specific simulation settings and solver configuration.
The active :class:`NewtonManager` subclass is determined by
:attr:`solver_cfg.class_type`, which :meth:`__post_init__` propagates to
:attr:`class_type` so that ``SimulationContext`` resolves the right
manager subclass automatically. User code keeps the existing two-level
shape ``NewtonCfg(solver_cfg=...)`` and does not need to set
:attr:`class_type` explicitly.
"""
class_type: type[NewtonManager] | str | None = None
"""The class type of the :class:`NewtonManager`.
Auto-set in :meth:`__post_init__` from :attr:`solver_cfg.class_type`.
Users normally do not set this directly.
"""
num_substeps: int = 1
"""Number of substeps to use for the solver."""
collision_decimation: int = 0
"""Re-collide every N solver substeps within a physics tick (``0`` = once per tick)."""
debug_mode: bool = False
"""Whether to enable debug mode for the solver."""
use_cuda_graph: bool = True
"""Whether to use CUDA graphing when simulating.
If set to False, the simulation performance will be severely degraded.
"""
deterministic_mode: Literal["not_guaranteed", "run_to_run", "gpu_to_gpu"] = "not_guaranteed"
"""Determinism guarantee applied to the Newton solver and collision pipeline.
The values ``"not_guaranteed"``, ``"run_to_run"``, and ``"gpu_to_gpu"``
map to the corresponding ``warp.DeterministicMode`` values. Deterministic
execution increases memory use and can reduce simulation performance.
.. warning::
Deterministic contact ordering adds sorting work and allocates buffers
sized for the configured maximum contact count. Runtime and memory
overhead therefore grow with contact capacity. Enable this mode only
when its reproducibility guarantee is required.
MJWarp on the GPU with
:attr:`~isaaclab_newton.physics.MJWarpSolverCfg.disable_sensors` set to
``True``, XPBD, and Featherstone support this setting. Newton raises an
error during solver initialization for unsupported solvers rather than
silently running them without the requested guarantee.
"""
solver_cfg: NewtonSolverCfg | None = None
"""Solver configuration. If None (default), MJWarpSolverCfg is used by default."""
soft_contact_cfg: NewtonSoftContactCfg | None = None
"""Global soft-contact parameters applied after model finalization.
If ``None``, Newton model defaults are preserved.
"""
collision_cfg: NewtonCollisionPipelineCfg | None = None
"""Newton collision pipeline configuration.
Controls how Newton's :class:`CollisionPipeline` is configured when it is active.
The pipeline is active when the solver delegates collision detection to Newton:
- :class:`MJWarpSolverCfg` with ``use_mujoco_contacts=False``,
- :class:`KaminoPADMMSolverCfg` or :class:`KaminoDVISolverCfg` with
``use_collision_detector=False``,
- :class:`XPBDSolverCfg` (always),
- :class:`VBDSolverCfg` (always),
- :class:`FeatherstoneSolverCfg` (always).
:class:`~isaaclab_newton.physics.MPMSolverCfg` does not use this pipeline;
implicit MPM treats rigid geometry as colliders internally.
If ``None`` (default), a pipeline with ``broad_phase="explicit"`` is created
automatically. Set this to a :class:`NewtonCollisionPipelineCfg` to customize
parameters such as broad phase algorithm, contact limits, or hydroelastic mode.
.. note::
Setting this while ``MJWarpSolverCfg.use_mujoco_contacts=True`` raises
:class:`ValueError`. When a Kamino solver config has ``use_collision_detector=True``,
the field is ignored because Kamino's internal detector handles contacts.
"""
default_shape_cfg: NewtonShapeCfg = NewtonShapeCfg()
"""Default per-shape collision properties applied to every shape in the scene.
Forwarded to Newton's :attr:`ModelBuilder.default_shape_cfg` at builder
construction via :func:`~isaaclab.utils.checked_apply`. See
:class:`NewtonShapeCfg` for the declared fields.
"""
load_visual_shapes: bool | None = None
"""Whether Newton replication imports visual-only geometry from USD.
``None`` imports it only when a viewer, an offscreen ``rgb_array`` capture, or a
camera sensor is active, so headless training does not pay the USD parse time and
memory for shapes nothing draws. Set to ``True`` to always import it, which is
needed when a ray-cast sensor must hit geometry that carries no collider.
"""
bvh_constructor_geometry: Literal["lbvh", "sah", "cubql"] = "cubql"
"""BVH construction algorithm for mesh geometry colliders.
Selects the bounding-volume-hierarchy builder Newton uses for the triangle
meshes of collision geometry, forwarded to :attr:`ModelBuilder.BvhConfig`.
Trades build time against query (traversal) quality:
- ``"lbvh"``: linear BVH; fastest to build, lowest-quality tree.
- ``"sah"``: surface-area-heuristic BVH; slower build, tighter tree with
faster ray/overlap queries.
- ``"cubql"``: cuBQL GPU builder; balances fast construction with good tree
quality on the GPU (default).
"""
bvh_constructor_scene: Literal["lbvh", "sah"] = "sah"
"""BVH construction algorithm for the top-level scene (broad-phase) hierarchy.
Selects the builder for the BVH over all colliders used during broad-phase
culling, forwarded to :attr:`ModelBuilder.BvhConfig`. See
:attr:`bvh_constructor_geometry` for the ``"lbvh"`` / ``"sah"`` trade-off;
``"cubql"`` is not available for the scene hierarchy.
"""
bvh_constructor_gaussian: Literal["lbvh", "sah", "cubql"] = "cubql"
"""BVH construction algorithm for Gaussian-splat primitives.
Selects the builder for the BVH over 3D Gaussian primitives (used by the
Gaussian renderer/collision path), forwarded to
:attr:`ModelBuilder.BvhConfig`. See :attr:`bvh_constructor_geometry` for the
``"lbvh"`` / ``"sah"`` / ``"cubql"`` trade-off.
"""
def __post_init__(self):
# NewtonCfg.class_type is auto-derived from solver_cfg.class_type.
# Refuse a user-set value: setting both is ambiguous and was
# previously silently overwritten.
if self.class_type is not None:
raise TypeError("Cannot manually set NewtonCfg.class_type; it is auto-derived from solver_cfg.class_type.")
if self.deterministic_mode not in ("not_guaranteed", "run_to_run", "gpu_to_gpu"):
raise ValueError(
"NewtonCfg.deterministic_mode must be 'not_guaranteed', 'run_to_run', or 'gpu_to_gpu', "
f"got {self.deterministic_mode!r}."
)
if self.solver_cfg is None:
from isaaclab_newton.physics.mjwarp_manager_cfg import MJWarpSolverCfg
self.solver_cfg = MJWarpSolverCfg()
self.class_type = self.solver_cfg.class_type
# Mid-tick re-collide is silently disabled when collision_decimation >= num_substeps.
if self.collision_decimation > 0 and self.collision_decimation >= self.num_substeps:
logger.warning(
"NewtonCfg.collision_decimation=%d is >= num_substeps=%d; mid-tick re-collide is disabled. "
"Set 0 < collision_decimation < num_substeps to enable.",
self.collision_decimation,
self.num_substeps,
)