psf_generator.propagators#

Submodules#

Classes#

ScalarCartesianPropagator

Propagator for the scalar approximation of the Richards-Wolf integral in Cartesian parameterization.

ScalarSphericalPropagator

Propagator for the scalar approximation of the Richard's-Wolf integral in spherical parameterization.

VectorialCartesianPropagator

Propagator for the vectorial case of the Richard's-Wolf integral in Cartesian parameterization.

VectorialSphericalPropagator

Propagator for the vectorial case of the Richard's-Wolf integral in spherical parameterization.

Package Contents#

class psf_generator.propagators.ScalarCartesianPropagator(n_pix_pupil=128, n_pix_psf=128, device='cpu', zernike_coefficients=None, special_phase_mask=None, custom_field=None, wavelength=632, na=1.3, pix_size=10, defocus_step=0, n_defocus=1, sz_correction=True, apod_factor=False, envelope=None, gibson_lanni=False, z_p=1000.0, n_s=1.3, n_g=1.5, n_g0=1.5, t_g=170000.0, t_g0=170000.0, n_i=1.5, n_i0=1.5, t_i0=100000.0)[source]#

Bases: psf_generator.propagators.cartesian_propagator.CartesianPropagator

Propagator for the scalar approximation of the Richards-Wolf integral in Cartesian parameterization.

The scalar approximation is

\[\boldsymbol{e}_{\infty}(\mathbf{s}) = \boldsymbol{e}_{\textrm{inc}}(\mathbf{s}).\]

The equation to compute the eletric field is

\[E(\boldsymbol{\rho}) = -\frac{\mathrm{i}fk}{2\pi}\iint\limits_{s_x^2 + s_y^2 \leq s_{max}^2} \frac{\boldsymbol{e}_{\infty}(s_x,s_y)}{s_z} \mathrm{e}^{\mathrm{i} ks_z z} \mathrm{e}^{\mathrm{i} k (s_x x + s_y y)} ds_x ds_y.\]

The focus field is the 2D Fourier transform of \(\frac{\boldsymbol{e}_{\infty}(s_x,s_y)}{s_z}\mathrm{e}^{\mathrm{i} k s_z z}\).

classmethod get_name() str[source]#
initialize_input_field() torch.Tensor[source]#

Define the corresponding 2D pupil function as the input field.

Notes#

This function is defined on the unit disk centered at (0,0)

\[u^2 + v^2 <= 1.\]

The mapping between this domain and the physical pupil coordinates are

\[u = s_x / s_{\mathrm{max}}, v = s_y / s_{\mathrm{max}}.\]

such that the physical domain is:

\[s_x^2 + s_y^2 <= s_{\mathrm{max}}^2 = \sin(\theta_{\mathrm{max}})^2.\]
class psf_generator.propagators.ScalarSphericalPropagator(n_pix_pupil=128, n_pix_psf=128, device='cpu', zernike_coefficients=None, custom_field=None, wavelength=632, na=1.3, pix_size=10, defocus_step=0, n_defocus=1, apod_factor=False, envelope=None, cos_factor=False, gibson_lanni=False, z_p=1000.0, n_s=1.3, n_g=1.5, n_g0=1.5, t_g=170000.0, t_g0=170000.0, n_i=1.5, n_i0=1.5, t_i0=100000.0, integrator=simpsons_rule)[source]#

Bases: psf_generator.propagators.spherical_propagator.SphericalPropagator

Propagator for the scalar approximation of the Richard’s-Wolf integral in spherical parameterization.

The equation to compute the eletric field is

\[E(\boldsymbol{\rho}) = -\mathrm{i}fk \int_0^{\theta_{\max}} d\theta \mathrm{e}_{\infty}(\theta) J_0(k \rho \sin \theta) \mathrm{e}^{\mathrm{i} kz\cos\theta} \sin\theta,\]

where \(J_0\) is the Bessel function of first kind and order 0.

classmethod get_name() str[source]#
initialize_input_field() torch.Tensor[source]#

Define a (1D) radial pupil function as the input field.

Notes#

This function is defined on the interval \(\rho \in [0,1]\); \(\rho\) is a “normalized” radius. The conversion to physical pupil coordinates - the polar angle \(\theta\) - is given by

\[\rho = \frac{\sin{\theta}}{\sin{\theta_{\max}}},\]

such that the physical domain is

\[\theta \leq \theta_{\max}.\]
compute_focus_field() torch.Tensor[source]#

Compute the focus field for scalar spherical propagator.

Parameters#

self.thetastorch.Tensor

Angles of sampling of shape (n_thetas, ).

self.rstorch.Tensor

Radii of sampling of shape (n_radii, ).

self.correction_factortorch.Tensor

Correction factor of shape (n_thetas, ).

J0torch.Tensor

Bessel function of the first kind of order 0 \(J_0\). Shape: (n_theta, n_radii).

Returns#

field: torch.Tensor

Output field.

Notes#

This involves expensive evaluations of Bessel functions. We compute it independently of defocus and handle defocus via batching with vmap().

_compute_psf_at_defocus(defocus_term, J0: torch.Tensor, pupil: torch.Tensor, sin_t: torch.Tensor) torch.Tensor[source]#

Compute PSF at defocus.

Parameters#

defocus_term:

Factor in the integrand corresponding to defocus.

J0: torch.Tensor

Bessel function of the first kind of order 0 \(J_0\).

pupil: torch.Tensor

Pupil function.

sin_t: torch.Tensor

Factor in the integrand of shape: (n_thetas, ).

Returns#

field: torch.Tensor

Output field at defocus. Shape: (n_channels=1, size_x, size_y).

Notes#

We first compute E(r)–integrand for a list of unique radii values, then scatter the radial evaluations of E(r) onto the xy image grid.

class psf_generator.propagators.VectorialCartesianPropagator(n_pix_pupil=128, n_pix_psf=128, device='cpu', zernike_coefficients=None, special_phase_mask=None, e0x=1.0, e0y=0.0, wavelength=632, na=1.3, pix_size=10, defocus_step=0, n_defocus=1, apod_factor=False, envelope=None, gibson_lanni=False, z_p=1000.0, n_s=1.3, n_g=1.5, n_g0=1.5, t_g=170000.0, t_g0=170000.0, n_i=1.5, n_i0=1.5, t_i0=100000.0)[source]#

Bases: psf_generator.propagators.cartesian_propagator.CartesianPropagator

Propagator for the vectorial case of the Richard’s-Wolf integral in Cartesian parameterization.

In the vectorial model, the far field \(\boldsymbol{e}_{\infty}\) depends on the vectorial incident field \(\boldsymbol{e}_{\textrm{inc}} = [\boldsymbol{e}_{\textrm{inc}}^x, \boldsymbol{e}_{\textrm{inc}}^y, 0]\) as follows:

\[\begin{split}\boldsymbol{e}_{\infty}(\theta,\phi) = \begin{bmatrix} (\cos\theta+1)+(\cos\theta-1)\cos2\phi \\ (\cos\theta-1)\sin2\phi \\ -2 \cos\phi \sin\theta \end{bmatrix} \frac{\boldsymbol{e}_{\textrm{inc}}^x}{2} + \begin{bmatrix} (\cos\theta-1)\sin2\phi \\ (\cos\theta+1)-(\cos\theta-1)\cos2\phi \\ - 2 \sin\phi \sin\theta \end{bmatrix} \frac{\boldsymbol{e}_{\textrm{inc}}^y}{2}.\end{split}\]

The equation to compute the electric field is

\[\mathbf{E}(\boldsymbol{\rho}) = -\frac{\mathrm{i} fk}{2\pi}\iint\limits_{s_x^2+s_y^2 \leq s_{M}^2} \frac{\boldsymbol{e}_{\infty}(s_x, s_y) \mathrm{e}^{\mathrm{i} kz}}{s_z} \mathrm{e}^{\mathrm{i} k(s_x x + s_y y)} ds_x ds_y.\]

Parameters#

self.e0xfloat, optional

Initial electric field component \(\mathbf{e}_0^x\). Default value is 1.0.

self.e0yfloat, optional

Initial electric field component \(\mathbf{e}_0^y\). Default value is 0.0.

Notes#

The vectorial propagators have two additional arguments apart from those inherited form the base propagator to account for polarization.

e0x#
e0y#
classmethod get_name() str[source]#
_get_args() Dict[source]#
initialize_input_field() torch.Tensor[source]#

Compute the corresponding input field.

class psf_generator.propagators.VectorialSphericalPropagator(n_pix_pupil=128, n_pix_psf=128, device='cpu', zernike_coefficients=None, e0x=1.0, e0y=0.0, wavelength=632, na=1.3, pix_size=10, defocus_step=0, n_defocus=1, apod_factor=False, envelope=None, cos_factor=False, gibson_lanni=False, z_p=1000.0, n_s=1.3, n_g=1.5, n_g0=1.5, t_g=170000.0, t_g0=170000.0, n_i=1.5, n_i0=1.5, t_i0=100000.0, integrator=simpsons_rule)[source]#

Bases: psf_generator.propagators.spherical_propagator.SphericalPropagator

Propagator for the vectorial case of the Richard’s-Wolf integral in spherical parameterization.

The equation to compute the electric field is

\[\begin{split}\mathbf{E}(\boldsymbol{\rho}) = - \frac{\mathrm{i} fk}{2} \begin{bmatrix} {2}^y\sin2\varphi\\ - I_{2}^x\sin2\varphi + [I_{0}^y + I_{2}^y\cos2\varphi]\\ -2\mathrm{i} I_{1}^x\cos\varphi - 2\mathrm{i} I_{1}^y\sin\varphi \end{bmatrix},\end{split}\]

where

\[ \begin{align}\begin{aligned}I_{0}^a (\rho,z) = \int_0^{\theta_{\max}} \boldsymbol{e}_{\textrm{inc}^a}(\theta)\sin\theta (\cos\theta+1) J_0(k\rho\sin\theta)\mathrm{e}^{\mathrm{i} kz\cos\theta}d\theta,\\I_{1}^a (\rho,z)= \int_0^{\theta_{\max}} \boldsymbol{e}_{\textrm{inc}^a}(\theta)\sin^2\theta J_1(k\rho\sin\theta)\mathrm{e}^{\mathrm{i} kz\cos\theta}d\theta,\\I_{2}^a (\rho,z) = \int_0^{\theta_{\max}} \boldsymbol{e}_{\textrm{inc}^a}(\theta)\sin\theta (\cos\theta-1) J_2(k\rho\sin\theta)\mathrm{e}^{\mathrm{i} kz\cos\theta}d\theta,\end{aligned}\end{align} \]

where \(a\in\{x,y\}, \boldsymbol{e}_{\textrm{inc}}(\theta) = [\boldsymbol{e}_{\textrm{inc}}^x(\theta), \boldsymbol{e}_{\textrm{inc}}^y(\theta), 0]\).

Parameters#

self.e0xfloat, optional

Initial electric field component \(\mathbf{e}_0^x\). Default value is 1.0.

self.e0yfloat, optional

Initial electric field component \(\mathbf{e}_0^y\). Default value is 0.0.

Notes#

The vectorial propagators have two additional arguments apart from those inherited form the base propagator to account for polarization.

e0x#
e0y#
varphi#
sin_phi#
cos_phi#
sin_twophi#
cos_twophi#
classmethod get_name() str[source]#
_get_args() Dict[source]#
initialize_input_field() torch.Tensor[source]#
compute_focus_field() torch.Tensor[source]#

Compute the focus field.

Returns#

field: torch.Tensor

Output PSF.

Notes#

This involves expensive evaluations of Bessel functions. We compute it independently of defocus and handle defocus via batching with vmap().

_compute_psf_at_defocus(defocus_term: torch.Tensor, J0: torch.Tensor, J1: torch.Tensor, J2: torch.Tensor, pupil: torch.Tensor, sin_t: torch.Tensor, cos_t: torch.Tensor) torch.Tensor[source]#

Compute the PSF at defocus.

Parameters#

defocus_term: torch.Tensor

Factor in the integrand corresponding to defocus.

J0: torch.Tensor

Bessel function of the first kind of order 0 \(J_0\).

J1: torch.Tensor

Bessel function of the first kind of order 1 \(J_1\).

J2: torch.Tensor

Bessel function of the first kind of order 2 \(J_2\).

pupil: torch.Tensor

Pupil function.

sin_t: torch.Tensor

shape: (n_thetas, )

cos_t: torch.Tensor

shape: (n_thetas, )

Returns#

PSF_field: torch.Tensor

Output field.