# Describing optical systems¶

It is common in physical optics modeling to represent an optical system in its “unfolded” state where all optical elements are arranged along a straight line (the optical axis). This approach assumes the following:

The beam is paraxial

Powered mirrors are represented as equivalent ideal thin lenses

The beam does not change dimensions across a lens

A lens has no thickness so all phase changes occur in a plane

Lentil uses `Plane`

objects to represent discretely sampled planes in an optical system
and `Wavefront`

objects to represent discretely sampled electromagnetic fields as they
propagate through an optical system.

## How a plane affects a wavefront¶

An optical plane generally has some effect on a wavefront as it propagates
through the plane. A plane may change a propagating wavefront’s amplitude, phase,
and/or physical extent. This `Plane`

-`Wavefront`

interaction is performed by the
plane’s `multiply()`

method. A `Plane`

and `Wavefront`

can be
multiplied in two ways:

By calling

`Plane.multiply()`

directly:>>> w1 = plane.multiply(w0)

By using the built-in multiplication operator (which in turn calls

`Plane.multiply()`

):>>> w1 = plane * w0

The `multiply()`

method constructs a complex phasor from the plane’s
`amplitude`

and `phase`

attributes and the
`Wavefront`

wavelength. The plane complex phasor is then multiplied element-wise with
the wavefront’s complex data array:

The plane’s `multiply()`

method also accepts an `inplace`

argument
that governs whether the multiplication operation is performed on the wavefront in-place
or using a copy:

```
>>> w1 = plane.multiply(w0, inplace=True)
>>> w1 is w0
True
```

The in-place multiplication operator can also be used:

```
>>> w *= plane
```

## Planes in a simple optical system¶

Most optical systems can be adequately modeled by a single far-field propagation
between a Pupil and image plane. This includes most cameras,
telescopes, and imaging instruments. In these models, all of the optics in a system are
represented by a single `Pupil`

plane:

```
>>> import matplotlib.pyplot as plt
>>> import lentil
>>> amplitude = lentil.circle(shape=(256, 256), radius=120)
>>> opd = lentil.zernike_compose(mask=amplitude,
... coeffs=[0, 0, 0, 100e-9, 300e-9, 0, -100e-9])
>>> pupil = lentil.Pupil(amplitude=amplitude, phase=opd, focal_length=10,
... pixelscale=1/240)
>>> plt.imshow(pupil.phase, origin='lower')
```

## Segmented optical systems¶

Creating a model of a segmented aperture optical system in Lentil doesn’t require any
special treatment. The `Plane`

and `Pupil`

objects work the same with sparse or
segmented amplitude, phase, and mask attributes as with monolithic ones.

That being said, it is advantageous from a performance point of view to supply a
3-dimensional segment mask when specifying a Plane’s `mask`

attribute rather than a flattened 2-dimensional global mask when working
with a segmented aperture, as depicted below:

This modification is not necessary to achieve accurate propagations, but can greatly improve performance. For additional details, see user_guide.diffraction.segmented.

## More complicated optical systems¶

More complicated imaging systems may contain multiple pupil and image planes. This
includes systems like spectrometers and coronagraphs. With these systems, the
`Pupil`

, `Image`

, and `Detector`

planes are
still used but much more care needs to be taken to ensure each plane is adequately
sampled to avoid the introduction of numerical artifacts in the diffraction propagation.

If access to an intermediate (non-pupil or image) plane is required or if an imaging system is not operating near focus, the near-field (Fresnel) propagation methods should be used instead.