def test_cam_to_tel(): from ctapipe.coordinates import CameraFrame, TelescopeFrame # Coordinates in any fram can be given as a numpy array of the xyz positions # e.g. in this case the position on pixels in the camera pix_x = [1] * u.m pix_y = [1] * u.m focal_length = 15 * u.m # first define the camera frame camera_coord = CameraFrame(pix_x, pix_y, focal_length=focal_length) # then use transform to function to convert to a new system # making sure to give the required values for the conversion # (these are not checked yet) telescope_coord = camera_coord.transform_to(TelescopeFrame()) assert telescope_coord.x[0] == (1 / 15) * u.rad # check rotation camera_coord = CameraFrame(pix_x, pix_y, focal_length=focal_length) telescope_coord_rot = camera_coord.transform_to(TelescopeFrame()) assert telescope_coord_rot.y[0] - (1 / 15) * u.rad < 1e-6 * u.rad # The Transform back camera_coord2 = telescope_coord.transform_to( CameraFrame(focal_length=focal_length)) # Check separation assert camera_coord.separation_3d(camera_coord2)[0] == 0 * u.m
def test_camera_coordinate_transform(camera_name): """test conversion of the coordinates stored in a camera frame""" from ctapipe.coordinates import EngineeringCameraFrame, CameraFrame, TelescopeFrame geom = CameraGeometry.from_name(camera_name) trans_geom = geom.transform_to(EngineeringCameraFrame()) unit = geom.pix_x.unit assert np.allclose(geom.pix_x.to_value(unit), -trans_geom.pix_y.to_value(unit)) assert np.allclose(geom.pix_y.to_value(unit), -trans_geom.pix_x.to_value(unit)) # also test converting into a spherical frame: focal_length = 1.2 * u.m geom.frame = CameraFrame(focal_length=focal_length) telescope_frame = TelescopeFrame() sky_geom = geom.transform_to(telescope_frame) x = sky_geom.pix_x.to_value(u.deg) assert len(x) == len(geom.pix_x) # and test going backward from spherical to cartesian: geom_cam = sky_geom.transform_to(CameraFrame(focal_length=focal_length)) assert np.allclose(geom_cam.pix_x.to_value(unit), geom.pix_x.to_value(unit))
def test_conversion(): """ Test conversion between CameraFrame and EngineeringCameraFrame """ from ctapipe.coordinates import CameraFrame, EngineeringCameraFrame coords = SkyCoord(x=[3, 1] * u.m, y=[2, 4] * u.m, frame=CameraFrame()) for coord in coords: eng_coord = coord.transform_to(EngineeringCameraFrame()) assert eng_coord.x == -coord.y assert eng_coord.y == -coord.x back = eng_coord.transform_to(CameraFrame()) assert back.x == coord.x assert back.y == coord.y eng_coord = coord.transform_to(EngineeringCameraFrame(n_mirrors=2)) assert eng_coord.x == coord.y assert eng_coord.y == -coord.x back = eng_coord.transform_to(CameraFrame()) assert back.x == coord.x assert back.y == coord.y
def get_position_in_cam(dir_alt, dir_az, event, tel_id): """ transform position in HorizonFrame to CameraFrame Parameters ---------- dir_alt : direction altitude dir_az : direction azimuth event : event data container tel_id : telescope ID Returns ------- cam_coord : position in camera of telescope tel_id """ # pointing direction of telescope pointing_az = event.mc.tel[tel_id].azimuth_raw * u.rad pointing_alt = event.mc.tel[tel_id].altitude_raw * u.rad pointing = SkyCoord(alt=pointing_alt, az=pointing_az, frame='altaz') focal_length = event.inst.subarray.tel[tel_id].\ optics.equivalent_focal_length cf = CameraFrame(focal_length=focal_length, array_direction=pointing, pointing_direction=pointing) # direction of event direction = HorizonFrame(alt=dir_alt, az=dir_az) cam_coord = direction.transform_to(cf) return cam_coord
def test_intersection_nominal_reconstruction(): """ Testing the reconstruction of the position in the nominal frame with a three-telescopes system. This is done using a squared configuration, of which the impact point occupies a vertex, ad the three telescopes the other three vertices. """ hill_inter = HillasIntersection() delta = 1.0 * u.m horizon_frame = AltAz() altitude = 70 * u.deg azimuth = 10 * u.deg array_direction = SkyCoord(alt=altitude, az=azimuth, frame=horizon_frame) nominal_frame = NominalFrame(origin=array_direction) focal_length = 28 * u.m camera_frame = CameraFrame(focal_length=focal_length, telescope_pointing=array_direction) cog_coords_camera_1 = SkyCoord(x=delta, y=0 * u.m, frame=camera_frame) cog_coords_camera_2 = SkyCoord(x=delta / 0.7, y=delta / 0.7, frame=camera_frame) cog_coords_camera_3 = SkyCoord(x=0 * u.m, y=delta, frame=camera_frame) cog_coords_nom_1 = cog_coords_camera_1.transform_to(nominal_frame) cog_coords_nom_2 = cog_coords_camera_2.transform_to(nominal_frame) cog_coords_nom_3 = cog_coords_camera_3.transform_to(nominal_frame) # x-axis is along the altitude and y-axis is along the azimuth hillas_1 = HillasParametersContainer(x=cog_coords_nom_1.delta_alt, y=cog_coords_nom_1.delta_az, intensity=100, psi=0 * u.deg) hillas_2 = HillasParametersContainer(x=cog_coords_nom_2.delta_alt, y=cog_coords_nom_2.delta_az, intensity=100, psi=45 * u.deg) hillas_3 = HillasParametersContainer(x=cog_coords_nom_3.delta_alt, y=cog_coords_nom_3.delta_az, intensity=100, psi=90 * u.deg) hillas_dict = {1: hillas_1, 2: hillas_2, 3: hillas_3} reco_nominal = hill_inter.reconstruct_nominal(hillas_parameters=hillas_dict) nominal_pos = SkyCoord( delta_az=u.Quantity(reco_nominal[0], u.rad), delta_alt=u.Quantity(reco_nominal[1], u.rad), frame=nominal_frame ) np.testing.assert_allclose(nominal_pos.altaz.az.to_value(u.deg), azimuth.to_value(u.deg), atol=1e-8) np.testing.assert_allclose(nominal_pos.altaz.alt.to_value(u.deg), altitude.to_value(u.deg), atol=1e-8)
def pixel_coords_to_telescope(geom, equivalent_focal_length): """ Get the x, y coordinates of the pixels in the telescope frame Paramenters --------- geom: CameraGeometry equivalent_focal_length: Focal length of the telescope Returns --------- delta_az, delta_alt: `floats` coordinates in the TelescopeFrame """ camera_coord = SkyCoord( x=geom.pix_x, y=geom.pix_y, frame=CameraFrame( focal_length=equivalent_focal_length, rotation=geom.cam_rotation, ) ) tel_coord = camera_coord.transform_to(TelescopeFrame()) return tel_coord.delta_az, tel_coord.delta_alt
def sky_to_camera(alt, az, focal, pointing_alt, pointing_az): """ Coordinate transform from aky position (alt, az) (in angles) to camera coordinates (x, y) in distance Parameters ---------- alt: astropy Quantity az: astropy Quantity focal: astropy Quantity pointing_alt: pointing altitude in angle unit pointing_az: pointing altitude in angle unit Returns ------- camera frame: `astropy.coordinates.sky_coordinate.SkyCoord` """ pointing_direction = SkyCoord(alt=clip_alt(pointing_alt), az=pointing_az, frame=horizon_frame) camera_frame = CameraFrame(focal_length=focal, telescope_pointing=pointing_direction) event_direction = SkyCoord(alt=clip_alt(alt), az=az, frame=horizon_frame) camera_pos = event_direction.transform_to(camera_frame) return camera_pos
def test_camera_focal_length_array(): from ctapipe.coordinates import CameraFrame, TelescopeFrame tel_coord = SkyCoord([1, 2] * u.deg, [0, 1] * u.deg, frame=TelescopeFrame()) cam_coord = tel_coord.transform_to(CameraFrame(focal_length=[28, 17] * u.m)) assert not np.isnan(cam_coord.x).any() assert not np.isnan(cam_coord.y).any()
def test_icrs_to_camera(): from ctapipe.coordinates import CameraFrame obstime = Time("2013-11-01T03:00") location = EarthLocation.of_site("Roque de los Muchachos") horizon_frame = AltAz(location=location, obstime=obstime) # simulate crab "on" observations crab = SkyCoord(ra="05h34m31.94s", dec="22d00m52.2s") telescope_pointing = crab.transform_to(horizon_frame) camera_frame = CameraFrame( focal_length=28 * u.m, telescope_pointing=telescope_pointing, location=location, obstime=obstime, ) ceta_tauri = SkyCoord(ra="5h37m38.6854231s", dec="21d08m33.158804s") ceta_tauri_camera = ceta_tauri.transform_to(camera_frame) camera_center = SkyCoord(0 * u.m, 0 * u.m, frame=camera_frame) crab_camera = crab.transform_to(camera_frame) assert crab_camera.x.to_value(u.m) == approx(0.0, abs=1e-10) assert crab_camera.y.to_value(u.m) == approx(0.0, abs=1e-10) # assert ceta tauri is in FoV assert camera_center.separation_3d(ceta_tauri_camera) < u.Quantity(0.6, u.m)
def test_cam_to_hor(): from ctapipe.coordinates import CameraFrame # Coordinates in any frame can be given as a numpy array of the xyz positions # e.g. in this case the position on pixels in the camera pix_x = [1] * u.m pix_y = [1] * u.m focal_length = 15000 * u.mm # first define the camera frame pointing = SkyCoord(alt=70 * u.deg, az=0 * u.deg, frame=AltAz()) camera_frame = CameraFrame(focal_length=focal_length, telescope_pointing=pointing) # transform camera_coord = SkyCoord(pix_x, pix_y, frame=camera_frame) altaz_coord = camera_coord.transform_to(AltAz()) # transform back altaz_coord2 = SkyCoord(az=altaz_coord.az, alt=altaz_coord.alt, frame=AltAz()) camera_coord2 = altaz_coord2.transform_to(camera_frame) # check transform assert np.isclose(camera_coord.x.to_value(u.m), camera_coord2.y.to_value(u.m))
def camera_to_sky(pos_x, pos_y, focal, pointing_alt, pointing_az): """ Parameters ---------- pos_x: X coordinate in camera (distance) pos_y: Y coordinate in camera (distance) focal: telescope focal (distance) pointing_alt: pointing altitude in angle unit pointing_az: pointing altitude in angle unit Returns ------- (alt, az) Example: -------- import astropy.units as u import numpy as np x = np.array([1,0]) * u.m y = np.array([1,1]) * u.m """ pointing_direction = SkyCoord(alt=pointing_alt, az=pointing_az, frame=horizon_frame) camera_frame = CameraFrame(focal_length=focal, telescope_pointing=pointing_direction) camera_coord = SkyCoord(pos_x, pos_y, frame=camera_frame) horizon = camera_coord.transform_to(horizon_frame) return horizon
def radec_to_camera(sky_coordinate, obstime, pointing_alt, pointing_az, focal): """ Coordinate transform from sky coordinate to camera coordinates (x, y) in distance Parameters ---------- sky_coordinate: astropy.coordinates.sky_coordinate.SkyCoord obstime: astropy.time.Time pointing_alt: pointing altitude in angle unit pointing_az: pointing altitude in angle unit focal: astropy Quantity Returns ------- camera frame: `astropy.coordinates.sky_coordinate.SkyCoord` """ horizon_frame = AltAz(location=location, obstime=obstime) pointing_direction = SkyCoord(alt=clip_alt(pointing_alt), az=pointing_az, frame=horizon_frame) camera_frame = CameraFrame( focal_length=focal, telescope_pointing=pointing_direction, obstime=obstime, location=location, ) camera_pos = sky_coordinate.transform_to(camera_frame) return camera_pos
def cam_to_tel(): # Coordinates in any fram can be given as a numpy array of the xyz positions # e.g. in this case the position on pixels in the camera pix_x = np.ones(2048) * u.m pix_y = np.ones(2048) * u.m # first define the camera frame camera_frame = CameraFrame(focal_length=15 * u.m) # create a coordinate in that frame camera_coord = SkyCoord(pix_x, pix_y, frame=camera_frame) # then use transform to function to convert to a new system making sure # to give the required values for the conversion (these are not checked # yet) telescope_coord = camera_coord.transform_to(TelescopeFrame()) # Print coordinates in the new frame print("Telescope Coordinate", telescope_coord) # Transforming back is then easy camera_coord2 = telescope_coord.transform_to(camera_frame) # We can easily check the distance between 2 coordinates in the same frame # In this case they should be the same print("Separation", np.sum(camera_coord.separation_3d(camera_coord2)))
def transform_to_telescope_altaz(self, alt, az, pointing_alt, pointing_az): """ Returns alt, az """ pointing_coord = SkyCoord(alt=0*u.deg+pointing_alt, az=pointing_az, frame=altaz, unit='deg') #pointing = pointing_coord_m.transform_to(self.altaz) camera_frame_m = CameraFrame( telescope_pointing=pointing_coord, focal_length=self.focal_length, obstime=self.obstime, location=self.magic_location, rotation=0*u.deg ) event_location = SkyCoord(alt=0*u.deg+alt, az=az, frame=altaz, unit='deg') tf1 = TelescopeFrame(telescope_pointing = pointing_coord, obstime = obstime, location = magic_location) loc1 = event_location.transform_to(tf1) loc1.delta_az.to_value(u.deg) return loc1.delta_alt.to_value(u.deg), loc1.delta_az.to_value(u.deg)
def test_array_draw(): filename = get_dataset("gamma_test.simtel.gz") cam_geom = {} source = hessio_event_source(filename, max_events=2) r1 = HESSIOR1Calibrator() dl0 = CameraDL0Reducer() calibrator = CameraDL1Calibrator() for event in source: array_pointing = SkyCoord( event.mcheader.run_array_direction[1] * u.rad, event.mcheader.run_array_direction[0] * u.rad, frame=AltAz) # array_view = ArrayPlotter(instrument=event.inst, # system=TiltedGroundFrame( # pointing_direction=array_pointing)) hillas_dict = {} r1.calibrate(event) dl0.reduce(event) calibrator.calibrate(event) # calibrate the events # store MC pointing direction for the array for tel_id in event.dl0.tels_with_data: pmt_signal = event.dl1.tel[tel_id].image[0] geom = deepcopy(event.inst.subarray.tel[tel_id].camera) fl = event.inst.subarray.tel[tel_id].optics.equivalent_focal_length # Transform the pixels positions into nominal coordinates camera_coord = CameraFrame(x=geom.pix_x, y=geom.pix_y, z=np.zeros(geom.pix_x.shape) * u.m, focal_length=fl, rotation=90 * u.deg - geom.cam_rotation) nom_coord = camera_coord.transform_to( NominalFrame(array_direction=array_pointing, pointing_direction=array_pointing)) geom.pix_x = nom_coord.x geom.pix_y = nom_coord.y mask = tailcuts_clean(geom, pmt_signal, picture_thresh=10., boundary_thresh=5.) try: moments = hillas_parameters(geom, pmt_signal * mask) hillas_dict[tel_id] = moments nom_coord = NominalPlotter(hillas_parameters=hillas_dict, draw_axes=True) nom_coord.draw_array() except HillasParameterizationError as e: print(e) continue
def get_muon_center(geom, equivalent_focal_length): """ Get the x,y coordinates of the center of the muon ring in the NominalFrame Paramenters --------- geom: CameraGeometry equivalent_focal_length: Focal length of the telescope Returns --------- x, y: `floats` coordinates in the NominalFrame """ x, y = geom.pix_x, geom.pix_y telescope_pointing = SkyCoord(alt=70 * u.deg, az=0 * u.deg, frame=AltAz()) camera_coord = SkyCoord(x=x, y=y, frame=CameraFrame( focal_length=equivalent_focal_length, rotation=geom.pix_rotation, telescope_pointing=telescope_pointing)) nom_coord = camera_coord.transform_to( NominalFrame(origin=telescope_pointing)) x = nom_coord.delta_az.to(u.deg) y = nom_coord.delta_alt.to(u.deg) return x, y
def get_event_pos_in_camera(event, tel): """ Return the position of the source in the camera frame Parameters ---------- event: `ctapipe.io.containers.DataContainer` tel: `ctapipe.instruement.telescope.TelescopeDescription` Returns ------- (x, y) (float, float): position in the camera """ array_pointing = SkyCoord(alt=clip_alt( event.mcheader.run_array_direction[1]), az=event.mcheader.run_array_direction[0], frame=horizon_frame) event_direction = SkyCoord(alt=clip_alt(event.mc.alt), az=event.mc.az, frame=horizon_frame) focal = tel.optics.equivalent_focal_length camera_frame = CameraFrame(focal_length=focal, telescope_pointing=array_pointing) camera_pos = event_direction.transform_to(camera_frame) return camera_pos.x, camera_pos.y
def test_muon_efficiency_fit(): from ctapipe.instrument import TelescopeDescription, SubarrayDescription from ctapipe.coordinates import TelescopeFrame, CameraFrame from ctapipe.image.muon.intensity_fitter import image_prediction, MuonIntensityFitter telescope = TelescopeDescription.from_name('LST', 'LSTCam') subarray = SubarrayDescription( 'LSTMono', {0: [0, 0, 0] * u.m}, {0: telescope}, ) center_x = 0.8 * u.deg center_y = 0.4 * u.deg radius = 1.2 * u.deg ring_width = 0.05 * u.deg impact_parameter = 5 * u.m phi = 0 * u.rad efficiency = 0.5 focal_length = telescope.optics.equivalent_focal_length geom = telescope.camera.geometry mirror_radius = np.sqrt(telescope.optics.mirror_area / np.pi) pixel_diameter = 2 * u.rad * (np.sqrt(geom.pix_area / np.pi) / focal_length).to_value(u.dimensionless_unscaled) tel = CameraFrame( x=geom.pix_x, y=geom.pix_y, focal_length=focal_length, rotation=geom.cam_rotation, ).transform_to(TelescopeFrame()) x = tel.fov_lon y = tel.fov_lat image = image_prediction( mirror_radius, hole_radius=0 * u.m, impact_parameter=impact_parameter, phi=phi, center_x=center_x, center_y=center_y, radius=radius, ring_width=ring_width, pixel_x=x, pixel_y=y, pixel_diameter=pixel_diameter[0] ) fitter = MuonIntensityFitter(subarray=subarray) result = fitter( tel_id=0, center_x=center_x, center_y=center_y, radius=radius, image=image * efficiency, pedestal=np.full_like(image, 1.1) ) assert u.isclose(result.impact, impact_parameter, rtol=0.05) assert u.isclose(result.width, ring_width, rtol=0.05) assert u.isclose(result.optical_efficiency, efficiency, rtol=0.05)
def test_camera_missing_focal_length(): from ctapipe.coordinates import CameraFrame, TelescopeFrame camera_frame = CameraFrame() coord = SkyCoord(x=0 * u.m, y=2 * u.m, frame=camera_frame) with raises(ValueError): coord.transform_to(TelescopeFrame())
def inititialize_hillas_planes( self, hillas_dict, subarray, pointing_alt, pointing_az ): """ creates a dictionary of :class:`.HillasPlane` from a dictionary of hillas parameters Parameters ---------- hillas_dict : dictionary dictionary of hillas moments subarray : ctapipe.instrument.SubarrayDescription subarray information tel_phi, tel_theta : dictionaries dictionaries of the orientation angles of the telescopes needs to contain at least the same keys as in `hillas_dict` """ self.hillas_planes = {} for tel_id, moments in hillas_dict.items(): p2_x = moments.cen_x + 0.1 * u.m * np.cos(moments.psi) p2_y = moments.cen_y + 0.1 * u.m * np.sin(moments.psi) focal_length = subarray.tel[tel_id].optics.equivalent_focal_length pointing = SkyCoord( alt=pointing_alt[tel_id], az=pointing_az[tel_id], frame='altaz' ) hf = HorizonFrame( array_direction=pointing, pointing_direction=pointing ) cf = CameraFrame( focal_length=focal_length, array_direction=pointing, pointing_direction=pointing ) cog_coord = SkyCoord(x=moments.cen_x, y=moments.cen_y, frame=cf) cog_coord = cog_coord.transform_to(hf) p2_coord = SkyCoord(x=p2_x, y=p2_y, frame=cf) p2_coord = p2_coord.transform_to(hf) circle = HillasPlane( p1=cog_coord, p2=p2_coord, telescope_position=subarray.positions[tel_id], weight=moments.size * (moments.length / moments.width), ) self.hillas_planes[tel_id] = circle
def initialize_hillas_planes( self, hillas_dict, subarray, pointing_alt, pointing_az ): """ creates a dictionary of :class:`.HillasPlane` from a dictionary of hillas parameters Parameters ---------- hillas_dict : dictionary dictionary of hillas moments subarray : ctapipe.instrument.SubarrayDescription subarray information tel_phi, tel_theta : dictionaries dictionaries of the orientation angles of the telescopes needs to contain at least the same keys as in `hillas_dict` """ self.hillas_planes = {} horizon_frame = HorizonFrame() for tel_id, moments in hillas_dict.items(): # we just need any point on the main shower axis a bit away from the cog p2_x = moments.x + 0.1 * u.m * np.cos(moments.psi) p2_y = moments.y + 0.1 * u.m * np.sin(moments.psi) focal_length = subarray.tel[tel_id].optics.equivalent_focal_length pointing = SkyCoord( alt=pointing_alt[tel_id], az=pointing_az[tel_id], frame=horizon_frame, ) camera_frame = CameraFrame( focal_length=focal_length, telescope_pointing=pointing ) cog_coord = SkyCoord( x=moments.x, y=moments.y, frame=camera_frame, ) cog_coord = cog_coord.transform_to(horizon_frame) p2_coord = SkyCoord(x=p2_x, y=p2_y, frame=camera_frame) p2_coord = p2_coord.transform_to(horizon_frame) circle = HillasPlane( p1=cog_coord, p2=p2_coord, telescope_position=subarray.positions[tel_id], weight=moments.intensity * (moments.length / moments.width), ) self.hillas_planes[tel_id] = circle
def test_camera_telescope_transform(): camera_coord = CameraFrame(x=1 * u.m, y=2 * u.m, z=0 * u.m) print(camera_coord) telescope_coord = camera_coord.transform_to(TelescopeFrame) print(telescope_coord) camera_coord2 = telescope_coord.transform_to(CameraFrame) print(camera_coord2)
def transform_to(self, frame: BaseCoordinateFrame) -> CG: """Transform the pixel coordinates stored in this geometry and the pixel and camera rotations to another camera coordinate frame. Note that `geom.frame` must contain all the necessary attributes needed to transform into the requested frame, i.e. if going from `CameraFrame` to `TelescopeFrame`, it should contain a `focal_length` attribute. Parameters ---------- frame: ctapipe.coordinates.CameraFrame The coordinate frame to transform to. Returns ------- CameraGeometry: new instance in the requested Frame """ if self.frame is None: self.frame = CameraFrame() coord = SkyCoord(self.pix_x, self.pix_y, frame=self.frame) trans = coord.transform_to(frame) # also transform the unit vectors, to get rotation / mirroring uv = SkyCoord([1, 0], [0, 1], unit=self.pix_x.unit, frame=self.frame) uv_trans = uv.transform_to(frame) # some trickery has to be done to deal with the fact that not all frames # use the same x/y attributes. Therefore we get the component names, and # access them by string: frame_attrs = list( uv_trans.frame.get_representation_component_names().keys()) uv_x = getattr(uv_trans, frame_attrs[0]) uv_y = getattr(uv_trans, frame_attrs[1]) trans_x = getattr(trans, frame_attrs[0]) trans_y = getattr(trans, frame_attrs[1]) rot = np.arctan2(uv_y[0], uv_y[1]) det = np.linalg.det([uv_x.value, uv_y.value]) cam_rotation = rot - self.cam_rotation pix_rotation = rot - self.pix_rotation return CameraGeometry( camera_name=self.camera_name, pix_id=self.pix_id, pix_x=trans_x, pix_y=trans_y, pix_area=self.guess_pixel_area(trans_x, trans_y, self.pix_type), pix_type=self.pix_type, pix_rotation=pix_rotation, cam_rotation=cam_rotation, neighbors=self._neighbors, apply_derotation=False, frame=frame, )
def cam_to_nom(): pix = [np.ones(2048), np.ones(2048), np.zeros(2048)] * u.m camera_coord = CameraFrame(pix) # In this case we bypass the telescope system nom_coord = camera_coord.transform_to( NominalFrame(array_direction=[75 * u.deg, 180 * u.deg], pointing_direction=[70 * u.deg, 180 * u.deg], focal_length=15 * u.m)) print("Nominal Coordinate", nom_coord)
def camera_to_altaz(pos_x, pos_y, focal, pointing_alt, pointing_az, obstime=None): """ Compute camera to Horizontal frame (Altitude-Azimuth system). For MC assume the default ObsTime. Parameters ---------- pos_x: `~astropy.units.Quantity` X coordinate in camera (distance) pos_y: `~astropy.units.Quantity` Y coordinate in camera (distance) focal: `~astropy.units.Quantity` telescope focal (distance) pointing_alt: `~astropy.units.Quantity` pointing altitude in angle unit pointing_az: `~astropy.units.Quantity` pointing altitude in angle unit obstime: `~astropy.time.Time` Returns ------- sky frame: `astropy.coordinates.SkyCoord` in AltAz frame Example: -------- import astropy.units as u import numpy as np pos_x = np.array([0, 0]) * u.m pos_y = np.array([0, 0]) * u.m focal = 28*u.m pointing_alt = np.array([1.0, 1.0]) * u.rad pointing_az = np.array([0.2, 0.5]) * u.rad sky_coords = utils.camera_to_altaz(pos_x, pos_y, focal, pointing_alt, pointing_az) """ if not obstime: logging.info("No time given. To be use only for MC data.") horizon_frame = AltAz(location=location, obstime=obstime) pointing_direction = SkyCoord(alt=clip_alt(pointing_alt), az=pointing_az, frame=horizon_frame) camera_frame = CameraFrame(focal_length=focal, telescope_pointing=pointing_direction) camera_coord = SkyCoord(pos_x, pos_y, frame=camera_frame) horizon = camera_coord.transform_to(horizon_frame) return horizon
def transform_to(self, frame: BaseCoordinateFrame): """Transform the pixel coordinates stored in this geometry and the pixel and camera rotations to another camera coordinate frame. Note that ``geom.frame`` must contain all the necessary attributes needed to transform into the requested frame, i.e. if going from `~ctapipe.coordinates.CameraFrame` to `~ctapipe.coordinates.TelescopeFrame`, it should contain the correct data in the ``focal_length`` attribute. Parameters ---------- frame: ctapipe.coordinates.CameraFrame The coordinate frame to transform to. Returns ------- CameraGeometry: new instance in the requested Frame """ if self.frame is None: self.frame = CameraFrame() coord = SkyCoord(self.pix_x, self.pix_y, frame=self.frame) trans = coord.transform_to(frame) # also transform the unit vectors, to get rotation / mirroring, scale uv = SkyCoord([1, 0], [0, 1], unit=self.pix_x.unit, frame=self.frame) uv_trans = uv.transform_to(frame) trans_x_name, trans_y_name = list( uv_trans.frame.get_representation_component_names().keys()) uv_trans_x = getattr(uv_trans, trans_x_name) uv_trans_y = getattr(uv_trans, trans_y_name) rot = np.arctan2(uv_trans_y[0], uv_trans_y[1]) cam_rotation = rot - self.cam_rotation pix_rotation = rot - self.pix_rotation scale = np.sqrt(uv_trans_x[0]**2 + uv_trans_y[0]**2) / self.pix_x.unit trans_x = getattr(trans, trans_x_name) trans_y = getattr(trans, trans_y_name) pix_area = (self.pix_area * scale**2).to(trans_x.unit**2) return CameraGeometry( camera_name=self.camera_name, pix_id=self.pix_id, pix_x=trans_x, pix_y=trans_y, pix_area=pix_area, pix_type=self.pix_type, pix_rotation=pix_rotation, cam_rotation=cam_rotation, neighbors=self._neighbors, apply_derotation=False, frame=frame, )
def test_hillas_container(): geom, image = create_sample_image_zeros(psi="0d") params = hillas_parameters(geom, image) assert isinstance(params, CameraHillasParametersContainer) geom.frame = CameraFrame(focal_length=28 * u.m) geom_telescope_frame = geom.transform_to(TelescopeFrame()) params = hillas_parameters(geom_telescope_frame, image) assert isinstance(params, HillasParametersContainer)
def test_cam_to_nominal(): from ctapipe.coordinates import CameraFrame, NominalFrame telescope_pointing = SkyCoord(alt=70 * u.deg, az=0 * u.deg, frame=AltAz()) array_pointing = SkyCoord(alt=72 * u.deg, az=0 * u.deg, frame=AltAz()) cam_frame = CameraFrame(focal_length=28 * u.m, telescope_pointing=telescope_pointing) cam = SkyCoord(x=0.5 * u.m, y=0.1 * u.m, frame=cam_frame) nom_frame = NominalFrame(origin=array_pointing) cam.transform_to(nom_frame)
def cam_to_tel(): # Coordinates in any fram can be given as a numpy array of the xyz positions # e.g. in this case the position on pixels in the camera pix = [np.ones(2048), np.ones(2048), np.zeros(2048)] * u.m # first define the camera frame camera_coord = CameraFrame(pix, focal_length=15 * u.m, rotation=0 * u.deg) # then use transform to function to convert to a new system # making sure to give the required values for the conversion (these are not checked yet) telescope_coord = camera_coord.transform_to(TelescopeFrame()) # Print coordinates in the new frame print("Telescope Coordinate", telescope_coord) # Transforming back is then easy camera_coord2 = telescope_coord.transform_to( CameraFrame(focal_length=15 * u.m, rotation=0 * u.deg)) # We can easily check the distance between 2 coordinates in the same frame # In this case they should be the same print("Separation", np.sum(camera_coord.separation_3d(camera_coord2)))
def main(infile): with h5py.File(infile, mode='r') as f: is_simulation = 'corsika_runs' in f if is_simulation: df = read_h5py(infile, key='events', columns=columns_sim) obstime = None else: df = read_h5py(infile, key='events', columns=columns_obs) obstime = Time(df.dragon_time, format='unix') altaz = AltAz(obstime=obstime, location=location) pointing = SkyCoord( alt=u.Quantity(df.alt_tel.values, u.rad, copy=False), az=u.Quantity(df.az_tel.values, u.rad, copy=False), frame=altaz, ) camera_frame = CameraFrame(telescope_pointing=pointing, location=location, obstime=obstime, focal_length=28 * u.m) prediction_cam = SkyCoord( x=u.Quantity(df.source_x_prediction.values, u.m, copy=False), y=u.Quantity(df.source_y_prediction.values, u.m, copy=False), frame=camera_frame, ) prediction_altaz = prediction_cam.transform_to(altaz) append_column_to_hdf5(infile, prediction_altaz.alt.rad, 'events', 'source_alt_prediction') append_column_to_hdf5(infile, prediction_altaz.az.rad, 'events', 'source_az_prediction') if not is_simulation: prediction_icrs = prediction_altaz.transform_to('icrs') pointing_icrs = pointing.transform_to('icrs') append_column_to_hdf5(infile, prediction_icrs.ra.rad, 'events', 'source_ra_prediction') append_column_to_hdf5(infile, prediction_icrs.dec.rad, 'events', 'source_dec_prediction') append_column_to_hdf5(infile, pointing_icrs.ra.rad, 'events', 'pointing_ra') append_column_to_hdf5(infile, pointing_icrs.dec.rad, 'events', 'pointing_dec')