扩展 Newton 求解器#

本页面向为 Isaac Lab 添加 Newton 求解器或构建自定义耦合求解器的贡献者,介绍 NewtonManager 的扩展约定:管理器负责哪些内容、钩子何时运行,以及子类必须提供什么。

如果只需选择和配置已有求解器,请使用面向使用者的页面: 后端与预设 介绍后端和预设选择, 求解器调参指南 介绍随附求解器, 耦合求解器 介绍耦合方式的选择。

何时需要求解器管理器#

每个 Newton 求解器都通过 NewtonManager 子类提供。以下情况需要编写新管理器:

  • Newton 求解器尚无 Isaac Lab 管理器;

  • 求解器需要自己的接触分配、构建器属性或重置处理;

  • 多个求解器必须推进同一共享模型,且子步顺序属于算法的一部分。

如果现有求解器能够推进整个模型,或场景可划分为命名求解器条目,就不必新建管理器。 CouplerProxyCfg 和 CouplerAdmmCfg 已支持这种划分, NewtonCouplerManager 将它们解析为共享模型上的条目视图。刚体与可变形物体混合场景应优先使用此路径。只有共享接触检测、但各求解器以不同方式使用接触,或求解器间需要自定义力、冲量或状态传递时,才编写耦合管理器。

职责与边界#

NewtonManager 是类级单例:所有状态保存在基类上,没有实例方法,因此每个仿真中恰好只有一个管理器子类处于启用状态。

负责方

职责

仿真上下文

根据 class_type 确定管理器子类,并驱动公共生命周期调用。

NewtonManager 基类

构建器、最终 Model 、状态、控制、碰撞流程与接触、子步迭代、CUDA 图捕获、Fabric 与 USD 同步、传感器和重置掩码。

管理器子类

构造求解器,以及求解器自身的内部状态、接触缓冲区或构建器属性。

耦合器条目

当前管理器为耦合器时,共享模型中互不重叠的一部分。

任务配置

class_type 指向管理器的 NewtonSolverCfg 子类;耦合配置还包含条目归属选择器。

NewtonCfg 将 solver_cfg.class_type 复制到自身的 class_type ,因此任务配置从不直接指定管理器。

生命周期#

公共入口按以下顺序运行。子类钩子为私有方法,由基类调用。

公共调用

执行内容

子类钩子

initialize()

保存仿真上下文,从仿真配置读取重力,并创建场景数据后端。

无

sim.get_or_create_backend(NewtonBuilderCfg(physics_cfg=sim.cfg.physics))

通过当前管理器的 create_builder() 工厂获取共享构建器,克隆器向其中导入已声明原型并组合各世界。

_register_builder_attributes()

start_simulation()

完成模型构建,然后分配状态和重置掩码。

_prepare_builder_for_finalize()

initialize_solver()

构建求解器,检查是否已赋值,再分配接触。

_build_solver(), _initialize_contacts()

reset()

硬重置对重新完成构建的模型再次运行 start_simulation() 和 initialize_solver() ;软重置复用现有模型、求解器、接触和图。

_prepare_builder_for_finalize() 、 _build_solver() 、 _initialize_contacts() (仅硬重置)

step()

执行一次执行器处理和 num_substeps 个求解器子步,然后更新传感器。

_reset_solver_internals(), _simulate_physics_only(), _step_solver(), _check_solver_status(), _log_solver_debug()

pre_render()

刷新运动学,再将刚体、线缆和粒子状态写入 Fabric 以供渲染。

_reset_solver_internals() (通过 forward() 调用)

close() 和 clear()

释放求解器、模型和全部类级状态。

_solver_specific_clear()

_build_solver() 在模型完成构建后运行,因此可根据实际模型确定求解器资源大小。 _register_builder_attributes() 在添加粒子和 finalize() 之前运行,是唯一可注册 Newton 自定义属性的位置。

step() 根据 handles_decimation() 选择两条路径之一。所有执行器都使用支持图捕获的 Newton 快速路径时,执行器与子步在同一个图中运行, step() 执行完整控制降采样循环,因此每次调用运行 decimation x num_substeps 次 _step_solver() 。否则,执行器即时运行,只有子步通过 _simulate_physics_only() 捕获为图,环境通过重复调用 step() 实现控制降采样。两条路径都通过同一子步循环调用 _step_solver() 。

图捕获可能在多个时机发生。通常由 initialize_solver() 捕获;启用支持图捕获的快速路径时, set_decimation() 在控制降采样倍数确定后捕获,RTX 路径则延迟到首次 step() 。所有路径都会检查 _supports_cuda_graph_capture() ,非 RTX 路径还检查 _requires_initial_reset_before_graph_capture() 。

警告

设置 _use_single_state = False 时,基类管理器在每个子步后交换 NewtonManager._state_0 和 NewtonManager._state_1 ;子步数为奇数时,最后一个子步改为拷贝。不要在 _build_solver() 中缓存 State 引用;每次使用时,通过类属性读取当前状态。

扩展约定#

子类必须实现 _build_solver() ,并为 NewtonManager 本身而非 cls 上的四个槽位赋值。如果 _solver 仍未设置, initialize_solver() 会抛出 RuntimeError 。其他三个槽位不验证,保留默认值,因此遗漏它们的子类会使用双缓冲状态运行,没有碰撞流程,也不接收可视化器施加的力。

槽位

含义

_solver

构造的 Newton SolverBase 实例。

_use_single_state

求解器在单个 State 上原地步进时为 True ;需要独立输入和输出状态时为 False 。

_needs_collision_pipeline

基类管理器应负责 Newton 碰撞流程时为 True ;求解器内部检测接触时为 False 。

_supports_rigid_body_force_input

求解器使用 State.body_f 中的外部刚体力时为 True 。

from newton import Model
from newton.solvers import SolverMySolver

from isaaclab.utils import configclass
from isaaclab_newton.physics import NewtonManager, NewtonSolverCfg


@configclass
class MySolverCfg(NewtonSolverCfg):
    class_type: type[NewtonManager] | str = "{DIR}.my_solver_manager:NewtonMySolverManager"
    solver_type: str = "my_solver"
    iterations: int = 16


class NewtonMySolverManager(NewtonManager):
    @classmethod
    def _build_solver(cls, model: Model, solver_cfg: MySolverCfg) -> None:
        NewtonManager._solver = SolverMySolver(model, iterations=solver_cfg.iterations)
        NewtonManager._use_single_state = False
        NewtonManager._needs_collision_pipeline = True
        NewtonManager._supports_rigid_body_force_input = True

其他方法仅在求解器需要时覆盖:

  • _create_solver() :构造求解器而不改变管理器状态,使耦合器能够嵌套使用该求解器。

  • _initialize_contacts() :分配自定义接触缓冲区。

  • _step_solver(state_0, state_1, control, contacts, substep_dt) :修改单个子步,同时保留基础仿真循环。

  • _simulate_physics_only() :在子步循环前后添加逐步工作。

  • _reset_solver_internals() :为被重置的世界清除求解器自身状态。

  • _register_builder_attributes() :在构建器上注册 Newton 自定义粒子、形状或刚体属性。

  • _prepare_builder_for_finalize() :在 finalize() 前规范化导入或复制的构建器数据。

  • _supports_cuda_graph_capture() :返回 False ,回退到即时执行。

  • _requires_initial_reset_before_graph_capture() :将无界面图捕获延迟到重置后的第一步。

  • _solver_specific_clear() :释放子类负责的类级状态。

  • _check_solver_status() 和 _log_solver_debug() :在步进后运行。

NewtonMPMManager 覆盖了两个构建器钩子。

配置不受支持时,应在 _build_solver() 中抛出异常,而不是静默降级。管理器应命名为 Newton<Solver>Manager 。

耦合路径#

四种架构的区别在于由谁驱动子步循环:

路径

结构

独立求解器

一个管理器子类、一个求解器、一个模型。基类负责子步循环。

代理耦合

CouplerProxyCfg 将模型划分为命名条目。 NewtonCouplerManager 构建 Newton 耦合求解器,将源刚体作为代理提供给目标求解器,并返回滞后反馈。无需新管理器。

ADMM 耦合

CouplerAdmmCfg 使用相同管理器和条目模型,但 Newton 创建对称接口约束,并迭代各子求解器。无需新管理器。

自定义共享模型管理器

子类自行构造多个子求解器,并覆盖 _step_solver() 固定子步顺序。仓库内的示例是 CoupledMJWarpVBDSolverCfg 。其管理器清除力累加器,只检测一次接触,在 coupling_mode="two_way" 时将软体对刚体的反作用力注入 body_f ,随后让 MJWarp 使用自身内部接触、VBD 使用已检测接触分别步进。

自定义共享模型管理器绕过条目归属解析,因此不能复用耦合器的选择器或验证。代理与 ADMM 的取舍见 耦合求解器 。