Source code for pylorenzmie.theory.Aberrated

from pylorenzmie.theory.LorenzMie import LorenzMie
from pylorenzmie.theory.Particle import Particle
from pylorenzmie.lib.lmtypes import Coordinates, Field, Properties
import numpy as np


[docs] def Aberrated(base_class: type) -> type: '''Return an aberrated subclass of a LorenzMie calculator. The returned class extends :meth:`scattered_field` to multiply the scattered field by a spherical-aberration phase mask. Parameters ---------- base_class : type A :class:`~pylorenzmie.theory.LorenzMie` subclass to extend. Returns ------- AberratedLorenzMie : type New class inheriting from *base_class*. ''' class AberratedLorenzMie(base_class): '''LorenzMie subclass with spherical aberration. Inherits from the base class supplied to :func:`Aberrated`. Parameters ---------- spherical : float, optional Spherical-aberration coefficient [pixels]. Default: 0. Notes ----- The aberration phase at each pixel is .. math:: \\Phi(\\vec{r}) = s \\frac{r^4}{(r^2 + z_p^2)^2} where :math:`s` is ``spherical``, :math:`r` is the in-plane distance from the particle center in pixels, and :math:`z_p` is the particle's axial position in pixels. ''' def __init__(self, *args, spherical: float = 0., **kwargs) -> None: super().__init__(*args, **kwargs) self.spherical = spherical @LorenzMie.properties.getter def properties(self) -> Properties: return {**super().properties, 'spherical': self.spherical} def _aberration(self, r_p: Coordinates) -> Field: '''Spherical-aberration phase mask for particle at r_p.''' if self.spherical == 0.: return 1. x = self.coordinates[0] - r_p[0] y = self.coordinates[1] - r_p[1] rsq = x * x + y * y zpsq = r_p[2] ** 2 phase = self.spherical * rsq * rsq / (rsq + zpsq) ** 2 return np.exp(1j * phase) def scattered_field(self, particle: Particle, **kwargs) -> Field: '''Scattered field including spherical aberration.''' field = super().scattered_field(particle, **kwargs) r_p = particle.r_p + particle.r_0 return field * self._aberration(r_p) return AberratedLorenzMie
AberratedLorenzMie = Aberrated(LorenzMie) # Fix __qualname__ so pickle can locate the class at module level. # Factory-defined classes get __qualname__ = 'Aberrated.<locals>.AberratedLorenzMie', # which Python cannot resolve during unpickling. AberratedLorenzMie.__qualname__ = 'AberratedLorenzMie' AberratedLorenzMie.__name__ = 'AberratedLorenzMie' if __name__ == '__main__': # pragma: no cover AberratedLorenzMie.example(spherical=0.9)