Source code for atomsmltr.environment.zones.volumes

"""
volumes - 1D zones
=======================

Here we implement 3D zones, namely ``Box``

.. code-block:: python

    from atomsmltr.environment.zones import Box

    pos_box = Box(
        xmin=-10,
        xmax=10,
        ymin=0,
        ymax=5,
        zmin=-8,
        zmax=100,
        target="position",
        action="tag",
        tag="position box",
    )
"""

# % IMPORTS
import numpy as np

# % LOCAL IMPORTS
from .generic import Zone
from ...utils.infostring import InfoString
from ...utils.misc import check_positive_float

# % CLASSES


[docs] class Box(Zone): """A 3D box with cartesian coordinates Parameters ---------- xmin : float minimum value for x xmax : float maximum value for x ymin : float minimum value for y ymax : float maximum value for y zmin : float minimum value for z zmax : float maximum value for z target : str, optional the target for the zone, can be "position" or "speed", by default "position" action : str, optional the action associated to the zone. Currently only "stop" is implemented, by default "stop" tag : str, optional the zone tag in_tag : str, optional tag for an object inside the zone, by default None out_tag : str, optional tag for an object inside the zone, by default None Example ------- .. code-block:: python from atomsmltr.environment.zones import Box pos_box = Box( xmin=-10, xmax=10, ymin=0, ymax=5, zmin=-8, zmax=100, target="position", action="tag", tag="position box", ) """ def __init__( self, xmin: float, xmax: float, ymin: float, ymax: float, zmin: float, zmax: float, target: str = "position", action: str = "stop", tag: str = None, in_tag: str = None, out_tag: str = None, ): super(Box, self).__init__( target=target, action=action, tag=tag, in_tag=in_tag, out_tag=out_tag ) self.xmin = xmin self.xmax = xmax self.ymin = ymin self.ymax = ymax self.zmin = zmin self.zmax = zmax # -- GETTERS & SETTERS @property def type(self): return "3D Box" @property def xmin(self): """float: the minimum value for x""" return self.__xmin @xmin.setter def xmin(self, xmin): self.__xmin = float(xmin) @property def xmax(self): """float: the maximum value for x""" return self.__xmax @xmax.setter def xmax(self, xmax): self.__xmax = float(xmax) @property def ymin(self): """float: the minimum value for y""" return self.__ymin @ymin.setter def ymin(self, ymin): self.__ymin = float(ymin) @property def ymax(self): """float: the maximum value for y""" return self.__ymax @ymax.setter def ymax(self, ymax): self.__ymax = float(ymax) @property def zmin(self): """float: the minimum value for z""" return self.__zmin @zmin.setter def zmin(self, zmin): self.__zmin = float(zmin) @property def zmax(self): """float: the maximum value for z""" return self.__zmax @zmax.setter def zmax(self, zmax): self.__zmax = float(zmax) # -- ZONE def _in_zone(self, vector): x, y, z = vector.T in_zone = ( (x >= self.xmin) & (x <= self.xmax) & (y >= self.ymin) & (y <= self.ymax) & (z >= self.zmin) & (z <= self.zmax) ) return in_zone.T # -- INFOSTRING
[docs] def gen_infostring_obj(self): """Generates an info string object""" title = self.type title = title[:1].upper() + title[1:] # capitalize first letter info = InfoString(title=title) info.add_section("Parameters") info.add_element("type", "3D Box") info.add_element("tag", self.tag) info.add_element("in_tag", self.in_tag) info.add_element("out_tag", self.tag) info.add_element("target", self.target) info.add_element("action", self.action) info.add_element(f"xmin, xmax", f"{self.xmin, self.xmax}") info.add_element(f"ymin, ymax", f"{self.ymin, self.ymax}") info.add_element(f"zmin, zmax", f"{self.zmin, self.zmax}") info.add_element(f"inverted", f"{self.inverted}") return info
# -- PLOT def plot1D(self, ax=None): pass def plot2D(self, ax=None): pass def plot3D(self, ax=None): pass
[docs] class Cylinder(Zone): """A cylinder zone Parameters ---------- origin : array, shape (3), optional the 'center' of the cylinder, i.e. a point on its axis, by default (0, 0, 0) direction : array, shape (3), optional a vector along the axis of the cylinder, by default (1, 0, 0) radius : float, optional the cylinder radius, in m or m/s, by default 1.0 target : str, optional the target for the zone, can be "position" or "speed", by default "position" action : str, optional the action associated to the zone. Currently only "stop" is implemented, by default "stop" tag : str, optional the zone tag in_tag : str, optional tag for an object inside the zone, by default None out_tag : str, optional tag for an object inside the zone, by default None """ def __init__( self, origin: np.ndarray = (0, 0, 0), direction: np.ndarray = (1, 0, 0), radius: float = 1.0, target="position", action="stop", tag=None, in_tag: str = None, out_tag: str = None, ): super(Cylinder, self).__init__( target=target, action=action, tag=tag, in_tag=in_tag, out_tag=out_tag ) self.origin = origin self.direction = direction self.radius = radius # -- PROPERTIES @property def type(self): return "3D Cylinder" # - origin @property def origin(self) -> np.ndarray: """array, shape (3): cylinder 'center'""" return self.__origin @origin.setter def origin(self, value: np.ndarray): value = np.asanyarray(value) if value.size != 3: raise ValueError("'origin' should be an array of size 3") self.__origin = value # - direction @property def direction(self) -> np.ndarray: """array, shape (3): cylinder axis direction""" return self.__direction @direction.setter def direction(self, value: np.ndarray): value = np.asanyarray(value) if value.size != 3: raise ValueError("'direction' should be an array of size 3") if np.linalg.norm(value) == 0: raise ValueError("'the norm of 'direction' cannot be zero") self.__direction = value / np.linalg.norm(value) # - radius @property def power(self) -> float: """float: cylinder radius (m) or (m/s)""" return self._power @power.setter def power(self, value: float) -> None: check_positive_float("power", value) self._power = float(value) # -- METHODS def _in_zone(self, vector): # -- compute distance to axis r = vector - self.origin cross_product = np.cross(r, self.direction) distance = np.linalg.norm(cross_product, axis=-1) # -- cylinder return distance <= self.radius # -- INFOSTRING
[docs] def gen_infostring_obj(self): """Generates an info string object""" title = self.type title = title[:1].upper() + title[1:] # capitalize first letter info = InfoString(title=title) info.add_section("Parameters") info.add_element("type", "3D Cylinder") info.add_element("tag", self.tag) info.add_element("in_tag", self.in_tag) info.add_element("out_tag", self.tag) info.add_element("target", self.target) info.add_element("action", self.action) info.add_element(f"direction", f"{self.direction}") info.add_element(f"origin", f"{self.origin}") info.add_element(f"radius", f"{self.radius}") info.add_element(f"inverted", f"{self.inverted}") return info
# -- PLOT def plot1D(self, ax=None): pass def plot2D(self, ax=None): pass def plot3D(self, ax=None): pass