Source code for coordio.positioner
from __future__ import annotations
from typing import TYPE_CHECKING
import numpy
from . import calibration, conv, defaults
from .coordinate import Coordinate, Coordinate2D, verifySite
from .exceptions import CoordIOError
if TYPE_CHECKING:
from .site import Site
[docs]class PositionerBase(Coordinate2D):
"""A representation of Positioner coordinates. Alpha/Beta coordinates
in degrees.
When converting from tangent coordinates,
Robot's are always "right handed" with alpha in [0, 360], beta in [0, 180]
Parameters
------------
value : numpy.ndarray
A Nx2 array with columns [alpha, beta] in degrees
site : `.Site`
mandatory parameter
holeID : str
valid identifier, one of calibration.VALID_HOLE_IDS
"""
__extra_params__ = ["site", "holeID"]
__warn_arrays__ = ["positioner_warn"]
__fiber_type__ = None # overridden by subclasses
# For typing.
positioner_warn: numpy.ndarray
holeID: str
site: Site
def __new__(cls, value, **kwargs):
verifySite(kwargs, strict=False)
holeID = kwargs.get("holeID", None)
if holeID is None:
raise CoordIOError("Must specify holeID for Positioner Coords")
if holeID not in calibration.VALID_HOLE_IDS:
raise CoordIOError("Must be valid holeID for Positioner Coords")
if isinstance(value, Coordinate):
if value.coordSysName == "Tangent":
if holeID.startswith("GFA"):
raise CoordIOError(
"Guide holeID supplied for Positioner coord"
)
# going from 3D to 2D coordsys
# initialize array
initArr = numpy.zeros((len(value), 2))
obj = super().__new__(cls, initArr, **kwargs)
obj._loadFiberData()
obj._fromTangent(value)
else:
raise CoordIOError(
'Cannot convert to Positioner from %s' % value.coordSysName
)
else:
obj = super().__new__(cls, value, **kwargs)
obj._loadFiberData()
obj._fromRaw()
if obj.__fiber_type__ not in ["Apogee", "Boss", "Metrology"]:
raise CoordIOError("valid __fiber_type__ must be specified!")
return obj
def _loadFiberData(self):
fiberData = defaults.getPositionerData(self.site.name, self.holeID)
if self.__fiber_type__ == "Metrology":
xFiber = fiberData[1]
yFiber = fiberData[2]
elif self.__fiber_type__ == "Apogee":
xFiber = fiberData[3]
yFiber = fiberData[4]
elif self.__fiber_type__ == "Boss":
xFiber = fiberData[5]
yFiber = fiberData[6]
else:
raise CoordIOError("Fiber not specified for positioner coords")
self.alphaArmLength = fiberData[0]
self.xFiber = xFiber
self.yFiber = yFiber
self.alphaOffset = fiberData[7]
self.betaOffset = fiberData[8]
def _fromTangent(self, tangentCoords):
"""Convert from tangent coords to alpha betas
"""
xTangent = tangentCoords.xProj
yTangent = tangentCoords.yProj
# this will always return a right hand orientation
alphaDeg, betaDeg, isOK = conv.tangentToPositioner(
xTangent,
yTangent,
self.xFiber,
self.yFiber,
self.alphaArmLength,
self.alphaOffset,
self.betaOffset
)
self[:, 0] = alphaDeg
self[:, 1] = betaDeg
self.positioner_warn[:] = isOK == False
self._fromRaw()
def _fromRaw(self):
# TODO: maybe not do this?
self = self % 360
[docs]class PositionerBoss(PositionerBase):
__fiber_type__ = "Boss"
[docs]class PositionerApogee(PositionerBase):
__fiber_type__ = "Apogee"
[docs]class PositionerMetrology(PositionerBase):
__fiber_type__ = "Metrology"