Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 99 additions & 27 deletions optika/systems/_sequential.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ def grid_input(self) -> optika.vectors.ObjectVectorArray:
"""
The input grid to sample with rays.

The components of this grid are interpreted as cell vertices,
and the rays of the system are traced at the corresponding cell
centers.

This grid is simultaneously projected onto both the field stop and the
pupil stop.

Expand Down Expand Up @@ -738,8 +742,32 @@ def _calc_rayfunction_input(

@functools.cached_property
def _rayfunction_input(self) -> optika.rays.RayFunctionArray:
return self._calc_rayfunction_input(
grid_input=self.grid_input,
result = self._calc_rayfunction_input(
grid_input=self._grid_input_centers,
normalized_field=False,
normalized_pupil=False,
)
result.inputs = self._grid_input_physical
return result

@functools.cached_property
def _grid_input_physical(self) -> optika.vectors.ObjectVectorArray:
"""The vertices of :attr:`grid_input` in physical units."""
return self._denormalize_grid(
grid=self.grid_input,
)

@functools.cached_property
def _grid_input_centers(self) -> optika.vectors.ObjectVectorArray:
"""
The cell centers of :attr:`grid_input` in physical units.

The components of :attr:`grid_input` are interpreted as cell vertices,
and the rays of the system are traced at the corresponding cell
centers.
"""
return self._grid_input_physical.cell_centers(
axis=self.axis_wavelength_ + self.axis_field_ + self.axis_pupil_,
)

def raytrace(
Expand Down Expand Up @@ -902,6 +930,11 @@ def rayfunction_default(self) -> optika.rays.RayFunctionArray:
Computes the rays in local coordinates at the last surface in the system
as a function of input wavelength and position using :attr:`grid_input`.

The components of :attr:`grid_input` are interpreted as cell vertices,
and the rays are traced at the corresponding cell centers, so the
inputs of this rayfunction are defined on cell vertices while the
outputs are defined on cell centers.

This property is cached to increase performance.
If :attr:`grid_input` is updated, the cache must be cleared with
``del system.rayfunction_default`` before calling this property.
Expand Down Expand Up @@ -1130,16 +1163,16 @@ def distortion(
Parameters
----------
wavelength
The wavelengths of the input rays.
The vertices of the wavelength grid.
If :obj:`None` (the default), ``self.grid_input.wavelength``
will be used.
field
The field positions of the input rays, in either normalized or
The vertices of the field grid, in either normalized or
physical units.
If :obj:`None` (the default), ``self.grid_input.field``
will be used.
pupil
The pupil positions of the input rays, in either normalized or
The vertices of the pupil grid, in either normalized or
physical units.
If :obj:`None` (the default), ``self.grid_input.pupil``
will be used.
Expand All @@ -1165,11 +1198,15 @@ def distortion(
"fitting a distortion model requires the wavelength grid "
"to vary along its own logical axis."
)

grid = rays.inputs.cell_centers(
axis=axis_wavelength + axis_field,
)
(axis_wavelength,) = axis_wavelength

coordinates_scene = na.SpectralPositionalVectorArray(
wavelength=rays.inputs.wavelength,
position=rays.inputs.field,
wavelength=grid.wavelength,
position=grid.field,
)

unvignetted = rays.outputs.unvignetted
Expand Down Expand Up @@ -1215,16 +1252,16 @@ def vignetting(
Parameters
----------
wavelength
The wavelengths of the input rays.
The vertices of the wavelength grid.
If :obj:`None` (the default), ``self.grid_input.wavelength``
will be used.
field
The field positions of the input rays, in either normalized or
The vertices of the field grid, in either normalized or
physical units.
If :obj:`None` (the default), ``self.grid_input.field``
will be used.
pupil
The pupil positions of the input rays, in either normalized or
The vertices of the pupil grid, in either normalized or
physical units.
If :obj:`None` (the default), ``self.grid_input.pupil``
will be used.
Expand All @@ -1250,11 +1287,15 @@ def vignetting(
"fitting a vignetting model requires the wavelength grid "
"to vary along its own logical axis."
)

grid = rays.inputs.cell_centers(
axis=axis_wavelength + axis_field,
)
(axis_wavelength,) = axis_wavelength

coordinates_scene = na.SpectralPositionalVectorArray(
wavelength=rays.inputs.wavelength,
position=rays.inputs.field,
wavelength=grid.wavelength,
position=grid.field,
)

unvignetted = rays.outputs.unvignetted
Expand Down Expand Up @@ -1293,21 +1334,23 @@ def _rayfunction_and_axes(
Trace the given grids through this system and return the resulting
rays along with the normalized wavelength, field, and pupil axes.

The grids are interpreted as cell vertices, and the rays are traced
at the corresponding cell centers, so that the inputs of the
resulting rayfunction are defined on cell vertices while the outputs
are defined on cell centers.
If all of the grids are :obj:`None`, :attr:`rayfunction_default` and
the normalized axes of :attr:`grid_input` are used.
Otherwise, the rays are computed with :meth:`rayfunction` and the
axes are inferred from the resulting inputs, so that grids left as
the normalized axes of :attr:`grid_input` are used, and grids left as
:obj:`None` inherit the corresponding component of :attr:`grid_input`.

Parameters
----------
wavelength
The wavelengths of the input rays.
The vertices of the wavelength grid.
field
The field positions of the input rays, in either normalized or
The vertices of the field grid, in either normalized or
physical units.
pupil
The pupil positions of the input rays, in either normalized or
The vertices of the pupil grid, in either normalized or
physical units.
normalized_field
A boolean flag indicating whether the `field` parameter is given
Expand All @@ -1322,28 +1365,53 @@ def _rayfunction_and_axes(
axis_field = self.axis_field_
axis_pupil = self.axis_pupil_
else:
rays = self.rayfunction(
if wavelength is None:
wavelength = self.grid_input.wavelength
if field is None:
field = self.grid_input.field
if pupil is None:
pupil = self.grid_input.pupil

grid = optika.vectors.ObjectVectorArray(
wavelength=wavelength,
field=field,
pupil=pupil,
normalized_field=normalized_field,
normalized_pupil=normalized_pupil,
)

axis_wavelength = self._normalize_axis_wavelength(
axis_wavelength=None,
wavelength=rays.inputs.wavelength,
wavelength=grid.wavelength,
)
axis_field = self._normalize_axis_field(
axis_field=None,
axis_wavelength=axis_wavelength,
field=rays.inputs.field,
field=grid.field,
)
axis_pupil = self._normalize_axis_pupil(
axis_pupil=None,
axis_field=axis_field,
axis_wavelength=axis_wavelength,
pupil=rays.inputs.pupil,
pupil=grid.pupil,
)

grid = self._denormalize_grid(
grid=grid,
normalized_field=normalized_field,
normalized_pupil=normalized_pupil,
)

grid_centers = grid.cell_centers(
axis=axis_wavelength + axis_field + axis_pupil,
)

rays = self.rayfunction(
wavelength=grid_centers.wavelength,
field=grid_centers.field,
pupil=grid_centers.pupil,
normalized_field=False,
normalized_pupil=False,
)
rays.inputs = grid
return rays, axis_wavelength, axis_field, axis_pupil

def plot(
Expand Down Expand Up @@ -1447,7 +1515,7 @@ def spot_diagram(
cmap
The colormap used to map scalar data to colors.
"""
grid = self.grid_input
grid = self._grid_input_centers

wavelength = na.as_named_array(grid.wavelength)
field = grid.field
Expand Down Expand Up @@ -1511,7 +1579,7 @@ def spot_diagram(
ax=ax,
s=s,
where=rays.unvignetted,
c=self.grid_input.wavelength.value,
c=na.value(wavelength),
colorizer=colorizer,
)

Expand All @@ -1523,7 +1591,7 @@ def spot_diagram(
na.plt.set_xlabel(f"$x$ ({position.x.unit:latex_inline})", ax=ax_lower)
na.plt.set_ylabel(f"$y$ ({position.y.unit:latex_inline})", ax=ax_left)

angle = self.rayfunction_default.inputs.field
angle = field

angle_x = angle.x
angle_y = angle.y
Expand Down Expand Up @@ -1829,6 +1897,10 @@ class SequentialSystem(
"""
The input grid to sample with rays.

The components of this grid are interpreted as cell vertices,
and the rays of the system are traced at the corresponding cell
centers.

This grid is simultaneously projected onto both the field stop and the
pupil stop.

Expand Down
Loading