Skip to content

contains

ContainedParticles

Bases: RelativeObjectState, LinkBasedStateMixin

Object state for computing the number of particles of a given system contained in this object's container volume

Source code in omnigibson/object_states/contains.py
class ContainedParticles(RelativeObjectState, LinkBasedStateMixin):
    """
    Object state for computing the number of particles of a given system contained in this object's container volume
    """

    def __init__(self, obj):
        super().__init__(obj)
        self.check_in_volume = None  # Function to check whether particles are in volume for this container
        self._volume = None  # Volume of this container
        self._compute_info = None  # Intermediate computation information to store

    @classproperty
    def metalink_prefix(cls):
        return m.CONTAINER_LINK_PREFIX

    def _get_value(self, system):
        """
        Args:
            system (VisualParticleSystem or PhysicalParticleSystem): System whose number of particles will be checked inside this object's
                container volume

        Returns:
            ContainedParticlesData: namedtuple with the following keys:
                - n_in_volume (int): Number of @system's particles inside this object's container volume
                - positions (th.tensor): (N, 3) Particle positions of all @system's particles
                - in_volume (th.tensor): (N,) boolean array, True if the corresponding particle is inside this
                    object's container volume, else False
        """
        # Value is false by default
        n_particles_in_volume, raw_positions, checked_positions, particles_in_volume = (
            0,
            th.empty(0),
            th.empty(0),
            th.empty(0),
        )

        # Only run additional computations if there are any particles
        if system.n_particles > 0:
            # First, we check what type of system
            # Currently, we support VisualParticleSystems and PhysicalParticleSystems
            if self.obj.scene.is_visual_particle_system(system_name=system.name):
                # Grab global particle poses and offset them in the direction of their orientation
                raw_positions, quats = system.get_particles_position_orientation()
                unit_z = th.zeros((len(raw_positions), 3, 1))
                unit_z[:, -1, :] = m.VISUAL_PARTICLE_OFFSET
                checked_positions = (T.quat2mat(quats) @ unit_z).reshape(-1, 3) + raw_positions
            elif self.obj.scene.is_physical_particle_system(system_name=system.name):
                raw_positions = system.get_particles_position_orientation()[0]
                checked_positions = raw_positions
            else:
                raise ValueError(
                    f"Invalid system {system} received for getting ContainedParticles state!"
                    f"Currently, only VisualParticleSystems and PhysicalParticleSystems are supported."
                )

        # Only calculate if we have valid positions
        if len(checked_positions) > 0:
            particles_in_volume = self.check_in_volume(checked_positions)
            n_particles_in_volume = particles_in_volume.sum()

        return ContainedParticlesData(n_particles_in_volume, raw_positions, particles_in_volume)

    def _initialize(self):
        super()._initialize()
        self.initialize_link_mixin()

        # Generate volume checker function for this object
        self.check_in_volume, calculate_volume = generate_points_in_volume_checker_function(
            obj=self.obj, volume_link=self.link
        )

        # Calculate volume
        self._volume = calculate_volume()

    @property
    def volume(self):
        """
        Returns:
            float: Total volume for this container
        """
        return self._volume

volume property

Returns:

Type Description
float

Total volume for this container