Skip to content

[WARP] Cleanup Part 4: Open the warp frontend to the OVPhysX backend#6580

Draft
hujc7 wants to merge 42 commits into
isaac-sim:developfrom
hujc7:jichuanh/warp-frontend-ovphysx
Draft

[WARP] Cleanup Part 4: Open the warp frontend to the OVPhysX backend#6580
hujc7 wants to merge 42 commits into
isaac-sim:developfrom
hujc7:jichuanh/warp-frontend-ovphysx

Conversation

@hujc7

@hujc7 hujc7 commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Review Map

PR Status Depends on Exact changes
#5504 Part 1: frontend bridge (stable ids on the warp runtime)
#6607 Part 2: mask-first frontend (draft) #5504 link
#6646 Part 3: scene reset mask-native + capture-ready (draft) #6607 link
📌 #6580 Part 4: OVPhysX backend (draft) #5504 link
#6611 Part 5: persistent-launch speedups (draft, absorbs #6551) #6646 link

1. Summary

  • --frontend warp now accepts OVPhysX: the physics gate takes NewtonCfg | OvPhysxCfg, so warp-frontend tasks run with presets=ovphysx as well as presets=newton_mjwarp.
  • Moved the body-frame state helpers to isaaclab.utils.warp.state_math — pure frame math with no Newton dependency; isaaclab_newton.kernels.state_kernels remains as a deprecation shim.
  • New backend data-parity test pins that every data.<field>.warp view the warp MDP twins read (articulation, contact-sensor, and joint-wrench fields) exists on both the Newton and OVPhysX data classes.
  • Docs: the warp-env Limitations section now states Newton or OVPhysX; classic PhysX remains unsupported.

2. Dependencies

3. Test plan

  • 68 tests pass on the branch: the warp-frontend suites plus the new backend data-parity sweep across both backends.
  • ./isaaclab.sh -f clean on all files.
  • OVPhysX runtime smoke (Isaac-Cartpole --frontend warp presets=ovphysx): pending — the pinned ovphysx==0.5.2 wheel is not yet installable in the dev environment; will attach the run before marking ready for review.

hujc7 added 30 commits May 5, 2026 09:37
PR isaac-sim#5297 (Decouple Renderer from Camera) replaced
`sim.get_setting('/isaaclab/visualizer')` (returned a comma-separated
string) with `sim.has_active_visualizers()` plus per-type queries; the
warp env path was missed, so it crashes with
"AttributeError: 'dict' object has no attribute 'split'" during env
construction.

Mirror the stable env's pattern:
- `has_active_visualizers()` for the gating predicate
- `has_kit()` so kitless Newton-only runs (`--viz rerun`) skip
  ViewportCameraController
Warp's ObservationTermCfg / RewardTermCfg / TerminationTermCfg had no
behavioural difference from their stable counterparts — same fields,
same base class. The override only carried Warp-first docstrings while
keeping the classes as siblings of stable's, which broke
`isinstance(stable_term, warp.TermCfg)` checks inside the experimental
managers when a stable cfg is fed through the warp runtime.

Re-export stable's term cfg classes directly. Term funcs still follow
the warp-first `func(env, out, **params)` signature at runtime; the
type annotation just lives on stable's class instead of warp's.
Lets a stable manager-based RL env cfg run on the experimental warp
runtime without a separate warp task registration. Replaces the
duplicate per-robot warp env cfgs by adapting the stable cfg in place.

Components:
- isaaclab_experimental/envs/warp_frontend.py: 'WarpFrontend' walks the
  stable cfg, swaps each `term.func` to its same-named warp twin (only
  accepting candidates whose `__module__` lives under the warp packages
  — the warp mdp module re-exports stable terms via `from … import *`,
  so a naive `getattr` would silently keep the stable function), swaps
  each action `class_type`, picks the `newton` field of any PresetCfg,
  drops sensors with no warp counterpart (`height_scanner`), and
  in-place class-promotes `SceneEntityCfg` instances so warp kernels
  see the `joint_mask` / *\_ids_wp` cached fields. A
  `WarpAdaptReport` records every term that had no warp twin and
  surfaces them via the logger; `strict=True` makes the same condition
  raise `LookupError` instead.
- scripts/reinforcement_learning/rsl_rl/train.py: '--manager=warp' flag
  routes the constructed env through `WarpFrontend.build` instead of
  `gym.make`. The flag also auto-injects `presets=newton` into Hydra's
  argv so that PresetCfg wrappers resolve to the newton preset (Hydra's
  preset resolution runs *before* the adapter).

Validated: cartpole and Anymal-D Flat both pass a 3-way comparison —
- 'Isaac-Cartpole-v0' (stable manager): trains.
- 'Isaac-Cartpole-Warp-v0' (existing direct path): reward 0.06 / ep 76.
- 'Isaac-Cartpole-v0 --manager=warp': reward 0.06 / ep 76 (matches
  direct exactly).
- 'Isaac-Velocity-Flat-Anymal-D-v0 presets=newton': -8.45 / 191.
- 'Isaac-Velocity-Flat-Anymal-D-Warp-v0': -7.47 / 168.
- 'Isaac-Velocity-Flat-Anymal-D-v0 --manager=warp': -7.69 / 174 (within
  run-to-run variance of the direct warp path).

Both stable and warp frontends remain functional for every task; this
PR adds a flag-based selector without removing the existing direct
warp registrations.
Adds the isaaclab_experimental changelog fragment for the WarpFrontend
adapter and the --manager flag, and applies the ruff-format pass that
the pre-commit hook produced on warp_frontend.py.
The adapter is now a sequence of CompatRule objects (resolve preset, drop
sensors, promote SceneEntityCfg, swap mdp funcs, swap action class). New
incompatibilities are added by writing a small rule subclass instead of
editing the dispatcher.

The CLI flag is renamed --manager → --frontend because the dispatch also
covers direct envs: a stable manager-based cfg is adapted onto
ManagerBasedRLEnvWarp; a direct task is verified to point at a warp env
class and dispatched via gym.make. A stable direct cfg + --frontend=warp
raises IncompatibleEnvError with the offending entry_point and a hint at
the *-Direct-Warp-v0 alternative.

Other fixes:

- Forward render_mode through build() so --video keeps working.
- Attach the CompatReport on env.unwrapped.warp_compat_report so callers
  can inspect what was dropped or left unresolved.
- Assert the warp SceneEntityCfg subclasses the stable one before doing
  the in-place __class__ promotion; the rule fails loudly if the
  hierarchy is ever broken.
- Narrow the bare except in mdp-module discovery so real ImportErrors
  from broken cfgs propagate.
- presets=newton is now only auto-injected for stable manager-based
  tasks; direct warp tasks (which don't carry presets) are left alone.
- Warn when the user passes presets=<other> with --frontend=warp.
- Add the commands group to the rule that promotes SceneEntityCfg.
The earlier check inspected gym.spec(task).entry_point, which for stable
manager-based tasks is "isaaclab.envs:ManagerBasedRLEnv" — the env class
path, not the cfg path. So the startswith("isaaclab_tasks.manager_based")
test always failed and presets=newton was never injected. Hydra then
resolved every PresetCfg in the cfg tree (physics, contact_forces, etc.)
to its default field, leaving the warp runtime with PhysX class_types it
can't load.

Switch to spec.kwargs["env_cfg_entry_point"], which actually points at the
task cfg module (e.g. "isaaclab_tasks.manager_based.locomotion.velocity.
config.anymal_d.flat_env_cfg:AnymalDFlatEnvCfg"), and the prefix check
selects the right tasks.
The single-file warp_frontend.py grew into a real subsystem worth
splitting out, so move it into a frontend/ package with explicit
abstractions:

- frontend/base.py: Frontend ABC, CompatRule (check + transform via a
  unified run() method), TaskResolver (centralised gym.spec
  introspection -> TaskMeta), Workflow / Runtime / Severity enums,
  Issue / Change / Report record types, register_frontend / get_frontend
  registry. Helpers walk_attrs / resolve_warp_twin / iter_term_attrs are
  shared utilities used by rules.
- frontend/torch.py: TorchFrontend, the default. Pass-through to gym.make
  with one rule (WarnIfTaskIsWarpRegistered) for the contradiction case.
- frontend/warp.py: WarpFrontend with the full rule pipeline. Includes a
  new CheckPhysicsIsNewton blocking rule that surfaces the PhysX-with-warp
  incompatibility (asset class_type strings resolve to isaaclab_physx.*
  classes that depend on omni.physics.tensors.api, which the warp runtime
  does not initialise).

CLI: rename --frontend stable -> torch since the axis is *runtime*, not
*stability tier*. The frontend selector now reads cleanly:

  --frontend torch  ->  default gym.make path
  --frontend warp   ->  experimental warp runtime via WarpFrontend

train.py becomes a thin dispatcher: get_frontend(name) gives a Frontend
instance, frontend.preprocess_hydra_args(...) handles preset injection,
frontend.build(cfg, task) returns the env. No more inline conditional
imports; no more inline preset-injection logic.

env.unwrapped.frontend_report is the inspection point - callers and tests
can read what changed and what was missing without re-running adapt().

To add a new compatibility check, write a CompatRule subclass and append
it to the relevant frontend's `rules` tuple. To add a new runtime,
subclass Frontend and call register_frontend(name, cls).
- SwapMdpFunctions: skip terms whose ``func.__module__`` is already under
  the warp prefixes. Without this, running the bridge against a task
  already registered under ``isaaclab_tasks_experimental`` (e.g.
  ``Isaac-Cartpole-Warp-v0 --frontend=warp``) would silently drop terms
  whose warp twin happens not to live in the resolved fallback module.
  Also tighten ``_mdp_modules`` to require the trailing dot when matching
  ``isaaclab_tasks`` so we don't double-replace the prefix and end up
  importing ``isaaclab_tasks_experimental_experimental.*``.

- ResolvePhysicsPreset: scope to MANAGER_BASED via ``applies_to``. Direct
  cfgs aren't expected to carry ``PresetCfg`` wrappers; running this rule
  on them was a no-op but the scoping makes the contract explicit.

- CheckPhysicsIsNewton: positively accept ``isaaclab_newton.*`` modules,
  block on ``isaaclab_physx.*``, warn on anything else. The previous
  rule only rejected PhysX, so a custom or third-party physics cfg in an
  unrelated module would slip through silently.

- PromoteSceneEntityCfg: catch ``TypeError`` from the in-place
  ``__class__`` reassignment and surface it as a blocking issue.
  ``issubclass`` does not guarantee Python permits the layout change
  (slots, layout flags); failing loud at this seam is better than a
  cryptic crash mid-pipeline.

- WarpFrontend.preprocess_hydra_args: normalise leading dashes when
  inspecting ``presets=``, so ``--presets=foo`` is treated the same as
  ``presets=foo`` (Hydra accepts both forms).

- Frontend.resolve: hard-block when ``gym.spec`` returned no spec.
  Previously ``meta.runtime`` was ``UNKNOWN`` and ``construct`` would
  fail later with a less specific error; now the block fires before any
  rule runs.

- train.py: import the frontend lazily and tolerate ``ImportError``
  when ``--frontend=torch`` (the default). The experimental package is
  optional, so a missing install used to break the default path; now it
  falls back to ``gym.make`` for torch and only fails for ``warp``.

- frontend/__init__.py: trim ``__all__`` and the wildcard re-export so
  helpers (``walk_attrs``, ``iter_term_attrs``, ``resolve_warp_twin``,
  ``WARP_ROOT_PREFIXES``) are no longer advertised as the public framework
  surface. They remain importable from ``frontend.base`` for users
  writing their own rules.
- TaskResolver._classify_runtime: also accept class/callable entry points
  by inspecting __module__. gym.register accepts both ``"module:Class"``
  strings and class objects; the old check only handled strings, so a
  warp-registered task using the class form classified as
  Runtime.UNKNOWN and the warn / verify rules silently disengaged.

- SwapMdpFunctions._mdp_modules: narrow the exception match from
  ImportError to ModuleNotFoundError where ``exc.name`` matches the
  module being looked up. Previously a real ImportError raised inside
  an existing mdp module (broken import inside the package) would be
  silently swallowed and the rule would fall through to the fallback
  module, producing misleading "no warp twin" reports.
…ger-bridge

# Conflicts:
#	scripts/reinforcement_learning/rsl_rl/train.py
#	source/isaaclab_experimental/isaaclab_experimental/managers/manager_term_cfg.py
Collapses the CompatRule / Frontend / Report / Issue / Change framework
(509+72+513+95 LOC across base/torch/warp/__init__) into one module
(frontend.py, ~370 LOC). Net diff: 1270 → 864 LOC.

Behavior changes:
- Drop the pre-Hydra presets=newton injection. The warp frontend now
  hard-checks cfg.sim.physics is NewtonCfg at build time and tells the
  user to pass presets=newton on the CLI when it isn't.
- Drop DropUnsupportedSensors. The Newton RayCaster (isaac-sim#5510) makes the
  height_scanner case obsolete; any future incompatible sensor should
  fail loudly with the sensor name rather than silently set None.
- Merge SwapMdpFunctions + SwapActionClassType into one pass that
  swaps term.func or term.class_type uniformly for every group
  including actions.
- Missing warp twin is always a hard failure (no strict / non-strict
  toggle). Partial swaps would leave torch funcs in a cfg consumed by
  warp managers, which only accept the kernel-style signature.
- Replace SceneEntityCfg.__class__ = WarpSceneEntityCfg with a proper
  WarpSceneEntityCfg.from_stable() classmethod that copies every
  selection field through __init__.

Train.py is unchanged in shape — two call sites, now using the
top-level build(frontend, cfg, task_id) function.
Frontend (envs/frontend.py)
- Replace _TERM_PATHS hardcode (with its policy-only observation
  limitation) with _walk_terms: a recursive ManagerTermBaseCfg
  discovery that descends any configclass and yields each term
  with its path. New cfg layouts and observation sub-groups
  (perception, critic, camera_images, ...) are picked up
  automatically with no framework change.
- _promote_scene_entity_cfgs and _swap_mdp consume the new walker;
  delete _walk_attrs / _iter_term_attrs / _TERM_PATHS.
- Per-promotion log now lists the actual SceneEntityCfg paths.
- Rename _require_direct_is_warp_task to
  _assert_direct_warp_registration. Update _detect_workflow with a
  note for adding new cfg roots.

Manager term cfg contract
- Relax stable ObservationTermCfg / RewardTermCfg / TerminationTermCfg
  func annotation to Callable[..., torch.Tensor | None] so the warp
  func(env, out) -> None contract type-checks alongside the existing
  torch return-value contract.
- Drop the now-redundant warp-side manager_term_cfg.py shim and
  redirect the 9 relative imports onto isaaclab.managers.manager_term_cfg.

Tests
- New TestWalkTerms cases verify the recursive type-driven discovery.
- TestPromoteSceneEntityCfgs / TestSwapMdp use real term cfgs and
  configclass fixtures so they exercise the actual walker contract.
The isaaclab_experimental fragment shrinks from 47 lines of nested
narrative to 12 lines per the existing terse-fragment rule. Adds the
matching fragments for the two other touched packages: isaaclab (the
term-cfg type-hint relax) and isaaclab_tasks_experimental (.skip — the
humanoid import redirect is internal).
Two missed-sync fixes carried alongside the manager_based viewport
sync that already landed earlier in this branch:

1. DirectRLEnvWarp viewport controller now mirrors stable
   DirectRLEnv: '(has_gui or has_active_visualizers()) and has_kit()'
   gate, instantiate ViewportCameraController accordingly. Replaces the
   stale get_setting('/isaaclab/has_gui'/'render/offscreen') check and
   removes the commented-out instantiation that left
   viewport_camera_controller unconditionally None.

2. render(mode='rgb_array') in ManagerBasedRLEnvWarp and
   DirectRLEnvWarp now read SimulationContext.has_gui and
   has_offscreen_render properties instead of get_setting on keys that
   were removed when the simulation manager was refactored. Without
   this the gate silently fell through on None values.
The legacy bare 'newton'/'kamino' preset names were renamed on develop to
'newton_mjwarp'/'newton_kamino' to disambiguate from the Newton backend
label. Update the warp-frontend hard-check error message, the
`_adapt_cfg_for_warp`/`_require_newton_physics` docstrings, the
rsl_rl/train.py comment, and the matching test assertion to spell the
canonical preset name so users get the right CLI token in errors.
…ger-bridge

# Conflicts:
#	source/isaaclab_experimental/isaaclab_experimental/managers/__init__.py
#	source/isaaclab_tasks_experimental/isaaclab_tasks_experimental/manager_based/classic/humanoid/mdp/rewards.py
Move the stable->warp cfg adaptation out of the train.py --frontend path
and into ManagerBasedEnvWarp.__init__, so a task registered directly as
*-Warp-v0 (with env_cfg_entry_point pointing at the stable cfg) goes
through the exact same Newton-physics check, SceneEntityCfg promotion and
MDP twin swap. Twin lookup is now keyed off the stable cfg class module
(type(cfg).__module__) instead of the gym task id, so it no longer needs a
registration to resolve. Adaptation is idempotent.

This lets the warp side reuse stable env cfgs instead of carrying parallel
copies that drift.
Flatten isaaclab_tasks_experimental from the legacy manager_based/ |
direct/ | classic/ trees into core/<task>/ mirroring isaaclab_tasks/core,
so the frontend's stable->warp module-path rewrite resolves twins again
after the stable migration.

Manager-based warp tasks now reuse the stable env cfg (env_cfg_entry_point
points at isaaclab_tasks.core...; physics + MDP twins are swapped at
construction) instead of carrying parallel copies that drift; the drift
cfgs are deleted. Direct warp tasks keep their own env class + cfg.

Twin lookup keys off each stable symbol's own module, so ant reusing
manager_humanoid's mdp resolves with no per-task shim (mirrors core,
which gives manager_ant no mdp/ of its own).
Only observation/reward/termination/action terms are swapped to warp twins
and have their SceneEntityCfg promoted; event, curriculum, recorder and
command terms run on the stable (torch) managers, so their stable funcs are
left in place. This lets the warp env reuse the full stable cfg (domain
randomization events, reward curricula, etc.) instead of a trimmed copy.

Add a parametrized coverage test that, for every manager-based *-Warp-v0
task, loads its stable cfg and asserts adapt_cfg_for_warp succeeds (all
warp-managed twins resolve). Three tasks are xfail(strict) pending warp
twins: cartpole survival_success_rate, ant/humanoid body_incoming_wrench.

Also add the missing core/__init__.py so the registration walk descends
into the migrated package.
Stable cartpole was consolidated to unversioned ids (Isaac-Cartpole,
Isaac-Cartpole-Direct); mirror that on the warp side so each warp task
pairs 1:1 with its stable counterpart. Other tasks keep -Warp-v0 because
their stable ids still carry -v0 on develop.
Implements the two missing warp MDP twins so the full stable cfg adapts for
every manager-based *-Warp task (clears the xfails in the conversion test):

- cartpole `survival_success_rate`: ManagerTermBase reward mirroring stable —
  zero reward contribution, logs Metrics/success_rate (time-out rate) on reset.
- generic `body_incoming_wrench`: observation reading the Newton joint-wrench
  sensor and gathering per-body force+torque, following the existing
  sensor-reading twins (undesired_contacts/illegal_contact). Lives in the
  shared fallback mdp so it is task-agnostic.

Extends the observation manager's `body:N` out_dim resolution to also read
`sensor_cfg` (not just `asset_cfg`), since wrench obs select bodies via a
sensor entity.
The cfg walker only matched ManagerTermBaseCfg, but ActionTermCfg is a
separate base (not a subclass) carrying a swappable class_type. As a result
action terms kept their stable class and the warp ActionManager rejected
them ("not of type ActionType") when a *-Warp task reused a stable cfg.
Match ActionTermCfg in _walk_terms so action class_type is swapped too, and
guard it in the conversion test.

Also fix the cartpole warp registration agent entry points to the current
stable modules (rsl_rl_ppo_cfg:Cartpole[Direct]PPORunnerCfg, sb3_ppo_cfg)
after the cartpole consolidation renamed them.
The warp EventManager invokes term funcs with a Warp env-mask, so a stable
event func breaks at runtime (torch index by wp.array). Add events to the
warp-managed groups so their funcs are swapped to warp twins; only curriculum,
recorder and command managers fall back to stable. Cartpole (reset_joints_by_offset)
and reach now adapt and cartpole trains end-to-end on warp.

Rewrite cartpole survival_success_rate as a plain zero-reward term func: its
stable form logs a metric on reset via a host readback, which is incompatible
with the reward manager's CUDA-graph-captured reset; the warp twin keeps the
zero reward and omits the diagnostic metric.

Velocity tasks remain xfail in the conversion test pending warp twins for
randomize_rigid_body_mass / randomize_rigid_body_material (domain randomization).
Reconcile two conflicts from develop (45 commits):

- scripts/reinforcement_learning/rsl_rl/train.py: keep the --frontend=warp
  lazy-import build path; drop the branch-local fold_preset_tokens() call in
  favor of develop's verbatim remaining_args. isaac-sim#5944 reworked setup_preset_cli
  to resolve physics=/presets= tokens during Hydra resolution, so folding is
  no longer needed and the function was removed upstream.
- isaaclab_tasks_experimental .../direct/cartpole/__init__.py: keep the branch
  deletion (cartpole moved under core/); develop made no substantive change to
  the old-location file.
Develop's task-cleanup PRs dropped the -v0 suffix from the core Ant,
Humanoid, and Reach-Franka torch ids. The warp variants follow a fixed
pattern (torch id with -Warp inserted before any -Play/-v0 suffix), so
sync the six affected registrations and their doc references:

  Isaac-Ant-Warp-v0              -> Isaac-Ant-Warp
  Isaac-Ant-Direct-Warp-v0       -> Isaac-Ant-Direct-Warp
  Isaac-Humanoid-Warp-v0         -> Isaac-Humanoid-Warp
  Isaac-Humanoid-Direct-Warp-v0  -> Isaac-Humanoid-Direct-Warp
  Isaac-Reach-Franka-Warp-v0     -> Isaac-Reach-Franka-Warp
  Isaac-Reach-Franka-Warp-Play-v0 -> Isaac-Reach-Franka-Warp-Play

Cartpole already conformed; contrib and core-velocity tasks kept -v0
upstream, so their warp ids are unchanged.
Retain the current direct and manager-based experimental task layout and move the frontend integration to the unified RSL-RL entrypoint. Align the direct Warp Cartpole with the rewritten stable task.
…nager-bridge

# Conflicts:
#	source/isaaclab/test/test_reinforcement_learning_common.py
Define the flag once in add_common_train_args so every RL library's
train and benchmark entrypoint exposes it, instead of registering it
per-script for RSL-RL only. create_isaaclab_env now reads the argument
directly, so a caller that misses the shared registration fails loudly
rather than silently defaulting to the torch runtime.

Also drop the frontend dispatch from the deprecated rsl_rl/train.py
wrapper; deprecated entrypoints should not grow new features.
The Warp survival_success_rate twin wrote zeros and dropped the
Metrics/success_rate value that the stable class-based term flushes
into extras on reset, so torch and warp runs of the same task were not
comparable on the success metric.

Rebuild the twin as a Warp ManagerTermBase class that accumulates the
timed-out fraction of just-reset envs in device buffers and exposes it
as a persistent tensor view through the reward manager's reset extras.
Class reward terms may now return such views from reset(); the reward
manager merges them, which keeps the whole reset stage CUDA-graph
capturable (no host readback).
hujc7 added 12 commits July 15, 2026 17:52
Replace the frontend's hardcoded stable-to-experimental module table
with a registry that experimental task packages populate at import time
via register_mdp_route(), so adding a task family no longer requires
editing the frontend module.

Twin lookup previously keyed only off the symbol's defining module,
which missed every twin that overrides a symbol defined in a core or
shared package: the stable reach rewards live in isaaclab.envs.mdp and
the humanoid observations in the shared locomotion package, so their
task-specific warp twins were never consulted and the stable Humanoid,
Ant, and Reach tasks could not adapt at all. Resolution now consults
the warp mirror of the cfg's own task MDP namespace first (routed from
the cfg class hierarchy), then the mirror of the symbol's package, then
the shared fallback — mirroring how a stable cfg consumes its mdp
namespace. This makes the stable Ant, Humanoid, and Reach joint-pos
tasks adapt cleanly under --frontend=warp.

Also convert test_frontend.py to pytest style and cover the new
registry (longest-prefix match, conflict rejection, broken-target
error, cfg-hierarchy resolution).
Every manager-based *-Warp-v0 task duplicated its stable environment
configuration file-for-file, so each stable task rewrite had to be
mirrored by hand (as happened with the Cartpole rewrite).

ManagerBasedRLEnvWarp now adapts its cfg in __init__, so warp env
construction accepts stable-derived cfgs directly. On top of that:

- Drop the Cartpole, Humanoid, Ant, and Reach-Franka warp registrations
  and their duplicated cfgs; the stable ids run on warp via
  --frontend warp presets=newton_mjwarp. Their packages keep only the
  warp MDP twins and the route registration.
- Rewrite the velocity *-Warp-v0 variants as thin subclasses of the
  stable flat cfgs that only disable the rigid-body material/mass
  randomization events, which have no warp twins yet. The duplicated
  velocity base cfg, per-robot cfgs, and unregistered rough cfgs are
  removed; the variants now select Newton via presets=newton_mjwarp
  like every other task.
- Cover both paths in test_frontend_cfg_conversion.py: the stable ids
  with full twin coverage adapt cleanly, and every registered warp
  variant still adapts.
- Update the warp environments documentation and the generated
  environment list accordingly.
Direct warp tasks duplicated their stable task configuration in a
parallel *-Direct-Warp-v0 registration, so every stable cfg change had
to be mirrored by hand.

A stable direct registration can now declare its warp implementation
with a warp_entry_point kwarg (mirroring env_cfg_entry_point);
--frontend warp constructs that class with the stable cfg and swaps
nothing else. Declared for Isaac-Cartpole-Direct, Isaac-Ant-Direct, and
Isaac-Humanoid-Direct, whose warp cfgs matched the stable ones
field-for-field; their *-Direct-Warp-v0 registrations and duplicated
cfgs are removed and the env classes annotate the stable cfg types.

The Allegro reorient warp task keeps its own registration: its cube is
modeled as an articulation, unlike the stable task's rigid object, so
the configurations genuinely differ.
Extract the --frontend flag into add_frontend_args so other entrypoints
(e.g. play) can reuse it without pulling in all training arguments;
add_common_train_args keeps calling it so every train and benchmark CLI
registers the flag.

Also derive SceneEntityCfg.from_stable from the stable dataclass fields
instead of a hand-maintained list, drop single-use aliases in the wrench
observation twin, and trim render comments to one line.
The experimental task package still used the manager_based/direct split
that the stable package left behind when it consolidated each task under
core/<task>. That mismatch was the only reason the warp MDP routing
needed non-obvious mappings.

Move the warp task packages to the same layout — core/cartpole,
core/locomotion/{ant,humanoid}, core/velocity, core/reach, and
core/reorient for the Allegro task — with each task package holding both
its manager-based MDP twins and its direct warp env class, exactly like
its stable counterpart. Routes and warp_entry_point declarations now
read as the mechanical mirror they are.
Group the warp-side machinery — route registry, cfg adaptation steps,
twin resolution, and both env build paths — under a WarpFrontend class
instead of a flat set of module functions. The module-level build(),
adapt_cfg_for_warp(), and register_mdp_route() API is unchanged for
callers; the class gives the machinery one named owner, keeps the route
registry as explicit class state, and leaves room for future frontends
to subclass or replace it.
The shared RL CLI already peels off the torch path before importing the
optional isaaclab_experimental package, so the frontend's own torch
branch (module-level build() with a Frontend enum) was dead code that
duplicated the gym.make dispatch. Remove it: create_isaaclab_env owns
the torch/warp dispatch and calls WarpFrontend.build_env directly, and
the module's public surface shrinks to WarpFrontend, Workflow,
register_mdp_route, and the error type. Callers use
WarpFrontend.adapt_cfg in place of the adapt_cfg_for_warp alias.
The experimental tree now mirrors the stable tree exactly, so twin
routing needs no declarations: mirror the module root
(isaaclab -> isaaclab_experimental, isaaclab_tasks ->
isaaclab_tasks_experimental) and look the symbol up on the nearest
.mdp package of the mirrored path — the cfg's own task namespace first,
then the symbol's defining package. Resolution is a pure function of
the installed package tree; misses accumulate across the whole cfg and
are reported in a single hard failure listing every missing twin and
all searched modules.

This deletes register_mdp_route, the route registry, the twin-provider
side-effect import, and all five task-package registration calls. The
humanoid MDP twins move to core/locomotion/mdp — the true mirror of the
stable shared locomotion package — which also removes the Ant special
case (both tasks now resolve mechanically).
Add warp adapters for the two stable startup randomization events
(randomize_rigid_body_material, randomize_rigid_body_mass): the stable
terms already dispatch to the active physics backend, so the adapters
only convert the warp event manager's env-mask calling convention to
the stable env-ids one and inherit the warp ManagerTermBase so the
managers accept them as class terms.

With those twins in place the stable flat velocity tasks adapt cleanly,
so the 18 velocity *-Warp-v0 registrations and their delta configs are
deleted — no manager-based warp registration remains, and the
conversion test pins that end state. The Allegro reorient task id drops
its stale -v0 suffix (Isaac-Reorient-Cube-Allegro-Direct-Warp).
Add one-line comments at the dense decision points of WarpFrontend
(twin lookup order, mirror walk, collect-all-misses reporting).

Replace the removed -Warp-v0 ids in the benchmarking guide with a
same-task A/B that differs only in --frontend, with identical Newton
physics on both runs.

Add the missing changelog entry for the RewardManager merging
class-term reset() extras into its episode logs.
The stable cfg already resolves its cube to an articulation under the
newton_mjwarp preset, so the duplicated warp cfg diverged only by
pinning ls_iterations=15; the stable preset values now apply.

Isaac-Reorient-Cube-Allegro-Direct declares the warp env class via
warp_entry_point; the separate -Warp registration and its cfg package
are deleted. A new end-state pin asserts no -Warp task ids remain, and
the frontend stub-task fixture now unregisters its ids so later test
modules see the real registry.
Move the body-frame state helpers from isaaclab_newton.kernels to a new
backend-neutral isaaclab.utils.warp.state_math module (they are pure
frame math; a deprecation shim remains), widen the frontend physics gate
to accept OvPhysxCfg alongside NewtonCfg, and add a backend data-parity
test pinning that every data.<field>.warp view the warp MDP twins read
exists on each warp-capable backend. With this, the twins carry no
Newton dependency and warp-frontend tasks accept presets=ovphysx.
@github-actions github-actions Bot added documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team labels Jul 17, 2026
@hujc7 hujc7 changed the title [WARP] Open the warp frontend to the OVPhysX backend [WARP] Cleanup Part 4: Open the warp frontend to the OVPhysX backend Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant