Skip to content

Commit 4b587d1

Browse files
authored
Fix NewtonManager scene data provider backend detection when _sim is unset (isaac-sim#5710)
## Summary - `NewtonManager._backend_is_newton` returned `False` when `PhysicsManager._sim` was `None`, even if a `SimulationContext` instance existed — leaving backend detection inconsistent with `update_visualization_state`, which already fell back to `SimulationContext.instance()`. - Introduce a shared `NewtonManager.get_scene_data_provider` classmethod that prefers `PhysicsManager._sim` and falls back to `SimulationContext.instance()`. - Route both `_backend_is_newton` and `update_visualization_state` through the new helper so they agree on the active scene-data provider. ## Test plan - [ ] Run the relevant `isaaclab_newton` physics tests: `./isaaclab.sh -p -m pytest source/isaaclab_newton/test` - [ ] Exercise a PhysX-backed scene where `PhysicsManager._sim` is unset at the moment `get_state` is called and confirm visualization transforms are populated. - [ ] Confirm Newton-backed runs still short-circuit `update_visualization_state` (no shadow model built). - [ ] `./isaaclab.sh -f`
1 parent 93e86f9 commit 4b587d1

4 files changed

Lines changed: 42 additions & 20 deletions

File tree

source/isaaclab/changelog.d/dev-newton-manager-fix.skip

Whitespace-only changes.

source/isaaclab/test/sim/test_newton_manager_visualization_state.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ def _reset_newton_manager_state():
2626
NewtonManager._model = None
2727
NewtonManager._state_0 = None
2828
NewtonManager._num_envs = None
29-
NewtonManager._visualization_scene_data = None
30-
NewtonManager._visualization_mapping = None
29+
NewtonManager._scene_data = None
30+
NewtonManager._scene_data_mapping = None
3131

3232

3333
def test_ensure_visualization_model_noop_when_backend_is_newton(monkeypatch):
@@ -153,6 +153,7 @@ def test_update_visualization_state_noop_when_backend_is_newton(monkeypatch):
153153

154154
_reset_newton_manager_state()
155155
monkeypatch.setattr(NewtonManager, "_backend_is_newton", classmethod(lambda cls, scene_data_provider=None: True))
156+
monkeypatch.setattr(NewtonManager, "get_scene_data_provider", classmethod(lambda cls: SimpleNamespace()))
156157

157158
# Pre-set sentinel values to ensure update doesn't touch them.
158159
NewtonManager._model = "live-model"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Fixed
2+
^^^^^
3+
4+
* Fixed :meth:`~isaaclab_newton.physics.NewtonManager._backend_is_newton`
5+
returning ``False`` when ``PhysicsManager._sim`` was unset but a
6+
:class:`~isaaclab.sim.SimulationContext` instance existed. The scene-data
7+
provider lookup now consistently falls back to
8+
:meth:`~isaaclab.sim.SimulationContext.instance`, via a new
9+
:meth:`~isaaclab_newton.physics.NewtonManager.get_scene_data_provider`
10+
helper shared with :meth:`~isaaclab_newton.physics.NewtonManager.update_visualization_state`.

source/isaaclab_newton/isaaclab_newton/physics/newton_manager.py

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@
3434
from newton.solvers import SolverBase, SolverKamino, SolverNotifyFlags
3535

3636
from isaaclab.physics import CallbackHandle, PhysicsEvent, PhysicsManager
37-
from isaaclab.scene_data import SceneDataBackend, SceneDataFormat
38-
from isaaclab.sim import SimulationContext
37+
from isaaclab.scene_data import SceneDataBackend, SceneDataFormat, SceneDataProvider
3938
from isaaclab.sim.utils.newton_model_utils import replace_newton_shape_colors
4039
from isaaclab.sim.utils.stage import get_current_stage
4140
from isaaclab.utils import checked_apply
@@ -1534,7 +1533,7 @@ def get_state_0(cls) -> State:
15341533
return cls._state_0
15351534

15361535
@classmethod
1537-
def get_state(cls, scene_data_provider=None) -> State:
1536+
def get_state(cls, scene_data_provider: SceneDataProvider | None = None) -> State:
15381537
"""Get the current Newton state for visualization.
15391538
15401539
Use this method from visualizers/renderers/video recorders that need a
@@ -1553,14 +1552,11 @@ def get_num_envs(cls) -> int:
15531552
return cls._num_envs
15541553

15551554
@classmethod
1556-
def _backend_is_newton(cls, scene_data_provider=None) -> bool:
1555+
def _backend_is_newton(cls, scene_data_provider: SceneDataProvider | None = None) -> bool:
15571556
"""Return ``True`` when the active sim backend is Newton."""
15581557
if scene_data_provider is not None:
15591558
return isinstance(scene_data_provider.backend, NewtonSceneDataBackend)
1560-
sim = PhysicsManager._sim
1561-
if sim is None:
1562-
return False
1563-
return isinstance(sim.get_scene_data_provider().backend, NewtonSceneDataBackend)
1559+
return isinstance(cls.get_scene_data_provider().backend, NewtonSceneDataBackend)
15641560

15651561
@classmethod
15661562
def _ensure_visualization_model(cls) -> None:
@@ -1762,7 +1758,23 @@ def _build_visualization_model_from_stage(cls, stage) -> ModelBuilder | None:
17621758
return builder
17631759

17641760
@classmethod
1765-
def update_visualization_state(cls, scene_data_provider=None) -> None:
1761+
def get_scene_data_provider(cls) -> SceneDataProvider:
1762+
"""Return the active scene data provider, or None if unavailable.
1763+
1764+
Prefers ``PhysicsManager._sim`` when set; otherwise falls back to
1765+
``SimulationContext.instance()``.
1766+
"""
1767+
sim = PhysicsManager._sim
1768+
if sim is None:
1769+
from isaaclab.sim import SimulationContext
1770+
1771+
sim = SimulationContext.instance()
1772+
1773+
assert sim is not None
1774+
return sim.get_scene_data_provider()
1775+
1776+
@classmethod
1777+
def update_visualization_state(cls, scene_data_provider: SceneDataProvider | None = None) -> None:
17661778
"""Refresh visualization state for the active sim backend.
17671779
17681780
Newton sim backend: no-op — ``_state_0`` is the live, authoritative state
@@ -1777,27 +1789,26 @@ def update_visualization_state(cls, scene_data_provider=None) -> None:
17771789
Invoked lazily from :meth:`get_state` so consumers do not need to
17781790
coordinate the sync explicitly.
17791791
"""
1792+
1793+
if scene_data_provider is None:
1794+
scene_data_provider = cls.get_scene_data_provider()
1795+
1796+
assert scene_data_provider is not None
1797+
17801798
if cls._backend_is_newton(scene_data_provider):
17811799
return
17821800
cls._ensure_visualization_model()
17831801
if cls._state_0 is None or cls._model is None or cls._state_0.body_q is None:
17841802
return
1785-
sdp = scene_data_provider
1786-
if sdp is None:
1787-
sim = SimulationContext.instance()
1788-
if sim is not None:
1789-
sdp = sim.get_scene_data_provider()
1790-
if sdp is None:
1791-
return
17921803

17931804
if cls._scene_data is None:
17941805
cls._scene_data = SceneDataFormat.Transform()
17951806
if cls._scene_data_mapping is None:
17961807
body_paths = list(getattr(cls._model, "body_label", None) or [])
1797-
cls._scene_data_mapping = sdp.create_mapping(body_paths)
1808+
cls._scene_data_mapping = scene_data_provider.create_mapping(body_paths)
17981809

17991810
cls._scene_data.transforms = cls._state_0.body_q
1800-
sdp.get_transforms(cls._scene_data, mapping=cls._scene_data_mapping)
1811+
scene_data_provider.get_transforms(cls._scene_data, mapping=cls._scene_data_mapping)
18011812

18021813
@classmethod
18031814
def get_state_1(cls) -> State:

0 commit comments

Comments
 (0)