class DumpInstrumentTool(Tool): description = Unicode(__doc__) name = "ctapipe-dump-instrument" infile = Path(exists=True, help="input simtelarray file").tag(config=True) format = Enum( ["fits", "ecsv", "hdf5"], default_value="fits", help="Format of output file", config=True, ) aliases = Dict( dict(infile="DumpInstrumentTool.infile", format="DumpInstrumentTool.format")) def setup(self): with event_source(self.infile) as source: self.subarray = source.subarray def start(self): self.write_camera_geometries() self.write_optics_descriptions() self.write_subarray_description() def finish(self): pass @staticmethod def _get_file_format_info(format_name, table_type, table_name): """ returns file extension + dict of required parameters for Table.write""" if format_name == "fits": return "fits.gz", dict() elif format_name == "ecsv": return "ecsv.txt", dict(format="ascii.ecsv") elif format_name == "hdf5": return "h5", dict(path="/" + table_type + "/" + table_name) else: raise NameError("format not supported") def write_camera_geometries(self): cam_types = get_camera_types(self.subarray) self.subarray.info(printer=self.log.info) for cam_name in cam_types: ext, args = self._get_file_format_info(self.format, "CAMGEOM", cam_name) self.log.debug(f"writing {cam_name}") tel_id = cam_types[cam_name].pop() geom = self.subarray.tel[tel_id].camera.geometry table = geom.to_table() table.meta["SOURCE"] = self.infile filename = f"{cam_name}.camgeom.{ext}" try: table.write(filename, **args) Provenance().add_output_file(filename, "dl0.tel.svc.camera") except IOError as err: self.log.warning( "couldn't write camera definition '%s' because: %s", filename, err) def write_optics_descriptions(self): sub = self.subarray ext, args = self._get_file_format_info(self.format, sub.name, "optics") tab = sub.to_table(kind="optics") tab.meta["SOURCE"] = self.infile filename = f"{sub.name}.optics.{ext}" try: tab.write(filename, **args) Provenance().add_output_file(filename, "dl0.sub.svc.optics") except IOError as err: self.log.warning( "couldn't write optics description '%s' because: %s", filename, err) def write_subarray_description(self): sub = self.subarray ext, args = self._get_file_format_info(self.format, sub.name, "subarray") tab = sub.to_table(kind="subarray") tab.meta["SOURCE"] = self.infile filename = f"{sub.name}.subarray.{ext}" try: tab.write(filename, **args) Provenance().add_output_file(filename, "dl0.sub.svc.subarray") except IOError as err: self.log.warning( "couldn't write subarray description '%s' because: %s", filename, err)
class DumpInstrumentTool(Tool): description = Unicode(__doc__) name = "ctapipe-dump-instrument" infile = Path(exists=True, help="input simtelarray file").tag(config=True) format = Enum( ["fits", "ecsv", "hdf5"], default_value="fits", help="Format of output file", config=True, ) aliases = Dict( dict(input="DumpInstrumentTool.infile", format="DumpInstrumentTool.format")) def setup(self): with EventSource(self.infile) as source: self.subarray = source.subarray def start(self): if self.format == "hdf5": self.subarray.to_hdf("subarray.h5") else: self.write_camera_definitions() self.write_optics_descriptions() self.write_subarray_description() def finish(self): pass @staticmethod def _get_file_format_info(format_name): """ returns file extension + dict of required parameters for Table.write""" if format_name == "fits": return "fits.gz", dict() elif format_name == "ecsv": return "ecsv", dict() else: raise NameError(f"format {format_name} not supported") def write_camera_definitions(self): """ writes out camgeom and camreadout files for each camera""" cam_types = get_camera_types(self.subarray) self.subarray.info(printer=self.log.info) for cam_name in cam_types: ext, args = self._get_file_format_info(self.format) self.log.debug(f"writing {cam_name}") tel_id = cam_types[cam_name].pop() geom = self.subarray.tel[tel_id].camera.geometry readout = self.subarray.tel[tel_id].camera.readout geom_table = geom.to_table() geom_table.meta["SOURCE"] = str(self.infile) geom_filename = f"{cam_name}.camgeom.{ext}" readout_table = readout.to_table() readout_table.meta["SOURCE"] = str(self.infile) readout_filename = f"{cam_name}.camreadout.{ext}" try: geom_table.write(geom_filename, **args) readout_table.write(readout_filename, **args) Provenance().add_output_file(geom_filename, "CameraGeometry") Provenance().add_output_file(readout_filename, "CameraReadout") except IOError as err: self.log.warning( "couldn't write camera definition because: %s", err) def write_optics_descriptions(self): """ writes out optics files for each telescope type""" sub = self.subarray ext, args = self._get_file_format_info(self.format) tab = sub.to_table(kind="optics") tab.meta["SOURCE"] = str(self.infile) filename = f"{sub.name}.optics.{ext}" try: tab.write(filename, **args) Provenance().add_output_file(filename, "OpticsDescription") except IOError as err: self.log.warning( "couldn't write optics description '%s' because: %s", filename, err) def write_subarray_description(self): sub = self.subarray ext, args = self._get_file_format_info(self.format) tab = sub.to_table(kind="subarray") tab.meta["SOURCE"] = str(self.infile) filename = f"{sub.name}.subarray.{ext}" try: tab.write(filename, **args) Provenance().add_output_file(filename, "SubarrayDescription") except IOError as err: self.log.warning( "couldn't write subarray description '%s' because: %s", filename, err)
class DumpTriggersTool(Tool): description = Unicode(__doc__) # ============================================= # configuration parameters: # ============================================= infile = Unicode(help='input simtelarray file').tag(config=True) outfile = Unicode('triggers.fits', help='output filename (*.fits, *.h5)').tag(config=True) overwrite = Bool(False, help="overwrite existing output file").tag(config=True) # ============================================= # map low-level options to high-level command-line options # ============================================= aliases = Dict({ 'infile': 'DumpTriggersTool.infile', 'outfile': 'DumpTriggersTool.outfile' }) flags = Dict({ 'overwrite': ({ 'DumpTriggersTool': { 'overwrite': True } }, 'Enable overwriting of output file') }) examples = ('ctapipe-dump-triggers --infile gamma.simtel.gz ' '--outfile trig.fits --overwrite' '\n\n' 'If you want to see more output, use --log_level=DEBUG') # ============================================= # The methods of the Tool (initialize, start, finish): # ============================================= def add_event_to_table(self, event): """ add the current hessio event to a row in the `self.events` table """ gpstime = event.trig.gps_time if self._prev_gpstime is None: self._prev_gpstime = gpstime if self._current_starttime is None: self._current_starttime = gpstime relative_time = gpstime - self._current_starttime delta_t = gpstime - self._prev_gpstime self._prev_gpstime = gpstime # build the trigger pattern as a fixed-length array # (better for storage in FITS format) #trigtels = event.get_telescope_with_data_list() trigtels = event.dl0.tels_with_data self._current_trigpattern[:] = 0 # zero the trigger pattern self._current_trigpattern[list(trigtels)] = 1 # set the triggered tels # to 1 # insert the row into the table self.events.add_row( (event.dl0.event_id, relative_time.sec, delta_t.sec, len(trigtels), self._current_trigpattern)) def setup(self): """ setup function, called before `start()` """ if self.infile == '': raise ValueError("No 'infile' parameter was specified. " "Use --help for info") self.events = Table( names=['EVENT_ID', 'T_REL', 'DELTA_T', 'N_TRIG', 'TRIGGERED_TELS'], dtype=[np.int64, np.float64, np.float64, np.int32, np.uint8]) self.events['TRIGGERED_TELS'].shape = (0, MAX_TELS) self.events['T_REL'].unit = u.s self.events['T_REL'].description = 'Time relative to first event' self.events['DELTA_T'].unit = u.s self.events.meta['INPUT'] = self.infile self._current_trigpattern = np.zeros(MAX_TELS) self._current_starttime = None self._prev_gpstime = None def start(self): """ main event loop """ source = hessio.hessio_event_source(self.infile) for event in source: self.add_event_to_table(event) def finish(self): """ finish up and write out results (called automatically after `start()`) """ # write out the final table if self.outfile.endswith('fits') or self.outfile.endswith('fits.gz'): self.events.write(self.outfile, overwrite=self.overwrite) elif self.outfile.endswith('h5'): self.events.write(self.outfile, path='/events', overwrite=self.overwrite) else: self.events.write(self.outfile) self.log.info("Table written to '{}'".format(self.outfile)) self.log.info('\n %s', self.events)
class DumpInstrumentTool(Tool): description = Unicode(__doc__) name = 'ctapipe-dump-instrument' infile = Unicode(help='input simtelarray file').tag(config=True) format = Enum(['fits', 'ecsv', 'hdf5'], default_value='fits', help='Format of output file', config=True) aliases = Dict( dict(infile='DumpInstrumentTool.infile', format='DumpInstrumentTool.format')) def setup(self): with event_source(self.infile) as source: data = next(iter( source)) # get one event, so the instrument table is there self.inst = data.inst # keep a reference to the instrument stuff def start(self): self.write_camera_geometries() self.write_optics_descriptions() self.write_subarray_description() def finish(self): pass @staticmethod def _get_file_format_info(format_name, table_type, table_name): """ returns file extension + dict of required parameters for Table.write""" if format_name == 'fits': return 'fits.gz', dict() elif format_name == 'ecsv': return 'ecsv.txt', dict(format='ascii.ecsv') elif format_name == 'hdf5': return 'h5', dict(path="/" + table_type + "/" + table_name) else: raise NameError("format not supported") def write_camera_geometries(self): cam_types = get_camera_types(self.inst.subarray) self.inst.subarray.info(printer=self.log.info) for cam_name in cam_types: ext, args = self._get_file_format_info(self.format, 'CAMGEOM', cam_name) self.log.debug(f"writing {cam_name}") tel_id = cam_types[cam_name].pop() geom = self.inst.subarray.tel[tel_id].camera.geometry table = geom.to_table() table.meta['SOURCE'] = self.infile filename = f"{cam_name}.camgeom.{ext}" try: table.write(filename, **args) Provenance().add_output_file(filename, 'dl0.tel.svc.camera') except IOError as err: self.log.warning( "couldn't write camera definition '%s' because: %s", filename, err) def write_optics_descriptions(self): sub = self.inst.subarray ext, args = self._get_file_format_info(self.format, sub.name, 'optics') tab = sub.to_table(kind='optics') tab.meta['SOURCE'] = self.infile filename = f'{sub.name}.optics.{ext}' try: tab.write(filename, **args) Provenance().add_output_file(filename, 'dl0.sub.svc.optics') except IOError as err: self.log.warning( "couldn't write optics description '%s' because: %s", filename, err) def write_subarray_description(self): sub = self.inst.subarray ext, args = self._get_file_format_info(self.format, sub.name, 'subarray') tab = sub.to_table(kind='subarray') tab.meta['SOURCE'] = self.infile filename = f'{sub.name}.subarray.{ext}' try: tab.write(filename, **args) Provenance().add_output_file(filename, 'dl0.sub.svc.subarray') except IOError as err: self.log.warning( "couldn't write subarray description '%s' because: %s", filename, err)
class DumpTriggersTool(Tool): description = Unicode(__doc__) name = "ctapipe-dump-triggers" # ============================================= # configuration parameters: # ============================================= infile = Path(exists=True, directory_ok=False, help="input simtelarray file").tag(config=True) outfile = Path( default_value="triggers.fits", directory_ok=False, help="output filename (*.fits, *.h5)", ).tag(config=True) overwrite = Bool(False, help="overwrite existing output file").tag(config=True) # ============================================= # map low-level options to high-level command-line options # ============================================= aliases = Dict({ "infile": "DumpTriggersTool.infile", "outfile": "DumpTriggersTool.outfile" }) flags = Dict({ "overwrite": ( { "DumpTriggersTool": { "overwrite": True } }, "Enable overwriting of output file", ) }) examples = ("ctapipe-dump-triggers --infile gamma.simtel.gz " "--outfile trig.fits --overwrite" "\n\n" "If you want to see more output, use --log_level=DEBUG") # ============================================= # The methods of the Tool (initialize, start, finish): # ============================================= def add_event_to_table(self, event): """ add the current hessio event to a row in the `self.events` table """ time = event.trigger.time if self._prev_time is None: self._prev_time = time if self._current_starttime is None: self._current_starttime = time relative_time = time - self._current_starttime delta_t = time - self._prev_time self._prev_time = time # build the trigger pattern as a fixed-length array # (better for storage in FITS format) # trigtels = event.get_telescope_with_data_list() trigtels = event.dl0.tel.keys() self._current_trigpattern[:] = 0 # zero the trigger pattern self._current_trigpattern[list(trigtels)] = 1 # set the triggered tels # to 1 # insert the row into the table self.events.add_row(( event.index.event_id, relative_time.sec, delta_t.sec, len(trigtels), self._current_trigpattern, )) def setup(self): """ setup function, called before `start()` """ if self.infile == "": raise ToolConfigurationError( "No 'infile' parameter was specified. ") self.events = Table( names=["EVENT_ID", "T_REL", "DELTA_T", "N_TRIG", "TRIGGERED_TELS"], dtype=[np.int64, np.float64, np.float64, np.int32, np.uint8], ) self.events["TRIGGERED_TELS"].shape = (0, MAX_TELS) self.events["T_REL"].unit = u.s self.events["T_REL"].description = "Time relative to first event" self.events["DELTA_T"].unit = u.s self.events.meta["INPUT"] = str(self.infile) self._current_trigpattern = np.zeros(MAX_TELS) self._current_starttime = None self._prev_time = None def start(self): """ main event loop """ with EventSource(self.infile) as source: for event in source: self.add_event_to_table(event) def finish(self): """ finish up and write out results (called automatically after `start()`) """ # write out the final table try: if ".fits" in self.outfile.suffixes: self.events.write(self.outfile, overwrite=self.overwrite) elif self.outfile.suffix in (".hdf5", ".h5", ".hdf"): self.events.write(self.outfile, path="/events", overwrite=self.overwrite) else: self.events.write(self.outfile) Provenance().add_output_file(self.outfile) except IOError as err: self.log.warning("Couldn't write output (%s)", err) self.log.info("\n %s", self.events)
class SingleTelEventDisplay(Tool): name = "ctapipe-display-televents" description = Unicode(__doc__) tel = Int(help="Telescope ID to display", default_value=0).tag(config=True) write = Bool(help="Write out images to PNG files", default_value=False).tag(config=True) clean = Bool(help="Apply image cleaning", default_value=False).tag(config=True) hillas = Bool(help="Apply and display Hillas parametrization", default_value=False).tag(config=True) samples = Bool(help="Show each sample", default_value=False).tag(config=True) display = Bool(help="Display results in interactive window", default_value=True).tag(config=True) delay = Float(help="delay between events in s", default_value=0.01, min=0.001).tag(config=True) progress = Bool(help="display progress bar", default_value=True).tag(config=True) aliases = Dict({ "input": "EventSource.input_url", "tel": "SingleTelEventDisplay.tel", "max-events": "EventSource.max_events", "write": "SingleTelEventDisplay.write", "clean": "SingleTelEventDisplay.clean", "hillas": "SingleTelEventDisplay.hillas", "samples": "SingleTelEventDisplay.samples", "display": "SingleTelEventDisplay.display", "delay": "SingleTelEventDisplay.delay", "progress": "SingleTelEventDisplay.progress", }) classes = [EventSource, CameraCalibrator] def __init__(self, **kwargs): super().__init__(**kwargs) def setup(self): self.event_source = EventSource(parent=self) self.event_source.allowed_tels = {self.tel} self.calibrator = CameraCalibrator(parent=self, subarray=self.event_source.subarray) self.log.info(f"SELECTING EVENTS FROM TELESCOPE {self.tel}") def start(self): disp = None for event in tqdm( self.event_source, desc=f"Tel{self.tel}", total=self.event_source.max_events, disable=~self.progress, ): self.log.debug(event.trigger) self.log.debug(f"Energy: {event.simulation.shower.energy}") self.calibrator(event) if disp is None: geom = self.event_source.subarray.tel[self.tel].camera.geometry self.log.info(geom) disp = CameraDisplay(geom) # disp.enable_pixel_picker() disp.add_colorbar() if self.display: plt.show(block=False) # display the event disp.axes.set_title("CT{:03d} ({}), event {:06d}".format( self.tel, geom.camera_name, event.index.event_id)) if self.samples: # display time-varying event data = event.dl0.tel[self.tel].waveform for ii in range(data.shape[1]): disp.image = data[:, ii] disp.set_limits_percent(70) plt.suptitle(f"Sample {ii:03d}") if self.display: plt.pause(self.delay) if self.write: plt.savefig( f"CT{self.tel:03d}_EV{event.index.event_id:10d}" f"_S{ii:02d}.png") else: # display integrated event: im = event.dl1.tel[self.tel].image if self.clean: mask = tailcuts_clean(geom, im, picture_thresh=10, boundary_thresh=7) im[~mask] = 0.0 disp.image = im if self.hillas: try: ellipses = disp.axes.findobj(Ellipse) if len(ellipses) > 0: ellipses[0].remove() params = hillas_parameters(geom, image=im) disp.overlay_moments(params, color="pink", lw=3, with_label=False) except HillasParameterizationError: pass if self.display: plt.pause(self.delay) if self.write: plt.savefig( f"CT{self.tel:03d}_EV{event.index.event_id:010d}.png") self.log.info("FINISHED READING DATA FILE") if disp is None: self.log.warning( "No events for tel {} were found in {}. Try a " "different EventIO file or another telescope".format( self.tel, self.infile))
class SimpleEventWriter(Tool): name = "ctapipe-simple-event-writer" description = Unicode(__doc__) infile = Path( default_value=get_dataset_path( "lst_prod3_calibration_and_mcphotons.simtel.zst"), help="input file to read", directory_ok=False, exists=True, ).tag(config=True) outfile = Path(help="output file name", directory_ok=False, default_value="output.h5").tag(config=True) progress = Bool(help="display progress bar", default_value=True).tag(config=True) aliases = Dict({ "infile": "EventSource.input_url", "outfile": "SimpleEventWriter.outfile", "max-events": "EventSource.max_events", "progress": "SimpleEventWriter.progress", }) classes = List([EventSource, CameraCalibrator]) def setup(self): self.log.info("Configure EventSource...") self.event_source = self.add_component( EventSource.from_url(self.infile, parent=self)) self.calibrator = self.add_component( CameraCalibrator(subarray=self.event_source.subarray, parent=self)) self.writer = self.add_component( HDF5TableWriter(filename=self.outfile, group_name="image_infos", overwrite=True)) def start(self): self.log.info("Loop on events...") for event in tqdm( self.event_source, desc="EventWriter", total=self.event_source.max_events, disable=~self.progress, ): self.calibrator(event) for tel_id in event.dl0.tels_with_data: geom = self.event_source.subarray.tel[tel_id].camera.geometry dl1_tel = event.dl1.tel[tel_id] # Image cleaning image = dl1_tel.image # Waiting for automatic gain selection mask = tailcuts_clean(geom, image, picture_thresh=10, boundary_thresh=5) cleaned = image.copy() cleaned[~mask] = 0 # Image parametrisation params = hillas_parameters(geom, cleaned) # Save Ids, MC infos and Hillas informations self.writer.write(geom.camera_name, [event.r0, event.mc, params]) def finish(self): self.log.info("End of job.") self.writer.close()
class SingleTelEventDisplay(Tool): name = "ctapipe-display-single-tel" description = Unicode(__doc__) infile = Unicode(help="input file to read", default='').tag(config=True) tel = Int(help='Telescope ID to display', default=0).tag(config=True) channel = Integer( help="channel number to display", min=0, max=1 ).tag(config=True) write = Bool( help="Write out images to PNG files", default=False ).tag(config=True) clean = Bool(help="Apply image cleaning", default=False).tag(config=True) hillas = Bool( help="Apply and display Hillas parametrization", default=False ).tag(config=True) samples = Bool(help="Show each sample", default=False).tag(config=True) display = Bool( help="Display results in interactive window", default_value=True ).tag(config=True) delay = Float( help='delay between events in s', default_value=0.01, min=0.001 ).tag(config=True) progress = Bool( help='display progress bar', default_value=True ).tag(config=True) aliases = Dict({ 'infile': 'EventSourceFactory.input_url', 'tel': 'SingleTelEventDisplay.tel', 'max-events': 'EventSourceFactory.max_events', 'channel': 'SingleTelEventDisplay.channel', 'write': 'SingleTelEventDisplay.write', 'clean': 'SingleTelEventDisplay.clean', 'hillas': 'SingleTelEventDisplay.hillas', 'samples': 'SingleTelEventDisplay.samples', 'display': 'SingleTelEventDisplay.display', 'delay': 'SingleTelEventDisplay.delay', 'progress': 'SingleTelEventDisplay.progress' }) classes = List([EventSourceFactory, CameraCalibrator]) def setup(self): self.event_source = EventSourceFactory.produce( config=self.config, tool=self ) self.event_source.allowed_tels = [ self.tel, ] self.calibrator = CameraCalibrator( config=self.config, tool=self, eventsource=self.event_source ) self.log.info('SELECTING EVENTS FROM TELESCOPE {}'.format(self.tel)) def start(self): disp = None for event in tqdm( self.event_source, desc='Tel{}'.format(self.tel), total=self.event_source.max_events, disable=~self.progress ): self.log.debug(event.trig) self.log.debug("Energy: {}".format(event.mc.energy)) self.calibrator.calibrate(event) if disp is None: geom = event.inst.subarray.tel[self.tel].camera self.log.info(geom) disp = CameraDisplay(geom) # disp.enable_pixel_picker() disp.add_colorbar() if self.display: plt.show(block=False) # display the event disp.axes.set_title( 'CT{:03d} ({}), event {:06d}'.format( self.tel, geom.cam_id, event.r0.event_id ) ) if self.samples: # display time-varying event data = event.dl0.tel[self.tel].waveform[self.channel] for ii in range(data.shape[1]): disp.image = data[:, ii] disp.set_limits_percent(70) plt.suptitle("Sample {:03d}".format(ii)) if self.display: plt.pause(self.delay) if self.write: plt.savefig( 'CT{:03d}_EV{:10d}_S{:02d}.png' .format(self.tel, event.r0.event_id, ii) ) else: # display integrated event: im = event.dl1.tel[self.tel].image[self.channel] if self.clean: mask = tailcuts_clean( geom, im, picture_thresh=10, boundary_thresh=7 ) im[~mask] = 0.0 disp.image = im if self.hillas: try: ellipses = disp.axes.findobj(Ellipse) if len(ellipses) > 0: ellipses[0].remove() params = hillas_parameters(geom, image=im) disp.overlay_moments( params, color='pink', lw=3, with_label=False ) except HillasParameterizationError: pass if self.display: plt.pause(self.delay) if self.write: plt.savefig( 'CT{:03d}_EV{:010d}.png' .format(self.tel, event.r0.event_id) ) self.log.info("FINISHED READING DATA FILE") if disp is None: self.log.warning( 'No events for tel {} were found in {}. Try a ' 'different EventIO file or another telescope' .format(self.tel, self.infile), )