Source code for embodichain.lab.sim.objects.backends.lifecycle
# ----------------------------------------------------------------------------
# Copyright (c) 2021-2026 DexForce Technology Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ----------------------------------------------------------------------------
"""Backend-specific native entity lifetime helpers."""
from __future__ import annotations
from typing import Sequence
import torch
from embodichain.lab.sim.physics.newton import is_newton_gradient_mode
from .newton import is_newton_scene
__all__ = [
"destroy_articulation_entities",
"destroy_rigid_entities",
"finalize_articulation_spawn",
"apply_rigid_initial_state",
]
def _world_arenas(world: object) -> list[object]:
env = world.get_env()
arenas = env.get_all_arenas()
return arenas if len(arenas) else [env]
[docs]
def destroy_rigid_entities(
world: object,
scene: object,
entities: Sequence[object],
*,
is_newton: bool | None = None,
) -> None:
"""Remove unbound rigid entities using the active backend's API."""
arenas = _world_arenas(world)
newton = is_newton_scene(scene) if is_newton is None else is_newton
for index, entity in enumerate(entities):
if newton:
arenas[index].remove_actor(entity.get_name())
else:
arenas[index].remove_actor(entity)
[docs]
def destroy_articulation_entities(
world: object,
scene: object,
entities: Sequence[object],
*,
is_newton: bool | None = None,
) -> None:
"""Remove unbound articulation entities using the active backend's API."""
arenas = _world_arenas(world)
newton = is_newton_scene(scene) if is_newton is None else is_newton
for index, entity in enumerate(entities):
if newton:
arenas[index].remove_skeleton(entity)
else:
arenas[index].remove_articulation(entity)
[docs]
def finalize_articulation_spawn(articulation: object, result: object) -> None:
"""Apply backend-specific initial-state handling after Spawn binding."""
if is_newton_gradient_mode(result):
initial_qpos = torch.as_tensor(articulation.cfg.init_qpos).reshape(-1)
if initial_qpos.numel() != articulation.dof:
raise ValueError(
f"Articulation {articulation.uid!r} expected {articulation.dof} "
f"initial joint positions, got {initial_qpos.numel()}."
)
if torch.any(initial_qpos != 0.0):
raise NotImplementedError(
"Newton gradient mode cannot apply non-zero init_qpos after "
"Spawn finalization. Author the initial coordinates in the "
"source asset or initialize them in a differentiable task "
"before opening a Warp tape."
)
return
if articulation._data.is_newton_backend:
# Newton finalization already authored the initial state. Clearing one
# facade would select only part of a multi-articulation world.
articulation.reset(clear_dynamics=False)
else:
articulation.reset()
[docs]
def apply_rigid_initial_state(rigid_object: object) -> None:
"""Apply backend-specific initial state without advancing physics."""
if rigid_object.is_spawn_bound:
if rigid_object._spawn_result.backend == "dexsim":
rigid_object.reset()
elif not is_newton_gradient_mode(rigid_object._spawn_result):
rigid_object.clear_dynamics()
return
if is_newton_scene(rigid_object._ps):
if rigid_object._newton_lifecycle_state() == "BUILDER":
rigid_object.set_local_pose(
rigid_object._build_cfg_init_pose(rigid_object._all_indices),
env_ids=rigid_object._all_indices,
)
return
if rigid_object.device.type == "cuda":
# Publish pending native state without moving existing scene objects.
rigid_object._world.update(0.0)
rigid_object.reset()