Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 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
12a3b4a
Merge remote-tracking branch 'upstream/develop' into jichuanh/warp-sc…
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
e35945b
Merge remote-tracking branch 'upstream/develop' into jichuanh/warp-sc…
hujc7 Oct 4, 2026
e9535c6
Merge remote-tracking branch 'upstream/main' into jichuanh/warp-scene…
hujc7 Oct 20, 2026
f6d31ca
Drop the history_order changelog entry that main already ships
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
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
6c31123
Write Newton tendon targets behind the host flag again
hujc7 Oct 26, 2026
44021e5
Reset only the masked environments from the stable scene
hujc7 Oct 26, 2026
43bb968
Merge remote-tracking branch 'upstream/main' into jichuanh/id-mask
hujc7 Oct 26, 2026
93daa9b
Merge branch 'jichuanh/id-mask' into jichuanh/warp-scene-mask-native
hujc7 Oct 26, 2026
e390289
Trim duplicate id-resolution and mask-writer tests
hujc7 Oct 27, 2026
2048c62
Trim redundant setup from the masked-reset tests
hujc7 Oct 27, 2026
0402115
Merge branch 'jichuanh/id-mask' into jichuanh/warp-scene-mask-native
hujc7 Oct 27, 2026
38721ea
Resample masked ray-caster drift from the device mask
hujc7 Oct 27, 2026
0e9e57d
Pass the reset mask to actuator models only when one is given
hujc7 Oct 27, 2026
59f9cf5
Accept env_mask in the multirotor reset
hujc7 Oct 27, 2026
d8d4911
Match the base reset selector type in the actuator overrides
hujc7 Oct 27, 2026
13ec11c
Accept every id form main accepted in resolve_1d_mask
hujc7 Oct 27, 2026
784b0a2
Refresh the solver on every replay of the Newton tendon mask writer
hujc7 Oct 27, 2026
6a4f173
Tidy the mask writers, their docs and the selection tests
hujc7 Oct 27, 2026
bc9a8bb
Reject Newton masks whose length differs from the asset dimension
hujc7 Oct 27, 2026
981e3a4
Accept strided torch limits in the Newton tendon position limit mask …
hujc7 Oct 27, 2026
cff8f86
Run the tendon replay test before the module's shared scene opens
hujc7 Oct 27, 2026
bbb5104
Revert "Reject Newton masks whose length differs from the asset dimen…
hujc7 Oct 27, 2026
029ee47
Resolve the Newton collection writer masks inline again
hujc7 Oct 27, 2026
551e508
Launch the rewritten Newton mask writers over the mask lengths
hujc7 Oct 27, 2026
86ce1c9
Write the rewritten Newton mask writers through a core masked write
hujc7 Oct 27, 2026
0b464e2
Merge branch 'jichuanh/id-mask' into jichuanh/warp-scene-mask-native
hujc7 Oct 27, 2026
b37d231
Merge upstream main 6ef40d19a6f into jichuanh/id-mask
hujc7 Oct 28, 2026
e1c666f
Merge jichuanh/id-mask (upstream main 6ef40d19a6f) into jichuanh/warp…
hujc7 Oct 28, 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 @@ -14,16 +14,12 @@ The following classes are part of the public :mod:`isaaclab_experimental.envs` A
:nosignatures:

DirectRLEnvWarp
InteractiveSceneWarp
ManagerBasedEnvWarp
ManagerBasedRLEnvWarp

.. autoclass:: DirectRLEnvWarp
:show-inheritance:

.. autoclass:: InteractiveSceneWarp
:show-inheritance:

.. autoclass:: ManagerBasedEnvWarp
:show-inheritance:

Expand Down
4 changes: 4 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,4 @@
* Added :func:`~isaaclab.utils.warp.memory.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.memory.resolve_1d_mask` does to a mask.
* Added :func:`~isaaclab.utils.warp.memory.write_2d_with_mask`, which writes 2-D data or one scalar into a Warp array
where a row mask and a column mask are both true, launching over the mask lengths.
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` and
:class:`~isaaclab.sensors.Camera` to resolve ``env_ids`` and ``env_mask`` through
:func:`~isaaclab.utils.warp.memory.resolve_ids` and :func:`~isaaclab.utils.warp.memory.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`. The
:class:`~isaaclab.sensors.Camera` now rejects floating-point ``env_ids`` with a :class:`TypeError` and
multi-dimensional ``env_ids`` with a :class:`ValueError` instead of casting and flattening them.
* Changed :class:`~isaaclab.utils.wrench_composer.WrenchComposer` to resolve ``body_ids`` through
:func:`~isaaclab.utils.warp.memory.resolve_ids` as well, so slices other than ``slice(None)`` are accepted.
* Changed :func:`~isaaclab.utils.warp.memory.resolve_1d_mask` to make ``scratch_mask`` optional for callers that never
pass ids. Their masks are returned as given. Ids without a ``scratch_mask`` raise a :class:`ValueError`.
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,10 @@
* 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.
* Added ``env_mask`` to :meth:`~isaaclab.scene.InteractiveScene.reset`, which forwards the mask to every asset and
sensor so only the masked environments are reset, without synchronizing the host. Surface grippers still reset by
index.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
* 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`` to support masked resets and reset from it without synchronizing the host, for example through
:func:`~isaaclab.utils.array.index_fill_` or :func:`torch.where`. Resets without a mask still call
``reset(env_ids)``.
* 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
16 changes: 13 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,28 @@ 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)
# actuator models written before masked resets existed only accept indices
mask_kwargs = {} if env_mask is None else {"env_mask": 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, **mask_kwargs)
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] | slice | 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] | slice | 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] | slice | 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] | slice | 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
48 changes: 25 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.memory 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,25 @@ 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,
)
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