surfaces.surface_group#

Surface Group

This module contains the SurfaceGroup class, which represents a group of surfaces in an optical system. The SurfaceGroup class provides methods for tracing rays through the surfaces, adding and removing surfaces, and converting the group to and from a dictionary for serialization.

Kramer Harrison, 2024

Classes

SurfaceGroup([surfaces])

Represents a group of surfaces in an optical system.

class SurfaceGroup(surfaces: list[Surface] | None = None)[source]#

Represents a group of surfaces in an optical system.

Variables:
  • surfaces (list) – List of surfaces in the group.

  • _last_thickness (float) – The thickness of the last surface added.

property L#

x direction cosines on all surfaces

Type:

np.array

property M#

y direction cosines on all surfaces

Type:

np.array

property N#

z direction cosines on all surfaces

Type:

np.array

add(new_surface=None, surface_type: SurfaceType = 'standard', comment='', index=None, is_stop=False, material: str | BaseMaterial = 'air', **kwargs)[source]#

Adds a new surface to the list of surfaces.

Parameters:
  • new_surface (Surface, optional) – The new surface to add. If not provided, a new surface will be created based on the other arguments.

  • surface_type (str, optional) – The type of surface to create.

  • comment (str, optional) – A comment for the surface. Defaults to ‘’.

  • index (int, optional) – The index at which to insert the new surface. If not provided, the surface will be appended to the end of the list.

  • is_stop (bool, optional) – Indicates if the surface is the aperture.

  • material (str, optional) – The material of the surface. Default is ‘air’.

  • **kwargs – Additional keyword arguments for surface-specific parameters such as radius, conic, dx, dy, rx, ry, rz, aperture, bsdf, x, y, z.

Raises:
  • ValueError – If a new surface is provided and no index is given.

  • IndexError – If the index is out of bounds for insertion, or negative.

build_paraxial_path() ParaxialPath[source]#

Build the shared folded-path metadata for the current geometry.

The path is a per-operation snapshot – geometry is mutable, so it is rebuilt rather than cached. High-level operations should build it once and pass it through their call chain instead of re-deriving frames, directions and parity in each consumer.

clear()[source]#

Clears the list of surfaces.

property conic#

conic constant of all surfaces

Type:

be.array

flip(start_index: int = 0, end_index: int = 0)[source]#

Flips a segment of the surfaces in the group.

The function will swap the materials on the Object and Image surface if both start_index and end_index are zero. Subgroups can be swapped by passing the index of the first surface and the index of the surface after the last surface of the group (standard Python slicing). Note that only “sensible” results are obtained when the material before and after the subgroup is the same (for example, air).

Parameters:
  • start_index (int, optional) – The starting index of the segment of surfaces to flip. Defaults to 0 (include object surface).

  • end_index (int, optional) – The ending index (exclusive for positive, inclusive for negative slice behavior) of the segment of surfaces to flip. Defaults to 0 (up to, and including, the image surface).

Raises:
  • RuntimeError – If either start_index or end_index is zero, but not both.

  • UnsupportedParaxialGeometryError – If the beam path is folded off global +z (or entered along another direction), before any surface order, material, coordinate or thickness is touched. Flipping derives new positions and thicknesses from global z differences, which is meaningless on a folded chain. This guard protects the direct SurfaceGroup.flip() API as well as OpticUpdater.flip().

classmethod from_dict(data)[source]#

Create a surface group from a dictionary.

Parameters:

data (dict) – The dictionary to create the surface group from.

Returns:

The surface group created from the dictionary.

Return type:

SurfaceGroup

get_thickness(surface_number)[source]#

Calculate the thickness between two surfaces.

Parameters:

surface_number (int) – The index of the first surface.

Returns:

The thickness between the two surfaces.

Return type:

float

property global_z_positions#

global z coordinates of the surface vertices.

Unlike positions this is a real-space coordinate, never an unfolded one. Use it for anything that has to place something in the global frame (drawing limits, reference spheres); use positions for first-order calculations.

Type:

np.array

property global_z_span#

the extent of the surface vertices in global z.

The old (pre-fold-aware) meaning of total_track: the span of the global z coordinates of the physical surface vertices. For straight systems this equals total_track; for folded systems it is the bounding extent in z, not a track length along the beam.

Type:

float

index(value)[source]#

Return the first index of the specified surface.

property intensity#

ray intensities on all surfaces

Type:

np.array

n(wavelength)[source]#

Get the refractive indices of the surfaces.

Parameters:

wavelength (float or str, optional) – The wavelength for which to calculate the refractive indices.

Returns:

The refractive indices of the surfaces.

Return type:

numpy.ndarray

property num_surfaces#

the number of surfaces

Type:

int

property opd#

optical path difference recorded on all surfaces

Type:

np.array

property positions#

signed unfolded axial positions of surface vertices.

The axial coordinate is the one the paraxial model is written in: a 1-D scalar coordinate along the unfolded optical axis, with each reflection reversing the direction of travel (so spacings after an odd number of mirrors are negative). While every leg of the beam path runs along ±z entered along +z – straight systems and mirrors at normal incidence – that is exactly the global z of each vertex, and this property returns it unchanged.

A mirror that folds the beam off the z axis (or an entry along any other direction, including -z) breaks that equivalence: two vertices on opposite sides of a 90° fold can share a z, so their spacing would read as zero. For those systems the coordinate is continued as signed cumulative vertex-to-vertex path length along the beam, which is what the surrounding first-order machinery – pupil locations, paraxial ray heights, solves – needs to stay correct through a fold.

This is an unfolded axial scalar, never a Cartesian coordinate: use global_z_positions for the global z component of the vertices, and vertices_gcs for full three-dimensional vertex positions.

Type:

np.array

property radii#

radii of curvature of all surfaces

Type:

np.array

remove(index)[source]#

Remove a surface from the list of surfaces.

Cannot remove the object surface (index 0). If relative coordinate positioning is active (use_absolute_cs=False), this may trigger an update of subsequent surface positions.

Parameters:

index (int) – The index of the surface to remove.

Raises:
  • ValueError – If attempting to remove the object surface (index 0).

  • IndexError – If the index is out of bounds for the current list of surfaces.

reset()[source]#

Resets all the surfaces in the collection.

This method iterates over each surface in the collection and calls

its reset method.

set_fresnel_coatings()[source]#

Set Fresnel coatings on all surfaces in the group.

property stop_index#

the index of the aperture stop surface

Type:

int

property surfaces#
to_dict()[source]#

Convert the surface group to a dictionary.

Returns:

The surface group as a dictionary.

Return type:

dict

property total_track#

the span of the unfolded signed axial surface coordinates.

This is the extent of positions over the physical surfaces (object excluded) – the track length of the scalar paraxial system. For straight systems it equals the global-z span. For a folded system it is the span along the unfolded axis (the length the equivalent unfolded system would have), which is what the total_track optimization operand constrains. Use global_z_span for the extent of the vertices in global z.

Type:

float

trace(rays, skip=0, record=True)[source]#

Trace the given rays through the surfaces.

Parameters:
  • rays (BaseRays) – List of rays to be traced.

  • skip (int, optional) – Number of surfaces to skip before tracing. Defaults to 0.

  • record (bool, optional) – Whether to store per-surface snapshots of the ray state (positions, directions, intensity, OPD). The snapshots feed analyses and visualization but keep eight full-size arrays alive per surface; pass False when only the rays returned at the image are needed. Defaults to True.

property u#

paraxial ray angles on all surfaces

Type:

np.array

property uses_polarization#

True if any surface uses polarization, False otherwise

Type:

bool

property vertices_gcs#

full 3-D surface vertex positions in global coordinates.

Shape (num_surfaces, 3). Use this whenever a consumer needs a real-space point; positions is an unfolded axial scalar and global_z_positions is only the z component of these vertices.

Type:

np.array

property x#

x intersection points on all surfaces

Type:

np.array

property y#

y intersection points on all surfaces

Type:

np.array

property z#

z intersection points on all surfaces

Type:

np.array