Skip to content

Commit 754a9f3

Browse files
committed
fix
1 parent 7b38e09 commit 754a9f3

2 files changed

Lines changed: 47 additions & 3 deletions

File tree

source/isaaclab/isaaclab/scene/interactive_scene.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ def __init__(self, cfg: InteractiveSceneCfg):
215215
if self.cfg.filter_collisions and "physx" in self.physics_backend:
216216
self.filter_collisions(self._global_prim_paths)
217217

218-
def _build_clone_plan_from_cfg(self) -> cloner.ClonePlan:
218+
def _build_clone_plan_from_cfg(self) -> cloner.ClonePlan | None:
219219
"""Build a clone plan from scene cfg spawn variants and write planned spawn paths."""
220220

221221
def num_variants(spawn_cfg) -> int:
@@ -251,8 +251,11 @@ def set_spawn_paths(spawn_cfg, paths: list[str | None]) -> None:
251251
raise ValueError(f"Spawner at '{prim_path}' must have at least one variant.")
252252
groups.append((cfg.spawn, prim_path.replace(self.env_regex_ns, self.env_fmt), count))
253253

254+
if not groups:
255+
return None
256+
254257
# Homogeneous scenes still spawn sources at env_0, but publish the simpler env-root plan.
255-
if not groups or all(count == 1 for _, _, count in groups):
258+
if all(count == 1 for _, _, count in groups):
256259
for spawn_cfg, destination, _ in groups:
257260
set_spawn_paths(spawn_cfg, [destination.format(0)])
258261
return cloner.ClonePlan(
@@ -293,6 +296,12 @@ def clone_environments(self, copy_from_source: bool = False):
293296
If True, clones are independent copies of the source prim and won't reflect its changes (start-up time
294297
may increase). Defaults to False.
295298
"""
299+
plan = self._clone_plan
300+
assert self.sim is not None
301+
if plan is None:
302+
self.sim.set_clone_plan(None)
303+
return
304+
296305
# PhysX-only: set env id bit count for replicated physics. Newton handles env separation in its own API.
297306
# Intentionally matches both physx and ovphysx (both are PhysX-based)
298307
if self.cfg.replicate_physics and "physx" in self.physics_backend:
@@ -303,7 +312,6 @@ def clone_environments(self, copy_from_source: bool = False):
303312
# ``SimulationContext.reset`` does the Fabric resync — re-enabling here would batch-resync everything
304313
# we just authored, which is slower than the unsuppressed baseline.
305314
with cloner.disabled_fabric_change_notifies(self.stage, restore=False):
306-
plan = self._clone_plan
307315
replicate_args = (plan.sources, plan.destinations, self._ALL_INDICES, plan.clone_mask)
308316

309317
if not copy_from_source and self.cloner_cfg.physics_clone_fn is not None:

source/isaaclab/test/scene/test_interactive_scene.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,18 @@ def _usd_replicate(stage, *args, **kwargs):
214214
assert len(set_plan_calls) == 1
215215

216216

217+
def test_clone_environments_skips_replication_without_plan():
218+
"""Direct-path cfg scenes publish no plan and do not dispatch cloners."""
219+
scene = object.__new__(InteractiveScene)
220+
scene._clone_plan = None
221+
set_plan_calls = []
222+
scene.sim = SimpleNamespace(set_clone_plan=set_plan_calls.append)
223+
224+
scene.clone_environments(copy_from_source=False)
225+
226+
assert set_plan_calls == [None]
227+
228+
217229
def test_clone_environments_executes_asset_level_plan_without_usd_positions(monkeypatch: pytest.MonkeyPatch):
218230
"""Asset-level plans preserve env-root transforms by skipping USD positions."""
219231
from isaaclab.cloner import ClonePlan
@@ -290,6 +302,7 @@ def test_build_clone_plan_from_cfg_plans_multi_and_single_spawners(monkeypatch:
290302

291303
plan = scene._build_clone_plan_from_cfg()
292304

305+
assert plan is not None
293306
assert plan.sources == [
294307
"/World/envs/env_0/Object",
295308
"/World/envs/env_1/Object",
@@ -325,12 +338,33 @@ def test_build_clone_plan_from_cfg_defaults_to_env0_plan(monkeypatch: pytest.Mon
325338

326339
plan = scene._build_clone_plan_from_cfg()
327340

341+
assert plan is not None
328342
assert plan.sources == ["/World/envs/env_0"]
329343
assert plan.destinations == [scene.env_fmt]
330344
assert plan.clone_mask.shape == (1, scene.num_envs)
331345
assert scene.cfg.robot.spawn.spawn_path == "/World/envs/env_0/Robot"
332346

333347

348+
def test_build_clone_plan_from_cfg_returns_none_without_env_scoped_groups(monkeypatch: pytest.MonkeyPatch):
349+
"""Direct-path cfg scenes should not force env-root replication."""
350+
from isaaclab.cloner import sequential
351+
352+
scene = object.__new__(InteractiveScene)
353+
scene.cfg = SimpleNamespace(
354+
num_envs=1,
355+
robot=SimpleNamespace(
356+
prim_path="/World/Robot",
357+
spawn=sim_utils.CuboidCfg(size=(0.1, 0.1, 0.1)),
358+
),
359+
)
360+
scene.env_fmt = "/World/envs/env_{}"
361+
scene.cloner_cfg = SimpleNamespace(clone_strategy=sequential)
362+
monkeypatch.setattr(InteractiveScene, "device", property(lambda self: "cpu"))
363+
364+
assert scene._build_clone_plan_from_cfg() is None
365+
assert scene.cfg.robot.spawn.spawn_path is None
366+
367+
334368
def test_build_clone_plan_from_cfg_sets_collection_member_paths(monkeypatch: pytest.MonkeyPatch):
335369
"""Rigid object collection members are planned independently."""
336370
from isaaclab.cloner import sequential
@@ -356,6 +390,7 @@ def test_build_clone_plan_from_cfg_sets_collection_member_paths(monkeypatch: pyt
356390

357391
plan = scene._build_clone_plan_from_cfg()
358392

393+
assert plan is not None
359394
planned_cube = scene.cfg.objects.rigid_objects["cube"]
360395
planned_shape = scene.cfg.objects.rigid_objects["shape"]
361396
assert planned_cube.spawn.spawn_path == "/World/envs/env_0/Cube"
@@ -388,6 +423,7 @@ def test_build_clone_plan_from_cfg_marks_unused_variants(monkeypatch: pytest.Mon
388423

389424
plan = scene._build_clone_plan_from_cfg()
390425

426+
assert plan is not None
391427
assert scene.cfg.object.spawn.spawn_paths == ["/World/envs/env_0/Object", "/World/envs/env_1/Object", None]
392428
assert plan.clone_mask[2].sum() == 0
393429

0 commit comments

Comments
 (0)