def test_FitGammaHillas(): ''' a test on one event of the complete fit procedure including: • tailcut cleaning • hillas parametrisation • GreatCircle creation • direction fit • position fit in the end, proper units in the output are asserted ''' filename = get_path("gamma_test.simtel.gz") fit = FitGammaHillas() cam_geom = {} tel_phi = {} tel_theta = {} source = hessio_event_source(filename) for event in source: hillas_dict = {} for tel_id in event.dl0.tels_with_data: if tel_id not in cam_geom: cam_geom[tel_id] = CameraGeometry.guess( event.inst.pixel_pos[tel_id][0], event.inst.pixel_pos[tel_id][1], event.inst.optical_foclen[tel_id]) tel_phi[tel_id] = 180.*u.deg tel_theta[tel_id] = 20.*u.deg pmt_signal = event.dl0.tel[tel_id].adc_sums[0] mask = tailcuts_clean(cam_geom[tel_id], pmt_signal, 1, picture_thresh=10., boundary_thresh=5.) pmt_signal[mask == 0] = 0 try: moments = hillas_parameters(event.inst.pixel_pos[tel_id][0], event.inst.pixel_pos[tel_id][1], pmt_signal) hillas_dict[tel_id] = moments except HillasParameterizationError as e: print(e) continue if len(hillas_dict) < 2: continue fit_result = fit.predict(hillas_dict, event.inst, tel_phi, tel_theta) print(fit_result) fit_result.alt.to(u.deg) fit_result.az.to(u.deg) fit_result.core_x.to(u.m) assert fit_result.is_valid return
def start(self): geom = None imsum = None disp = None for data in hessio_event_source(self.infile, allowed_tels=self._selected_tels, max_events=None): 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.r0.tels_with_data) <= 2: continue imsum[:] = 0 for telid in data.r0.tels_with_data: imsum += data.r0.tel[telid].adc_sums[0] self.log.info("event={} ntels={} energy={}" \ .format(data.r0.event_id, len(data.r0.tels_with_data), data.mc.energy)) disp.image = imsum plt.pause(0.1)
def hillas(event): hillas_dict = {} tel_phi = {} tel_theta = {} for tel in event: tel_id = tel['tel_id'] tel_phi[tel_id] = 0. * u.deg tel_theta[tel_id] = 20. * u.deg pmt_signal = tel['adc_sums'][0] # print(pmt_signal) inst = broadcastInst.value pix_x = inst.pixel_pos[tel_id][0] pix_y = inst.pixel_pos[tel_id][1] foc = inst.optical_foclen[tel_id] cam_geom = CameraGeometry.guess(pix_x, pix_y, foc) mask = tailcuts_clean(cam_geom, pmt_signal, 1, picture_thresh=10., boundary_thresh=5.) pmt_signal[mask == 0] = 0 try: moments = hillas_parameters(cam_geom.pix_x, cam_geom.pix_y, pmt_signal) hillas_dict[tel['tel_id']] = moments except HillasParameterizationError as e: print(e) return (hillas_dict, tel_phi, tel_theta)
def fit(self, event): self.iteration=0 shower_pars = [ 1., 1.2, 0., 0., 0., 10000 ] if self.seed: shower_pars[0] = self.seed.energy .to(u.TeV).value shower_pars[1] = self.seed.alt .to(u.rad).value shower_pars[2] = self.seed.az .to(u.rad).value shower_pars[3] = self.seed.core_x .to(u.m ).value shower_pars[4] = self.seed.core_y .to(u.m ).value shower_pars[5] = self.seed.h_shower_max.to(u.m ).value # selct only pixel with data and those around them data = dict() for tel_id, tel in event.mc.tel.items(): geom = CameraGeometry.guess(self.cameras(tel_id)['PixX'].to(u.m), self.cameras(tel_id)['PixY'].to(u.m), self.telescopes['FL'][tel_id] * u.m) mask = tel.photo_electrons>0 for pixid in geom.pix_id[mask]: mask[geom.neighbors[pixid]] = True data[tel_id] = tel.photo_electrons[mask] #data = dict( [ (tel_id, tel.photo_electrons[tel.photo_electrons>0]) for tel_id, tel in event.mc.tel.items() ] ) print(shower_pars) # shower_pars = np.arra([ E / TeV, alt / rad, az / rad, core_x / m, core_y / m, h_shower_max / m]) fit_result = minimize( lambda x : self.get_nlog_likelihood(x, data), shower_pars, #method='nelder-mead', options={'xtol': 1e-8, 'disp': True} method='BFGS', options={'disp': True} ) return fit_result
def test_FitGammaHillas(): ''' a test of the complete fit procedure on one event including: • tailcut cleaning • hillas parametrisation • GreatCircle creation • direction fit • position fit in the end, proper units in the output are asserted ''' filename = get_path("gamma_test.simtel.gz") fit = FitGammaHillas() cam_geom = {} tel_phi = {} tel_theta = {} source = hessio_event_source(filename) for event in source: hillas_dict = {} for tel_id in event.dl0.tels_with_data: if tel_id not in cam_geom: cam_geom[tel_id] = CameraGeometry.guess( event.inst.pixel_pos[tel_id][0], event.inst.pixel_pos[tel_id][1], event.inst.optical_foclen[tel_id]) tel_phi[tel_id] = 0.*u.deg tel_theta[tel_id] = 20.*u.deg pmt_signal = event.dl0.tel[tel_id].adc_sums[0] mask = tailcuts_clean(cam_geom[tel_id], pmt_signal, 1, picture_thresh=10., boundary_thresh=5.) pmt_signal[mask == 0] = 0 try: moments = hillas_parameters(event.inst.pixel_pos[tel_id][0], event.inst.pixel_pos[tel_id][1], pmt_signal) hillas_dict[tel_id] = moments except HillasParameterizationError as e: print(e) continue if len(hillas_dict) < 2: continue fit_result = fit.predict(hillas_dict, event.inst, tel_phi, tel_theta) print(fit_result) fit_result.alt.to(u.deg) fit_result.az.to(u.deg) fit_result.core_x.to(u.m) assert fit_result.is_valid return
def camera_image(input_file, ax): first_event = input_file.get_event(0) geom = CameraGeometry.guess(*first_event.meta.pixel_pos[telid], first_event.meta.optical_foclen[telid]) camera = CameraDisplay(geom, ax=ax) camera.cmap = plt.cm.viridis import time def update(iframe, source): data = next(source) print(iframe) # data = np.zeros((2048,128)) # data[iframe,0] = iframe camera.image = data return camera.pixels, source = get_data(input_file) anim = FuncAnimation(fig, update, fargs=[source], blit=True, frames=1000, interval=1, repeat=False) plt.show()
def get_geometry(self, tel): cam_dimensions = (self.event.dl0.tel[tel].num_pixels, self.event.meta.optical_foclen[tel]) if tel not in self.geom_dict: self.geom_dict[tel] = \ CameraGeometry.guess(*self.event.meta.pixel_pos[tel], self.event.meta.optical_foclen[tel]) return self.geom_dict[tel]
def get_geometry(self, tel): cam_dimensions = (self.event.dl0.tel[tel].num_pixels, self.event.meta.optical_foclen[tel]) if cam_dimensions not in self.geom_dict: self.geom_dict[cam_dimensions] = \ CameraGeometry.guess(*self.event.meta.pixel_pos[tel], self.event.meta.optical_foclen[tel]) return self.geom_dict[cam_dimensions]
def get_geometry(self, tel): npix = len(self.event.dl0.tel[tel].adc_sums[0]) cam_dimensions = (npix, self.event.inst.optical_foclen[tel]) if tel not in self.geom_dict: self.geom_dict[tel] = \ CameraGeometry.guess(*self.event.inst.pixel_pos[tel], self.event.inst.optical_foclen[tel]) return self.geom_dict[tel]
def convert_geometry_back(geom, signal, key, foc_len, add_rot=0): """reverts the geometry distortion performed by convert_geometry_1d_to_2d back to a hexagonal grid stored in 1D arrays Parameters: ---------- geom : CameraGeometry geometry object where pixel positions are stored in a 2D rectangular camera grid signal : ndarray pixel intensity stored in a 2D rectangular camera grid key: key to retrieve buffered geometry information foc_len : astropy.Quantity in metres focal length of the telescope used to retrieve the original geometry through CameraGeometry.guess add_rot : int/float (default: 0) parameter to apply an additional rotation of @add_rot times 60° Returns: -------- unrot_geom : CameraGeometry pixel rotated back to a hexagonal grid stored in a 1D array signal : ndarray 1D (no timing) or 2D (with timing) array of the pmt signals """ global unrot_buffer square_mask = geom.mask if key in unrot_buffer: unrot_geom = unrot_buffer[key] else: if key in rot_buffer: x_scale = rot_buffer[key][-1] else: raise KeyError("key '{}' not found in the buffer".format(key)) grid_x, grid_y = geom.pix_x / x_scale, geom.pix_y rot_angle = add_rot * 60 * u.deg if geom.cam_id == "NectarCam" or geom.cam_id == "LSTCam": rot_angle += 90 * u.deg unrot_x, unrot_y = reskew_hex_pixel_grid(grid_x[square_mask == 1], grid_y[square_mask == 1], rot_angle) unrot_geom = CameraGeometry.guess(unrot_x, unrot_y, foc_len) unrot_buffer[key] = unrot_geom return unrot_geom, signal[square_mask == 1, ...]
def test_FitGammaHillas(): filename = get_path("gamma_test.simtel.gz") fit = FitGammaHillas() fit.setup_geometry(*load_hessio(filename), phi=180 * u.deg, theta=20 * u.deg) tel_geom = {} source = hessio_event_source(filename) for event in source: hillas_dict = {} for tel_id in set(event.trig.tels_with_trigger) & set( event.dl0.tels_with_data): if tel_id not in tel_geom: tel_geom[tel_id] = CameraGeometry.guess( fit.cameras(tel_id)['PixX'].to(u.m), fit.cameras(tel_id)['PixY'].to(u.m), fit.telescopes['FL'][tel_id - 1] * u.m) pmt_signal = event.dl0.tel[tel_id].adc_sums[0] mask = tailcuts_clean(tel_geom[tel_id], pmt_signal, 1, picture_thresh=10., boundary_thresh=5.) pmt_signal[mask is False] = 0 try: moments, moms2 = hillas_parameters( fit.cameras(tel_id)['PixX'], fit.cameras(tel_id)['PixY'], pmt_signal) hillas_dict[tel_id] = moments except HillasParameterizationError as e: print(e) continue if len(hillas_dict) < 2: continue fit_result = fit.predict(hillas_dict) print(fit_result) assert fit_result return
def test_FitGammaHillas(): filename = get_path("gamma_test.simtel.gz") fit = FitGammaHillas() fit.setup_geometry(*load_hessio(filename), phi=180 * u.deg, theta=20 * u.deg) tel_geom = {} source = hessio_event_source(filename) for event in source: hillas_dict = {} for tel_id in set(event.trig.tels_with_trigger) & set(event.dl0.tels_with_data): if tel_id not in tel_geom: tel_geom[tel_id] = CameraGeometry.guess( fit.cameras(tel_id)["PixX"].to(u.m), fit.cameras(tel_id)["PixY"].to(u.m), fit.telescopes["FL"][tel_id - 1] * u.m, ) pmt_signal = event.dl0.tel[tel_id].adc_sums[0] mask = tailcuts_clean(tel_geom[tel_id], pmt_signal, 1, picture_thresh=10.0, boundary_thresh=5.0) pmt_signal[mask is False] = 0 try: moments, moms2 = hillas_parameters(fit.cameras(tel_id)["PixX"], fit.cameras(tel_id)["PixY"], pmt_signal) hillas_dict[tel_id] = moments except HillasParameterizationError as e: print(e) continue if len(hillas_dict) < 2: continue fit_result = fit.predict(hillas_dict) print(fit_result) assert fit_result return
def test_nb_peak_integration(): telid = 11 event = get_test_event() params = get_test_parameters() data = np.array(list(event.dl0.tel[telid].adc_samples.values())) ped = event.mc.tel[telid].pedestal num_samples = event.inst.num_samples[telid] data_ped = data - np.atleast_3d(ped/num_samples) geom = CameraGeometry.guess(*event.inst.pixel_pos[telid], event.inst.optical_foclen[telid]) data_ped = np.array([data_ped[0], data_ped[0]]) # Test LG functionality integration, window, peakpos = nb_peak_integration(data_ped, geom, params) assert integration[0][0] == -64 assert integration[1][0] == -64 assert sum(window[0][0]) == params['integration_window'][0] assert sum(window[1][0]) == params['integration_window'][0] assert peakpos[0][0] == 20 assert peakpos[1][0] == 20
def test_nb_peak_integration(): telid = 11 event = get_test_event() params = get_test_parameters() data = np.array(list(event.dl0.tel[telid].adc_samples.values())) ped = event.dl0.tel[telid].pedestal nsamples = event.dl0.tel[telid].num_samples data_ped = data - np.atleast_3d(ped / nsamples) geom = CameraGeometry.guess(*event.meta.pixel_pos[telid], event.meta.optical_foclen[telid]) data_ped = np.array([data_ped[0], data_ped[0]]) # Test LG functionality integration, window, peakpos = nb_peak_integration(data_ped, geom, params) assert integration[0][0] == -64 assert integration[1][0] == -64 assert sum(window[0][0]) == params['window'] assert sum(window[1][0]) == params['window'] assert peakpos[0][0] == 20 assert peakpos[1][0] == 20
def test_nb_peak_integration(): telid = 11 event = get_test_event() data = event.r0.tel[telid].adc_samples nsamples = data.shape[2] ped = event.mc.tel[telid].pedestal data_ped = data - np.atleast_3d(ped / nsamples) data_ped = np.array([data_ped[0], data_ped[0]]) # Test LG functionality geom = CameraGeometry.guess(*event.inst.pixel_pos[telid], event.inst.optical_foclen[telid]) nei = geom.neighbors integrator = NeighbourPeakIntegrator(None, None) integrator.neighbours = nei integration, peakpos, window = integrator.extract_charge(data_ped) assert_almost_equal(integration[0][0], -64, 0) assert_almost_equal(integration[1][0], -64, 0) assert peakpos[0][0] == 20 assert peakpos[1][0] == 20
def test_integrator_switch(): telid = 11 event = get_test_event() params = get_test_parameters() num_samples = event.inst.num_samples[telid] data = event.dl0.tel[telid].adc_samples ped = event.mc.tel[telid].pedestal data_ped = data - np.atleast_3d(ped / num_samples) geom = CameraGeometry.guess(*event.inst.pixel_pos[telid], event.inst.optical_foclen[telid]) params['integrator'] = 'full_integration' integration, window, peakpos = integrator_switch(data_ped, geom, params) assert integration[0][0] == 149 assert sum(window[0][0]) == num_samples assert peakpos[0] is None params['integrator'] = 'simple_integration' integration, window, peakpos = integrator_switch(data_ped, geom, params) assert integration[0][0] == 70 assert sum(window[0][0]) == params['integration_window'][0] assert peakpos[0] is None params['integrator'] = 'global_peak_integration' integration, window, peakpos = integrator_switch(data_ped, geom, params) assert integration[0][0] == 58 assert sum(window[0][0]) == params['integration_window'][0] assert peakpos[0][0] == 14 params['integrator'] = 'local_peak_integration' integration, window, peakpos = integrator_switch(data_ped, geom, params) assert integration[0][0] == 76 assert sum(window[0][0]) == params['integration_window'][0] assert peakpos[0][0] == 13 params['integrator'] = 'nb_peak_integration' integration, window, peakpos = integrator_switch(data_ped, geom, params) assert integration[0][0] == -64 assert sum(window[0][0]) == params['integration_window'][0] assert peakpos[0][0] == 20
def test_integrator_switch(): telid = 11 event = get_test_event() params = get_test_parameters() num_samples = event.inst.num_samples[telid] data = np.array(list(event.dl0.tel[telid].adc_samples.values())) ped = event.mc.tel[telid].pedestal data_ped = data - np.atleast_3d(ped/num_samples) geom = CameraGeometry.guess(*event.inst.pixel_pos[telid], event.inst.optical_foclen[telid]) params['integrator'] = 'full_integration' integration, window, peakpos = integrator_switch(data_ped, geom, params) assert integration[0][0] == 149 assert sum(window[0][0]) == num_samples assert peakpos[0] is None params['integrator'] = 'simple_integration' integration, window, peakpos = integrator_switch(data_ped, geom, params) assert integration[0][0] == 70 assert sum(window[0][0]) == params['integration_window'][0] assert peakpos[0] is None params['integrator'] = 'global_peak_integration' integration, window, peakpos = integrator_switch(data_ped, geom, params) assert integration[0][0] == 58 assert sum(window[0][0]) == params['integration_window'][0] assert peakpos[0][0] == 14 params['integrator'] = 'local_peak_integration' integration, window, peakpos = integrator_switch(data_ped, geom, params) assert integration[0][0] == 76 assert sum(window[0][0]) == params['integration_window'][0] assert peakpos[0][0] == 13 params['integrator'] = 'nb_peak_integration' integration, window, peakpos = integrator_switch(data_ped, geom, params) assert integration[0][0] == -64 assert sum(window[0][0]) == params['integration_window'][0] assert peakpos[0][0] == 20
def test_nb_peak_integration(): telid = 11 event = get_test_event() data = event.dl0.tel[telid].adc_samples nsamples = data.shape[2] ped = event.mc.tel[telid].pedestal data_ped = data - np.atleast_3d(ped/nsamples) data_ped = np.array([data_ped[0], data_ped[0]]) # Test LG functionality geom = CameraGeometry.guess(*event.inst.pixel_pos[telid], event.inst.optical_foclen[telid]) nei = geom.neighbors integrator = NeighbourPeakIntegrator(None, None) integrator.neighbours = nei integration = integrator.extract_charge(data_ped) peakpos = integrator.peakpos print(integration[0][0]) assert_almost_equal(integration[0][0], -64, 0) assert_almost_equal(integration[1][0], -64, 0) assert peakpos[0][0] == 20 assert peakpos[1][0] == 20
def telid(self, val): # If tel id has changed delete camera if not self.__telid == val: self.camera_ax.cla() for ax in self.waveform_ax_list: ax.cla() self.camera = None self.__telid = val log.info('[plot] Switching telescope (telid={})'.format(self.telid)) self.waveform_view = self.waveform_view if not self.camera: pixel_pos = self.event.inst.pixel_pos[val] optical_foclen = self.event.inst.optical_foclen[val] if val not in self.geom_dict: self.geom = CameraGeometry.guess(*pixel_pos, optical_foclen) self.geom_dict[val] = self.geom else: self.geom = self.geom_dict[val] if self.calibrate and self.calib_params: windows = self.event.dl1.tel[val].integration_window[0] self.camera.integration_window = windows self.camera.update_window_visibility(True) else: self.camera.update_window_visibility(False) self.current_time = 0 self.setup_matplotlib_widgets() self._canvas.show() if self.tk_activated: self.update_tk_elements()
def get_parametrisation(self, shower, tel_data): Energy = shower.energy shower_dir = set_phi_theta_r(shower.az, 90.*u.deg+shower.alt, 1*u.dimless) shower_core = np.array([ shower.core_x/u.m, shower.core_y/u.m, 0. ]) *u.m shower_max_pos = shower_core - shower_dir * shower.h_shower_max / sin(shower.alt) for tel_id, photo_electrons in tel_data.items(): print("entering telescope {}".format(tel_id)) # if all telescopes until id are present, idx should be id-1, but to be sure tel_idx = np.searchsorted( self.telescopes['TelID'], tel_id ) # the position of the telescope in the local reference frame tel_pos = np.array([ self.telescopes['TelX'][tel_idx], self.telescopes['TelY'][tel_idx], self.telescopes['TelZ'][tel_idx] ]) * u.m # the direction the telescope is facing # TODO use actual telescope directions tel_dir = set_phi_theta_r(tel_phi, tel_theta, 1*u.dimless) d = length(shower_core - tel_pos) # TODO replace with actual pixel direction when they become available if tel_id not in self.pix_dirs: print("\tgenerating pixel directions for telescope {}".format(tel_id)) # doesn't seem to be right for camera types with 0 degree rotation... # use default value of -100.893 degrees in guessPixDirectionFocLength #camera_rotation = _guess_camera_type(len(self.cameras(tel_id)['PixX']), self.telescopes['FL'][tel_idx]*u.m)[4] geom = CameraGeometry.guess(self.cameras(tel_id)['PixX'].to(u.m), self.cameras(tel_id)['PixY'].to(u.m), self.telescopes['FL'][tel_idx] * u.m) self.pix_dirs[tel_id] = guessPixDirectionFocLength(geom.pix_x, geom.pix_y, tel_phi, tel_theta, self.telescopes['FL'][tel_idx] * u.m) print("\t... done") shower_max_dir = normalise(shower_max_pos-tel_pos) for pix_id, npe in enumerate( photo_electrons ): pixel_area = self.cameras(tel_id)['PixA'][pix_id] # the direction the pixel is looking in pixel_dir = self.pix_dirs[tel_id][pix_id] # angle between pixel direction and telescope diretion (for acceptance test) alpha = angle(pixel_dir, tel_dir) # angle between the pixel direction and the shower direction delta = angle(pixel_dir, shower_dir) # angle between the pixel direction and the direction to the shower maximum rho = angle(pixel_dir, shower_max_dir) # connecting vector between the pixel direction and the shower-max direction temp_dir = normalise(pixel_dir - shower_max_dir) # if the current pixel contains the shower-max direction, defining an angle makes little sense # put the info in the underflow bin gamma = angle(shower_dir - pixel_dir * shower_dir.dot(pixel_dir), # component of the shower direction perpendicular to the telescope direction temp_dir - pixel_dir * temp_dir.dot(pixel_dir)) # component of the connecting vector between pixel direction and # shower-max direction perpendicular to the telescope direction #print ([Energy, d, delta, shower.alt, rho, gamma], npe, pixel_area) #yield ([Energy, d, delta, shower.alt, rho, gamma], npe, pixel_area) #yield ([angle(tel_dir,shower_max_dir), d, delta, shower.alt, rho, gamma], npe, pixel_area) yield ([ alpha, d, rho, gamma], npe, pixel_area)
def integration_mc(event, telid, params, geom=None): """ Generic integrator for mc files. Calls the integrator_switch for actual integration. Subtracts the pedestal and applies the integration correction. Parameters ---------- event : container A `ctapipe` event container telid : int telescope id params : dict REQUIRED: params['integrator'] - Integration scheme params['integration_window'] - Integration window size and shift of integration window centre (adapted such that window fits into readout). OPTIONAL: params['integration_sigamp'] - Amplitude in ADC counts above pedestal at which a signal is considered as significant (separate for high gain/low gain). geom : `ctapipe.io.CameraGeometry` geometry of the camera's pixels. Leave as None for automatic calculation when it is required. Returns ------- charge : ndarray array of pixels with integrated charge [ADC counts] (pedestal substracted) integration_window : ndarray bool array of same shape as data. Specified which samples are included in the integration window data_ped : ndarray pedestal subtracted data peakpos : ndarray position of the peak as determined by the peak-finding algorithm for each pixel and channel """ # Obtain the data nsamples = event.dl0.tel[telid].num_samples data = np.array(list(event.dl0.tel[telid].adc_samples.values())) ped = event.dl0.tel[telid].pedestal data_ped = data - np.atleast_3d(ped/nsamples) int_dict, inverted = integrator_dict() if geom is None and inverted[params['integrator']]\ in integrators_requiring_geom(): log.debug("[calib] Guessing camera geometry") geom = CameraGeometry.guess(*event.meta.pixel_pos[telid], event.meta.optical_foclen[telid]) log.debug("[calib] Camera geometry found") # Integrate integration, integration_window, peakpos = \ integrator_switch(data_ped, geom, params) # Get the integration correction int_corr = set_integration_correction(event, telid, params) if peakpos[0] is None: int_corr = 1 # Convert integration into charge charge = np.round(integration * int_corr) return charge, integration_window, data_ped, peakpos
def integration_mc(event, telid, params, geom=None): """ Generic integrator for mc files. Calls the integrator_switch for actual integration. Subtracts the pedestal and applies the integration correction. Parameters ---------- event : container A `ctapipe` event container telid : int telescope id params : dict REQUIRED: params['integrator'] - Integration scheme params['integration_window'] - Integration window size and shift of integration window centre (adapted such that window fits into readout). OPTIONAL: params['integration_sigamp'] - Amplitude in ADC counts above pedestal at which a signal is considered as significant (separate for high gain/low gain). geom : `ctapipe.io.CameraGeometry` geometry of the camera's pixels. Leave as None for automatic calculation when it is required. Returns ------- charge : ndarray array of pixels with integrated charge [ADC counts] (pedestal substracted) integration_window : ndarray bool array of same shape as data. Specified which samples are included in the integration window data_ped : ndarray pedestal subtracted data peakpos : ndarray position of the peak as determined by the peak-finding algorithm for each pixel and channel """ # Obtain the data num_samples = event.inst.num_samples[telid] # KPK: addd this if statement since ASTRI data failed (only 1 # sample). Is that the correct way to fix it? if num_samples == 1: data = event.dl0.tel[telid].adc_sums data = data[:, :, np.newaxis] else: # TODO: the following line converts the structure into a 3D array where the third dimensions is the channel. Should we simply store it that way rathre than a dict by channel? (also this is not a fast operation) data = event.dl0.tel[telid].adc_samples ped = event.mc.tel[telid].pedestal # monte-carlo pedstal data_ped = data - np.atleast_3d(ped / num_samples) int_dict, inverted = integrator_dict() if geom is None and inverted[params['integrator']]\ in integrators_requiring_geom(): log.debug("[calib] Guessing camera geometry") geom = CameraGeometry.guess(*event.inst.pixel_pos[telid], event.inst.optical_foclen[telid]) log.debug("[calib] Camera geometry found") # Integrate integration, integration_window, peakpos = \ integrator_switch(data_ped, geom, params) # Get the integration correction int_corr = set_integration_correction(event, telid, params) if peakpos[0] is None: int_corr = 1 # Convert integration into charge charge = np.round(integration * int_corr) return charge, integration_window, data_ped, peakpos
def integration_mc(event, telid, params, geom=None): """ Generic integrator for mc files. Calls the integrator_switch for actual integration. Subtracts the pedestal and applies the integration correction. Parameters ---------- event : container A `ctapipe` event container telid : int telescope id params : dict REQUIRED: params['integrator'] - Integration scheme params['window'] - Integration window size params['shift'] - Starting sample for this integration (adapted such that window fits into readout). OPTIONAL: params['sigamp'] - Amplitude in ADC counts above pedestal at which a signal is considered as significant (separate for high gain/low gain). geom : `ctapipe.io.CameraGeometry` geometry of the camera's pixels. Leave as None for automatic calculation when it is required. Returns ------- charge : ndarray array of pixels with integrated charge [ADC counts] (pedestal substracted) integration_window : ndarray bool array of same shape as data. Specified which samples are included in the integration window data_ped : ndarray pedestal subtracted data peakpos : ndarray position of the peak as determined by the peak-finding algorithm for each pixel and channel """ # Obtain the data nsamples = event.dl0.tel[telid].num_samples data = np.array(list(event.dl0.tel[telid].adc_samples.values())) ped = event.dl0.tel[telid].pedestal data_ped = data - np.atleast_3d(ped/nsamples) int_dict, inverted = integrator_dict() if geom is None and inverted[params['integrator']] in \ integrators_requiring_geom(): log.debug("[calib] Guessing camera geometry") geom = CameraGeometry.guess(*event.meta.pixel_pos[telid], event.meta.optical_foclen[telid]) log.debug("[calib] Camera geometry found") # Integrate integration, integration_window, peakpos = \ integrator_switch(data_ped, geom, params) # Get the integration correction int_corr = set_integration_correction(event, telid, params) if peakpos[0] is None: int_corr = 1 # Convert integration into charge charge = np.round(integration * int_corr) return charge, integration_window, data_ped, peakpos
def calibrate_event(event, params, geom_dict=None): """ Generic calibrator for events. Calls the calibrator corresponding to the source of the event, and stores the dl1 (calibrated_image) information into a new event container. Parameters ---------- event : container A `ctapipe` event container params : dict REQUIRED: params['integrator'] - Integration scheme params['integration_window'] - Integration window size and shift of integration window centre (adapted such that window fits into readout). OPTIONAL: params['integration_clip_amp'] - Amplitude in p.e. above which the signal is clipped. params['integration_calib_scale'] : Identical to global variable CALIB_SCALE in reconstruct.c in hessioxxx software package. 0.92 is the default value (corresponds to HESS). The required value changes between cameras (GCT = 1.05). params['integration_sigamp'] - Amplitude in ADC counts above pedestal at which a signal is considered as significant (separate for high gain/low gain). geom_dict : dict Dict of pixel geometry for each telescope. Leave as None for automatic calculation when it is required. dict[(num_pixels, focal_length)] = `ctapipe.io.CameraGeometry` Returns ------- calibrated : container A new `ctapipe` event container containing the dl1 information, and a reference to all other information contained in the original event container. """ # Obtain relevent calibrator switch = {'hessio': partial(mc.calibrate_mc, event=event, params=params)} try: calibrator = switch[event.meta['source']] except KeyError: log.exception("no calibration created for data origin: '{}'".format( event.meta['source'])) raise # KPK: should not copy the event here! there is no reason to # Copying is # up to the user if they want to do it, not in the algorithms. # calibrated = copy(event) # params stored in metadata event.dl1.meta.update(params) # Fill dl1 event.dl1.reset() for telid in event.dl0.tels_with_data: nchan = event.inst.num_channels[telid] npix = event.inst.num_pixels[telid] event.dl1.tel[telid] = CalibratedCameraContainer() # Get geometry int_dict, inverted = integrator_dict() geom = None # Check if geom is even needed for integrator if inverted[params['integrator']] in integrators_requiring_geom(): if geom_dict is not None and telid in geom_dict: geom = geom_dict[telid] else: log.debug("[calib] Guessing camera geometry") geom = CameraGeometry.guess(*event.inst.pixel_pos[telid], event.inst.optical_foclen[telid]) log.debug("[calib] Camera geometry found") if geom_dict is not None: geom_dict[telid] = geom pe, window, data_ped, peakpos = calibrator(telid=telid, geom=geom) tel = event.dl1.tel[telid] tel.calibrated_image = pe tel.peakpos = peakpos for chan in range(nchan): tel.integration_window[chan] = window[chan] tel.pedestal_subtracted_adc[chan] = data_ped[chan] return event
def get_geometry(self, event, telid): if telid not in self._geom_dict: geom = CameraGeometry.guess(*event.inst.pixel_pos[telid], event.inst.optical_foclen[telid]) self._geom_dict[telid] = geom return self._geom_dict[telid]
def calibrate_event(event, params, geom_dict=None): """ Generic calibrator for events. Calls the calibrator corresponding to the source of the event, and stores the dl1 (calibrated_image) information into a new event container. Parameters ---------- event : container A `ctapipe` event container params : dict REQUIRED: params['integrator'] - Integration scheme params['integration_window'] - Integration window size and shift of integration window centre (adapted such that window fits into readout). OPTIONAL: params['integration_clip_amp'] - Amplitude in p.e. above which the signal is clipped. params['integration_calib_scale'] : Identical to global variable CALIB_SCALE in reconstruct.c in hessioxxx software package. 0.92 is the default value (corresponds to HESS). The required value changes between cameras (GCT = 1.05). params['integration_sigamp'] - Amplitude in ADC counts above pedestal at which a signal is considered as significant (separate for high gain/low gain). geom_dict : dict Dict of pixel geometry for each telescope. Leave as None for automatic calculation when it is required. dict[(num_pixels, focal_length)] = `ctapipe.io.CameraGeometry` Returns ------- calibrated : container A new `ctapipe` event container containing the dl1 information, and a reference to all other information contained in the original event container. """ # Obtain relevent calibrator switch = { 'hessio': partial(mc.calibrate_mc, event=event, params=params) } try: calibrator = switch[event.meta['source']] except KeyError: log.exception("no calibration created for data origin: '{}'" .format(event.meta['source'])) raise # KPK: should not copy the event here! there is no reason to # Copying is # up to the user if they want to do it, not in the algorithms. # calibrated = copy(event) # params stored in metadata event.dl1.meta.update(params) # Fill dl1 event.dl1.reset() for telid in event.dl0.tels_with_data: nchan = event.inst.num_channels[telid] npix = event.inst.num_pixels[telid] event.dl1.tel[telid] = CalibratedCameraContainer() # Get geometry int_dict, inverted = integrator_dict() geom = None # Check if geom is even needed for integrator if inverted[params['integrator']] in integrators_requiring_geom(): if geom_dict is not None and telid in geom_dict: geom = geom_dict[telid] else: log.debug("[calib] Guessing camera geometry") geom = CameraGeometry.guess(*event.inst.pixel_pos[telid], event.inst.optical_foclen[telid]) log.debug("[calib] Camera geometry found") if geom_dict is not None: geom_dict[telid] = geom pe, window, data_ped, peakpos = calibrator(telid=telid, geom=geom) tel = event.dl1.tel[telid] tel.calibrated_image = pe tel.peakpos = peakpos for chan in range(nchan): tel.integration_window[chan] = window[chan] tel.pedestal_subtracted_adc[chan] = data_ped[chan] return event
def plot(self, input_file, event, telid, chan, extractor_name, nei): # Extract required images dl0 = event.dl0.tel[telid].adc_samples[chan] t_pe = event.mc.tel[telid].photo_electron_image dl1 = event.dl1.tel[telid].image[chan] max_time = np.unravel_index(np.argmax(dl0), dl0.shape)[1] max_charges = np.max(dl0, axis=1) max_pix = int(np.argmax(max_charges)) min_pix = int(np.argmin(max_charges)) geom = CameraGeometry.guess(*event.inst.pixel_pos[telid], event.inst.optical_foclen[telid]) # Get Neighbours max_pixel_nei = nei[max_pix] min_pixel_nei = nei[min_pix] # Get Windows windows = event.dl1.tel[telid].extracted_samples[chan] length = np.sum(windows, axis=1) start = np.argmax(windows, axis=1) end = start + length # Draw figures ax_max_nei = {} ax_min_nei = {} fig_waveforms = plt.figure(figsize=(18, 9)) fig_waveforms.subplots_adjust(hspace=.5) fig_camera = plt.figure(figsize=(15, 12)) ax_max_pix = fig_waveforms.add_subplot(4, 2, 1) ax_min_pix = fig_waveforms.add_subplot(4, 2, 2) ax_max_nei[0] = fig_waveforms.add_subplot(4, 2, 3) ax_min_nei[0] = fig_waveforms.add_subplot(4, 2, 4) ax_max_nei[1] = fig_waveforms.add_subplot(4, 2, 5) ax_min_nei[1] = fig_waveforms.add_subplot(4, 2, 6) ax_max_nei[2] = fig_waveforms.add_subplot(4, 2, 7) ax_min_nei[2] = fig_waveforms.add_subplot(4, 2, 8) ax_img_nei = fig_camera.add_subplot(2, 2, 1) ax_img_max = fig_camera.add_subplot(2, 2, 2) ax_img_true = fig_camera.add_subplot(2, 2, 3) ax_img_cal = fig_camera.add_subplot(2, 2, 4) # Draw max pixel traces ax_max_pix.plot(dl0[max_pix]) ax_max_pix.set_xlabel("Time (ns)") ax_max_pix.set_ylabel("DL0 Samples (ADC)") ax_max_pix.set_title( "(Max) Pixel: {}, True: {}, Measured = {:.3f}".format( max_pix, t_pe[max_pix], dl1[max_pix])) max_ylim = ax_max_pix.get_ylim() ax_max_pix.plot([start[max_pix], start[max_pix]], ax_max_pix.get_ylim(), color='r', alpha=1) ax_max_pix.plot([end[max_pix], end[max_pix]], ax_max_pix.get_ylim(), color='r', alpha=1) for i, ax in ax_max_nei.items(): if len(max_pixel_nei) > i: pix = max_pixel_nei[i] ax.plot(dl0[pix]) ax.set_xlabel("Time (ns)") ax.set_ylabel("DL0 Samples (ADC)") ax.set_title( "(Max Nei) Pixel: {}, True: {}, Measured = {:.3f}".format( pix, t_pe[pix], dl1[pix])) ax.set_ylim(max_ylim) ax.plot([start[pix], start[pix]], ax.get_ylim(), color='r', alpha=1) ax.plot([end[pix], end[pix]], ax.get_ylim(), color='r', alpha=1) # Draw min pixel traces ax_min_pix.plot(dl0[min_pix]) ax_min_pix.set_xlabel("Time (ns)") ax_min_pix.set_ylabel("DL0 Samples (ADC)") ax_min_pix.set_title( "(Min) Pixel: {}, True: {}, Measured = {:.3f}".format( min_pix, t_pe[min_pix], dl1[min_pix])) ax_min_pix.set_ylim(max_ylim) ax_min_pix.plot([start[min_pix], start[min_pix]], ax_min_pix.get_ylim(), color='r', alpha=1) ax_min_pix.plot([end[min_pix], end[min_pix]], ax_min_pix.get_ylim(), color='r', alpha=1) for i, ax in ax_min_nei.items(): if len(min_pixel_nei) > i: pix = min_pixel_nei[i] ax.plot(dl0[pix]) ax.set_xlabel("Time (ns)") ax.set_ylabel("DL0 Samples (ADC)") ax.set_title( "(Min Nei) Pixel: {}, True: {}, Measured = {:.3f}".format( pix, t_pe[pix], dl1[pix])) ax.set_ylim(max_ylim) ax.plot([start[pix], start[pix]], ax.get_ylim(), color='r', alpha=1) ax.plot([end[pix], end[pix]], ax.get_ylim(), color='r', alpha=1) # Draw cameras nei_camera = np.zeros_like(max_charges, dtype=np.int) nei_camera[min_pixel_nei] = 2 nei_camera[min_pix] = 1 nei_camera[max_pixel_nei] = 3 nei_camera[max_pix] = 4 camera = CameraDisplay(geom, ax=ax_img_nei) camera.image = nei_camera camera.cmap = plt.cm.viridis ax_img_nei.set_title("Neighbour Map") ax_img_nei.annotate("Pixel: {}".format(max_pix), xy=(geom.pix_x.value[max_pix], geom.pix_y.value[max_pix]), xycoords='data', xytext=(0.05, 0.98), textcoords='axes fraction', arrowprops=dict(facecolor='red', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') ax_img_nei.annotate("Pixel: {}".format(min_pix), xy=(geom.pix_x.value[min_pix], geom.pix_y.value[min_pix]), xycoords='data', xytext=(0.05, 0.94), textcoords='axes fraction', arrowprops=dict(facecolor='orange', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') camera = CameraDisplay(geom, ax=ax_img_max) camera.image = dl0[:, max_time] camera.cmap = plt.cm.viridis camera.add_colorbar(ax=ax_img_max, label="DL0 Samples (ADC)") ax_img_max.set_title("Max Timeslice (T = {})".format(max_time)) ax_img_max.annotate("Pixel: {}".format(max_pix), xy=(geom.pix_x.value[max_pix], geom.pix_y.value[max_pix]), xycoords='data', xytext=(0.05, 0.98), textcoords='axes fraction', arrowprops=dict(facecolor='red', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') ax_img_max.annotate("Pixel: {}".format(min_pix), xy=(geom.pix_x.value[min_pix], geom.pix_y.value[min_pix]), xycoords='data', xytext=(0.05, 0.94), textcoords='axes fraction', arrowprops=dict(facecolor='orange', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') camera = CameraDisplay(geom, ax=ax_img_true) camera.image = t_pe camera.cmap = plt.cm.viridis camera.add_colorbar(ax=ax_img_true, label="True Charge (p.e.)") ax_img_true.set_title("True Charge") ax_img_true.annotate("Pixel: {}".format(max_pix), xy=(geom.pix_x.value[max_pix], geom.pix_y.value[max_pix]), xycoords='data', xytext=(0.05, 0.98), textcoords='axes fraction', arrowprops=dict(facecolor='red', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') ax_img_true.annotate("Pixel: {}".format(min_pix), xy=(geom.pix_x.value[min_pix], geom.pix_y.value[min_pix]), xycoords='data', xytext=(0.05, 0.94), textcoords='axes fraction', arrowprops=dict(facecolor='orange', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') camera = CameraDisplay(geom, ax=ax_img_cal) camera.image = dl1 camera.cmap = plt.cm.viridis camera.add_colorbar(ax=ax_img_cal, label="Calib Charge (Photo-electrons)") ax_img_cal.set_title("Charge (integrator={})".format(extractor_name)) ax_img_cal.annotate("Pixel: {}".format(max_pix), xy=(geom.pix_x.value[max_pix], geom.pix_y.value[max_pix]), xycoords='data', xytext=(0.05, 0.98), textcoords='axes fraction', arrowprops=dict(facecolor='red', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') ax_img_cal.annotate("Pixel: {}".format(min_pix), xy=(geom.pix_x.value[min_pix], geom.pix_y.value[min_pix]), xycoords='data', xytext=(0.05, 0.94), textcoords='axes fraction', arrowprops=dict(facecolor='orange', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') fig_waveforms.suptitle("Integrator = {}".format(extractor_name)) fig_camera.suptitle("Camera = {}".format(geom.cam_id)) waveform_output_name = "e{}_t{}_c{}_extractor{}_waveform.pdf"\ .format(event.count, telid, chan, extractor_name) camera_output_name = "e{}_t{}_c{}_extractor{}_camera.pdf"\ .format(event.count, telid, chan, extractor_name) output_dir = self.output_dir if output_dir is None: output_dir = input_file.output_directory output_dir = os.path.join(output_dir, self.name) if not os.path.exists(output_dir): self.log.info("Creating directory: {}".format(output_dir)) os.makedirs(output_dir) waveform_output_path = os.path.join(output_dir, waveform_output_name) self.log.info("Saving: {}".format(waveform_output_path)) fig_waveforms.savefig(waveform_output_path, format='pdf', bbox_inches='tight') camera_output_path = os.path.join(output_dir, camera_output_name) self.log.info("Saving: {}".format(camera_output_path)) fig_camera.savefig(camera_output_path, format='pdf', bbox_inches='tight')
def main(): script = os.path.splitext(os.path.basename(__file__))[0] log.info("[SCRIPT] {}".format(script)) parser = argparse.ArgumentParser(description='Create a gif of an event') parser.add_argument('-f', '--file', dest='input_path', action='store', required=True, help='path to the input file') parser.add_argument('-O', '--origin', dest='origin', action='store', required=True, help='origin of the file: {}' .format(origin_list())) parser.add_argument('-o', '--output', dest='output_dir', action='store', default=None, help='path of the output directory to store the ' 'images (default = input file directory)') parser.add_argument('-e', '--event', dest='event_req', action='store', required=True, type=int, help='event index to plot (not id!)') parser.add_argument('--id', dest='event_id_f', action='store_true', default=False, help='-e will specify event_id instead ' 'of index') parser.add_argument('-t', '--telescope', dest='tel', action='store', type=int, default=None, help='telecope to view') parser.add_argument('-c', '--channel', dest='chan', action='store', type=int, default=0, help='channel to view (default = 0 (HG))') calibration_arguments(parser) logger_detail = parser.add_mutually_exclusive_group() logger_detail.add_argument('-q', '--quiet', dest='quiet', action='store_true', default=False, help='Quiet mode') logger_detail.add_argument('-v', '--verbose', dest='verbose', action='store_true', default=False, help='Verbose mode') logger_detail.add_argument('-d', '--debug', dest='debug', action='store_true', default=False, help='Debug mode') args = parser.parse_args() if args.quiet: log.setLevel(40) if args.verbose: log.setLevel(20) if args.debug: log.setLevel(10) telid = args.tel chan = args.chan log.debug("[file] Reading file") input_file = InputFile(args.input_path, args.origin) event = input_file.get_event(args.event_req, args.event_id_f) # Print event/args values log.info("[event_index] {}".format(event.count)) log.info("[event_id] {}".format(event.dl0.event_id)) log.info("[telescope] {}".format(telid)) log.info("[channel] {}".format(chan)) params = calibration_parameters(args) # Create a dictionary to store any geoms in geom = CameraGeometry.guess(*event.meta.pixel_pos[telid], event.meta.optical_foclen[telid]) geom_dict = {telid: geom} calibrated_event = calibrate_event(event, params, geom_dict) # Select telescope tels = list(calibrated_event.dl0.tels_with_data) if telid is None or telid not in tels: log.error("[event] please specify one of the following telescopes " "for this event: {}".format(tels)) exit() # Extract required images data_ped = calibrated_event.dl1.tel[telid].pedestal_subtracted_adc[chan] true_pe = calibrated_event.mc.tel[telid].photo_electrons measured_pe = calibrated_event.dl1.tel[telid].pe_charge max_time = np.unravel_index(np.argmax(data_ped), data_ped.shape)[1] max_charges = np.max(data_ped, axis=1) max_pixel = int(np.argmax(max_charges)) min_pixel = int(np.argmin(max_charges)) # Get Neighbours max_pixel_nei = geom.neighbors[max_pixel] min_pixel_nei = geom.neighbors[min_pixel] # Get Windows windows = calibrated_event.dl1.tel[telid].integration_window[chan] length = np.sum(windows, axis=1) start = np.argmax(windows, axis=1) end = start + length - 1 # Draw figures ax_max_nei = {} ax_min_nei = {} fig_waveforms = plt.figure(figsize=(24, 10)) fig_waveforms.subplots_adjust(hspace=.5) fig_camera = plt.figure(figsize=(30, 24)) ax_max_pix = fig_waveforms.add_subplot(4, 2, 1) ax_min_pix = fig_waveforms.add_subplot(4, 2, 2) ax_max_nei[0] = fig_waveforms.add_subplot(4, 2, 3) ax_min_nei[0] = fig_waveforms.add_subplot(4, 2, 4) ax_max_nei[1] = fig_waveforms.add_subplot(4, 2, 5) ax_min_nei[1] = fig_waveforms.add_subplot(4, 2, 6) ax_max_nei[2] = fig_waveforms.add_subplot(4, 2, 7) ax_min_nei[2] = fig_waveforms.add_subplot(4, 2, 8) ax_img_nei = fig_camera.add_subplot(2, 2, 1) ax_img_max = fig_camera.add_subplot(2, 2, 2) ax_img_true = fig_camera.add_subplot(2, 2, 3) ax_img_cal = fig_camera.add_subplot(2, 2, 4) plotter = CameraPlotter(event, geom_dict) # Draw max pixel traces plotter.draw_waveform(data_ped[max_pixel], ax_max_pix) ax_max_pix.set_title("(Max) Pixel: {}, " "True: {}, " "Measured = {}".format(max_pixel, true_pe[max_pixel], measured_pe[max_pixel])) ax_max_pix.set_ylabel("Amplitude-Ped (ADC)") max_ylim = ax_max_pix.get_ylim() plotter.draw_waveform_positionline(start[max_pixel], ax_max_pix) plotter.draw_waveform_positionline(end[max_pixel], ax_max_pix) for i, ax in ax_max_nei.items(): if len(max_pixel_nei) > i: pix = max_pixel_nei[i] plotter.draw_waveform(data_ped[pix], ax) ax.set_title("(Max Nei) Pixel: {}, " "True: {}, " "Measured = {}".format(pix, true_pe[pix], measured_pe[pix])) ax.set_ylabel("Amplitude-Ped (ADC)") ax.set_ylim(max_ylim) plotter.draw_waveform_positionline(start[pix], ax) plotter.draw_waveform_positionline(end[pix], ax) # Draw min pixel traces plotter.draw_waveform(data_ped[min_pixel], ax_min_pix) ax_min_pix.set_title("(Min) Pixel: {}, " "True: {}, " "Measured = {}".format(min_pixel, true_pe[min_pixel], measured_pe[min_pixel])) ax_min_pix.set_ylabel("Amplitude-Ped (ADC)") ax_min_pix.set_ylim(max_ylim) plotter.draw_waveform_positionline(start[min_pixel], ax_min_pix) plotter.draw_waveform_positionline(end[min_pixel], ax_min_pix) for i, ax in ax_min_nei.items(): if len(min_pixel_nei) > i: pix = min_pixel_nei[i] plotter.draw_waveform(data_ped[pix], ax) ax.set_title("(Min Nei) Pixel: {}, " "True: {}, " "Measured = {}".format(pix, true_pe[pix], measured_pe[pix])) ax.set_ylabel("Amplitude-Ped (ADC)") ax.set_ylim(max_ylim) plotter.draw_waveform_positionline(start[pix], ax) plotter.draw_waveform_positionline(end[pix], ax) # Draw cameras nei_camera = np.zeros_like(max_charges, dtype=np.int) nei_camera[min_pixel_nei] = 2 nei_camera[min_pixel] = 1 nei_camera[max_pixel_nei] = 3 nei_camera[max_pixel] = 4 camera = plotter.draw_camera(telid, nei_camera, ax_img_nei) camera.cmap = plt.cm.viridis ax_img_nei.set_title("Neighbour Map") plotter.draw_camera_pixel_annotation(telid, max_pixel, min_pixel, ax_img_nei) camera = plotter.draw_camera(telid, data_ped[:, max_time], ax_img_max) camera.add_colorbar(ax=ax_img_max, label="Amplitude-Ped (ADC)") ax_img_max.set_title("Max Timeslice (T = {})".format(max_time)) plotter.draw_camera_pixel_annotation(telid, max_pixel, min_pixel, ax_img_max) camera = plotter.draw_camera(telid, true_pe, ax_img_true) camera.add_colorbar(ax=ax_img_true, label="True Charge (Photo-electrons)") ax_img_true.set_title("True Charge") plotter.draw_camera_pixel_annotation(telid, max_pixel, min_pixel, ax_img_true) camera = plotter.draw_camera(telid, measured_pe, ax_img_cal) camera.add_colorbar(ax=ax_img_cal, label="Calib Charge (Photo-electrons)") ax_img_cal.set_title("Charge (integrator={})".format(params['integrator'])) plotter.draw_camera_pixel_annotation(telid, max_pixel, min_pixel, ax_img_cal) fig_waveforms.suptitle("Integrator = {}".format(params['integrator'])) fig_camera.suptitle("Camera = {}".format(geom.cam_id)) # TODO: another figure of all waveforms that have non-zero true charge waveform_output_name = "{}_e{}_t{}_c{}_integrator{}_waveform.pdf"\ .format(input_file.filename, event.count, telid, chan, args.integrator) camera_output_name = "{}_e{}_t{}_c{}_integrator{}_camera.pdf"\ .format(input_file.filename, event.count, telid, chan, args.integrator) output_dir = args.output_dir if args.output_dir is not None else \ input_file.output_directory output_dir = os.path.join(output_dir, script) if not os.path.exists(output_dir): log.info("[output] Creating directory: {}".format(output_dir)) os.makedirs(output_dir) waveform_output_path = os.path.join(output_dir, waveform_output_name) log.info("[output] {}".format(waveform_output_path)) fig_waveforms.savefig(waveform_output_path, format='pdf') camera_output_path = os.path.join(output_dir, camera_output_name) log.info("[output] {}".format(camera_output_path)) fig_camera.savefig(camera_output_path, format='pdf') log.info("[COMPLETE]")
def plot(self, input_file, event, telid, chan, extractor_name, nei): # Extract required images dl0 = event.dl0.tel[telid].adc_samples[chan] t_pe = event.mc.tel[telid].photo_electron_image dl1 = event.dl1.tel[telid].image[chan] max_time = np.unravel_index(np.argmax(dl0), dl0.shape)[1] max_charges = np.max(dl0, axis=1) max_pix = int(np.argmax(max_charges)) min_pix = int(np.argmin(max_charges)) geom = CameraGeometry.guess(*event.inst.pixel_pos[telid], event.inst.optical_foclen[telid]) # Get Neighbours max_pixel_nei = nei[max_pix] min_pixel_nei = nei[min_pix] # Get Windows windows = event.dl1.tel[telid].extracted_samples[chan] length = np.sum(windows, axis=1) start = np.argmax(windows, axis=1) end = start + length # Draw figures ax_max_nei = {} ax_min_nei = {} fig_waveforms = plt.figure(figsize=(18, 9)) fig_waveforms.subplots_adjust(hspace=.5) fig_camera = plt.figure(figsize=(15, 12)) ax_max_pix = fig_waveforms.add_subplot(4, 2, 1) ax_min_pix = fig_waveforms.add_subplot(4, 2, 2) ax_max_nei[0] = fig_waveforms.add_subplot(4, 2, 3) ax_min_nei[0] = fig_waveforms.add_subplot(4, 2, 4) ax_max_nei[1] = fig_waveforms.add_subplot(4, 2, 5) ax_min_nei[1] = fig_waveforms.add_subplot(4, 2, 6) ax_max_nei[2] = fig_waveforms.add_subplot(4, 2, 7) ax_min_nei[2] = fig_waveforms.add_subplot(4, 2, 8) ax_img_nei = fig_camera.add_subplot(2, 2, 1) ax_img_max = fig_camera.add_subplot(2, 2, 2) ax_img_true = fig_camera.add_subplot(2, 2, 3) ax_img_cal = fig_camera.add_subplot(2, 2, 4) # Draw max pixel traces ax_max_pix.plot(dl0[max_pix]) ax_max_pix.set_xlabel("Time (ns)") ax_max_pix.set_ylabel("DL0 Samples (ADC)") ax_max_pix.set_title("(Max) Pixel: {}, True: {}, Measured = {:.3f}" .format(max_pix, t_pe[max_pix], dl1[max_pix])) max_ylim = ax_max_pix.get_ylim() ax_max_pix.plot([start[max_pix], start[max_pix]], ax_max_pix.get_ylim(), color='r', alpha=1) ax_max_pix.plot([end[max_pix], end[max_pix]], ax_max_pix.get_ylim(), color='r', alpha=1) for i, ax in ax_max_nei.items(): if len(max_pixel_nei) > i: pix = max_pixel_nei[i] ax.plot(dl0[pix]) ax.set_xlabel("Time (ns)") ax.set_ylabel("DL0 Samples (ADC)") ax.set_title("(Max Nei) Pixel: {}, True: {}, Measured = {:.3f}" .format(pix, t_pe[pix], dl1[pix])) ax.set_ylim(max_ylim) ax.plot([start[pix], start[pix]], ax.get_ylim(), color='r', alpha=1) ax.plot([end[pix], end[pix]], ax.get_ylim(), color='r', alpha=1) # Draw min pixel traces ax_min_pix.plot(dl0[min_pix]) ax_min_pix.set_xlabel("Time (ns)") ax_min_pix.set_ylabel("DL0 Samples (ADC)") ax_min_pix.set_title("(Min) Pixel: {}, True: {}, Measured = {:.3f}" .format(min_pix, t_pe[min_pix], dl1[min_pix])) ax_min_pix.set_ylim(max_ylim) ax_min_pix.plot([start[min_pix], start[min_pix]], ax_min_pix.get_ylim(), color='r', alpha=1) ax_min_pix.plot([end[min_pix], end[min_pix]], ax_min_pix.get_ylim(), color='r', alpha=1) for i, ax in ax_min_nei.items(): if len(min_pixel_nei) > i: pix = min_pixel_nei[i] ax.plot(dl0[pix]) ax.set_xlabel("Time (ns)") ax.set_ylabel("DL0 Samples (ADC)") ax.set_title("(Min Nei) Pixel: {}, True: {}, Measured = {:.3f}" .format(pix, t_pe[pix], dl1[pix])) ax.set_ylim(max_ylim) ax.plot([start[pix], start[pix]], ax.get_ylim(), color='r', alpha=1) ax.plot([end[pix], end[pix]], ax.get_ylim(), color='r', alpha=1) # Draw cameras nei_camera = np.zeros_like(max_charges, dtype=np.int) nei_camera[min_pixel_nei] = 2 nei_camera[min_pix] = 1 nei_camera[max_pixel_nei] = 3 nei_camera[max_pix] = 4 camera = CameraDisplay(geom, ax=ax_img_nei) camera.image = nei_camera camera.cmap = plt.cm.viridis ax_img_nei.set_title("Neighbour Map") ax_img_nei.annotate("Pixel: {}".format(max_pix), xy=(geom.pix_x.value[max_pix], geom.pix_y.value[max_pix]), xycoords='data', xytext=(0.05, 0.98), textcoords='axes fraction', arrowprops=dict(facecolor='red', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') ax_img_nei.annotate("Pixel: {}".format(min_pix), xy=(geom.pix_x.value[min_pix], geom.pix_y.value[min_pix]), xycoords='data', xytext=(0.05, 0.94), textcoords='axes fraction', arrowprops=dict(facecolor='orange', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') camera = CameraDisplay(geom, ax=ax_img_max) camera.image = dl0[:, max_time] camera.cmap = plt.cm.viridis camera.add_colorbar(ax=ax_img_max, label="DL0 Samples (ADC)") ax_img_max.set_title("Max Timeslice (T = {})".format(max_time)) ax_img_max.annotate("Pixel: {}".format(max_pix), xy=(geom.pix_x.value[max_pix], geom.pix_y.value[max_pix]), xycoords='data', xytext=(0.05, 0.98), textcoords='axes fraction', arrowprops=dict(facecolor='red', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') ax_img_max.annotate("Pixel: {}".format(min_pix), xy=(geom.pix_x.value[min_pix], geom.pix_y.value[min_pix]), xycoords='data', xytext=(0.05, 0.94), textcoords='axes fraction', arrowprops=dict(facecolor='orange', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') camera = CameraDisplay(geom, ax=ax_img_true) camera.image = t_pe camera.cmap = plt.cm.viridis camera.add_colorbar(ax=ax_img_true, label="True Charge (p.e.)") ax_img_true.set_title("True Charge") ax_img_true.annotate("Pixel: {}".format(max_pix), xy=(geom.pix_x.value[max_pix], geom.pix_y.value[max_pix]), xycoords='data', xytext=(0.05, 0.98), textcoords='axes fraction', arrowprops=dict(facecolor='red', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') ax_img_true.annotate("Pixel: {}".format(min_pix), xy=(geom.pix_x.value[min_pix], geom.pix_y.value[min_pix]), xycoords='data', xytext=(0.05, 0.94), textcoords='axes fraction', arrowprops=dict(facecolor='orange', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') camera = CameraDisplay(geom, ax=ax_img_cal) camera.image = dl1 camera.cmap = plt.cm.viridis camera.add_colorbar(ax=ax_img_cal, label="Calib Charge (Photo-electrons)") ax_img_cal.set_title("Charge (integrator={})".format(extractor_name)) ax_img_cal.annotate("Pixel: {}".format(max_pix), xy=(geom.pix_x.value[max_pix], geom.pix_y.value[max_pix]), xycoords='data', xytext=(0.05, 0.98), textcoords='axes fraction', arrowprops=dict(facecolor='red', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') ax_img_cal.annotate("Pixel: {}".format(min_pix), xy=(geom.pix_x.value[min_pix], geom.pix_y.value[min_pix]), xycoords='data', xytext=(0.05, 0.94), textcoords='axes fraction', arrowprops=dict(facecolor='orange', width=2, alpha=0.4), horizontalalignment='left', verticalalignment='top') fig_waveforms.suptitle("Integrator = {}".format(extractor_name)) fig_camera.suptitle("Camera = {}".format(geom.cam_id)) waveform_output_name = "e{}_t{}_c{}_extractor{}_waveform.pdf"\ .format(event.count, telid, chan, extractor_name) camera_output_name = "e{}_t{}_c{}_extractor{}_camera.pdf"\ .format(event.count, telid, chan, extractor_name) output_dir = self.output_dir if output_dir is None: output_dir = input_file.output_directory output_dir = os.path.join(output_dir, self.name) if not os.path.exists(output_dir): self.log.info("Creating directory: {}".format(output_dir)) os.makedirs(output_dir) waveform_output_path = os.path.join(output_dir, waveform_output_name) self.log.info("Saving: {}".format(waveform_output_path)) fig_waveforms.savefig(waveform_output_path, format='pdf', bbox_inches='tight') camera_output_path = os.path.join(output_dir, camera_output_name) self.log.info("Saving: {}".format(camera_output_path)) fig_camera.savefig(camera_output_path, format='pdf', bbox_inches='tight')
def main(): script = os.path.splitext(os.path.basename(__file__))[0] log.info("[SCRIPT] {}".format(script)) parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('-f', '--file', dest='input_path', action='store', default=get_path('gamma_test.simtel.gz'), help='path to the input file') parser.add_argument('-O', '--origin', dest='origin', action='store', choices=InputFile.origin_list(), default='hessio', help='origin of the file') parser.add_argument('-o', '--output', dest='output_dir', action='store', default=None, help='path of the output directory to store the ' 'images (default = input file directory)') parser.add_argument('-e', '--event', dest='event_req', action='store', default=0, type=int, help='event index to plot (not id!)') parser.add_argument('--id', dest='event_id_f', action='store_true', default=False, help='-e will specify event_id instead ' 'of index') parser.add_argument('-t', '--telescope', dest='tel', action='store', type=int, default=None, help='telecope to view') parser.add_argument('-c', '--channel', dest='chan', action='store', type=int, default=0, help='channel to view (default = 0 (HG))') parser.add_argument('--calib-help', dest='calib_help', action='store_true', default=False, help='display the arguments used for the camera ' 'calibration') logger_detail = parser.add_mutually_exclusive_group() logger_detail.add_argument('-q', '--quiet', dest='quiet', action='store_true', default=False, help='Quiet mode') logger_detail.add_argument('-v', '--verbose', dest='verbose', action='store_true', default=False, help='Verbose mode') logger_detail.add_argument('-d', '--debug', dest='debug', action='store_true', default=False, help='Debug mode') args, excess_args = parser.parse_known_args() if args.quiet: log.setLevel(40) if args.verbose: log.setLevel(20) if args.debug: log.setLevel(10) telid = args.tel chan = args.chan log.debug("[file] Reading file") input_file = InputFile(args.input_path, args.origin) event = input_file.get_event(args.event_req, args.event_id_f) # Print event/args values log.info("[event_index] {}".format(event.count)) log.info("[event_id] {}".format(event.dl0.event_id)) log.info("[telescope] {}".format(telid)) log.info("[channel] {}".format(chan)) params, unknown_args = calibration_parameters(excess_args, args.origin, args.calib_help) if unknown_args: parser.print_help() calibration_parameters(unknown_args, args.origin, True) msg = 'unrecognized arguments: %s' parser.error(msg % ' '.join(unknown_args)) # Create a dictionary to store any geoms in geom = CameraGeometry.guess(*event.meta.pixel_pos[telid], event.meta.optical_foclen[telid]) geom_dict = {telid: geom} calibrated_event = calibrate_event(event, params, geom_dict) # Select telescope tels = list(calibrated_event.dl0.tels_with_data) if telid is None or telid not in tels: log.error("[event] please specify one of the following telescopes " "for this event: {}".format(tels)) exit() # Extract required images data_ped = calibrated_event.dl1.tel[telid].pedestal_subtracted_adc[chan] true_pe = calibrated_event.mc.tel[telid].photo_electrons measured_pe = calibrated_event.dl1.tel[telid].pe_charge max_time = np.unravel_index(np.argmax(data_ped), data_ped.shape)[1] max_charges = np.max(data_ped, axis=1) max_pixel = int(np.argmax(max_charges)) min_pixel = int(np.argmin(max_charges)) # Get Neighbours max_pixel_nei = geom.neighbors[max_pixel] min_pixel_nei = geom.neighbors[min_pixel] # Get Windows windows = calibrated_event.dl1.tel[telid].integration_window[chan] length = np.sum(windows, axis=1) start = np.argmax(windows, axis=1) end = start + length - 1 # Draw figures ax_max_nei = {} ax_min_nei = {} fig_waveforms = plt.figure(figsize=(18, 9)) fig_waveforms.subplots_adjust(hspace=.5) fig_camera = plt.figure(figsize=(15, 12)) ax_max_pix = fig_waveforms.add_subplot(4, 2, 1) ax_min_pix = fig_waveforms.add_subplot(4, 2, 2) ax_max_nei[0] = fig_waveforms.add_subplot(4, 2, 3) ax_min_nei[0] = fig_waveforms.add_subplot(4, 2, 4) ax_max_nei[1] = fig_waveforms.add_subplot(4, 2, 5) ax_min_nei[1] = fig_waveforms.add_subplot(4, 2, 6) ax_max_nei[2] = fig_waveforms.add_subplot(4, 2, 7) ax_min_nei[2] = fig_waveforms.add_subplot(4, 2, 8) ax_img_nei = fig_camera.add_subplot(2, 2, 1) ax_img_max = fig_camera.add_subplot(2, 2, 2) ax_img_true = fig_camera.add_subplot(2, 2, 3) ax_img_cal = fig_camera.add_subplot(2, 2, 4) plotter = CameraPlotter(event, geom_dict) # Draw max pixel traces plotter.draw_waveform(data_ped[max_pixel], ax_max_pix) ax_max_pix.set_title("(Max) Pixel: {}, " "True: {}, " "Measured = {:.3f}".format(max_pixel, true_pe[max_pixel], measured_pe[max_pixel])) ax_max_pix.set_ylabel("Amplitude-Ped (ADC)") max_ylim = ax_max_pix.get_ylim() plotter.draw_waveform_positionline(start[max_pixel], ax_max_pix) plotter.draw_waveform_positionline(end[max_pixel], ax_max_pix) for i, ax in ax_max_nei.items(): if len(max_pixel_nei) > i: pix = max_pixel_nei[i] plotter.draw_waveform(data_ped[pix], ax) ax.set_title("(Max Nei) Pixel: {}, " "True: {}, " "Measured = {:.3f}".format(pix, true_pe[pix], measured_pe[pix])) ax.set_ylabel("Amplitude-Ped (ADC)") ax.set_ylim(max_ylim) plotter.draw_waveform_positionline(start[pix], ax) plotter.draw_waveform_positionline(end[pix], ax) # Draw min pixel traces plotter.draw_waveform(data_ped[min_pixel], ax_min_pix) ax_min_pix.set_title("(Min) Pixel: {}, " "True: {}, " "Measured = {:.3f}".format(min_pixel, true_pe[min_pixel], measured_pe[min_pixel])) ax_min_pix.set_ylabel("Amplitude-Ped (ADC)") ax_min_pix.set_ylim(max_ylim) plotter.draw_waveform_positionline(start[min_pixel], ax_min_pix) plotter.draw_waveform_positionline(end[min_pixel], ax_min_pix) for i, ax in ax_min_nei.items(): if len(min_pixel_nei) > i: pix = min_pixel_nei[i] plotter.draw_waveform(data_ped[pix], ax) ax.set_title("(Min Nei) Pixel: {}, " "True: {}, " "Measured = {:.3f}".format(pix, true_pe[pix], measured_pe[pix])) ax.set_ylabel("Amplitude-Ped (ADC)") ax.set_ylim(max_ylim) plotter.draw_waveform_positionline(start[pix], ax) plotter.draw_waveform_positionline(end[pix], ax) # Draw cameras nei_camera = np.zeros_like(max_charges, dtype=np.int) nei_camera[min_pixel_nei] = 2 nei_camera[min_pixel] = 1 nei_camera[max_pixel_nei] = 3 nei_camera[max_pixel] = 4 camera = plotter.draw_camera(telid, nei_camera, ax_img_nei) camera.cmap = plt.cm.viridis ax_img_nei.set_title("Neighbour Map") plotter.draw_camera_pixel_annotation(telid, max_pixel, min_pixel, ax_img_nei) camera = plotter.draw_camera(telid, data_ped[:, max_time], ax_img_max) camera.add_colorbar(ax=ax_img_max, label="Amplitude-Ped (ADC)") ax_img_max.set_title("Max Timeslice (T = {})".format(max_time)) plotter.draw_camera_pixel_annotation(telid, max_pixel, min_pixel, ax_img_max) camera = plotter.draw_camera(telid, true_pe, ax_img_true) camera.add_colorbar(ax=ax_img_true, label="True Charge (Photo-electrons)") ax_img_true.set_title("True Charge") plotter.draw_camera_pixel_annotation(telid, max_pixel, min_pixel, ax_img_true) int_dict, inverted = integrator_dict() integrator_name = '' if 'integrator' not in params else \ params['integrator'] camera = plotter.draw_camera(telid, measured_pe, ax_img_cal) camera.add_colorbar(ax=ax_img_cal, label="Calib Charge (Photo-electrons)") ax_img_cal.set_title("Charge (integrator={})".format(integrator_name)) plotter.draw_camera_pixel_annotation(telid, max_pixel, min_pixel, ax_img_cal) fig_waveforms.suptitle("Integrator = {}".format(integrator_name)) fig_camera.suptitle("Camera = {}".format(geom.cam_id)) waveform_output_name = "{}_e{}_t{}_c{}_integrator{}_waveform.pdf"\ .format(input_file.filename, event.count, telid, chan, inverted[params['integrator']]) camera_output_name = "{}_e{}_t{}_c{}_integrator{}_camera.pdf"\ .format(input_file.filename, event.count, telid, chan, inverted[params['integrator']]) output_dir = args.output_dir if args.output_dir is not None else \ input_file.output_directory output_dir = os.path.join(output_dir, script) if not os.path.exists(output_dir): log.info("[output] Creating directory: {}".format(output_dir)) os.makedirs(output_dir) waveform_output_path = os.path.join(output_dir, waveform_output_name) log.info("[output] {}".format(waveform_output_path)) fig_waveforms.savefig(waveform_output_path, format='pdf', bbox_inches='tight') camera_output_path = os.path.join(output_dir, camera_output_name) log.info("[output] {}".format(camera_output_path)) fig_camera.savefig(camera_output_path, format='pdf', bbox_inches='tight') log.info("[COMPLETE]")
def calibrate_event(event, params, geom_dict=None): """ Generic calibrator for events. Calls the calibrator corresponding to the source of the event, and stores the dl1 (pe_charge) information into a new event container. Parameters ---------- event : container A `ctapipe` event container params : dict REQUIRED: params['integrator'] - Integration scheme params['integration_window'] - Integration window size and shift of integration window centre (adapted such that window fits into readout). OPTIONAL: params['integration_clip_amp'] - Amplitude in p.e. above which the signal is clipped. params['integration_calib_scale'] : Identical to global variable CALIB_SCALE in reconstruct.c in hessioxxx software package. 0.92 is the default value (corresponds to HESS). The required value changes between cameras (GCT = 1.05). params['integration_sigamp'] - Amplitude in ADC counts above pedestal at which a signal is considered as significant (separate for high gain/low gain). geom_dict : dict Dict of pixel geometry for each telescope. Leave as None for automatic calculation when it is required. dict[(num_pixels, focal_length)] = `ctapipe.io.CameraGeometry` Returns ------- calibrated : container A new `ctapipe` event container containing the dl1 information, and a reference to all other information contained in the original event container. """ # Obtain relevent calibrator switch = { 'hessio': partial(mc.calibrate_mc, event=event, params=params) } try: calibrator = switch[event.meta.source] except KeyError: log.exception("no calibration created for data origin: '{}'" .format(event.meta.source)) raise calibrated = copy(event) # Add dl1 to the event container (if it hasn't already been added) try: calibrated.add_item("dl1", RawData()) calibrated.dl1.run_id = event.dl0.run_id calibrated.dl1.event_id = event.dl0.event_id calibrated.dl1.tels_with_data = event.dl0.tels_with_data calibrated.dl1.calibration_parameters = params except AttributeError: pass # Fill dl1 calibrated.dl1.tel = dict() # clear the previous telescopes for telid in event.dl0.tels_with_data: nchan = event.dl0.tel[telid].num_channels npix = event.dl0.tel[telid].num_pixels calibrated.dl1.tel[telid] = CalibratedCameraData(telid) calibrated.dl1.tel[telid].num_channels = nchan calibrated.dl1.tel[telid].num_pixels = npix # Get geometry int_dict, inverted = integrator_dict() geom = None cam_dimensions = (event.dl0.tel[telid].num_pixels, event.meta.optical_foclen[telid]) # Check if geom is even needed for integrator if inverted[params['integrator']] in integrators_requiring_geom(): if geom_dict is not None and telid in geom_dict: geom = geom_dict[telid] else: log.debug("[calib] Guessing camera geometry") geom = CameraGeometry.guess(*event.meta.pixel_pos[telid], event.meta.optical_foclen[telid]) log.debug("[calib] Camera geometry found") if geom_dict is not None: geom_dict[telid] = geom pe, window, data_ped, peakpos = calibrator(telid=telid, geom=geom) calibrated.dl1.tel[telid].pe_charge = pe calibrated.dl1.tel[telid].peakpos = peakpos for chan in range(nchan): calibrated.dl1.tel[telid].integration_window[chan] = window[chan] calibrated.dl1.tel[telid].pedestal_subtracted_adc[chan] = \ data_ped[chan] return calibrated
def integration_mc(event, telid, params, geom=None): """ Generic integrator for mc files. Calls the integrator_switch for actual integration. Subtracts the pedestal and applies the integration correction. Parameters ---------- event : container A `ctapipe` event container telid : int telescope id params : dict REQUIRED: params['integrator'] - Integration scheme params['integration_window'] - Integration window size and shift of integration window centre (adapted such that window fits into readout). OPTIONAL: params['integration_sigamp'] - Amplitude in ADC counts above pedestal at which a signal is considered as significant (separate for high gain/low gain). geom : `ctapipe.io.CameraGeometry` geometry of the camera's pixels. Leave as None for automatic calculation when it is required. Returns ------- charge : ndarray array of pixels with integrated charge [ADC counts] (pedestal substracted) integration_window : ndarray bool array of same shape as data. Specified which samples are included in the integration window data_ped : ndarray pedestal subtracted data peakpos : ndarray position of the peak as determined by the peak-finding algorithm for each pixel and channel """ # Obtain the data num_samples = event.inst.num_samples[telid] # KPK: addd this if statement since ASTRI data failed (only 1 # sample). Is that the correct way to fix it? if num_samples == 1: data = np.array(list(event.dl0.tel[telid].adc_sums.values())) data = data[:,:,np.newaxis] else: # TODO: the following line converts the structure into a 3D array where the third dimensions is the channel. Should we simply store it that way rathre than a dict by channel? (also this is not a fast operation) data = np.array(list(event.dl0.tel[telid].adc_samples.values())) ped = event.mc.tel[telid].pedestal # monte-carlo pedstal data_ped = data - np.atleast_3d(ped/num_samples) int_dict, inverted = integrator_dict() if geom is None and inverted[params['integrator']]\ in integrators_requiring_geom(): log.debug("[calib] Guessing camera geometry") geom = CameraGeometry.guess(*event.inst.pixel_pos[telid], event.inst.optical_foclen[telid]) log.debug("[calib] Camera geometry found") # Integrate integration, integration_window, peakpos = \ integrator_switch(data_ped, geom, params) # Get the integration correction int_corr = set_integration_correction(event, telid, params) if peakpos[0] is None: int_corr = 1 # Convert integration into charge charge = np.round(integration * int_corr) return charge, integration_window, data_ped, peakpos
def calibrate_event(event, params, geom_dict=None): """ Generic calibrator for events. Calls the calibrator corresponding to the source of the event, and stores the dl1 (pe_charge) information into a new event container. Parameters ---------- event : container A `ctapipe` event container params : dict REQUIRED: params['integrator'] - Integration scheme params['integration_window'] - Integration window size and shift of integration window centre (adapted such that window fits into readout). OPTIONAL: params['integration_clip_amp'] - Amplitude in p.e. above which the signal is clipped. params['integration_calib_scale'] : Identical to global variable CALIB_SCALE in reconstruct.c in hessioxxx software package. 0.92 is the default value (corresponds to HESS). The required value changes between cameras (GCT = 1.05). params['integration_sigamp'] - Amplitude in ADC counts above pedestal at which a signal is considered as significant (separate for high gain/low gain). geom_dict : dict Dict of pixel geometry for each telescope. Leave as None for automatic calculation when it is required. dict[(num_pixels, focal_length)] = `ctapipe.io.CameraGeometry` Returns ------- calibrated : container A new `ctapipe` event container containing the dl1 information, and a reference to all other information contained in the original event container. """ # Obtain relevent calibrator switch = {'hessio': partial(mc.calibrate_mc, event=event, params=params)} try: calibrator = switch[event.meta.source] except KeyError: log.exception("no calibration created for data origin: '{}'".format( event.meta.source)) raise calibrated = copy(event) # Add dl1 to the event container (if it hasn't already been added) try: calibrated.add_item("dl1", RawData()) calibrated.dl1.run_id = event.dl0.run_id calibrated.dl1.event_id = event.dl0.event_id calibrated.dl1.tels_with_data = event.dl0.tels_with_data calibrated.dl1.calibration_parameters = params except AttributeError: pass # Fill dl1 calibrated.dl1.tel = dict() # clear the previous telescopes for telid in event.dl0.tels_with_data: nchan = event.dl0.tel[telid].num_channels npix = event.dl0.tel[telid].num_pixels calibrated.dl1.tel[telid] = CalibratedCameraData(telid) calibrated.dl1.tel[telid].num_channels = nchan calibrated.dl1.tel[telid].num_pixels = npix # Get geometry int_dict, inverted = integrator_dict() geom = None cam_dimensions = (event.dl0.tel[telid].num_pixels, event.meta.optical_foclen[telid]) # Check if geom is even needed for integrator if inverted[params['integrator']] in integrators_requiring_geom(): if geom_dict is not None and telid in geom_dict: geom = geom_dict[telid] else: log.debug("[calib] Guessing camera geometry") geom = CameraGeometry.guess(*event.meta.pixel_pos[telid], event.meta.optical_foclen[telid]) log.debug("[calib] Camera geometry found") if geom_dict is not None: geom_dict[telid] = geom pe, window, data_ped, peakpos = calibrator(telid=telid, geom=geom) calibrated.dl1.tel[telid].pe_charge = pe calibrated.dl1.tel[telid].peakpos = peakpos for chan in range(nchan): calibrated.dl1.tel[telid].integration_window[chan] = window[chan] calibrated.dl1.tel[telid].pedestal_subtracted_adc[chan] = \ data_ped[chan] return calibrated