class DetectorFrame(ITRS): """A coordinate frames to visualize triangulation rings from pairs of gravitational-wave detectors.""" site_1 = EarthLocationAttribute() site_2 = EarthLocationAttribute() default_representation = SphericalRepresentation
def __init__(self, *args, **kwargs): loc = kwargs.get('location', None) if isinstance(loc, MoonLocation): frame_transform_graph.frame_attributes['location'] = MoonLocationAttribute(default=None) elif isinstance(loc, EarthLocation): frame_transform_graph.frame_attributes['location'] = \ EarthLocationAttribute(default=None) super().__init__(*args, **kwargs) # Set the graph to its default frame_transform_graph.frame_attributes['location'] = EarthLocationAttribute(default=None)
class CameraFrame(BaseCoordinateFrame): ''' Astropy CoordinateFrame representing coordinates in the CameraPlane Attributes ---------- pointing_direction: astropy.coordinates.AltAz The pointing direction of the telescope obstime: astropy.Time The timestamp of the observation, only needed to directly transform to Equatorial coordinates, transforming to AltAz does not need this. location: astropy.coordinates.EarthLocation The location of the observer, only needed to directly transform to Equatorial coordinates, transforming to AltAz does not need this, default is FACT's location rotated: bool True means x points right and y points up when looking on the camera from the dish, which is the efinition of FACT-Tools >= 1.0 and Mars. False means x points up and y points left, which is definition in the original FACTPixelMap file. ''' default_representation = PlanarRepresentation pointing_direction = CoordinateAttribute(frame=AltAz, default=None) obstime = TimeAttribute(default=None) location = EarthLocationAttribute(default=LOCATION) rotated = Attribute(default=True)
class TelescopeFrame(BaseCoordinateFrame): """ Telescope coordinate frame. A Frame using a UnitSphericalRepresentation. This is basically the same as a HorizonCoordinate, but the origin is at the telescope's pointing direction. This is used to specify coordinates in the field of view of a telescope that is independent of the optical properties of the telescope. ``fov_lon`` is aligned with azimuth and ``fov_lat`` is aligned with altitude of the horizontal coordinate frame as implemented in ``astropy.coordinates.AltAz``. This is what astropy calls a SkyOffsetCoordinate. Attributes ---------- telescope_pointing: SkyCoord[AltAz] Coordinate of the telescope pointing in AltAz obstime: Tiem Observation time location: EarthLocation Location of the telescope """ frame_specific_representation_info = { UnitSphericalRepresentation: [ RepresentationMapping("lon", "fov_lon"), RepresentationMapping("lat", "fov_lat"), ] } default_representation = UnitSphericalRepresentation telescope_pointing = CoordinateAttribute(default=None, frame=AltAz) obstime = TimeAttribute(default=None) location = EarthLocationAttribute(default=None) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # make sure telescope coordinate is in range [-180°, 180°] if isinstance(self._data, UnitSphericalRepresentation): self._data.lon.wrap_angle = Angle(180, unit=u.deg)
class NominalFrame(BaseCoordinateFrame): """ Nominal coordinate frame. A Frame using a UnitSphericalRepresentation. This is basically the same as a HorizonCoordinate, but the origin is at an arbitray position in the sky. This is what astropy calls a SkyOffsetCoordinate If the telescopes are in divergent pointing, this Frame can be used to transform to a common system. Attributes ---------- origin: SkyCoord[AltAz] Origin of this frame as a HorizonCoordinate obstime: Tiem Observation time location: EarthLocation Location of the telescope """ frame_specific_representation_info = { UnitSphericalRepresentation: [ RepresentationMapping("lon", "fov_lon"), RepresentationMapping("lat", "fov_lat"), ] } default_representation = UnitSphericalRepresentation origin = CoordinateAttribute(default=None, frame=AltAz) obstime = TimeAttribute(default=None) location = EarthLocationAttribute(default=None) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # make sure telescope coordinate is in range [-180°, 180°] if isinstance(self._data, UnitSphericalRepresentation): self._data.lon.wrap_angle = Angle(180, unit=u.deg)
class CameraFrame(BaseCoordinateFrame): """ Camera coordinate frame. The camera frame is a 2d cartesian frame, describing position of objects in the focal plane of the telescope. The frame is defined as in H.E.S.S., starting at the horizon, the telescope is pointed to magnetic north in azimuth and then up to zenith. Now, x points north and y points west, so in this orientation, the camera coordinates line up with the CORSIKA ground coordinate system. MAGIC and FACT use a different camera coordinate system: Standing at the dish, looking at the camera, x points right, y points up. To transform MAGIC/FACT to ctapipe, do x' = -y, y' = -x. Attributes ---------- focal_length : u.Quantity[length] Focal length of the telescope as a unit quantity (usually meters) rotation : u.Quantity[angle] Rotation angle of the camera (0 deg in most cases) telescope_pointing : SkyCoord[AltAz] Pointing direction of the telescope as SkyCoord in AltAz obstime : Time Observation time location : EarthLocation location of the telescope """ default_representation = PlanarRepresentation focal_length = QuantityAttribute(default=0, unit=u.m) rotation = QuantityAttribute(default=0 * u.deg, unit=u.rad) telescope_pointing = CoordinateAttribute(frame=AltAz, default=None) obstime = TimeAttribute(default=None) location = EarthLocationAttribute(default=None)
class TelescopeFrame(BaseCoordinateFrame): ''' Telescope coordinate frame. A Frame using a UnitSphericalRepresentation. This is basically the same as a HorizonCoordinate, but the origin is at the telescope's pointing direction. This is what astropy calls a SkyOffsetCoordinate Attributes ---------- telescope_pointing: SkyCoord[HorizonFrame] Coordinate of the telescope pointing in HorizonFrame obstime: Tiem Observation time location: EarthLocation Location of the telescope ''' frame_specific_representation_info = { UnitSphericalRepresentation: [ RepresentationMapping('lon', 'delta_az'), RepresentationMapping('lat', 'delta_alt'), ] } default_representation = UnitSphericalRepresentation telescope_pointing = CoordinateAttribute(default=None, frame=HorizonFrame) obstime = TimeAttribute(default=None) location = EarthLocationAttribute(default=None) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # make sure telescope coordinate is in range [-180°, 180°] if isinstance(self._data, UnitSphericalRepresentation): self._data.lon.wrap_angle = Angle(180, unit=u.deg)
def transform_to(self, frame, merge_attributes=True): # a modified version of the corresponding astropy function. from astropy.coordinates.errors import ConvertError frame_kwargs = {} # Frame name (string) or frame class? Coerce into an instance. try: frame = _get_frame_class(frame)() except Exception: pass if isinstance(frame, SkyCoord): frame = frame.frame # Change to underlying coord frame instance if isinstance(frame, BaseCoordinateFrame): new_frame_cls = frame.__class__ # Get frame attributes, allowing defaults to be overridden by # explicitly set attributes of the source if ``merge_attributes``. for attr in frame_transform_graph.frame_attributes: self_val = getattr(self, attr, None) frame_val = getattr(frame, attr, None) if (frame_val is not None and not (merge_attributes and frame.is_frame_attr_default(attr))): frame_kwargs[attr] = frame_val elif (self_val is not None and not self.is_frame_attr_default(attr)): frame_kwargs[attr] = self_val elif frame_val is not None: frame_kwargs[attr] = frame_val else: raise ValueError('Transform `frame` must be a frame name, class, or instance') # Hacky solution here -- Frames other than LunarTopo cannot accept a MoonLocation object # and can get confused by it. Do not pass along `location` unless certain it will work. moonloc_incompatible = not isinstance(frame, LunarTopo) graph_attrs = frame_transform_graph.frame_attributes if hasattr(self, 'location'): loc = getattr(self, 'location') if isinstance(loc, MoonLocation): if moonloc_incompatible: frame_kwargs.pop('location') elif 'location' in graph_attrs.keys() \ and isinstance(graph_attrs['location'], MoonLocationAttribute): frame_transform_graph.frame_attributes['location'] = \ EarthLocationAttribute(default=None) # Get the composite transform to the new frame trans = frame_transform_graph.get_transform(self.frame.__class__, new_frame_cls) if trans is None: raise ConvertError('Cannot transform from {} to {}' .format(self.frame.__class__, new_frame_cls)) # Make a generic frame which will accept all the frame kwargs that # are provided and allow for transforming through intermediate frames # which may require one or more of those kwargs. generic_frame = GenericFrame(frame_kwargs) # Do the transformation, returning a coordinate frame of the desired # final type (not generic). new_coord = trans(self.frame, generic_frame) # Finally make the new SkyCoord object from the `new_coord` and # remaining frame_kwargs that are not frame_attributes in `new_coord`. for attr in (set(new_coord.get_frame_attr_names()) & set(frame_kwargs.keys())): frame_kwargs.pop(attr) return self.__class__(new_coord, **frame_kwargs)