Profiles#

The torchoptics.profiles module provides functions for generating common spatial profiles. Each function returns a 2D tensor that can be used as the data argument to Field or as input to elements like AmplitudeModulator.

All profile functions accept shape, spacing, and offset arguments. When spacing is omitted, the global default is used.

import torch
import torchoptics
from torchoptics import visualize_tensor
from torchoptics.profiles import (
  airy_pattern, airy_beam, bessel, binary_grating, blazed_grating, checkerboard,
  circle, cylindrical_lens_phase, gaussian, hermite_gaussian, hexagon,
  laguerre_gaussian, lens_phase, plane_wave_phase, rectangle,
  siemens_star, sinc, sinusoidal_grating, spherical_wave_phase,
  square, triangle, zernike,
)

torchoptics.set_default_spacing(10e-6)

Beam Modes#

Gaussian#

gaussian() generates the fundamental Gaussian beam:

profile = gaussian(300, waist_radius=500e-6)
visualize_tensor(profile, title="Gaussian Beam")
../_images/profiles-2.png

Hermite-Gaussian#

hermite_gaussian() generates higher-order \(\text{HG}_{mn}\) modes. The indices \(m\) and \(n\) count intensity nodes along the two transverse axes, producing a rectangular array of \((m+1)(n+1)\) bright lobes:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(3, 3, figsize=(7, 7), constrained_layout=True)
for ax, (m, n) in zip(axes.flat, [(m, n) for n in range(3) for m in range(3)]):
    profile = hermite_gaussian(300, m=m, n=n, waist_radius=250e-6)
    intensity = profile.abs().square()
    ax.imshow(intensity / intensity.max(), cmap="inferno")
    ax.set_title(f"$\\mathrm{{HG}}_{{{m},{n}}}$", fontsize=13)
    ax.axis("off")
plt.suptitle("Hermite-Gaussian Mode Gallery", fontsize=14)
../_images/profiles-3.png

Laguerre-Gaussian#

laguerre_gaussian() generates \(\text{LG}_{p\ell}\) modes. The radial index \(p\) adds concentric dark rings; the azimuthal index \(\ell\) encodes the topological charge of the helical phase front \(e^{i\ell\phi}\), which carries orbital angular momentum of \(\ell\hbar\) per photon:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(3, 4, figsize=(10, 8), constrained_layout=True)
for ax, (p, l) in zip(axes.flat, [(p, l) for p in range(3) for l in range(4)]):
    profile = laguerre_gaussian(300, p=p, l=l, waist_radius=250e-6)
    intensity = profile.abs().square()
    ax.imshow(intensity / intensity.max(), cmap="inferno")
    ax.set_title(f"$\\mathrm{{LG}}_{{{p},{l}}}$", fontsize=12)
    ax.axis("off")
plt.suptitle("Laguerre-Gaussian Mode Gallery", fontsize=14)
../_images/profiles-4.png

Superpositions of counter-rotating vortices \(\mathrm{LG}_{0}^{+\ell} + \mathrm{LG}_{0}^{-\ell}\) produce \(2|\ell|\) intensity petals through azimuthal interference:

petal = laguerre_gaussian(300, p=0, l=4, waist_radius=500e-6) \
    + laguerre_gaussian(300, p=0, l=-4, waist_radius=500e-6)
visualize_tensor(petal, title="8-Petal Beam ($\\mathrm{LG}_{0}^{+4} + \\mathrm{LG}_{0}^{-4}$)")
../_images/profiles-5.png

Bessel#

bessel() generates non-diffracting Bessel beams \(J_0(k r \sin\theta)\):

profile = bessel(300, cone_angle=0.01, wavelength=700e-9)
vmax = profile.abs().max() * 0.5
visualize_tensor(profile, title="Bessel Beam", vmin=-vmax, vmax=vmax, cmap="RdBu")
../_images/profiles-6.png

Airy Beam#

airy_beam() generates a truncated 2D Airy beam, which combines the Airy function with an exponential truncation factor to keep the energy finite while preserving the characteristic self-accelerating lobe:

profile = airy_beam(300, scale=50e-6, truncation=0.05)
vmax = profile.abs().max().item() * 0.5
visualize_tensor(profile, title="Airy Beam", vmin=-vmax, vmax=vmax, cmap="RdBu")
../_images/profiles-7.png

Zernike Modes#

zernike() generates Zernike polynomials \(Z_n^m(\rho, \theta)\) for wavefront aberrations. The indices \(n\) and \(m\) determine the radial and angular structure, making these modes a standard basis for circular pupils and optical aberration analysis:

from matplotlib.gridspec import GridSpec

cmap = plt.get_cmap("RdBu_r")
fig = plt.figure(figsize=(8, 6), facecolor=cmap(0.5))
gs = GridSpec(5, 9, figure=fig, hspace=0.15, wspace=0.05)
fig.subplots_adjust(left=0.02, right=0.98, top=0.92, bottom=0.02)

for n in range(5):
    for i, m in enumerate(range(-n, n + 1, 2)):
        profile = zernike(300, n=n, m=m, radius=1.4e-3)
        ax = fig.add_subplot(gs[n, (4 - n) + 2 * i])
        vmax = profile.abs().max().item()
        ax.imshow(profile, cmap=cmap, vmin=-vmax, vmax=vmax)
        ax.set_title(f"$Z_{{{n}}}^{{{m}}}$", fontsize=9)
        ax.axis("off")
plt.suptitle("Zernike Mode Gallery", fontsize=14)
../_images/profiles-8.png

Geometric Apertures#

Binary aperture masks (1 inside, 0 outside):

Function

Description

circle()

Circular aperture with given radius.

rectangle()

Rectangular aperture with side lengths side.

square()

Square aperture with side length side.

triangle()

Triangular aperture with given base and height.

hexagon()

Regular hexagon with circumradius radius.

octagon()

Regular octagon with circumradius radius.

regular_polygon()

Regular N-sided polygon with circumradius radius.

profile = circle(300, radius=1e-3)
visualize_tensor(profile, title="Circle")
../_images/profiles-9.png
profile = rectangle(300, side=(1.5e-3, 0.8e-3))
visualize_tensor(profile, title="Rectangle")
../_images/profiles-10.png
profile = square(300, side=1.5e-3)
visualize_tensor(profile, title="Square")
../_images/profiles-11.png
profile = triangle(300, base=1.5e-3, height=1.5e-3)
visualize_tensor(profile, title="Triangle")
../_images/profiles-12.png
profile = hexagon(300, radius=1e-3)
visualize_tensor(profile, title="Hexagon")
../_images/profiles-13.png

Gratings#

Periodic profiles along a configurable direction:

Function

Description

binary_grating()

Square-wave grating with configurable duty cycle.

blazed_grating()

Sawtooth (linearly ramped) grating.

sinusoidal_grating()

Smooth sinusoidal grating.

profile = binary_grating(300, period=200e-6)
visualize_tensor(profile, title="Binary Grating")
../_images/profiles-14.png
profile = blazed_grating(300, period=200e-6)
visualize_tensor(profile, title="Blazed Grating")
../_images/profiles-15.png
profile = sinusoidal_grating(300, period=200e-6)
visualize_tensor(profile, title="Sinusoidal Grating")
../_images/profiles-16.png

Test Patterns#

Function

Description

checkerboard()

Tiled checkerboard pattern.

siemens_star()

Spoke-based resolution target.

profile = checkerboard(300, tile_length=200e-6, num_tiles=10)
visualize_tensor(profile, title="Checkerboard")
../_images/profiles-17.png
profile = siemens_star(300, num_spokes=24, radius=1.2e-3)
visualize_tensor(profile, title="Siemens Star")
../_images/profiles-18.png

Wave Phases#

Real-valued phase tensors representing the spatial phase of a wavefront in radians. Wrap in torch.exp(1j * phase) to obtain the complex field amplitude, or pass directly to PhaseModulator to apply the phase as a modulation element:

Function

Description

plane_wave_phase()

Tilted plane wave with polar angle \(\theta\) and azimuthal angle \(\phi\).

spherical_wave_phase()

Diverging spherical wave from a point source.

lens_phase()

Quadratic thin-lens phase profile.

cylindrical_lens_phase()

Quadratic phase in one direction.

field = torch.exp(1j * plane_wave_phase(300, theta=0.001, wavelength=700e-9))
visualize_tensor(field, title="Plane Wave Phase")
../_images/profiles-19.png
field = torch.exp(1j * spherical_wave_phase(300, z=0.5, wavelength=700e-9))
visualize_tensor(field, title="Spherical Wave Phase")
../_images/profiles-20.png
field = torch.exp(1j * lens_phase(300, focal_length=300e-3, wavelength=700e-9))
visualize_tensor(field, title="Lens Phase")
../_images/profiles-21.png
field = torch.exp(1j * cylindrical_lens_phase(300, focal_length=300e-3, wavelength=700e-9))
visualize_tensor(field, title="Cylindrical Lens Phase")
../_images/profiles-22.png

Special Functions#

Function

Description

airy_pattern()

Airy pattern \(\bigl(2J_1(r/a)/(r/a)\bigr)^2\).

sinc()

2D sinc function (Fourier transform of a rectangle).

profile = airy_pattern(300, scale=100e-6)
visualize_tensor(profile, title="Airy Pattern", vmax=1)
../_images/profiles-23.png
profile = sinc(300, scale=(500e-6, 500e-6))
visualize_tensor(profile, title="Sinc")
../_images/profiles-24.png

Coherence Functions#

4D tensors representing the mutual coherence function \(\Gamma(x_1, y_1, x_2, y_2)\) for partially coherent light (see Spatial Coherence):

Function

Description

schell_model()

General Schell model with custom intensity and coherence functions.

gaussian_schell_model()

Gaussian Schell model with Gaussian intensity and coherence.

Using Profiles with Elements#

Profiles plug directly into elements:

import math
from torchoptics.elements import AmplitudeModulator, PhaseModulator
from torchoptics.profiles import circle, blazed_grating

aperture = AmplitudeModulator(circle(300, radius=1e-3), z=0.1)
grating = PhaseModulator(blazed_grating(300, period=100e-6, height=2 * math.pi), z=0.2)