def test_image_prediction(self): pixel_x = np.array([0]) * u.deg pixel_y = np.array([0]) * u.deg image = np.array([1]) pixel_area = np.array([1]) * u.deg * u.deg self.impact_reco.set_event_properties( {1: image}, {1: pixel_x}, {1: pixel_y}, {1: pixel_area}, {1: "CHEC"}, {1: 0 * u.m}, {1: 0 * u.m}, array_direction=[0 * u.deg, 0 * u.deg]) """First check image prediction by directly accessing the function""" pred = self.impact_reco.image_prediction("CHEC", zenith=0, azimuth=0, energy=1, impact=50, x_max=0, pix_x=pixel_x, pix_y=pixel_y) assert np.sum(pred) != 0 """Then check helper function gives the same answer""" shower = ReconstructedShowerContainer() shower.is_valid = True shower.alt = 0 * u.deg shower.az = 0 * u.deg shower.core_x = 0 * u.m shower.core_y = 100 * u.m shower.h_max = 300 + 93 * np.log10(1) energy = ReconstructedEnergyContainer() energy.is_valid = True energy.energy = 1 * u.TeV pred2 = self.impact_reco.get_prediction(1, shower_reco=shower, energy_reco=energy) print(pred, pred2) assert pred.all() == pred2.all()
def test_image_prediction(self): pixel_x = np.array([0]) * u.deg pixel_y = np.array([0]) * u.deg image = np.array([1]) pixel_area = np.array([1]) * u.deg * u.deg self.impact_reco.set_event_properties({1: image}, {1: pixel_x}, {1: pixel_y}, {1: pixel_area}, {1: "CHEC"}, {1: 0 * u.m}, {1: 0 * u.m}, array_direction=[0 * u.deg, 0 * u.deg]) """First check image prediction by directly accessing the function""" pred = self.impact_reco.image_prediction("CHEC", zenith=0, azimuth=0, energy=1, impact=50, x_max=0, pix_x=pixel_x, pix_y=pixel_y) assert np.sum(pred) != 0 """Then check helper function gives the same answer""" shower = ReconstructedShowerContainer() shower.is_valid = True shower.alt = 0 * u.deg shower.az = 0 * u.deg shower.core_x = 0 * u.m shower.core_y = 100 * u.m shower.h_max = 300 + 93 * np.log10(1) energy = ReconstructedEnergyContainer() energy.is_valid = True energy.energy = 1 * u.TeV pred2 = self.impact_reco.get_prediction(1, shower_reco=shower, energy_reco=energy) print(pred, pred2) assert pred.all() == pred2.all()
def predict(self, hillas_dict, inst, array_pointing, telescopes_pointings=None): """ Parameters ---------- hillas_dict: dict Dictionary containing Hillas parameters for all telescopes in reconstruction inst : ctapipe.io.InstrumentContainer instrumental description array_pointing: SkyCoord[AltAz] pointing direction of the array telescopes_pointings: dict[SkyCoord[AltAz]] dictionary of pointing direction per each telescope Returns ------- ReconstructedShowerContainer: """ # filter warnings for missing obs time. this is needed because MC data has no obs time warnings.filterwarnings(action='ignore', category=MissingFrameAttributeWarning) # stereoscopy needs at least two telescopes if len(hillas_dict) < 2: raise TooFewTelescopesException( "need at least two telescopes, have {}".format( len(hillas_dict))) # check for np.nan or 0 width's as these screw up weights if any( [np.isnan(hillas_dict[tel]['width'].value) for tel in hillas_dict]): raise InvalidWidthException( "A HillasContainer contains an ellipse of width==np.nan") if any([hillas_dict[tel]['width'].value == 0 for tel in hillas_dict]): raise InvalidWidthException( "A HillasContainer contains an ellipse of width==0") if telescopes_pointings is None: telescopes_pointings = { tel_id: array_pointing for tel_id in hillas_dict.keys() } tilted_frame = TiltedGroundFrame(pointing_direction=array_pointing) ground_positions = inst.subarray.tel_coords grd_coord = GroundFrame(x=ground_positions.x, y=ground_positions.y, z=ground_positions.z) tilt_coord = grd_coord.transform_to(tilted_frame) tel_x = { tel_id: tilt_coord.x[tel_id - 1] for tel_id in list(hillas_dict.keys()) } tel_y = { tel_id: tilt_coord.y[tel_id - 1] for tel_id in list(hillas_dict.keys()) } nom_frame = NominalFrame(origin=array_pointing) hillas_dict_mod = copy.deepcopy(hillas_dict) for tel_id, hillas in hillas_dict_mod.items(): # prevent from using rads instead of meters as inputs assert hillas.x.to(u.m).unit == u.Unit('m') focal_length = inst.subarray.tel[ tel_id].optics.equivalent_focal_length camera_frame = CameraFrame( telescope_pointing=telescopes_pointings[tel_id], focal_length=focal_length, ) cog_coords = SkyCoord(x=hillas.x, y=hillas.y, frame=camera_frame) cog_coords_nom = cog_coords.transform_to(nom_frame) hillas.x = cog_coords_nom.delta_alt hillas.y = cog_coords_nom.delta_az src_x, src_y, err_x, err_y = self.reconstruct_nominal(hillas_dict_mod) core_x, core_y, core_err_x, core_err_y = self.reconstruct_tilted( hillas_dict_mod, tel_x, tel_y) err_x *= u.rad err_y *= u.rad nom = SkyCoord(delta_az=src_x * u.rad, delta_alt=src_y * u.rad, frame=nom_frame) # nom = sky_pos.transform_to(nom_frame) sky_pos = nom.transform_to(array_pointing.frame) result = ReconstructedShowerContainer() result.alt = sky_pos.altaz.alt.to(u.rad) result.az = sky_pos.altaz.az.to(u.rad) tilt = SkyCoord( x=core_x * u.m, y=core_y * u.m, frame=tilted_frame, ) grd = project_to_ground(tilt) result.core_x = grd.x result.core_y = grd.y x_max = self.reconstruct_xmax( nom.delta_az, nom.delta_alt, tilt.x, tilt.y, hillas_dict_mod, tel_x, tel_y, 90 * u.deg - array_pointing.alt, ) result.core_uncert = np.sqrt(core_err_x**2 + core_err_y**2) * u.m result.tel_ids = [h for h in hillas_dict_mod.keys()] result.average_intensity = np.mean( [h.intensity for h in hillas_dict_mod.values()]) result.is_valid = True src_error = np.sqrt(err_x**2 + err_y**2) result.alt_uncert = src_error.to(u.rad) result.az_uncert = src_error.to(u.rad) result.h_max = x_max result.h_max_uncert = np.nan result.goodness_of_fit = np.nan return result
def process_event(event, calibrator, config): '''Processes one event. Calls calculate_image_features and performs a stereo hillas reconstruction. ReconstructedShowerContainer will be filled with nans (+units) if hillas failed. Returns: -------- ArrayEventContainer list(telescope_event_containers.values()) ''' logging.info(f'processing event {event.dl0.event_id}') calibrator(event) telescope_types = [] hillas_reconstructor = HillasReconstructor() telescope_event_containers = {} horizon_frame = AltAz() telescope_pointings = {} array_pointing = SkyCoord( az=event.mcheader.run_array_direction[0], alt=event.mcheader.run_array_direction[1], frame=horizon_frame, ) for telescope_id, dl1 in event.dl1.tel.items(): cam_type = event.inst.subarray.tels[telescope_id].camera.cam_id if cam_type not in config.cleaning_level.keys(): logging.info(f"No cleaning levels for camera {cam_type}. Skipping event") continue telescope_types.append(str(event.inst.subarray.tels[telescope_id].optics)) try: telescope_event_containers[telescope_id] = calculate_image_features( telescope_id, event, dl1, config ) except HillasParameterizationError: logging.info( f'Error calculating hillas features for event {event.dl0.event_id, telescope_id}', exc_info=True, ) continue except Exception: logging.info( f'Error calculating image features for event {event.dl0.event_id, telescope_id}', exc_info=True, ) continue telescope_pointings[telescope_id] = SkyCoord( alt=telescope_event_containers[telescope_id].pointing.altitude, az=telescope_event_containers[telescope_id].pointing.azimuth, frame=horizon_frame, ) if len(telescope_event_containers) < 1: raise Exception('None of the allowed telescopes triggered for event %s', event.dl0.event_id) parameters = {tel_id: telescope_event_containers[tel_id].hillas for tel_id in telescope_event_containers} try: reconstruction_container = hillas_reconstructor.predict( parameters, event.inst, array_pointing, telescopes_pointings=telescope_pointings ) reconstruction_container.prefix = '' except Exception: logging.info( 'Not enough telescopes for which Hillas parameters could be reconstructed', exc_info=True ) reconstruction_container = ReconstructedShowerContainer() reconstruction_container.alt = u.Quantity(np.nan, u.rad) reconstruction_container.alt_uncert = u.Quantity(np.nan, u.rad) reconstruction_container.az = u.Quantity(np.nan, u.rad) reconstruction_container.az_uncert = np.nan reconstruction_container.core_x = u.Quantity(np.nan, u.m) reconstruction_container.core_y = u.Quantity(np.nan, u.m) reconstruction_container.core_uncert = np.nan reconstruction_container.h_max = u.Quantity(np.nan, u.m) reconstruction_container.h_max_uncert = np.nan reconstruction_container.is_valid = False reconstruction_container.tel_ids = [] reconstruction_container.average_intensity = np.nan reconstruction_container.goodness_of_fit = np.nan reconstruction_container.prefix = '' calculate_distance_to_core(telescope_event_containers, event, reconstruction_container) mc_container = copy.deepcopy(event.mc) mc_container.tel = None mc_container.prefix = 'mc' counter = Counter(telescope_types) array_event = ArrayEventContainer( array_event_id=event.dl0.event_id, run_id=event.r0.obs_id, reco=reconstruction_container, total_intensity=sum([t.hillas.intensity for t in telescope_event_containers.values()]), num_triggered_lst=counter['LST'], num_triggered_mst=counter['MST'], num_triggered_sst=counter['SST'], num_triggered_telescopes=len(telescope_types), mc=mc_container, ) return array_event, list(telescope_event_containers.values())