Skip to content

Commit

Permalink
Docs
Browse files Browse the repository at this point in the history
  • Loading branch information
andykee committed Dec 7, 2023
1 parent 1b271c0 commit 943d7b3
Show file tree
Hide file tree
Showing 13 changed files with 245 additions and 212 deletions.
12 changes: 12 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,18 @@

autosummary_generate = True

rst_prolog = """
.. currentmodule:: lentil
.. |Pupil| replace:: :class:`Pupil`
.. |Image| replace:: :class:`Image`
.. |Detector| replace:: :class:`Detector`
.. |Plane| replace:: :class:`Plane`
.. |Wavefront| replace:: :class:`Wavefront`
.. |Tilt| replace:: :class:`Tilt`
"""

# -- Plot config -------------------------------------------------------------
dpi = 144

Expand Down
7 changes: 7 additions & 0 deletions docs/ref/internals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
Internals
*********

Plane type
----------
.. autosummary::
:toctree: generated/

lentil.ptype.ptype

Field
-----
.. autosummary::
Expand Down
115 changes: 115 additions & 0 deletions docs/user/advanced/extend.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,118 @@
****************
Extending Lentil
****************

Customizing Plane
=================
The Plane class or any of the classes derived from Plane can be subclassed to modify
any of the default behavior. Reasons to do this may include but are not limited to:

* Dynamically computing the :attr:`~lentil.Plane.opd` attribute
* Changing the Plane-Wavefront interaction by redefining the `Plane.multiply()` method
* Modifying the way a Plane is resampled or rescaled

Some general guidance for how to safely subclass Plane is provided below.

.. note::

Lentil's |Plane| class and its subclasses all use Python's ``__init_subclass__()``
method to ensure any required default values are set - even if a user-defined
subclass does not explicitly call ``Plane``'s constructor ``__init__()`` method. For
this reason, it is not strictly necessary to call ``super().__init__()`` when
implementing a custom Plane subclass. It also won't hurt, as long as you're careful
to either call ``super().__init__()`` before defining any static plane attributes or
passing these attributes along to the ``super().__init__()`` call to ensure they are
properly set.

Redefining the amplitude, OPD, or mask attributes
---------------------------------------------------
Plane :attr:`~lentil.Plane.amplitude`, :attr:`~lentil.Plane.opd`, and
:attr:`~lentil.Plane.mask` are all defined as properties, but Python allows you to
redefine them as class attributes without issue:

.. code-block:: python3
import lentil
class CustomPlane(le.Plane):
def __init__(self):
self.amplitude = lentil.circle((256,256), 128)
self.opd = lentil.zernike(lentil.circlemask((256,256),128), 4)
If more dynamic behavior is required, the property can be redefined. For example, to
return a new random OPD each time the :attr:`~lentil.Plane.opd` attribute is
accessed:

.. code-block:: python3
import numpy as np
import lentil
class CustomPlane(lentil.Plane):
def __init__(self):
self.mask = lentil.circlemask((256,256), 128)
self.amplitude = lentil.circle((256,256), 128)
@property
def phaopdse(self):
return lentil.zernike_compose(self.mask, np.random.random(10))
It is also straightforward to implement a custom :attr:`~lentil.Plane.opd` property to
provide a stateful OPD attribute:

.. code-block:: python3
import numpy as np
import lentil
class CustomPlane(lentil.Plane):
def __init__(self, x=np.zeros(10)):
self.mask = lentil.circlemask((256,256), 128)
self.amplitude = lentil.circle((256,256), 128)
self.x = x
@property
def opd(self):
return lentil.zernike_compose(self.mask, self.x)
.. note::

Polychromatic or broadband diffraction propagations access the OPD, amplitude,
and mask attributes for each propagatioon wavelength. Because these attributes
remain fixed during a propagation, it is inefficient to repeatedly recompute
them. To mitigate this, it can be very useful to provide a mechanism for freezing
these dynamic attributes. There are many ways to do this. One approach is provided
below:

.. code-block:: python3
import copy
import numpy as np
import lentil
class CustomPlane(lentil.Plane):
def __init__(self):
self.mask = lentil.circlemask((256,256), 128)
self.amplitude = lentil.circle((256,256), 128)
@property
def opd(self):
return lentil.zernike_compose(self.mask, np.random.random(10))
def freeze(self):
# Return a copy of CustomPlane with the OPD attribute redefined
# to be a static copy of the OPD when freeze() is called
out = copy.deepcopy(self)
out.opd = self.opd.copy()
return out
Customizing Plane methods
-------------------------
Any of the |Plane| methods can be redefined in a subclass without restriction. Care
should be taken to ensure any redefined methods return data compatible with the
parent method's return type to preserve compatibility within Lentil.


Implementing the _Tilt interface
--------------------------------
3 changes: 0 additions & 3 deletions docs/user/fundamentals/coordinates.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
Coordinate system
*****************

.. |Pupil| replace:: :class:`~lentil.Pupil`
.. |Image| replace:: :class:`~lentil.Image`

Lentil adopts the widely used convention of aligning the z-axis along the direction
of light propagation through an optical system. For a right-handed coordinate system,
it follows that the remaining axes are oriented as shown in the figure below:
Expand Down
32 changes: 13 additions & 19 deletions docs/user/fundamentals/diffraction.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
.. _user.fundamentals.diffraction:

.. |Wavefront| replace:: :class:`~lentil.Wavefront`
.. |Plane| replace:: :class:`~lentil.Plane`
.. |Pupil| replace:: :class:`~lentil.Pupil`
.. |Image| replace:: :class:`~lentil.Image`
.. |Detector| replace:: :class:`~lentil.Detector`

*********************************
Numerical diffraction propagation
*********************************
Expand Down Expand Up @@ -84,7 +78,7 @@ follows the same basic flow:
.. note::

Additional details on the plane-wavefront interaction can be found in
:ref:`user.optical_systems.plane_wavefront`.
:ref:`user.fundamentals.plane_wavefront`.

3. **Propagate the wavefront to the next plane in the optical system** - the |Wavefront|
object provides a number of methods to propagate between planes. The appropriate method
Expand Down Expand Up @@ -267,21 +261,21 @@ Sampling considerations

Working with large tilts
========================
.. .. image:: /_static/img/propagate_tilt_phase.png
.. :width: 450px
.. :align: center
.. image:: /_static/img/propagate_tilt_phase.png
:width: 450px
:align: center

.. .. image:: /_static/img/propagate_tilt_phase_wrap.png
.. :width: 650px
.. :align: center
.. image:: /_static/img/propagate_tilt_phase_wrap.png
:width: 650px
:align: center

.. .. image:: /_static/img/propagate_tilt_angle.png
.. :width: 600px
.. :align: center
.. image:: /_static/img/propagate_tilt_angle.png
:width: 600px
:align: center

.. .. image:: /_static/img/propagate_tilt_angle_steps.png
.. :width: 600px
.. :align: center
.. image:: /_static/img/propagate_tilt_angle_steps.png
:width: 600px
:align: center

.. _user.diffraction.segmented:

Expand Down
Loading

0 comments on commit 943d7b3

Please sign in to comment.