### Install TorchOptics Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/_static/torchoptics_colab.ipynb Installs the TorchOptics package and clears the output. Run this cell first. ```python # Install the TorchOptics package !pip install torchoptics from IPython.display import clear_output clear_output() ``` -------------------------------- ### Install TorchOptics Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/index.rst Install the TorchOptics library using pip. This command installs the latest stable version. ```bash pip install torchoptics ``` -------------------------------- ### Mach-Zehnder Interferometer Setup Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Illustrates the construction of a Mach-Zehnder interferometer using two beam splitters. Assumes 'shape', 'input_field', and 'device' are pre-defined. ```python bs1 = BeamSplitter(shape, theta=math.pi / 4, phi_0=0, phi_r=0, phi_t=0, z=0).to(device) bs2 = BeamSplitter(shape, theta=math.pi / 4, phi_0=0, phi_r=0, phi_t=0, z=0).to(device) arm1, arm2 = bs1(input_field) # Recombine out1, out2 = bs2(arm1, arm2) ``` -------------------------------- ### Install Pre-commit Hooks Source: https://github.com/matthewfilipovich/torchoptics/blob/main/CONTRIBUTING.md Install pre-commit hooks to automatically format and lint code before commits. These hooks use ruff and pyright. ```bash pre-commit install ``` -------------------------------- ### Install Development Dependencies Source: https://github.com/matthewfilipovich/torchoptics/blob/main/CONTRIBUTING.md Install TorchOptics and its development extras using uv. This ensures all necessary packages for development and testing are available. ```bash uv sync --all-extras ``` -------------------------------- ### Clone TorchOptics Repository Source: https://github.com/matthewfilipovich/torchoptics/blob/main/CONTRIBUTING.md Clone your forked repository to start development. Navigate into the cloned directory. ```bash git clone https://github.com/your-username/torchoptics.git cd torchoptics ``` -------------------------------- ### Create and Analyze a Gaussian Field Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Instantiate a `Field` object representing a complex optical wave. This example demonstrates creating a Gaussian field, setting explicit wavelength and spacing, and performing basic analysis like calculating intensity, power, centroid, and standard deviation. Supports batch processing. ```python import torch import torchoptics from torchoptics import Field from torchoptics.profiles import gaussian, octagon torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) device = "cuda" if torch.cuda.is_available() else "cpu" # Create a Gaussian field at z=0 field = Field(gaussian(256, waist_radius=300e-6), z=0).to(device) print(field.intensity().shape) # torch.Size([256, 256]) print(field.power()) # tensor(1.0000, ...) (normalized) print(field.centroid()) # tensor([0., 0.], ...) print(field.std()) # tensor([2.12e-04, 2.12e-04], ...) # Explicit wavelength and spacing (overrides defaults) field2 = Field( octagon(500, radius=1.5e-3), wavelength=532e-9, z=0.0, spacing=(5e-6, 5e-6), offset=(0.0, 0.0), ).to(device) # Batch of fields: shape (..., H, W) batch_data = torch.randn(4, 256, 256, dtype=torch.complex128) batch_field = Field(batch_data).to(device) print(batch_field.power().shape) # torch.Size([4]) ``` -------------------------------- ### Create a Field from a Gaussian Profile Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/fields.rst Another example of creating a Field using a profile function, specifically a Gaussian beam. ```python gaussian_field = Field(gaussian(300, waist_radius=500e-6)) gaussian_field.visualize(title="Gaussian Beam") ``` -------------------------------- ### Lens and CylindricalLens Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Demonstrates the creation and usage of Lens and CylindricalLens elements for focusing light. Includes examples of simple focusing, visualizing modulation profiles, and creating astigmatic fields with cylindrical lenses. ```APIDOC ## Lens(shape, focal_length, z, spacing, offset) ### Description A thin spherical lens with phase modulation `M(x,y) = exp(-iπ(x²+y²)/(λf))`, automatically clipped to a circular aperture. Wavelength-dependent (polychromatic). ### Parameters - **shape** (int) - Description not available in source. - **focal_length** (float) - Focal length of the lens. - **z** (float) - Axial position of the lens. - **spacing** (float, optional) - Default spacing for subsequent elements. - **offset** (tuple, optional) - Default offset for subsequent elements. ### Example ```python import torch import torchoptics from torchoptics import Field, System from torchoptics.elements import CylindricalLens, Lens from torchoptics.profiles import gaussian torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) device = "cuda" if torch.cuda.is_available() else "cpu" shape = 300 f = 100e-3 # 100 mm focal length input_field = Field(gaussian(shape, waist_radius=500e-6), z=0).to(device) # Simple focusing system system = System(Lens(shape, f, z=0)).to(device) focused = system.measure_at_z(input_field, z=f) # field at focal plane print(f"Focused beam std: {focused.std()}") # Visualize the lens modulation profile lens = Lens(shape, f, z=0) lens.visualize(title="Lens Phase Profile (700 nm)") # Cylindrical lens: focuses only along one axis (theta=0 → x-axis) import math cyl_system = System( CylindricalLens(shape, focal_length=f, theta=0, z=0), ).to(device) astig_field = cyl_system.measure_at_z(input_field, z=f) print(f"Astigmatic beam std: {astig_field.std()}") # Polychromatic: pass different wavelengths lens_element = Lens(shape, f, z=f) for wl in [450e-9, 550e-9, 650e-9]: mod = lens_element.modulation_profile(wavelength=wl) print(f"λ={wl*1e9:.0f} nm modulation shape: {mod.shape}") ``` ``` -------------------------------- ### Global Configuration Functions Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Functions to set and get default simulation parameters like spacing, wavelength, and data type. These defaults are used by Field and element functions when specific values are not provided. ```APIDOC ## Global Configuration ### `set_default_spacing` / `set_default_wavelength` / `set_default_dtype` Set simulation-wide defaults for grid spacing (meters), wavelength (meters), and floating-point dtype. These defaults are used by all `Field`, element, and profile functions whenever their respective arguments are `None`, avoiding repetitive parameter passing. `get_default_*` counterparts retrieve the current values. ```python import torch import torchoptics # Set defaults at the start of every simulation torchoptics.set_default_spacing(10e-6) # 10 µm pixel pitch torchoptics.set_default_wavelength(700e-9) # 700 nm red light torchoptics.set_default_dtype(torch.float64) # double precision (default) print(torchoptics.get_default_spacing()) # tensor([1.0000e-05, 1.0000e-05], dtype=torch.float64) print(torchoptics.get_default_wavelength()) # tensor(7.0000e-07, dtype=torch.float64) print(torchoptics.get_default_dtype()) # torch.float64 # Anisotropic spacing (different x and y pitch) torchoptics.set_default_spacing((8e-6, 12e-6)) ``` ``` -------------------------------- ### Build Documentation Locally Source: https://github.com/matthewfilipovich/torchoptics/blob/main/CONTRIBUTING.md Build the project's HTML documentation using make. This command should be run from the project's root directory. ```bash make -C docs html ``` -------------------------------- ### Serve Documentation Locally Source: https://github.com/matthewfilipovich/torchoptics/blob/main/CONTRIBUTING.md Serve the built HTML documentation using Python's http.server. This allows you to preview documentation changes in a browser. ```bash python -m http.server 8000 --directory docs/build/html ``` -------------------------------- ### Create Waveplate Elements Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/elements.rst Demonstrates the creation of general, quarter-waveplate, and half-waveplate elements with specified parameters. Ensure 'shape' is defined and 'math' is imported. ```python from torchoptics.elements import HalfWaveplate, QuarterWaveplate, Waveplate # General waveplate wp = Waveplate(shape, phi=math.pi/3, theta=math.pi/4, z=0) # Quarter waveplate at 45°: converts x-linear to circular qwp = QuarterWaveplate(shape, theta=math.pi/4, z=0) # Half waveplate at 22.5°: rotates polarization by 45° hwp = HalfWaveplate(shape, theta=math.pi/8, z=0) ``` -------------------------------- ### Perform Forward Pass Through System Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/systems.rst The forward pass propagates an input field through all elements of the system in order of increasing 'z'. Elements with 'z' less than the field's starting 'z' are skipped; elements at the starting 'z' are applied. ```python input_field = Field(gaussian(shape, waist_radius=1e-3), z=0) output_field = system(input_field) ``` -------------------------------- ### Create and Initialize an Optical System Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/systems.rst Instantiate a System by passing optical elements to its constructor. The 'z' attribute of each element determines its position along the optical axis. Default spacing and wavelength can be set globally. ```python import torch import torchoptics from torchoptics import Field, System from torchoptics.elements import AmplitudeModulator, Lens from torchoptics.profiles import circle, gaussian torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) shape = 1000 f = 200e-3 system = System( Lens(shape, f, z=1 * f), Lens(shape, f, z=3 * f), ) ``` -------------------------------- ### Set Default Spacing and Wavelength Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/configuration.rst Set the global default spacing and wavelength for TorchOptics. These values are used when creating `Field` or `Element` objects without explicit parameters. Set these at the start of your script. ```python import torchoptics torchoptics.set_default_spacing(10e-6) # 10 µm grid spacing torchoptics.set_default_wavelength(700e-9) # 700 nm wavelength ``` -------------------------------- ### Lens Element: Simple Focusing System Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Demonstrates creating a simple focusing system with a Lens element and measuring the field at the focal plane. Also shows how to visualize the lens's phase profile and simulate a cylindrical lens for astigmatic focusing. ```python import torch import torchoptics from torchoptics import Field, System from torchoptics.elements import CylindricalLens, Lens from torchoptics.profiles import gaussian torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) device = "cuda" if torch.cuda.is_available() else "cpu" shape = 300 f = 100e-3 # 100 mm focal length input_field = Field(gaussian(shape, waist_radius=500e-6), z=0).to(device) # Simple focusing system system = System(Lens(shape, f, z=0)).to(device) focused = system.measure_at_z(input_field, z=f) # field at focal plane print(f"Focused beam std: {focused.std()}") # Visualize the lens modulation profile lens = Lens(shape, f, z=0) lens.visualize(title="Lens Phase Profile (700 nm)") # Cylindrical lens: focuses only along one axis (theta=0 → x-axis) import math cyl_system = System( CylindricalLens(shape, focal_length=f, theta=0, z=0), ).to(device) astig_field = cyl_system.measure_at_z(input_field, z=f) print(f"Astigmatic beam std: {astig_field.std()}") # Polychromatic: pass different wavelengths lens_element = Lens(shape, f, z=f) for wl in [450e-9, 550e-9, 650e-9]: mod = lens_element.modulation_profile(wavelength=wl) print(f"λ={wl*1e9:.0f} nm modulation shape: {mod.shape}") ``` -------------------------------- ### Modulator Elements Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Details on various modulator elements including PhaseModulator, AmplitudeModulator, Modulator, and PolychromaticPhaseModulator. Shows examples of trainable phase modulators, fixed amplitude masks, arbitrary complex modulators, and dispersive elements. ```APIDOC ## PhaseModulator(phase, z) / AmplitudeModulator(amplitude, z) / Modulator(modulation, z) / PolychromaticPhaseModulator(thickness, n, z) ### Description Field modulators applied to the complex field amplitude. `PhaseModulator` wraps a real phase tensor as `exp(i·phase)`. `AmplitudeModulator` applies a real amplitude mask. `Modulator` applies an arbitrary complex profile. `PolychromaticPhaseModulator` models physical thickness with a wavelength-dependent refractive index for chromatic dispersion. ### Parameters - **phase** (torch.Tensor) - Phase profile for PhaseModulator. - **amplitude** (torch.Tensor) - Amplitude mask for AmplitudeModulator. - **modulation** (torch.Tensor) - Arbitrary complex modulation profile for Modulator. - **thickness** (torch.Tensor) - Physical thickness of the material for PolychromaticPhaseModulator. - **n** (float or callable) - Refractive index (constant or function of wavelength) for PolychromaticPhaseModulator. - **z** (float) - Axial position of the modulator. ### Example ```python import torch import torchoptics from torch.nn import Parameter from torchoptics import Field, System from torchoptics.elements import AmplitudeModulator, Modulator, PhaseModulator, PolychromaticPhaseModulator from torchoptics.profiles import circle, gaussian torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) device = "cuda" if torch.cuda.is_available() else "cpu" shape = 256 input_field = Field(gaussian(shape, waist_radius=300e-6)).to(device) # --- Trainable PhaseModulator for inverse design --- phase_mod = PhaseModulator(Parameter(torch.zeros(shape, shape)), z=0.1).to(device) optimizer = torch.optim.Adam([phase_mod.phase], lr=0.01) output = System(phase_mod).measure_at_z(input_field, z=0.5) loss = -output.intensity().max() loss.backward() optimizer.step() # --- Fixed AmplitudeModulator (aperture mask) --- aperture = AmplitudeModulator(circle(shape, radius=1e-3), z=0.0).to(device) masked_field = System(aperture)(input_field) print(f"Power after aperture: {masked_field.power():.4f}") # --- Complex Modulator (arbitrary hologram) --- hologram = torch.exp(1j * torch.randn(shape, shape, dtype=torch.float64)) mod = Modulator(hologram, z=0.0).to(device) # --- PolychromaticPhaseModulator (dispersive glass) --- thickness = torch.ones(shape, shape) * 1e-3 # 1 mm glass slab # Constant refractive index glass_fixed = PolychromaticPhaseModulator(thickness, n=1.5, z=0.0).to(device) # Dispersive refractive index (Cauchy-like) def n_cauchy(wavelength): return 1.5 + 0.005 / wavelength**2 # simplified dispersion glass_dispersive = PolychromaticPhaseModulator(thickness, n=n_cauchy, z=0.0).to(device) mod_profile_red = glass_dispersive.modulation_profile(wavelength=700e-9) mod_profile_blue = glass_dispersive.modulation_profile(wavelength=450e-9) print(f"Phase shift red: {mod_profile_red.angle().mean():.4f} rad") print(f"Phase shift blue: {mod_profile_blue.angle().mean():.4f} rad") ``` ``` -------------------------------- ### Using Profiles with Optical Elements Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/profiles.rst Demonstrates how to integrate profile functions like 'circle' and 'blazed_grating' with optical elements such as AmplitudeModulator and PhaseModulator. ```python 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) ``` -------------------------------- ### Initialize Input and Target Fields for Inverse Design Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/quickstart/index.rst Sets up the input Gaussian beam and the target eight-petal beam for an inverse design task. Includes setting default spacing and wavelength, and normalizing the target field. ```python import torch from torch.nn import Parameter import torchoptics from torchoptics import Field, System from torchoptics.elements import PhaseModulator from torchoptics.profiles import gaussian, laguerre_gaussian torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) shape = 250 waist_radius = 300e-6 # Input: Gaussian beam input_field = Field(gaussian(shape, waist_radius=waist_radius), z=0) input_field.visualize(title="Input: Gaussian") ``` ```python # Target: eight-petal beam (LG_0^{+4} + LG_0^{-4} superposition) target_data = laguerre_gaussian(shape, p=0, l=4, waist_radius=waist_radius) \ + laguerre_gaussian(shape, p=0, l=-4, waist_radius=waist_radius) target_field = Field(target_data, z=0.8).normalize() # normalize to unit power target_field.visualize(title="Target: Petal Beam") ``` -------------------------------- ### Set Global Defaults for TorchOptics Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/quickstart/index.rst Import TorchOptics and set the grid spacing and wavelength for all subsequent simulations. These defaults define the physical scale of the simulation. ```python import torch import torchoptics from torchoptics import Field, System from torchoptics.elements import AmplitudeModulator, Lens from torchoptics.profiles import checkerboard, circle, gaussian torchoptics.set_default_spacing(10e-6) # 10 µm grid spacing torchoptics.set_default_wavelength(700e-9) # 700 nm (red light) ``` -------------------------------- ### Optical System Simulation Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/_static/torchoptics_colab.ipynb Sets up and simulates a 4f optical system using TorchOptics. This includes defining input fields, lenses, and measuring the field at different focal planes. ```python import torch import torchoptics from torchoptics import Field, System from torchoptics.elements import Lens from torchoptics.profiles import checkerboard # Set simulation properties shape = 1000 # Number of grid points in each dimension spacing = 10e-6 # Spacing between grid points (m) wavelength = 700e-9 # Field wavelength (m) focal_length = 200e-3 # Lens focal length (m) tile_length = 400e-6 # Checkerboard tile length (m) num_tiles = 15 # Number of tiles in each dimension # Determine device device = "cuda" if torch.cuda.is_available() else "cpu" # Configure default properties torchoptics.set_default_spacing(spacing) torchoptics.set_default_wavelength(wavelength) # Initialize input field with checkerboard pattern field_data = checkerboard(shape, tile_length, num_tiles) input_field = Field(field_data).to(device) # Define 4f optical system with two lenses system = System( Lens(shape, focal_length, z=1 * focal_length), Lens(shape, focal_length, z=3 * focal_length), ).to(device) # Measure field at focal planes along the z-axis measurements = [system.measure_at_z(input_field, z=i * focal_length) for i in range(5)] # Visualize the measured intensity distributions for i, measurement in enumerate(measurements): measurement.visualize(title=f"z={i}f", vmax=1) ``` -------------------------------- ### System Class for Sequential Optical Elements Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Sets up and propagates a field through a sequence of optical elements (e.g., lenses, modulators) using the System class. Elements are sorted by z-position. Ensure default spacing and wavelength are set. ```python import torch import torchoptics from torchoptics import Field, System from torchoptics.elements import AmplitudeModulator, Lens from torchoptics.profiles import checkerboard, circle torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) device = "cuda" if torch.cuda.is_available() else "cpu" shape = 500 f = 50e-3 # focal length input_field = Field(checkerboard(shape, tile_length=200e-6, num_tiles=15)).to(device) # 4f system with high-pass spatial filter at Fourier plane system = System( Lens(shape, f, z=1 * f), AmplitudeModulator(1 - circle(shape, radius=200e-6), z=2 * f), Lens(shape, f, z=3 * f), ).to(device) # Propagate through full system (output after last element) output_field = system(input_field) # Measure at specific z positions (same shape/spacing as input field) for i in range(5): field_at_z = system.measure_at_z(input_field, z=i * f) print(f"z={i}f power={field_at_z.power():.4f}") ``` -------------------------------- ### Standard PyTorch Training Loop for Optical Systems Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/inverse_design.rst Demonstrates a typical training loop for optimizing an optical system using TorchOptics. It sets up input and target fields, defines a system with trainable modulators, and iteratively minimizes a loss based on field overlap. ```python import torch from torch.nn import Parameter import torchoptics from torchoptics import Field, System from torchoptics.elements import PhaseModulator from torchoptics.profiles import gaussian torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) shape = 250 input_field = Field(gaussian(shape, waist_radius=300e-6), z=0) target_field = Field(gaussian(shape, waist_radius=100e-6), z=0.4).normalize() system = System( PhaseModulator(Parameter(torch.zeros(shape, shape)), z=0.0), PhaseModulator(Parameter(torch.zeros(shape, shape)), z=0.2), ) optimizer = torch.optim.Adam(system.parameters(), lr=0.1) for iteration in range(200): optimizer.zero_grad() output = system.measure_at_z(input_field, z=0.4) loss = 1 - output.inner(target_field).abs().square() loss.backward() optimizer.step() ``` -------------------------------- ### Simulate System with Phase Modulator Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Demonstrates using a PhaseModulator in a system and measuring the diffracted field. ```python import torch input_field = Field(gaussian(shape, waist_radius=500e-6)) grating_mod = PhaseModulator(blaze, z=0.0) system = System(grating_mod) diffracted = system.measure_at_z(input_field, z=0.2) print(f"Diffracted field intensity max: {diffracted.intensity().max():.4f}") ``` -------------------------------- ### Create Polarized Modulator Elements Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/elements.rst Shows how to create polarized modulators with uniform or spatially-varying Jones matrices. Requires 'torch' and 'shape' to be defined. ```python from torchoptics.elements import PolarizedModulator, PolarizedPhaseModulator # Spatially uniform identity Jones matrix (pass-through) jones = torch.eye(3, dtype=torch.cdouble).view(3, 3, 1, 1).expand(3, 3, shape, shape).contiguous() pol_mod = PolarizedModulator(jones, z=0) # Spatially-varying phase shift per Jones component phase = torch.zeros(3, 3, shape, shape) pol_phase_mod = PolarizedPhaseModulator(phase, z=0) ``` -------------------------------- ### Field Normalization, Inner, and Outer Products Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Demonstrates normalizing field power, calculating mode overlap using inner products, and computing fidelity loss for optimization. Ensure default spacing and wavelength are set before use. ```python import torch import torchoptics from torchoptics import Field from torchoptics.profiles import gaussian, laguerre_gaussian torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) shape = 256 waist_radius = 300e-6 # Create and normalize fields field_g = Field(gaussian(shape, waist_radius), z=0).normalize() field_lg = Field(laguerre_gaussian(shape, p=0, l=1, waist_radius=waist_radius), z=0).normalize() # Inner product: measures mode overlap (1 = perfect match) overlap = field_g.inner(field_lg) print(f"Overlap (Gaussian vs LG01): {overlap.abs().item():.4f}") # ~0.0 (orthogonal modes) self_overlap = field_g.inner(field_g) print(f"Self-overlap: {self_overlap.abs().item():.4f}") # 1.0000 # Mode-overlap fidelity loss for optimization target = Field(laguerre_gaussian(shape, p=0, l=2, waist_radius=waist_radius), z=0).normalize() loss = 1 - field_g.inner(target).abs().square() print(f"Fidelity loss: {loss.item():.4f}") # Power normalization field_unnorm = Field(gaussian(shape, waist_radius) * 5.0) print(f"Power before: {field_unnorm.power().item():.4f}") field_norm = field_unnorm.normalize(normalized_power=2.0) print(f"Power after: {field_norm.power().item():.4f}") # 2.0000 ``` -------------------------------- ### Detector and LinearDetector Usage Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Demonstrates calculating per-cell power maps with Detector and performing classification with LinearDetector. Ensure default spacing and wavelength are set, and the device is configured. ```python import torch import torchoptics from torchoptics import Field, System from torchoptics.elements import Detector, Lens, LinearDetector from torchoptics.profiles import gaussian torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) device = "cuda" if torch.cuda.is_available() else "cpu" shape = 256 n_classes = 10 # output channels for classification input_field = Field(gaussian(shape, waist_radius=300e-6)).to(device) f = 50e-3 # --- Detector: per-cell power map --- system_det = System( Lens(shape, f, z=f), Detector(shape, z=2 * f), ).to(device) power_map = system_det(input_field) print(f"Power map shape: {power_map.shape}") # torch.Size([256, 256]) print(f"Total power: {power_map.sum():.4f}") # ≈ field total power # --- LinearDetector: differentiable optical classifier --- # weight shape: (C, H, W) — one spatial mask per output class weight = torch.rand(n_classes, shape, shape, dtype=torch.float64) linear_det = LinearDetector(weight, z=2 * f).to(device) system_cls = System( Lens(shape, f, z=f), linear_det, ).to(device) class_powers = system_cls(input_field) print(f"Class powers shape: {class_powers.shape}") # torch.Size([10]) predicted_class = class_powers.argmax().item() print(f"Predicted class: {predicted_class}") # Gradient flows through the detector for end-to-end training loss = class_powers.softmax(dim=0)[3] # maximize class 3 loss.backward() ``` -------------------------------- ### Train Diffractive Optical System Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Demonstrates training an optical system using PyTorch optimizers by making PhaseModulator parameters trainable and defining a loss function based on field properties. Ensure device is set for CUDA if available. ```python import torch import torchoptics from torch.nn import Parameter from torchoptics import Field, System from torchoptics.elements import PhaseModulator from torchoptics.profiles import gaussian, laguerre_gaussian torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) device = "cuda" if torch.cuda.is_available() else "cpu" shape = 250 waist_radius = 300e-6 # Input: Gaussian beam input_field = Field(gaussian(shape, waist_radius), z=0).to(device) # Target: eight-petal beam (superposition of LG04 and LG0-4) petal_profile = laguerre_gaussian(shape, p=0, l=4, waist_radius=waist_radius) petal_profile += laguerre_gaussian(shape, p=0, l=-4, waist_radius=waist_radius) target_field = Field(petal_profile, z=0.8).normalize().to(device) ``` -------------------------------- ### Polarization Elements: Polarizers and Waveplates Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Simulates polarized light interactions using elements like LinearPolarizer, Waveplate, and CircularPolarizer. Requires input fields with shape (..., 3, H, W) for polarization components. ```python import torch import torchoptics from torchoptics import Field from torchoptics.elements import ( HalfWaveplate, LeftCircularPolarizer, LinearPolarizer, QuarterWaveplate, RightCircularPolarizer, ) from torchoptics.profiles import gaussian torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) device = "cuda" if torch.cuda.is_available() else "cpu" shape = 128 profile = gaussian(shape, waist_radius=200e-6) # Polarized field: data shape (3, H, W) — x, y, z polarization components pol_data = torch.zeros(3, shape, shape, dtype=torch.complex128) pol_data[0] = profile # x-polarized input pol_field = Field(pol_data).to(device) # --- Linear polarizer at 45° --- lp = LinearPolarizer(shape, theta=torch.pi / 4, z=0).to(device) out_lp = lp(pol_field) print(f"Power after 45° polarizer: {out_lp.power():.4f}") # ~0.5 of input # --- Quarter waveplate (converts linear to circular polarization) --- qwp = QuarterWaveplate(shape, theta=torch.pi / 4, z=0).to(device) out_qwp = qwp(pol_field) # --- Half waveplate (rotates polarization direction) --- hwp = HalfWaveplate(shape, theta=torch.pi / 8, z=0).to(device) out_hwp = hwp(pol_field) # --- General waveplate (arbitrary phase delay phi, fast axis theta) --- import math waveplate = Waveplate(shape, phi=math.pi / 3, theta=0, z=0).to(device) out_waveplate = waveplate(pol_field) # --- Circular polarizer --- lcp = LeftCircularPolarizer(shape, z=0).to(device) rcp = RightCircularPolarizer(shape, z=0).to(device) out_lcp = lcp(pol_field) out_rcp = rcp(pol_field) print(f"LCP power: {out_lcp.power():.4f}, RCP power: {out_rcp.power():.4f}") # Split into polarization components f0, f1, f2 = pol_field.polarized_split() print(f"x-component power: {f0.power():.4f}") ``` -------------------------------- ### System Configuration Output Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/systems.rst This is the text output when printing a System object, detailing each element's parameters. ```text System( (0): Lens(shape=(1000, 1000), z=2.00e-01, spacing=(1.00e-05, 1.00e-05), offset=(0.00e+00, 0.00e+00), focal_length=2.00e-01) (1): Lens(shape=(1000, 1000), z=6.00e-01, spacing=(1.00e-05, 1.00e-05), offset=(0.00e+00, 0.00e+00), focal_length=2.00e-01) ) ``` -------------------------------- ### Visualize Binary Grating Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/profiles.rst Generates and visualizes a binary grating profile. Requires a visualization function. ```python profile = binary_grating(300, period=200e-6) visualize_tensor(profile, title="Binary Grating") ``` -------------------------------- ### Generate Wavefront Profiles Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Generates various wavefront profiles including Zernike polynomials, lens phase, plane waves, and spherical waves. Ensure default spacing and wavelength are set. ```python import torch import torchoptics from torchoptics.profiles import ( cylindrical_lens_phase, lens_phase, plane_wave_phase, spherical_wave_phase, zernike, ) from torchoptics.elements import PhaseModulator torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) shape = 256 # Zernike polynomials (n=2, m=0 → defocus; n=2, m=2 → astigmatism) defocus = zernike(shape, n=2, m=0, radius=1e-3) # real-valued astigmatism = zernike(shape, n=2, m=2, radius=1e-3) coma = zernike(shape, n=3, m=1, radius=1e-3) trefoil = zernike(shape, n=3, m=3, radius=1e-3) spherical_ab = zernike(shape, n=4, m=0, radius=1e-3) # Add Zernike aberrations to a system aberration_phase = defocus * 2.0 + astigmatism * 0.5 + coma * 0.3 aberrated_element = PhaseModulator(aberration_phase, z=0.0) # Lens phase profile (for manual construction) lp = lens_phase(shape, focal_length=50e-3, wavelength=700e-9) print(f"Lens phase range: [{lp.min():.2f}, {lp.max():.2f}] rad") # Plane wave with tilt pw = plane_wave_phase(shape, angle=(0.01, 0.0), wavelength=700e-9) # 10 mrad tilt # Spherical wave from a point source sw = spherical_wave_phase(shape, source_z=-0.5, wavelength=700e-9) ``` -------------------------------- ### Generate Binary Grating Profile Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Creates a binary diffraction grating profile (0/h square-wave). Requires setting default spacing and wavelength. 'shape' and 'period' must be defined. ```python import math import torchoptics from torchoptics.profiles import binary_grating torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) shape = 256 period = 100e-6 # 100 µm grating period # Binary grating (50% duty cycle, height = 1) bg = binary_grating(shape, period=period, duty_cycle=0.5, height=1.0) ``` -------------------------------- ### Visualize Lens Phase Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/profiles.rst Generates and visualizes a thin-lens phase profile. Requires a visualization function. ```python field = torch.exp(1j * lens_phase(300, focal_length=300e-3, wavelength=700e-9)) visualize_tensor(field, title="Lens Phase") ``` -------------------------------- ### Enable Debug Logging for Propagation Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/propagation.rst Enable debug logging for the 'torchoptics' logger to inspect method selection and plane geometries during propagation. ```python import logging logging.getLogger("torchoptics").setLevel(logging.DEBUG) field.propagate_to_z(0.5) ``` -------------------------------- ### System Indexing and Iteration Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/systems.rst Systems support standard Python indexing and slicing to access individual elements or create sub-systems. They are also iterable, allowing you to loop through each element. ```python first = system[0] # Single element sub = system[0:2] # New System from slice n = len(system) # Element count for element in system: print(element) ``` -------------------------------- ### Visualize Sinusoidal Grating Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/profiles.rst Generates and visualizes a sinusoidal grating profile. Requires a visualization function. ```python profile = sinusoidal_grating(300, period=200e-6) visualize_tensor(profile, title="Sinusoidal Grating") ``` -------------------------------- ### Make Modulation Data Trainable Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/inverse_design.rst Wrap modulation data in `torch.nn.Parameter` to make it a learnable property of an optical element. ```python import torch from torch.nn import Parameter from torchoptics.elements import PhaseModulator slm = PhaseModulator(Parameter(torch.zeros(300, 300)), z=0) ``` -------------------------------- ### System Class for Optical Systems Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Documentation for the System class, which chains multiple optical elements to simulate a complete optical system. It supports sequential propagation and measurement at arbitrary planes. ```APIDOC ## System Class ### Description An ordered container of optical elements that propagates a `Field` through them in sequence, sorted by their `z` positions. Supports `forward`, `measure_at_z`, `measure`, and `measure_at_plane` for field evaluation at arbitrary planes. Elements with trainable parameters integrate seamlessly with PyTorch optimizers. ### Constructor `System(*elements)` ### Methods - `forward(input_field)`: Propagates the input field through the entire system. - `measure_at_z(input_field, z)`: Measures the field at a specific z-position after propagating through the system. - `measure(input_field)`: Measures the field at the end of the system. - `measure_at_plane(input_field, plane)`: Measures the field at a specified plane. ### Examples ```python import torch import torchoptics from torchoptics import Field, System from torchoptics.elements import AmplitudeModulator, Lens from torchoptics.profiles import checkerboard, circle torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) device = "cuda" if torch.cuda.is_available() else "cpu" shape = 500 f = 50e-3 # focal length input_field = Field(checkerboard(shape, tile_length=200e-6, num_tiles=15)).to(device) # Define a 4f system system = System( Lens(shape, f, z=1 * f), AmplitudeModulator(1 - circle(shape, radius=200e-6), z=2 * f), Lens(shape, f, z=3 * f), ).to(device) # Propagate through the system output_field = system(input_field) # Measure at specific z positions for i in range(5): field_at_z = system.measure_at_z(input_field, z=i * f) print(f"z={i}f power={field_at_z.power():.4f}") ``` ``` -------------------------------- ### Thin Lens Phase Profile Visualization Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/elements.rst Visualizes the phase profile of a thin lens element. The phase is quadratic and wavelength-dependent. ```python lens = Lens(shape, focal_length=200e-3, z=0) lens.visualize(title="Thin Lens Phase Profile (f = 200 mm)") ``` -------------------------------- ### Simulate Wave Propagation Source: https://github.com/matthewfilipovich/torchoptics/blob/main/README.md Simulate free-space propagation of an octagonal aperture. Requires setting default spacing and wavelength. The field can then be propagated to a specified distance and visualized. ```python import torch import torchoptics from torchoptics import Field from torchoptics.profiles import octagon device = "cuda" if torch.cuda.is_available() else "cpu" torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) field = Field(octagon(shape=500, radius=150e-5)).to(device) for z in torch.linspace(0, 2, 11): field.propagate_to_z(z).visualize(title=f"z = {z:.2f} m") ``` -------------------------------- ### Generate Blazed Grating Profile Source: https://context7.com/matthewfilipovich/torchoptics/llms.txt Creates a blazed (sawtooth) diffraction grating profile. Requires setting default spacing and wavelength. 'shape' and 'period' must be defined. ```python import math import torchoptics from torchoptics.profiles import blazed_grating torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) shape = 256 period = 100e-6 # 100 µm grating period # Blazed grating (sawtooth, full 2π phase swing as height=2π for phase mod) blaze = blazed_grating(shape, period=period, height=2 * math.pi) ``` -------------------------------- ### Train Petal Beam with TorchOptics Source: https://github.com/matthewfilipovich/torchoptics/blob/main/README.md Trains a diffractive optical system to convert a Gaussian beam into a petal beam. Requires PyTorch and TorchOptics. Sets default spacing and wavelength. ```python import torch import torchoptics from torch.nn import Parameter from torchoptics import Field, System from torchoptics.elements import PhaseModulator from torchoptics.profiles import gaussian, laguerre_gaussian device = "cuda" if torch.cuda.is_available() else "cpu" torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) shape = 250 waist_radius = 300e-6 input_field = Field(gaussian(shape, waist_radius=waist_radius), z=0).to(device) petal_profile = laguerre_gaussian(shape, p=0, l=4, waist_radius=waist_radius) petal_profile += laguerre_gaussian(shape, p=0, l=-4, waist_radius=waist_radius) target_field = Field(petal_profile, z=0.8).normalize().to(device) system = System( PhaseModulator(Parameter(torch.zeros(shape, shape)), z=0.2), PhaseModulator(Parameter(torch.zeros(shape, shape)), z=0.4), PhaseModulator(Parameter(torch.zeros(shape, shape)), z=0.6), ).to(device) optimizer = torch.optim.Adam(system.parameters(), lr=0.05) for iteration in range(100): optimizer.zero_grad() output_field = system.measure_at_z(input_field, 0.8) loss = 1 - output_field.inner(target_field).abs().square() loss.backward() optimizer.step() ``` -------------------------------- ### Create Low and High Coherence Sources Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/spatial_coherence.rst Constructs SpatialCoherence objects using gaussian_schell_model with different coherence widths to simulate low and high coherence light. Ensure default spacing and wavelength are set. ```python import torchoptics from torchoptics import SpatialCoherence, visualize_tensor from torchoptics.profiles import gaussian_schell_model torchoptics.set_default_spacing(10e-6) torchoptics.set_default_wavelength(700e-9) low_coh = SpatialCoherence( gaussian_schell_model(30, waist_radius=40e-6, coherence_width=10e-6) ) high_coh = SpatialCoherence( gaussian_schell_model(30, waist_radius=40e-6, coherence_width=1e-3) ) low_coh.visualize(title="Low Coherence (σ_c = 10 µm)") high_coh.visualize(title="High Coherence (σ_c = 1 mm)") ``` -------------------------------- ### Visualize Plane Wave Phase Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/user-guide/profiles.rst Generates and visualizes a plane wave phase profile. Requires a visualization function. ```python field = torch.exp(1j * plane_wave_phase(300, theta=0.001, wavelength=700e-9)) visualize_tensor(field, title="Plane Wave Phase") ``` -------------------------------- ### Create and Visualize a Gaussian Beam Source: https://github.com/matthewfilipovich/torchoptics/blob/main/docs/source/quickstart/index.rst Create an optical field representing a Gaussian beam with a specified waist radius. This serves as an input for simulating focusing with optical elements. ```python gaussian_beam = Field(gaussian(shape, waist_radius=1e-3)) gaussian_beam.visualize(title="Gaussian Beam (z = 0)") ```