paraxial#

Paraxial Module

This module provides various functionalities for the computation of paraxial properties of lens systems.

Note that object-space coordinates are defined relative to the first surface (at index 1), while image-space coordinates are defined relative to the image surface. This is relevant for the focal points (F1 & F2), principal planes (P1 & P2), anti-principal planes (P1anti & P2anti), nodal planes (N1 & N2), and anti-nodal planes (N1anti & N2anti). In the Optiland convention, the 1 denotes object space and the 2 denotes image space. For example, P1 is the object space principle plane and F2 is the back focal point.

Kramer Harrison, 2024

Classes

Paraxial(optic)

A class representing a paraxial optical system.

class Paraxial(optic: Optic)[source]#

A class representing a paraxial optical system.

This class provides methods to calculate various properties of the optical system, such as focal lengths, entrance pupil location, exit pupil location, entrance pupil diameter, exit pupil diameter, image-space F-number, magnification, and more.

Variables:
  • optic (Optic) – The optical system being analyzed.

  • surfaces (SurfaceGroup) – The surface group of the optical system.

EPD() ScalarOrArray[source]#

Calculate the entrance pupil diameter (EPD).

Returns:

Entrance pupil diameter.

EPL(path: ParaxialPath | None = None) ScalarOrArray[source]#

Calculate the entrance pupil location (EPL).

This value is relative to the first physical surface (index 1), matching the convention of other first-order quantities on this class (XPL is relative to the image surface, N1anti / N2anti relative to their respective reference surfaces). The prescription report and the EPL optimization operand both surface this value as-is. Call sites that need a global z (object space, surface positions, ray launch points) should call entrance_pupil_z() instead.

Parameters:

path – Optional prebuilt ParaxialPath to reuse.

Returns:

Entrance pupil position relative to the first surface

(which lies at z=0 by definition in its local coordinate system).

F1() ScalarOrArray[source]#

Calculate the front focal point (F1) location.

Note that this is defined relative to the first surface (at index 1).

Returns:

Front focal point location.

F2() ScalarOrArray[source]#

Calculate the back focal point (F2) location.

Note that this is defined relative to the image surface location.

Returns:

Back focal point location.

FNO() ScalarOrArray[source]#

Calculate the image-space F-number (FNO).

Returns:

Image-space F-number.

Return type:

float

N1() ScalarOrArray[source]#

Calculate the front nodal plane (N1) location.

Note that this is defined relative to the first surface (at index 1).

Returns:

Front nodal plane location.

N1anti() ScalarOrArray[source]#

Calculate the front anti-nodal plane (N1anti) location.

Note that this is defined relative to the first surface (at index 1).

Returns:

Front anti-nodal plane location.

N2() ScalarOrArray[source]#

Calculate the back nodal plane (N2) location.

Note that this is defined relative to the image surface location.

Returns:

Back nodal plane location.

N2anti() ScalarOrArray[source]#

Calculate the back anti-nodal plane (N2anti) location.

Note that this is defined relative to the image surface location.

Returns:

Back anti-nodal plane location.

P1() ScalarOrArray[source]#

Calculate the front principal plane (P1) location.

Note that this is defined relative to the first surface (at index 1).

Returns:

Front principal plane location.

P1anti() ScalarOrArray[source]#

Calculate the front anti-principal plane (P1anti) location.

Note that this is defined relative to the first surface (at index 1).

Returns:

Front anti-principal plane location.

P2() ScalarOrArray[source]#

Calculate the back principal plane (P2) location.

Note that this is defined relative to the image surface location.

Returns:

Back principal plane location.

P2anti() ScalarOrArray[source]#

Calculate the back anti-principal plane (P2anti) location.

Note that this is defined relative to the image surface location.

Returns:

Back anti-principal plane location.

XPD() ScalarOrArray[source]#

Calculate the exit pupil diameter (XPD).

Returns:

Exit pupil diameter.

XPL(path: ParaxialPath | None = None) ScalarOrArray[source]#

Calculate the exit pupil location (XPL).

Parameters:

path – Optional prebuilt ParaxialPath to reuse.

Returns:

Exit pupil location relative to the image surface.

chief_ray() tuple[BEArray, BEArray][source]#

Calculates the chief ray heights and angles at each surface.

The chief ray originates from the edge of the field of view and passes through the center of the aperture stop.

Returns:

  • y_chief: Heights of the chief ray at each surface.

  • u_chief: Slopes of the chief ray after each surface.

Return type:

A tuple containing two arrays

entrance_pupil_axial_position(path: ParaxialPath | None = None) ScalarOrArray[source]#

Entrance pupil location on the unfolded signed axial coordinate.

This is EPL() re-anchored to the same axial coordinate that SurfaceGroup.positions uses, so it can be differenced directly against surface positions. It is a 1-D unfolded axial scalar, never a Cartesian coordinate; use entrance_pupil_point_gcs() for the pupil’s real-space location.

Parameters:

path – Optional prebuilt ParaxialPath to reuse.

entrance_pupil_point_gcs(path: ParaxialPath | None = None) tuple[source]#

Entrance pupil position as a 3-D point in global coordinates.

The entrance pupil is the stop imaged into object space; in the scalar folded model its apparent point lies on the unfolded entry line: r_EP = r_1 + EPL * d_0, with r_1 the first physical surface’s vertex and d_0 the unit entry direction.

Parameters:

path – Optional prebuilt ParaxialPath to reuse.

Returns:

The pupil point as an (x, y, z) tuple of backend scalars.

entrance_pupil_z(path: ParaxialPath | None = None) ScalarOrArray[source]#

Entrance pupil location as an axial scalar (legacy name).

EPL() returns a value relative to the first physical surface (per the documented convention). Call sites that mix the pupil location with other axial coordinates (object position, surface positions) should use this helper so the conversion lives in one place. Issue #613 was caused by call sites silently assuming EPL was global; routing them through this helper makes the convention explicit at the boundary.

Despite the historical name, this is NOT a Cartesian global z: it is the pupil’s coordinate along the signed unfolded axis of SurfaceGroup.positions. The two coincide only while every leg of the beam path runs along +z. For a folded or off-axis-entered system the pupil’s position in space is a point on the entry line – use entrance_pupil_point_gcs() for that point, and prefer entrance_pupil_axial_position() (same value, honest name) in new code.

Parameters:

path – Optional prebuilt ParaxialPath to reuse.

exit_pupil_point_gcs(path: ParaxialPath | None = None) tuple[source]#

Exit pupil position as a 3-D point in global coordinates.

Maps the axial XPL() scalar onto the physical image-space leg: r_XP = r_I + p_I * XPL * d_I, with r_I the image vertex and p_I, d_I the reflection parity and physical beam direction arriving at the image plane.

Parameters:

path – Optional prebuilt ParaxialPath to reuse.

Returns:

The pupil point as an (x, y, z) tuple of backend scalars.

f1() ScalarOrArray[source]#

Calculate the front focal length (f1).

Returns:

Front focal length.

f2() ScalarOrArray[source]#

Calculate the back focal length (f2), also known as effective focal length.

Returns:

Back focal length.

f2_range(start: int, end: int, wavelength: float | None = None, *, path: ParaxialPath | None = None) ScalarOrArray[source]#

Calculate the effective focal length of a range of surfaces.

The range is treated as a lens group in isolation: the returned value is the paraxial EFL that surfaces start through end have with their own conjugates, evaluated in the media that bound the range in the parent system.

This is deliberately not a decomposition of the full system’s power. The focal lengths of a system’s groups do not, in general, recombine into f2(), since that would additionally require the separations between the groups’ principal planes.

Delegates to ray_transfer_matrix(), so it shares the same validated scalar sequence (and supported scalar domain) as the explicit paraxial trace.

Parameters:
  • start – Index of the first surface of the range, inclusive.

  • end – Index of the last surface of the range, inclusive.

  • wavelength – Wavelength in micrometers at which the refractive indices are evaluated. Defaults to the system’s primary wavelength.

  • path – Optional prebuilt ParaxialPath to reuse across several first-order calls.

Returns:

Effective focal length of the surface range. A range with no net

power (an afocal group) returns infinity.

Raises:
invariant() ScalarOrArray[source]#

Calculate the Lagrange invariant.

Returns:

The Lagrange invariant of the system.

magnification() ScalarOrArray[source]#

Calculate the transverse magnification.

Returns:

The system’s transverse magnification.

marginal_ray() tuple[BEArray, BEArray][source]#

Calculates the marginal ray heights and angles at each surface.

The marginal ray originates from the center of the object and passes through the edge of the aperture stop.

Returns:

  • y_marginal: Heights of the marginal ray at each surface.

  • u_marginal: Slopes of the marginal ray after each surface.

Return type:

A tuple containing two arrays

ray_transfer_matrix(start: int, end: int, wavelength: float | None = None, *, path: ParaxialPath | None = None) BEArray[source]#

Build the paraxial ray-transfer (ABCD) matrix of a surface range.

The matrix maps a paraxial ray incident on surface start to the ray leaving surface end:

[y_out]   [A  B] [y_in]
[u_out] = [C  D] [u_in]

Both indices are inclusive. The input height and slope are those immediately before surface start, and the output height and slope those immediately after surface end. Only surfaces inside the range contribute: no propagation is included before start or after end.

The matrix is assembled from the same validated scalar sequence as trace_generic() (shared path metadata, scalar-domain validation, straight-system advisories, and orientation-aware effective radii and focal lengths), so the matrix and an explicit paraxial trace of the same range always agree. The supported scalar domain is that of ParaxialPath: piecewise-centered legs joined by plane fold mirrors, powered surfaces normal to their local beam segment; geometry outside it raises UnsupportedParaxialGeometryError.

Parameters:
  • start – Index of the first surface of the range, inclusive. Must be at least 1, since surface 0 is the object surface and carries no power.

  • end – Index of the last surface of the range, inclusive.

  • wavelength – Wavelength in micrometers at which the refractive indices are evaluated. Defaults to the system’s primary wavelength.

  • path – Optional prebuilt ParaxialPath for the current geometry, so a high-level operation making several first-order calls pays the path construction once. Must be a fresh snapshot of the surfaces being analyzed.

Returns:

The 2x2 ray-transfer matrix of the surface range.

Raises:
property surfaces: SurfaceGroup#

the surface group of the optical system.

Type:

SurfaceGroup

trace(Hy: ArrayLike, Py: ArrayLike, wavelength: float)[source]#

Trace paraxial ray through the optical system based on specified field and pupil coordinates.

Parameters:
  • Hy (float) – Normalized field coordinate (typically in y).

  • Py (float) – Normalized pupil coordinate (typically in y).

  • wavelength (float) – Wavelength of the light in micrometers.

Returns:

A tuple containing two arrays:
  • y_ray: Heights of the traced ray at each surface.

  • u_ray: Slopes of the traced ray after each surface.

Return type:

tuple[be.ndarray, be.ndarray]

trace_generic(y: BEArray | float, u: BEArray | float, z: BEArray | float, wavelength: float, reverse: bool = False, skip: int = 0, path: ParaxialPath | None = None) tuple[BEArray, BEArray][source]#

Trace generically-defined paraxial rays through the optical system.

Parameters:
  • y – The initial height(s) of the rays.

  • u – The initial slope(s) of the rays.

  • z – The initial axial position(s) of the rays, relative to the first surface if tracing forward, or relative to the last surface if tracing in reverse (before internal reversal).

  • wavelength – The wavelength of the rays in micrometers.

  • reverse – If True, trace the rays in reverse direction (from image to object space). Defaults to False.

  • skip – The number of surfaces to skip from the beginning of the trace (or end if reverse). Defaults to 0.

  • path – Optional prebuilt ParaxialPath for the current geometry (built once per high-level operation). Must be a fresh snapshot of the surfaces being traced.

Returns:

A tuple containing the height(s)

and slope(s) of the rays at each surface interface after tracing.