Skip to content

[Warp] Part 3/12: Reset only the masked environments and fix manager-based Warp environment construction - #6646

Open
hujc7 wants to merge 45 commits into
isaac-sim:mainfrom
hujc7:jichuanh/warp-scene-mask-native
Open

hujc7 wants to merge 45 commits into
isaac-sim:mainfrom
hujc7:jichuanh/warp-scene-mask-native

Conversation

@hujc7

@hujc7 hujc7 commented Jul 21, 2026 •

Copy link
Copy Markdown
Collaborator

Review Map

PR Status Depends on Exact changes
#8821 Part 1/12: shared id and mask helpers, mask writers without host sync — —
#8824 Part 2/12: PhysX tendon mask setters through the masks #8821 link
📌 #6646 Part 3/12: mask-correct partial resets #8821 link
#8783 Part 4/12: shared Warp RNG state #6646 link
#6607 Part 5/12: per-term capture, stable stepping parity #8783 link
#8228 Part 6/12: Warp commands, Rough tasks, live term changes #6607 link
#6582 Part 7/12: Shadow Warp twin, Allegro twin fixes #6607 link
#7012 Part 8/12: --video on the Warp frontend — —
#8856 Part 9/12: stable SceneEntityCfg Warp selections, capture utilities #8228 link
---
config:
  look: neo
  flowchart:
    curve: basis
---
flowchart TD
  P1("<b>#8821</b> · Part 1<br/>id/mask helpers")
  P2("<b>#8824</b> · Part 2<br/>PhysX tendon masks")
  P3("📌 <b>#6646</b> · Part 3<br/>masked resets")
  P4("<b>#8783</b> · Part 4<br/>WarpRng")
  P5("<b>#6607</b> · Part 5<br/>per-term capture")
  P6("<b>#8228</b> · Part 6<br/>commands, Rough")
  P7("<b>#6582</b> · Part 7<br/>Shadow twin")
  P8("<b>#7012</b> · Part 8<br/>--video, independent")
  P9("<b>#8856</b> · Part 9<br/>stable SceneEntityCfg, capture")
  P1 --> P2
  P1 --> P3 --> P4 --> P5
  P5 --> P6
  P5 --> P7
  P6 --> P9
  style P3 stroke-width:3px
Loading

Summary

Masked resets on Newton, OvPhysX and PhysX reset only the selected environments' actuator, wrench, sensor and deformable state (main resets every environment's), and no longer synchronize with the host, so the Warp frontend can record them in CUDA graphs.
InteractiveScene.reset takes the mask too, so the Warp environments use the stable scene.

Description

Update (2026-10-26): InteractiveScene.reset(env_mask=...) forwards the mask to every asset and sensor; InteractiveSceneWarp is removed. #8821 now owns the mask writers this PR used to change.

1. Fixes on main

  1. Articulation.reset(env_mask=...) (Newton, OvPhysX, PhysX) reset the actuator state of every environment.
  2. Newton and PhysX RigidObject / RigidObjectCollection resets ignored env_mask and cleared every environment's external wrenches.
  3. InteractiveSceneWarp.reset(env_mask) reset deformables, surface grippers and sensors in every environment and skipped cable objects.
  4. A contrib Multirotor reset with only env_mask reset every environment's thrusters.

2. Capture readiness

Actuator models, DelayBuffer and backend-native actuators reset from the mask without converting it to indices; masked ray-caster drift is resampled in a Warp kernel.

3. Breaking changes

  1. ActuatorBase.reset takes env_mask; custom actuator models must reset from it without a host sync.
  2. isaaclab_experimental.envs.InteractiveSceneWarp is removed; use isaaclab.scene.InteractiveScene.

4. Evidence (MEASURED, desk RTX PRO 6000)

  • At 93daa9b9bf6: Newton native-actuator (40), articulation (39) and Warp frontend (29) tests pass; InteractiveScene.reset mask forwarding is a stub-scene unit test (test_interactive_scene.py); Warp Cartpole, Flat-Go2, Cartpole-Direct and torch Cartpole run with the stable scene (4096 envs, 150 steps with resets).
  • New tests fail on main: actuator and wrench isolation, the OvPhysX reset, the PhysX wrench reset, and masked resets under capture (cudaErrorStreamCaptureImplicit). Cable-object forwarding and the surface-gripper mask reset have no test.

5. Follow-ups

  • OvPhysX RigidObjectCollection mask writers still convert on the host: the OvPhysX wheel's writes wait on the legacy stream (Warp CUDA error 906).

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (existing functionality will not work without user modification)

Release backport

  • Backport this pull request to the active release branch after it merges into main

Screenshots

Not applicable.

Checklist

Docker and GPU tests run on demand. Push the commits you want tested, then
comment run-ci on the pull request.

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with uv run isaaclab --format
  • I have made corresponding changes to the documentation: the Warp guides already describe mask-based resets
  • My changes generate no new warnings
  • I have validated the changed behavior with focused coverage and applied the test-audit criteria to any test changes
  • I have added a changelog fragment under source/<pkg>/changelog.d/ for every touched package (do not edit CHANGELOG.rst or bump package versions — CI handles that)
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label Jul 21, 2026
@hujc7
hujc7 force-pushed the jichuanh/warp-scene-mask-native branch from c589567 to 0086860 Compare July 21, 2026 19:15
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jul 21, 2026
@hujc7
hujc7 force-pushed the jichuanh/warp-scene-mask-native branch 2 times, most recently from 58c7ed4 to 6d49e32 Compare July 22, 2026 17:49
kellyguo11 added a commit that referenced this pull request Jul 24, 2026
…asks (#5504)

## Review Map

- A stacked PR’s page shows the cumulative diff of its dependency chain;
the "Exact changes" link pins that PR’s own commit range.
- SHA links can go stale after a branch update; the copy on #5504 is
refreshed first.

| PR | Status | Depends on | Exact changes |
|---|---|---|---|
| 📌 #5504 Part 1: frontend bridge (stable ids on the warp runtime) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/5504?label=)
| — | — |
| #6607 Part 2: mask-first frontend (draft) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6607?label=)
| #5504 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6607/changes/00ae695ac63e67ca678b91a837d3737529d2ec91..f68d03f40854b31a36063c5068f2933d32ea5db9)
|
| #6646 Part 3: scene reset mask-native + capture-ready (draft, base
rewritten — pending rebase onto #6607) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6646?label=)
| #6607 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6646/changes/4360622bde446c52c3fc85924639f9d1119d6e95..6d49e32f11e15894a4a0e49161a356ec79679ac6)
|
| #6580 Part 4: OVPhysX backend (draft) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6580?label=)
| #5504 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6580/changes/fc37fa65ad95d1ac6e3f32e721329ef715899d37..716cef20979ca6c578a6e595812291c7b1a282fc)
|
| #6611 Part 5: persistent-launch speedups (draft, absorbs #6551) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6611?label=)
| #6646 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6611/changes/6d49e32f11e15894a4a0e49161a356ec79679ac6..6e3da794215da03745a9bc8d35790e22262b099a)
|

## 1. Summary

- `--frontend {torch,warp}` on the shared RL CLI (train **and play**)
runs **stable** task ids on the warp runtime — no duplicated configs, no
parallel warp task registrations at all (end state pinned by test). The
`rlinf` integration constructs environments inside the external
framework and is not frontend-routable (known limitation).
- **1.24–1.70× faster end-to-end** than torch on the same tasks,
identical Newton physics (§3.1).
- Manager-based: `WarpFrontend` adapts the stable cfg in place; MDP
twins resolve by name on the mirrored experimental package tree —
deterministic, registration-free, missing twins reported in one
aggregated failure.
- Direct: the stable registration declares its warp class via
`warp_entry_point`; only the env class swaps, the cfg is shared.
- Stable observation-noise cfgs (constant/uniform/gaussian) swap to
warp-native twins during adaptation; cfgs without a twin (class-based
noise models, customized funcs, tensor-valued params) are a hard error
instead of silently dropping noise. The warp observation manager rejects
non-warp noise cfgs and plumbs the shared per-env RNG state.
- Plus: warp adapters for the material/mass randomization startup
events; `isaaclab_tasks_experimental` mirrors the stable `core/<task>`
layout; `Metrics/success_rate` restored under warp.

## 2. Migration map

| Retired | Replacement |
|---|---|
| `Isaac-{Cartpole,Humanoid,Ant}-Warp-v0`, `Isaac-Reach-Franka-Warp-v0`
(+`-Play`) | stable id + `--frontend warp presets=newton_mjwarp` |
| `Isaac-Velocity-Flat-<Robot>-Warp-v0` (+`-Play`), all robots | stable
id + `--frontend warp presets=newton_mjwarp` |
| `Isaac-{Cartpole,Ant,Humanoid}-Direct-Warp-v0`,
`Isaac-Reorient-Cube-Allegro-Direct-Warp-v0` | stable id + `--frontend
warp presets=newton_mjwarp` (via `warp_entry_point`) |

## 3. Test plan

- [x] Merged current `develop`; `./isaaclab.sh -f` clean on all files.
- [x] Re-merged develop (task-id catalog update #6606, entrypoints
refactor); environments catalog regenerated; conversion sweep + warp
smokes (`Isaac-Velocity-Flat-UnitreeGo2`, `Isaac-Cartpole-Direct`)
re-run green; pre-commit clean on all files.
- [x] 142 focused tests: frontend units, cfg-conversion sweep over every
covered stable id, no-warp-registrations end-state pin, shared-CLI
tests.
- [x] 5-iteration RSL-RL trainings exit clean (`Training time:` present,
no traceback): `Isaac-Cartpole` (torch); `Isaac-Cartpole`,
`Isaac-Humanoid`, `Isaac-Cartpole-Direct`, `Isaac-Ant-Direct`,
`Isaac-Velocity-Flat-AnymalD`, `Isaac-Velocity-Flat-H1` (warp;
randomization events active); `Isaac-Reorient-Cube-Allegro-Direct`
(warp). `Metrics/success_rate` reported under warp.

### 3.1 Frontend A/B benchmark

Same stable task id and cfg on both sides, `presets=newton_mjwarp` on
**both** (identical Newton physics — only `--frontend` differs); rsl_rl,
4096 envs, 300 iterations, headless, one L40 per run, single run per
cell. Metric: rsl_rl `Training time:` — learn-loop wall-clock (env
stepping + PPO update; warp includes its one-time CUDA-graph capture).
PPO-update cost is common to both, so the env-pipeline gain exceeds the
end-to-end ratio.

| Task | torch | warp | end-to-end | final reward (torch / warp) |
|---|---|---|---|---|
| `Isaac-Cartpole` | 58.2 s | 39.7 s | 1.46× | 4.95 / 4.95 |
| `Isaac-Humanoid` | 162.0 s | 110.5 s | 1.47× | 149.1 / 179.8 |
| `Isaac-Ant` | 109.8 s | 64.5 s | 1.70× | 82.1 / 77.1 |
| `Isaac-Velocity-Flat-AnymalD` | 162.4 s | 130.7 s | 1.24× | 20.3 /
21.4 |

## 4. Out of scope / follow-ups

- No video-recorder plumbing on warp envs; rough terrain blocked on Warp
`TerrainImporter` APIs; no twins for IK/OSC actions, `height_scan`, or
Digit/Spot-specific terms.
- OVPhysX support for the warp frontend prepared as a follow-up PR
(physics gate widening + backend data-parity test).
- Candidate refactor: fold the ~300 lines of converged plumbing shared
by `DirectRLEnvWarp` and stable `DirectRLEnv` into a common base.

---------

Co-authored-by: Kelly Guo <kellyguo123@hotmail.com>
matthewtrepte pushed a commit to matthewtrepte/IsaacLab that referenced this pull request Aug 4, 2026
…asks (isaac-sim#5504)

## Review Map

- A stacked PR’s page shows the cumulative diff of its dependency chain;
the "Exact changes" link pins that PR’s own commit range.
- SHA links can go stale after a branch update; the copy on isaac-sim#5504 is
refreshed first.

| PR | Status | Depends on | Exact changes |
|---|---|---|---|
| 📌 isaac-sim#5504 Part 1: frontend bridge (stable ids on the warp runtime) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/5504?label=)
| — | — |
| isaac-sim#6607 Part 2: mask-first frontend (draft) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6607?label=)
| isaac-sim#5504 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6607/changes/00ae695ac63e67ca678b91a837d3737529d2ec91..f68d03f40854b31a36063c5068f2933d32ea5db9)
|
| isaac-sim#6646 Part 3: scene reset mask-native + capture-ready (draft, base
rewritten — pending rebase onto isaac-sim#6607) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6646?label=)
| isaac-sim#6607 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6646/changes/4360622bde446c52c3fc85924639f9d1119d6e95..6d49e32f11e15894a4a0e49161a356ec79679ac6)
|
| isaac-sim#6580 Part 4: OVPhysX backend (draft) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6580?label=)
| isaac-sim#5504 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6580/changes/fc37fa65ad95d1ac6e3f32e721329ef715899d37..716cef20979ca6c578a6e595812291c7b1a282fc)
|
| isaac-sim#6611 Part 5: persistent-launch speedups (draft, absorbs isaac-sim#6551) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6611?label=)
| isaac-sim#6646 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6611/changes/6d49e32f11e15894a4a0e49161a356ec79679ac6..6e3da794215da03745a9bc8d35790e22262b099a)
|

## 1. Summary

- `--frontend {torch,warp}` on the shared RL CLI (train **and play**)
runs **stable** task ids on the warp runtime — no duplicated configs, no
parallel warp task registrations at all (end state pinned by test). The
`rlinf` integration constructs environments inside the external
framework and is not frontend-routable (known limitation).
- **1.24–1.70× faster end-to-end** than torch on the same tasks,
identical Newton physics (§3.1).
- Manager-based: `WarpFrontend` adapts the stable cfg in place; MDP
twins resolve by name on the mirrored experimental package tree —
deterministic, registration-free, missing twins reported in one
aggregated failure.
- Direct: the stable registration declares its warp class via
`warp_entry_point`; only the env class swaps, the cfg is shared.
- Stable observation-noise cfgs (constant/uniform/gaussian) swap to
warp-native twins during adaptation; cfgs without a twin (class-based
noise models, customized funcs, tensor-valued params) are a hard error
instead of silently dropping noise. The warp observation manager rejects
non-warp noise cfgs and plumbs the shared per-env RNG state.
- Plus: warp adapters for the material/mass randomization startup
events; `isaaclab_tasks_experimental` mirrors the stable `core/<task>`
layout; `Metrics/success_rate` restored under warp.

## 2. Migration map

| Retired | Replacement |
|---|---|
| `Isaac-{Cartpole,Humanoid,Ant}-Warp-v0`, `Isaac-Reach-Franka-Warp-v0`
(+`-Play`) | stable id + `--frontend warp presets=newton_mjwarp` |
| `Isaac-Velocity-Flat-<Robot>-Warp-v0` (+`-Play`), all robots | stable
id + `--frontend warp presets=newton_mjwarp` |
| `Isaac-{Cartpole,Ant,Humanoid}-Direct-Warp-v0`,
`Isaac-Reorient-Cube-Allegro-Direct-Warp-v0` | stable id + `--frontend
warp presets=newton_mjwarp` (via `warp_entry_point`) |

## 3. Test plan

- [x] Merged current `develop`; `./isaaclab.sh -f` clean on all files.
- [x] Re-merged develop (task-id catalog update isaac-sim#6606, entrypoints
refactor); environments catalog regenerated; conversion sweep + warp
smokes (`Isaac-Velocity-Flat-UnitreeGo2`, `Isaac-Cartpole-Direct`)
re-run green; pre-commit clean on all files.
- [x] 142 focused tests: frontend units, cfg-conversion sweep over every
covered stable id, no-warp-registrations end-state pin, shared-CLI
tests.
- [x] 5-iteration RSL-RL trainings exit clean (`Training time:` present,
no traceback): `Isaac-Cartpole` (torch); `Isaac-Cartpole`,
`Isaac-Humanoid`, `Isaac-Cartpole-Direct`, `Isaac-Ant-Direct`,
`Isaac-Velocity-Flat-AnymalD`, `Isaac-Velocity-Flat-H1` (warp;
randomization events active); `Isaac-Reorient-Cube-Allegro-Direct`
(warp). `Metrics/success_rate` reported under warp.

### 3.1 Frontend A/B benchmark

Same stable task id and cfg on both sides, `presets=newton_mjwarp` on
**both** (identical Newton physics — only `--frontend` differs); rsl_rl,
4096 envs, 300 iterations, headless, one L40 per run, single run per
cell. Metric: rsl_rl `Training time:` — learn-loop wall-clock (env
stepping + PPO update; warp includes its one-time CUDA-graph capture).
PPO-update cost is common to both, so the env-pipeline gain exceeds the
end-to-end ratio.

| Task | torch | warp | end-to-end | final reward (torch / warp) |
|---|---|---|---|---|
| `Isaac-Cartpole` | 58.2 s | 39.7 s | 1.46× | 4.95 / 4.95 |
| `Isaac-Humanoid` | 162.0 s | 110.5 s | 1.47× | 149.1 / 179.8 |
| `Isaac-Ant` | 109.8 s | 64.5 s | 1.70× | 82.1 / 77.1 |
| `Isaac-Velocity-Flat-AnymalD` | 162.4 s | 130.7 s | 1.24× | 20.3 /
21.4 |

## 4. Out of scope / follow-ups

- No video-recorder plumbing on warp envs; rough terrain blocked on Warp
`TerrainImporter` APIs; no twins for IK/OSC actions, `height_scan`, or
Digit/Spot-specific terms.
- OVPhysX support for the warp frontend prepared as a follow-up PR
(physics gate widening + backend data-parity test).
- Candidate refactor: fold the ~300 lines of converged plumbing shared
by `DirectRLEnvWarp` and stable `DirectRLEnv` into a common base.

---------

Co-authored-by: Kelly Guo <kellyguo123@hotmail.com>
A mask-only Articulation.reset called ActuatorCollection.reset(None), which
cleared delay buffers, network history, and Newton-native actuator state for
every environment. Newton rigid objects and collections dropped the mask
before resetting their wrench composers, clearing every environment's
persistent wrench.

ActuatorCollection.reset now takes env_mask. Isaac Lab actuator models still
reset by index, so the collection converts the mask to indices once for all
groups, and skips the conversion when no group carries reset state. Native
actuator state resets from the mask through a new
ActuatorControl.reset_native_actuators_mask hook; Newton and OVPhysX pass the
mask to the Newton actuator adapter, and the base default converts to indices
so backends that only implement the index hook stay correct.
InteractiveSceneWarp.reset passed env_ids=None to deformable objects, surface
grippers, and sensors on a masked reset, so every environment's sensor state
was cleared on each partial reset, and it never reset cable objects.

Forward the mask to every entity family in the stable scene's order. Surface
grippers use their reset_mask method. Cable objects take env_mask like the
other scene assets, so the scene does not convert the mask for a reset that
holds no state.
RigidObjectCollection.write_body_*_to_sim_mask converted masks to indices
with torch.nonzero before delegating to the index writers, so the mask
writers synchronized the host and could not be captured in a CUDA graph,
although their docstrings name them as the graph-capable path. They now
launch masked kernels over the full environment-body grid, and body_ids
selections resolve to a mask through a preallocated scratch buffer.

BaseRayCaster.reset compacted a mask with nonzero before resampling drift.
A masked reset now resamples every environment and keeps the new values
where the mask is set; index and slice selections are unchanged.
isaac-sim#8079 added ObservationGroupCfg.history_order and taught the stable
observation manager to skip it as a group setting. The Warp manager's skip
list was not updated, so it parsed the field as a term and raised a
TypeError for every observation group, and no manager-based Warp
environment could be constructed.

Skip history_order like the other group settings. The Warp manager raises
NotImplementedError for any term with history, and history_order only
takes effect with history, so a time-ordered group cannot be silently
reordered wrong.
The fixed-tendon set_*_mask methods and
write_fixed_tendon_properties_to_sim_mask converted masks to indices with
torch.nonzero and delegated to the index writers, so they synchronized the
host and could not be captured in a CUDA graph.

Write the masked cells in-kernel instead: scalar and full data go into the
staging buffers through masked kernels, and the property writer copies the
masked cells of each staging buffer into its simulation binding. The mask
compaction helpers have no remaining callers and are removed.
A masked Articulation.reset on the Newton-native actuator path allocated a
per-DOF mask for every actuator on each call, and a masked ray-caster
reset sampled drift with torch ops and uploaded its ranges, so neither
could run inside a CUDA graph captured on Warp's stream.

NewtonActuatorAdapter preallocates its per-DOF reset masks. BaseRayCaster
resamples masked drift in a Warp kernel from per-environment random states
seeded from torch's global generator at initialization, with the ranges
passed as launch arguments; index and slice resets keep the torch path.
The Newton fixed-tendon position-target setters raised a host-side dirty
flag, and write_data_to_sim scattered the buffered targets into MuJoCo's
controls only while it was set. A setter recorded in a CUDA graph raised
the flag once, at capture time, so later replays updated the target buffer
on the device but never reached the solver.

Write the buffered targets on every step whenever the articulation has
tendon actuators, and drop the flag from the Newton setters. The write
costs about 60 us per call on Shadow Hand; gating it on a device-side flag
would need Newton's control-array mapping re-implemented in a kernel.
@hujc7
hujc7 force-pushed the jichuanh/warp-scene-mask-native branch from 6d49e32 to 12a3b4a Compare October 1, 2026 02:08
@hujc7 hujc7 changed the title [WARP] Cleanup Part 3: Make scene reset mask-native and capture-ready [Warp] Part 1/5: Reset only the masked environments and fix manager-based Warp environment construction Oct 1, 2026
@hujc7

hujc7 commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Oct 1, 2026
@hujc7
hujc7 marked this pull request as ready for review October 26, 2026 16:59
@hujc7
hujc7 requested a review from a team October 26, 2026 16:59
@greptile-apps

greptile-apps Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 3/5

[Medium impact] The changes affect reset behavior across several simulation backends and shared asset APIs.

Fix repeated tendon property refreshes and unselected gripper resets before merging.

Findings

  1. P1 Replays leave tendon properties stale ▶
  2. P1 Unselected grippers still open ▶
  3. P2 Reverse slices stop working ▶
  4. P2 Drift reset ignores copied mask ▶

Summary

Adds mask-based partial resets across actuators, assets and sensors, and shares selection helpers across backends.

  • Actuator resets clear history only for selected environments.
  • Warp scene resets forward the mask to the selected assets.
  • Rigid-object resets clear wrenches only for selected environments.
  • Ray-caster resets resample drift only for selected environments.
  • Backend selection helpers resolve ids and masks in a shared way.

Acknowledged scope:

  • hujc7 explicitly keeps tendon targets behind the host flag for performance; callers must set targets eagerly.
  • hujc7 defers captured OVPhysX collection writes because the upstream wheel waits on the legacy stream.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Masked scene reset] --> B[Actuator state]
    A --> C[Wrench buffers]
    A --> D[Deformables and cables]
    A --> E[Sensors]
    A --> F[Surface grippers]
    B --> G[Selected environments]
    C --> G
    D --> G
    E --> G
    F --> H[Mask omitted: every gripper opens]
Loading

Reviews (1) · Last reviewed commit: "Write Newton tendon targets behind the h..." · Reviewed by Greptile

Comment on lines +3170 to +3171
# the solver keeps its own copy of the tendon properties and only re-reads them when notified
self._backend_manager.add_model_change(ModelFlags.TENDON_PROPERTIES)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Replays leave tendon properties stale

write_fixed_tendon_properties_to_sim_mask records the copies into a CUDA graph, but add_model_change runs only in Python during capture. After the first replay and sim.step(), the queued notification is cleared. A second replay writes new properties without refreshing the solver, so physics keeps using the previous stiffness, damping and limits.

Make the solver refresh happen on every replay. Test two replays with different values, separated by physics steps.

Comment on lines +27 to +28
.. caution::
If both ``env_ids`` and ``env_mask`` are provided, ``env_mask`` takes precedence.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Unselected grippers still open

The scene reset fix still omits the mask for surface grippers. Calling scene.reset(env_mask=mask) reaches surface_gripper.reset(None), which opens every gripper. This releases objects in environments whose episodes are still running.

Call reset_mask(env_mask) when a mask is supplied, and add a scene test that keeps an unselected gripper closed.


"""Warp utility functions and shared kernels for isaaclab_experimental."""

from isaaclab.utils.warp.utils import resolve_1d_mask

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Reverse slices stop working

Replacing the experimental resolve_1d_mask drops negative-step slice support. For example, resolve_env_mask(env_ids=slice(None, None, -2)) previously expanded the slice with Python range. The shared helper instead assigns through a PyTorch slice, which raises because its step must be positive.

Preserve the range-based path for negative steps and add a regression test.

Comment on lines +129 to +131
inputs=[
env_mask,
wp.vec2f(*self.cfg.drift_range),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Drift reset ignores copied mask

For a CUDA ray caster given a CPU Warp mask, _resolve_indices_and_mask copies the mask to CUDA and resets the sensor correctly. The new drift kernel still receives the original CPU env_mask, so its CUDA launch fails when drift is enabled.

Pass the device-correct reset_mask to this kernel instead.

Suggested change
inputs=[
env_mask,
wp.vec2f(*self.cfg.drift_range),
inputs=[
reset_mask,
wp.vec2f(*self.cfg.drift_range),

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isaac Lab Review Bot

Needs attention: Compatibility and deprecation (1), Implementation (1), Style consistency (1), Test quality (1). Other reviewed categories look good.

  • PR description: The title still claims a manager-construction fix absent from the production diff; retitle it, remove dated/reverted history and the unsupported 2–4% figure, and correct the surface-gripper reset claim.
  • Design and architecture: Architecture looks good.
  • Scope and over-engineering: No over-engineering issues.
  • API: API changes look good.
  • Compatibility and deprecation: Breaking changes: ActuatorCollection always calls custom ActuatorBase.reset with env_mask, so existing subclasses fail even on unmasked resets; preserve old calls and add a warned transition before requiring the keyword.
  • Implementation: InteractiveSceneWarp promises mask precedence but calls surface_gripper.reset with env_ids only, resetting every gripper on mask-only resets; call reset_mask with env_mask.
  • Style consistency: ImplicitActuator and IdealPDActuator narrow ActuatorBase.reset’s env_ids annotation by omitting slice; use the base signature in every override.
  • Test quality: The Newton tendon capture test checks staged buffers, so it cannot detect a broken simulation-copy kernel; assert the sim_bind_fixed_tendon* buffers after replay.

Significant concerns. Posted 4 inline findings.

Automated review; human maintainers own approval decisions.

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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Critical · Compatibility — Actuator reset break lacks deprecation

env_mask is passed on every reset, so any custom ActuatorBase subclass declaring reset(env_ids) raises TypeError even for unmasked resets. Forward env_mask only when set, with a deprecation warning.

"""

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Warning · Style Consistency — Reset overrides narrow base selector type

ActuatorBase.reset now accepts slice, and DelayedPDActuator keeps it, but these implicit and ideal overrides annotate Sequence[int] | None. Use the base signature in every override.

"""Reset scene entities using either env_ids or a boolean env_mask.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Warning · Implementation — Masked scene reset skips grippers

This caution promises mask precedence, but surface_gripper.reset(env_ids) below still receives ids only, so a mask-only scene reset clears every environment's gripper. Dispatch through reset_mask(env_mask).

articulation.set_fixed_tendon_position_limit_mask(
limit=limits, fixed_tendon_mask=tendon_mask, env_mask=env_mask
)
articulation.write_fixed_tendon_properties_to_sim_mask(fixed_tendon_mask=tendon_mask, env_mask=env_mask)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Warning · Test Quality — Tendon capture test asserts staged buffers

Assertions read data.fixed_tendon_, the buffers the setters write, so a broken copy_fixed_tendon_properties_with_mask kernel still passes. Assert the sim_bind_fixed_tendon buffers after replay.

hujc7 added 3 commits October 26, 2026 13:59
InteractiveScene.reset takes env_mask and forwards it to every asset and
sensor, so the Warp environments use the stable scene and
InteractiveSceneWarp is removed.
# Conflicts:
#	source/isaaclab_newton/isaaclab_newton/assets/articulation/actuator_control.py
#	source/isaaclab_newton/test/assets/test_newton_actuators_newton.py
@hujc7

hujc7 commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Oct 26, 2026

@AntoineRichard AntoineRichard left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Experimental review tooling 🤖

Thanks for opening this PR to IsaacLab! We're currently experimenting with automated review tooling, and we'd appreciate a little human time to review the review! The reviewer is under review, too.

Please reply with feedback on useful findings, false positives, and anything the tool missed.

Open Code Review v1.13.3 with Sol6.1 (azure/openai/gpt-6.1-sol, via NVIDIA Inference Hub) reviewed 93daa9b9bf62af55010f9a0a892a6d48017c8f2e.

Reasoning effort: high. Review effort: medium.

Result: OCR reported 6 observations. 4 potential issues are posted inline and 2 additional suggestions are summarized below.

Additional suggestions from the tool
  • source/isaaclab_newton/test/sensors/test_newton_raycast_sensor.py:231 (medium, test): Independent uniform samples can legitimately compare equal under torch.allclose's default tolerance. For the scalar z drift in [0.1, 0.2], even distinct samples within roughly 1–2e-6 trigger a failure. Neither this test nor its simulation fixture fixes the RNG seed, so this assertion and its graph-replay counterpart can fail intermittently despite correct resampling. Use explicitly seeded expected samples, or verify RNG-state advancement without requiring every scalar draw to differ.
  • source/isaaclab_newton/changelog.d/jichuanh-id-mask.changed.rst:6 (low, documentation): The mask helpers use resolve_1d_mask, not resolve_ids. Please distinguish the two here: resolve_ids(mask=...) converts masks to indices and synchronizes the host, whereas the updated mask writers preserve masks.

Scope: 90 of 95 changed files selected, including Python tests and .rst files. This was a static review; simulation tests were not run.

Review time: 9m16s. Token usage: 3,392,693.


"""Warp utility functions and shared kernels for isaaclab_experimental."""

from isaaclab.utils.warp.utils import resolve_1d_mask

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Experimental review tooling · medium · bug

This redirect regresses negative-step slice selections exposed by ManagerBasedEnvWarp.resolve_env_mask. The previous experimental helper expanded slices with slice.indices() and range(), whereas the core helper uses wp.to_torch(scratch_mask)[ids] = True. PyTorch rejects negative slice steps, so inputs such as env_ids=slice(None, None, -2) now raise ValueError instead of producing a mask. Preserve negative-step handling in the core helper before switching the export, and add a resolve_1d_mask regression test; the new negative-step tests currently cover only resolve_ids.

"""

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:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Experimental review tooling · high · bug

Mask support is added only to the actuator collection, but Multirotor.reset() still accepts only env_ids. The updated InteractiveScene.reset(env_mask=...) forwards that keyword to every articulation, so a scene containing a multirotor raises TypeError before reaching this code. Update Multirotor.reset() to accept and forward env_mask, and use the same selection when restoring thrust_target. Add a regression test through the public reset method; the collection-only test bypasses this failure.

Comment on lines +129 to +130
inputs=[
env_mask,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Experimental review tooling · medium · bug

Pass reset_mask to this kernel instead of the original env_mask. _resolve_indices_and_mask() copies a Warp mask to the sensor's device when necessary, but this launch bypasses that normalized result. For example, resetting a CUDA sensor with a CPU Warp mask and nonzero drift now fails with a device mismatch after its timing buffers have already been reset.

device=self.device,
)
# the solver keeps its own copy of the tendon properties and only re-reads them when notified
self._backend_manager.add_model_change(ModelFlags.TENDON_PROPERTIES)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Experimental review tooling · medium · bug

This notification runs only during CUDA-graph capture, not on replay. add_model_change() adds to a Python set that NewtonManager.step() clears after notifying the solver. After replay → step → change inputs → replay → step, the simulation-bound tendon buffers update again, but the solver's separate tendon properties remain stale. Make the notification replay-aware (or capture the solver refresh), and extend the CUDA test to check solver.mjw_model after two replays separated by physics steps.

@hujc7 hujc7 changed the title [Warp] Part 3/8: Reset only the masked environments and fix manager-based Warp environment construction [Warp] Part 3/12: Reset only the masked environments and fix manager-based Warp environment construction Oct 27, 2026
hujc7 added 2 commits October 27, 2026 12:08
Assert the no-copy slice views once in the resolve_ids test and keep one
wiring line per backend resolver in the asset contracts. Merge the two
resolve_ids tests into one dtype-parametrized table, use a fixed small
mask, and scope the CUDA-only resolve_1d_mask tests to the CUDA devices.

Drop the Newton early return in the articulation writer contract so the
fixed-tendon mask setters are checked for extra environments with torch
and warp data, and remove the narrower standalone Newton test. Fold the
collection body_ids mask-writer check into the writer read-back test and
remove the duplicate ProxyArray check from the wrench composer test.
Replace the Newton scene test, which built a simulation and stepped it
to check that a masked scene reset reaches one sensor, with a stub-scene
unit test of InteractiveScene.reset: every asset and sensor receives the
mask, surface grippers receive the masked ids, and a reset by ids passes
no mask.

Drop the eager masked cases that the CUDA-graph replay tests already
cover for the Newton actuator state and the ray caster drift, and remove
the Warp observation manager history_order test, whose fix is already on
main and is unrelated to masked resets.
@hujc7

hujc7 commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Oct 27, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

asset New asset feature or request documentation Improvements or additions to documentation infrastructure isaac-lab Related to Isaac Lab team isaac-mimic Related to Isaac Mimic team isaac-sim Related to Isaac Sim team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants