Source code for optika.sags._toroidal
import dataclasses
import numpy as np
import astropy.units as u
import named_arrays as na
import optika
from ._abc import AbstractSag
__all__ = [
"ToroidalSag",
]
[docs]
@dataclasses.dataclass(eq=False, repr=False)
class ToroidalSag(
AbstractSag,
):
"""
A toroidal sag profile.
"""
radius: u.Quantity | na.AbstractScalar = np.inf * u.mm
"""The minor radius of this toroidal surface."""
radius_of_rotation: u.Quantity | na.AbstractScalar = 0 * u.mm
"""The major radius of this toroidal surface."""
@property
def shape(self) -> dict[str, int]:
return na.broadcast_shapes(
optika.shape(self.radius),
optika.shape(self.radius_of_rotation),
optika.shape(self.transformation),
optika.shape(self.parameters_slope_error),
optika.shape(self.parameters_roughness),
optika.shape(self.parameters_microroughness),
)
def __call__(
self,
position: na.AbstractCartesian3dVectorArray,
) -> na.AbstractScalar:
c = 1 / self.radius
r = self.radius_of_rotation
transformation = self.transformation
if transformation is not None:
position = transformation.inverse(position)
shape = na.shape_broadcasted(position, c, r)
position = na.broadcast_to(position, shape)
c = na.broadcast_to(c, shape)
r = na.broadcast_to(r, shape)
x2 = np.square(position.x)
y2 = np.square(position.y)
zy = c * y2 / (1 + np.sqrt(1 - np.square(c) * y2))
z = r - np.sqrt(np.square(r - zy) - x2)
return z
[docs]
def normal(
self,
position: na.AbstractCartesian3dVectorArray,
) -> na.AbstractCartesian3dVectorArray:
c = 1 / self.radius
r = self.radius_of_rotation
transformation = self.transformation
if transformation is not None:
position = transformation.inverse(position)
shape = na.shape_broadcasted(position, c, r)
position = na.broadcast_to(position, shape)
c = na.broadcast_to(c, shape)
r = na.broadcast_to(r, shape)
x2 = np.square(position.x)
y2 = np.square(position.y)
c2 = np.square(c)
g = np.sqrt(1 - c2 * y2)
zy = c * y2 / (1 + g)
f = np.sqrt(np.square(r - zy) - x2)
dzdx = position.x / f
dzydy = c * position.y / g
dzdy = (r - zy) * dzydy / f
result = na.Cartesian3dVectorArray(
x=dzdx,
y=dzdy,
z=-1 * u.dimensionless_unscaled,
)
return result / result.length