def main(input_file, output_file, limit): ''' The INPUT_FILE argument specifies the path to a simtel file. This script reads the camera definitions from there and puts them into a json file specified by OUTPUT_FILE argument. ''' event_source = EventSourceFactory.produce( input_url=input_file, max_events=limit if limit > 1 else None, ) calibrator = CameraCalibrator(eventsource=event_source, ) data = [] for id, event in tqdm(enumerate(event_source)): if len(valid_triggerd_cameras(event)) < 2: continue calibrator.calibrate(event) c = {} # import IPython; IPython.embed() c['array'] = fill_array_dict(valid_triggerd_telescope_ids(event)) c['event_id'] = id c['images'] = fill_images_dict(event) c['mc'] = fill_mc_dict(event) data.append(c) with gzip.open(output_file, 'wt') as of: json.dump(data, of, indent=2)
class DisplayDL1Calib(Tool): name = "ctapipe-display-dl1" description = __doc__ telescope = Int(None, allow_none=True, help='Telescope to view. Set to None to display all ' 'telescopes.').tag(config=True) extractor_product = tool_utils.enum_trait(ImageExtractor, default='NeighborPeakWindowSum') aliases = Dict( dict(max_events='EventSource.max_events', extractor='DisplayDL1Calib.extractor_product', T='DisplayDL1Calib.telescope', O='ImagePlotter.output_path')) flags = Dict( dict(D=({ 'ImagePlotter': { 'display': True } }, "Display the photoelectron images on-screen as they " "are produced."))) classes = List([EventSource, CameraDL1Calibrator, ImagePlotter] + tool_utils.classes_with_traits(ImageExtractor)) def __init__(self, **kwargs): super().__init__(**kwargs) self.eventsource = None self.calibrator = None self.plotter = None def setup(self): self.eventsource = EventSource.from_url( get_dataset_path("gamma_test_large.simtel.gz"), parent=self, ) self.calibrator = CameraCalibrator(parent=self) self.plotter = ImagePlotter(parent=self) def start(self): for event in self.eventsource: self.calibrator.calibrate(event) tel_list = event.r0.tels_with_data if self.telescope: if self.telescope not in tel_list: continue tel_list = [self.telescope] for telid in tel_list: self.plotter.plot(event, telid) def finish(self): self.plotter.finish()
def load_calibrate(filename): # LOAD AND CALIBRATE # pwd = "/home/thomas/Programs/astro/CTAPIPE_DAN/" # filename = 'gamma_20deg_0deg_run100___cta-prod3-lapalma3-2147m-LaPalma_cone10.simtel.gz' # filename = 'gamma_20deg_0deg_run100___cta-prod3_desert-2150m-Paranal-merged.simtel.gz' # filename = 'gamma_20deg_0deg_run118___cta-prod3_desert-2150m-Paranal-merged_cone10.simtel.gz' # filename = 'gamma_20deg_180deg_run11___cta-prod3_desert-2150m-Paranal-merged_cone10.simtel.gz' # layout = np.loadtxt(pwd+'CTA.prod3Sb.3HB9-FG.lis', usecols=0, dtype=int) if "Paranal" in filename: layout = [4, 5, 6, 11] print("PARANAL WITH {0}".format(layout)) elif "palma" in filename: layout = [5, 6, 7, 8] print("LAPALMA WITH {0}".format(layout)) print("Layout telescopes IDs:".format(layout)) # layout = [279, 280, 281, 282, 283, 284, 286, 287, 289, 297, 298, 299, # 300, 301, 302, 303, 304, 305, 306, 307, 308, 315, 316, 317, # 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, # 330, 331, 332, 333, 334, 335, 336, 337, 338, 345, 346, 347, # 348, 349, 350, 375, 376, 377, 378, 379, 380, 393, 400, 402, # 403, 404, 405, 406, 408, 410, 411, 412, 413, 414, 415, 416, # 417] layout = set(layout) source = event_source(filename) source.max_events = 50 source.allowed_tels = layout events = [copy.deepcopy(event) for event in source] cal = CameraCalibrator(None, None, r1_product='HESSIOR1Calibrator', extractor_product='NeighbourPeakIntegrator') for event in events: cal.calibrate(event) # Find "big" event (piece of code from T.V. notebook ...thanks :D ) events_amplitude = [] for event in events: event_amplitude = 0 for tel_id in event.r0.tels_with_data: if event.dl1.tel[tel_id].image is not None: event_amplitude += event.dl1.tel[tel_id].image[0].sum() events_amplitude.append(event_amplitude) events_amplitude = np.array(events_amplitude) mm = events_amplitude.argmax() print("event: {0}".format(mm)) event = events[mm] return event
def main(simtel_file, output_pdf, num_events): event_source = EventSourceFactory.produce( input_url=simtel_file, max_events=num_events, ) calibrator = CameraCalibrator(eventsource=event_source, ) with PdfPages(output_pdf) as pdf: for event in tqdm(event_source, total=num_events): if event.mc.energy > 10 * u.TeV: calibrator.calibrate(event) reco = HillasReconstructor() plt.figure(figsize=(20, 20)) plt.suptitle( f'EVENT {event.r0.event_id} \n Energy: {event.mc.energy} \n Type: {event.mc.shower_primary_id}' ) try: result = plot_event(event, reco, pdf) except TooFewTelescopesException: pdf.savefig() # saves the current figure into a pdf page plt.close() continue pdf.savefig() # saves the current figure into a pdf page plt.close() d = calculate_distance_theta(result.alt, result.az, event.mc.alt, event.mc.az) plt.figure(figsize=(18, 18)) plot_array_birdsview(event, result, reco) plt.suptitle( f'EVENT {event.r0.event_id} \n Energy: {event.mc.energy} \n Type: {event.mc.shower_primary_id} \n \ Alt: {event.mc.alt.to(u.deg)}, Az: {event.mc.az.to(u.deg)} \n \ Predicted Alt: {result.alt.to(u.deg)}, Predicted Az: {result.az.to(u.deg)} \n \ Distance {d}') plt.legend() pdf.savefig() # saves the current figure into a pdf page plt.close() plt.figure(figsize=(18, 18)) plot_array_sideview(event, result, reco) plt.suptitle( f'EVENT {event.r0.event_id} \n Energy: {event.mc.energy} \n Type: {event.mc.shower_primary_id} \n \ Alt: {event.mc.alt.to(u.deg)}, Az: {event.mc.az.to(u.deg)} \n \ Predicted Alt: {result.alt.to(u.deg)}, Predicted Az: {result.az.to(u.deg)} \n \ Distance: {d}') plt.legend() pdf.savefig() # saves the current figure into a pdf page plt.close()
def test_basic_muon_reco(example_event): """ Really simplistic test: just run the analyze_muon_event code, to make sure it doesn't crash. The input event is so far not a muon, so no output is generated. Parameters ---------- test_event - a sample event (fixture) """ calib = CameraCalibrator() calib.calibrate(example_event) muon_params = muon.analyze_muon_event(example_event) assert muon_params is not None
def process_file(input_file, reco_algorithm, n_events=-1, silent=False): event_source = EventSourceFactory.produce( input_url=input_file, max_events=n_events if n_events > 1 else None, product='HESSIOEventSource', ) calibrator = CameraCalibrator(eventsource=event_source, ) telescope_event_information = [] array_event_information = [] for event in tqdm(event_source, disable=silent): if number_of_valid_triggerd_cameras(event) < 2: continue calibrator.calibrate(event) try: image_features, reconstruction, _, _ = process_event( event, reco_algorithm=reco_algorithm) event_features = event_information(event, image_features, reconstruction) array_event_information.append(event_features) telescope_event_information.append(image_features) except TooFewTelescopesException: continue if (len(telescope_event_information) == 0): return None, None, None telescope_events = pd.concat(telescope_event_information) telescope_events.set_index(['run_id', 'array_event_id', 'telescope_id'], drop=True, verify_integrity=True, inplace=True) array_events = pd.DataFrame(array_event_information) array_events.set_index(['run_id', 'array_event_id'], drop=True, verify_integrity=True, inplace=True) run_information = read_simtel_mc_information(input_file) df_runs = pd.DataFrame([run_information]) df_runs.set_index('run_id', drop=True, verify_integrity=True, inplace=True) return df_runs, array_events, telescope_events
class DisplayDL1Calib(Tool): name = "DisplayDL1Calib" description = "Calibrate dl0 data to dl1, and plot the photoelectron " \ "images." telescope = Int(None, allow_none=True, help='Telescope to view. Set to None to display all ' 'telescopes.').tag(config=True) aliases = Dict( dict(f='EventFileReaderFactory.input_path', r='EventFileReaderFactory.reader', max_events='EventFileReaderFactory.max_events', extractor='ChargeExtractorFactory.extractor', window_width='ChargeExtractorFactory.window_width', t0='ChargeExtractorFactory.t0', window_shift='ChargeExtractorFactory.window_shift', sig_amp_cut_HG='ChargeExtractorFactory.sig_amp_cut_HG', sig_amp_cut_LG='ChargeExtractorFactory.sig_amp_cut_LG', lwt='ChargeExtractorFactory.lwt', clip_amplitude='CameraDL1Calibrator.clip_amplitude', T='DisplayDL1Calib.telescope', O='ImagePlotter.output_path')) flags = Dict( dict(D=({ 'ImagePlotter': { 'display': True } }, "Display the photoelectron images on-screen as they " "are produced."))) classes = List([ EventFileReaderFactory, ChargeExtractorFactory, CameraDL1Calibrator, ImagePlotter ]) def __init__(self, **kwargs): super().__init__(**kwargs) self.reader = None self.calibrator = None self.plotter = None def setup(self): self.log_format = "%(levelname)s: %(message)s [%(name)s.%(funcName)s]" kwargs = dict(config=self.config, tool=self) reader_factory = EventFileReaderFactory(**kwargs) reader_class = reader_factory.get_class() self.reader = reader_class(**kwargs) self.calibrator = CameraCalibrator(origin=self.reader.origin, **kwargs) self.plotter = ImagePlotter(**kwargs) def start(self): source = self.reader.read() for event in source: self.calibrator.calibrate(event) tel_list = event.r0.tels_with_data if self.telescope: if self.telescope not in tel_list: continue tel_list = [self.telescope] for telid in tel_list: self.plotter.plot(event, telid) def finish(self): self.plotter.finish()
class DisplayDL1Calib(Tool): name = "ctapipe-display-dl1" description = __doc__ telescope = Int( None, allow_none=True, help='Telescope to view. Set to None to display all ' 'telescopes.' ).tag(config=True) extractor_product = tool_utils.enum_trait( ImageExtractor, default='NeighborPeakWindowSum' ) aliases = Dict( dict( max_events='EventSource.max_events', extractor='DisplayDL1Calib.extractor_product', T='DisplayDL1Calib.telescope', O='ImagePlotter.output_path' ) ) flags = Dict( dict( D=( { 'ImagePlotter': { 'display': True } }, "Display the photoelectron images on-screen as they " "are produced." ) ) ) classes = List( [ EventSource, CameraDL1Calibrator, ImagePlotter ] + tool_utils.classes_with_traits(ImageExtractor) ) def __init__(self, **kwargs): super().__init__(**kwargs) self.eventsource = None self.calibrator = None self.plotter = None def setup(self): self.eventsource = EventSource.from_url( get_dataset_path("gamma_test_large.simtel.gz"), parent=self, ) self.calibrator = CameraCalibrator( eventsource=self.eventsource, parent=self, ) self.plotter = ImagePlotter(parent=self) def start(self): for event in self.eventsource: self.calibrator.calibrate(event) tel_list = event.r0.tels_with_data if self.telescope: if self.telescope not in tel_list: continue tel_list = [self.telescope] for telid in tel_list: self.plotter.plot(event, telid) def finish(self): self.plotter.finish()
class SimpleEventWriter(Tool): name = 'ctapipe-simple-event-writer' description = Unicode(__doc__) infile = Unicode(help='input file to read', default='').tag(config=True) outfile = Unicode(help='output file name', default_value='output.h5').tag(config=True) progress = Bool(help='display progress bar', default_value=True).tag(config=True) aliases = Dict({ 'infile': 'EventSourceFactory.input_url', 'outfile': 'SimpleEventWriter.outfile', 'max-events': 'EventSourceFactory.max_events', 'progress': 'SimpleEventWriter.progress' }) classes = List([EventSourceFactory, CameraCalibrator, CutFlow]) def setup(self): self.log.info('Configure EventSourceFactory...') self.event_source = EventSourceFactory.produce( config=self.config, tool=self, product='HESSIOEventSource') self.event_source.allowed_tels = self.config['Analysis'][ 'allowed_tels'] self.calibrator = CameraCalibrator(config=self.config, tool=self, eventsource=self.event_source) self.writer = HDF5TableWriter(filename=self.outfile, group_name='image_infos', overwrite=True) # Define Pre-selection for images preselcuts = self.config['Preselect'] self.image_cutflow = CutFlow('Image preselection') self.image_cutflow.set_cuts( dict(no_sel=None, n_pixel=lambda s: np.count_nonzero(s) < preselcuts['n_pixel'][ 'min'], image_amplitude=lambda q: q < preselcuts['image_amplitude'][ 'min'])) # Define Pre-selection for events self.event_cutflow = CutFlow('Event preselection') self.event_cutflow.set_cuts(dict(no_sel=None)) 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.event_cutflow.count('no_sel') self.calibrator.calibrate(event) for tel_id in event.dl0.tels_with_data: self.image_cutflow.count('no_sel') camera = event.inst.subarray.tel[tel_id].camera dl1_tel = event.dl1.tel[tel_id] # Image cleaning image = dl1_tel.image[ 0] # Waiting for automatic gain selection mask = tailcuts_clean(camera, image, picture_thresh=10, boundary_thresh=5) cleaned = image.copy() cleaned[~mask] = 0 # Preselection cuts if self.image_cutflow.cut('n_pixel', cleaned): continue if self.image_cutflow.cut('image_amplitude', np.sum(cleaned)): continue # Image parametrisation params = hillas_parameters(camera, cleaned) # Save Ids, MC infos and Hillas informations self.writer.write(camera.cam_id, [event.r0, event.mc, params]) def finish(self): self.log.info('End of job.') self.image_cutflow() self.event_cutflow() self.writer.close()
class CTAFileLoader(object): """ Loads CTA Files and handles them for saving events in different format """ # particle ID: 0 for gamma, 1 for proton def __init__(self, telescopes, file_name_mask, load_option, calibrate=False, use_cut_value=-1, pedestals_only=False): """ :param particleID: ID of particle to save, deprecated :param telescopes: set of telescopes to save events for :param start_at_runnum: runnum to start at :param end_at_runnum: runnum to stop at (file is included) :param load_file_name_start: name of file to load after runnum :param load_file_name_end: name of file to load after runnum :param use_cut_value: use cut and remove all events lower, -1 for no cut """ self.pedestals_only = pedestals_only self.calibrate = calibrate self.eventList = [] self.load_option = load_option CameraCalibrator() # CameraCalibrator() if calibrate: config = traitlets.config.Config() self.calibrator = CameraCalibrator(config=config) # r1_product="HESSIOR1Calibrator",extractor_product="NeighbourPeakIntegrator", self.telescopes = telescopes # # Mask run number with @ # self.runnumset = set() p = file_name_mask.split(sep="/") path = "" for k in range(len(p) - 1): path += p[k] + "/" filename_mask = p[-1] p = None self.masked_file_name = filename_mask self.path = path fl = glob.glob(path + filename_mask.replace('@', '*')) mask = r"\w+_M\d{1}.*_(\d+).*_Y_.+.*" for fp in fl: s2 = fp.split(sep="/")[-1] self.runnumset.add(re.findall(mask, s2)[0]) self.file_name_mask = filename_mask self.cut_value = use_cut_value self.use_cut = False if self.cut_value == -1 else True if load_option == LoadOption.cal_at_once: self.loadFilesWithMask() def loadFileWithID(self, fid): filename = self.loadFileName_start + str(fid) + self.loadFileName_end #if self.particleID == 1: # filename = "Protons/proton_20deg_174.681deg_run" + str( # fid) + "___cta-prod4-lapalma-2158m--baseline_with-MAGIC.simtel.gz" #elif self.particleID == 0: # filename = "Gamma/gamma_20deg_174.681deg_run" + str( # fid) + "___cta-prod4-lapalma-2158m--baseline_with-MAGIC_cone1.5.simtel.gz" # print("Invalid particle ID given, please set 0 for gamma, 1 for proton file to load") self.loadFile(self.filepath + filename) def loadFileWithID_string(self, fidstr): filename = self.loadFileName_start + fidstr + self.loadFileName_end #if self.particleID == 1: # filename = "Protons/proton_20deg_174.681deg_run" + str( # fid) + "___cta-prod4-lapalma-2158m--baseline_with-MAGIC.simtel.gz" #elif self.particleID == 0: # filename = "Gamma/gamma_20deg_174.681deg_run" + str( # fid) + "___cta-prod4-lapalma-2158m--baseline_with-MAGIC_cone1.5.simtel.gz" # print("Invalid particle ID given, please set 0 for gamma, 1 for proton file to load") self.loadFile(self.filepath + filename) def loadNextFile(self): maxFilesToTest = 100 currentFileToTest = 0 # If all files were loaded at once if self.load_option == LoadOption.cal_at_once: if self.eventList <= 0: print("Eventlist empty - all events used") return False return True if len(self.runnumset) > 0: # runnumset namecopy = copy.deepcopy(self.file_name_mask) fnmask = self.path + namecopy.replace("@", self.runnumset.pop()) print("QAI: ", fnmask) #try: if self.loadFile(fnmask): return True #finally: # print("Error loading files, ending...") print("Loaded all files.") return False print("Could not find next file.") def loadFilesWithMask(self): # Use masks? path = "/remote/ceph/group/magic/MAGIC-LST/MARS/CrabNebula/CalibratedWithPointings/2018_03_09/*05070968*00[1-2]*root" mask = self.filepath + self.loadFileName_start + "*" + self.loadFileName_end # Might need to change this line to work? event_factory = MAGICEventSource(input_url=path) event_factory.allowed_tels = self.telescopes #{1, 2} event_generator = event_factory._generator() # event = next(event_generator) for s_event in event_generator: # Use event only if M1 and M2 are triggered #if 1 in s_event.r0.tels_with_data and 1 in self.telescopes and 2 in s_event.r0.tels_with_data: if self.telescopes <= s_event.r0.tels_with_data: self.calibrator.calibrate(s_event) # print("Oder num: {:d}, event id: {:.0f}, triggered telescopes: {}".format(stereo_event.count, stereo_event.r0.event_id, stereo_event.r0.tels_with_data)) a = copy.deepcopy(s_event) self.eventList.append(a) #event_factory.pyhessio.close_file() print("New File loaded, file {:d} contains {:d} events".format( 14, len(self.eventList))) def loadFile(self, path): # Use masks? path = "/remote/ceph/group/magic/MAGIC-LST/MARS/CrabNebula/CalibratedWithPointings/2018_03_09/*05070968*00[1-2]*root" # might need to change this line to work? #try: if True: if self.load_option == LoadOption.raw_sim or self.load_option == LoadOption.raw_data: event_factory = event_source(input_url=path) event_factory.allowed_tels = self.telescopes #{1, 2} event_generator = event_factory._generator() if self.pedestals_only: print( "Warning: Pedestals only available for real data, not for simulation data." ) elif self.load_option == LoadOption.cal_sim or self.load_option == LoadOption.cal_data: #event_factory.allowed_tels = self.telescopes #{1, 2} if self.pedestals_only: event_factory = MAGICEventSource(input_url=path) pedestal_event_generator1 = event_factory._pedestal_event_generator( telescope='M1') pedestal_event_generator2 = event_factory._pedestal_event_generator( telescope='M2') else: event_factory = MAGICEventSource(input_url=path) event_generator = event_factory._generator() else: #except Exception as e: print("Error 194: File does not exist: " + path + " or ") print("Error: %s" % str(e)) return False # event = next(event_generator) if self.pedestals_only: ped_available = True while ped_available: try: p1 = next(pedestal_event_generator1, None) p2 = next(pedestal_event_generator2, None) except: print("Errror:") p1 = None p2 = None if p1 is None or p2 is None: ped_available = False else: a1 = copy.deepcopy(p1) a2 = copy.deepcopy(p2) self.eventList.append({1: a1, 2: a2}) else: for s_event in event_generator: # Use event only if M1 and M2 are triggered #if 1 in s_event.r0.tels_with_data and 1 in self.telescopes and 2 in s_event.r0.tels_with_data: if self.telescopes <= s_event.r0.tels_with_data: if self.calibrate: self.calibrator(s_event) # print("Oder num: {:d}, event id: {:.0f}, triggered telescopes: {}".format(stereo_event.count, stereo_event.r0.event_id, stereo_event.r0.tels_with_data)) a = copy.deepcopy(s_event) if not self.use_cut or apply_cut(a, self.cut_value, self.load_option): self.eventList.append(a) #print("Accepted. ",len(self.eventList)) #event_factory.pyhessio.close_file() print("New File loaded, file {:d} contains {:d} events".format( 14, len(self.eventList))) return True def checkEventList(self): """ Checks whether eventList is empty and loads new file if it is Returns False if it is empty and all files were loaded Return True if it is not empty """ if len(self.eventList) < 1: print("Not enough") if self.loadNextFile(): if not self.checkEventList(): return False else: return False #print("Loaded") return True def getNextEvent(self): """ Returns next event and removes it from eventList Automatically loads next file if eventList is empty """ if self.checkEventList(): return self.eventList.pop(0) else: return None
""" The most basic pipeline, using no special features of the framework other than a for-loop. This is useful for debugging and profiling of speed. """ import sys import numpy as np from ctapipe.calib import CameraCalibrator from ctapipe.io.hessio import hessio_event_source if __name__ == '__main__': filename = sys.argv[1] source = hessio_event_source(filename, max_events=None) cal = CameraCalibrator(None, None) for data in source: print("EVENT: {}, ENERGY: {:.2f}, TELS:{}".format( data.r0.event_id, data.mc.energy, len(data.dl0.tels_with_data))) cal.calibrate(data) # now the calibrated images are in data.dl1.tel[x].image
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': 'EventFileReaderFactory.input_path', 'tel': 'SingleTelEventDisplay.tel', 'max-events': 'EventFileReaderFactory.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([EventFileReaderFactory, CameraCalibrator]) def setup(self): reader_factory = EventFileReaderFactory(None, self) reader_class = reader_factory.get_class() self.reader = reader_class(None, self) self.calibrator = CameraCalibrator(config=None, tool=self, origin=self.reader.origin) self.source = self.reader.read(allowed_tels=[self.tel, ]) self.log.info('SELECTING EVENTS FROM TELESCOPE {}'.format(self.tel)) def start(self): disp = None for event in tqdm(self.source, desc='Tel{}'.format(self.tel), total=self.reader.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: x, y = event.inst.pixel_pos[self.tel] focal_len = event.inst.optical_foclen[self.tel] geom = CameraGeometry.guess(x, y, focal_len) 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].pe_samples[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(pix_x=geom.pix_x, pix_y=geom.pix_y, 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), ) pass
class EventPreparer: """ Class which loop on events and returns results stored in container The Class has several purposes. First of all, it prepares the images of the event that will be further use for reconstruction by applying calibration, cleaning and selection. Then, it reconstructs the geometry of the event and then returns image (e.g. Hillas parameters)and event information (e.g. reults od the reconstruction). Parameters ---------- config: dict Configuration with analysis parameters mode: str Mode of the reconstruction, e.g. tail or wave event_cutflow: ctapipe.utils.CutFlow Statistic of events processed image_cutflow: ctapipe.utils.CutFlow Statistic of images processed Returns: dict Dictionnary of results """ def __init__(self, config, mode, event_cutflow=None, image_cutflow=None): # Cleaning for reconstruction self.cleaner_reco = ImageCleaner( # for reconstruction config=config["ImageCleaning"]["biggest"], mode=mode) # Cleaning for energy/score estimation # Add possibility to force energy/score cleaning with tailcut analysis force_mode = mode try: if config["General"]["force_tailcut_for_extended_cleaning"] is True: force_mode = config["General"]["force_mode"] print("> Activate force-mode for cleaning!!!!") except: pass # force_mode = mode self.cleaner_extended = ImageCleaner( # for energy/score estimation config=config["ImageCleaning"]["extended"], mode=force_mode) # Image book keeping self.image_cutflow = image_cutflow or CutFlow("ImageCutFlow") # Add quality cuts on images charge_bounds = config["ImageSelection"]["charge"] npix_bounds = config["ImageSelection"]["pixel"] ellipticity_bounds = config["ImageSelection"]["ellipticity"] nominal_distance_bounds = config["ImageSelection"]["nominal_distance"] self.camera_radius = { "LSTCam": 1.126, "NectarCam": 1.126, } # Average between max(xpix) and max(ypix), in meter self.image_cutflow.set_cuts( OrderedDict([ ("noCuts", None), ("min pixel", lambda s: np.count_nonzero(s) < npix_bounds[0]), ("min charge", lambda x: x < charge_bounds[0]), # ("poor moments", lambda m: m.width <= 0 or m.length <= 0 or np.isnan(m.width) or np.isnan(m.length)), # TBC, maybe we loose events without nan conditions ("poor moments", lambda m: m.width <= 0 or m.length <= 0), ( "bad ellipticity", lambda m: (m.width / m.length) < ellipticity_bounds[0] or (m.width / m.length) > ellipticity_bounds[-1], ), # ("close to the edge", lambda m, cam_id: m.r.value > (nominal_distance_bounds[-1] * 1.12949101073069946)) # in meter ( "close to the edge", lambda m, cam_id: m.r.value > (nominal_distance_bounds[-1] * self.camera_radius[cam_id]), ), # in meter ])) # Reconstruction self.shower_reco = HillasReconstructor() # Event book keeping self.event_cutflow = event_cutflow or CutFlow("EventCutFlow") # Add cuts on events min_ntel = config["Reconstruction"]["min_tel"] self.event_cutflow.set_cuts( OrderedDict([ ("noCuts", None), ("min2Tels trig", lambda x: x < min_ntel), ("min2Tels reco", lambda x: x < min_ntel), ("direction nan", lambda x: x.is_valid == False), ])) def prepare_event(self, source, return_stub=False): # configuration for the camera calibrator # modifies the integration window to be more like in MARS # JLK, only for LST!!!! # Option for integration correction is done above cfg = Config() cfg["ChargeExtractorFactory"]["window_width"] = 5 cfg["ChargeExtractorFactory"]["window_shift"] = 2 self.calib = CameraCalibrator( config=cfg, extractor_product="LocalPeakIntegrator", eventsource=source, tool=None, ) for event in source: self.event_cutflow.count("noCuts") if self.event_cutflow.cut("min2Tels trig", len(event.dl0.tels_with_data)): if return_stub: yield stub(event) else: continue # calibrate the event self.calib.calibrate(event) # telescope loop tot_signal = 0 max_signals = {} n_pixel_dict = {} hillas_dict_reco = {} # for geometry hillas_dict = {} # for discrimination n_tels = { "tot": len(event.dl0.tels_with_data), "LST": 0, "MST": 0, "SST": 0, } n_cluster_dict = {} impact_dict_reco = {} # impact distance measured in tilt system point_azimuth_dict = {} point_altitude_dict = {} # To compute impact parameter in tilt system run_array_direction = event.mcheader.run_array_direction az, alt = run_array_direction[0], run_array_direction[1] ground_frame = GroundFrame() for tel_id in event.dl0.tels_with_data: self.image_cutflow.count("noCuts") camera = event.inst.subarray.tel[tel_id].camera # count the current telescope according to its size tel_type = event.inst.subarray.tel[tel_id].optics.tel_type # JLK, N telescopes before cut selection are not really interesting for # discrimination, too much fluctuations # n_tels[tel_type] += 1 # the camera image as a 1D array and stuff needed for calibration # Choose gain according to pywicta's procedure image_1d = simtel_event_to_images(event=event, tel_id=tel_id, ctapipe_format=True) pmt_signal = image_1d.input_image # calibrated image # clean the image try: with warnings.catch_warnings(): # Image with biggest cluster (reco cleaning) image_biggest = self.cleaner_reco.clean_image( pmt_signal, camera) image_biggest2d = geometry_converter.image_1d_to_2d( image_biggest, camera.cam_id) image_biggest2d = filter_pixels_clusters( image_biggest2d) image_biggest = geometry_converter.image_2d_to_1d( image_biggest2d, camera.cam_id) # Image for score/energy estimation (with clusters) image_extended = self.cleaner_extended.clean_image( pmt_signal, camera) except FileNotFoundError as e: # JLK, WHAT? print(e) continue # Apply some selection if self.image_cutflow.cut("min pixel", image_biggest): continue if self.image_cutflow.cut("min charge", np.sum(image_biggest)): continue # For cluster counts image_2d = geometry_converter.image_1d_to_2d( image_extended, camera.cam_id) n_cluster_dict[ tel_id] = pixel_clusters.number_of_pixels_clusters( array=image_2d, threshold=0) # could this go into `hillas_parameters` ...? max_signals[tel_id] = np.max(image_extended) # do the hillas reconstruction of the images # QUESTION should this change in numpy behaviour be done here # or within `hillas_parameters` itself? # JLK: make selection on biggest cluster with np.errstate(invalid="raise", divide="raise"): try: moments_reco = hillas_parameters( camera, image_biggest) # for geometry (eg direction) moments = hillas_parameters( camera, image_extended ) # for discrimination and energy reconstruction # if width and/or length are zero (e.g. when there is only only one # pixel or when all pixel are exactly in one row), the # parametrisation won't be very useful: skip if self.image_cutflow.cut("poor moments", moments_reco): # print('poor moments') continue if self.image_cutflow.cut("close to the edge", moments_reco, camera.cam_id): # print('close to the edge') continue if self.image_cutflow.cut("bad ellipticity", moments_reco): # print('bad ellipticity: w={}, l={}'.format(moments_reco.width, moments_reco.length)) continue except (FloatingPointError, hillas.HillasParameterizationError): continue point_azimuth_dict[ tel_id] = event.mc.tel[tel_id].azimuth_raw * u.rad point_altitude_dict[ tel_id] = event.mc.tel[tel_id].altitude_raw * u.rad n_tels[tel_type] += 1 hillas_dict[tel_id] = moments hillas_dict_reco[tel_id] = moments_reco n_pixel_dict[tel_id] = len(np.where(image_extended > 0)[0]) tot_signal += moments.intensity n_tels["reco"] = len(hillas_dict_reco) n_tels["discri"] = len(hillas_dict) if self.event_cutflow.cut("min2Tels reco", n_tels["reco"]): if return_stub: yield stub(event) else: continue try: with warnings.catch_warnings(): warnings.simplefilter("ignore") # Reconstruction results reco_result = self.shower_reco.predict( hillas_dict_reco, event.inst, point_altitude_dict, point_azimuth_dict, ) # shower_sys = TiltedGroundFrame(pointing_direction=HorizonFrame( # az=reco_result.az, # alt=reco_result.alt # )) # Impact parameter for energy estimation (/ tel) subarray = event.inst.subarray for tel_id in hillas_dict.keys(): pos = subarray.positions[tel_id] tel_ground = SkyCoord(pos[0], pos[1], pos[2], frame=ground_frame) # tel_tilt = tel_ground.transform_to(shower_sys) core_ground = SkyCoord( reco_result.core_x, reco_result.core_y, 0 * u.m, frame=ground_frame, ) # core_tilt = core_ground.transform_to(shower_sys) # Should be better handled (tilted frame) impact_dict_reco[tel_id] = np.sqrt( (core_ground.x - tel_ground.x)**2 + (core_ground.y - tel_ground.y)**2) except Exception as e: print("exception in reconstruction:", e) raise if return_stub: yield stub(event) else: continue if self.event_cutflow.cut("direction nan", reco_result): if return_stub: yield stub(event) else: continue yield PreparedEvent( event=event, n_pixel_dict=n_pixel_dict, hillas_dict=hillas_dict, hillas_dict_reco=hillas_dict_reco, n_tels=n_tels, tot_signal=tot_signal, max_signals=max_signals, n_cluster_dict=n_cluster_dict, reco_result=reco_result, impact_dict=impact_dict_reco, )
class ImageSumDisplayerTool(Tool): description = Unicode(__doc__) name = "ctapipe-image-sum-display" infile = Unicode(help='input simtelarray file', default="/Users/kosack/Data/CTA/Prod3/gamma.simtel.gz" ).tag(config=True) telgroup = Integer(help='telescope group number', default=1).tag( config=True) max_events = Integer(help='stop after this many events if non-zero', default_value=0, min=0).tag(config=True) output_suffix=Unicode(help='suffix (file extension) of output ' 'filenames to write images ' 'to (no writing is done if blank). ' 'Images will be named [EVENTID][suffix]' , default_value="").tag(config=True) aliases = Dict({'infile': 'ImageSumDisplayerTool.infile', 'telgroup': 'ImageSumDisplayerTool.telgroup', 'max-events': 'ImageSumDisplayerTool.max_events', 'output-suffix': 'ImageSumDisplayerTool.output_suffix'}) classes = List([CameraCalibrator,]) def setup(self): # load up the telescope types table (need to first open a file, a bit of # a hack until a proper insturment module exists) and select only the # telescopes with the same camera type data = next(hessio_event_source(self.infile, max_events=1)) camtypes = get_camera_types(data.inst) print_camera_types(data.inst, printer=self.log.info) group = camtypes.groups[self.telgroup] self._selected_tels = group['tel_id'].data self._base_tel = self._selected_tels[0] self.log.info("Telescope group %d: %s with %s camera", self.telgroup, group[0]['tel_type'], group[0]['cam_type']) self.log.info("SELECTED TELESCOPES:{}".format(self._selected_tels)) self.calibrator = CameraCalibrator(self.config, self) def start(self): geom = None imsum = None disp = None for data in hessio_event_source(self.infile, allowed_tels=self._selected_tels, max_events=self.max_events): self.calibrator.calibrate(data) if geom is None: x, y = data.inst.pixel_pos[self._base_tel] flen = data.inst.optical_foclen[self._base_tel] geom = CameraGeometry.guess(x, y, flen) imsum = np.zeros(shape=x.shape, dtype=np.float) disp = CameraDisplay(geom, title=geom.cam_id) disp.add_colorbar() disp.cmap = 'viridis' if len(data.dl0.tels_with_data) <= 2: continue imsum[:] = 0 for telid in data.dl0.tels_with_data: imsum += data.dl1.tel[telid].image[0] self.log.info("event={} ntels={} energy={}" \ .format(data.r0.event_id, len(data.dl0.tels_with_data), data.mc.energy)) disp.image = imsum plt.pause(0.1) if self.output_suffix is not "": filename = "{:020d}{}".format(data.r0.event_id, self.output_suffix) self.log.info("saving: '{}'".format(filename)) plt.savefig(filename)
class CTAFileLoader(object): """ Loads CTA Files and handles them for saving events in different format """ # particle ID: 0 for gamma, 1 for proton def __init__( self, telescopes, start_at_runnum=0, end_at_runnum=0, load_file_name_start="Protons/proton_20deg_174.681deg_run", load_file_name_end="___cta-prod4-lapalma-2158m--baseline_with-MAGIC.simtel.gz", filepath=data_path): """ :param particleID: ID of particle to save, deprecated :param telescopes: set of telescopes to save events for :param start_at_runnum: runnum to start at :param end_at_runnum: runnum to stop at (file is included) :param load_file_name_start: name of file to load after runnum :param load_file_name_end: name of file to load after runnum :param """ self.eventList = [] # CameraCalibrator() config = traitlets.config.Config() self.calibrator = CameraCalibrator( r1_product="HESSIOR1Calibrator", extractor_product="NeighbourPeakIntegrator", config=config) self.telescopes = telescopes self.currentFileID = start_at_runnum self.start_at_runnum = start_at_runnum self.end_at_runnum = end_at_runnum if end_at_runnum >= start_at_runnum else start_at_runnum self.loadFileName_start = load_file_name_start self.loadFileName_end = load_file_name_end self.filepath = filepath def loadFileWithID(self, fid): filename = self.loadFileName_start + str(fid) + self.loadFileName_end #if self.particleID == 1: # filename = "Protons/proton_20deg_174.681deg_run" + str( # fid) + "___cta-prod4-lapalma-2158m--baseline_with-MAGIC.simtel.gz" #elif self.particleID == 0: # filename = "Gamma/gamma_20deg_174.681deg_run" + str( # fid) + "___cta-prod4-lapalma-2158m--baseline_with-MAGIC_cone1.5.simtel.gz" # print("Invalid particle ID given, please set 0 for gamma, 1 for proton file to load") self.loadFile(self.filepath + filename) def loadFileWithID_string(self, fidstr): filename = self.loadFileName_start + fidstr + self.loadFileName_end #if self.particleID == 1: # filename = "Protons/proton_20deg_174.681deg_run" + str( # fid) + "___cta-prod4-lapalma-2158m--baseline_with-MAGIC.simtel.gz" #elif self.particleID == 0: # filename = "Gamma/gamma_20deg_174.681deg_run" + str( # fid) + "___cta-prod4-lapalma-2158m--baseline_with-MAGIC_cone1.5.simtel.gz" # print("Invalid particle ID given, please set 0 for gamma, 1 for proton file to load") self.loadFile(self.filepath + filename) def loadNextFile(self): maxFilesToTest = 100 currentFileToTest = 0 while currentFileToTest < maxFilesToTest: if self.currentFileID > self.end_at_runnum: print("Loaded all files.") return False filename = self.loadFileName_start + str( self.currentFileID) + self.loadFileName_end #if self.particleID == 1: # filename = "Protons/proton_20deg_174.681deg_run" + str( # self.currentFileID) + "___cta-prod4-lapalma-2158m--baseline_with-MAGIC.simtel.gz" #elif self.particleID == 0: # filename = "Gamma/gamma_20deg_174.681deg_run" + str( # self.currentFileID) + "___cta-prod4-lapalma-2158m--baseline_with-MAGIC_cone1.5.simtel.gz" #else: # print("Invalid particle ID given, please set 0 for gamma, 1 for proton file to load") # return # Check whether the file exists or not my_file = Path(self.filepath + filename) print(my_file) if not my_file.is_file(): print("File does not exist: " + filename) self.currentFileID += 1 else: self.loadFile(self.filepath + filename) self.currentFileID += 1 return True currentFileToTest += 1 print("Could not find next file.") def loadFile(self, path): event_factory = EventSourceFactory.produce(input_url=path) event_factory.allowed_tels = self.telescopes #{1, 2} event_generator = event_factory._generator() # event = next(event_generator) for s_event in event_generator: # Use event only if M1 and M2 are triggered #if 1 in s_event.r0.tels_with_data and 1 in self.telescopes and 2 in s_event.r0.tels_with_data: if self.telescopes <= s_event.r0.tels_with_data: self.calibrator.calibrate(s_event) # print("Oder num: {:d}, event id: {:.0f}, triggered telescopes: {}".format(stereo_event.count, stereo_event.r0.event_id, stereo_event.r0.tels_with_data)) a = copy.deepcopy(s_event) self.eventList.append(a) event_factory.pyhessio.close_file() print("New File loaded, file {:d} contains {:d} events".format( self.currentFileID, len(self.eventList))) def checkEventList(self): """ Checks whether eventList is empty and loads new file if it is Returns False if it is empty and all files were loaded Return True if it is not empty """ if len(self.eventList) < 1: if self.loadNextFile(): if not self.checkEventList(): return False else: return False return True def getNextEvent(self): """ Returns next event and removes it from eventList Automatically loads next file if eventList is empty """ self.checkEventList() return self.eventList.pop(0)
def extract_images(simtel_file_path, tel_id_filter_list=None, event_id_filter_list=None, output_directory=None, crop=True): # EXTRACT IMAGES ########################################################## # hessio_event_source returns a Python generator that streams data from an # EventIO/HESSIO MC data file (e.g. a standard CTA data file). # This generator contains ctapipe.core.Container instances ("event"). # # Parameters: # - max_events: maximum number of events to read # - allowed_tels: select only a subset of telescope, if None, all are read. source = hessio_event_source(simtel_file_path, allowed_tels=tel_id_filter_list) # ITERATE OVER EVENTS ##################################################### calib = CameraCalibrator(None, None) for event in source: calib.calibrate(event) # calibrate the event event_id = int(event.dl0.event_id) if (event_id_filter_list is None) or (event_id in event_id_filter_list): #print("event", event_id) # ITERATE OVER IMAGES ############################################# for tel_id in event.trig.tels_with_trigger: tel_id = int(tel_id) if tel_id in tel_id_filter_list: #print("telescope", tel_id) # CHECK THE IMAGE GEOMETRY (ASTRI ONLY) ################### # TODO #print("checking geometry") x, y = event.inst.pixel_pos[tel_id] foclen = event.inst.optical_foclen[tel_id] geom = CameraGeometry.guess(x, y, foclen) if (geom.pix_type != "rectangular") or (geom.cam_id not in ("ASTRICam", "ASTRI")): raise ValueError("Telescope {}: error (the input image is not a valide ASTRI telescope image) -> {} ({})".format(tel_id, geom.pix_type, geom.cam_id)) # GET IMAGES ############################################## pe_image = event.mc.tel[tel_id].photo_electron_image # 1D np array #uncalibrated_image = event.dl0.tel[tel_id].adc_sums # ctapipe 0.3.0 uncalibrated_image = event.r0.tel[tel_id].adc_sums # ctapipe 0.4.0 pedestal = event.mc.tel[tel_id].pedestal gain = event.mc.tel[tel_id].dc_to_pe pixel_pos = event.inst.pixel_pos[tel_id] calibrated_image = event.dl1.tel[tel_id].image calibrated_image[1, calibrated_image[0,:] <= ASTRI_CAM_CHANNEL_THRESHOLD] = 0 calibrated_image[0, calibrated_image[0,:] > ASTRI_CAM_CHANNEL_THRESHOLD] = 0 calibrated_image = calibrated_image.sum(axis=0) #print(pe_image.shape) #print(calibrated_image.shape) #print(uncalibrated_image.shape) #print(pedestal.shape) #print(gain.shape) #print(pixel_pos.shape) #print(pixel_pos[0]) #print(pixel_pos[1]) # CONVERTING GEOMETRY (1D TO 2D) ########################## pe_image_2d = geometry_converter.astri_to_2d_array(pe_image, crop=crop) calibrated_image_2d = geometry_converter.astri_to_2d_array(calibrated_image, crop=crop) uncalibrated_image_2d = geometry_converter.astri_to_3d_array(uncalibrated_image, crop=crop) pedestal_2d = geometry_converter.astri_to_3d_array(pedestal, crop=crop) gains_2d = geometry_converter.astri_to_3d_array(gain, crop=crop) pixel_pos_2d = geometry_converter.astri_to_3d_array(pixel_pos, crop=crop) #print(pe_image_2d.shape) #print(calibrated_image_2d.shape) #print(uncalibrated_image_2d.shape) #print(pedestal_2d.shape) #print(gains_2d.shape) #print(pixel_pos_2d.shape) #sys.exit(0) # GET PIXEL MASK ########################################## pixel_mask = geometry_converter.astri_pixel_mask(crop) # 1 for pixels with actual data, 0 for virtual (blank) pixels # MAKE METADATA ########################################### metadata = {} metadata['version'] = 1 # Version of the datapipe fits format if crop: metadata['cam_id'] = "ASTRI_CROPPED" else: metadata['cam_id'] = "ASTRI" metadata['tel_id'] = tel_id metadata['event_id'] = event_id metadata['simtel'] = simtel_file_path metadata['tel_trig'] = len(event.trig.tels_with_trigger) metadata['energy'] = quantity_to_tuple(event.mc.energy, 'TeV') metadata['mc_az'] = quantity_to_tuple(event.mc.az, 'rad') metadata['mc_alt'] = quantity_to_tuple(event.mc.alt, 'rad') metadata['mc_corex'] = quantity_to_tuple(event.mc.core_x, 'm') metadata['mc_corey'] = quantity_to_tuple(event.mc.core_y, 'm') metadata['mc_hfi'] = quantity_to_tuple(event.mc.h_first_int, 'm') metadata['count'] = int(event.count) metadata['run_id'] = int(event.dl0.run_id) metadata['tel_data'] = len(event.dl0.tels_with_data) metadata['foclen'] = quantity_to_tuple(event.inst.optical_foclen[tel_id], 'm') metadata['tel_posx'] = quantity_to_tuple(event.inst.tel_pos[tel_id][0], 'm') metadata['tel_posy'] = quantity_to_tuple(event.inst.tel_pos[tel_id][1], 'm') metadata['tel_posz'] = quantity_to_tuple(event.inst.tel_pos[tel_id][2], 'm') # TODO: Astropy fails to store the following data in FITS files #metadata['uid'] = os.getuid() #metadata['datetime'] = str(datetime.datetime.now()) #metadata['version'] = VERSION #metadata['argv'] = " ".join(sys.argv).encode('ascii', errors='ignore').decode('ascii') #metadata['python'] = " ".join(sys.version.splitlines()).encode('ascii', errors='ignore').decode('ascii') #metadata['system'] = " ".join(os.uname()) # SAVE THE IMAGE ########################################## output_file_path_template = "{}_TEL{:03d}_EV{:05d}.fits" if output_directory is not None: simtel_basename = os.path.basename(simtel_file_path) prefix = os.path.join(output_directory, simtel_basename) else: prefix = simtel_file_path output_file_path = output_file_path_template.format(prefix, tel_id, event_id) print("saving", output_file_path) images.save_benchmark_images(img = calibrated_image_2d, pe_img = pe_image_2d, adc_sums_img = uncalibrated_image_2d, pedestal_img = pedestal_2d, gains_img = gains_2d, pixel_pos = pixel_pos_2d, pixel_mask = pixel_mask, metadata = metadata, output_file_path = output_file_path)
class MuonDisplayerTool(Tool): name = 'ctapipe-display-muons' description = t.Unicode(__doc__) infile = t.Unicode( help='input file name', default=get_dataset('gamma_test_large.simtel.gz') ).tag(config=True) outfile = t.Unicode(help='output file name', default=None).tag(config=True) display = t.Bool( help='display the camera events', default=False ).tag(config=True) classes = t.List([CameraCalibrator,]) aliases = t.Dict({'infile': 'MuonDisplayerTool.infile', 'outfile': 'MuonDisplayerTool.outfile', 'display' : 'MuonDisplayerTool.display' }) def setup(self): self.calib = CameraCalibrator(config=self.config, tool=self) def start(self): output_parameters = {'MuonEff': [], 'ImpactP': [], 'RingWidth': []} numev = 0 num_muons_found = 0 for event in hessio_event_source(self.infile): self.log.info("Event Number: %d, found %d muons", numev, num_muons_found) self.calib.calibrate(event) muon_evt = analyze_muon_event(event) numev += 1 if not muon_evt['MuonIntensityParams']: # No telescopes contained a good muon continue else: if self.display: plot_muon_event(event, muon_evt) for tid in muon_evt['TelIds']: idx = muon_evt['TelIds'].index(tid) if not muon_evt['MuonIntensityParams'][idx]: continue self.log.info("** Muon params: %s", muon_evt[idx]) output_parameters['MuonEff'].append( muon_evt['MuonIntensityParams'][idx].optical_efficiency_muon ) output_parameters['ImpactP'].append( muon_evt['MuonIntensityParams'][idx].impact_parameter.value ) output_parameters['RingWidth'].append( muon_evt['MuonIntensityParams'][idx].ring_width.value ) print_muon(muon_evt, printer=self.log.info) num_muons_found += 1 t = Table(output_parameters) t['ImpactP'].unit = 'm' t['RingWidth'].unit = 'deg' if self.outfile: t.write(self.outfile)
class SingleTelEventDisplay(Tool): name = "ctapipe-display-televents" 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': 'SingleTelEventDisplay.infile', 'tel': 'SingleTelEventDisplay.tel', 'max-events': 'EventSource.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([EventSource, CameraCalibrator]) def __init__(self, **kwargs): super().__init__(**kwargs) def setup(self): print('TOLLES INFILE', self.infile) self.event_source = EventSource.from_url(self.infile, parent=self) self.event_source.allowed_tels = {self.tel, } self.calibrator = CameraCalibrator( parent=self, eventsource=self.event_source ) 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.trig) self.log.debug(f"Energy: {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(f"Sample {ii:03d}") if self.display: plt.pause(self.delay) if self.write: plt.savefig( f'CT{self.tel:03d}_EV{event.r0.event_id:10d}' f'_S{ii:02d}.png' ) 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( f'CT{self.tel:03d}_EV{event.r0.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), )
# print(event.dl0) # print(event.dl1) # print(event.dl2) # print(event.mcheader) # print(event.trig) # trace = event.r0.tel[tel_id].adc_samples[0] # peds, pedvars = # pedestals.calc_pedestals_from_traces(trace,start,end) # print("PEDS:",peds) # print("VARS:",pedvars) # event_id = event.r0.event_id cal.calibrate(event) # energy reconstruction input # X = {} # hillas_params_dict = {} # tel_phi_dict = {} # tel_theta_dict = {} for tel_id in event.r0.tels_with_data: # print(event.dl1.tel[tel_id].peakpos) # trace = np.array(event.r0.tel[tel_id].adc_samples) # apply trace integration # trace_integrated = integ.extract_charge(trace)[0][0]
def process_data(self, data_file, max_events=None): """Main method to read a simtel.gz data file, process the event data, and write it to a formatted HDF5 data file. """ logger.info("Preparing HDF5 file structure...") f = tables.open_file(self.output_path, mode="a", title="Output File") self.write_metadata(f, data_file) selected_tels, num_tel = self.select_telescopes(data_file) event = next(hessio_event_source(data_file)) # create and fill array information table if not f.__contains__('/Array_Info'): arr_table = f.create_table(f.root, 'Array_Info', row_types.Array, ("Table of array data")) arr_row = arr_table.row for tel_type in selected_tels: for tel_id in selected_tels[tel_type]: arr_row["tel_id"] = tel_id arr_row["tel_x"] = event.inst.subarray.positions[ tel_id].value[0] arr_row["tel_y"] = event.inst.subarray.positions[ tel_id].value[1] arr_row["tel_z"] = event.inst.subarray.positions[ tel_id].value[2] arr_row["tel_type"] = tel_type arr_row[ "run_array_direction"] = event.mcheader.run_array_direction arr_row.append() # create and fill telescope information table if not f.__contains__('/Telescope_Info'): tel_table = f.create_table(f.root, 'Telescope_Info', row_types.Tel, ("Table of telescope data")) descr = tel_table.description._v_colobjects descr2 = descr.copy() max_npix = self.TEL_NUM_PIXELS[max(self.TEL_NUM_PIXELS, key=self.TEL_NUM_PIXELS.get)] descr2["pixel_pos"] = tables.Float32Col(shape=(2, max_npix)) tel_table2 = f.create_table(f.root, 'temp', descr2, "Table of telescope data") tel_table.attrs._f_copy(tel_table2) tel_table.remove() tel_table2.move(f.root, 'Telescope_Info') tel_row = tel_table2.row # add units to table attributes random_tel_type = random.choice(list(selected_tels.keys())) random_tel_id = random.choice(selected_tels[random_tel_type]) tel_table2.attrs.tel_pos_units = str( event.inst.subarray.positions[random_tel_id].unit) for tel_type in selected_tels: random_tel_id = random.choice(selected_tels[tel_type]) tel_row["tel_type"] = tel_type tel_row["num_pixels"] = len( event.inst.subarray.tel[random_tel_id].camera.pix_id) posx = np.hstack([ event.inst.subarray.tel[random_tel_id].camera.pix_x.value, np.zeros(max_npix - len( event.inst.subarray.tel[random_tel_id].camera.pix_x)) ]) posy = np.hstack([ event.inst.subarray.tel[random_tel_id].camera.pix_y.value, np.zeros(max_npix - len( event.inst.subarray.tel[random_tel_id].camera.pix_y)) ]) tel_row["pixel_pos"] = [posx, posy] tel_row.append() #create event table if not f.__contains__('/Event_Info'): table = f.create_table(f.root, 'Event_Info', row_types.Event, "Table of Event metadata") descr = table.description._v_colobjects descr2 = descr.copy() if self.storage_mode == 'tel_type': for tel_type in selected_tels: descr2[tel_type + '_indices'] = tables.Int32Col( shape=(len(selected_tels[tel_type]))) elif self.storage_mode == 'tel_id': descr2["indices"] = tables.Int32Col(shape=(num_tel)) table2 = f.create_table(f.root, 'temp', descr2, "Table of Events") table.attrs._f_copy(table2) table.remove() table2.move(f.root, 'Event_Info') #add units to table attributes table2.attrs.core_pos_units = str(event.mc.core_x.unit) table2.attrs.h_first_int_units = str(event.mc.h_first_int.unit) table2.attrs.mc_energy_units = str(event.mc.energy.unit) table2.attrs.alt_az_units = str(event.mc.alt.unit) #create image tables for tel_type in selected_tels: if self.img_mode == '2D': img_width = self.IMAGE_SHAPES[tel_type][ 0] * self.img_scale_factors[tel_type] img_length = self.IMAGE_SHAPES[tel_type][ 1] * self.img_scale_factors[tel_type] if self.img_dim_order == 'channels_first': array_shape = (self.img_channels, img_width, img_length) elif self.img_dim_order == 'channels_last': array_shape = (img_width, img_length, self.img_channels) np_type = np.dtype(np.dtype(self.img_dtypes[tel_type]), array_shape) columns_dict = { "image": tables.Col.from_dtype(np_type), "event_index": tables.Int32Col() } elif self.img_mode == '1D': array_shape = (self.TEL_NUM_PIXELS[tel_type], ) np_type = np.dtype( (np.dtype(self.img_dtypes[tel_type]), array_shape)) columns_dict = { "image_charge": tables.Col.from_dtype(np_type), "event_index": tables.Int32Col() } if self.include_timing: columns_dict["image_peak_times"] = tables.Col.from_dtype( np_type) description = type('description', (tables.IsDescription, ), columns_dict) if self.storage_mode == 'tel_type': if not f.__contains__('/' + tel_type): table = f.create_table( f.root, tel_type, description, "Table of {} images".format(tel_type)) #append blank image at index 0 image_row = table.row if self.img_mode == '2D': image_row['image'] = self.trace_converter.convert( None, None, tel_type) elif self.img_mode == '1D': shape = (image.TEL_NUM_PIXELS[tel_type], ) image_row['image_charge'] = np.zeros( shape, dtype=self.img_dtypes[tel_type]) image_row['event_index'] = -1 if self.include_timing: image_row['image_peak_times'] = np.zeros( shape, dtype=self.img_dtypes[tel_type]) image_row.append() table.flush() elif self.storage_mode == 'tel_id': for tel_id in selected_tels[tel_type]: if not f.__contains__('T' + str(tel_id)): table = f.create_table( f.root, 'T' + str(tel_id), description, "Table of T{} images".format(str(tel_id))) #append blank image at index 0 image_row = table.row if self.img_mode == '2D': image_row['image'] = self.trace_converter.convert( None, None, tel_type) elif self.img_mode == '1D': shape = (image.TEL_NUM_PIXELS[tel_type], ) image_row['image_charge'] = np.zeros( shape, dtype=self.img_dtypes[tel_type]) image_row['event_index'] = -1 if self.include_timing: image_row['image_peak_times'] = np.zeros( shape, dtype=self.img_dtypes[tel_type]) image_row.append() table.flush() # specify calibration and other processing options cal = CameraCalibrator(None, None) logger.info("Processing events...") event_count = 0 passing_count = 0 source = hessio_event_source( data_file, allowed_tels=[j for i in selected_tels for j in selected_tels[i]], max_events=max_events) for event in source: event_count += 1 if self.cuts_dict: if self.ED_cuts_dict is not None: logger.warning( 'Warning: Both ED_cuts_dict and cuts dictionary found. Using cuts dictionary instead.' ) if test_cuts(event, cuts_dict): passing_count += 1 else: continue else: if self.ED_cuts_dict is not None: if (event.r0.run_id, event.r0.event_id) in self.ED_cuts_dict: bin_number, reconstructed_energy = self.ED_cuts_dict[( event.r0.run_id, event.r0.event_id)] passing_count += 1 else: continue cal.calibrate(event) table = f.root.Event_Info table.flush() event_row = table.row event_index = table.nrows if self.storage_mode == 'tel_type': tel_index_vectors = { tel_type: [] for tel_type in selected_tels } elif self.storage_mode == 'tel_id': all_tel_index_vector = [] for tel_type in selected_tels.keys(): for tel_id in sorted(selected_tels[tel_type]): if self.storage_mode == 'tel_type': index_vector = tel_index_vectors[tel_type] elif self.storage_mode == 'tel_id': index_vector = all_tel_index_vector if tel_id in event.r0.tels_with_data: pixel_vector = event.dl1.tel[tel_id].image[0] logger.debug( 'Storing image from tel_type {} ({} pixels)'. format(tel_type, len(pixel_vector))) if self.include_timing: peaks_vector = event.dl1.tel[tel_id].peakpos[0] else: peaks_vector = None if self.storage_mode == 'tel_type': table = eval('f.root.{}'.format(tel_type)) elif self.storage_mode == 'tel_id': table = eval('f.root.T{}'.format(tel_id)) next_index = table.nrows image_row = table.row if self.img_mode == '2D': image_row['image'] = self.trace_converter.convert( pixel_vector, peaks_vector, tel_type) elif self.img_mode == '1D': image_row['image_charge'] = pixel_vector if self.include_timing: image_row['image_peak_times'] = peaks_vector image_row["event_index"] = event_index image_row.append() index_vector.append(next_index) table.flush() else: index_vector.append(0) if self.storage_mode == 'tel_type': for tel_type in tel_index_vectors: event_row[tel_type + '_indices'] = tel_index_vectors[tel_type] elif self.storage_mode == 'tel_id': event_row['indices'] = all_tel_index_vector event_row['event_number'] = event.r0.event_id event_row['run_number'] = event.r0.run_id event_row['particle_id'] = event.mc.shower_primary_id event_row['core_x'] = event.mc.core_x.value event_row['core_y'] = event.mc.core_y.value event_row['h_first_int'] = event.mc.h_first_int.value event_row['mc_energy'] = event.mc.energy.value event_row['alt'] = event.mc.alt.value event_row['az'] = event.mc.az.value event_row.append() table.flush() f.root.Event_Info.flush() total_num_events = f.root.Event_Info.nrows f.close() logger.info("{} events read in file".format(event_count)) logger.info("{} total events in output file.".format(total_num_events)) if self.cuts_dict or self.ED_cuts_dict: logger.info( "{} events passed cuts/written to file".format(passing_count)) logger.info("Done!")
class SimpleEventWriter(Tool): name = 'ctapipe-simple-event-writer' description = Unicode(__doc__) infile = Unicode(help='input file to read', default='').tag(config=True) outfile = Unicode(help='output file name', default_value='output.h5').tag(config=True) progress = Bool(help='display progress bar', default_value=True).tag(config=True) aliases = Dict({ 'infile': 'EventSourceFactory.input_url', 'outfile': 'SimpleEventWriter.outfile', 'max-events': 'EventSourceFactory.max_events', 'progress': 'SimpleEventWriter.progress' }) classes = List([EventSourceFactory, CameraCalibrator, CutFlow]) def setup(self): self.log.info('Configure EventSourceFactory...') self.event_source = EventSourceFactory.produce( config=self.config, tool=self, product='SimTelEventSource' ) self.event_source.allowed_tels = self.config['Analysis']['allowed_tels'] self.calibrator = CameraCalibrator( config=self.config, tool=self, eventsource=self.event_source ) self.writer = HDF5TableWriter( filename=self.outfile, group_name='image_infos', overwrite=True ) # Define Pre-selection for images preselcuts = self.config['Preselect'] self.image_cutflow = CutFlow('Image preselection') self.image_cutflow.set_cuts(dict( no_sel=None, n_pixel=lambda s: np.count_nonzero(s) < preselcuts['n_pixel']['min'], image_amplitude=lambda q: q < preselcuts['image_amplitude']['min'] )) # Define Pre-selection for events self.event_cutflow = CutFlow('Event preselection') self.event_cutflow.set_cuts(dict( no_sel=None )) 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.event_cutflow.count('no_sel') self.calibrator.calibrate(event) for tel_id in event.dl0.tels_with_data: self.image_cutflow.count('no_sel') camera = event.inst.subarray.tel[tel_id].camera dl1_tel = event.dl1.tel[tel_id] # Image cleaning image = dl1_tel.image[0] # Waiting for automatic gain selection mask = tailcuts_clean(camera, image, picture_thresh=10, boundary_thresh=5) cleaned = image.copy() cleaned[~mask] = 0 # Preselection cuts if self.image_cutflow.cut('n_pixel', cleaned): continue if self.image_cutflow.cut('image_amplitude', np.sum(cleaned)): continue # Image parametrisation params = hillas_parameters(camera, cleaned) # Save Ids, MC infos and Hillas informations self.writer.write(camera.cam_id, [event.r0, event.mc, params]) def finish(self): self.log.info('End of job.') self.image_cutflow() self.event_cutflow() self.writer.close()
def extract_images(simtel_file_path, tel_id_filter_list=None, event_id_filter_list=None, output_directory=None, crop=True): # EXTRACT IMAGES ########################################################## # hessio_event_source returns a Python generator that streams data from an # EventIO/HESSIO MC data file (e.g. a standard CTA data file). # This generator contains ctapipe.core.Container instances ("event"). # # Parameters: # - max_events: maximum number of events to read # - allowed_tels: select only a subset of telescope, if None, all are read. source = hessio_event_source(simtel_file_path, allowed_tels=tel_id_filter_list) # ITERATE OVER EVENTS ##################################################### calib = CameraCalibrator(None, None) for event in source: calib.calibrate(event) # calibrate the event event_id = int(event.dl0.event_id) if (event_id_filter_list is None) or (event_id in event_id_filter_list): #print("event", event_id) # ITERATE OVER IMAGES ############################################# for tel_id in event.trig.tels_with_trigger: tel_id = int(tel_id) if tel_id in tel_id_filter_list: #print("telescope", tel_id) # CHECK THE IMAGE GEOMETRY (ASTRI ONLY) ################### # TODO #print("checking geometry") x, y = event.inst.subarray.tel[ tel_id].camera.pix_x, event.inst.subarray.tel[ tel_id].camera.pix_y foclen = event.inst.subarray.tel[ tel_id].optics.equivalent_focal_length geom = CameraGeometry.guess(x, y, foclen) if (geom.pix_type != "rectangular") or (geom.cam_id not in ("ASTRICam", "ASTRI")): raise ValueError( "Telescope {}: error (the input image is not a valide ASTRI telescope image) -> {} ({})" .format(tel_id, geom.pix_type, geom.cam_id)) # GET IMAGES ############################################## pe_image = event.mc.tel[ tel_id].photo_electron_image # 1D np array #uncalibrated_image = event.dl0.tel[tel_id].adc_sums # ctapipe 0.3.0 uncalibrated_image = event.r0.tel[ tel_id].adc_sums # ctapipe 0.4.0 pedestal = event.mc.tel[tel_id].pedestal gain = event.mc.tel[tel_id].dc_to_pe pixel_pos = (event.inst.subarray.tel[tel_id].camera.pix_x, event.inst.subarray.tel[tel_id].camera.pix_y) calibrated_image = event.dl1.tel[tel_id].image calibrated_image[1, calibrated_image[ 0, :] <= ASTRI_CAM_CHANNEL_THRESHOLD] = 0 calibrated_image[0, calibrated_image[ 0, :] > ASTRI_CAM_CHANNEL_THRESHOLD] = 0 calibrated_image = calibrated_image.sum(axis=0) #print(pe_image.shape) #print(calibrated_image.shape) #print(uncalibrated_image.shape) #print(pedestal.shape) #print(gain.shape) #print(pixel_pos.shape) #print(pixel_pos[0]) #print(pixel_pos[1]) # CONVERTING GEOMETRY (1D TO 2D) ########################## pe_image_2d = geometry_converter.astri_to_2d_array( pe_image, crop=crop) calibrated_image_2d = geometry_converter.astri_to_2d_array( calibrated_image, crop=crop) uncalibrated_image_2d = geometry_converter.astri_to_3d_array( uncalibrated_image, crop=crop) pedestal_2d = geometry_converter.astri_to_3d_array( pedestal, crop=crop) gains_2d = geometry_converter.astri_to_3d_array(gain, crop=crop) pixel_pos_2d = geometry_converter.astri_to_3d_array( pixel_pos, crop=crop) #print(pe_image_2d.shape) #print(calibrated_image_2d.shape) #print(uncalibrated_image_2d.shape) #print(pedestal_2d.shape) #print(gains_2d.shape) #print(pixel_pos_2d.shape) #sys.exit(0) # GET PIXEL MASK ########################################## pixel_mask = geometry_converter.astri_pixel_mask( crop ) # 1 for pixels with actual data, 0 for virtual (blank) pixels # MAKE METADATA ########################################### metadata = {} metadata[ 'version'] = 1 # Version of the pywicta fits format if crop: metadata['cam_id'] = "ASTRI_CROPPED" else: metadata['cam_id'] = "ASTRI" metadata['tel_id'] = tel_id metadata['event_id'] = event_id metadata['simtel'] = simtel_file_path metadata['tel_trig'] = len(event.trig.tels_with_trigger) metadata['energy'] = quantity_to_tuple( event.mc.energy, 'TeV') metadata['mc_az'] = quantity_to_tuple(event.mc.az, 'rad') metadata['mc_alt'] = quantity_to_tuple(event.mc.alt, 'rad') metadata['mc_corex'] = quantity_to_tuple( event.mc.core_x, 'm') metadata['mc_corey'] = quantity_to_tuple( event.mc.core_y, 'm') metadata['mc_hfi'] = quantity_to_tuple( event.mc.h_first_int, 'm') metadata['count'] = int(event.count) metadata['run_id'] = int(event.dl0.obs_id) metadata['tel_data'] = len(event.dl0.tels_with_data) metadata['foclen'] = quantity_to_tuple( event.inst.subarray.tel[tel_id].optics. equivalent_focal_length, 'm') metadata['tel_posx'] = quantity_to_tuple( event.inst.subarray.tel_coords[tel_id].x, 'm') metadata['tel_posy'] = quantity_to_tuple( event.inst.subarray.tel_coords[tel_id].y, 'm') metadata['tel_posz'] = quantity_to_tuple( event.inst.subarray.tel_coords[tel_id].z, 'm') # TODO: Astropy fails to store the following data in FITS files #metadata['uid'] = os.getuid() #metadata['datetime'] = str(datetime.datetime.now()) #metadata['version'] = VERSION #metadata['argv'] = " ".join(sys.argv).encode('ascii', errors='ignore').decode('ascii') #metadata['python'] = " ".join(sys.version.splitlines()).encode('ascii', errors='ignore').decode('ascii') #metadata['system'] = " ".join(os.uname()) # SAVE THE IMAGE ########################################## output_file_path_template = "{}_TEL{:03d}_EV{:05d}.fits" if output_directory is not None: simtel_basename = os.path.basename(simtel_file_path) prefix = os.path.join(output_directory, simtel_basename) else: prefix = simtel_file_path output_file_path = output_file_path_template.format( prefix, tel_id, event_id) print("saving", output_file_path) images.save_benchmark_images( img=calibrated_image_2d, pe_img=pe_image_2d, adc_sums_img=uncalibrated_image_2d, pedestal_img=pedestal_2d, gains_img=gains_2d, pixel_pos=pixel_pos_2d, pixel_mask=pixel_mask, metadata=metadata, output_file_path=output_file_path)
""" very simple example that loads a single event into memory, for exploration purposes """ import sys from ctapipe.calib import CameraCalibrator from ctapipe.io import event_source from ctapipe.utils import get_dataset_path if __name__ == '__main__': calib = CameraCalibrator(r1_product="HESSIOR1Calibrator") if len(sys.argv) >= 2: filename = sys.argv[1] else: filename = get_dataset_path("gamma_test_large.simtel.gz") with event_source(filename, max_events=1) as source: for event in source: calib.calibrate(event) print(event)
class ImageSumDisplayerTool(Tool): description = Unicode(__doc__) name = "ctapipe-image-sum-display" infile = Unicode( help='input simtelarray file', default="/Users/kosack/Data/CTA/Prod3/gamma.simtel.gz").tag( config=True) telgroup = Integer(help='telescope group number', default=1).tag(config=True) max_events = Integer(help='stop after this many events if non-zero', default_value=0, min=0).tag(config=True) output_suffix = Unicode(help='suffix (file extension) of output ' 'filenames to write images ' 'to (no writing is done if blank). ' 'Images will be named [EVENTID][suffix]', default_value="").tag(config=True) aliases = Dict({ 'infile': 'ImageSumDisplayerTool.infile', 'telgroup': 'ImageSumDisplayerTool.telgroup', 'max-events': 'ImageSumDisplayerTool.max_events', 'output-suffix': 'ImageSumDisplayerTool.output_suffix' }) classes = List([ CameraCalibrator, ]) def setup(self): # load up the telescope types table (need to first open a file, a bit of # a hack until a proper insturment module exists) and select only the # telescopes with the same camera type data = next(hessio_event_source(self.infile, max_events=1)) camtypes = get_camera_types(data.inst) group = camtypes.groups[self.telgroup] self._selected_tels = group['tel_id'].data self._base_tel = self._selected_tels[0] self.log.info("Telescope group %d: %s with %s camera", self.telgroup, group[0]['tel_type'], group[0]['cam_type']) self.log.info("SELECTED TELESCOPES:{}".format(self._selected_tels)) self.calibrator = CameraCalibrator(self.config, self) def start(self): geom = None imsum = None disp = None for data in hessio_event_source(self.infile, allowed_tels=self._selected_tels, max_events=self.max_events): self.calibrator.calibrate(data) if geom is None: x, y = data.inst.pixel_pos[self._base_tel] flen = data.inst.optical_foclen[self._base_tel] geom = CameraGeometry.guess(x, y, flen) imsum = np.zeros(shape=x.shape, dtype=np.float) disp = CameraDisplay(geom, title=geom.cam_id) disp.add_colorbar() disp.cmap = 'viridis' if len(data.dl0.tels_with_data) <= 2: continue imsum[:] = 0 for telid in data.dl0.tels_with_data: imsum += data.dl1.tel[telid].image[0] self.log.info("event={} ntels={} energy={}" \ .format(data.r0.event_id, len(data.dl0.tels_with_data), data.mc.energy)) disp.image = imsum plt.pause(0.1) if self.output_suffix is not "": filename = "{:020d}{}".format(data.r0.event_id, self.output_suffix) self.log.info("saving: '{}'".format(filename)) plt.savefig(filename)
The most basic pipeline, using no special features of the framework other than a for-loop. This is useful for debugging and profiling of speed. """ import sys import numpy as np from ctapipe.calib import CameraCalibrator from ctapipe.io.hessio import hessio_event_source if __name__ == '__main__': filename = sys.argv[1] source = hessio_event_source(filename, max_events=None) cal = CameraCalibrator(None, None) for data in source: print("EVENT: {}, ENERGY: {:.2f}, TELS:{}" .format(data.r0.event_id, data.mc.energy, len(data.dl0.tels_with_data)) ) cal.calibrate(data) # now the calibrated images are in data.dl1.tel[x].image
ax2 = fig0.add_subplot(122) ax1.set_title('Lab data') ax1.set_ylabel('amplitude') ax1.set_xlabel('time [ns]') ax2.set_title('MC data') ax2.set_ylabel('amplitude') ax2.set_xlabel('time [ns]') ######### CAMERA DATA p.e. ########### cal = CameraCalibrator(r1_product="TargetioR1Calibrator") try: for event_r1 in tqdm(event_source(args.labfile, max_events=args.maxevents), total=args.maxevents): cal.calibrate(event_r1) # Not needed as it is already R1 data? print('\n\nCamera Event\n\n') if args.lab_pix == None: for i in range(0, 64): if args.lab_thresh == None: ax1.plot(range(len(event_r1.r1.tel[0].waveform[0][0])), event_r1.r1.tel[0].waveform[0][i] / args.mv2pe, color='C0') else: if max(event_r1.r1.tel[0].waveform[0] [i]) / args.mv2pe > args.lab_thresh: print('plotting only lab pixel: ', i) ax1.plot(range(len(event_r1.r1.tel[0].waveform[0][0])), event_r1.r1.tel[0].waveform[0][i] / args.mv2pe, color='C0')
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].pe_samples[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), ) pass
def process_file(input_file, config, return_input_file=False, product='SimTelEventSource'): event_source = EventSourceFactory.produce( input_url=input_file.as_posix(), max_events=config.n_events if config.n_events > 1 else None, product=product, ) #event_source.allowed_tels = config.allowed_telescope_ids # if we only want one telescope later calibrator = CameraCalibrator( eventsource=event_source, r1_product='HESSIOR1Calibrator', extractor_product=config.integrator, ) telescope_event_information = [] array_event_information = [] for event in tqdm(event_source, disable=config.silent): if number_of_valid_triggerd_cameras( event, config) < config.min_number_of_valid_triggered_cameras: continue calibrator.calibrate(event) try: image_features, reconstruction, _ = process_event(event, config) event_features = event_information(event, image_features, reconstruction, config) array_event_information.append(event_features) telescope_event_information.append(image_features) except TooFewTelescopesException: continue telescope_events = pd.concat(telescope_event_information) if not telescope_events.empty: telescope_events.set_index( ['run_id', 'array_event_id', 'telescope_id'], drop=True, verify_integrity=True, inplace=True) array_events = pd.DataFrame(array_event_information) if not array_events.empty: array_events.set_index(['run_id', 'array_event_id'], drop=True, verify_integrity=True, inplace=True) run_information = read_simtel_mc_information( input_file) ### TODO: adapt to real data df_runs = pd.DataFrame([run_information]) if not df_runs.empty: df_runs.set_index('run_id', drop=True, verify_integrity=True, inplace=True) if return_input_file: return df_runs, array_events, telescope_events, input_file return df_runs, array_events, telescope_events
class MuonDisplayerTool(Tool): name = 'ctapipe-display-muons' description = t.Unicode(__doc__) events = t.Unicode("", help="input event data file").tag(config=True) outfile = t.Unicode("muons.hdf5", help='HDF5 output file name').tag( config=True) display = t.Bool( help='display the camera events', default=False ).tag(config=True) classes = t.List([ CameraCalibrator, EventSourceFactory ]) aliases = t.Dict({ 'input': 'MuonDisplayerTool.events', 'outfile': 'MuonDisplayerTool.outfile', 'display': 'MuonDisplayerTool.display', 'max_events': 'EventSourceFactory.max_events', 'allowed_tels': 'EventSourceFactory.allowed_tels', }) def setup(self): if self.events == '': raise ToolConfigurationError("please specify --input <events file>") self.log.debug("input: %s", self.events) self.source = EventSourceFactory.produce(input_url=self.events) self.calib = CameraCalibrator( config=self.config, tool=self, eventsource=self.source ) self.writer = HDF5TableWriter(self.outfile, "muons") def start(self): numev = 0 self.num_muons_found = defaultdict(int) for event in tqdm(self.source, desc='detecting muons'): self.calib.calibrate(event) muon_evt = analyze_muon_event(event) if numev == 0: _exclude_some_columns(event.inst.subarray, self.writer) numev += 1 if not muon_evt['MuonIntensityParams']: # No telescopes contained a good muon continue else: if self.display: plot_muon_event(event, muon_evt) for tel_id in muon_evt['TelIds']: idx = muon_evt['TelIds'].index(tel_id) intens_params = muon_evt['MuonIntensityParams'][idx] if intens_params is not None: ring_params = muon_evt['MuonRingParams'][idx] cam_id = str(event.inst.subarray.tel[tel_id].camera) self.num_muons_found[cam_id] += 1 self.log.debug("INTENSITY: %s", intens_params) self.log.debug("RING: %s", ring_params) self.writer.write(table_name=cam_id, containers=[intens_params, ring_params]) self.log.info( "Event Number: %d, found %s muons", numev, dict(self.num_muons_found) ) def finish(self): Provenance().add_output_file(self.outfile, role='dl1.tel.evt.muon') self.writer.close()
from ctapipe.coordinates import HorizonFrame, CameraFrame, NominalFrame cleaning_level = { 'LSTCam': (3.5, 7.5, 2), # ?? (3, 6) for Abelardo... 'FlashCam': (4, 8, 2), # there is some scaling missing? 'ASTRICam': (5, 7, 2), } input_url = get_dataset_path('gamma_test_large.simtel.gz') with event_source(input_url=input_url) as source: calibrator = CameraCalibrator(eventsource=source, ) for event in source: calibrator.calibrate(event) nominal_frame = NominalFrame( origin=SkyCoord(alt=70 * u.deg, az=0 * u.deg, frame=HorizonFrame)) nom_delta_az = [] nom_delta_alt = [] photons = [] for tel_id, dl1 in event.dl1.tel.items(): camera = event.inst.subarray.tels[tel_id].camera focal_length = event.inst.subarray.tels[ tel_id].optics.equivalent_focal_length image = dl1.image[0] # telescope mc info
class ImageSumDisplayerTool(Tool): description = Unicode(__doc__) name = "ctapipe-display-imagesum" infile = Unicode( help='input simtelarray file', default="/Users/kosack/Data/CTA/Prod3/gamma.simtel.gz" ).tag(config=True) telgroup = Integer( help='telescope group number', default=1 ).tag(config=True) max_events = Integer( help='stop after this many events if non-zero', default_value=0, min=0 ).tag(config=True) output_suffix = Unicode( help='suffix (file extension) of output ' 'filenames to write images ' 'to (no writing is done if blank). ' 'Images will be named [EVENTID][suffix]', default_value="" ).tag(config=True) aliases = Dict({ 'infile': 'ImageSumDisplayerTool.infile', 'telgroup': 'ImageSumDisplayerTool.telgroup', 'max-events': 'ImageSumDisplayerTool.max_events', 'output-suffix': 'ImageSumDisplayerTool.output_suffix' }) classes = List([CameraCalibrator, SimTelEventSource]) def setup(self): # load up the telescope types table (need to first open a file, a bit of # a hack until a proper insturment module exists) and select only the # telescopes with the same camera type self.reader = SimTelEventSource( input_url=self.infile, max_events=self.max_events ) for event in self.reader: camtypes = event.inst.subarray.to_table().group_by('camera_type') event.inst.subarray.info(printer=self.log.info) break group = camtypes.groups[self.telgroup] self._selected_tels = list(group['id'].data) self._base_tel = self._selected_tels[0] self.log.info( "Telescope group %d: %s", self.telgroup, str(event.inst.subarray.tel[self._selected_tels[0]]) ) self.log.info(f"SELECTED TELESCOPES:{self._selected_tels}") self.calibrator = CameraCalibrator( parent=self, eventsource=self.reader ) self.reader.allowed_tels = self._selected_tels def start(self): geom = None imsum = None disp = None for event in self.reader: self.calibrator.calibrate(event) if geom is None: geom = event.inst.subarray.tel[self._base_tel].camera imsum = np.zeros(shape=geom.pix_x.shape, dtype=np.float) disp = CameraDisplay(geom, title=geom.cam_id) disp.add_colorbar() disp.cmap = 'viridis' if len(event.dl0.tels_with_data) <= 2: continue imsum[:] = 0 for telid in event.dl0.tels_with_data: imsum += event.dl1.tel[telid].image[0] self.log.info( "event={} ntels={} energy={}".format( event.r0.event_id, len(event.dl0.tels_with_data), event.mc.energy ) ) disp.image = imsum plt.pause(0.1) if self.output_suffix is not "": filename = "{:020d}{}".format( event.r0.event_id, self.output_suffix ) self.log.info(f"saving: '{filename}'") plt.savefig(filename)
class DisplayDL1Calib(Tool): name = "DisplayDL1Calib" description = "Calibrate dl0 data to dl1, and plot the photoelectron " \ "images." telescope = Int(None, allow_none=True, help='Telescope to view. Set to None to display all ' 'telescopes.').tag(config=True) aliases = Dict(dict(f='EventFileReaderFactory.input_path', r='EventFileReaderFactory.reader', max_events='EventFileReaderFactory.max_events', extractor='ChargeExtractorFactory.extractor', window_width='ChargeExtractorFactory.window_width', t0='ChargeExtractorFactory.t0', window_shift='ChargeExtractorFactory.window_shift', sig_amp_cut_HG='ChargeExtractorFactory.sig_amp_cut_HG', sig_amp_cut_LG='ChargeExtractorFactory.sig_amp_cut_LG', lwt='ChargeExtractorFactory.lwt', clip_amplitude='CameraDL1Calibrator.clip_amplitude', T='DisplayDL1Calib.telescope', O='ImagePlotter.output_path' )) flags = Dict(dict(D=({'ImagePlotter': {'display': True}}, "Display the photoelectron images on-screen as they " "are produced.") )) classes = List([EventFileReaderFactory, ChargeExtractorFactory, CameraDL1Calibrator, ImagePlotter ]) def __init__(self, **kwargs): super().__init__(**kwargs) self.reader = None self.calibrator = None self.plotter = None def setup(self): kwargs = dict(config=self.config, tool=self) reader_factory = EventFileReaderFactory(**kwargs) reader_class = reader_factory.get_class() self.reader = reader_class(**kwargs) self.calibrator = CameraCalibrator(origin=self.reader.origin, **kwargs) self.plotter = ImagePlotter(**kwargs) def start(self): source = self.reader.read() for event in source: self.calibrator.calibrate(event) tel_list = event.r0.tels_with_data if self.telescope: if self.telescope not in tel_list: continue tel_list = [self.telescope] for telid in tel_list: self.plotter.plot(event, telid) def finish(self): self.plotter.finish()
class AnalyseData: def __init__(self): self.pixel_mask = [1] * 2048 self.calib = CameraCalibrator(None, None) self.filename = '/Users/armstrongt/Workspace/CTA/MCValidation/data/bypass2_enoise_pe100.simtel.gz' # def __init__(self): # self.file_reader = None # self.r1 = None # self.dl0 = None # self.dl1 = None # self.calculator = None def plot_peds(self, event, peds, pedvars): """ make a quick plot of the pedestal values""" pixid = np.arange(len(peds)) plt.subplot(1, 2, 1) plt.scatter(pixid, peds) plt.title("Pedestals for event {}".format(event.r0.event_id)) plt.subplot(1, 2, 2) plt.scatter(pixid, pedvars) plt.title("Ped Variances for event {}".format(event.r0.event_id)) def calc_pedestals(self): start = 15 end = None for event in hessio_event_source(self.filename): for telid in event.r0.tels_with_data: for chan in range(event.r0.tel[telid].adc_samples.shape[0]): traces = event.r0.tel[telid].adc_samples[chan, ...] peds, pedvars = pedestals.calc_pedestals_from_traces( traces, start, end) print("Number of samples: {}".format(traces.shape[1])) print("Calculate over window:({},{})".format(start, end)) print("PEDS:", peds) print("VARS:", pedvars) print("-----") self.plot_peds(event, peds, pedvars) plt.show() def get_image(self): all_pe = [] for event in hessio_event_source(self.filename): for telid in event.r0.tels_with_data: self.calib.calibrate(event) im = event.dl1.tel[telid].image # print(im[0]) all_pe = all_pe + list(im[0]) return all_pe def get_charge(self): fig = plt.figure(1) ax = fig.add_subplot(111) calculator = ChargeResolutionCalculator(config=None, tool=None) calculator2 = ChargeResolutionCalculator(config=None, tool=None) pevals = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 24, 26, 28, 30, 32, 35, 37, 40, 43, 46, 49, 53, 57, 61, 65, 70, 75, 81, 86, 93, 100, 107, 114, 123, 132, 141, 151, 162, 174, 187, 200, 215, 231, 247, 265, 284, 305, 327, 351, 376, 403, 432, 464, 497, 533, 572, 613, 657, 705, 756, 811, 869, 932, 1000 ] for n, i in enumerate(pevals): self.filename = '/Users/armstrongt/Workspace/CTA/MCValidation/data/bypass2_enoise_pe_e%s.simtel.gz' % n ntrig = 0 source = hessio_event_source(self.filename, allowed_tels=None, max_events=None) for event in source: self.calib.calibrate(event) true_charge = event.mc.tel[ 1].photo_electron_image * self.pixel_mask measured_charge = event.dl1.tel[1].image[0] * self.pixel_mask true_charge2 = np.asarray( [int(i)] * len(measured_charge)) * self.pixel_mask calculator.add_charges(true_charge, measured_charge) calculator2.add_charges(true_charge2, measured_charge) ntrig = ntrig + 1 x, res, res_error, scaled_res, scaled_res_error = calculator.get_charge_resolution( ) x2, res2, res_error2, scaled_res2, scaled_res_error2 = calculator2.get_charge_resolution( ) ax.errorbar(x, res, yerr=res_error, marker='x', linestyle="None", label='MC Charge Res') ax.errorbar(x2, res2, yerr=res_error2, marker='x', color='C1', linestyle="None", label='\'Lab\' Charge Res') x = np.logspace(np.log10(0.9), np.log10(1000 * 1.1), 100) requirement = ChargeResolutionCalculator.requirement(x) goal = ChargeResolutionCalculator.goal(x) poisson = ChargeResolutionCalculator.poisson(x) r_p = ax.plot(x, requirement, 'r', ls='--', label='Requirement') g_p = ax.plot(x, goal, 'g', ls='--', label='Goal') p_p = ax.plot(x, poisson, c='0.75', ls='--', label='Poisson') plt.legend() plt.yscale('log') plt.xscale('log') plt.xlabel('true charge') plt.ylabel('charge resolution') plt.show() def get_trig_eff(self): fig = plt.figure(1) ax = fig.add_subplot(111) pevals = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 24, 26, 28, 30, 32, 35, 37, 40, 43, 46, 49, 53, 57, 61, 65, 70, 75, 81, 86, 93, 100, 107, 114, 123, 132, 141, 151, 162, 174, 187, 200, 215, 231, 247, 265, 284, 305, 327, 351, 376, 403, 432, 464, 497, 533, 572, 613, 657, 705, 756, 811, 869, 932, 1000 ] sum_image = [] sum_true_charge = [] sum_true_charge2 = [] trig = [] for n, i in enumerate(pevals): self.filename = '/Users/armstrongt/Workspace/CTA/MCValidation/data/bypass2_enoise_pe_e%s.simtel.gz' % n ntrig = 0 source = hessio_event_source(self.filename, allowed_tels=None, max_events=None) sum_image_i = [] sum_true_charge_i = [] for event in source: self.calib.calibrate(event) true_charge = event.mc.tel[ 1].photo_electron_image * self.pixel_mask measured_charge = event.dl1.tel[1].image[0] true_charge2 = np.asarray([int(i)] * len(measured_charge)) sum_image_i.append(sum(measured_charge)) sum_true_charge_i.append(sum(true_charge)) ntrig = ntrig + 1 sum_true_charge2.append(10 * i) sum_image.append(np.mean(sum_image_i)) sum_true_charge.append(np.mean(sum_true_charge_i)) trig.append(ntrig) plt.plot(sum_image, trig, label='measured') plt.plot(sum_true_charge2, trig, label='true input') plt.plot(sum_true_charge, trig, label='true measured') plt.xlabel('total charge') plt.ylabel('trigger efficiency') plt.legend() plt.show() def go(self): fig = plt.figure() ax = fig.add_subplot(111) disp = None source = hessio_event_source(self.filename, requested_event=24) for event in source: self.calib.calibrate(event) for i in range(50): ipix = np.random.randint(0, 2048) samp = event.dl0.tel[1]['pe_samples'][0][ipix] # plt.plot(range(len(samp)),samp) plt.show() if disp is None: geom = event.inst.subarray.tel[1].camera disp = CameraDisplay(geom) # disp.enable_pixel_picker() disp.add_colorbar() plt.show(block=False) # im = event.dl1.tel[1].image[0] mask = tailcuts_clean(geom, im, picture_thresh=10, boundary_thresh=5) im[~mask] = 0.0 maxpe = max(event.dl1.tel[1].image[0]) disp.image = im print(np.mean(im), '+/-', np.std(im)) plt.show()
class MuonDisplayerTool(Tool): name = 'ctapipe-display-muons' description = t.Unicode(__doc__) infile = t.Unicode( help='input file name', default=get_dataset('gamma_test_large.simtel.gz')).tag(config=True) outfile = t.Unicode(help='output file name', default=None).tag(config=True) display = t.Bool(help='display the camera events', default=False).tag(config=True) classes = t.List([ CameraCalibrator, ]) aliases = t.Dict({ 'infile': 'MuonDisplayerTool.infile', 'outfile': 'MuonDisplayerTool.outfile', 'display': 'MuonDisplayerTool.display' }) def setup(self): self.calib = CameraCalibrator() def start(self): output_parameters = { 'MuonEff': [], 'ImpactP': [], 'RingWidth': [], 'RingCont': [], 'RingComp': [], 'RingPixComp': [], 'Core_x': [], 'Core_y': [], 'Impact_x_arr': [], 'Impact_y_arr': [], 'MCImpactP': [], 'ImpactDiff': [], 'RingSize': [], 'RingRadius': [], 'NTels': [] } numev = 0 num_muons_found = 0 for event in event_source(self.infile): self.log.info("Event Number: %d, found %d muons", numev, num_muons_found) self.calib.calibrate(event) muon_evt = analyze_muon_event(event) numev += 1 if not muon_evt[ 'MuonIntensityParams']: # No telescopes contained a good muon continue else: if self.display: plot_muon_event(event, muon_evt) ntels = len(event.r0.tels_with_data) #if(len( event.r0.tels_with_data) <= 1): #continue #print("event.r0.tels_with_data", event.r0.tels_with_data) for tid in muon_evt['TelIds']: idx = muon_evt['TelIds'].index(tid) if muon_evt['MuonIntensityParams'][idx] is not None: print("pos, tid", event.inst.subarray.positions[tid], tid) tel_x = event.inst.subarray.positions[tid][0] tel_y = event.inst.subarray.positions[tid][1] core_x = event.mc.core_x # MC Core x core_y = event.mc.core_y # MC Core y rec_impact_x = muon_evt['MuonIntensityParams'][ idx].impact_parameter_pos_x rec_impact_y = muon_evt['MuonIntensityParams'][ idx].impact_parameter_pos_y print("rec_impact_x, rec_impact_y", rec_impact_x, rec_impact_y) print("event.mc.core_x, event.mc.core_y", event.mc.core_x, event.mc.core_y) impact_mc = np.sqrt( np.power(core_x - tel_x, 2) + np.power(core_y - tel_y, 2)) print("simulated impact", impact_mc) # Coordinate transformation to move the impact point to array coordinates rec_impact_x_arr = tel_x + rec_impact_x rec_impact_y_arr = tel_y + rec_impact_y print("impact_x_arr, impact_y_arr", rec_impact_x_arr, rec_impact_y_arr) # Distance between core of the showe and impact parameter impact_diff = np.sqrt( np.power(core_x - rec_impact_x_arr, 2) + np.power(core_y - rec_impact_y_arr, 2)) print("impact_diff ", impact_diff) self.log.info("** Muon params: %s", muon_evt['MuonIntensityParams'][idx]) output_parameters['MuonEff'].append( muon_evt['MuonIntensityParams'] [idx].optical_efficiency_muon) output_parameters['ImpactP'].append( muon_evt['MuonIntensityParams'] [idx].impact_parameter.value) output_parameters['RingWidth'].append( muon_evt['MuonIntensityParams'] [idx].ring_width.value) output_parameters['RingCont'].append( muon_evt['MuonRingParams'][idx].ring_containment) output_parameters['RingComp'].append( muon_evt['MuonIntensityParams'] [idx].ring_completeness) output_parameters['RingPixComp'].append( muon_evt['MuonIntensityParams'] [idx].ring_pix_completeness) output_parameters['Core_x'].append( event.mc.core_x.value) output_parameters['Core_y'].append( event.mc.core_y.value) output_parameters['Impact_x_arr'].append( rec_impact_x_arr.value) output_parameters['Impact_y_arr'].append( rec_impact_y_arr.value) output_parameters['MCImpactP'].append(impact_mc.value) output_parameters['ImpactDiff'].append( impact_diff.value) output_parameters['RingSize'].append( muon_evt['MuonIntensityParams'][idx].ring_size) output_parameters['RingRadius'].append( muon_evt['MuonRingParams'][idx].ring_radius.value) output_parameters['NTels'].append(ntels) print_muon(muon_evt, printer=self.log.info) num_muons_found += 1 t = Table(output_parameters) t['ImpactP'].unit = 'm' t['RingWidth'].unit = 'deg' #t['MCImpactP'].unit = 'm' if self.outfile: t.write(self.outfile)
class MuonDisplayerTool(Tool): name = 'ctapipe-display-muons' description = t.Unicode(__doc__) events = t.Unicode("", help="input event data file").tag(config=True) outfile = t.Unicode("muons.hdf5", help='HDF5 output file name').tag( config=True) display = t.Bool( help='display the camera events', default=False ).tag(config=True) classes = t.List([ CameraCalibrator, EventSource ]) aliases = t.Dict({ 'input': 'MuonDisplayerTool.events', 'outfile': 'MuonDisplayerTool.outfile', 'display': 'MuonDisplayerTool.display', 'max_events': 'EventSource.max_events', 'allowed_tels': 'EventSource.allowed_tels', }) def setup(self): if self.events == '': raise ToolConfigurationError("please specify --input <events file>") self.log.debug("input: %s", self.events) self.source = event_source(self.events) self.calib = CameraCalibrator( config=self.config, tool=self, eventsource=self.source ) self.writer = HDF5TableWriter(self.outfile, "muons") def start(self): numev = 0 self.num_muons_found = defaultdict(int) for event in tqdm(self.source, desc='detecting muons'): self.calib.calibrate(event) muon_evt = analyze_muon_event(event) if numev == 0: _exclude_some_columns(event.inst.subarray, self.writer) numev += 1 if not muon_evt['MuonIntensityParams']: # No telescopes contained a good muon continue else: if self.display: plot_muon_event(event, muon_evt) for tel_id in muon_evt['TelIds']: idx = muon_evt['TelIds'].index(tel_id) intens_params = muon_evt['MuonIntensityParams'][idx] if intens_params is not None: ring_params = muon_evt['MuonRingParams'][idx] cam_id = str(event.inst.subarray.tel[tel_id].camera) self.num_muons_found[cam_id] += 1 self.log.debug("INTENSITY: %s", intens_params) self.log.debug("RING: %s", ring_params) self.writer.write(table_name=cam_id, containers=[intens_params, ring_params]) self.log.info( "Event Number: %d, found %s muons", numev, dict(self.num_muons_found) ) def finish(self): Provenance().add_output_file(self.outfile, role='dl1.tel.evt.muon') self.writer.close()
class DisplayDL1Calib(Tool): name = "DisplayDL1Calib" description = "Calibrate dl0 data to dl1, and plot the photoelectron " \ "images." telescope = Int( None, allow_none=True, help='Telescope to view. Set to None to display all ' 'telescopes.' ).tag(config=True) aliases = Dict( dict( max_events='EventSourceFactory.max_events', extractor='ChargeExtractorFactory.product', window_width='ChargeExtractorFactory.window_width', t0='ChargeExtractorFactory.t0', window_shift='ChargeExtractorFactory.window_shift', sig_amp_cut_HG='ChargeExtractorFactory.sig_amp_cut_HG', sig_amp_cut_LG='ChargeExtractorFactory.sig_amp_cut_LG', lwt='ChargeExtractorFactory.lwt', clip_amplitude='CameraDL1Calibrator.clip_amplitude', T='DisplayDL1Calib.telescope', O='ImagePlotter.output_path' ) ) flags = Dict( dict( D=({ 'ImagePlotter': { 'display': True } }, "Display the photoelectron images on-screen as they " "are produced.") ) ) classes = List([ EventSourceFactory, ChargeExtractorFactory, CameraDL1Calibrator, ImagePlotter ]) def __init__(self, **kwargs): super().__init__(**kwargs) self.eventsource = None self.calibrator = None self.plotter = None def setup(self): kwargs = dict(config=self.config, tool=self) self.eventsource = EventSourceFactory.produce( input_url=get_dataset_path("gamma_test.simtel.gz"), **kwargs ) self.calibrator = CameraCalibrator( eventsource=self.eventsource, **kwargs ) self.plotter = ImagePlotter(**kwargs) def start(self): for event in self.eventsource: self.calibrator.calibrate(event) tel_list = event.r0.tels_with_data if self.telescope: if self.telescope not in tel_list: continue tel_list = [self.telescope] for telid in tel_list: self.plotter.plot(event, telid) def finish(self): self.plotter.finish()
class PedestalGenerator(Tool): name = "PedestalGenerator" description = "Generate the a pickle file of Pedestals for " \ "either MC or data files." telescopes = Int(1, help='Telescopes to include from the event file. ' 'Default = 1').tag(config=True) pixel = Int(None, allow_none=True, help='Which pixel to use, defaul = all').tag(config=True) output_name = Unicode( 'extracted_pedestals', help='path where to store the output extracted pedestal hdf5 ' 'file').tag(config=True) input_path = Unicode(help='Path to directory containing data').tag( config=True) max_events = Int(1, help='Maximum number of events to use').tag(config=True) t0 = Int(0, help='Timeslice to start pedestal').tag(config=True) window_width = Int( 10, help='length of window within which to determine pedestal').tag( config=True) debug = Bool(False, "plot resulting histograms").tag(config=True) aliases = Dict( dict(input_path='PedestalGenerator.input_path', max_events='PedestalGenerator.max_events', window_width='PedestalGenerator.window_width', t0='PedestalGenerator.t0', T='PedestalGenerator.telescopes', p='PedestalGenerator.pixel', o='PedestalGenerator.output_name', dd='PedestalGenerator.debug')) classes = List([ EventSourceFactory, HESSIOEventSource, TargetIOEventSource, ChargeExtractorFactory, CameraDL1Calibrator, CameraCalibrator ]) def __init__(self, **kwargs): super().__init__(**kwargs) self.eventsource = None self.r1 = None self.dl0 = None self.dl1 = None self.cal = None self.run_list = None self.file_list = None self.baseline_bins = np.arange(0, 7, 7 / 17.) self.baseline_start_rms = [] self.baseline_start_mean = [] self.baseline_end_rms = [] self.baseline_end_mean = [] self.waveform_rms = [] self.waveform_mean = [] self.pulse_max = [] self.pulse_fwhm = [] self.pltnsb = [0.01, 0.05, 0.100, 0.200, 0.300, 0.500] def setup(self): kwargs = dict(config=self.config, tool=self) self.run_list = np.loadtxt('%s/../runlist.txt' % self.input_path, unpack=True) self.file_list = listdir('%s' % self.input_path) self.dl0 = CameraDL0Reducer(**kwargs) self.dl1 = CameraDL1Calibrator(**kwargs) self.cal = CameraCalibrator( eventsource=EventSourceFactory.produce(input_url="%s/%s" % (self.input_path, self.file_list[0]), max_events=1)) def start(self): for n, run in enumerate(self.run_list[0]): self.baseline_start_rms.append([]) self.baseline_start_mean.append([]) self.baseline_end_rms.append([]) self.baseline_end_mean.append([]) self.waveform_rms.append([]) self.waveform_mean.append([]) self.pulse_max.append([]) self.pulse_fwhm.append([]) # if self.run_list[6][n] not in self.pltnsb: # print('lets save some time!') # continue #check if str(int(run)) not in self.file_list[n]: print(str(int(run)), self.file_list[n]) print('check runlist.txt order, needs to be sorted?') self.file_list.sort() if str(int(run)) not in self.file_list[n]: print('Sorting didn\'t seem to help, giving up.') exit() else: print('Sorted and sorted.') file_name = "%s/%s" % (self.input_path, self.file_list[n]) print(file_name) try: source = EventSourceFactory.produce(input_url=file_name, max_events=self.max_events) for event in tqdm(source): self.cal.calibrate(event) self.dl0.reduce(event) self.dl1.calibrate(event) teldata = event.r1.tel[self.telescopes].waveform[0] if self.pixel is None: self.baseline_start_mean[n].append( np.mean(np.mean(teldata[:, 0:20], axis=1))) self.baseline_start_rms[n].append( np.mean(np.std(teldata[:, 0:20], axis=1))) self.baseline_end_mean[n].append( np.mean(np.mean(teldata[:, -20:], axis=1))) self.baseline_end_rms[n].append( np.mean(np.std(teldata[:, -20:], axis=1))) self.waveform_mean[n].append( np.mean(np.mean(teldata, axis=1))) self.waveform_rms[n].append( np.mean(np.std(teldata, axis=1))) pls_max = [] pls_fwhm = [] nm = len(teldata[0]) nmrange = np.arange(nm) mean = np.mean(np.multiply(teldata, np.arange(nm)), axis=1) #sigma = np.mean(teldata*(range(nm) - mean)**2, axis=1) for i in range(0, 2048): popt, pcov = curve_fit(gaus, nmrange, teldata[i], p0=[1, mean[i], 3]) spline = UnivariateSpline( nmrange, gaus(nmrange, *popt) - np.max(gaus(nmrange, *popt)) / 2, s=0) #print(nm, mean, sigma, popt) #print(spline) #exit() try: r1, r2 = spline.roots() except ValueError: r1 = 0 r2 = 0 fwhm = r2 - r1 mx = max(gaus(range(nm), *popt)) pls_max.append(mx) pls_fwhm.append(fwhm) self.pulse_fwhm[n].append(np.mean(pls_fwhm)) self.pulse_max[n].append(np.mean(pls_max)) else: self.baseline_start_mean[n].append( np.mean(teldata[self.pixel, 0:20])) self.baseline_start_rms[n].append( np.std(teldata[self.pixel, 0:20])) self.baseline_end_mean[n].append( np.mean(teldata[self.pixel, -20:])) self.baseline_end_rms[n].append( np.std(teldata[self.pixel, -20:])) self.waveform_mean[n].append( np.mean(teldata[self.pixel, :])) self.waveform_rms[n].append( np.std(teldata[self.pixel, :])) n = len(teldata[0]) mean = sum( range(len(teldata[0])) * (teldata[self.pixel])) / n sigma = sum((teldata[self.pixel]) * (range(len(teldata[0])) - mean)**2) / n popt, pcov = curve_fit(gaus, range(len(teldata[0])), teldata[self.pixel], p0=[1, mean, sigma]) spline = UnivariateSpline( range(len(teldata[0])), gaus(range(len(teldata[0])), *popt) - np.max(gaus(range(len(teldata[0])), *popt)) / 2, s=0) r1, r2 = spline.roots() fwhm = r2 - r1 mx = max(gaus(range(len(teldata[0])), *popt)) self.pulse_max[n].append(mx) self.pulse_fwhm[n].append(fwhm) except FileNotFoundError: stop = 0 print('file_not_found') def finish(self): if self.debug: fig1 = plt.figure(1) ax1 = fig1.add_subplot(111) fig2 = plt.figure(2) ax2 = fig2.add_subplot(111) fig3 = plt.figure(3) ax3 = fig3.add_subplot(111) fig4 = plt.figure(4) ax4 = fig4.add_subplot(111) fig5 = plt.figure(5) ax5 = fig5.add_subplot(111) fig6 = plt.figure(6) ax6 = fig6.add_subplot(111) fig7 = plt.figure(7) ax7 = fig7.add_subplot(111) fig8 = plt.figure(8) ax8 = fig8.add_subplot(111) for n in range(len(self.baseline_start_rms)): if len(self.baseline_start_mean[n]) > 0: ax1.hist(self.baseline_start_mean[n], bins=50, alpha=0.9, histtype='stepfilled', label='%s MHz' % str(1000 * self.run_list[6][n])) ax2.hist(self.baseline_start_rms[n], bins=50, alpha=0.9, histtype='stepfilled', label='%s MHz' % str(1000 * self.run_list[6][n])) ax3.hist(self.baseline_end_mean[n], bins=50, alpha=0.9, histtype='stepfilled', label='%s MHz' % str(1000 * self.run_list[6][n])) ax4.hist(self.baseline_end_rms[n], bins=50, alpha=0.9, histtype='stepfilled', label='%s MHz' % str(1000 * self.run_list[6][n])) ax5.hist(self.waveform_mean[n], bins=50, alpha=0.9, histtype='stepfilled', label='%s MHz' % str(1000 * self.run_list[6][n])) ax6.hist(self.waveform_rms[n], bins=50, alpha=0.9, histtype='stepfilled', label='%s MHz' % str(1000 * self.run_list[6][n])) ax7.hist(self.pulse_max[n], bins=50, alpha=0.9, histtype='stepfilled', label='%s MHz' % str(1000 * self.run_list[6][n])) ax8.hist(self.pulse_fwhm[n], bins=50, alpha=0.9, histtype='stepfilled', label='%s MHz' % str(1000 * self.run_list[6][n])) ax1.set_title('baseline_start_mean') ax2.set_title('baseline_start_rms') ax3.set_title('baseline_end_mean') ax4.set_title('baseline_end_rms') ax5.set_title('waveform_mean') ax6.set_title('waveform_rms') ax7.set_title('pulse_max') ax8.set_title('pulse_fwhm') ax1.legend() ax2.legend() ax3.legend() ax4.legend() ax5.legend() ax6.legend() ax7.legend() ax8.legend() plt.show() if not path.isdir(self.output_name): makedirs(self.output_name) columns_str = [ 'baselineStartMean', 'baselineStartRMS', 'baselineEndMean', 'baselineEndRMS', 'baselineWaveformMean', 'baselineWaveformRMS', 'pulseMAX', 'pulseFWHM' ] for n in range(len(self.baseline_start_rms)): if len(self.baseline_start_mean[n]) > 0: print(self.baseline_start_mean[n]) out_array = np.array([ self.baseline_start_mean[n], self.baseline_start_rms[n], self.baseline_end_mean[n], self.baseline_end_rms[n], self.waveform_mean[n], self.waveform_rms[n], self.pulse_max[n], self.pulse_fwhm[n] ]) print(out_array, columns_str) data = pd.DataFrame(out_array.T, columns=columns_str) data.to_hdf( '%s/extracted_pedestals_%sMHz.h5' % (self.output_name, str(1000 * self.run_list[6][n])), 'table', append=True) # columns_str.append('%sMHz_baselineStartMean' % str(1000*self.run_list[6][n])) # columns_str.append('%sMHz_baselineStartRMS' % str(1000*self.run_list[6][n])) # columns_str.append('%sMHz_baselineEndMean' % str(1000*self.run_list[6][n])) # columns_str.append('%sMHz_baselineEndRMS' % str(1000*self.run_list[6][n])) # columns_str.append('%sMHz_baselineWaveformMean' % str(1000*self.run_list[6][n])) # columns_str.append('%sMHz_baselineWaveformRMS' % str(1000*self.run_list[6][n])) # out_array = np.concatenate((self.baseline_start_mean,self.baseline_start_rms, # self.baseline_end_mean, self.baseline_end_rms, # self.waveform_mean, self.waveform_rms), axis=0) # data = pd.DataFrame(out_array.T, columns=columns_str) # data.columns = data.columns.str.split('_', expand=True) # print(data) # data.to_hdf(self.output_name, 'table', append=True) print('Done!')
'ASTRICam': (5, 7, 2), } input_url = get_dataset_path('gamma_test_large.simtel.gz') event_source = EventSourceFactory.produce(input_url=input_url) calibrator = CameraCalibrator( eventsource=event_source, ) reco = HillasReconstructor() for event in event_source: print('Event', event.count) calibrator.calibrate(event) # mapping of telescope_id to parameters for stereo reconstruction hillas_containers = {} pointing_azimuth = {} pointing_altitude = {} time_gradients = {} for telescope_id, dl1 in event.dl1.tel.items(): camera = event.inst.subarray.tels[telescope_id].camera image = dl1.image[0] peakpos = dl1.peakpos[0] # cleaning boundary, picture, min_neighbors = cleaning_level[camera.cam_id]
def extract_images(simtel_file_path, tel_id_filter_list=None, event_id_filter_list=None, output_directory=None): # EXTRACT IMAGES ########################################################## # hessio_event_source returns a Python generator that streams data from an # EventIO/HESSIO MC data file (e.g. a standard CTA data file). # This generator contains ctapipe.core.Container instances ("event"). # # Parameters: # - max_events: maximum number of events to read # - allowed_tels: select only a subset of telescope, if None, all are read. source = hessio_event_source(simtel_file_path, allowed_tels=tel_id_filter_list) # ITERATE OVER EVENTS ##################################################### calib = CameraCalibrator(None, None) for event in source: calib.calibrate(event) # calibrate the event event_id = int(event.dl0.event_id) if (event_id_filter_list is None) or (event_id in event_id_filter_list): #print("event", event_id) # ITERATE OVER IMAGES ############################################# for tel_id in event.trig.tels_with_trigger: tel_id = int(tel_id) if tel_id in tel_id_filter_list: #print("telescope", tel_id) # CHECK THE IMAGE GEOMETRY ################################ #print("checking geometry") x, y = event.inst.subarray.tel[ tel_id].camera.pix_x, event.inst.subarray.tel[ tel_id].camera.pix_y foclen = event.inst.subarray.tel[ tel_id].optics.equivalent_focal_length geom = CameraGeometry.guess(x, y, foclen) if (geom.pix_type != "hexagonal") or (geom.cam_id != "DigiCam"): raise ValueError( "Telescope {}: error (the input image is not a valide DigiCam telescope image) -> {} ({})" .format(tel_id, geom.pix_type, geom.cam_id)) # GET IMAGES ############################################## pe_image = event.mc.tel[ tel_id].photo_electron_image # 1D np array #uncalibrated_image = event.dl0.tel[tel_id].adc_sums # ctapipe 0.3.0 uncalibrated_image = event.r0.tel[ tel_id].adc_sums # ctapipe 0.4.0 pedestal = event.mc.tel[tel_id].pedestal gain = event.mc.tel[tel_id].dc_to_pe pixel_pos = (event.inst.subarray.tel[tel_id].camera.pix_x, event.inst.subarray.tel[tel_id].camera.pix_y) calibrated_image = event.dl1.tel[tel_id].image #print(pe_image.shape) #print(calibrated_image.shape) #print(uncalibrated_image.shape) #print(pedestal.shape) #print(gain.shape) #print(pixel_pos.shape) #print(pixel_pos[0]) #print(pixel_pos[1]) # CONVERTING GEOMETRY (1D TO 2D) ########################## buffer_id_str = geom.cam_id + "0" geom2d, pe_image_2d = ctapipe_geom_converter.convert_geometry_1d_to_2d( geom, pe_image, buffer_id_str, add_rot=0) geom2d, calibrated_image_2d = ctapipe_geom_converter.convert_geometry_1d_to_2d( geom, calibrated_image[0], buffer_id_str, add_rot=0) geom2d, uncalibrated_image_2d = ctapipe_geom_converter.convert_geometry_1d_to_2d( geom, uncalibrated_image[0], buffer_id_str, add_rot=0) geom2d, pedestal_2d = ctapipe_geom_converter.convert_geometry_1d_to_2d( geom, pedestal[0], buffer_id_str, add_rot=0) geom2d, gains_2d = ctapipe_geom_converter.convert_geometry_1d_to_2d( geom, gain[0], buffer_id_str, add_rot=0) # Make a mock pixel position array... pixel_pos_2d = np.array( np.meshgrid( np.linspace(pixel_pos[0].min(), pixel_pos[0].max(), pe_image_2d.shape[0]), np.linspace(pixel_pos[1].min(), pixel_pos[1].max(), pe_image_2d.shape[1]))) # PUT NAN IN BLANK PIXELS ################################# calibrated_image_2d[np.logical_not(geom2d.mask)] = np.nan pe_image_2d[np.logical_not(geom2d.mask)] = np.nan uncalibrated_image_2d[np.logical_not(geom2d.mask)] = np.nan pedestal_2d[np.logical_not(geom2d.mask)] = np.nan gains_2d[np.logical_not(geom2d.mask)] = np.nan pixel_pos_2d[0, np.logical_not(geom2d.mask)] = np.nan pixel_pos_2d[1, np.logical_not(geom2d.mask)] = np.nan ########################################################### # The ctapipe geometry converter operate on one channel # only and then takes and return a 2D array but pywicta # fits files keep all channels and thus takes 3D arrays... uncalibrated_image_2d = np.array([uncalibrated_image_2d]) pedestal_2d = np.array([pedestal_2d]) gains_2d = np.array([gains_2d]) ########################################################### #print(pe_image_2d.shape) #print(calibrated_image_2d.shape) #print(uncalibrated_image_2d.shape) #print(pedestal_2d.shape) #print(gains_2d.shape) #img = pixel_pos_2d #print(img[1]) #import matplotlib.pyplot as plt #im = plt.imshow(img[1]) #plt.colorbar(im) #plt.show() #sys.exit(0) # GET PIXEL MASK ########################################## pixel_mask = geom2d.mask.astype( int ) # 1 for pixels with actual data, 0 for virtual (blank) pixels # MAKE METADATA ########################################### metadata = {} metadata[ 'version'] = 1 # Version of the pywicta fits format metadata['cam_id'] = "DigiCam" metadata['tel_id'] = tel_id metadata['event_id'] = event_id metadata['simtel'] = simtel_file_path metadata['tel_trig'] = len(event.trig.tels_with_trigger) metadata['energy'] = quantity_to_tuple( event.mc.energy, 'TeV') metadata['mc_az'] = quantity_to_tuple(event.mc.az, 'rad') metadata['mc_alt'] = quantity_to_tuple(event.mc.alt, 'rad') metadata['mc_corex'] = quantity_to_tuple( event.mc.core_x, 'm') metadata['mc_corey'] = quantity_to_tuple( event.mc.core_y, 'm') metadata['mc_hfi'] = quantity_to_tuple( event.mc.h_first_int, 'm') metadata['count'] = int(event.count) metadata['run_id'] = int(event.dl0.obs_id) metadata['tel_data'] = len(event.dl0.tels_with_data) metadata['foclen'] = quantity_to_tuple( event.inst.subarray.tel[tel_id].optics. equivalent_focal_length, 'm') metadata['tel_posx'] = quantity_to_tuple( event.inst.subarray.tel_coords[tel_id].x, 'm') metadata['tel_posy'] = quantity_to_tuple( event.inst.subarray.tel_coords[tel_id].y, 'm') metadata['tel_posz'] = quantity_to_tuple( event.inst.subarray.tel_coords[tel_id].z, 'm') # TODO: Astropy fails to store the following data in FITS files #metadata['uid'] = os.getuid() #metadata['datetime'] = str(datetime.datetime.now()) #metadata['version'] = VERSION #metadata['argv'] = " ".join(sys.argv).encode('ascii', errors='ignore').decode('ascii') #metadata['python'] = " ".join(sys.version.splitlines()).encode('ascii', errors='ignore').decode('ascii') #metadata['system'] = " ".join(os.uname()) # SAVE THE IMAGE ########################################## output_file_path_template = "{}_TEL{:03d}_EV{:05d}.fits" if output_directory is not None: simtel_basename = os.path.basename(simtel_file_path) prefix = os.path.join(output_directory, simtel_basename) else: prefix = simtel_file_path output_file_path = output_file_path_template.format( prefix, tel_id, event_id) print("saving", output_file_path) images.save_benchmark_images( img=calibrated_image_2d, pe_img=pe_image_2d, adc_sums_img=uncalibrated_image_2d, pedestal_img=pedestal_2d, gains_img=gains_2d, pixel_pos=pixel_pos_2d, pixel_mask=pixel_mask, metadata=metadata, output_file_path=output_file_path)
class ChargeResolutionGenerator(Tool): name = "ChargeResolutionGenerator" description = "Generate the a pickle file of ChargeResolutionFile for " \ "either MC or data files." telescopes = Int(1,help='Telescopes to include from the event file. ' 'Default = 1').tag(config=True) output_name = Unicode('charge_resolution', help='Name of the output charge resolution hdf5 ' 'file').tag(config=True) input_path = Unicode(help='Path to directory containing data').tag(config=True) max_events = Int(1, help='Maximum number of events to use').tag(config=True) plot_cam = Bool(False, "enable plotting of individual camera").tag(config=True) use_true_pe = Bool(False, "Use true mc p.e.").tag(config=True) calibrator = Unicode('HESSIOR1Calibrator', help='which calibrator to use, default = HESSIOR1Calibrator').tag(config=True) aliases = Dict(dict(input_path='ChargeResolutionGenerator.input_path', calibrator='ChargeResolutionGenerator.calibrator', max_events='ChargeResolutionGenerator.max_events', extractor='ChargeExtractorFactory.product', window_width='ChargeExtractorFactory.window_width', t0='ChargeExtractorFactory.t0', window_shift='ChargeExtractorFactory.window_shift', sig_amp_cut_HG='ChargeExtractorFactory.sig_amp_cut_HG', sig_amp_cut_LG='ChargeExtractorFactory.sig_amp_cut_LG', lwt='ChargeExtractorFactory.lwt', clip_amplitude='CameraDL1Calibrator.clip_amplitude', radius='CameraDL1Calibrator.radius', max_pe='ChargeResolutionCalculator.max_pe', T='ChargeResolutionGenerator.telescopes', o='ChargeResolutionGenerator.output_name', plot_cam='ChargeResolutionGenerator.plot_cam', use_true_pe='ChargeResolutionGenerator.use_true_pe' )) classes = List([EventSourceFactory, HESSIOEventSource, TargetIOEventSource, ChargeExtractorFactory, CameraDL1Calibrator, ChargeResolutionCalculator, CameraCalibrator ]) def __init__(self, **kwargs): super().__init__(**kwargs) self.eventsource = None self.r1 = None self.dl0 = None self.dl1 = None self.calculator = None self.cal = None def setup(self): kwargs = dict(config=self.config, tool=self) self.dl0 = CameraDL0Reducer(**kwargs) self.dl1 = CameraDL1Calibrator(**kwargs) self.cal = CameraCalibrator(r1_product=self.calibrator) self.calculator = ChargeResolutionCalculator(**kwargs) def start(self): run_list = np.loadtxt('%s/runlist.txt' % self.input_path, unpack=True) plot_cam = False plot_delay = 0.5 disp = None if debug: fig=plt.figure(1) ax=fig.add_subplot(111) for n, run in enumerate(run_list[0]): # TODO remove need for hardcoded file name if self.calibrator == "TargetIOR1Calibrator": file_name = "%s/Run%s_r1.tio" % (self.input_path, int(run)) print(file_name) elif self.calibrator == "HESSIOR1Calibrator": file_name = "%s/sim_tel/run%s.simtel.gz" % (self.input_path, int(run)) print(file_name) try: source = EventSourceFactory.produce(input_url =file_name, max_events=self.max_events) true_pe = [] # lab_pe = [] for event in tqdm(source): self.cal.calibrate(event) self.dl0.reduce(event) self.dl1.calibrate(event) input_pe = run_list[3][n] if self.plot_cam == True: if disp is None: geom = event.inst.subarray.tel[self.telescopes].camera disp = CameraDisplay(geom) disp.add_colorbar() plt.show(block=False) im = event.dl1.tel[self.telescopes].image[0] disp.image = im plt.pause(plot_delay) true_charge_mc = event.mc.tel[self.telescopes].photo_electron_image measured_charge = event.dl1.tel[self.telescopes].image[0] true_charge_lab = np.asarray([input_pe]*len(measured_charge)) true_pe.append(true_charge_mc) if self.use_true_pe: true_charge=true_charge_mc else: true_charge=true_charge_lab.astype(int) self.calculator.add_charges(true_charge, measured_charge) if debug: plt.errorbar(input_pe, np.mean(true_pe), np.std(true_pe),color='k') except FileNotFoundError: stop=0 print('file_not_found') if debug: plt.xscale('log') plt.yscale('log') plt.plot([0,1000],[0,1000], 'k:') plt.xlabel('Input p.e.') plt.ylabel('True mc p.e.') plt.show() def finish(self): out_file = '%s/charge_resolution_test.h5' % self.input_path self.calculator.save(self.output_name)
def extract_images(simtel_file_path, tel_id_filter_list=None, event_id_filter_list=None, output_directory=None): # EXTRACT IMAGES ########################################################## # hessio_event_source returns a Python generator that streams data from an # EventIO/HESSIO MC data file (e.g. a standard CTA data file). # This generator contains ctapipe.core.Container instances ("event"). # # Parameters: # - max_events: maximum number of events to read # - allowed_tels: select only a subset of telescope, if None, all are read. source = hessio_event_source(simtel_file_path, allowed_tels=tel_id_filter_list) # ITERATE OVER EVENTS ##################################################### calib = CameraCalibrator(None, None) for event in source: calib.calibrate(event) # calibrate the event event_id = int(event.dl0.event_id) if (event_id_filter_list is None) or (event_id in event_id_filter_list): #print("event", event_id) # ITERATE OVER IMAGES ############################################# for tel_id in event.trig.tels_with_trigger: tel_id = int(tel_id) if tel_id in tel_id_filter_list: #print("telescope", tel_id) # CHECK THE IMAGE GEOMETRY ################################ #print("checking geometry") x, y = event.inst.pixel_pos[tel_id] foclen = event.inst.optical_foclen[tel_id] geom = CameraGeometry.guess(x, y, foclen) if (geom.pix_type != "hexagonal") or (geom.cam_id != "LSTCam"): raise ValueError("Telescope {}: error (the input image is not a valide LSTCam telescope image) -> {} ({})".format(tel_id, geom.pix_type, geom.cam_id)) # GET IMAGES ############################################## pe_image = event.mc.tel[tel_id].photo_electron_image # 1D np array #uncalibrated_image = event.dl0.tel[tel_id].adc_sums # ctapipe 0.3.0 uncalibrated_image = event.r0.tel[tel_id].adc_sums # ctapipe 0.4.0 pedestal = event.mc.tel[tel_id].pedestal gain = event.mc.tel[tel_id].dc_to_pe pixel_pos = event.inst.pixel_pos[tel_id] calibrated_image = event.dl1.tel[tel_id].image calibrated_image[1, calibrated_image[0,:] <= LST_CAM_CHANNEL_THRESHOLD] = 0 calibrated_image[0, calibrated_image[0,:] > LST_CAM_CHANNEL_THRESHOLD] = 0 calibrated_image = calibrated_image.sum(axis=0) #print(pe_image.shape) #print(calibrated_image.shape) #print(uncalibrated_image.shape) #print(pedestal.shape) #print(gain.shape) #print(pixel_pos.shape) #print(pixel_pos[0]) #print(pixel_pos[1]) # CONVERTING GEOMETRY (1D TO 2D) ########################## buffer_id_str = geom.cam_id + "0" geom2d, pe_image_2d = ctapipe_geom_converter.convert_geometry_1d_to_2d(geom, pe_image, buffer_id_str, add_rot=0) geom2d, calibrated_image_2d = ctapipe_geom_converter.convert_geometry_1d_to_2d(geom, calibrated_image, buffer_id_str, add_rot=0) geom2d, uncalibrated_image_2d_ch0 = ctapipe_geom_converter.convert_geometry_1d_to_2d(geom, uncalibrated_image[0], buffer_id_str, add_rot=0) geom2d, uncalibrated_image_2d_ch1 = ctapipe_geom_converter.convert_geometry_1d_to_2d(geom, uncalibrated_image[1], buffer_id_str, add_rot=0) geom2d, pedestal_2d_ch0 = ctapipe_geom_converter.convert_geometry_1d_to_2d(geom, pedestal[0], buffer_id_str, add_rot=0) geom2d, pedestal_2d_ch1 = ctapipe_geom_converter.convert_geometry_1d_to_2d(geom, pedestal[1], buffer_id_str, add_rot=0) geom2d, gains_2d_ch0 = ctapipe_geom_converter.convert_geometry_1d_to_2d(geom, gain[0], buffer_id_str, add_rot=0) geom2d, gains_2d_ch1 = ctapipe_geom_converter.convert_geometry_1d_to_2d(geom, gain[1], buffer_id_str, add_rot=0) # Make a mock pixel position array... pixel_pos_2d = np.array(np.meshgrid(np.linspace(pixel_pos[0].min(), pixel_pos[0].max(), pe_image_2d.shape[0]), np.linspace(pixel_pos[1].min(), pixel_pos[1].max(), pe_image_2d.shape[1]))) ########################################################### # The ctapipe geometry converter operate on one channel # only and then takes and return a 2D array but datapipe # fits files keep all channels and thus takes 3D arrays... uncalibrated_image_2d = np.array([uncalibrated_image_2d_ch0, uncalibrated_image_2d_ch1]) pedestal_2d = np.array([pedestal_2d_ch0, pedestal_2d_ch1 ]) gains_2d = np.array([gains_2d_ch0, gains_2d_ch1]) # PUT NAN IN BLANK PIXELS ################################# calibrated_image_2d[np.logical_not(geom2d.mask)] = np.nan pe_image_2d[np.logical_not(geom2d.mask)] = np.nan uncalibrated_image_2d[0, np.logical_not(geom2d.mask)] = np.nan uncalibrated_image_2d[1, np.logical_not(geom2d.mask)] = np.nan pedestal_2d[0, np.logical_not(geom2d.mask)] = np.nan pedestal_2d[1, np.logical_not(geom2d.mask)] = np.nan gains_2d[0, np.logical_not(geom2d.mask)] = np.nan gains_2d[1, np.logical_not(geom2d.mask)] = np.nan pixel_pos_2d[0, np.logical_not(geom2d.mask)] = np.nan pixel_pos_2d[1, np.logical_not(geom2d.mask)] = np.nan ########################################################### #print(pe_image_2d.shape) #print(calibrated_image_2d.shape) #print(uncalibrated_image_2d.shape) #print(pedestal_2d.shape) #print(gains_2d.shape) #img = pixel_pos_2d #print(img[1]) #import matplotlib.pyplot as plt #im = plt.imshow(img[1]) #plt.colorbar(im) #plt.show() #sys.exit(0) # GET PIXEL MASK ########################################## pixel_mask = geom2d.mask.astype(int) # 1 for pixels with actual data, 0 for virtual (blank) pixels # MAKE METADATA ########################################### metadata = {} metadata['version'] = 1 # Version of the datapipe fits format metadata['cam_id'] = "LSTCam" metadata['tel_id'] = tel_id metadata['event_id'] = event_id metadata['simtel'] = simtel_file_path metadata['tel_trig'] = len(event.trig.tels_with_trigger) metadata['energy'] = quantity_to_tuple(event.mc.energy, 'TeV') metadata['mc_az'] = quantity_to_tuple(event.mc.az, 'rad') metadata['mc_alt'] = quantity_to_tuple(event.mc.alt, 'rad') metadata['mc_corex'] = quantity_to_tuple(event.mc.core_x, 'm') metadata['mc_corey'] = quantity_to_tuple(event.mc.core_y, 'm') metadata['mc_hfi'] = quantity_to_tuple(event.mc.h_first_int, 'm') metadata['count'] = int(event.count) metadata['run_id'] = int(event.dl0.run_id) metadata['tel_data'] = len(event.dl0.tels_with_data) metadata['foclen'] = quantity_to_tuple(event.inst.optical_foclen[tel_id], 'm') metadata['tel_posx'] = quantity_to_tuple(event.inst.tel_pos[tel_id][0], 'm') metadata['tel_posy'] = quantity_to_tuple(event.inst.tel_pos[tel_id][1], 'm') metadata['tel_posz'] = quantity_to_tuple(event.inst.tel_pos[tel_id][2], 'm') # TODO: Astropy fails to store the following data in FITS files #metadata['uid'] = os.getuid() #metadata['datetime'] = str(datetime.datetime.now()) #metadata['version'] = VERSION #metadata['argv'] = " ".join(sys.argv).encode('ascii', errors='ignore').decode('ascii') #metadata['python'] = " ".join(sys.version.splitlines()).encode('ascii', errors='ignore').decode('ascii') #metadata['system'] = " ".join(os.uname()) # SAVE THE IMAGE ########################################## output_file_path_template = "{}_TEL{:03d}_EV{:05d}.fits" if output_directory is not None: simtel_basename = os.path.basename(simtel_file_path) prefix = os.path.join(output_directory, simtel_basename) else: prefix = simtel_file_path output_file_path = output_file_path_template.format(prefix, tel_id, event_id) print("saving", output_file_path) images.save_benchmark_images(img = calibrated_image_2d, pe_img = pe_image_2d, adc_sums_img = uncalibrated_image_2d, pedestal_img = pedestal_2d, gains_img = gains_2d, pixel_pos = pixel_pos_2d, pixel_mask = pixel_mask, metadata = metadata, output_file_path = output_file_path)
class FlatFieldGenerator(Tool): name = "FlatFieldGenerator" description = "Generate the a pickle file of FlatField for " \ "either MC or data files." telescopes = Int(1, help='Telescopes to include from the event file. ' 'Default = 1').tag(config=True) output_name = Unicode('extracted_flatfield', help='Name of the output extracted flat field hdf5 ' 'file').tag(config=True) infile = Unicode(help='Path to file containing data').tag(config=True) max_events = Int(1, help='Maximum number of events to use').tag(config=True) plot_cam = Bool(False, "enable plotting of individual camera").tag(config=True) use_true_pe = Bool(False, "Use true mc p.e.").tag(config=True) calibrator = Unicode( 'HESSIOR1Calibrator', help='which calibrator to use, default = HESSIOR1Calibrator').tag( config=True) debug = Bool(False, "plot resulting histograms").tag(config=True) aliases = Dict( dict(infile='FlatFieldGenerator.infile', calibrator='FlatFieldGenerator.calibrator', max_events='FlatFieldGenerator.max_events', extractor='ChargeExtractorFactory.product', window_width='ChargeExtractorFactory.window_width', t0='ChargeExtractorFactory.t0', window_shift='ChargeExtractorFactory.window_shift', sig_amp_cut_HG='ChargeExtractorFactory.sig_amp_cut_HG', sig_amp_cut_LG='ChargeExtractorFactory.sig_amp_cut_LG', lwt='ChargeExtractorFactory.lwt', clip_amplitude='CameraDL1Calibrator.clip_amplitude', radius='CameraDL1Calibrator.radius', T='FlatFieldGenerator.telescopes', o='FlatFieldGenerator.output_name', plot_cam='FlatFieldGenerator.plot_cam', use_true_pe='FlatFieldGenerator.use_true_pe', dd='FlatFieldGenerator.debug')) classes = List([ EventSourceFactory, HESSIOEventSource, TargetIOEventSource, ChargeExtractorFactory, CameraDL1Calibrator, CameraCalibrator ]) def __init__(self, **kwargs): super().__init__(**kwargs) self.eventsource = None self.r1 = None self.dl0 = None self.dl1 = None self.calculator = None self.cal = None self.aver = None self.cross = None self.glob_peak = None self.local_peak = None self.neighbour = None self.reconstructed_image_array = [] self.mean_reconstructed_image_array = None self.mean_true_image_array = None self.event_count = 0 self.geom = None self.disp = None def setup(self): kwargs = dict(config=self.config, tool=self) self.dl0 = CameraDL0Reducer(**kwargs) self.dl1 = CameraDL1Calibrator(**kwargs) self.cal = CameraCalibrator(r1_product=self.calibrator) self.cross = CrossCorrelation() self.glob_peak = GlobalPeakIntegrator() self.local_peak = LocalPeakIntegrator() self.neighbour = NeighbourPeakIntegrator() self.aver = AverageWfPeakIntegrator() def start(self): fig1 = plt.figure(3) ax1 = fig1.add_subplot(111, aspect='equal') try: source = EventSourceFactory.produce(input_url=self.infile, max_events=self.max_events) for event in tqdm(source): self.cal.calibrate(event) self.dl0.reduce(event) self.dl1.calibrate(event) if self.disp is None: self.geom = event.inst.subarray.tel[self.telescopes].camera self.mean_reconstructed_image_array = np.zeros( len(self.geom.pix_id)) self.mean_true_image_array = np.zeros(len( self.geom.pix_id)) self.disp = 1 if self.debug: self.disp = CameraDisplay(self.geom) self.disp.add_colorbar() # reco_array = self.cross.get_charge(event.r1.tel[self.telescopes].waveform[0])['charge'] # reco_array = self.glob_peak.extract_charge(event.r1.tel[self.telescopes].waveform)[0][0] reco_array = self.local_peak.extract_charge( event.r1.tel[self.telescopes].waveform )[0][ 0] #/ np.mean(self.local_peak.extract_charge(event.r1.tel[self.telescopes].waveform)[0][0]) true_array = event.mc.tel[ self. telescopes].photo_electron_image #/ np.mean(event.mc.tel[self.telescopes].photo_electron_image) # print(true_array) # print(reco_array) # exit() # plt.scatter(event.mc.tel[self.telescopes].photo_electron_image,reco_array) # plt.show() # # exit() # reco_array = self.aver.extract_charge(event.r1.tel[self.telescopes].waveform)[0][0] # reco_array = self.neighbour.extract_charge(event.r1.tel[self.telescopes].waveform)[0][0] # print(reco_array) # exit() # print(event.mc.tel[self.telescopes].photo_electron_image) self.mean_true_image_array = np.add(self.mean_true_image_array, true_array) self.mean_reconstructed_image_array = np.add( self.mean_reconstructed_image_array, reco_array) # print(self.mean_true_image_array) # print(self.mean_reconstructed_image_array) # dist = np.sqrt(self.geom.pix_x.value**2 + self.geom.pix_y.value**2) # plt.scatter( self.mean_true_image_array/np.mean(self.mean_true_image_array), self.mean_reconstructed_image_array/np.mean(self.mean_reconstructed_image_array), c = dist, alpha=0.4) # ax1.set_ylim(0,2) # ax1.set_xlim(0,2) # plt.draw() # plt.pause(0.4) # plt.cla() # self.reconstructed_image_array.append(event.dl1.tel[self.telescopes].image[0]) self.event_count += 1 except FileNotFoundError: print('file_not_found') def finish(self): # out_file = open(self.output_name) # out_file.write('#PixID meanIllum\n') # for i in range(len(self.reconstructed_image_array)): # out_file.write('%s\t%s\n' % (self.geom.pix_id, self.reconstructed_image_array)) # out_file.close() self.mean_reconstructed_image_array = self.mean_reconstructed_image_array / self.event_count self.mean_true_image_array = self.mean_true_image_array / self.event_count if self.debug: # mean_image = np.mean(self.reconstructed_image_array,axis=0)/np.mean(np.mean(self.reconstructed_image_array)) mean_image = self.mean_reconstructed_image_array self.disp.image = self.mean_true_image_array # fig = plt.figure(3) # plt.hist(self.mean_true_image_array/self.mean_true_image_array.mean(), alpha = 0.5, label='true') # plt.hist( self.mean_reconstructed_image_array/self.mean_reconstructed_image_array.mean(), alpha = 0.5, label='reco') # plt.legend() # from IPython import embed # embed() # self.disp.norm = 'log' # self.disp.set_limits_minmax(40.5,44.5) plt.show()