Source code for isaaclab_ov.assets.deformable_object.deformable_object_data

# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

"""Lazy data container for OVPhysX deformable objects."""

from __future__ import annotations

import weakref

import warp as wp

from isaaclab.assets.deformable_object.base_deformable_object_data import BaseDeformableObjectData
from isaaclab.utils.buffers import TimestampedBufferWarp
from isaaclab.utils.warp import ProxyArray

from isaaclab_ov.tensor_types import TensorType

from .kernels import compute_mean_vec3f_over_vertices, compute_nodal_state_w, vec6f
from .views import OvPhysxDeformableBodyView


[docs] class DeformableObjectData(BaseDeformableObjectData): """Data container for an OVPhysX-backed deformable object. Simulation state is read lazily into stable Warp allocations. Each public :class:`~isaaclab.utils.warp.ProxyArray` is created once and remains valid while OVPhysX refreshes its underlying allocation in place. """ __backend_name__: str = "ovphysx" """The name of the backend for the deformable object data.""" def __init__( self, root_view: OvPhysxDeformableBodyView, device: str, *, position_tensor_type: TensorType, velocity_tensor_type: TensorType, ) -> None: """Initialize the deformable object data. Args: root_view: OVPhysX deformable body view used for simulation-state reads. device: Device used for simulation state and derived computations. position_tensor_type: Tensor type used for simulation-node positions. velocity_tensor_type: Tensor type used for simulation-node velocities. """ super().__init__(device) self._root_view: OvPhysxDeformableBodyView = weakref.proxy(root_view) self._position_tensor_type = position_tensor_type self._velocity_tensor_type = velocity_tensor_type self._num_instances = root_view.count self._max_sim_vertices = root_view.max_simulation_nodes_per_body self._max_sim_elements = root_view.max_simulation_elements_per_body self._max_collision_elements = root_view.max_collision_elements_per_body self._nodal_pos_w = TimestampedBufferWarp((self._num_instances, self._max_sim_vertices), device, wp.vec3f) self._nodal_vel_w = TimestampedBufferWarp((self._num_instances, self._max_sim_vertices), device, wp.vec3f) self._nodal_state_w = TimestampedBufferWarp((self._num_instances, self._max_sim_vertices), device, vec6f) self._root_pos_w = TimestampedBufferWarp((self._num_instances,), device, wp.vec3f) self._root_vel_w = TimestampedBufferWarp((self._num_instances,), device, wp.vec3f) self._nodal_pos_w_proxy: ProxyArray | None = None self._nodal_vel_w_proxy: ProxyArray | None = None self._nodal_state_w_proxy: ProxyArray | None = None self._root_pos_w_proxy: ProxyArray | None = None self._root_vel_w_proxy: ProxyArray | None = None self.default_nodal_state_w: ProxyArray | None = None self.nodal_kinematic_target: ProxyArray | None = None @property def nodal_pos_w(self) -> ProxyArray: """Nodal positions in simulation world frame [m]. Shape is ``(num_instances, max_sim_vertices_per_body)``, dtype ``wp.vec3f``. """ if self._nodal_pos_w.timestamp < self._sim_timestamp: self._root_view.read_into( self._position_tensor_type, self._nodal_pos_w.data.view(wp.float32).reshape((self._num_instances, self._max_sim_vertices, 3)), ) self._nodal_pos_w.timestamp = self._sim_timestamp if self._nodal_pos_w_proxy is None: self._nodal_pos_w_proxy = ProxyArray(self._nodal_pos_w.data) return self._nodal_pos_w_proxy @property def nodal_vel_w(self) -> ProxyArray: """Nodal velocities in simulation world frame [m/s]. Shape is ``(num_instances, max_sim_vertices_per_body)``, dtype ``wp.vec3f``. """ if self._nodal_vel_w.timestamp < self._sim_timestamp: self._root_view.read_into( self._velocity_tensor_type, self._nodal_vel_w.data.view(wp.float32).reshape((self._num_instances, self._max_sim_vertices, 3)), ) self._nodal_vel_w.timestamp = self._sim_timestamp if self._nodal_vel_w_proxy is None: self._nodal_vel_w_proxy = ProxyArray(self._nodal_vel_w.data) return self._nodal_vel_w_proxy @property def nodal_state_w(self) -> ProxyArray: """Nodal position-velocity states in simulation world frame [m, m/s]. Shape is ``(num_instances, max_sim_vertices_per_body)``, dtype ``vec6f``. """ if self._nodal_state_w.timestamp < self._sim_timestamp: wp.launch( compute_nodal_state_w, dim=(self._num_instances, self._max_sim_vertices), inputs=[self.nodal_pos_w.warp, self.nodal_vel_w.warp], outputs=[self._nodal_state_w.data], device=self.device, ) self._nodal_state_w.timestamp = self._sim_timestamp if self._nodal_state_w_proxy is None: self._nodal_state_w_proxy = ProxyArray(self._nodal_state_w.data) return self._nodal_state_w_proxy @property def root_pos_w(self) -> ProxyArray: """Mean simulation-node position in simulation world frame [m]. Shape is ``(num_instances,)``, dtype ``wp.vec3f``. """ if self._root_pos_w.timestamp < self._sim_timestamp: wp.launch( compute_mean_vec3f_over_vertices, dim=self._num_instances, inputs=[self.nodal_pos_w.warp, self._max_sim_vertices], outputs=[self._root_pos_w.data], device=self.device, ) self._root_pos_w.timestamp = self._sim_timestamp if self._root_pos_w_proxy is None: self._root_pos_w_proxy = ProxyArray(self._root_pos_w.data) return self._root_pos_w_proxy @property def root_vel_w(self) -> ProxyArray: """Mean simulation-node velocity in simulation world frame [m/s]. Shape is ``(num_instances,)``, dtype ``wp.vec3f``. """ if self._root_vel_w.timestamp < self._sim_timestamp: wp.launch( compute_mean_vec3f_over_vertices, dim=self._num_instances, inputs=[self.nodal_vel_w.warp, self._max_sim_vertices], outputs=[self._root_vel_w.data], device=self.device, ) self._root_vel_w.timestamp = self._sim_timestamp if self._root_vel_w_proxy is None: self._root_vel_w_proxy = ProxyArray(self._root_vel_w.data) return self._root_vel_w_proxy