Source code for pyuff_ustb.objects.probes.curvilinear_array

from typing import TYPE_CHECKING

import numpy as np

from pyuff_ustb.objects.probes.probe import Probe
from pyuff_ustb.objects.uff import (
    compulsory_property,
    dependent_property,
    optional_property,
)
from pyuff_ustb.readers import read_array, read_scalar

if TYPE_CHECKING:
    # Make sure properties are treated as properties when type checking
    compulsory_property = property
    optional_property = property
    dependent_property = property


[docs] class CurvilinearArray(Probe): """:class:`Uff` class to define a curvilinear array probe geometry. :class:`CurvilinearArray` defines a array of regularly space elements on an arc in the azimuth dimensions. Optionally it can hold each element width and height, assuming the elements are rectangular. Original authors: Alfonso Rodriguez-Molares (alfonsom@ntnu.no) """ # Compulsory properties @compulsory_property def N(self) -> int: "Number of elements" return int(read_scalar(self._reader["N"])) @compulsory_property def pitch(self) -> float: "Distance between the elements in the azimuth direction [m]" return read_scalar(self._reader["pitch"]) @compulsory_property def radius(self) -> float: "Radius of the curvilinear array [m]" return read_scalar(self._reader["radius"]) # Optional properties @optional_property def element_width(self) -> float: "Width of the elements in the azimuth direction [m]" return read_scalar(self._reader["element_width"]) @optional_property def element_height(self) -> float: "Height of the elements in the elevation direction [m]" return read_scalar(self._reader["element_height"]) # Dependent properties @dependent_property def maximum_angle(self) -> float: "Angle of the outermost elements in the array" return np.max(np.abs(self.theta)) # Override some compulsory properties of Probe @compulsory_property def geometry(self) -> np.ndarray: # Try to read geometry from the file first if "geometry" in self._reader: return read_array(self._reader["geometry"]) # If geometry is not set in the file, calculate it based on the fields. element_width = ( self.element_width if self.element_width is not None else self.pitch ) element_height = ( self.element_height if self.element_height is not None else 10 * element_width ) # Compute element coordinates dtheta = 2 * np.arcsin(self.pitch / 2 / self.radius) theta = np.arange(0, self.N) * dtheta theta = theta - np.mean(theta) x0 = self.radius * np.sin(theta) z0 = self.radius * np.cos(theta) - self.radius return np.array( [ x0, np.zeros(self.N), z0, theta, np.zeros(self.N), element_width * np.ones(self.N), element_height * np.ones(self.N), ] )