Source code for solves.quick_focus

"""Quick Focus Solve Module

Defines the quick focus solve.

Seçkin Berkay Öztürk, 2025
"""

from __future__ import annotations

import optiland.backend as be
from optiland.solves.base import BaseSolve


[docs] class QuickFocusSolve(BaseSolve): """Quick Focus Args: optic (Optic): The optic object. Raises: ValueError: If the optical system is not defined. """ def __init__(self, optic, *args): self.optic = optic self.num_surfaces = self.optic.surfaces.num_surfaces if self.num_surfaces <= 2: raise ValueError("Can not optimize for an empty optical system")
[docs] def optimal_focus_distance( self, Hx=0, Hy=0, wavelength=0.55, num_rays=5, distribution="hexapolar", ): """Compute the optimal location of the image plane where the RMS spot size is minimized. This is based on solving the quadratic equation that describes the RMS spot size as a function of the propagation distance. Args: Hx (float): The normalized x field. Hy (float): The normalized y field. wavelength (float): The wavelength of the light. num_rays (int): The number of rays to trace. distribution (str): The distribution of rays to trace. Returns: float: The optimal axial position (z-coordinate) of the image plane that minimizes the RMS spot size. """ rays = self.optic.trace( Hx=Hx, Hy=Hy, wavelength=wavelength, num_rays=num_rays, distribution=distribution, ) A = rays.L**2 + rays.M**2 B = rays.L * rays.x + rays.M * rays.y with be.errstate(divide="ignore", invalid="ignore"): t_opt = be.where(A != 0, -B / A, be.nan) z_focus = be.nanmean(rays.z + t_opt * rays.N) return z_focus
[docs] def apply(self): """Applies the QuickFocusSolve to the optic. This method calculates the optimal focus distance and sets the z-position of the last surface (image plane) accordingly. """ z_focus = self.optimal_focus_distance( wavelength=self.optic.wavelengths.primary_wavelength.value, ) self.optic.surfaces[-1].geometry.cs.z = z_focus