Source code for optika.sags._abc
import abc
import dataclasses
import numpy as np
import astropy.units as u
import named_arrays as na
import optika
__all__ = [
"AbstractSag",
]
[docs]
@dataclasses.dataclass(eq=False, repr=False)
class AbstractSag(
optika.mixins.Printable,
optika.mixins.Transformable,
optika.mixins.Shaped,
optika.propagators.AbstractRayPropagator,
):
"""
Base class for all types of sag profiles.
"""
transformation: None | na.transformations.AbstractTransformation = (
dataclasses.field(default=None, kw_only=True)
)
"""
The transformation between the surface coordinate system and the sag
coordinate system.
"""
parameters_slope_error: None | optika.metrology.SlopeErrorParameters = (
dataclasses.field(default=None, kw_only=True)
)
"""The slope error parameters for this sag profile."""
parameters_roughness: None | optika.metrology.RoughnessParameters = (
dataclasses.field(default=None, kw_only=True)
)
"""The roughness parameters for this sag profile."""
parameters_microroughness: None | optika.metrology.RoughnessParameters = (
dataclasses.field(default=None, kw_only=True)
)
"""The microroughness parameters for this sag profile."""
@abc.abstractmethod
def __call__(
self,
position: na.AbstractCartesian3dVectorArray,
) -> na.AbstractScalar:
"""
Check if the given positions are inside the aperture.
Parameters
----------
position
The points to check if inside the aperture.
The :math:`z` coordinate is ignored.
"""
[docs]
@abc.abstractmethod
def normal(
self,
position: na.AbstractCartesian3dVectorArray,
) -> na.AbstractCartesian3dVectorArray:
"""
The vector perpendicular to the surface at the given position.
Parameters
----------
position
The location on the surface to evaluate the normal vector
"""
[docs]
def intercept(
self,
rays: optika.rays.AbstractRayVectorArray,
) -> optika.rays.RayVectorArray:
"""
A set of new rays with the same direction as the input rays,
but with the :attr:`optika.rays.RayVectorArray.position` updated to
their interception point with this sag function.
Parameters
----------
rays
input rays that will intercept this sag function
"""
def line(t: na.AbstractScalar) -> na.Cartesian3dVectorArray:
return rays.position + rays.direction * t
def func(t: na.AbstractScalar) -> na.AbstractScalar:
a = line(t)
z = self(a)
return a.z - z
t_intercept = na.optimize.root_secant(
function=func,
guess=0 * u.mm,
min_step_size=1e-6 * u.mm,
)
result = rays.copy_shallow()
result.position = line(t_intercept)
return result
[docs]
def propagate_rays(
self,
rays: optika.rays.AbstractRayVectorArray,
) -> optika.rays.AbstractRayVectorArray:
result = self.intercept(rays)
displacement = result.position - rays.position
f = np.exp(-result.attenuation * displacement.length)
result.intensity = f * result.intensity
return result