Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
ce4db9c
Reset only masked environments in Newton and OVPhysX assets
hujc7 Sep 30, 2026
116e021
Forward the reset mask to every Warp scene entity
hujc7 Sep 30, 2026
88b1ba2
Write collection masks and reset ray-caster drift without host sync
hujc7 Sep 30, 2026
16ee932
Read history_order as a group setting in the Warp observation manager
hujc7 Sep 30, 2026
7949cb9
Write fixed tendon masks on Newton articulations without host sync
hujc7 Sep 30, 2026
12bd5a9
Make masked native-actuator and ray-caster resets capturable
hujc7 Sep 30, 2026
eb458ca
Write Newton tendon targets every step so captured commands apply
hujc7 Sep 30, 2026
b358e1a
Capture Warp frontend stages without an eager warm-up
hujc7 Sep 30, 2026
d0b411a
Reset Warp manager-based environments by mask
hujc7 Sep 30, 2026
d528675
Make stateful Warp event terms classes
hujc7 Sep 30, 2026
80cacc6
Test event capture through the recorded reset stage
hujc7 Sep 30, 2026
ca4eefb
Decide Warp stage capture per term
hujc7 Sep 30, 2026
eb61420
Drop the removed fixed-tendon mask conversion from the sync gate
hujc7 Sep 30, 2026
bf58395
Decide Warp term capturability from each term's parameters
hujc7 Sep 30, 2026
ab709eb
Let physics own decimation in the Warp environments
hujc7 Sep 30, 2026
3ac3db4
Store terminal observations in the Warp environments
hujc7 Sep 30, 2026
e6fcbba
Return copies of the logged values from the Warp environments
hujc7 Sep 30, 2026
a1743b7
Return copies of the reset log from the base Warp environment
hujc7 Sep 30, 2026
12a3b4a
Merge remote-tracking branch 'upstream/develop' into jichuanh/warp-sc…
hujc7 Oct 1, 2026
adfd1ad
Merge branch 'jichuanh/warp-scene-mask-native' into jichuanh/warp-fro…
hujc7 Oct 1, 2026
29b25ec
Merge remote-tracking branch 'upstream/develop' into jichuanh/warp-sc…
hujc7 Oct 1, 2026
2bb8e9e
Resolve adapter reset ids through preallocated masks
hujc7 Oct 1, 2026
edc61c8
Reset Isaac Lab actuator models from the environment mask
hujc7 Oct 1, 2026
e89284a
Reset surface grippers by index in the Warp scene
hujc7 Oct 1, 2026
8b2a161
Drop float from the fixed-tendon position limit type
hujc7 Oct 1, 2026
4fb4e01
Rename the fixed-tendon mask helper and move it beside its setters
hujc7 Oct 1, 2026
3c5e2de
Reuse the shared masked-copy kernel for tendon and link-pose writes
hujc7 Oct 1, 2026
ea94e20
Rename the collection body-mask resolver to _resolve_body_mask
hujc7 Oct 1, 2026
3f26cfa
Pass masks explicitly to actuator models, native actuators and delay …
hujc7 Oct 1, 2026
75de1d9
Forward env_mask through PhysX asset resets
hujc7 Oct 1, 2026
6ac6061
Share one per-environment Warp RNG state through WarpRng
hujc7 Oct 1, 2026
7966bba
Merge remote-tracking branch 'upstream/develop' into jichuanh/warp-sc…
hujc7 Oct 1, 2026
69c13a6
Point the Warp migration guide at WarpRng.state
hujc7 Oct 1, 2026
f846372
Allocate the scratch body mask in the Newton collection test helper
hujc7 Oct 1, 2026
11e36c4
Reset Multirotor thrusters and test actuator stubs from the environme…
hujc7 Oct 1, 2026
9328d98
Defer annotations in the seed module so the docs import it with Warp …
hujc7 Oct 1, 2026
e86c3c4
Merge remote-tracking branch 'upstream/develop' into jichuanh/warp-sc…
hujc7 Oct 1, 2026
e06ab39
Merge branch 'jichuanh/warp-scene-mask-native' into jichuanh/warp-fro…
hujc7 Oct 2, 2026
ee9e8ad
Record Warp stages per call and step the Warp environments like stable
hujc7 Oct 2, 2026
5ad9281
Merge remote-tracking branch 'upstream/develop' into jichuanh/warp-fr…
hujc7 Oct 2, 2026
e35945b
Merge remote-tracking branch 'upstream/develop' into jichuanh/warp-sc…
hujc7 Oct 4, 2026
0c8af1d
Merge branch 'jichuanh/warp-scene-mask-native' into jichuanh/warp-fro…
hujc7 Oct 4, 2026
e9535c6
Merge remote-tracking branch 'upstream/main' into jichuanh/warp-scene…
hujc7 Oct 20, 2026
326f33a
Merge branch 'jichuanh/warp-scene-mask-native' into jichuanh/warp-fro…
hujc7 Oct 20, 2026
0fb7300
Reach the physics backend through the simulation's backend manager in…
hujc7 Oct 20, 2026
f6d31ca
Drop the history_order changelog entry that main already ships
hujc7 Oct 20, 2026
eb283d9
Merge branch 'jichuanh/warp-scene-mask-native' into jichuanh/warp-fro…
hujc7 Oct 20, 2026
dbb3b12
Merge remote-tracking branch 'upstream/main' into jichuanh/warp-scene…
hujc7 Oct 22, 2026
2030fe3
Move the shared WarpRng state out of this pull request
hujc7 Oct 22, 2026
3ddcf7e
Share one per-environment Warp RNG state through WarpRng
hujc7 Oct 22, 2026
5f1321c
Merge branch 'jichuanh/warp-rng-shared' into jichuanh/warp-frontend-c…
hujc7 Oct 22, 2026
5676dd1
Add resolve_ids next to resolve_1d_mask as the shared id and mask hel…
hujc7 Oct 26, 2026
97e5662
Resolve sensor, camera and wrench composer selections through the sha…
hujc7 Oct 26, 2026
92590d0
Fix the deformable mask writers that raised on any env mask
hujc7 Oct 26, 2026
f044c92
Resolve Newton selections through the shared helpers and write its ma…
hujc7 Oct 26, 2026
7b48c38
Resolve OVPhysX selections through the shared helpers
hujc7 Oct 26, 2026
3d3661f
Resolve PhysX selections through the shared helpers
hujc7 Oct 26, 2026
b455d35
Merge jichuanh/id-mask (#8821) into jichuanh/warp-scene-mask-native
hujc7 Oct 26, 2026
a9f7c50
Merge remote-tracking branch 'upstream/main' into jichuanh/warp-scene…
hujc7 Oct 26, 2026
3846f49
Merge branch 'jichuanh/warp-scene-mask-native' into jichuanh/warp-rng…
hujc7 Oct 26, 2026
009c820
Merge branch 'jichuanh/warp-rng-shared' into jichuanh/warp-frontend-c…
hujc7 Oct 26, 2026
6c31123
Write Newton tendon targets behind the host flag again
hujc7 Oct 26, 2026
fdd4f5e
Merge branch 'jichuanh/warp-scene-mask-native' into jichuanh/warp-rng…
hujc7 Oct 26, 2026
121ed8a
Merge branch 'jichuanh/warp-rng-shared' into jichuanh/warp-frontend-c…
hujc7 Oct 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@ The following classes are part of the public :mod:`isaaclab_experimental.utils`
.. autosummary::
:nosignatures:

ManagerCallMode
ManagerCallSwitch
WarpGraphCache
CapturedStage
captured
eager

.. autoclass:: ManagerCallMode
.. autoclass:: CapturedStage
:show-inheritance:

.. autoclass:: ManagerCallSwitch
:show-inheritance:
.. autofunction:: captured

.. autoclass:: WarpGraphCache
:show-inheritance:
.. autofunction:: eager
3 changes: 2 additions & 1 deletion docs/source/concepts/warp_environments.rst
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,8 @@ checks the mask to skip non-selected environments:
return
# ... modify state for selected envs only

- RNG uses per-env ``env.rng_state_wp`` (``wp.uint32``) instead of ``torch.rand``
- RNG uses the per-env :attr:`WarpRng.state <isaaclab.utils.seed.WarpRng.state>` (``wp.uint32``) instead of
``torch.rand``
- **Startup/prestartup** events use the torch convention ``(env, env_ids, **params)``
- **Reset/interval** events use the warp convention ``(env, env_mask, **params)``

Expand Down
2 changes: 2 additions & 0 deletions source/isaaclab/changelog.d/jichuanh-id-mask.added.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Added :func:`~isaaclab.utils.warp.utils.resolve_ids`, which resolves an index selection given as ids or as a
boolean mask to ids on a device, as :func:`~isaaclab.utils.warp.utils.resolve_1d_mask` does to a mask.
11 changes: 11 additions & 0 deletions source/isaaclab/changelog.d/jichuanh-id-mask.changed.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
* Changed the env selection helpers of :class:`~isaaclab.utils.wrench_composer.WrenchComposer`,
:class:`~isaaclab.sensors.SensorBase` and :class:`~isaaclab.sensors.Camera` to resolve ``env_ids`` and ``env_mask``
through :func:`~isaaclab.utils.warp.utils.resolve_ids` and :func:`~isaaclab.utils.warp.utils.resolve_1d_mask`.
Any integer sequence and slices with a negative step are accepted, ids on another device are moved to the owner's
device, and a :class:`~isaaclab.utils.warp.ProxyArray` is rejected with a :class:`TypeError`.
* Changed :class:`~isaaclab.utils.wrench_composer.WrenchComposer` to resolve ``body_ids`` through
:func:`~isaaclab.utils.warp.utils.resolve_ids` as well, so slices other than ``slice(None)`` are accepted.
* Changed :func:`~isaaclab.utils.warp.utils.resolve_1d_mask` to make ``scratch_mask`` optional for callers that never
pass ids. Ids without a ``scratch_mask`` raise a :class:`ValueError`.
* Changed :func:`~isaaclab.utils.warp.utils.resolve_1d_mask` to copy a Warp mask on another device to ``device``, and
to accept a boolean torch mask on ``device`` inside a CUDA graph capture.
2 changes: 2 additions & 0 deletions source/isaaclab/changelog.d/jichuanh-id-mask.fixed.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Fixed the ``write_nodal_*_to_sim_mask`` methods of :class:`~isaaclab.assets.BaseDeformableObject`, which the
OVPhysX deformable object inherits, raising a :class:`RuntimeError` whenever ``env_mask`` was given.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* Added :class:`~isaaclab.utils.seed.WarpRng`, the per-environment Warp random number generator state that
environments and sensors share, one per process. :func:`~isaaclab.utils.seed.configure_seed` reseeds it in place,
and environments call :meth:`~isaaclab.utils.seed.WarpRng.initialize` at construction.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Changed masked :meth:`~isaaclab.sensors.ray_caster.BaseRayCaster.reset` to draw its drift from the shared
:class:`~isaaclab.utils.seed.WarpRng` state instead of random states of its own.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
* Added ``env_mask`` to :meth:`~isaaclab.actuators.ActuatorCollection.reset` and
:meth:`~isaaclab.actuators.ActuatorControl.reset_native_actuators`. Isaac Lab actuator models and backend-native
actuator state reset only the masked environments from the mask itself, without converting it to indices.
* Added ``batch_mask`` to :meth:`~isaaclab.utils.buffers.DelayBuffer.set_time_lag` and
:meth:`~isaaclab.utils.buffers.DelayBuffer.reset`, which select batches on the device without synchronizing the
host. Tensor lags set through a mask are full-sized and are not range-checked.
* Added ``env_mask`` to :meth:`~isaaclab.assets.BaseCableObject.reset`, matching the other scene assets.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
* Changed masked :meth:`~isaaclab.sensors.ray_caster.BaseRayCaster.reset` to resample drift in a Warp kernel from
per-environment random states seeded from torch's global generator, so it neither synchronizes the host nor
allocates and can be captured in a CUDA graph. When both ``env_ids`` and ``env_mask`` are given, the mask selects
the resampled environments, matching :meth:`~isaaclab.sensors.SensorBase.reset`.
* Changed :meth:`~isaaclab.actuators.newton.NewtonActuatorAdapter.reset` to reuse preallocated per-DOF masks, so
masked resets of Newton-native actuator state do not allocate and can be captured in a CUDA graph.
* **Breaking:** Changed :meth:`~isaaclab.actuators.ActuatorBase.reset` to take an ``env_mask`` argument, the
boolean mask of the environments to reset that masked resets pass instead of indices. Custom actuator models must
accept ``env_mask`` and reset from it without synchronizing the host, for example through
:func:`~isaaclab.utils.array.index_fill_` or :func:`torch.where`.
* Changed :class:`~isaaclab.actuators.DelayedPDActuator` to raise :class:`ValueError` at construction unless
``0 <= min_delay <= max_delay``, instead of at a reset, because masked resets apply the sampled delays without
checking them on the host.
* Changed the ``limit`` annotation of
:meth:`~isaaclab.assets.BaseArticulation.set_fixed_tendon_position_limit_index` and
:meth:`~isaaclab.assets.BaseArticulation.set_fixed_tendon_position_limit_mask` to exclude ``float``, matching the
backends, which raise :class:`ValueError` for a float because it cannot hold both bounds.
Empty file.
10 changes: 8 additions & 2 deletions source/isaaclab/isaaclab/actuators/actuator_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,17 @@ def joint_indices(self) -> slice | torch.Tensor:
"""

@abstractmethod
def reset(self, env_ids: Sequence[int]):
def reset(self, env_ids: Sequence[int] | slice | None = None, env_mask: torch.Tensor | None = None):
"""Reset the internals within the group.

.. caution::
If both ``env_ids`` and ``env_mask`` are provided, ``env_mask`` takes precedence.

Args:
env_ids: List of environment IDs to reset.
env_ids: Environment indices or a slice selecting the environments to reset. None resets all
environments.
env_mask: Boolean mask of the environments to reset. Shape is (num_envs,). Implementations reset from it
without synchronizing the host, for example through :func:`~isaaclab.utils.array.index_fill_`.
"""
raise NotImplementedError

Expand Down
15 changes: 12 additions & 3 deletions source/isaaclab/isaaclab/actuators/actuator_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,18 +180,27 @@ def applied_effort(self) -> ProxyArray:

# Lifecycle.

def reset(self, env_ids: Sequence[int] | slice | None = None) -> None:
def reset(self, env_ids: Sequence[int] | slice | None = None, env_mask: wp.array | None = None) -> None:
"""Reset all actuator group states.

Isaac Lab actuator models receive the mask as a zero-copy boolean tensor through the ``env_mask``
argument of :meth:`~isaaclab.actuators.ActuatorBase.reset`. Backend-native actuator state resets from
the mask directly.

.. caution::
If both ``env_ids`` and ``env_mask`` are provided, ``env_mask`` takes precedence.

Args:
env_ids: Environment indices to reset. Defaults to all environments.
env_mask: Environment mask. Shape is (num_instances,). Defaults to None.
"""
group_env_ids = self._control._normalize_index_sequence(env_ids)
group_env_mask = None if env_mask is None else wp.to_torch(env_mask)
for actuator in self._groups.values():
# Newton-executed groups are reset through the backend below.
if isinstance(actuator, ActuatorBase):
actuator.reset(group_env_ids)
self._control.reset_native_actuators(slice(None) if group_env_ids is None else group_env_ids)
actuator.reset(group_env_ids, env_mask=group_env_mask)
self._control.reset_native_actuators(slice(None) if group_env_ids is None else group_env_ids, env_mask)

def compute(self, dt: float = 0.0) -> None:
"""Compute processed actuator commands and telemetry.
Expand Down
6 changes: 5 additions & 1 deletion source/isaaclab/isaaclab/actuators/actuator_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,11 +307,15 @@ def submit_commands(self, collection: ActuatorCollection) -> None:
"""
raise NotImplementedError

def reset_native_actuators(self, env_ids: Sequence[int] | slice) -> None:
def reset_native_actuators(self, env_ids: Sequence[int] | slice, env_mask: wp.array | None = None) -> None:
"""Reset backend-native actuator state.

.. caution::
If both ``env_ids`` and ``env_mask`` are provided, ``env_mask`` takes precedence.

Args:
env_ids: Environments to reset.
env_mask: Environment mask. Shape is (num_instances,). Defaults to None.
"""


Expand Down
14 changes: 8 additions & 6 deletions source/isaaclab/isaaclab/actuators/actuator_net.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,12 @@ def __init__(self, cfg: ActuatorNetLSTMCfg, *args, **kwargs):
Operations.
"""

def reset(self, env_ids: Sequence[int]):
def reset(self, env_ids: Sequence[int] | None = None, env_mask: torch.Tensor | None = None):
# reset the hidden and cell states for the specified environments
selection = env_ids if env_mask is None else env_mask
with torch.no_grad():
index_fill_(self.sea_hidden_state_per_env, env_ids, 0.0, dim=1)
index_fill_(self.sea_cell_state_per_env, env_ids, 0.0, dim=1)
index_fill_(self.sea_hidden_state_per_env, selection, 0.0, dim=1)
index_fill_(self.sea_cell_state_per_env, selection, 0.0, dim=1)

def compute(
self, control_action: ArticulationActions, joint_pos: torch.Tensor, joint_vel: torch.Tensor
Expand Down Expand Up @@ -138,10 +139,11 @@ def __init__(self, cfg: ActuatorNetMLPCfg, *args, **kwargs):
Operations.
"""

def reset(self, env_ids: Sequence[int]):
def reset(self, env_ids: Sequence[int] | None = None, env_mask: torch.Tensor | None = None):
# reset the history for the specified environments
index_fill_(self._joint_pos_error_history, env_ids, 0.0)
index_fill_(self._joint_vel_history, env_ids, 0.0)
selection = env_ids if env_mask is None else env_mask
index_fill_(self._joint_pos_error_history, selection, 0.0)
index_fill_(self._joint_vel_history, selection, 0.0)

def compute(
self, control_action: ArticulationActions, joint_pos: torch.Tensor, joint_vel: torch.Tensor
Expand Down
21 changes: 14 additions & 7 deletions source/isaaclab/isaaclab/actuators/actuator_pd.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ def _warn_articulation_owned_write(self, name: str, writer_name: str) -> None:
Operations.
"""

def reset(self, env_ids: Sequence[int] | None = None):
def reset(self, env_ids: Sequence[int] | None = None, env_mask: torch.Tensor | None = None):
# This is a no-op. There is no state to reset for implicit actuators.
pass

Expand Down Expand Up @@ -313,7 +313,7 @@ def __init__(
Operations.
"""

def reset(self, env_ids: Sequence[int]):
def reset(self, env_ids: Sequence[int] | None = None, env_mask: torch.Tensor | None = None):
pass

def compute(
Expand Down Expand Up @@ -451,18 +451,25 @@ class DelayedPDActuator(IdealPDActuator):

def __init__(self, cfg: DelayedPDActuatorCfg, *args, **kwargs):
super().__init__(cfg, *args, **kwargs)
# masked resets apply the sampled delays without range-checking them on the host
if not 0 <= cfg.min_delay <= cfg.max_delay:
raise ValueError(f"Expected 0 <= min_delay <= max_delay, received {cfg.min_delay} and {cfg.max_delay}.")
# instantiate the delay buffers
self.positions_delay_buffer = DelayBuffer(cfg.max_delay, self._num_envs, device=self._device)
self.velocities_delay_buffer = DelayBuffer(cfg.max_delay, self._num_envs, device=self._device)
self.efforts_delay_buffer = DelayBuffer(cfg.max_delay, self._num_envs, device=self._device)
self._delay_buffers = (self.positions_delay_buffer, self.velocities_delay_buffer, self.efforts_delay_buffer)

def reset(self, env_ids: Sequence[int]):
super().reset(env_ids)
def reset(self, env_ids: Sequence[int] | slice | None = None, env_mask: torch.Tensor | None = None):
super().reset(env_ids, env_mask)
# number of environments (since env_ids can be a slice)
if env_ids is None:
env_ids = slice(None)
num_envs = len(range(self._num_envs)[env_ids]) if isinstance(env_ids, slice) else len(env_ids)
if env_mask is not None:
# a mask samples every environment and the delay buffers keep the masked ones on the device
num_envs = self._num_envs
else:
num_envs = len(range(self._num_envs)[env_ids]) if isinstance(env_ids, slice) else len(env_ids)
# set a new random delay for environments in env_ids
time_lags = torch.randint(
low=self.cfg.min_delay,
Expand All @@ -473,8 +480,8 @@ def reset(self, env_ids: Sequence[int]):
)
# set delays and reset buffers
for delay_buffer in self._delay_buffers:
delay_buffer.set_time_lag(time_lags, env_ids)
delay_buffer.reset(env_ids)
delay_buffer.set_time_lag(time_lags, env_ids, batch_mask=env_mask)
delay_buffer.reset(env_ids, batch_mask=env_mask)

def compute(
self, control_action: ArticulationActions, joint_pos: torch.Tensor, joint_vel: torch.Tensor
Expand Down
49 changes: 26 additions & 23 deletions source/isaaclab/isaaclab/actuators/newton/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,8 @@
from newton.selection import ArticulationView

from ...utils import index_fill_
from .kernels import (
build_implicit_dof_mask,
build_per_dof_env_mask_kernel,
set_mask_kernel,
zero_at_indices_kernel,
)
from ...utils.warp.utils import resolve_1d_mask
from .kernels import build_implicit_dof_mask, build_per_dof_env_mask_kernel, zero_at_indices_kernel

if TYPE_CHECKING:
from .. import ActuatorCollection
Expand Down Expand Up @@ -106,6 +102,12 @@ def __init__(

self._states_a = [act.state() for act in actuators]
self._states_b = [act.state() for act in actuators]
# Newton actuator states reset by a per-DOF mask, which every partial reset expands from the env mask.
# Allocated once and fully rewritten on each reset, so a reset does not allocate.
self._reset_dof_masks = [wp.zeros(act.indices.shape[0], dtype=wp.bool, device=device) for act in actuators]
# Env masks for resolving env ids in :meth:`reset`.
self._all_env_mask = wp.ones(num_envs, dtype=wp.bool, device=device)
self._scratch_env_mask = wp.zeros(num_envs, dtype=wp.bool, device=device)

# Pre-clamp computed effort buffer. Each Newton actuator scatter-adds
# its raw drive output to ``sim_control.joint_computed_f`` when
Expand Down Expand Up @@ -172,14 +174,20 @@ def _swap_state_buffers(self) -> None:
"""Advance the actuator state ping-pong after an eager step or graph replay."""
self._states_a, self._states_b = self._states_b, self._states_a

def reset(self, env_ids: Sequence[int] | torch.Tensor | slice | None = None) -> None:
def reset(
self,
env_ids: Sequence[int] | torch.Tensor | slice | None = None,
env_mask: wp.array | None = None,
) -> None:
"""Reset actuator states for the given environments.

Args:
env_ids: Environment indices to reset. ``None`` (or
``slice(None)``, which IsaacLab callers sometimes pass)
resets all environments. Otherwise expects a torch tensor
or sequence of int indices.
env_mask: Boolean environment mask with shape ``(num_envs,)``.
Takes precedence over :paramref:`env_ids`.

Newton's :meth:`Actuator.State.reset` expects a per-DOF boolean
mask of length ``num_actuators`` (= ``num_envs * dofs_per_actuator``),
Expand All @@ -188,31 +196,26 @@ def reset(self, env_ids: Sequence[int] | torch.Tensor | slice | None = None) ->
etc.). We therefore build a per-actuator per-DOF mask from the
env mask before delegating to each state.
"""
if env_ids is None or env_ids == slice(None):
if env_mask is None and (env_ids is None or env_ids == slice(None)):
for sa, sb in zip(self._states_a, self._states_b):
if sa is not None:
sa.reset(None)
if sb is not None:
sb.reset(None)
return

num_envs = len(range(self._num_envs)[env_ids]) if isinstance(env_ids, slice) else len(env_ids)
if num_envs == 0:
return
env_mask = wp.zeros(self._num_envs, dtype=wp.bool, device=self._device)
if isinstance(env_ids, slice):
wp.to_torch(env_mask)[env_ids] = True
else:
# Torch indexed scalar assignment uploads True and synchronizes on CUDA.
indices = (
wp.from_torch(env_ids)
if isinstance(env_ids, torch.Tensor)
else wp.array(env_ids, dtype=wp.int32, device=self._device)
if env_mask is None:
num_envs = len(range(self._num_envs)[env_ids]) if isinstance(env_ids, slice) else len(env_ids)
if num_envs == 0:
return
env_mask = resolve_1d_mask(
ids=env_ids,
all_mask=self._all_env_mask,
scratch_mask=self._scratch_env_mask,
device=self._device,
)
wp.launch(set_mask_kernel, dim=num_envs, inputs=[env_mask, indices], device=self._device)

for act, sa, sb in zip(self.actuators, self._states_a, self._states_b):
per_dof_mask = wp.zeros(act.indices.shape[0], dtype=wp.bool, device=self._device)
for act, sa, sb, per_dof_mask in zip(self.actuators, self._states_a, self._states_b, self._reset_dof_masks):
wp.launch(
build_per_dof_env_mask_kernel,
dim=act.indices.shape[0],
Expand Down
10 changes: 1 addition & 9 deletions source/isaaclab/isaaclab/actuators/newton/kernels.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
"""Shared Warp kernels for the Newton actuator fast path."""

from collections.abc import Sequence
from typing import Any

import torch
import warp as wp

from ...utils import index_fill_

# ---------------------------------------------------------------------------
# Adapter / per-actuator helper kernels: per-DOF zeroing, env-mask building,
# Adapter / per-actuator helper kernels: per-DOF zeroing
# and per-DOF env-mask projection (used by :meth:`NewtonActuatorAdapter.reset`).
# Parameter reads and writes go through Newton's selection API instead.
# ---------------------------------------------------------------------------
Expand All @@ -27,13 +26,6 @@ def zero_at_indices_kernel(data: wp.array(dtype=wp.float32), indices: wp.array(d
data[indices[i]] = 0.0


@wp.kernel(enable_backward=False)
def set_mask_kernel(mask: wp.array(dtype=wp.bool), indices: wp.array(dtype=Any)):
"""Set selected mask entries without converting or uploading the indices."""
i = wp.tid()
mask[indices[i]] = True


@wp.kernel(enable_backward=False)
def build_per_dof_env_mask_kernel(
indices: wp.array(dtype=wp.uint32),
Expand Down
11 changes: 8 additions & 3 deletions source/isaaclab/isaaclab/actuators/newton/physx_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,15 @@ def compute(self, collection: ActuatorCollection, dt: float) -> None:
return
self._run_native_actuator_kernels(collection, dt)

def reset(self, env_ids: Sequence[int] | slice) -> None:
"""Reset selected native actuator state."""
def reset(self, env_ids: Sequence[int] | slice | None = None, env_mask: wp.array | None = None) -> None:
"""Reset selected native actuator state.

Args:
env_ids: Environments to reset. Defaults to all environments.
env_mask: Environment mask. Takes precedence over ``env_ids``. Shape is (num_instances,).
"""
if self.adapter is not None:
self.adapter.reset(env_ids)
self.adapter.reset(env_ids, env_mask)

def _run_native_actuator_kernels(self, collection: ActuatorCollection, dt: float) -> None:
from . import kernels as actuator_kernels # noqa: PLC0415
Expand Down
Loading
Loading