optiland.rays.ray_aiming.pupil_map#

Pupil Map Module

This module implements the per-field affine launch model used by the chief-ray calibrated robust ray aimer (see robust.py), together with a warm-start cache keyed by (Hx, Hy, wavelength).

The pupil map is a cheap seed generator only: it is exact at the chief ray and four cardinal edge probes, and a good linear approximation elsewhere. The final Newton/Broyden polish (in iterative.py) makes every ray exact, so the map never needs to carry gradient information – it is stored as plain Python floats, which are inherently detached from any autograd graph.

Kramer Harrison, 2026

Functions

to_float(x)

Extract a plain Python float from a scalar or length-1 backend array.

Classes

PupilMap(base, A, param)

Per-field affine launch model in local transverse coordinates.

PupilMapCache([precision])

Warm-start cache of PupilMap, keyed by (Hx, Hy, wavelength).

class PupilMap(base: tuple[float, float, float, float, float, float], A: tuple[tuple[float, float], tuple[float, float]], param: LaunchParameterization)[source]#

Per-field affine launch model in local transverse coordinates.

seed(Px, Py) evaluates (xi, eta) = A @ [Px, Py] and maps the result through the chief ray’s bound LaunchParameterization: for infinite conjugates the launch point moves in the entry-frame transverse plane around the chief launch (fixed field direction); for finite conjugates the object point is fixed and the direction rotates in the tangent basis around the chief direction, staying unit-norm. The stored coordinates are local transverse offsets, never global (x, y) – a system entered off the z axis seeds correctly.

Variables:
  • base – Chief launch state (x, y, z, L, M, N) as plain floats.

  • A – Affine matrix ((a11, a12), (a21, a22)) mapping normalized pupil coordinates to (xi, eta).

  • param – The launch parameterization (entry-frame basis, conjugate mode) the offsets are expressed in.

A#
base#
property is_infinite: bool#
param#
seed(Px: Any, Py: Any) tuple[source]#

Evaluate the affine model for pupil coordinates (Px, Py).

Parameters:
  • Px – Normalized pupil x-coordinates.

  • Py – Normalized pupil y-coordinates.

Returns:

Full launch guess (x, y, z, L, M, N).

Return type:

tuple

class PupilMapCache(precision: int = 6)[source]#

Warm-start cache of PupilMap, keyed by (Hx, Hy, wavelength).

The cache is never cleared on a system change. Instead, a lightweight fingerprint of the aiming-relevant system state is tracked per entry: a cache hit is only “fresh” (reusable without recomputation) if the fingerprint at store time still matches the current one. A stale or missing entry is always still usable as a warm-start seed for a fresh calibration – correctness never depends on the cache, only speed.

fingerprint(optic: Optic) Any[source]#

Compute a lightweight hash of aiming-relevant system state.

Only surfaces up to and including the stop matter for aiming, so post-stop surfaces (and unrelated optic metadata) are excluded to keep this cheap enough to call on every aiming request.

get_fresh(Hx: float, Hy: float, wl: float) PupilMap | None[source]#

Return the cached map only if the system hasn’t changed since it was stored – an exact-reuse hit that skips recalibration entirely.

get_stale(Hx: float, Hy: float, wl: float) PupilMap | None[source]#

Return the map for this exact key regardless of freshness.

nearest(Hx: float, Hy: float) PupilMap | None[source]#

Return the cached map whose field is nearest in (Hx, Hy).

Used for field-marching warm starts (D8): a newly requested field with no cached entry seeds its chief solve from the closest field already solved, rather than a cold paraxial guess.

put(Hx: float, Hy: float, wl: float, pmap: PupilMap) None[source]#
sync(optic: Optic) None[source]#

Recompute the current system fingerprint (once per aiming call).

to_float(x: Any) float[source]#

Extract a plain Python float from a scalar or length-1 backend array.