Point Spread Functions
To implement your own subtype of a PointSpreadFunction you need to decide if the type you want to implement is a model (PSFModel) or something else.
TransferFunctions.PSFModel — TypePSFModel <: PointSpreadFunctionPointSpreadFunction subtype for PSF models. A PSF model is a PointSpreadFunction that has parameters accessible through params and can be fitted to data.
If there is some symmetry in the PSF, you should implement the TransferFunctions.symmetry method which may lead to optimization of the methods that are defined on the abstract types.
TransferFunctions.symmetry — Functionsymmtery(psf::PointSpreadFunction)Marks the symmetries of a PointSpreadFunction.
There are two types of symmetries as of now
TransferFunctions.PointSpreadFunctionSymmetry — TypePointSpreadFunctionSymmetryA marker type that indicates the symmetries of a PointSpreadFunction which may lead to optimized methods.
Subtypes thus far include ZAxisRadialSymmetry and NoSymmetry.
TransferFunctions.NoSymmetry — TypeNoSymmetry <: PointSpreadFunctionSymmetryNoSymmetry marks a PointSpreadFunction that is not symmetric in any way. You need to compute every $x$, $y$, $z$ coordinate separately.
TransferFunctions.ZAxisRadialSymmetry — TypeZAxisRadialSymmetry <: PointSpreadFunctionSymmetry$z$ axis radial symmetry of a PointSpreadFunction indicates that the PSF is symmetric in the radially around the z-axis.
Next you have to implement the TransferFunctions.intensity method for the correct arguments which you have to determine from the type of TransferFunctions.PointSpreadFunctionSymmetry that is used for the type of PSF that you want to implement.
TransferFunctions.intensity — Functionintensity(psf::PointSpreadFunction, r::Length...)The intensity of the PointSpreadFunction at the given coordinates.
For different PointSpreadFunctionSymmetry of the psf, it has to be defined for different arguments.
symmetry(psf) == ZAxisRadialSymmetry() && psf isa PointSpreadFunction{2}then a single argument version must be defined
intensity(psf, r::Length) = # ...symmetry(psf) == ZAxisRadialSymmetry() && psf isa PointSpreadFunction{3}then a two argument version must be defined
intensity(psf, r::Length, z::Length) = # ...symmetry(psf) == NoSymmetry() && psf isa PointSpreadFunction{2}then a two argument version must be defined
intensity(psf, x::Length, y::Length) = # ...symmetry(psf) == NoSymmetry() && psf isa PointSpreadFunction{3}then a three argument version must be defined
intensity(psf, x::Length, y::Length, z::Length) = # ...intensity(psf::AiryDisc, r::Length)Compute the intensity of the AiryDisc PSF at a distance r from its center.
Intensity of the Airy disc is given by $h(r) = (2J₁(αr)/(αr))²$ where $α = 2πNA/λ$ and $J₁$ is the first order Bessel function of the first kind.
intensity(tf::AiryDisc{3}, r::Length, z::Length)Compute the intensity of the AiryDisc PSF at a distance r from its center and $z$-offset z.
It is defined as the product of the lateral intensity and the axial intensity.
For a subtype that has parameters that may be optimized to fit the PSF to data, you should implement the TransferFunctions.params method
TransferFunctions.params — Functionparams(psf::PSFModel)Get the parameters of the PSF model psf as a ComponentVector.
This is useful for fitting the model to data.