Optiland Cheat Sheet
Optiland is a Python library for designing, analyzing, and optimizing optical systems. This guide covers the fundamental concepts to get you started.
Core Concepts
At its heart, Optiland revolves around a few key components:
Optic Object: This is the main container for your entire optical system. It holds all the surfaces, aperture definitions, field points, and wavelength information.
Example:
my_system = optic.Optic()
SurfaceGroup (
optiland.surfaces.SurfaceGroup): Manages the collection of surfaces within anOpticobject.Surfaces (
Surface): These represent the individual optical surfaces (lenses, mirrors, image planes, etc.). Each surface has a geometry, material properties on either side, and can optionally have coatings, physical apertures, or be designated as the system’s aperture stop.Object Surface (
ObjectSurface): The first surface in your system, representing the object being imaged. It can be at a finite distance or at infinity.Image Surface (
ImageSurface): The final surface where the image is formed.Standard Surface (
StandardGeometry): Spherical or conic surfaces.Aspheric & Freeform Surfaces: Optiland supports various complex geometries like
EvenAsphere,OddAsphere,PolynomialGeometry,ChebyshevPolynomialGeometry,ZernikePolynomialGeometry, and more…Paraxial Surface (
ParaxialSurface): A thin lens approximation defined by its focal length, useful for initial layouts.
Materials (
Material): Define the optical properties of the media between surfaces, primarily the refractive index (n) and optionally the extinction coefficient (k) as a function of wavelength.Optiland can use data from the refractiveindex.info database (
MaterialFile) or allow you to define ideal materials (IdealMaterial) or materials based on index (nd) and Abbe number (Vd) (AbbeMaterial). TheAbbeMaterialsupports both a legacy polynomial model and a new, more accurate Buchdahl model (recommended).
Geometries (
BaseGeometry): These define the mathematical shape of a surface (e.g., plane, sphere, asphere).Aperture (
BaseSystemAperture): Defines the system’s limiting aperture. This can be specified as Entrance Pupil Diameter (EPD), Image Space F-number (imageFNO), Object Space Numerical Aperture (objectNA), or Float by Stop Size (float_by_stop_size).Fields (
Field,FieldGroup): Define the points in the object plane that are being imaged. Can be specified by angle or object height. Vignetting can also be applied.Wavelengths (
Wavelength,WavelengthGroup): Specify the wavelengths of light used for analysis, including a primary wavelength. All wavelengths are internally converted to microns (µm).Coordinate Systems (
CoordinateSystem): Each surface has its own local coordinate system (LCS) defined by its position (x, y, z) and rotation (rx, ry, rz) relative to a reference system.Apodization (
BaseApodization): Defines the intensity distribution within the pupil. This is uniform (UniformApodization) by default, but other options include Gaussian (GaussianApodization).
Numerical Backend
Optiland can use NumPy (default) or PyTorch.
- PyTorch allows for automatic differentiation.
Switch with:
import optiland.backend as be be.set_backend("torch") # or "numpy"
Basic Workflow: Defining an Optical System
Import Optiland:
from optiland import optic from optiland import materials # if using specific materials import optiland.backend as be # backend for numerical operations - either numpy or torch
Create an
OpticInstance:my_lens = optic.Optic(name="My Cooke Triplet")
Add Surfaces (
add_surface): Surfaces are added sequentially. * The first surface (index 0) is typically the object surface.my_lens.surfaces.add(index=0, radius=np.inf, thickness=np.inf) # Object at infinity
Add optical surfaces with their properties:
my_lens.surfaces.add(index=1, radius=22.01359, thickness=3.25896, material="SK16") my_lens.surfaces.add(index=2, radius=-435.76044, thickness=6.00755) # Air gap by default my_lens.surfaces.add(index=3, radius=-22.21328, thickness=0.99997, material=("F2", "schott"), is_stop=True) # Stop surface # ... more surfaces ...
The last surface is the image plane.
my_lens.surfaces.add(index=N) # N is the index after the last optical surface
Set System Aperture (
set_aperture):my_lens.set_aperture(aperture_type="EPD", value=10.0) # Entrance Pupil Diameter of 10 mm # Or: my_lens.set_aperture(aperture_type="imageFNO", value=5.0) # Or: my_lens.set_aperture(aperture_type="float_by_stop_size", value=7.6), specifies diameter of the stop surface
Define Field of View (
set_field_type,add_field):my_lens.fields.set_type(field_type="angle") # Field specified by angle my_lens.fields.add(y=0.0) # On-axis field my_lens.fields.add(y=14.0) # Off-axis field at 14 degrees my_lens.fields.add(y=20.0) # Or for object height: # my_lens.fields.set_type(field_type="object_height") # my_lens.fields.add(y=10.0) # Object height of 10 mm
Define Wavelengths (
add_wavelength):my_lens.wavelengths.add(value=0.4861) # F-line (blue) in µm my_lens.wavelengths.add(value=0.5876, is_primary=True) # d-line (yellow), primary my_lens.wavelengths.add(value=0.6563) # C-line (red)
(Optional) Image Plane Solve (
image_solve): Moves the image surface to the paraxial focus.my_lens.image_solve()
Coordinate System & Sign Conventions
Understanding Optiland’s coordinate system and sign conventions is crucial:
Global Coordinate System (GCS): A fixed reference frame.
Local Coordinate System (LCS): Each surface has its own LCS.
Light Propagation: From left to right, along the positive z-axis.
Surface Vertex: Surface 1 typically at GCS origin (z=0). Others at their LCS origin.
Thickness: Axial separation to the next surface. Positive means to the right.
- Radius of Curvature (R):
Positive R: Center of curvature to the right (convex to left).
Negative R: Center of curvature to the left (concave to left).
Infinite R: Planar surface.
Tilts and Decenters: The rotation matrix (of the global CS) is given by
R = Rz @ Ry @ Rx.- Ray Parameters:
Height (y): Positive above the optical axis.
Slope (u - paraxial): Positive if traveling upwards.
Direction Cosines (L, M, N - real): Components of the unit vector.
Angles: Positive clockwise.
Ray Tracing
Optiland uses normalized coordinates for both the field and pupil to define rays in a general, system-independent way:
Field Coordinates (Hx, Hy): Define the ray’s starting field position. (0, 0) corresponds to the optical axis, and (±1, ±1) spans the full normalized field of view.
Pupil Coordinates (Px, Py): Define the ray’s position in the entrance pupil. (0, 0) corresponds to the chief ray, and (±1, ±1) spans the full normalized entrance pupil.
Optiland can trace both paraxial and real rays.
Paraxial Rays:
For first-order calculations. Access through
optic.paraxial.Example:
heights, slopes = lens.paraxial.trace(Hy, Py)
Real Rays:
For detailed analysis, including aberrations.
Example: Trace a bundle of rays
optic.trace(Hx, Hy, wavelength, num_rays, distribution)
Example: Trace a specific ray, defined by the normalized field and pupil coordinates.
optic.trace_generic(Hx, Hy, Px, Py, wavelength)
Advanced Ray Tracing (
RealRays,surface_group.trace): For more control, create aRealRaysobject and trace usingoptic.surfaces.trace(rays).Example:
from optiland.rays import RealRays import optiland.backend as be # Assume 'my_lens' is an existing Optic object # Create a grid of rays at z=0 (e.g., entrance pupil plane) x_coords = be.linspace(-5.0, 5.0, 3) # Adjust range based on EPD y_coords = be.linspace(-5.0, 5.0, 3) X, Y = be.meshgrid(x_coords, y_coords) # Create a collimated ray bundle (traveling along +z) x_in = X.reshape(-1) y_in = Y.reshape(-1) z_in = be.zeros_like(x_in) L_in = be.zeros_like(x_in) M_in = be.zeros_like(x_in) N_in = be.ones_like(x_in) intensity = be.ones_like(x_in) # Create the RealRays object primary_wl = my_lens.wavelengths.primary_wavelength.value rays_in = RealRays(x=x_in, y=y_in, z=z_in, L=L_in, M=M_in, N=N_in, wavelength=primary_wl, intensity=intensity) # Trace the manually created rays rays_out = my_lens.surfaces.trace(rays_in) # Get x, y coordinates at the image plane (last surface) x_image = my_lens.surfaces.x[-1,:] y_image = my_lens.surfaces.y[-1,:]
Ray Distributions (
distribution.py): Specify pupil distribution (e.g.,'hexapolar','uniform','random').
Analysis Tools
Optiland offers a suite of tools to evaluate performance:
Aberrations: Seidel & chromatic. (my_lens.aberrations.seidels())SpotDiagram: Geometric ray spread.RayFan: Transverse ray aberrations.OPD: Wavefront errors.MTF: Image contrast vs. frequency.PSF: Point spread function.FieldCurvature,Distortion: Field performance.(Many classes have a ``.view()`` method for plotting).
See the Example Gallery for a full overview of available analysis tools and their usage.
Visualization
2D Layout (
optic.draw()):my_lens.draw(num_rays=5, distribution='line_y')
3D Layout (
optic.draw3D()):my_lens.draw3D(num_rays=24, distribution='ring')
Lens Data Table (
optic.info()): Prints surface data in a tabular format, resembling the commonly found Lens Data Editor (LDE).my_lens.info()
GUI Keyboard Shortcuts
Ctrl+K: Open the VS Code-style Command Palette for quick access to actions and tools.
1 / 2: Load layout presets 1 and 2, respectively.
Advanced Features (Brief Overview)
Coatings (
coatings.py): Model anti-reflection or reflective coatings (SimpleCoating,FresnelCoating).Thin Films (
thin_film/*): Define and optimize multilayer thin-film stacks, including tolerancing and Needle Synthesis.Polarization (
polarized_rays.py,jones.py): Trace polarized light and apply Jones calculus for polarizing elements.Pickups (
pickup.py): Link a parameter of one surface to another (e.g., make radius of S2 = -radius of S1).Solves (
solves): Automatically adjust parameters to meet certain conditions (e.g.,QuickFocusSolveadjusts image plane for best focus).Optimization (
optimization/*): Define merit functions with operands and variables to optimize system designs.Tolerancing (
tolerancing/*): Analyze the impact of manufacturing errors using sensitivity analysis and Monte Carlo simulations.
This cheat sheet should provide a solid starting point. Happy designing! ✨