Skip to content

Optical Layers

TransmissiveLayer

Bases: OpticalLayer

Base class to hold transmissive layers imbuing them with a transmission and normalise parameter.

UML

UML

Attributes:

Name Type Description
transmission Array

The Array of transmission values to be applied to the input wavefront.

normalise bool

Whether to normalise the wavefront after passing through the optic.

Source code in src/dLux/layers/optical_layers.py
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
class TransmissiveLayer(OpticalLayer):
    """
    Base class to hold transmissive layers imbuing them with a transmission and
    normalise parameter.

    ??? abstract "UML"
        ![UML](../../assets/uml/TransmissiveLayer.png)

    Attributes
    ----------
    transmission: Array
        The Array of transmission values to be applied to the input wavefront.
    normalise: bool
        Whether to normalise the wavefront after passing through the optic.
    """

    transmission: Array
    normalise: bool

    def __init__(
        self: OpticalLayer,
        transmission: Array = None,
        normalise: bool = False,
        **kwargs,
    ):
        """
        Parameters
        ----------
        transmission: Array = None
            The array of transmission values to be applied to the input wavefront.
        normalise : bool = False
            Whether to normalise the wavefront after passing through the optic.
        """
        if transmission is not None:
            transmission = np.asarray(transmission, dtype=float)
        self.transmission = transmission
        self.normalise = bool(normalise)
        super().__init__(**kwargs)

    def apply(self: OpticalLayer, wavefront: Wavefront) -> Wavefront:
        """
        Applies the layer to the wavefront.

        Parameters
        ----------
        wavefront : Wavefront
            The wavefront to operate on.

        Returns
        -------
        wavefront : Wavefront
            The transformed wavefront.
        """
        wavefront *= self.transmission
        if self.normalise:
            wavefront = wavefront.normalise()
        return wavefront

__init__(transmission=None, normalise=False, **kwargs)

Parameters:

Name Type Description Default
transmission Array

The array of transmission values to be applied to the input wavefront.

None
normalise bool = False

Whether to normalise the wavefront after passing through the optic.

False
Source code in src/dLux/layers/optical_layers.py
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
def __init__(
    self: OpticalLayer,
    transmission: Array = None,
    normalise: bool = False,
    **kwargs,
):
    """
    Parameters
    ----------
    transmission: Array = None
        The array of transmission values to be applied to the input wavefront.
    normalise : bool = False
        Whether to normalise the wavefront after passing through the optic.
    """
    if transmission is not None:
        transmission = np.asarray(transmission, dtype=float)
    self.transmission = transmission
    self.normalise = bool(normalise)
    super().__init__(**kwargs)

apply(wavefront)

Applies the layer to the wavefront.

Parameters:

Name Type Description Default
wavefront Wavefront

The wavefront to operate on.

required

Returns:

Name Type Description
wavefront Wavefront

The transformed wavefront.

Source code in src/dLux/layers/optical_layers.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
def apply(self: OpticalLayer, wavefront: Wavefront) -> Wavefront:
    """
    Applies the layer to the wavefront.

    Parameters
    ----------
    wavefront : Wavefront
        The wavefront to operate on.

    Returns
    -------
    wavefront : Wavefront
        The transformed wavefront.
    """
    wavefront *= self.transmission
    if self.normalise:
        wavefront = wavefront.normalise()
    return wavefront

AberratedLayer

Bases: OpticalLayer

Optical layer for holding static aberrations. Aberrations can be applied as either a phase or OPD, or both.

UML

UML

Attributes:

Name Type Description
opd (Array, metres)

The Array of OPD values to be applied to the input wavefront.

phase (Array, radians)

The Array of phase values to be applied to the input wavefront.

Source code in src/dLux/layers/optical_layers.py
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
class AberratedLayer(OpticalLayer):
    """
    Optical layer for holding static aberrations. Aberrations can be applied as either
    a phase or OPD, or both.

    ??? abstract "UML"
        ![UML](../../assets/uml/AberratedLayer.png)

    Attributes
    ----------
    opd : Array, metres
        The Array of OPD values to be applied to the input wavefront.
    phase : Array, radians
        The Array of phase values to be applied to the input wavefront.
    """

    opd: Array
    phase: Array

    def __init__(
        self: OpticalLayer,
        opd: Array = None,
        phase: Array = None,
        **kwargs,
    ):
        """
        Parameters
        ----------
        opd : Array, metres = None
            The Array of OPD values to be applied to the input wavefront.
        phase : Array, radians = None
            The Array of phase values to be applied to the input wavefront.
        """
        if opd is not None:
            opd = np.asarray(opd, dtype=float)
        self.opd = opd

        if phase is not None:
            phase = np.asarray(phase, dtype=float)
        self.phase = phase

        if self.opd is not None and self.phase is not None:
            if self.opd.shape != self.phase.shape:
                raise ValueError(
                    "opd and phase must have the same shape. Got "
                    f"shapes {self.opd.shape} and {self.phase.shape}."
                )
        super().__init__(**kwargs)

    def apply(self: OpticalLayer, wavefront: Wavefront) -> Wavefront:
        """
        Applies the layer to the wavefront.

        Parameters
        ----------
        wavefront : Wavefront
            The wavefront to operate on.

        Returns
        -------
        wavefront : Wavefront
            The transformed wavefront.
        """
        wavefront += self.opd
        wavefront = wavefront.add_phase(self.phase)
        return wavefront

__init__(opd=None, phase=None, **kwargs)

Parameters:

Name Type Description Default
opd Array, metres = None

The Array of OPD values to be applied to the input wavefront.

None
phase Array, radians = None

The Array of phase values to be applied to the input wavefront.

None
Source code in src/dLux/layers/optical_layers.py
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
def __init__(
    self: OpticalLayer,
    opd: Array = None,
    phase: Array = None,
    **kwargs,
):
    """
    Parameters
    ----------
    opd : Array, metres = None
        The Array of OPD values to be applied to the input wavefront.
    phase : Array, radians = None
        The Array of phase values to be applied to the input wavefront.
    """
    if opd is not None:
        opd = np.asarray(opd, dtype=float)
    self.opd = opd

    if phase is not None:
        phase = np.asarray(phase, dtype=float)
    self.phase = phase

    if self.opd is not None and self.phase is not None:
        if self.opd.shape != self.phase.shape:
            raise ValueError(
                "opd and phase must have the same shape. Got "
                f"shapes {self.opd.shape} and {self.phase.shape}."
            )
    super().__init__(**kwargs)

apply(wavefront)

Applies the layer to the wavefront.

Parameters:

Name Type Description Default
wavefront Wavefront

The wavefront to operate on.

required

Returns:

Name Type Description
wavefront Wavefront

The transformed wavefront.

Source code in src/dLux/layers/optical_layers.py
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
def apply(self: OpticalLayer, wavefront: Wavefront) -> Wavefront:
    """
    Applies the layer to the wavefront.

    Parameters
    ----------
    wavefront : Wavefront
        The wavefront to operate on.

    Returns
    -------
    wavefront : Wavefront
        The transformed wavefront.
    """
    wavefront += self.opd
    wavefront = wavefront.add_phase(self.phase)
    return wavefront

BasisLayer

Bases: OpticalLayer

An OpticalLayer class that holds a set of basis vectors and coefficients, which are dot-producted at run time to produce the output. The basis can be applied as either a phase or OPD, by setting the as_phase attribute.

UML

UML

Attributes:

Name Type Description
basis Union[Array, list]

The set of basis vectors. Should in generate be a 3 dimensional array.

coefficients Array

The array of coefficients to be applied to each basis vector.

as_phase bool = False

Whether to apply the basis as a phase or OPD. If True the output is applied as a phase, else it is applied as an OPD.

Source code in src/dLux/layers/optical_layers.py
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
class BasisLayer(OpticalLayer):
    """
    An OpticalLayer class that holds a set of basis vectors and coefficients, which are
    dot-producted at run time to produce the output. The basis can be applied as either
    a phase or OPD, by setting the `as_phase` attribute.

    ??? abstract "UML"
        ![UML](../../assets/uml/BasisLayer.png)

    Attributes
    ----------
    basis: Union[Array, list]
        The set of basis vectors. Should in generate be a 3 dimensional array.
    coefficients: Array
        The array of coefficients to be applied to each basis vector.
    as_phase: bool = False
        Whether to apply the basis as a phase or OPD. If True the output is applied as
        a phase, else it is applied as an OPD.
    """

    basis: Union[Array, list]
    coefficients: Array
    as_phase: bool

    # NOTE: We need the None basis input for aberrated apertures
    def __init__(
        self: OpticalLayer,
        basis: Array = None,
        coefficients: Array = None,
        as_phase: bool = False,
        **kwargs,
    ):
        """
        Parameters
        ----------
        basis: Union[Array, list]
            The set of basis vectors. Should in generate be a 3 dimensional array.
        coefficients: Array
            The Array of coefficients to be applied to each basis vector.
        as_phase: bool = False
            Whether to apply the basis as a phase or OPD. If True the output is applied
            as a phase, else it is applied as an OPD.
        """
        super().__init__(**kwargs)

        if basis is not None:
            basis = np.asarray(basis, dtype=float)
            if coefficients is None:
                coefficients = np.zeros(basis.shape[:-2])
            else:
                coefficients = np.asarray(coefficients, dtype=float)
                if basis.shape[:-2] != coefficients.shape:
                    raise ValueError(
                        "The number of basis vectors must be equal to "
                        "the number of coefficients."
                    )

        self.basis = basis
        self.coefficients = coefficients
        self.as_phase = bool(as_phase)

    def eval_basis(self: OpticalLayer) -> Array:
        """
        Calculates the dot product of the basis vectors and coefficients.

        Returns
        -------
        output : Array
            The output of the dot product between the basis vectors and coefficients.
        """
        return dlu.eval_basis(self.basis, self.coefficients)

    def apply(self: OpticalLayer, wavefront: Wavefront) -> Wavefront:
        """
        Applies the layer to the wavefront.

        Parameters
        ----------
        wavefront : Wavefront
            The wavefront to operate on.

        Returns
        -------
        wavefront : Wavefront
            The transformed wavefront.
        """
        output = self.eval_basis()
        if self.as_phase:
            wavefront = wavefront.add_phase(output)
        else:
            wavefront += output
        return wavefront

__init__(basis=None, coefficients=None, as_phase=False, **kwargs)

Parameters:

Name Type Description Default
basis Array

The set of basis vectors. Should in generate be a 3 dimensional array.

None
coefficients Array

The Array of coefficients to be applied to each basis vector.

None
as_phase bool

Whether to apply the basis as a phase or OPD. If True the output is applied as a phase, else it is applied as an OPD.

False
Source code in src/dLux/layers/optical_layers.py
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
def __init__(
    self: OpticalLayer,
    basis: Array = None,
    coefficients: Array = None,
    as_phase: bool = False,
    **kwargs,
):
    """
    Parameters
    ----------
    basis: Union[Array, list]
        The set of basis vectors. Should in generate be a 3 dimensional array.
    coefficients: Array
        The Array of coefficients to be applied to each basis vector.
    as_phase: bool = False
        Whether to apply the basis as a phase or OPD. If True the output is applied
        as a phase, else it is applied as an OPD.
    """
    super().__init__(**kwargs)

    if basis is not None:
        basis = np.asarray(basis, dtype=float)
        if coefficients is None:
            coefficients = np.zeros(basis.shape[:-2])
        else:
            coefficients = np.asarray(coefficients, dtype=float)
            if basis.shape[:-2] != coefficients.shape:
                raise ValueError(
                    "The number of basis vectors must be equal to "
                    "the number of coefficients."
                )

    self.basis = basis
    self.coefficients = coefficients
    self.as_phase = bool(as_phase)

apply(wavefront)

Applies the layer to the wavefront.

Parameters:

Name Type Description Default
wavefront Wavefront

The wavefront to operate on.

required

Returns:

Name Type Description
wavefront Wavefront

The transformed wavefront.

Source code in src/dLux/layers/optical_layers.py
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
def apply(self: OpticalLayer, wavefront: Wavefront) -> Wavefront:
    """
    Applies the layer to the wavefront.

    Parameters
    ----------
    wavefront : Wavefront
        The wavefront to operate on.

    Returns
    -------
    wavefront : Wavefront
        The transformed wavefront.
    """
    output = self.eval_basis()
    if self.as_phase:
        wavefront = wavefront.add_phase(output)
    else:
        wavefront += output
    return wavefront

eval_basis()

Calculates the dot product of the basis vectors and coefficients.

Returns:

Name Type Description
output Array

The output of the dot product between the basis vectors and coefficients.

Source code in src/dLux/layers/optical_layers.py
240
241
242
243
244
245
246
247
248
249
def eval_basis(self: OpticalLayer) -> Array:
    """
    Calculates the dot product of the basis vectors and coefficients.

    Returns
    -------
    output : Array
        The output of the dot product between the basis vectors and coefficients.
    """
    return dlu.eval_basis(self.basis, self.coefficients)

Tilt

Bases: OpticalLayer

Tilts the wavefront by the input (x, y) angles.

UML

UML

Attributes:

Name Type Description
angles (Array, radians)

The (x, y) angles by which to tilt the wavefront.

Source code in src/dLux/layers/optical_layers.py
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
class Tilt(OpticalLayer):
    """
    Tilts the wavefront by the input (x, y) angles.

    ??? abstract "UML"
        ![UML](../../assets/uml/Tilt.png)

    Attributes
    ----------
    angles : Array, radians
        The (x, y) angles by which to tilt the wavefront.
    """

    angles: Array

    def __init__(self: OpticalLayer, angles: Array):
        """
        Parameters
        ----------
        angles : Array, radians
            The (x, y) angles by which to tilt the wavefront.
        """
        super().__init__()
        self.angles = np.asarray(angles, dtype=float)

        if self.angles.shape != (2,):
            raise ValueError("angles must have have (2,)")

    def apply(self: OpticalLayer, wavefront: Wavefront) -> Wavefront:
        """
        Applies the layer to the wavefront.

        Parameters
        ----------
        wavefront : Wavefront
            The wavefront to operate on.

        Returns
        -------
        wavefront : Wavefront
            The transformed wavefront.
        """
        return wavefront.tilt(self.angles)

__init__(angles)

Parameters:

Name Type Description Default
angles (Array, radians)

The (x, y) angles by which to tilt the wavefront.

required
Source code in src/dLux/layers/optical_layers.py
288
289
290
291
292
293
294
295
296
297
298
299
def __init__(self: OpticalLayer, angles: Array):
    """
    Parameters
    ----------
    angles : Array, radians
        The (x, y) angles by which to tilt the wavefront.
    """
    super().__init__()
    self.angles = np.asarray(angles, dtype=float)

    if self.angles.shape != (2,):
        raise ValueError("angles must have have (2,)")

apply(wavefront)

Applies the layer to the wavefront.

Parameters:

Name Type Description Default
wavefront Wavefront

The wavefront to operate on.

required

Returns:

Name Type Description
wavefront Wavefront

The transformed wavefront.

Source code in src/dLux/layers/optical_layers.py
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
def apply(self: OpticalLayer, wavefront: Wavefront) -> Wavefront:
    """
    Applies the layer to the wavefront.

    Parameters
    ----------
    wavefront : Wavefront
        The wavefront to operate on.

    Returns
    -------
    wavefront : Wavefront
        The transformed wavefront.
    """
    return wavefront.tilt(self.angles)

Normalise

Bases: OpticalLayer

Normalises the wavefront to unit intensity.

UML

UML

Source code in src/dLux/layers/optical_layers.py
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
class Normalise(OpticalLayer):
    """
    Normalises the wavefront to unit intensity.

    ??? abstract "UML"
        ![UML](../../assets/uml/Normalise.png)
    """

    def apply(self: OpticalLayer, wavefront: Wavefront) -> Wavefront:
        """
        Applies the layer to the wavefront.

        Parameters
        ----------
        wavefront : Wavefront
            The wavefront to operate on.

        Returns
        -------
        wavefront : Wavefront
            The transformed wavefront.
        """
        return wavefront.normalise()

apply(wavefront)

Applies the layer to the wavefront.

Parameters:

Name Type Description Default
wavefront Wavefront

The wavefront to operate on.

required

Returns:

Name Type Description
wavefront Wavefront

The transformed wavefront.

Source code in src/dLux/layers/optical_layers.py
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
def apply(self: OpticalLayer, wavefront: Wavefront) -> Wavefront:
    """
    Applies the layer to the wavefront.

    Parameters
    ----------
    wavefront : Wavefront
        The wavefront to operate on.

    Returns
    -------
    wavefront : Wavefront
        The transformed wavefront.
    """
    return wavefront.normalise()