Extending Lentil#
Subclassing existing planes#
Lentil planes are designed to be subclassed, allowing users to easily modify default behavior. A number of special methods are provided for easy operator overloading:
Customizing plane attributes#
The following methods can be defined to create dynamic plane attributes. These are commonly used when a plane attribute is stateful and needs to be recomputed at the time of attribute access.
- object.__amp__(self)#
Called when the plane’s
amplitudeattribute is accessed. The__amp__()method should return a Numpy array.
- object.__mask__(self)#
Called when the plane’s
maskattribute is accessed. The__mask__()method should return a Numpy array.
- object.__opd__(self)#
Called when the plane’s
opdattribute is accessed. The__opd__()method should return a Numpy array.
Below is a simple example implementing a tip/tilt mirror where the plane’s
opd attribute depends on the state of the x attribute. The logic for
computing the opd attribute is defined by the __opd__() method:
class TipTiltMirror(lentil.Plane):
def __init__(self):
amplitude = lentil.circle((256,256),120)
self.x = np.zeros(2)
self._tt_basis = lentil.zernike_basis(amplitude, modes=[2,3])
super().__init__(amplitude=amplitude)
def __opd__(self):
return np.einsum('ijk,i->jk', self._tt_basis, self.x)
>>> tt = TipTiltMirror()
>>> tt.x = [1e-6, 3e-6]
>>> plt.imshow(tt.opd, cmap='RdBu_r')
>>> plt.colorbar()
Note
Numerical diffraction propagation calculations can repeatedly access
the opd, amplitude, and mask attributes. Because these attributes
remain fixed during a propagation, it is inefficient to recalculate
them each time the attribute is accessed. To mitigate this, the plane’s
freeze() method can be used to temporarily cache these attributes.
For more information, see Freezing planes with computationally expensive attribute access
Customizing how a plane interacts with a wavefront#
- object.__mul__(self, wavefront)#
Called when a plane is multiplied with a wavefront.