Source code for optiland.aperture.float_by_stop

"""Float-By-Stop-Size Aperture

Kramer Harrison, 2026
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from optiland.aperture.base import BaseSystemAperture

if TYPE_CHECKING:
    from optiland.paraxial import Paraxial


[docs] class FloatByStopAperture(BaseSystemAperture): """Aperture specified as the diameter of the stop surface. The entrance pupil diameter is derived via paraxial ray tracing through the stop surface. For infinite-conjugate systems the marginal ray is traced forward; for finite-conjugate systems the object-space angle is scaled from the paraxial stop height. Args: value: Stop surface diameter in lens units. """ _ap_type_key = "float_by_stop_size" def __init__(self, value: float) -> None: self._value = value @property def ap_type(self) -> str: return "float_by_stop_size" @property def value(self) -> float: return self._value @property def supports_telecentric(self) -> bool: return True @property def is_scalable(self) -> bool: return True
[docs] def compute_epd(self, paraxial: Paraxial, wavelength: float | None = None) -> float: """Compute EPD by paraxial ray tracing through the stop surface. Args: paraxial: Paraxial engine providing ray tracing and system access. wavelength: Primary wavelength in micrometers. When ``None``, falls back to ``paraxial.optic.primary_wavelength``. Returns: Entrance pupil diameter. Raises: ValueError: If the object surface is not defined. """ if paraxial.optic.object_surface is None: raise ValueError( "float_by_stop_size aperture requires a defined object surface." ) if wavelength is None: wavelength = paraxial.optic.primary_wavelength stop_index = paraxial.surfaces.stop_index if paraxial.optic.object_surface.is_infinite: y, _ = paraxial.trace_generic(1.0, 0.0, -1, wavelength) return self._value / y[stop_index] else: obj_z = paraxial.optic.object_surface.geometry.cs.z epl = paraxial.EPL() y, _ = paraxial.trace_generic(0.0, 0.1, obj_z, wavelength) u0 = 0.1 * self._value / y[stop_index] return u0 * (epl - obj_z)
[docs] def scale(self, factor: float) -> FloatByStopAperture: """Return a new :class:`FloatByStopAperture` with value scaled by *factor*. Args: factor: Multiplicative scale factor. Returns: A new FloatByStopAperture instance. """ return FloatByStopAperture(self._value * factor)
[docs] def to_dict(self) -> dict: return {"type": "float_by_stop_size", "value": self._value}
@classmethod def _from_dict(cls, data: dict) -> FloatByStopAperture: return cls(data["value"])