Theory (pylorenzmie.theory)#

Instrument#

class pylorenzmie.theory.Instrument.Instrument(wavelength=0.447, magnification=0.048, numerical_aperture=1.45, noise=0.05, n_m=1.34)[source]#

Bases: LMObject

In-line holographic microscope for Lorenz-Mie microscopy.

Encapsulates the optical parameters of the instrument. All five attributes (n_m, wavelength, magnification, numerical_aperture, noise) are exposed via properties and are therefore available to Optimizer during fitting.

wavelength#

Vacuum wavelength of the illuminating light, in μm. Default: 0.447.

Type:

float

magnification#

Effective pixel size (object-space), in μm/pixel. Default: 0.048.

Type:

float

numerical_aperture#

Numerical aperture of the objective lens. Default: 1.45.

Type:

float

noise#

Camera noise as a fraction of the mean intensity. Default: 0.05.

Type:

float

n_m#

Refractive index of the medium. Default: 1.340.

Type:

float

wavelength: float = 0.447#
magnification: float = 0.048#
numerical_aperture: float = 1.45#
noise: float = 0.05#
n_m: float = 1.34#
property properties: dict[str, bool | int | float | str]#

Adjustable parameters of this object.

Returns a flat dict mapping parameter names to their current values. Only parameters included here are visible to the serialization methods and to Optimizer during fitting.

Subclasses must override the getter using:

@ParentClass.properties.getter
def properties(self) -> Properties:
    props = super().properties
    props.update(...)
    return props

The base-class getter returns an empty dict; the base-class setter iterates over the supplied dict and calls setattr for every key that already exists as an attribute. Unknown keys are silently ignored and logged at DEBUG level.

wavenumber(in_medium=True, scaled=True)[source]#

Wave number of the illuminating light.

Parameters:
  • in_medium (bool) – If True (default), return the wave number in the medium. If False, return the wave number in vacuum.

  • scaled (bool) – If True (default), return in rad/pixel. If False, return in rad/μm.

Return type:

float

Returns:

k (float) – Wave number.

Particle#

class pylorenzmie.theory.Particle.Particle(x_p=0.0, y_p=0.0, z_p=100.0, x_0=0.0, y_0=0.0, z_0=0.0)[source]#

Bases: 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 ab().

Particle implements the sequence protocol (__len__, __iter__, __getitem__) so that a single particle and a list of particles are interchangeable in LorenzMie.field().

x_p#

x coordinate of the particle center, in pixels. Default: 0.

Type:

float

y_p#

y coordinate of the particle center, in pixels. Default: 0.

Type:

float

z_p#

z coordinate of the particle center, in pixels. Default: 100.

Type:

float

x_0#

x coordinate of the local origin, in pixels. Default: 0.

Type:

float

y_0#

y coordinate of the local origin, in pixels. Default: 0.

Type:

float

z_0#

z coordinate of the local origin, in pixels. Default: 0.

Type:

float

Notes

All coordinates are in pixels. r_0 is set by 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.0#
y_p: float = 0.0#
z_p: float = 100.0#
x_0: float = 0.0#
y_0: float = 0.0#
z_0: float = 0.0#
property r_p: NDArray[float]#

3-D position of the particle center, in pixels.

Returns:

numpy.ndarray, shape (3,)[x_p, y_p, z_p].

property r_0: NDArray[float]#

Origin of the local coordinate system, in pixels.

Returns:

numpy.ndarray, shape (3,)[x_0, y_0, z_0].

property properties: dict[str, bool | int | float | str]#

Adjustable parameters of this object.

Returns a flat dict mapping parameter names to their current values. Only parameters included here are visible to the serialization methods and to Optimizer during fitting.

Subclasses must override the getter using:

@ParentClass.properties.getter
def properties(self) -> Properties:
    props = super().properties
    props.update(...)
    return props

The base-class getter returns an empty dict; the base-class setter iterates over the supplied dict and calls setattr for every key that already exists as an attribute. Unknown keys are silently ignored and logged at DEBUG level.

ab(n_m=1 + 0j, wavelength=0.532)[source]#

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.

Return type:

GenericAlias[complex]

Returns:

ab (numpy.ndarray, shape (n_terms, 2), dtype complex) – Mie scattering coefficients.

Sphere#

class pylorenzmie.theory.Sphere.Sphere(x_p=0.0, y_p=0.0, z_p=100.0, x_0=0.0, y_0=0.0, z_0=0.0, a_p=1.0, n_p=1.5, k_p=0.0)[source]#

Bases: Particle

Homogeneous spherical scatterer for Lorenz-Mie microscopy.

Extends Particle with the physical parameters needed to compute Mie scattering coefficients for an isotropic homogeneous sphere illuminated by a coherent plane wave polarized along x and propagating along z.

a_p#

Radius of the sphere, in μm. Default: 1.

Type:

float

n_p#

Refractive index of the sphere. Default: 1.5.

Type:

float

k_p#

Absorption coefficient of the sphere. Default: 0.

Type:

float

References

  1. C. F. Bohren and D. R. Huffman, Absorption and Scattering of Light by Small Particles (Wiley, 1983), Chapter 8.

  2. W. Yang, “Improved recursive algorithm for light scattering by a multilayered sphere,” Applied Optics 42, 1710–1720 (2003).

  3. O. Pena and U. Pal, “Scattering of electromagnetic radiation by a multilayered sphere,” Computer Physics Communications 180, 2348–2354 (2009). Equation numbering follows this reference.

  4. W. J. Wiscombe, “Improved Mie scattering algorithms,” Applied Optics 19, 1505–1509 (1980).

  5. A. A. R. Neves and D. Pisignano, “Effect of finite terms on the truncation error of Mie series,” Optics Letters 37, 2481–2483 (2012).

a_p: float = 1.0#
n_p: float = 1.5#
k_p: float = 0.0#
property d_p: float#

Diameter of the sphere, in μm.

Equivalent to 2 * a_p. Setting d_p updates a_p.

Returns:

float

property properties: dict[str, bool | int | float | str]#

Adjustable parameters of this object.

Returns a flat dict mapping parameter names to their current values. Only parameters included here are visible to the serialization methods and to Optimizer during fitting.

Subclasses must override the getter using:

@ParentClass.properties.getter
def properties(self) -> Properties:
    props = super().properties
    props.update(...)
    return props

The base-class getter returns an empty dict; the base-class setter iterates over the supplied dict and calls setattr for every key that already exists as an attribute. Unknown keys are silently ignored and logged at DEBUG level.

ab(n_m=1.42, wavelength=0.532)[source]#

Mie scattering coefficients for the sphere.

Parameters:
  • n_m (float or complex) – Refractive index of the medium. Default: 1.42.

  • wavelength (float) – Vacuum wavelength of the illuminating light, in μm. Default: 0.532.

Return type:

GenericAlias[complex]

Returns:

ab (numpy.ndarray, shape (n_terms, 2), dtype complex) – Mie scattering coefficients.

static wiscombe_yang(x, m)[source]#

Number of terms to retain in the partial-wave expansion.

Implements the truncation criterion of Wiscombe (1980) with the extension for multilayered spheres from Yang (2003) Eq. (30).

Parameters:
  • x (float) – Size parameter of the sphere (or outermost layer).

  • m (float or complex) – Refractive index of the sphere relative to the medium.

Return type:

int

Returns:

nstop (int) – Number of terms to retain.

static neves_pisignano(x, precision=6.0)[source]#

Number of terms to retain, after Neves and Pisignano (2012).

Alternative termination criterion to wiscombe_yang().

Parameters:
  • x (float) – Size parameter of the sphere.

  • precision (float) – Desired decimal digits of precision. Default: 6.

Return type:

int

Returns:

nstop (int) – Number of terms to retain.

static mie_coefficients(a_p, n_p, k_p, n_m, wavelength)[source]#

Mie scattering coefficients for a homogeneous sphere.

Parameters:
  • a_p (float) – Radius of the sphere, in μm.

  • n_p (float) – Refractive index of the sphere.

  • k_p (float) – Absorption coefficient of the sphere.

  • n_m (float or complex) – Refractive index of the medium.

  • wavelength (float) – Vacuum wavelength of the illuminating light, in μm.

Return type:

GenericAlias[complex]

Returns:

ab (numpy.ndarray, shape (n_terms, 2), dtype complex) – Mie scattering coefficients.

classmethod example()[source]#
Return type:

None

Cluster#

class pylorenzmie.theory.Cluster.Cluster(x_p=0.0, y_p=0.0, z_p=100.0, x_0=0.0, y_0=0.0, z_0=0.0, particles=<factory>)[source]#

Bases: Particle

A cluster of particles for Lorenz-Mie microscopy.

Groups a list of Particle objects into a single scatterer. The cluster position r_p sets the origin of each constituent particle’s coordinate system via Particle.r_0.

Inherits from Particle.

Parameters:

particles (list of Particle, optional) – Constituent particles. Default: empty list.

Notes

Setting x_p, y_p, z_p, or particles automatically calls update() to propagate the new cluster center to each constituent particle’s r_0.

particles: list[Particle]#
property properties: dict[str, bool | int | float | str]#

Adjustable parameters of this object.

Returns a flat dict mapping parameter names to their current values. Only parameters included here are visible to the serialization methods and to Optimizer during fitting.

Subclasses must override the getter using:

@ParentClass.properties.getter
def properties(self) -> Properties:
    props = super().properties
    props.update(...)
    return props

The base-class getter returns an empty dict; the base-class setter iterates over the supplied dict and calls setattr for every key that already exists as an attribute. Unknown keys are silently ignored and logged at DEBUG level.

update()[source]#

Propagate cluster position to each constituent particle’s origin.

Return type:

None

Dimer#

class pylorenzmie.theory.Dimer.Dimer(x_p=0.0, y_p=0.0, z_p=100.0, x_0=0.0, y_0=0.0, z_0=0.0, particles=<factory>, a_p=0.75, n_p=1.45, k_p=0.0, theta=0.7853981633974483, phi=0.0, magnification=0.048)[source]#

Bases: Cluster

A touching pair of identical spheres for Lorenz-Mie microscopy.

Positions two Sphere objects symmetrically about the cluster center, separated by twice the sphere radius. Orientation is specified as elevation and azimuthal angles.

Inherits from Cluster.

Parameters:
  • a_p (float, optional) – Radius of each sphere [μm]. Default: 0.75.

  • n_p (float, optional) – Refractive index of each sphere. Default: 1.45.

  • k_p (float, optional) – Imaginary part of the refractive index. Default: 0.

  • theta (float, optional) – Elevation angle of the dimer axis above the xy-plane [rad]. theta = 0 → axis in the xy-plane; theta = pi/2 → axis along z. Default: pi/4.

  • phi (float, optional) – Azimuthal angle of the dimer axis in the xy-plane [rad]. Default: 0.

  • magnification (float, optional) – Instrument magnification [μm/pixel], used to convert the sphere radius to a pixel-space separation. Default: 0.048.

a_p: float = 0.75#
n_p: float = 1.45#
k_p: float = 0.0#
theta: float = 0.7853981633974483#
phi: float = 0.0#
magnification: float = 0.048#
property properties: dict[str, bool | int | float | str]#

Adjustable parameters of this object.

Returns a flat dict mapping parameter names to their current values. Only parameters included here are visible to the serialization methods and to Optimizer during fitting.

Subclasses must override the getter using:

@ParentClass.properties.getter
def properties(self) -> Properties:
    props = super().properties
    props.update(...)
    return props

The base-class getter returns an empty dict; the base-class setter iterates over the supplied dict and calls setattr for every key that already exists as an attribute. Unknown keys are silently ignored and logged at DEBUG level.

update_positions()[source]#

Set sphere positions from current orientation and radius.

Places each sphere at ±(a_p / magnification) pixels from the cluster center along the dimer axis.

Return type:

None

classmethod example()[source]#
Return type:

None

LorenzMie#

class pylorenzmie.theory.LorenzMie.LorenzMie(coordinates=None, particle=None, instrument=None)[source]#

Bases: LMObject

Scattered light field computed with Generalized Lorenz-Mie theory.

Computes the electric field scattered by one or more particles, then forms a synthetic hologram by interfering the scattered field with the incident plane wave. The incident illumination is assumed to be a plane wave linearly polarized along x and propagating along -z.

The class attribute method is used by Optimizer to select a compatible calculator.

coordinates#

Pixel coordinates at which the field is evaluated, shape (3, npts). Defaults to a 201×201 grid if not supplied.

Type:

numpy.ndarray

particle#

Scattering particle(s). Defaults to a Sphere.

Type:

Particle or list of Particle

instrument#

Optical parameters of the microscope.

Type:

Instrument

References

  1. C. F. Bohren and D. R. Huffman, Absorption and Scattering of Light by Small Particles (Wiley, 1983), Chapter 4.

  2. W. J. Wiscombe, “Improved Mie scattering algorithms,” Appl. Opt. 19, 1505–1509 (1980).

  3. W. J. Lentz, “Generating Bessel functions in Mie scattering calculations using continued fractions,” Appl. Opt. 15, 668–671 (1976).

  4. S.-H. Lee, Y. Roichman, G.-R. Yi, S.-H. Kim, S.-M. Yang, A. van Blaaderen, P. van Oostrum and D. G. Grier, “Characterizing and tracking single colloidal particles with video holographic microscopy,” Opt. Express 15, 18275–18282 (2007).

  5. F. C. Cheong, B. Sun, R. Dreyfus, J. Amato-Grill, K. Xiao, L. Dixon and D. G. Grier, “Flow visualization and flow cytometry with holographic video microscopy,” Opt. Express 17, 13071–13079 (2009).

method: str = 'numpy'#
property properties: dict[str, bool | int | float | str]#

Adjustable parameters of this object.

Returns a flat dict mapping parameter names to their current values. Only parameters included here are visible to the serialization methods and to Optimizer during fitting.

Subclasses must override the getter using:

@ParentClass.properties.getter
def properties(self) -> Properties:
    props = super().properties
    props.update(...)
    return props

The base-class getter returns an empty dict; the base-class setter iterates over the supplied dict and calls setattr for every key that already exists as an attribute. Unknown keys are silently ignored and logged at DEBUG level.

property coordinates: NDArray[float]#

Pixel coordinates at which the field is evaluated.

Shape is always (3, npts). If assigned a (2, npts) array, the z-coordinates are set to zero. Assigning None creates a default 201×201 grid.

hologram(**kwargs)[source]#

Hologram of the particle at the current coordinates.

Parameters:
  • cartesian (bool) – If True (default), project the field onto Cartesian coordinates. If False, return the field in spherical polar coordinates.

  • bohren (bool) – If True (default), use +z along the propagation direction. If False, flip the orientation of z.

Return type:

GenericAlias[float] | GenericAlias[int]

Returns:

hologram (numpy.ndarray, shape (npts,)) – Computed hologram intensity at each coordinate.

scattered_field(particle, **kwargs)[source]#

Electric field scattered by a single particle.

Parameters:
  • particle (Particle) – The scattering particle.

  • **kwargs – Passed to lorenzmie() (cartesian, bohren).

Return type:

GenericAlias[complex]

Returns:

field (numpy.ndarray, shape (3, npts), dtype complex) – Complex scattered field, including the propagation phase exp(-i k z_p).

field(**kwargs)[source]#

Electric field scattered by the particle(s).

Parameters:
  • cartesian (bool) – If True (default), project the field onto Cartesian coordinates. If False, return the field in spherical polar coordinates.

  • bohren (bool) – If True (default), use +z along the propagation direction. If False, flip the orientation of z.

Return type:

GenericAlias[complex]

Returns:

field (numpy.ndarray, shape (3, npts), dtype complex) – Complex electric field scattered by the particle.

lorenzmie(ab, kdr, cartesian=True, bohren=True)[source]#

Scattered field for given Mie coefficients and geometry.

Parameters:
  • ab (numpy.ndarray, shape (n_orders, 2)) – Mie scattering coefficients.

  • kdr (numpy.ndarray, shape (3, npts)) – Wave-number-scaled displacement from particle to each coordinate point.

  • cartesian (bool) – If True, return field projected onto Cartesian coordinates. Default: True.

  • bohren (bool) – If True, use sign convention from Bohren and Huffman. Default: True.

Return type:

GenericAlias[complex]

Returns:

field (numpy.ndarray, shape (3, npts), dtype complex) – Complex scattered field at each coordinate.

classmethod example(shape=(201, 201), show=True, **kwargs)[source]#
Return type:

None

Aberrated#

pylorenzmie.theory.Aberrated.Aberrated(base_class)[source]#

Return an aberrated subclass of a LorenzMie calculator.

The returned class extends scattered_field() to multiply the scattered field by a spherical-aberration phase mask.

Parameters:

base_class (type) – A LorenzMie subclass to extend.

Return type:

type

Returns:

AberratedLorenzMie (type) – New class inheriting from base_class.

class pylorenzmie.theory.Aberrated.AberratedLorenzMie(*args, spherical=0.0, **kwargs)#

Bases: LorenzMie

LorenzMie subclass with spherical aberration.

Inherits from the base class supplied to Aberrated().

Parameters:

spherical (float, optional) – Spherical-aberration coefficient [pixels]. Default: 0.

Notes

The aberration phase at each pixel is

\[\Phi(\vec{r}) = s \frac{r^4}{(r^2 + z_p^2)^2}\]

where \(s\) is spherical, \(r\) is the in-plane distance from the particle center in pixels, and \(z_p\) is the particle’s axial position in pixels.

property properties: dict[str, bool | int | float | str]#

Adjustable parameters of this object.

Returns a flat dict mapping parameter names to their current values. Only parameters included here are visible to the serialization methods and to Optimizer during fitting.

Subclasses must override the getter using:

@ParentClass.properties.getter
def properties(self) -> Properties:
    props = super().properties
    props.update(...)
    return props

The base-class getter returns an empty dict; the base-class setter iterates over the supplied dict and calls setattr for every key that already exists as an attribute. Unknown keys are silently ignored and logged at DEBUG level.

scattered_field(particle: Particle, **kwargs) NDArray[complex]#

Scattered field including spherical aberration.

Return type:

GenericAlias[complex]

cupyLorenzMie#

class pylorenzmie.theory.cupyLorenzMie.cupyLorenzMie(*args, double_precision=True, **kwargs)[source]#

Bases: LorenzMie

Compute scattered light field with CUDA acceleration.

Inherits#

pylorenzmie.theory.LorenzMie

Properties#

double_precisionbool

If True, perform GPU calculations in double precision. Default: True

field(cartesian=True, bohren=True, gpu=False)[source]#

Returns the complex-valued field at each of the coordinates.

gpubool

If True, return gpu variable for field. Default [False]: return cpu field

method: str = 'cupy numpy'#
property double_precision: bool#
hologram(cartesian=True, bohren=True, device=False)[source]#

Returns the hologram of the particle

Return type:

ndarray

Returns:

  • hologram (cp.ndarray) – The hologram of the particle on the GPU

  • Keywords

  • ——–

  • cartesian (bool) – If True, compute the field in cartesian coordinates. Default: True

  • bohren (bool) – If True, use Bohren’s convention for the field. Default: True

field(cartesian=True, bohren=True, device=False)[source]#

Returns the field scattered by a particle

Return type:

ndarray

culorenzmief()[source]#

Return CUDA kernel for single-precision field computation

Return type:

RawKernel

culorenzmie()[source]#

Return CUDA kernel for double-precision field computation

Return type:

RawKernel

numbaLorenzMie#

pylorenzmie.theory.numbaLorenzMie.compute_field_jit(kdr, buffers, scratch, ab, cartesian, bohren)#

Numba-compiled scattered field sum over Mie partial waves.

Parameters:
  • kdr (numpy.ndarray, shape (3, npts)) – Wave-number-scaled displacement from particle to each coordinate point.

  • buffers (tuple of numpy.ndarray, each shape (3, npts), dtype complex) – Pre-allocated working arrays (Mo1n, Ne1n, Es, Ec).

  • scratch (numpy.ndarray, shape (2, npts), dtype float) – Pre-allocated real scratch arrays (swisc, twisc) for the Legendre upward recurrence.

  • ab (numpy.ndarray, shape (n_orders, 2), dtype complex) – Mie scattering coefficients.

  • cartesian (bool) – If True, return field projected onto Cartesian coordinates.

  • bohren (bool) – If True, use sign convention from Bohren and Huffman.

Returns:

field (numpy.ndarray, shape (3, npts), dtype complex) – Complex scattered field at each coordinate.

class pylorenzmie.theory.numbaLorenzMie.numbaLorenzMie(coordinates=None, particle=None, instrument=None)[source]#

Bases: LorenzMie

LorenzMie accelerated with Numba JIT compilation.

Overrides lorenzmie() with a Numba-compiled kernel that runs the partial-wave sum in native code. The first call triggers JIT compilation (warm-up); subsequent calls use the cached compiled function.

The class attribute method = 'numba' allows Optimizer to select a compatible model.

method: str = 'numba'#
lorenzmie(ab, kdr, cartesian=True, bohren=True)[source]#

Scattered field for given Mie coefficients and geometry.

Parameters:
  • ab (numpy.ndarray, shape (n_orders, 2)) – Mie scattering coefficients.

  • kdr (numpy.ndarray, shape (3, npts)) – Wave-number-scaled displacement from particle to each coordinate point.

  • cartesian (bool) – If True, return field projected onto Cartesian coordinates. Default: True.

  • bohren (bool) – If True, use sign convention from Bohren and Huffman. Default: True.

Return type:

GenericAlias[complex]

Returns:

field (numpy.ndarray, shape (3, npts), dtype complex) – Complex scattered field at each coordinate.