8. Ray Tracing Framework

The ray tracing framework in Optiland simulates light propagation through an optical system. It handles various types of rays, supports flexible ray generation, and traces rays across surfaces in sequential optical systems.

8.1. Ray Representation

Rays are the fundamental elements of the ray tracing process. A ray consists of the following attributes:

  • Origin (x, y, z): The starting point of the ray.

  • Direction (L, M, N): The ray’s unit vector indicating its direction.

  • Wavelength: The wavelength of the ray in the system.

  • Intensity: The ray’s relative intensity.

  • Optical Path Difference (OPD): The accumulated path difference of the ray relative to the chief ray.

  • Polarization Matrix (optional): A 3x3 matrix representing the transformation of a ray’s initial electric field into its final state. This is used by the PolarizedRays class.

Note

In Optiland, all ray attributes are defined as NumPy arrays for efficient computation.

8.2. Ray Types

Optiland supports three types of rays:

  • Real Rays: Standard rays with full 3D attributes, used for detailed tracing.

  • Paraxial Rays: Simplified rays using only height (y), angle (u), wavelength, and starting position (z). These are used for first-order system analysis.

  • Polarized Rays: Rays with additional polarization information, allowing simulations involving birefringent materials or coatings.

8.3. Ray Generation

The ray tracing framework uses a Ray Generator to produce rays for tracing. The generator operates based on user-defined parameters, including:

  • Field points

  • Wavelengths

  • Aperture sampling (e.g., uniform grid, random, etc.)

  • Polarization state

  • System properties (e.g., F/#, NA, telecentricity)

  • Apodization (intensity distribution within the pupil)

Generated rays are passed to the Surface Group for tracing through the optical system. Each Optic instance has a ray_tracer attribute, which in turn contains the RayGenerator.

8.4. Ray Tracing

For real rays, the ray tracing process is managed by the RealRayTracer. The ray tracer is responsible for:

  • Generating the appropriate rays via its RayGenerator.

  • Ray tracing input validation.

  • Propagating rays through the surface group.

For paraxial rays, there are two primary methods for tracing: - The ParaxialRayTracer class provides a dedicated tracer for paraxial rays. - The Surface.trace method can also directly handle ParaxialRays, providing an alternative way to trace them.

8.5. Tracing Process

Ray tracing is performed by sequentially propagating rays across the surfaces in the system:

  1. Rays are converted into the local coordinate system of the current surface.

  2. Rays intersections with the surface are identified and the ray propagates to the intersection point.

  3. If the surface has a physica aperture, rays may be clipped (intensity set to zero) if they fall outside this aperture.

  4. The rays interact with the surface, modifying their direction, intensity, polarization matrix, and other attributes.

  5. Ray are transformed back to the global coordinate system.

  6. Ray information (intersection points, intensities, etc.) is recorded on the surface for later analysis and visualization.

  7. The process is repeated for each surface in the system.

Paraxial rays follow a similar process but use simplified equations for faster computations.

Note

For details on how rays interact with surfaces, see the Surface Overview section.

8.6. Extensibility

The framework is designed to be extensible:

  • New ray types can be added by subclassing the BaseRays base class.

  • Custom ray generators can be implemented by following the existing interface.

  • Additional tracing logic can be integrated into the surface trace method for specialized applications.

For a practical example of ray tracing, see the Getting Started section.

8.7. Ray Aiming

Optiland implements a flexible Ray Aiming system to determine the correct launch coordinates for rays such that they fill the stop surface, even in systems with significant pupil aberrations.

This functionality is managed by the BaseRayAimer class and its subclasses. The system uses a Registry Pattern, allowing users to easily switch strategies or register custom ones.

8.7.1. Available Strategies

  • Paraxial: Standard aiming using paraxial entrance pupil approximation. Fast but less accurate for wide-angle/aberrated systems.

  • Iterative: Uses a Newton-Raphson-like iterative solver to refine ray launch coordinates until they hit the physical stop.

  • Robust: An extension of the iterative method using Pupil Expansion (Continuation Method). It solves for small pupil fractions first and uses the result as a guess for larger pupils, ensuring convergence in highly stressed systems.

  • Cached: A wrapper that caches intermediate results from any other strategy. Useful for optimization or tolerance analysis where system changes are incremental. Enabled by setting cache=True.

8.7.2. Configuration

Ray aiming is configured via the Optic instance:

# Enable robust ray aiming with caching
optic.set_ray_aiming(mode="robust", max_iter=20, tol=1e-6, cache=True)

8.7.3. Custom Aimers

Users can implement custom strategies by subclassing BaseRayAimer and registering them:

from optiland.rays.ray_aiming import BaseRayAimer, register_aimer

@register_aimer("my_custom_aimer")
class MyAimer(BaseRayAimer):
    def aim_rays(self, fields, wavelengths, pupil_coords):
        # Custom logic
        return x, y, z, L, M, N