Skip to content

Simplify and strengthen asset tests across physics backends - #7282

Merged
StafaH merged 38 commits into
isaac-sim:developfrom
AntoineRichard:antoiner/asset-tests-redesign
Oct 3, 2026
Merged

StafaH merged 38 commits into
isaac-sim:developfrom
AntoineRichard:antoiner/asset-tests-redesign

Conversation

@AntoineRichard

@AntoineRichard AntoineRichard commented Aug 21, 2026 •

Copy link
Copy Markdown
Collaborator

Description

The asset tests repeated expensive scenes, replayed the same contracts on every backend, and carried custom scaffolding that made them hard to follow. This PR consolidates them across PhysX, Newton, and OVPhysX into lean, directly readable tests: cheap mocked contracts own the shared API, and real-solver tests only cover what needs the real solver.

This is the combined PR for review and merge. The split PRs are not being updated.

Test organization

  • One file per asset family and backend. Every test file pays a fixed 4–7 s of imports (and a Kit launch for PhysX and in the CI core job), so tests live in the file that already pays those costs: unit-level checks sit beside the real-solver tests of the same asset, rigid objects and rigid-object collections share one file and one scene, and the shared contracts are two files. The asset tests went from 39 files to 19.
  • Shared contracts (source/isaaclab/test/assets/contract/): test_articulation_contract.py (including joint/body ordering) and test_rigid_object_contract.py (rigid objects and collections, one factory) run every backend on mocked views. backends.py owns the Kit/kitless bootstrap, backend availability, and the manager doubles; unavailable backends collect as skips. Newton runs on CPU only, since its asset code has no CUDA-specific path; PhysX and OVPhysX keep CUDA rows for their pinned-staging paths.
  • Writers are one table-driven test per family covering warp and torch inputs, index and mask selection, partial writes through the public getters (unselected entries must be untouched), scalar writes, and oversized-input rejection.
  • Ordering is a small set of table-driven contracts (property routing, body-state reads, duplicate selectors, stale staging, reset rereads) using cyclic orderings, since a reversal is its own inverse and cannot catch a swapped index map.
  • Backend tests reuse module-scoped composite scenes, with two environments so partial writes prove untouched state, and build each scene on one device unless a Lab code path differs by device (OVPhysX CPU stage serialization, CUDA-graph capture, CPU-only regressions). Tests that own a simulation run before the composite scene; PhysX asserts this so a misplaced test fails loudly.
  • Actuator equivalence on PhysX and Newton runs on the local two-leg and cartpole USD fixtures (in isaaclab_newton/test/assets/data) instead of ANYmal.
  • WrenchComposer keeps literal unit cases and one real PhysX delivery test. Newton OSC controllers run closed-loop tracking and gravity compensation on an island of the Newton articulation scene.

What was removed or merged

  • Custom framework: capabilities.py, contract_boot.py, mock_backends.py, public_surface.py, and tests that only exercised test scaffolding or a copied member inventory.
  • Duplicate index/mask, root/body/joint/tendon, and rigid/collection writer tests; per-helper _make_* variants; tests that rebuilt the same mocked asset to check overlapping properties.
  • PhysX: Franka and Shadow Hand scenes (local branching fixture covers the Jacobian, gravity compensation, and fixed tendons), the 800-step IK test, ~15 ANYmal actuator simulations reduced to 3, and gravity tests folded into the shared scenes.
  • OVPhysX: unit files merged into the asset files that already pay the same imports; collection tests share the rigid-object scene; heterogeneous clone tests share scenes; collision-filter and rejection variants no longer doubled across devices; reset checks folded into the wrench tests.
  • Newton: rigid-object scenes run on CPU only (CUDA stays covered by the actuator, CUDA-graph, and capture tests); authoring tests merged into one table; shorter controller tracking loops; eight files merged into three.
  • A source-inspection WrenchComposer test, and redundant dtype/selector matrices.
  • device_split runner support (tools/_device_split.py, its test, the pytest marker, and workflow mentions). No test declares it after the OVPhysX device fix below.
  • DC_MOTOR_ACTUATORS and ActuatorStateResetBase from isaaclab.test.utils.actuator_equivalence, which no longer have callers.

Every merged or removed contract has a keeper. Non-obvious merges were checked with a one-line production mutation that turns the keeper red (for example, writer kernels ignoring the mask, COM caches not invalidated, Jacobian link shift skipped, collection COM/inertia fixes reverted).

Coverage deliberately given up: the Lab-path DelayedPD reset check now runs on Newton only (PhysX asserts reset forwards environment IDs); armature-to-mass-matrix invalidation is no longer tested because PhysX does not reflect armature writes in the mass matrix within one step; PhysX composite-scene checks run on CUDA only (CPU staging stays covered by the mocked contracts); OVPhysX collision isolation, mimic fingers, and non-geometry heterogeneous articulation variants run on CUDA only.

Runtime changes included in this PR

  • Fix PhysX rigid-object-collection COM and inertia setters (stacked from Fix PhysX rigid-object collection COM and inertia setters #8131).
  • Allow OVPhysX CPU and CUDA simulations in one process: configure each USD physics scene for the selected device instead of pinning the process to its first device or using the sticky CPU mode. Lifecycle coverage includes CPU → CUDA → CPU.

Validation

Each file ran in its own process on an NVIDIA RTX PRO 6000 Blackwell (warm Warp cache), comparing the head of this PR before the cleanup (ad9b10a37) with the current one:

Scope Files Time before → after
Shared contracts 5 → 2 40 s → 17 s
Core WrenchComposer, actuators, terminations 5 → 4 19 s → 15 s
Newton assets, actuators, controllers 8 → 3 84 s → 42 s
PhysX assets 9 → 5 85 s → 40 s
OVPhysX assets and physics manager 12 → 5 100 s → 52 s
Asset tests total 39 → 19 328 s → 166 s

Current results: 1,042 passed, 31 skipped, 10 strict xfails, 99 deselected (Newton CUDA contract rows). The OVPhysX sensor, view, and randomization files are unchanged apart from dropping their device-split fixtures (~134 s, not counted above). Fewer files also means fewer Kit launches in CI, where each one costs more than locally.

Formatting, lint, LFS, and whitespace hooks pass. The changelog check passes against upstream develop.

Known failures pinned as strict xfails

  • OVPhysX partial body writes overwrite unselected bodies of the selected environment (rigid-object collection).
  • Newton fixed-tendon mask setters accept data with extra environments.
  • PhysX and OVPhysX rigid objects do not reject an enabled articulation root.
  • After a failed PhysX initialization, the first CPU simulation reads zero poses for kinematic collection bodies. The previous file order masked this.
  • GPU PhysX applies mass and inertia writes to the mass matrix and gravity compensation on the next step.

Other limitations exposed by the redesign and left out of scope: full PhysX collection reset leaves wrench composers active; GPU link-frame wrench delivery can use stale transforms after teleports; Newton native-actuator reset is model-wide.

Type of change

  • Test-suite redesign and cleanup
  • Bug fixes for PhysX collection setters and OVPhysX device lifecycle
  • CI tooling cleanup (device_split removal)

Checklist

  • Read the contribution guidelines
  • Run the formatting and lint checks
  • Apply the test-audit criteria and verify keepers with mutations
  • Validate the changed tests on CPU and CUDA where configured
  • Add changelog fragments for every touched package
  • Make corresponding documentation changes for the runtime behavior
  • Existing contributor listed in CONTRIBUTORS.md

@AntoineRichard
AntoineRichard requested a review from a team August 21, 2026 16:46
@github-actions github-actions Bot added documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team labels Aug 21, 2026
@greptile-apps

greptile-apps Bot commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[Medium risk] Reorganizes and expands asset contract tests across physics backends.

No confirmed new issue from the readability cleanup blocks merging.

Summary

The PR consolidates cross-backend asset contracts, simplifies backend tests, adds local Newton USD fixtures, and includes PhysX collection-setter and OVPhysX device-lifecycle fixes. The latest readability cleanup yielded no confirmed new finding.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  T[Directly collected asset contracts] --> F[Backend and device fixtures]
  F --> M[Mock asset factories]
  M --> P[PhysX]
  M --> N[Newton]
  M --> O[OVPhysX]
Loading

Reviews (2) · Last reviewed commit: "Simplify asset tests and remove custom t..."

@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

The asset-test redesign establishes shared contracts, backend-focused units, and small real-solver seams, with accompanying PhysX and OVPhysX fixes. Before merge, remove the committed benchmark/work-report artifact and eliminate the redundant, unenforced public-member snapshots.

  • Design and architecture: The contract/unit/integration ownership split and explicit backend-capability table are coherent. However, the committed redesign-results document is a machine- and revision-specific work artifact prohibited by repository guidance, and public_surface.py contains unused duplicate member inventories that can silently diverge from the enforced mappings.
  • API: The touched production APIs retain their signatures: PhysX collection COM/inertia changes reshape only at the TensorAPI boundary, deformable type inference preserves material-before-topology precedence, and the OVPhysX device lifecycle change affects internal manager behavior. The public-surface audit is useful, but its unused duplicate snapshots should be removed or made authoritative.
  • Implementation: The contract bootstrap, backend capability declarations, manager patch scoping, writer readbacks, fused-layout checks, and backend regression seams were traced. Required cleanup is limited to removing the generated benchmark report from the repository and consolidating the duplicated public-member inventory.

Minor fixes needed. Posted 2 actionable findings inline.

Automated review; human maintainers own approval decisions.

- Times in the comparison are the repository orchestrator's aggregate pytest
and subprocess wall times, not the outer shell duration.

## Copy-ready PR performance section

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 · Design Architecture — Committed generated benchmark results artifact

This file is a generated work report: it contains a "Copy-ready PR performance section", a rebase-specific base SHA, a machine-specific environment (GPU, driver, wheel versions), sandbox paths such as /tmp/isaaclab-task8-warp, and a per-module disposition map. Repository guidelines prohibit committing generated plans, scratch files, or agent artifacts. It will go stale immediately after merge and carries no reader-facing documentation value. Keep these measurements in the pull-request description instead.



_PUBLIC_MEMBER_SNAPSHOT = {
"AssetBase": """

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.

🔵 Suggestion · Design Architecture — Unused member snapshots duplicate enforced mapping

Only the BaseRigidObjectData, BaseRigidObjectCollectionData, and BaseArticulationData entries of _PUBLIC_MEMBER_SNAPSHOT feed PUBLIC_SURFACE_CONTRACTS; the AssetBase, BaseRigidObject, BaseRigidObjectCollection, and BaseArticulation entries are never referenced and respell the same member names that the _mapping(...) calls list inline. A future API change updates only the audited copy, leaving a silently diverging second inventory. Drop the unreferenced entries or build the mappings from them.

@AntoineRichard
AntoineRichard force-pushed the antoiner/asset-tests-redesign branch 2 times, most recently from e828d86 to f2ab714 Compare August 26, 2026 11:37
RigidObjectCollection.set_coms_index passed wp.transformf data to the
PhysX tensor API, which raises a KeyError. It also marked the lazily
filled body_com_pose_b cache as fresh after a partial write, so the
unselected entries read back as zeros when the cache had not been read
before. set_inertias_index flattened the (num_instances, num_bodies, 9)
inertias with the 2D reshape, which the backend rejects.

Pass the COM poses as float32, let the next read refresh the COM cache
from the view as RigidObject does, and reshape the inertias with the 3D
helper. A new test writes both properties to a non-sorted subset of
(env, body) cells and checks the PhysX view and the data buffers.
Move the mocked cross-backend asset interface tests into a contract package
with api, data, and write entry modules. An explicit capability table gives
every backend a visible row: unavailable backends and unsupported branches
collect as skips with their reason instead of silently dropping out. A
kitless usdrt/carb stub and an availability guard keep PhysX articulations
in the matrix, where they previously were skipped without notice.

Factory manager patches are scoped to one test and restored afterwards.
PhysX views apply TensorAPI writes so partial writers are checked against
unselected backend rows, Newton joins the fixed-tendon contract, the
deprecated command aliases are checked against the actuator collection, and
one enforced inventory classifies the public base-class surface.
Replace the randomized and device-parametrized composer matrix with literal
two-environment, two-body cases that pin frames, fast paths, live CoM and
rotation reads, selection, set, reset, merge, lazy composition, and the
deprecated API.

Keep one real PhysX test: a world force at a world offset must match raw
PhysX delivery, and a world wrench at the CoM of a rotated body far from the
origin must follow the world axes. The composer-versus-PhysX matrix is
removed; its only non-trivial parity case is the retained offset force, and
its other cases issued the same PhysX call on both sides.
OvPhysxManager pinned the first simulation device for the whole process
because the backend entered the OVPhysX process-wide CPU-only mode, which
OVPhysX 0.6.3 still documents as irreversible. CPU scenes now leave that
mode off and select CPU dynamics per scene through enableGPUDynamics=false
and the MBP broadphase, as the OVPhysX developer guide recommends for mixed
CPU/GPU processes, so the device lock is removed.

A child-process test runs CPU, CUDA, CPU and CUDA, CPU scene sequences and
checks device placement, state I/O, and that each CPU scene reproduces the
same trajectory. A unit test pins the per-device scene attributes.
Replace the per-test Nucleus-robot scenes with one module-scoped scene per
device built from locally authored islands of the branching fixture. Each
island serves one test, is reset once, and uses two environments where a
partial write must prove the other environment keeps its backend state.

The CUDA scene keeps the pinned-host staging, native Newton actuator,
dynamics, tendon, floating-root, and FK-refresh tests. The CPU scene covers
the host-resident property path and the host actuator path, so the file
no longer needs one process per device.

Unit-level articulation data and actuator-control tests move verbatim to
unit modules.
Rigid-object and collection tests share one module-scoped scene of locally
authored cuboids per device instead of rebuilding Nucleus props per test.
They keep the partial-state, raw inertial, fused-layout, material, wrench,
kinematic, and scene-data-provider checks, and the reset checks that make
both wrench composers active first.

A strict xfail pins a collection bug: a partial body pose write pushes whole
environment rows from a pose buffer that is not refreshed first, so the
unselected bodies of that environment are rewound to stale poses.

The CPU deformable rejection test no longer needs a spawned child process.
Take over what the removed OVPhysX real-backend joint-state test checked, on
every backend: unsorted int64 environment and joint selectors on the fused
writer, the finite-difference baseline it restarts for the written joints,
skip_forward leaving body caches to the caller, and the deprecated combined
writer producing the same state as the public writers.
Run the PhysX articulation checks against one module-scoped scene built
from the local branching fixture instead of per-test Nucleus robots. The
scene holds two-environment islands (fixed with MJWarp ordering and USD
gains, floating with configured gains, floating with a root-moving body
order, and fixed with a reversed joint and a spatial tendon), so partial
writes target environment 1 and prove environment 0 is preserved in the
real PhysX state.

Keep the Shadow Hand fixed-tendon, Franka gravity-compensation, and
Franka IK tests on their shipped assets, and check initialization
failures on the local fixture. Move the kernel unit tests under unit/
and cover the effort termination term with a core unit test.
…enes

Share one module-scoped scene of locally authored cubes per file instead
of a Nucleus scene per test. Partial state, inertial, and wrench writes
select environment 1 or non-sorted body-major subsets and read the PhysX
view back; center-of-mass offsets check every root and body frame writer
and the spin kinematics. Failure modes, the gravity vector, physics
warmup, and the collection subset regressions keep their own scenes.

The rigid-object articulation-root rejection is kept as a strict xfail:
the check was removed from the PhysX rigid object, and the previous
Nucleus fixture only failed because it resolved no rigid body.
Drop the ideal-PD, DC-motor, and remotized-PD equivalence runs, whose
actuator translation is backend independent: the mixed implicit/explicit
run still exercises the PD and DC-motor authoring on PhysX, and the
Newton suite owns the remaining models. Move the native-path preparation
checks to a kitless unit file, and replace the graph-capture failure and
outer-capture rollouts with unit tests of the shared PhysX actuator
runtime.
Replace the disabled deformable suite with one scene of locally authored
surface and volume meshes that need no mesher or collision cooking, and
check partial nodal writes, kinematic targets, and the surface target
rejection. Author the surface gripper locally, keep the CI skip for the
real open/close seam, and check the command and property payloads with a
recording view.
Bring the tracking branch to the union of the 24 series branches after aligning them with the coding and testing guidelines in docs/source/refs/contributing.rst.
Bring the tracking branch to the union of the series branches after the independent review round.
@AntoineRichard

Copy link
Copy Markdown
Collaborator Author

Consolidated to 13 PRs

The series is now 13 PRs instead of 24: #8134, #8135, #8138, #8139, #8141, #8144, #8146, #8147, #8149, #8151, #8153, #8154 and #8156, titled "Accelerate and strengthen asset tests [N/13]".

  • What was merged: parts that edited the same file (the articulation halves) and small owner PRs whose coverage they received now share one PR. The 11 absorbed PRs are closed, each pointing to the PR that absorbed it. No code changed in the consolidation.
  • Review round: before consolidating, every PR went through an independent review with mutation checks. The coverage gaps it found are closed, each proven by the reviewer's own mutation.
  • Other fixes from that round:
    • Accelerate and strengthen asset tests [3/13] #8138 now sets the device on every physics scene in the stage.
    • Eight OVPhysX test files no longer skip the second device.
    • The WrenchComposer delivery test runs on CPU again.
    • isaacsim_ci routing matches develop.
  • Timing: measured serially on one machine, the five asset scopes take 374.9 s → 150.5 s (2.5×). The description has the full table, sizes and dependencies.

@StafaH StafaH changed the title Accelerate and strengthen asset tests [tracker] Simplify and strengthen asset tests across physics backends Oct 2, 2026
@StafaH
StafaH marked this pull request as ready for review October 2, 2026 21:13
@StafaH
StafaH requested a review from myurasov-nv as a code owner October 2, 2026 22:45
@StafaH StafaH added the ci:run-docker Trigger the on-demand Docker and GPU CI workflow label Oct 2, 2026
@StafaH

StafaH commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator

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 2, 2026
@StafaH
StafaH merged commit 8f1a1d3 into isaac-sim:develop Oct 3, 2026
60 checks passed
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 infrastructure isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants