Coverage for rta_to_lstchain_formator/utils/coordinates.py: 45%
59 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-25 05:21 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-25 05:21 +0000
1from collections import OrderedDict
3import astropy.units as u
4import numpy as np
5from astropy.coordinates import (
6 AltAz,
7 BaseCoordinateFrame,
8 BaseRepresentation,
9 CartesianRepresentation,
10 CoordinateAttribute,
11 EarthLocation,
12 EarthLocationAttribute,
13 QuantityAttribute,
14 SkyCoord,
15 TimeAttribute,
16)
17from astropy.time import Time
18from numpy import broadcast_arrays
21# copied from https://github.com/cta-observatory/ctapipe/blob/v0.19.2/ctapipe/coordinates/representation.py#L13
22# to avoid dependency on entire ctapipe
23class PlanarRepresentation(BaseRepresentation):
24 """
25 Representation of a point in a 2D plane.
26 This is essentially a copy of the Cartesian representation used
27 in astropy.
29 Parameters
30 ----------
32 x, y : `~astropy.units.Quantity`
33 The x and y coordinates of the point(s). If ``x`` and ``y``have
34 different shapes, they should be broadcastable.
36 copy : bool, optional
37 If True arrays will be copied rather than referenced.
39 """
41 attr_classes = OrderedDict([("x", u.Quantity), ("y", u.Quantity)])
43 def __init__(self, x, y, copy=True, **kwargs):
44 if x is None or y is None:
45 raise ValueError("x and y are required to instantiate CartesianRepresentation")
47 if not isinstance(x, self.attr_classes["x"]):
48 raise TypeError("x should be a {}".format(self.attr_classes["x"].__name__))
50 if not isinstance(y, self.attr_classes["y"]):
51 raise TypeError("y should be a {}".format(self.attr_classes["y"].__name__))
53 x = self.attr_classes["x"](x, copy=copy)
54 y = self.attr_classes["y"](y, copy=copy)
56 if not (x.unit.physical_type == y.unit.physical_type):
57 raise u.UnitsError("x and y should have matching physical types")
59 try:
60 x, y = broadcast_arrays(x, y, subok=True)
61 except ValueError:
62 raise ValueError("Input parameters x and y cannot be broadcast")
64 self._x = x
65 self._y = y
66 self._differentials = {}
68 @property
69 def x(self):
70 """
71 The x component of the point(s).
72 """
73 return self._x
75 @property
76 def y(self):
77 """
78 The y component of the point(s).
79 """
80 return self._y
82 @property
83 def xy(self):
84 return u.Quantity((self._x, self._y))
86 @classmethod
87 def from_cartesian(cls, cartesian):
88 return cls(x=cartesian.x, y=cartesian.y)
90 def to_cartesian(self):
91 return CartesianRepresentation(x=self._x, y=self._y, z=0 * self._x.unit)
93 @property
94 def components(self):
95 return "x", "y"
98# Copied from https://github.com/cta-observatory/ctapipe/blob/v0.19.2/ctapipe/coordinates/camera_frame.py#L44
99# to avoid dependency on entire ctapipe
100class CameraFrame(BaseCoordinateFrame):
101 """
102 Camera coordinate frame.
104 The camera frame is a 2d cartesian frame,
105 describing position of objects in the focal plane of the telescope.
107 The frame is defined as in H.E.S.S., starting at the horizon,
108 the telescope is pointed to magnetic north in azimuth and then up to zenith.
110 Now, x points north and y points west, so in this orientation, the
111 camera coordinates line up with the CORSIKA ground coordinate system.
113 MAGIC and FACT use a different camera coordinate system:
114 Standing at the dish, looking at the camera, x points right, y points up.
115 To transform MAGIC/FACT to ctapipe, do x' = -y, y' = -x.
117 Attributes
118 ----------
120 focal_length : u.Quantity[length]
121 Focal length of the telescope as a unit quantity (usually meters)
122 rotation : u.Quantity[angle]
123 Rotation angle of the camera (0 deg in most cases)
124 telescope_pointing : SkyCoord[AltAz]
125 Pointing direction of the telescope as SkyCoord in AltAz
126 obstime : Time
127 Observation time
128 location : EarthLocation
129 location of the telescope
130 """
132 default_representation = PlanarRepresentation
134 focal_length = QuantityAttribute(default=0, unit=u.m)
135 rotation = QuantityAttribute(default=0 * u.deg, unit=u.rad)
136 telescope_pointing = CoordinateAttribute(frame=AltAz, default=None)
138 obstime = TimeAttribute(default=None)
139 location = EarthLocationAttribute(default=None)
142# Copied from https://github.com/cta-observatory/ctapipe_io_lst/blob/v0.22.6/src/ctapipe_io_lst/constants.py#L30
143# to avoid dependency on entire lstchain
144#: location of lst-1 as `~astropy.coordinates.EarthLocation`
145#: Taken from Abelardo's Coordinates of LST-1 & MAGIC presentation
146#: https://redmine.cta-observatory.org/attachments/65827
147LST1_LOCATION = EarthLocation(
148 lon=-17.89149701 * u.deg,
149 lat=28.76152611 * u.deg,
150 # height of central pin + distance from pin to elevation axis
151 height=2184 * u.m + 15.883 * u.m,
152)
155# copied from https://github.com/cta-observatory/cta-lstchain/blob/v0.10.7/lstchain/reco/utils.py#L608
156# to avoid dependency on entire lstchain
157def clip_alt(alt):
158 """
159 Make sure altitude is not larger than 90 deg (it happens in some MC files for zenith=0),
160 to keep astropy happy
161 """
162 return np.clip(alt, -90.0 * u.deg, 90.0 * u.deg)
165# copied from https://github.com/cta-observatory/cta-lstchain/blob/v0.10.7/lstchain/reco/utils.py#L316
166# to avoid dependency on entire lstchain
167def sky_to_camera(alt, az, focal, pointing_alt, pointing_az):
168 """
169 Coordinate transform from aky position (alt, az) (in angles)
170 to camera coordinates (x, y) in distance.
172 Parameters
173 ----------
174 alt: astropy Quantity
175 az: astropy Quantity
176 focal: astropy Quantity
177 pointing_alt: pointing altitude in angle unit
178 pointing_az: pointing altitude in angle unit
180 Returns
181 -------
182 camera frame: `astropy.coordinates.sky_coordinate.SkyCoord`
183 """
184 pointing_direction = SkyCoord(
185 alt=clip_alt(pointing_alt),
186 az=pointing_az,
187 frame=AltAz(location=LST1_LOCATION, obstime=Time("2018-11-01T02:00")),
188 )
190 camera_frame = CameraFrame(focal_length=focal, telescope_pointing=pointing_direction)
192 event_direction = SkyCoord(
193 alt=clip_alt(alt), az=az, frame=AltAz(location=LST1_LOCATION, obstime=Time("2018-11-01T02:00"))
194 )
196 camera_pos = event_direction.transform_to(camera_frame)
198 return camera_pos