Source code for optiland.rays.ray_generator

"""Ray Generator

This module contains the RayGenerator class, which is used to generate rays
for tracing through an optical system.

Kramer Harrison, 2024
"""

from __future__ import annotations

from typing import TYPE_CHECKING

import optiland.backend as be
from optiland.rays.polarized_rays import PolarizedRays
from optiland.rays.ray_aiming.registry import create_ray_aimer
from optiland.rays.real_rays import RealRays

if TYPE_CHECKING:
    from optiland._types import ScalarOrArray


[docs] class RayGenerator: """Generator class for creating rays.""" def __init__(self, optic): self.optic = optic self.aimer = create_ray_aimer("paraxial", optic)
[docs] def set_ray_aiming( self, mode: str, max_iter: int = 10, tol: float = 1e-6, **kwargs ): """Set the ray aiming strategy. Args: mode (str): The name of the ray aiming strategy. Options include "paraxial", "iterative", and "robust". max_iter (int, optional): Maximum iterations for iterative/robust methods. Defaults to 10. tol (float, optional): Convergence tolerance for iterative/robust methods. Defaults to 1e-6. **kwargs: Additional parameters passed to the aimer constructor. """ self.aimer = create_ray_aimer( mode, self.optic, max_iter=max_iter, tol=tol, **kwargs )
[docs] def generate_rays( self, Hx: float, Hy: float, Px: ScalarOrArray, Py: ScalarOrArray, wavelength: ScalarOrArray, ) -> RealRays: """Generates rays for tracing based on the given parameters. Args: Hx: Normalized x field coordinate. Hy: Normalized y field coordinate. Px: x-coordinate of the pupil point. Py: y-coordinate of the pupil point. wavelength: Wavelength of the rays. Returns: RealRays object containing the generated rays. """ if hasattr(self.optic.ray_tracer, "ray_aiming_config"): config = self.optic.ray_tracer.ray_aiming_config if not hasattr(self, "_current_config") or self._current_config != config: self.set_ray_aiming(**config) self._current_config = config.copy() # Aim rays using the configured strategy x0, y0, z0, L, M, N = self.aimer.aim_rays( (Hx, Hy), wavelength, (Px, Py), ) apodization = self.optic.apodization if apodization: intensity = apodization.get_intensity(Px, Py) else: intensity = be.ones_like(Px) wavelength = be.ones_like(x0) * wavelength if self.optic.polarization == "ignore": if self.optic.surfaces.uses_polarization: raise ValueError( "Polarization must be set when surfaces have " "polarization-dependent coatings.", ) rays = RealRays( x0, y0, z0, L, M, N, intensity=intensity, wavelength=wavelength ) return rays return PolarizedRays(x0, y0, z0, L, M, N, intensity, wavelength)