Source code for pylorenzmie.theory.Particle

from collections.abc import Iterator
from dataclasses import dataclass, field
import numpy as np
from pylorenzmie.lib import LMObject
from pylorenzmie.lib.lmtypes import (Coordinates, Coefficients, Properties)


[docs] @dataclass class Particle(LMObject): '''Abstract base for a scattering particle in Lorenz-Mie microscopy. Holds the particle's 3-D position and the origin of the local coordinate system. Subclasses add the physical parameters needed to compute Mie scattering coefficients via :meth:`ab`. ``Particle`` implements the sequence protocol (``__len__``, ``__iter__``, ``__getitem__``) so that a single particle and a list of particles are interchangeable in :meth:`LorenzMie.field`. Attributes ---------- x_p : float x coordinate of the particle center, in pixels. Default: 0. y_p : float y coordinate of the particle center, in pixels. Default: 0. z_p : float z coordinate of the particle center, in pixels. Default: 100. x_0 : float x coordinate of the local origin, in pixels. Default: 0. y_0 : float y coordinate of the local origin, in pixels. Default: 0. z_0 : float z coordinate of the local origin, in pixels. Default: 0. Notes ----- All coordinates are in pixels. ``r_0`` is set by :class:`Cluster` to translate each constituent particle into the cluster's local frame; it is not an adjustable parameter and is excluded from ``properties``. ''' x_p: float = 0. y_p: float = 0. z_p: float = 100. x_0: float = field(repr=False, default=0.) y_0: float = field(repr=False, default=0.) z_0: float = field(repr=False, default=0.) def __len__(self) -> int: return 1 def __iter__(self) -> Iterator['Particle']: return iter([self]) def __getitem__(self, index: int) -> 'Particle': if index != 0: raise IndexError('Particle index out of range') return self @property def r_p(self) -> Coordinates: '''3-D position of the particle center, in pixels. Returns ------- numpy.ndarray, shape (3,) ``[x_p, y_p, z_p]``. ''' return np.asarray([self.x_p, self.y_p, self.z_p]) @r_p.setter def r_p(self, r_p: Coordinates) -> None: self.x_p, self.y_p, self.z_p = r_p @property def r_0(self) -> Coordinates: '''Origin of the local coordinate system, in pixels. Returns ------- numpy.ndarray, shape (3,) ``[x_0, y_0, z_0]``. ''' return np.asarray([self.x_0, self.y_0, self.z_0]) @r_0.setter def r_0(self, r_0: Coordinates) -> None: self.x_0, self.y_0, self.z_0 = r_0 @LMObject.properties.getter def properties(self) -> Properties: return {'x_p': self.x_p, 'y_p': self.y_p, 'z_p': self.z_p}
[docs] def ab(self, n_m: float | complex = 1.+0.j, wavelength: float = 0.532) -> Coefficients: '''Mie scattering coefficients for this particle. The base-class implementation returns ``ones((1, 2))`` as a trivial placeholder. Subclasses must override this method with a physically meaningful calculation. Parameters ---------- n_m : float or complex Refractive index of the surrounding medium. Default: 1+0j. wavelength : float Vacuum wavelength of the illuminating light, in μm. Default: 0.532. Returns ------- ab : numpy.ndarray, shape (n_terms, 2), dtype complex Mie scattering coefficients. ''' return np.ones((1, 2), dtype=complex)
if __name__ == '__main__': # pragma: no cover Particle.example()