diff --git a/optika/_tests/test_systems.py b/optika/_tests/test_systems.py index 3f4d256..1a554b4 100644 --- a/optika/_tests/test_systems.py +++ b/optika/_tests/test_systems.py @@ -257,6 +257,7 @@ def test_rayfunction_default(self, a: optika.systems.AbstractSequentialSystem): axis_pixel=na.Cartesian2dVectorArray("detector_x", "detector_y"), timedelta_exposure=1 * u.s, num_pixel=na.Cartesian2dVectorArray(128, 128), + transformation=na.transformations.Cartesian3dTranslation(z=1 * u.mm), is_field_stop=True, ) diff --git a/optika/sensors/_sensors.py b/optika/sensors/_sensors.py index 4c54c07..9388d2e 100644 --- a/optika/sensors/_sensors.py +++ b/optika/sensors/_sensors.py @@ -100,7 +100,7 @@ def readout( Parameters ---------- rays - A set of incident rays in global coordinates to measure. + A set of incident rays in local coordinates to measure. timedelta The exposure time of the measurement. If :obj:`None` (the default), the value in :attr:`timedelta_exposure` @@ -114,9 +114,6 @@ def readout( if timedelta is None: timedelta = self.timedelta_exposure - if self.transformation is not None: - rays = self.transformation.inverse(rays) - where = where & rays.unvignetted rays = dataclasses.replace( diff --git a/optika/systems.py b/optika/systems.py index 7e548ab..b3b564c 100644 --- a/optika/systems.py +++ b/optika/systems.py @@ -603,8 +603,8 @@ def raytrace( ) -> optika.rays.RayFunctionArray: """ Given the wavelength, field position, and pupil position of some input - rays, trace those rays through the system and return the result, - including all intermediate rays. + rays, trace those rays through the system and return the result in + global coordinates, including all intermediate rays. Parameters ---------- @@ -634,7 +634,8 @@ def raytrace( See Also -------- - rayfunction : Similar to `raytrace` except it only returns the rays at the last surface. + rayfunction : Similar to `raytrace` except it only returns the rays at + the last surface in local coordinates. """ if axis is None: @@ -683,7 +684,7 @@ def rayfunction( """ Given the wavelength, field position, and pupil position of some input rays, trace those rays through the system and return the resulting - rays at the last surface. + rays in local coordinates at the last surface. Parameters ---------- @@ -710,7 +711,8 @@ def rayfunction( See Also -------- - raytrace : Similar to `rayfunction` except it computes all the intermediate rays. + raytrace : Similar to `rayfunction` except it computes all the + intermediate rays, and it returns results in global coordinates. """ axis = "_dummy" @@ -723,13 +725,25 @@ def rayfunction( normalized_field=normalized_field, normalized_pupil=normalized_pupil, ) - return raytrace[{axis: ~0}] + rayfunction = raytrace[{axis: ~0}] + rays = rayfunction.outputs + + if self.sensor.transformation is not None: + rays = self.sensor.transformation.inverse(rays) + + rayfunction.outputs = rays + + return rayfunction @functools.cached_property def rayfunction_default(self) -> optika.rays.RayFunctionArray: """ - Computes the rays at the last surface in the system as a function of - input wavelength and position using :attr:`grid_input`. + 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`. + + 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 property. """ return self.rayfunction()