class TIOReader: """ Reader for the R0 and R1 tio files """ def __init__(self, path, max_events=None): try: from target_io import WaveformArrayReader from target_calib import CameraConfiguration except ModuleNotFoundError: msg = ("Cannot find TARGET libraries, please follow installation " "instructions from https://forge.in2p3.fr/projects/gct/" "wiki/Installing_CHEC_Software") raise ModuleNotFoundError(msg) if not os.path.exists(path): raise FileNotFoundError("File does not exist: {}".format(path)) self.path = path self._reader = WaveformArrayReader(self.path, 2, 1) self.is_r1 = self._reader.fR1 self.n_events = self._reader.fNEvents self.run_id = self._reader.fRunID self.n_pixels = self._reader.fNPixels self.n_modules = self._reader.fNModules self.n_tmpix = self.n_pixels // self.n_modules self.n_samples = self._reader.fNSamples self._camera_config = CameraConfiguration(self._reader.fCameraVersion) self.tc_mapping = self._camera_config.GetMapping(self.n_modules == 1) self._pixel = self._PixelWaveforms(self) self.n_cells = self._camera_config.GetNCells() self.camera_version = self._camera_config.GetVersion() self.reference_pulse_path = self._camera_config.GetReferencePulsePath() self.current_tack = None self.current_cpu_ns = None self.current_cpu_s = None self.first_cell_ids = np.zeros(self.n_pixels, dtype=np.uint16) if self.is_r1: self.samples = np.zeros((self.n_pixels, self.n_samples), dtype=np.float32) self.get_tio_event = self._reader.GetR1Event else: self.samples = np.zeros((self.n_pixels, self.n_samples), dtype=np.uint16) self.get_tio_event = self._reader.GetR0Event if max_events and max_events < self.n_events: self.n_events = max_events def _get_event(self, iev): self.index = iev self.get_tio_event(iev, self.samples, self.first_cell_ids) self.current_tack = self._reader.fCurrentTimeTack self.current_cpu_ns = self._reader.fCurrentTimeNs self.current_cpu_s = self._reader.fCurrentTimeSec return self.samples def __iter__(self): for iev in range(self.n_events): yield self._get_event(iev) def __getitem__(self, iev): return np.copy(self._get_event(iev)) class _PixelWaveforms: def __init__(self, tio_reader): self.reader = tio_reader def __getitem__(self, p): if not isinstance(p, list) and not isinstance(p, np.ndarray): p = [p] n_events = self.reader.n_events n_pixels = len(p) n_samples = self.reader.n_samples waveforms = np.zeros((n_events, n_pixels, n_samples)) for iev, wf in enumerate(self.reader): waveforms[iev] = wf[p] return waveforms @property def pixel(self): return self._pixel @property def mapping(self): return get_clp_mapping_from_tc_mapping(self.tc_mapping) def get_sn(self, tm): if tm >= self.n_modules: raise IndexError("Requested TM out of range: {}".format(tm)) return self._reader.GetSN(tm) @staticmethod def is_compatible(filepath): try: h = fits.getheader(filepath, 0) if 'EVENT_HEADER_VERSION' not in h: return False except IOError: return False return True
class SimtelReader(WaveformReader): def __init__(self, path, max_events=None): """ Reads simtelarray files utilising the SimTelEventSource from ctapipe Parameters ---------- path : str Path to the simtel file max_events : int Maximum number of events to read from the file """ super().__init__(path, max_events) try: from ctapipe.io import SimTelEventSource, EventSeeker except ModuleNotFoundError: msg = "Cannot find ctapipe installation" raise ModuleNotFoundError(msg) try: from target_calib import CameraConfiguration except ModuleNotFoundError: msg = ("Cannot find TARGET libraries, please follow installation " "instructions from https://forge.in2p3.fr/projects/gct/" "wiki/Installing_CHEC_Software") raise ModuleNotFoundError(msg) self.path = path reader = SimTelEventSource(input_url=path, max_events=max_events, back_seekable=True) self.seeker = EventSeeker(reader) first_event = self.seeker[0] tels = list(first_event.r0.tels_with_data) self.tel = tels[0] shape = first_event.r0.tel[self.tel].waveform.shape _, self.n_pixels, self.n_samples = shape self.n_modules = self.n_pixels // 64 self.index = 0 n_modules = 32 camera_version = "1.1.0" self._camera_config = CameraConfiguration(camera_version) tc_mapping = self._camera_config.GetMapping(n_modules == 1) self.mapping = get_clp_mapping_from_tc_mapping(tc_mapping) pix_x = first_event.inst.subarray.tel[tels[0]].camera.pix_x.value pix_y = first_event.inst.subarray.tel[tels[0]].camera.pix_y.value self.mapping['xpix'] = pix_x self.mapping['ypix'] = pix_y self.reference_pulse_path = self._camera_config.GetReferencePulsePath() self.camera_version = self._camera_config.GetVersion() self.gps_time = None self.mc_true = None self.mc = None self.pointing = None self.mcheader = None def _get_event(self, iev): event = self.seeker[iev] self._fill_event_containers(event) return event.r1.tel[self.tel].waveform[0] @staticmethod def is_compatible(path): # read the first 4 bytes with open(path, 'rb') as f: marker_bytes = f.read(4) # if file is gzip, read the first 4 bytes with gzip again if marker_bytes[0] == 0x1f and marker_bytes[1] == 0x8b: with gzip.open(path, 'rb') as f: marker_bytes = f.read(4) # check for the simtel magic marker int_marker, = struct.unpack('I', marker_bytes) return int_marker == 3558836791 or int_marker == 931798996 def __iter__(self): for event in self.seeker: self._fill_event_containers(event) yield event.r1.tel[self.tel].waveform[0] def _fill_event_containers(self, event): self.index = event.count self.run_id = event.r0.obs_id self.gps_time = event.trig.gps_time self.mc_true = event.mc.tel[self.tel].photo_electron_image self.mc = dict(iev=self.index, t_cpu=self.t_cpu, energy=event.mc.energy.value, alt=event.mc.alt.value, az=event.mc.az.value, core_x=event.mc.core_x.value, core_y=event.mc.core_y.value, h_first_int=event.mc.h_first_int.value, x_max=event.mc.x_max.value, shower_primary_id=event.mc.shower_primary_id) self.pointing = dict( iev=self.index, t_cpu=self.t_cpu, azimuth_raw=event.mc.tel[self.tel].azimuth_raw, altitude_raw=event.mc.tel[self.tel].altitude_raw, azimuth_cor=event.mc.tel[self.tel].azimuth_cor, altitude_cor=event.mc.tel[self.tel].altitude_cor, ) if self.mcheader is None: mch = event.mcheader self.mcheader = dict( corsika_version=mch.corsika_version, simtel_version=mch.simtel_version, energy_range_min=mch.energy_range_min.value, energy_range_max=mch.energy_range_max.value, prod_site_B_total=mch.prod_site_B_total.value, prod_site_B_declination=mch.prod_site_B_declination.value, prod_site_B_inclination=mch.prod_site_B_inclination.value, prod_site_alt=mch.prod_site_alt.value, spectral_index=mch.spectral_index, shower_prog_start=mch.shower_prog_start, shower_prog_id=mch.shower_prog_id, detector_prog_start=mch.detector_prog_start, detector_prog_id=mch.detector_prog_id, num_showers=mch.num_showers, shower_reuse=mch.shower_reuse, max_alt=mch.max_alt.value, min_alt=mch.min_alt.value, max_az=mch.max_az.value, min_az=mch.min_az.value, diffuse=mch.diffuse, max_viewcone_radius=mch.max_viewcone_radius.value, min_viewcone_radius=mch.min_viewcone_radius.value, max_scatter_range=mch.max_scatter_range.value, min_scatter_range=mch.min_scatter_range.value, core_pos_mode=mch.core_pos_mode, injection_height=mch.injection_height.value, atmosphere=mch.atmosphere, corsika_iact_options=mch.corsika_iact_options, corsika_low_E_model=mch.corsika_low_E_model, corsika_high_E_model=mch.corsika_high_E_model, corsika_bunchsize=mch.corsika_bunchsize, corsika_wlen_min=mch.corsika_wlen_min.value, corsika_wlen_max=mch.corsika_wlen_max.value, corsika_low_E_detail=mch.corsika_low_E_detail, corsika_high_E_detail=mch.corsika_high_E_detail, ) @property def n_events(self): return len(self.seeker) @property def t_cpu(self): return pd.to_datetime(self.gps_time.value, unit='s')
class TIOReader(WaveformReader): def __init__(self, path, max_events=None, skip_events=2, skip_end_events=1): """ Utilies TargetIO to read R0 and R1 tio files. Enables easy access to the waveforms for anaylsis. Waveforms can be read from the file by either indexing this reader or iterating over it: >>> path = "/path/to/file_r0.tio" >>> reader = TIOReader(path) >>> wf = reader[3] # Obtain the waveforms for the third event >>> path = "/path/to/file_r0.tio" >>> reader = TIOReader(path) >>> wfs = reader[:10] # Obtain the waveforms for the first 10 events >>> path = "/path/to/file_r0.tio" >>> reader = TIOReader(path) >>> for wf in reader: # Iterate over all events in the file >>> print(wf) Parameters ---------- path : str Path to the _r0.tio or _r1.tio file max_events : int Maximum number of events to read from the file """ super().__init__(path, max_events) try: from target_io import WaveformArrayReader from target_calib import CameraConfiguration except ModuleNotFoundError: msg = ("Cannot find TARGET libraries, please follow installation " "instructions from https://forge.in2p3.fr/projects/gct/" "wiki/Installing_CHEC_Software") raise ModuleNotFoundError(msg) self._reader = WaveformArrayReader( self.path, skip_events, skip_end_events ) self.is_r1 = self._reader.fR1 self._n_events = self._reader.fNEvents self.run_id = self._reader.fRunID self.n_pixels = self._reader.fNPixels self.n_superpixels_per_module = self._reader.fNSuperpixelsPerModule self.n_modules = self._reader.fNModules self.n_tmpix = self.n_pixels // self.n_modules self.n_samples = self._reader.fNSamples self._camera_config = CameraConfiguration(self._reader.fCameraVersion) self.tc_mapping = self._camera_config.GetMapping(self.n_modules == 1) self.n_cells = self._camera_config.GetNCells() self.camera_version = self._camera_config.GetVersion() self.reference_pulse_path = self._camera_config.GetReferencePulsePath() self.current_tack = None self.current_cpu_ns = None self.current_cpu_s = None self.first_cell_ids = np.zeros(self.n_pixels, dtype=np.uint16) self.stale = np.zeros(self.n_pixels, dtype=np.uint8) if self.is_r1: self.samples = np.zeros((self.n_pixels, self.n_samples), dtype=np.float32) self.get_tio_event = self._reader.GetR1Event else: self.samples = np.zeros((self.n_pixels, self.n_samples), dtype=np.uint16) self.get_tio_event = self._reader.GetR0Event if max_events and max_events < self._n_events: self._n_events = max_events def _get_event(self, iev): self.index = iev try: # TODO: Remove try in future version self.get_tio_event(iev, self.samples, self.first_cell_ids, self.stale) except TypeError: warnings.warn( "This call to WaveformArrayReader has been deprecated. " "Please update TargetIO", SyntaxWarning ) self.get_tio_event(iev, self.samples, self.first_cell_ids) self.current_tack = self._reader.fCurrentTimeTack self.current_cpu_ns = self._reader.fCurrentTimeNs self.current_cpu_s = self._reader.fCurrentTimeSec return self.samples @staticmethod def is_compatible(path): with open(path, 'rb') as f: marker_bytes = f.read(1024) # if file is gzip, read the first 4 bytes with gzip again if marker_bytes[0] == 0x1f and marker_bytes[1] == 0x8b: with gzip.open(path, 'rb') as f: marker_bytes = f.read(1024) if b'FITS' not in marker_bytes: return False try: h = fits.getheader(path, 0) if 'EVENT_HEADER_VERSION' not in h: return False except IOError: return False return True @property def n_events(self): return self._n_events @property def t_cpu(self): return pd.to_datetime( np.int64(self.current_cpu_s * 1E9) + np.int64(self.current_cpu_ns), unit='ns' ) @property def mapping(self): return get_clp_mapping_from_tc_mapping(self.tc_mapping) def get_sn(self, tm): """ Get the SN of the TARGET module in a slot Parameters ---------- tm : int Slot number for the TARGET module Returns ------- int Serial number of the TM """ if tm >= self.n_modules: raise IndexError("Requested TM out of range: {}".format(tm)) return self._reader.GetSN(tm) def get_sipm_temp(self, tm): if tm >= self.n_modules: raise IndexError("Requested TM out of range: {}".format(tm)) return self._reader.GetSiPMTemp(tm) def get_primary_temp(self, tm): if tm >= self.n_modules: raise IndexError("Requested TM out of range: {}".format(tm)) return self._reader.GetPrimaryTemp(tm) def get_sp_dac(self, tm, sp): if tm >= self.n_modules: raise IndexError("Requested TM out of range: {}".format(tm)) if sp >= self.n_superpixels_per_module: raise IndexError("Requested SP out of range: {}".format(sp)) return self._reader.GetSPDAC(tm, sp) def get_sp_hvon(self, tm, sp): if tm >= self.n_modules: raise IndexError("Requested TM out of range: {}".format(tm)) if sp >= self.n_superpixels_per_module: raise IndexError("Requested SP out of range: {}".format(sp)) return self._reader.GetSPHVON(tm, sp)