Skip to content

Zernike Polynomials

This module contains the code required to generate Zernike polynomials.

zernike_name

Gets the name of the jth Zernike polynomial.

Parameters:

Name Type Description Default
j int

The Zernike (noll) index.

required

Returns:

Name Type Description
name str

The name of the Zernike polynomial.

Source code in src/dLux/utils/zernikes.py
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
def zernike_name(j: int) -> str:
    """
    Gets the name of the jth Zernike polynomial.

    Parameters
    ----------
    j : int
        The Zernike (noll) index.

    Returns
    -------
    name : str
        The name of the Zernike polynomial.
    """
    return zernike_names[int(j)] if j >= 1 and j <= 36 else f"Zernike {int(j)}"

noll_indices

Calculate the radial and azimuthal orders of the Zernike polynomial.

Parameters:

Name Type Description Default
j int

The Zernike (noll) index.

required

Returns:

Type Description
n, m : tuple[int]

The radial and azimuthal orders of the Zernike polynomial.

Source code in src/dLux/utils/zernikes.py
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
def noll_indices(j: int) -> tuple[int]:
    """
    Calculate the radial and azimuthal orders of the Zernike polynomial.

    Parameters
    ----------
    j : int
        The Zernike (noll) index.

    Returns
    -------
    n, m : tuple[int]
        The radial and azimuthal orders of the Zernike polynomial.
    """
    n = (np.ceil(-1 / 2 + np.sqrt(1 + 8 * j) / 2) - 1).astype(int)
    smallest_j_in_row = n * (n + 1) / 2 + 1
    number_of_shifts = (j - smallest_j_in_row + ~(n & 1) + 2) // 2
    sign_of_shift = -(j & 1) + ~(j & 1) + 2
    base_case = n & 1
    m = (sign_of_shift * (base_case + number_of_shifts * 2)).astype(int)
    return int(n), int(m)

zernike_factors

Calculates the normalisation coefficients and powers of the Zernike polynomial.

Parameters:

Name Type Description Default
j int

The Zernike (noll) index.

required

Returns:

Type Description
c, k : tuple[Array]

The normalisation coefficients and powers of the Zernike polynomial.

Source code in src/dLux/utils/zernikes.py
108
109
110
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
def zernike_factors(j: int) -> tuple[Array]:
    """
    Calculates the normalisation coefficients and powers of the Zernike polynomial.

    Parameters
    ----------
    j : int
        The Zernike (noll) index.

    Returns
    -------
    c, k : tuple[Array]
        The normalisation coefficients and powers of the Zernike polynomial.
    """
    if j < 1:
        raise ValueError("The Zernike index must be greater than 0.")
    n, m = noll_indices(j)

    # Calculate k
    k = np.arange(((n - m) // 2) + 1, dtype=float)

    # Calculate c
    sign = lax.pow(-1.0, k)
    _fact_1 = dlu.factorial(np.abs(n - k))
    _fact_2 = dlu.factorial(k)
    _fact_3 = dlu.factorial(((n + m) // 2) - k)
    _fact_4 = dlu.factorial(((n - m) // 2) - k)
    c = sign * _fact_1 / _fact_2 / _fact_3 / _fact_4
    return c, k

zernike

Calculates the Zernike polynomial. Note that this function is not-jittable as is has dynamic array shapes. To use this function in a jittable way, use the zernike_fast function, with the pre-calculated c and k parameters.

Parameters:

Name Type Description Default
j int

The Zernike (noll) index.

required
coordinates Array

The Cartesian coordinates to calculate the Zernike polynomial upon.

required
diameter float = 2

The diameter of the aperture to calculate the Zernike polynomial upon.

2

Returns:

Name Type Description
zernike Array

The Zernike polynomial.

Source code in src/dLux/utils/zernikes.py
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 zernike(j: int, coordinates: Array, diameter: float = 2) -> Array:
    """
    Calculates the Zernike polynomial. Note that this function is not-jittable as is
    has dynamic array shapes. To use this function in a jittable way, use the
    zernike_fast function, with the pre-calculated c and k parameters.

    Parameters
    ----------
    j : int
        The Zernike (noll) index.
    coordinates : Array
        The Cartesian coordinates to calculate the Zernike polynomial upon.
    diameter : float = 2
        The diameter of the aperture to calculate the Zernike polynomial upon.

    Returns
    -------
    zernike : Array
        The Zernike polynomial.
    """
    coordinates = scale_coords(coordinates, diameter / 2)
    polar_coordinates = dlu.cart2polar(coordinates)
    rho = polar_coordinates[0]
    theta = polar_coordinates[1]
    aperture = rho <= 1.0
    n, m = noll_indices(j)
    c, k = zernike_factors(j)
    return aperture * eval_radial(rho, n, c, k) * eval_azimuthal(theta, n, m)

zernike_fast

Calculates the Zernike polynomial using the pre-calculated c and k parameters, such that this function is jittable.

Parameters:

Name Type Description Default
n int

The radial order of the Zernike polynomial.

required
m int

The azimuthal order of the Zernike polynomial.

required
c Array

The normalisation coefficients of the Zernike polynomial.

required
k Array

The powers of the Zernike polynomial.

required
coordinates Array

The Cartesian coordinates to calculate the Zernike polynomial upon.

required

Returns:

Name Type Description
zernike Array

The Zernike polynomial.

Source code in src/dLux/utils/zernikes.py
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
def zernike_fast(
    n: int, m: int, c: Array, k: Array, coordinates: Array
) -> Array:
    """
    Calculates the Zernike polynomial using the pre-calculated c and k parameters, such
    that this function is jittable.

    Parameters
    ----------
    n : int
        The radial order of the Zernike polynomial.
    m : int
        The azimuthal order of the Zernike polynomial.
    c : Array
        The normalisation coefficients of the Zernike polynomial.
    k : Array
        The powers of the Zernike polynomial.
    coordinates : Array
        The Cartesian coordinates to calculate the Zernike polynomial upon.

    Returns
    -------
    zernike : Array
        The Zernike polynomial.
    """
    polar_coordinates = dlu.cart2polar(coordinates)
    rho = polar_coordinates[0]
    theta = polar_coordinates[1]
    aperture = rho <= 1.0
    return aperture * eval_radial(rho, n, c, k) * eval_azimuthal(theta, n, m)

zernike_basis

Calculates the Zernike polynomial basis. Note that this function is not-jittable.

Parameters:

Name Type Description Default
js list[int]

The Zernike (noll) indices.

required
coordinates Array

The Cartesian coordinates to calculate the Zernike polynomial upon.

required
diameter float = 2

The diameter of the aperture to calculate the Zernike polynomial upon.

2

Returns:

Name Type Description
zernike_basis Array

The Zernike polynomial basis.

Source code in src/dLux/utils/zernikes.py
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
def zernike_basis(
    js: list[int], coordinates: Array, diameter: float = 2
) -> Array:
    """
    Calculates the Zernike polynomial basis. Note that this function is not-jittable.

    Parameters
    ----------
    js : list[int]
        The Zernike (noll) indices.
    coordinates : Array
        The Cartesian coordinates to calculate the Zernike polynomial upon.
    diameter : float = 2
        The diameter of the aperture to calculate the Zernike polynomial upon.

    Returns
    -------
    zernike_basis : Array
        The Zernike polynomial basis.
    """
    return np.array([zernike(j, coordinates, diameter) for j in js])

polike

Calculates the Zernike polynomial on an n-sided aperture. Note that this function is not-jittable as is has dynamic array shapes. To use this function in a jittable way, use the polike_fast function, with the pre-calculated c and k parameters.

Parameters:

Name Type Description Default
nsides int

The number of sides of the aperture.

required
j int

The Zernike (noll) index.

required
coordinates Array

The Cartesian coordinates to calculate the Zernike polynomial upon.

required
diameter float = 2

The diameter of the aperture to calculate the Zernike polynomial upon.

2

Returns:

Name Type Description
polike Array

The Zernike polynomial on an n-sided aperture.

Source code in src/dLux/utils/zernikes.py
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
def polike(
    nsides: int, j: int, coordinates: Array, diameter: float = 2
) -> Array:
    """
    Calculates the Zernike polynomial on an n-sided aperture. Note that this function
    is not-jittable as is has dynamic array shapes. To use this function in a jittable
    way, use the polike_fast function, with the pre-calculated c and k parameters.

    Parameters
    ----------
    nsides : int
        The number of sides of the aperture.
    j : int
        The Zernike (noll) index.
    coordinates : Array
        The Cartesian coordinates to calculate the Zernike polynomial upon.
    diameter : float = 2
        The diameter of the aperture to calculate the Zernike polynomial upon.

    Returns
    -------
    polike : Array
        The Zernike polynomial on an n-sided aperture.
    """
    if nsides < 3:
        raise ValueError(f"nsides must be >= 3, not {nsides}.")
    coordinates = scale_coords(coordinates, diameter / 2)
    theta = dlu.cart2polar(coordinates)[1]
    alpha = np.pi / nsides
    phi = theta + alpha
    wedge = np.floor((phi + alpha) / (2.0 * alpha))
    u_alpha = phi - wedge * (2 * alpha)
    r_alpha = np.cos(alpha) / np.cos(u_alpha)
    return 1 / r_alpha * zernike(j, coordinates / r_alpha)

polike_fast

Calculates the Zernike polynomial on an n-sided aperture using the pre-calculated c and k parameters, such that this function is jittable.

Parameters:

Name Type Description Default
nsides int

The number of sides of the aperture.

required
n int

The radial order of the Zernike polynomial.

required
m int

The azimuthal order of the Zernike polynomial.

required
c Array

The normalisation coefficients of the Zernike polynomial.

required
k Array

The powers of the Zernike polynomial.

required
coordinates Array

The Cartesian coordinates to calculate the Zernike polynomial upon.

required

Returns:

Name Type Description
polike Array

The Zernike polynomial on an n-sided aperture.

Source code in src/dLux/utils/zernikes.py
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
def polike_fast(
    nsides: int, n: int, m: int, c: Array, k: Array, coordinates: Array
) -> Array:
    """
    Calculates the Zernike polynomial on an n-sided aperture using the pre-calculated
    c and k parameters, such that this function is jittable.

    Parameters
    ----------
    nsides : int
        The number of sides of the aperture.
    n : int
        The radial order of the Zernike polynomial.
    m : int
        The azimuthal order of the Zernike polynomial.
    c : Array
        The normalisation coefficients of the Zernike polynomial.
    k : Array
        The powers of the Zernike polynomial.
    coordinates : Array
        The Cartesian coordinates to calculate the Zernike polynomial upon.

    Returns
    -------
    polike : Array
        The Zernike polynomial on an n-sided aperture.
    """
    if nsides < 3:
        raise ValueError(f"nsides must be >= 3, not {nsides}.")
    alpha = np.pi / nsides
    phi = dlu.cart2polar(coordinates)[1] + alpha
    wedge = np.floor((phi + alpha) / (2.0 * alpha))
    u_alpha = phi - wedge * (2 * alpha)
    r_alpha = np.cos(alpha) / np.cos(u_alpha)
    return 1 / r_alpha * zernike_fast(n, m, c, k, coordinates / r_alpha)

polike_basis

Calculates the Zernike polynomial basis on an n-sided aperture. Note that this function is not-jittable.

Parameters:

Name Type Description Default
nsides int

The number of sides of the aperture.

required
js list[int]

The Zernike (noll) indices.

required
coordinates Array

The Cartesian coordinates to calculate the Zernike polynomial upon.

required
diameter float = 2

The diameter of the aperture to calculate the Zernike polynomial upon.

2

Returns:

Name Type Description
polike_basis Array

The Zernike polynomial basis on an n-sided aperture.

Source code in src/dLux/utils/zernikes.py
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
def polike_basis(
    nsides: int, js: list[int], coordinates: Array, diameter: float = 2
):
    """
    Calculates the Zernike polynomial basis on an n-sided aperture. Note that this
    function is not-jittable.

    Parameters
    ----------
    nsides : int
        The number of sides of the aperture.
    js : list[int]
        The Zernike (noll) indices.
    coordinates : Array
        The Cartesian coordinates to calculate the Zernike polynomial upon.
    diameter : float = 2
        The diameter of the aperture to calculate the Zernike polynomial upon.

    Returns
    -------
    polike_basis : Array
        The Zernike polynomial basis on an n-sided aperture.
    """
    return np.array([polike(nsides, j, coordinates, diameter) for j in js])