Source code for optiland.nonsequential.components.configs
"""Config dataclasses for NSQ compound components.
SurfaceConfig, InteractionType, LensConfig, DoubletConfig, MirrorConfig.
Kramer Harrison, 2026
"""
from __future__ import annotations
import enum
from dataclasses import dataclass
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from optiland.nonsequential.bsdf.base import BaseBSDF
from optiland.nonsequential.materials.nsq_material import NSQMaterial
[docs]
class InteractionType(enum.Enum):
"""Optical interaction type for a single surface.
Attributes:
REFRACTIVE: Surface refracts (and optionally reflects via Fresnel).
REFLECTIVE: Surface reflects only; no transmission.
ABSORBING: Surface absorbs all incident rays.
"""
REFRACTIVE = "refractive"
REFLECTIVE = "reflective"
ABSORBING = "absorbing"
[docs]
@dataclass
class SurfaceConfig:
"""Optional per-surface overrides within a compound component.
All fields default to ``None``, meaning "use the compound-level default."
When a field is set, it overrides the compound's default for that surface.
Attributes:
bsdf: Custom BSDF for this surface. Routes rays through the scatter
model instead of the surface's specular/refractive behaviour.
scatter_fraction: Probability in [0, 1] that a ray striking this
surface is routed through ``bsdf`` rather than following the
specular or refractive path. The default of 1.0 sends every ray
to the BSDF, turning the surface into a pure diffuser. Set it
below 1 to model a partially scattering surface, e.g. 0.1 for a
surface that scatters a tenth of the light and transmits the
rest. Ignored when ``bsdf`` is None.
coating: An ``optiland.coatings.BaseCoating`` for a refractive
surface (e.g. an AR coating). When set, its reflectance/
transmittance replace the bare Fresnel calculation, so NSQ and
the sequential engine agree on R. Must be an unpolarized coating
(``SimpleCoating``); a ``BaseCoatingPolarized`` instance (Jones-
matrix based -- ``FresnelCoating``, ``ThinFilmCoating``, ...)
raises ``NotImplementedError`` rather than being silently
degraded to its scalar average. Ignored on absorbing surfaces.
aperture_radius: Semi-diameter override [mm]. Overrides the aperture
computed from the compound config.
interaction: Force a specific interaction type on this surface.
reflectance: Required when ``interaction`` selects
``InteractionType.REFLECTIVE``: a constant in [0, 1], a
wavelength-dependent ``callable(wavelength_um) -> reflectance``,
or an unpolarized ``BaseCoating``. See
``ReflectiveComponent`` -- constructing a reflective surface
without one raises rather than defaulting to a perfect mirror.
"""
bsdf: BaseBSDF | None = None
scatter_fraction: float = 1.0
coating: object | None = None # optiland.coatings.BaseCoating
aperture_radius: float | None = None
interaction: InteractionType | None = None
reflectance: object | None = None # float | Callable | BaseCoating
[docs]
@dataclass
class LensConfig:
"""Configuration for a single-element refractive lens.
The lens assembles up to four physical surfaces:
1. **Front face** -- refractive, conic.
2. **Back face** -- refractive, conic.
3. **Edge** -- cylindrical frustum, absorbing by default.
4. **Rim** -- annular plane, absorbing; only created when
``front_aperture_radius != back_aperture_radius``.
Attributes:
r1: Front vertex radius of curvature [mm]. Positive = centre of
curvature on +z side.
r2: Back vertex radius of curvature [mm].
thickness: Centre thickness of the lens [mm].
material: Glass name (e.g. ``'N-BK7'``) or a ready-made
:class:`~optiland.nonsequential.materials.NSQMaterial` instance.
front_aperture_radius: Semi-diameter of the front face [mm].
back_aperture_radius: Semi-diameter of the back face [mm].
Defaults to ``front_aperture_radius`` when ``None``.
conic1: Conic constant of the front face (0 = sphere).
conic2: Conic constant of the back face (0 = sphere).
front: Per-surface overrides for the front face.
back: Per-surface overrides for the back face.
edge: Per-surface overrides for the edge (barrel) surface.
rim: Per-surface overrides for the rim annulus (only used when
apertures differ).
"""
r1: float
r2: float
thickness: float
material: str | NSQMaterial
front_aperture_radius: float
back_aperture_radius: float | None = None
conic1: float = 0.0
conic2: float = 0.0
front: SurfaceConfig | None = None
back: SurfaceConfig | None = None
edge: SurfaceConfig | None = None
rim: SurfaceConfig | None = None
[docs]
@dataclass
class DoubletConfig:
"""Configuration for a cemented achromatic doublet.
Surfaces in order (front -> back): front face, cemented interface, back
face, edge.
Attributes:
r1: Front radius of curvature [mm].
r2: Cemented interface radius of curvature [mm].
r3: Back radius of curvature [mm].
thickness1: Thickness of the crown element [mm].
thickness2: Thickness of the flint element [mm].
material1: Crown element glass name or NSQMaterial.
material2: Flint element glass name or NSQMaterial.
aperture_radius: Common semi-diameter for all surfaces [mm].
conic1: Conic constant of the front face.
conic2: Conic constant of the cemented interface.
conic3: Conic constant of the back face.
front: Per-surface overrides for the front face.
cemented: Per-surface overrides for the cemented interface.
back: Per-surface overrides for the back face.
edge: Per-surface overrides for the edge surface.
"""
r1: float
r2: float
r3: float
thickness1: float
thickness2: float
material1: str | NSQMaterial
material2: str | NSQMaterial
aperture_radius: float
conic1: float = 0.0
conic2: float = 0.0
conic3: float = 0.0
front: SurfaceConfig | None = None
cemented: SurfaceConfig | None = None
back: SurfaceConfig | None = None
edge: SurfaceConfig | None = None
[docs]
@dataclass
class MirrorConfig:
"""Configuration for a single reflective mirror surface.
Attributes:
radius: Vertex radius of curvature [mm]. Negative = concave when
oriented with the normal pointing toward +z.
reflectance: Mirror reflectance: a constant in [0, 1], a
wavelength-dependent ``callable(wavelength_um) -> reflectance``,
or an unpolarized ``optiland.coatings.BaseCoating`` (e.g.
``SimpleCoating``). Required -- there is no implicit
perfect-mirror default: a mirror built without specifying
how much light it reflects is a modelling bug, not a 100%
reflector. Overridden per-surface by ``surface.reflectance``.
conic: Conic constant (0 = sphere, -1 = paraboloid, etc.).
aperture_radius: Semi-diameter [mm].
surface: Per-surface overrides (e.g. to attach a scatter BSDF).
"""
radius: float
reflectance: object # float | Callable | BaseCoating
conic: float = 0.0
aperture_radius: float = 25.0
surface: SurfaceConfig | None = None