def camera_to_sky(pos_x, pos_y, focal, pointing_alt, pointing_az): """ Parameters ---------- pos_x: X coordinate in camera (distance) pos_y: Y coordinate in camera (distance) focal: telescope focal (distance) pointing_alt: pointing altitude in angle unit pointing_az: pointing altitude in angle unit Returns ------- (alt, az) Example: -------- import astropy.units as u import numpy as np x = np.array([1,0]) * u.m y = np.array([1,1]) * u.m """ pointing_direction = HorizonFrame(alt=pointing_alt, az=pointing_az) source_pos_in_camera = NominalFrame( array_direction=pointing_direction, pointing_direction=pointing_direction, x=pos_x / focal * u.rad, y=pos_y / focal * u.rad, ) return source_pos_in_camera.transform_to(pointing_direction)
def nominal_to_altaz(): t = np.zeros(10) t[5] = 1 nom = NominalFrame(x=t * u.deg, y=t * u.deg, array_direction=[75 * u.deg, 180 * u.deg]) alt_az = nom.transform_to(HorizonFrame) print("AltAz Coordinate", alt_az)
def get_event_pos_in_sky(hillas, disp, tel, pointing_direction): side = 1 # TODO: method to guess side focal = tel.optics.equivalent_focal_length source_pos_in_camera = NominalFrame(array_direction=pointing_direction, pointing_direction=pointing_direction, x=(hillas.x + side * disp * np.cos(hillas.phi)) / focal * u.rad, y=(hillas.y + side * disp * np.sin(hillas.phi)) / focal * u.rad ) horizon_frame = HorizonFrame(alt=pointing_direction.alt, az=pointing_direction.az) return source_pos_in_camera.transform_to(horizon_frame)
def predict(self, shower_seed, energy_seed): """ Parameters ---------- shower_seed: ReconstructedShowerContainer Seed shower geometry to be used in the fit energy_seed: ReconstructedEnergyContainer Seed energy to be used in fit Returns ------- ReconstructedShowerContainer, ReconstructedEnergyContainer: Reconstructed ImPACT shower geometry and energy """ horizon_seed = HorizonFrame(az=shower_seed.az, alt=shower_seed.alt) nominal_seed = horizon_seed.transform_to(NominalFrame( array_direction=self.array_direction)) source_x = nominal_seed.x.to(u.rad).value source_y = nominal_seed.y.to(u.rad).value ground = GroundFrame(x=shower_seed.core_x, y=shower_seed.core_y, z=0 * u.m) tilted = ground.transform_to( TiltedGroundFrame(pointing_direction=self.array_direction) ) tilt_x = tilted.x.to(u.m).value tilt_y = tilted.y.to(u.m).value zenith = 90 * u.deg - self.array_direction.alt if len(self.hillas_parameters) > 3: shift = [1] else: shift = [1.5, 1, 0.5, 0, -0.5, -1, -1.5] seed_list = spread_line_seed(self.hillas_parameters, self.tel_pos_x, self.tel_pos_y, source_x[0], source_y[0], tilt_x, tilt_y, energy_seed.energy.value, shift_frac = shift) chosen_seed = self.choose_seed(seed_list) # Perform maximum likelihood fit fit_params, errors, like = self.minimise(params=chosen_seed[0], step=chosen_seed[1], limits=chosen_seed[2], minimiser_name=self.minimiser_name) # Create a container class for reconstructed shower shower_result = ReconstructedShowerContainer() # Convert the best fits direction and core to Horizon and ground systems and # copy to the shower container nominal = NominalFrame(x=fit_params[0] * u.rad, y=fit_params[1] * u.rad, array_direction=self.array_direction) horizon = nominal.transform_to(HorizonFrame()) shower_result.alt, shower_result.az = horizon.alt, horizon.az tilted = TiltedGroundFrame(x=fit_params[2] * u.m, y=fit_params[3] * u.m, pointing_direction=self.array_direction) ground = project_to_ground(tilted) shower_result.core_x = ground.x shower_result.core_y = ground.y shower_result.is_valid = True # Currently no errors not availible to copy NaN shower_result.alt_uncert = np.nan shower_result.az_uncert = np.nan shower_result.core_uncert = np.nan # Copy reconstructed Xmax shower_result.h_max = fit_params[5] * self.get_shower_max(fit_params[0], fit_params[1], fit_params[2], fit_params[3], zenith.to(u.rad).value) shower_result.h_max *= np.cos(zenith) shower_result.h_max_uncert = errors[5] * shower_result.h_max shower_result.goodness_of_fit = like # Create a container class for reconstructed energy energy_result = ReconstructedEnergyContainer() # Fill with results energy_result.energy = fit_params[4] * u.TeV energy_result.energy_uncert = errors[4] * u.TeV energy_result.is_valid = True return shower_result, energy_result
def plot_muon_event(event, muonparams, args=None): if muonparams['MuonRingParams'] is not None: # Plot the muon event and overlay muon parameters fig = plt.figure(figsize=(16, 7)) colorbar = None colorbar2 = None #for tel_id in event.dl0.tels_with_data: for tel_id in muonparams['TelIds']: idx = muonparams['TelIds'].index(tel_id) if not muonparams['MuonRingParams'][idx]: continue #otherwise... npads = 2 # Only create two pads if there is timing information extracted # from the calibration ax1 = fig.add_subplot(1, npads, 1) plotter = CameraPlotter(event) image = event.dl1.tel[tel_id].image[0] geom = event.inst.subarray.tel[tel_id].camera tailcuts = (5., 7.) # Try a higher threshold for if geom.cam_id == 'FlashCam': tailcuts = (10., 12.) clean_mask = tailcuts_clean(geom, image, picture_thresh=tailcuts[0], boundary_thresh=tailcuts[1]) signals = image * clean_mask #print("Ring Centre in Nominal Coords:",muonparams[0].ring_center_x,muonparams[0].ring_center_y) muon_incl = np.sqrt( muonparams['MuonRingParams'][idx].ring_center_x**2. + muonparams['MuonRingParams'][idx].ring_center_y**2.) muon_phi = np.arctan( muonparams['MuonRingParams'][idx].ring_center_y / muonparams['MuonRingParams'][idx].ring_center_x) rotr_angle = geom.pix_rotation # if event.inst.optical_foclen[tel_id] > 10.*u.m and # event.dl0.tel[tel_id].num_pixels != 1764: if geom.cam_id == 'LSTCam' or geom.cam_id == 'NectarCam': #print("Resetting the rotation angle") rotr_angle = 0. * u.deg # Convert to camera frame (centre & radius) altaz = HorizonFrame(alt=event.mc.alt, az=event.mc.az) ring_nominal = NominalFrame( x=muonparams['MuonRingParams'][idx].ring_center_x, y=muonparams['MuonRingParams'][idx].ring_center_y, array_direction=altaz, pointing_direction=altaz) # embed() ring_camcoord = ring_nominal.transform_to( CameraFrame(pointing_direction=altaz, focal_length=event.inst.optical_foclen[tel_id], rotation=rotr_angle)) centroid_rad = np.sqrt(ring_camcoord.y**2 + ring_camcoord.x**2) centroid = (ring_camcoord.x.value, ring_camcoord.y.value) ringrad_camcoord = muonparams['MuonRingParams'][idx].ring_radius.to(u.rad) \ * event.inst.optical_foclen[tel_id] * 2. # But not FC? px, py = event.inst.pixel_pos[tel_id] flen = event.inst.optical_foclen[tel_id] camera_coord = CameraFrame(x=px, y=py, focal_length=flen, rotation=geom.pix_rotation) nom_coord = camera_coord.transform_to( NominalFrame(array_direction=altaz, pointing_direction=altaz)) px = nom_coord.x.to(u.deg) py = nom_coord.y.to(u.deg) dist = np.sqrt( np.power(px - muonparams['MuonRingParams'][idx].ring_center_x, 2) + np.power(py - muonparams['MuonRingParams'][idx].ring_center_y, 2)) ring_dist = np.abs(dist - muonparams['MuonRingParams'][idx].ring_radius) pixRmask = ring_dist < muonparams['MuonRingParams'][ idx].ring_radius * 0.4 #if muonparams[1] is not None: if muonparams['MuonIntensityParams'][idx] is not None: signals *= muonparams['MuonIntensityParams'][idx].mask camera1 = plotter.draw_camera(tel_id, signals, ax1) cmaxmin = (max(signals) - min(signals)) cmin = min(signals) if not cmin: cmin = 1. if not cmaxmin: cmaxmin = 1. cmap_charge = colors.LinearSegmentedColormap.from_list( 'cmap_c', [(0 / cmaxmin, 'darkblue'), (np.abs(cmin) / cmaxmin, 'black'), (2.0 * np.abs(cmin) / cmaxmin, 'blue'), (2.5 * np.abs(cmin) / cmaxmin, 'green'), (1, 'yellow')]) camera1.pixels.set_cmap(cmap_charge) if not colorbar: camera1.add_colorbar(ax=ax1, label=" [photo-electrons]") colorbar = camera1.colorbar else: camera1.colorbar = colorbar camera1.update(True) camera1.add_ellipse(centroid, ringrad_camcoord.value, ringrad_camcoord.value, 0., 0., color="red") if muonparams['MuonIntensityParams'][idx] is not None: # continue #Comment this...(should ringwidthfrac also be *0.5?) ringwidthfrac = muonparams['MuonIntensityParams'][ idx].ring_width / muonparams['MuonRingParams'][ idx].ring_radius ringrad_inner = ringrad_camcoord * (1. - ringwidthfrac) ringrad_outer = ringrad_camcoord * (1. + ringwidthfrac) camera1.add_ellipse(centroid, ringrad_inner.value, ringrad_inner.value, 0., 0., color="magenta") camera1.add_ellipse(centroid, ringrad_outer.value, ringrad_outer.value, 0., 0., color="magenta") npads = 2 ax2 = fig.add_subplot(1, npads, npads) pred = muonparams['MuonIntensityParams'][idx].prediction if len(pred) != np.sum( muonparams['MuonIntensityParams'][idx].mask): print("Warning! Lengths do not match...len(pred)=", len(pred), "len(mask)=", np.sum(muonparams['MuonIntensityParams'][idx].mask)) # Numpy broadcasting - fill in the shape plotpred = np.zeros(image.shape) plotpred[muonparams['MuonIntensityParams'][idx].mask == True] = pred camera2 = plotter.draw_camera(tel_id, plotpred, ax2) if np.isnan(max(plotpred)) or np.isnan(min(plotpred)): print("nan prediction, skipping...") continue c2maxmin = (max(plotpred) - min(plotpred)) if not c2maxmin: c2maxmin = 1. c2map_charge = colors.LinearSegmentedColormap.from_list( 'c2map_c', [(0 / c2maxmin, 'darkblue'), (np.abs(min(plotpred)) / c2maxmin, 'black'), (2.0 * np.abs(min(plotpred)) / c2maxmin, 'blue'), (2.5 * np.abs(min(plotpred)) / c2maxmin, 'green'), (1, 'yellow')]) camera2.pixels.set_cmap(c2map_charge) if not colorbar2: camera2.add_colorbar(ax=ax2, label=" [photo-electrons]") colorbar2 = camera2.colorbar else: camera2.colorbar = colorbar2 camera2.update(True) plt.pause(1.) # make shorter # plt.pause(0.1) # if pp is not None: # pp.savefig(fig) #fig.savefig(str(args.output_path) + "_" + # str(event.dl0.event_id) + '.png') plt.close()
def plot_muon_event(event, muonparams, geom_dict=None, args=None): if muonparams[0] is not None: # Plot the muon event and overlay muon parameters fig = plt.figure(figsize=(16, 7)) # if args.display: # plt.show(block=False) #pp = PdfPages(args.output_path) if args.output_path is not None else None # pp = None #For now, need to correct this colorbar = None colorbar2 = None for tel_id in event.dl0.tels_with_data: npads = 2 # Only create two pads if there is timing information extracted # from the calibration ax1 = fig.add_subplot(1, npads, 1) plotter = CameraPlotter(event, geom_dict) #image = event.dl1.tel[tel_id].calibrated_image image = event.dl1.tel[tel_id].image[0] # Get geometry geom = None if geom_dict is not None and tel_id in geom_dict: geom = geom_dict[tel_id] else: #log.debug("[calib] Guessing camera geometry") geom = CameraGeometry.guess(*event.inst.pixel_pos[tel_id], event.inst.optical_foclen[tel_id]) #log.debug("[calib] Camera geometry found") if geom_dict is not None: geom_dict[tel_id] = geom tailcuts = (5., 7.) # Try a higher threshold for if geom.cam_id == 'FlashCam': tailcuts = (10., 12.) #print("Using Tail Cuts:",tailcuts) clean_mask = tailcuts_clean(geom, image, picture_thresh=tailcuts[0], boundary_thresh=tailcuts[1]) signals = image * clean_mask #print("Ring Centre in Nominal Coords:",muonparams[0].ring_center_x,muonparams[0].ring_center_y) muon_incl = np.sqrt(muonparams[0].ring_center_x**2. + muonparams[0].ring_center_y**2.) muon_phi = np.arctan(muonparams[0].ring_center_y / muonparams[0].ring_center_x) rotr_angle = geom.pix_rotation # if event.inst.optical_foclen[tel_id] > 10.*u.m and # event.dl0.tel[tel_id].num_pixels != 1764: if geom.cam_id == 'LSTCam' or geom.cam_id == 'NectarCam': #print("Resetting the rotation angle") rotr_angle = 0. * u.deg # Convert to camera frame (centre & radius) altaz = HorizonFrame(alt=event.mc.alt, az=event.mc.az) ring_nominal = NominalFrame(x=muonparams[0].ring_center_x, y=muonparams[0].ring_center_y, array_direction=altaz, pointing_direction=altaz) # embed() ring_camcoord = ring_nominal.transform_to(CameraFrame( pointing_direction=altaz, focal_length=event.inst.optical_foclen[tel_id], rotation=rotr_angle)) centroid_rad = np.sqrt(ring_camcoord.y**2 + ring_camcoord.x**2) centroid = (ring_camcoord.x.value, ring_camcoord.y.value) ringrad_camcoord = muonparams[0].ring_radius.to(u.rad) \ * event.inst.optical_foclen[tel_id] * 2. # But not FC? #rot_angle = 0.*u.deg # if event.inst.optical_foclen[tel_id] > 10.*u.m and event.dl0.tel[tel_id].num_pixels != 1764: #rot_angle = -100.14*u.deg px, py = event.inst.pixel_pos[tel_id] flen = event.inst.optical_foclen[tel_id] camera_coord = CameraFrame(x=px, y=py, z=np.zeros(px.shape) * u.m, focal_length=flen, rotation=geom.pix_rotation) nom_coord = camera_coord.transform_to( NominalFrame(array_direction=altaz, pointing_direction=altaz) ) #,focal_length = event.inst.optical_foclen[tel_id])) # tel['TelescopeTable_VersionFeb2016'][tel['TelescopeTable_VersionFeb2016']['TelID']==telid]['FL'][0]*u.m)) px = nom_coord.x.to(u.deg) py = nom_coord.y.to(u.deg) dist = np.sqrt(np.power( px - muonparams[0].ring_center_x, 2) + np.power(py - muonparams[0].ring_center_y, 2)) ring_dist = np.abs(dist - muonparams[0].ring_radius) pixRmask = ring_dist < muonparams[0].ring_radius * 0.4 if muonparams[1] is not None: signals *= muonparams[1].mask camera1 = plotter.draw_camera(tel_id, signals, ax1) cmaxmin = (max(signals) - min(signals)) if not cmaxmin: cmaxmin = 1. cmap_charge = colors.LinearSegmentedColormap.from_list( 'cmap_c', [(0 / cmaxmin, 'darkblue'), (np.abs(min(signals)) / cmaxmin, 'black'), (2.0 * np.abs(min(signals)) / cmaxmin, 'blue'), (2.5 * np.abs(min(signals)) / cmaxmin, 'green'), (1, 'yellow')] ) camera1.pixels.set_cmap(cmap_charge) if not colorbar: camera1.add_colorbar(ax=ax1, label=" [photo-electrons]") colorbar = camera1.colorbar else: camera1.colorbar = colorbar camera1.update(True) camera1.add_ellipse(centroid, ringrad_camcoord.value, ringrad_camcoord.value, 0., 0., color="red") # ax1.set_title("CT {} ({}) - Mean pixel charge" # .format(tel_id, geom_dict[tel_id].cam_id)) if muonparams[1] is not None: # continue #Comment this...(should ringwidthfrac also be *0.5?) ringwidthfrac = muonparams[ 1].ring_width / muonparams[0].ring_radius ringrad_inner = ringrad_camcoord * (1. - ringwidthfrac) ringrad_outer = ringrad_camcoord * (1. + ringwidthfrac) camera1.add_ellipse(centroid, ringrad_inner.value, ringrad_inner.value, 0., 0., color="magenta") camera1.add_ellipse(centroid, ringrad_outer.value, ringrad_outer.value, 0., 0., color="magenta") npads = 2 ax2 = fig.add_subplot(1, npads, npads) pred = muonparams[1].prediction if len(pred) != np.sum(muonparams[1].mask): print("Warning! Lengths do not match...len(pred)=", len(pred), "len(mask)=", np.sum(muonparams[1].mask)) # Numpy broadcasting - fill in the shape plotpred = np.zeros(image.shape) plotpred[muonparams[1].mask == True] = pred camera2 = plotter.draw_camera(tel_id, plotpred, ax2) c2maxmin = (max(plotpred) - min(plotpred)) if not c2maxmin: c2maxmin = 1. c2map_charge = colors.LinearSegmentedColormap.from_list( 'c2map_c', [(0 / c2maxmin, 'darkblue'), (np.abs(min(plotpred)) / c2maxmin, 'black'), (2.0 * np.abs(min(plotpred)) / c2maxmin, 'blue'), (2.5 * np.abs(min(plotpred)) / c2maxmin, 'green'), (1, 'yellow')] ) camera2.pixels.set_cmap(c2map_charge) if not colorbar2: camera2.add_colorbar(ax=ax2, label=" [photo-electrons]") colorbar2 = camera2.colorbar else: camera2.colorbar = colorbar2 camera2.update(True) plt.pause(1.) # make shorter # plt.pause(0.1) # if pp is not None: # pp.savefig(fig) fig.savefig(str(args.output_path) + "_" + str(event.dl0.event_id) + '.png') plt.close()
def nominal_to_altaz(): t = np.zeros(10) t[5] = 1 nom = NominalFrame(x=t*u.deg,y=t*u.deg,array_direction = [75*u.deg,180*u.deg]) alt_az = nom.transform_to(HorizonFrame) print("AltAz Coordinate",alt_az)
def predict(self, shower_seed, energy_seed): """ Parameters ---------- shower_seed: ReconstructedShowerContainer Seed shower geometry to be used in the fit energy_seed: ReconstructedEnergyContainer Seed energy to be used in fit Returns ------- ReconstructedShowerContainer, ReconstructedEnergyContainer: Reconstructed ImPACT shower geometry and energy """ horizon_seed = HorizonFrame(az=shower_seed.az, alt=shower_seed.alt) nominal_seed = horizon_seed.transform_to( NominalFrame(array_direction=self.array_direction)) print(nominal_seed) print(horizon_seed) print(self.array_direction) source_x = nominal_seed.x[0].to(u.rad).value source_y = nominal_seed.y[0].to(u.rad).value ground = GroundFrame(x=shower_seed.core_x, y=shower_seed.core_y, z=0 * u.m) tilted = ground.transform_to( TiltedGroundFrame(pointing_direction=self.array_direction)) tilt_x = tilted.x.to(u.m).value tilt_y = tilted.y.to(u.m).value lower_en_limit = energy_seed.energy * 0.5 en_seed = energy_seed.energy if lower_en_limit < 0.04 * u.TeV: lower_en_limit = 0.04 * u.TeV en_seed = 0.041 * u.TeV seed = (source_x, source_y, tilt_x, tilt_y, en_seed.value, 0.8) step = (0.001, 0.001, 10, 10, en_seed.value * 0.1, 0.1) limits = ((source_x - 0.01, source_x + 0.01), (source_y - 0.01, source_y + 0.01), (tilt_x - 100, tilt_x + 100), (tilt_y - 100, tilt_y + 100), (lower_en_limit.value, en_seed.value * 2), (0.5, 2)) fit_params, errors = self.minimise(params=seed, step=step, limits=limits, minimiser_name=self.minimiser_name) # container class for reconstructed showers ''' shower_result = ReconstructedShowerContainer() nominal = NominalFrame(x=fit_params[0] * u.rad, y=fit_params[1] * u.rad, array_direction=self.array_direction) horizon = nominal.transform_to(HorizonFrame()) shower_result.alt, shower_result.az = horizon.alt, horizon.az tilted = TiltedGroundFrame(x=fit_params[2] * u.m, y=fit_params[3] * u.m, pointing_direction=self.array_direction) ground = project_to_ground(tilted) shower_result.core_x = ground.x shower_result.core_y = ground.y shower_result.is_valid = True shower_result.alt_uncert = np.nan shower_result.az_uncert = np.nan shower_result.core_uncert = np.nan zenith = 90 * u.deg - self.array_direction.alt shower_result.h_max = fit_params[5] * \ self.get_shower_max(fit_params[0], fit_params[1], fit_params[2], fit_params[3], zenith.to(u.rad).value) shower_result.h_max_uncert = errors[5] * shower_result.h_max shower_result.goodness_of_fit = np.nan shower_result.tel_ids = list(self.image.keys()) energy_result = ReconstructedEnergyContainer() energy_result.energy = fit_params[4] * u.TeV energy_result.energy_uncert = errors[4] * u.TeV energy_result.is_valid = True energy_result.tel_ids = list(self.image.keys()) # Return interesting stuff return shower_result, energy_result
def predict(self, shower_seed, energy_seed): """ Parameters ---------- source_x: float Initial guess of source position in the nominal frame source_y: float Initial guess of source position in the nominal frame core_x: float Initial guess of the core position in the tilted system core_y: float Initial guess of the core position in the tilted system energy: float Initial guess of energy Returns ------- Shower object with fit results """ horizon_seed = HorizonFrame(az=shower_seed.az, alt=shower_seed.alt) nominal_seed = horizon_seed.transform_to( NominalFrame(array_direction=self.array_direction)) source_x = nominal_seed.x.to(u.rad).value source_y = nominal_seed.y.to(u.rad).value ground = GroundFrame(x=shower_seed.core_x, y=shower_seed.core_y, z=0 * u.m) tilted = ground.transform_to( TiltedGroundFrame(pointing_direction=self.array_direction)) tilt_x = tilted.x.to(u.m).value tilt_y = tilted.y.to(u.m).value lower_en_limit = energy_seed.energy * 0.1 if lower_en_limit < 0.04 * u.TeV: lower_en_limit = 0.04 * u.TeV # Create Minuit object with first guesses at parameters, strip away the # units as Minuit doesnt like them min = Minuit(self.get_likelihood, print_level=1, source_x=source_x, error_source_x=0.01 / 57.3, fix_source_x=False, limit_source_x=(source_x - 0.5 / 57.3, source_x + 0.5 / 57.3), source_y=source_y, error_source_y=0.01 / 57.3, fix_source_y=False, limit_source_y=(source_y - 0.5 / 57.3, source_y + 0.5 / 57.3), core_x=tilt_x, error_core_x=10, limit_core_x=(tilt_x - 200, tilt_x + 200), core_y=tilt_y, error_core_y=10, limit_core_y=(tilt_y - 200, tilt_y + 200), energy=energy_seed.energy.value, error_energy=energy_seed.energy.value * 0.05, limit_energy=(lower_en_limit.value, energy_seed.energy.value * 10.), x_max_scale=1, error_x_max_scale=0.1, limit_x_max_scale=(0.5, 2), fix_x_max_scale=False, errordef=1) min.tol *= 1000 min.strategy = 0 # Perform minimisation migrad = min.migrad() fit_params = min.values errors = min.errors # print(migrad) # print(min.minos()) # container class for reconstructed showers ''' shower_result = ReconstructedShowerContainer() nominal = NominalFrame(x=fit_params["source_x"] * u.rad, y=fit_params["source_y"] * u.rad, array_direction=self.array_direction) horizon = nominal.transform_to(HorizonFrame()) shower_result.alt, shower_result.az = horizon.alt, horizon.az tilted = TiltedGroundFrame(x=fit_params["core_x"] * u.m, y=fit_params["core_y"] * u.m, pointing_direction=self.array_direction) ground = project_to_ground(tilted) shower_result.core_x = ground.x shower_result.core_y = ground.y shower_result.is_valid = True shower_result.alt_uncert = np.nan shower_result.az_uncert = np.nan shower_result.core_uncert = np.nan zenith = 90 * u.deg - self.array_direction[0] shower_result.h_max = fit_params["x_max_scale"] * \ self.get_shower_max(fit_params["source_x"], fit_params["source_y"], fit_params["core_x"], fit_params["core_y"], zenith.to(u.rad).value) shower_result.h_max_uncert = errors["x_max_scale"] * shower_result.h_max shower_result.goodness_of_fit = np.nan shower_result.tel_ids = list(self.image.keys()) energy_result = ReconstructedEnergyContainer() energy_result.energy = fit_params["energy"] * u.TeV energy_result.energy_uncert = errors["energy"] * u.TeV energy_result.is_valid = True energy_result.tel_ids = list(self.image.keys()) # Return interesting stuff return shower_result, energy_result
def predict(self, shower_seed, energy_seed): """ Parameters ---------- shower_seed: ReconstructedShowerContainer Seed shower geometry to be used in the fit energy_seed: ReconstructedEnergyContainer Seed energy to be used in fit Returns ------- ReconstructedShowerContainer, ReconstructedEnergyContainer: Reconstructed ImPACT shower geometry and energy """ horizon_seed = HorizonFrame(az=shower_seed.az, alt=shower_seed.alt) nominal_seed = horizon_seed.transform_to(NominalFrame(array_direction=self.array_direction)) print(nominal_seed) print(horizon_seed) print(self.array_direction) source_x = nominal_seed.x[0].to(u.rad).value source_y = nominal_seed.y[0].to(u.rad).value ground = GroundFrame(x=shower_seed.core_x, y=shower_seed.core_y, z=0 * u.m) tilted = ground.transform_to( TiltedGroundFrame(pointing_direction=self.array_direction) ) tilt_x = tilted.x.to(u.m).value tilt_y = tilted.y.to(u.m).value lower_en_limit = energy_seed.energy * 0.5 en_seed = energy_seed.energy if lower_en_limit < 0.04 * u.TeV: lower_en_limit = 0.04 * u.TeV en_seed = 0.041 * u.TeV seed = (source_x, source_y, tilt_x, tilt_y, en_seed.value, 0.8) step = (0.001, 0.001, 10, 10, en_seed.value*0.1, 0.1) limits = ((source_x-0.01, source_x+0.01), (source_y-0.01, source_y+0.01), (tilt_x-100, tilt_x+100), (tilt_y-100, tilt_y+100), (lower_en_limit.value, en_seed.value*2), (0.5,2)) fit_params, errors = self.minimise(params=seed, step=step, limits=limits, minimiser_name=self.minimiser_name) # container class for reconstructed showers ''' shower_result = ReconstructedShowerContainer() nominal = NominalFrame(x=fit_params[0] * u.rad, y=fit_params[1] * u.rad, array_direction=self.array_direction) horizon = nominal.transform_to(HorizonFrame()) shower_result.alt, shower_result.az = horizon.alt, horizon.az tilted = TiltedGroundFrame(x=fit_params[2] * u.m, y=fit_params[3] * u.m, pointing_direction=self.array_direction) ground = project_to_ground(tilted) shower_result.core_x = ground.x shower_result.core_y = ground.y shower_result.is_valid = True shower_result.alt_uncert = np.nan shower_result.az_uncert = np.nan shower_result.core_uncert = np.nan zenith = 90*u.deg - self.array_direction.alt shower_result.h_max = fit_params[5] * \ self.get_shower_max(fit_params[0], fit_params[1], fit_params[2], fit_params[3], zenith.to(u.rad).value) shower_result.h_max_uncert = errors[5] * shower_result.h_max shower_result.goodness_of_fit = np.nan shower_result.tel_ids = list(self.image.keys()) energy_result = ReconstructedEnergyContainer() energy_result.energy = fit_params[4] * u.TeV energy_result.energy_uncert = errors[4] * u.TeV energy_result.is_valid = True energy_result.tel_ids = list(self.image.keys()) # Return interesting stuff return shower_result, energy_result
def plot_muon_event(event, muonparams, args=None): if muonparams['MuonRingParams'] is not None: # Plot the muon event and overlay muon parameters fig = plt.figure(figsize=(16, 7)) colorbar = None colorbar2 = None #for tel_id in event.dl0.tels_with_data: for tel_id in muonparams['TelIds']: idx = muonparams['TelIds'].index(tel_id) if not muonparams['MuonRingParams'][idx]: continue #otherwise... npads = 2 # Only create two pads if there is timing information extracted # from the calibration ax1 = fig.add_subplot(1, npads, 1) plotter = CameraPlotter(event) image = event.dl1.tel[tel_id].image[0] geom = event.inst.subarray.tel[tel_id].camera tailcuts = (5., 7.) # Try a higher threshold for if geom.cam_id == 'FlashCam': tailcuts = (10., 12.) clean_mask = tailcuts_clean(geom, image, picture_thresh=tailcuts[0], boundary_thresh=tailcuts[1]) signals = image * clean_mask #print("Ring Centre in Nominal Coords:",muonparams[0].ring_center_x,muonparams[0].ring_center_y) muon_incl = np.sqrt(muonparams['MuonRingParams'][idx].ring_center_x**2. + muonparams['MuonRingParams'][idx].ring_center_y**2.) muon_phi = np.arctan(muonparams['MuonRingParams'][idx].ring_center_y / muonparams['MuonRingParams'][idx].ring_center_x) rotr_angle = geom.pix_rotation # if event.inst.optical_foclen[tel_id] > 10.*u.m and # event.dl0.tel[tel_id].num_pixels != 1764: if geom.cam_id == 'LSTCam' or geom.cam_id == 'NectarCam': #print("Resetting the rotation angle") rotr_angle = 0. * u.deg # Convert to camera frame (centre & radius) altaz = HorizonFrame(alt=event.mc.alt, az=event.mc.az) ring_nominal = NominalFrame(x=muonparams['MuonRingParams'][idx].ring_center_x, y=muonparams['MuonRingParams'][idx].ring_center_y, array_direction=altaz, pointing_direction=altaz) # embed() ring_camcoord = ring_nominal.transform_to(CameraFrame( pointing_direction=altaz, focal_length=event.inst.optical_foclen[tel_id], rotation=rotr_angle)) centroid_rad = np.sqrt(ring_camcoord.y**2 + ring_camcoord.x**2) centroid = (ring_camcoord.x.value, ring_camcoord.y.value) ringrad_camcoord = muonparams['MuonRingParams'][idx].ring_radius.to(u.rad) \ * event.inst.optical_foclen[tel_id] * 2. # But not FC? px, py = event.inst.pixel_pos[tel_id] flen = event.inst.optical_foclen[tel_id] camera_coord = CameraFrame(x=px, y=py, z=np.zeros(px.shape) * u.m, focal_length=flen, rotation=geom.pix_rotation) nom_coord = camera_coord.transform_to( NominalFrame(array_direction=altaz, pointing_direction=altaz) ) px = nom_coord.x.to(u.deg) py = nom_coord.y.to(u.deg) dist = np.sqrt(np.power( px - muonparams['MuonRingParams'][idx].ring_center_x, 2) + np.power(py - muonparams['MuonRingParams'][idx].ring_center_y, 2)) ring_dist = np.abs(dist - muonparams['MuonRingParams'][idx].ring_radius) pixRmask = ring_dist < muonparams['MuonRingParams'][idx].ring_radius * 0.4 #if muonparams[1] is not None: if muonparams['MuonIntensityParams'][idx] is not None: signals *= muonparams['MuonIntensityParams'][idx].mask camera1 = plotter.draw_camera(tel_id, signals, ax1) cmaxmin = (max(signals) - min(signals)) cmin = min(signals) if not cmin: cmin = 1. if not cmaxmin: cmaxmin = 1. cmap_charge = colors.LinearSegmentedColormap.from_list( 'cmap_c', [(0 / cmaxmin, 'darkblue'), (np.abs(cmin) / cmaxmin, 'black'), (2.0 * np.abs(cmin) / cmaxmin, 'blue'), (2.5 * np.abs(cmin) / cmaxmin, 'green'), (1, 'yellow')] ) camera1.pixels.set_cmap(cmap_charge) if not colorbar: camera1.add_colorbar(ax=ax1, label=" [photo-electrons]") colorbar = camera1.colorbar else: camera1.colorbar = colorbar camera1.update(True) camera1.add_ellipse(centroid, ringrad_camcoord.value, ringrad_camcoord.value, 0., 0., color="red") if muonparams['MuonIntensityParams'][idx] is not None: # continue #Comment this...(should ringwidthfrac also be *0.5?) ringwidthfrac = muonparams['MuonIntensityParams'][idx].ring_width / muonparams['MuonRingParams'][idx].ring_radius ringrad_inner = ringrad_camcoord * (1. - ringwidthfrac) ringrad_outer = ringrad_camcoord * (1. + ringwidthfrac) camera1.add_ellipse(centroid, ringrad_inner.value, ringrad_inner.value, 0., 0., color="magenta") camera1.add_ellipse(centroid, ringrad_outer.value, ringrad_outer.value, 0., 0., color="magenta") npads = 2 ax2 = fig.add_subplot(1, npads, npads) pred = muonparams['MuonIntensityParams'][idx].prediction if len(pred) != np.sum(muonparams['MuonIntensityParams'][idx].mask): print("Warning! Lengths do not match...len(pred)=", len(pred), "len(mask)=", np.sum(muonparams['MuonIntensityParams'][idx].mask)) # Numpy broadcasting - fill in the shape plotpred = np.zeros(image.shape) plotpred[muonparams['MuonIntensityParams'][idx].mask == True] = pred camera2 = plotter.draw_camera(tel_id, plotpred, ax2) if np.isnan(max(plotpred)) or np.isnan(min(plotpred)): print("nan prediction, skipping...") continue c2maxmin = (max(plotpred) - min(plotpred)) if not c2maxmin: c2maxmin = 1. c2map_charge = colors.LinearSegmentedColormap.from_list( 'c2map_c', [(0 / c2maxmin, 'darkblue'), (np.abs(min(plotpred)) / c2maxmin, 'black'), (2.0 * np.abs(min(plotpred)) / c2maxmin, 'blue'), (2.5 * np.abs(min(plotpred)) / c2maxmin, 'green'), (1, 'yellow')] ) camera2.pixels.set_cmap(c2map_charge) if not colorbar2: camera2.add_colorbar(ax=ax2, label=" [photo-electrons]") colorbar2 = camera2.colorbar else: camera2.colorbar = colorbar2 camera2.update(True) plt.pause(1.) # make shorter # plt.pause(0.1) # if pp is not None: # pp.savefig(fig) #fig.savefig(str(args.output_path) + "_" + # str(event.dl0.event_id) + '.png') plt.close()
def predict(self, shower_seed, energy_seed): """ Parameters ---------- source_x: float Initial guess of source position in the nominal frame source_y: float Initial guess of source position in the nominal frame core_x: float Initial guess of the core position in the tilted system core_y: float Initial guess of the core position in the tilted system energy: float Initial guess of energy Returns ------- Shower object with fit results """ horizon_seed = HorizonFrame(az=shower_seed.az, alt=shower_seed.alt) nominal_seed = horizon_seed.transform_to( NominalFrame(array_direction=self.array_direction) ) source_x = nominal_seed.x.to(u.rad).value source_y = nominal_seed.y.to(u.rad).value ground = GroundFrame(x=shower_seed.core_x, y=shower_seed.core_y, z=0 * u.m) tilted = ground.transform_to( TiltedGroundFrame(pointing_direction=self.array_direction) ) tilt_x = tilted.x.to(u.m).value tilt_y = tilted.y.to(u.m).value lower_en_limit = energy_seed.energy * 0.1 if lower_en_limit < 0.04 * u.TeV: lower_en_limit = 0.04 * u.TeV # Create Minuit object with first guesses at parameters, strip away the # units as Minuit doesnt like them min = Minuit(self.get_likelihood, print_level=1, source_x=source_x, error_source_x=0.01 / 57.3, fix_source_x=False, limit_source_x=(source_x - 0.5 / 57.3, source_x + 0.5 / 57.3), source_y=source_y, error_source_y=0.01 / 57.3, fix_source_y=False, limit_source_y=(source_y - 0.5 / 57.3, source_y + 0.5 / 57.3), core_x=tilt_x, error_core_x=10, limit_core_x=(tilt_x - 200, tilt_x + 200), core_y=tilt_y, error_core_y=10, limit_core_y=(tilt_y - 200, tilt_y + 200), energy=energy_seed.energy.value, error_energy=energy_seed.energy.value * 0.05, limit_energy=(lower_en_limit.value, energy_seed.energy.value * 10.), x_max_scale=1, error_x_max_scale=0.1, limit_x_max_scale=(0.5, 2), fix_x_max_scale=False, errordef=1) min.tol *= 1000 min.strategy = 0 # Perform minimisation migrad = min.migrad() fit_params = min.values errors = min.errors # print(migrad) # print(min.minos()) # container class for reconstructed showers ''' shower_result = ReconstructedShowerContainer() nominal = NominalFrame(x=fit_params["source_x"] * u.rad, y=fit_params["source_y"] * u.rad, array_direction=self.array_direction) horizon = nominal.transform_to(HorizonFrame()) shower_result.alt, shower_result.az = horizon.alt, horizon.az tilted = TiltedGroundFrame(x=fit_params["core_x"] * u.m, y=fit_params["core_y"] * u.m, pointing_direction=self.array_direction) ground = project_to_ground(tilted) shower_result.core_x = ground.x shower_result.core_y = ground.y shower_result.is_valid = True shower_result.alt_uncert = np.nan shower_result.az_uncert = np.nan shower_result.core_uncert = np.nan zenith = 90 * u.deg - self.array_direction[0] shower_result.h_max = fit_params["x_max_scale"] * \ self.get_shower_max(fit_params["source_x"], fit_params["source_y"], fit_params["core_x"], fit_params["core_y"], zenith.to(u.rad).value) shower_result.h_max_uncert = errors["x_max_scale"] * shower_result.h_max shower_result.goodness_of_fit = np.nan shower_result.tel_ids = list(self.image.keys()) energy_result = ReconstructedEnergyContainer() energy_result.energy = fit_params["energy"] * u.TeV energy_result.energy_uncert = errors["energy"] * u.TeV energy_result.is_valid = True energy_result.tel_ids = list(self.image.keys()) # Return interesting stuff return shower_result, energy_result
def predict(self, hillas_parameters, tel_x, tel_y, array_direction): """ Parameters ---------- hillas_parameters: dict Dictionary containing Hillas parameters for all telescopes in reconstruction tel_x: dict Dictionary containing telescope position on ground for all telescopes in reconstruction tel_y: dict Dictionary containing telescope position on ground for all telescopes in reconstruction array_direction: HorizonFrame Pointing direction of the array Returns ------- ReconstructedShowerContainer: """ src_x, src_y, err_x, err_y = self.reconstruct_nominal(hillas_parameters) core_x, core_y, core_err_x, core_err_y = self.reconstruct_tilted( hillas_parameters, tel_x, tel_y) err_x *= u.rad err_y *= u.rad nom = NominalFrame(x=src_x * u.rad, y=src_y * u.rad, array_direction=array_direction) horiz = nom.transform_to(HorizonFrame()) result = ReconstructedShowerContainer() result.alt, result.az = horiz.alt, horiz.az tilt = TiltedGroundFrame(x=core_x * u.m, y=core_y * u.m, pointing_direction=array_direction) grd = project_to_ground(tilt) result.core_x = grd.x result.core_y = grd.y x_max = self.reconstruct_xmax(nom.x, nom.y, tilt.x, tilt.y, hillas_parameters, tel_x, tel_y, 90 * u.deg - array_direction.alt) result.core_uncert = np.sqrt(core_err_x * core_err_x + core_err_y * core_err_y) * u.m result.tel_ids = [h for h in hillas_parameters.keys()] result.average_size = np.mean([h.size for h in hillas_parameters.values()]) result.is_valid = True src_error = np.sqrt(err_x * err_x + err_y * err_y) result.alt_uncert = src_error.to(u.deg) result.az_uncert = src_error.to(u.deg) result.h_max = x_max result.h_max_uncert = np.nan result.goodness_of_fit = np.nan return result
def plot_muon_event(event, muonparams, geom_dict=None, args=None): if muonparams[0] is not None: # Plot the muon event and overlay muon parameters fig = plt.figure(figsize=(16, 7)) # if args.display: # plt.show(block=False) #pp = PdfPages(args.output_path) if args.output_path is not None else None # pp = None #For now, need to correct this colorbar = None colorbar2 = None for tel_id in event.dl0.tels_with_data: npads = 2 # Only create two pads if there is timing information extracted # from the calibration ax1 = fig.add_subplot(1, npads, 1) plotter = CameraPlotter(event, geom_dict) #image = event.dl1.tel[tel_id].calibrated_image image = event.dl1.tel[tel_id].image[0] # Get geometry geom = None if geom_dict is not None and tel_id in geom_dict: geom = geom_dict[tel_id] else: #log.debug("[calib] Guessing camera geometry") geom = CameraGeometry.guess(*event.inst.pixel_pos[tel_id], event.inst.optical_foclen[tel_id]) #log.debug("[calib] Camera geometry found") if geom_dict is not None: geom_dict[tel_id] = geom tailcuts = (5., 7.) # Try a higher threshold for if geom.cam_id == 'FlashCam': tailcuts = (10., 12.) #print("Using Tail Cuts:",tailcuts) clean_mask = tailcuts_clean(geom, image, picture_thresh=tailcuts[0], boundary_thresh=tailcuts[1]) signals = image * clean_mask #print("Ring Centre in Nominal Coords:",muonparams[0].ring_center_x,muonparams[0].ring_center_y) muon_incl = np.sqrt(muonparams[0].ring_center_x**2. + muonparams[0].ring_center_y**2.) muon_phi = np.arctan(muonparams[0].ring_center_y / muonparams[0].ring_center_x) rotr_angle = geom.pix_rotation # if event.inst.optical_foclen[tel_id] > 10.*u.m and # event.dl0.tel[tel_id].num_pixels != 1764: if geom.cam_id == 'LSTCam' or geom.cam_id == 'NectarCam': #print("Resetting the rotation angle") rotr_angle = 0. * u.deg # Convert to camera frame (centre & radius) altaz = HorizonFrame(alt=event.mc.alt, az=event.mc.az) ring_nominal = NominalFrame(x=muonparams[0].ring_center_x, y=muonparams[0].ring_center_y, array_direction=altaz, pointing_direction=altaz) # embed() ring_camcoord = ring_nominal.transform_to( CameraFrame(pointing_direction=altaz, focal_length=event.inst.optical_foclen[tel_id], rotation=rotr_angle)) centroid_rad = np.sqrt(ring_camcoord.y**2 + ring_camcoord.x**2) centroid = (ring_camcoord.x.value, ring_camcoord.y.value) ringrad_camcoord = muonparams[0].ring_radius.to(u.rad) \ * event.inst.optical_foclen[tel_id] * 2. # But not FC? #rot_angle = 0.*u.deg # if event.inst.optical_foclen[tel_id] > 10.*u.m and event.dl0.tel[tel_id].num_pixels != 1764: #rot_angle = -100.14*u.deg px, py = event.inst.pixel_pos[tel_id] flen = event.inst.optical_foclen[tel_id] camera_coord = CameraFrame(x=px, y=py, z=np.zeros(px.shape) * u.m, focal_length=flen, rotation=geom.pix_rotation) nom_coord = camera_coord.transform_to( NominalFrame(array_direction=altaz, pointing_direction=altaz)) #,focal_length = event.inst.optical_foclen[tel_id])) # tel['TelescopeTable_VersionFeb2016'][tel['TelescopeTable_VersionFeb2016']['TelID']==telid]['FL'][0]*u.m)) px = nom_coord.x.to(u.deg) py = nom_coord.y.to(u.deg) dist = np.sqrt( np.power(px - muonparams[0].ring_center_x, 2) + np.power(py - muonparams[0].ring_center_y, 2)) ring_dist = np.abs(dist - muonparams[0].ring_radius) pixRmask = ring_dist < muonparams[0].ring_radius * 0.4 if muonparams[1] is not None: signals *= muonparams[1].mask camera1 = plotter.draw_camera(tel_id, signals, ax1) cmaxmin = (max(signals) - min(signals)) if not cmaxmin: cmaxmin = 1. cmap_charge = colors.LinearSegmentedColormap.from_list( 'cmap_c', [(0 / cmaxmin, 'darkblue'), (np.abs(min(signals)) / cmaxmin, 'black'), (2.0 * np.abs(min(signals)) / cmaxmin, 'blue'), (2.5 * np.abs(min(signals)) / cmaxmin, 'green'), (1, 'yellow')]) camera1.pixels.set_cmap(cmap_charge) if not colorbar: camera1.add_colorbar(ax=ax1, label=" [photo-electrons]") colorbar = camera1.colorbar else: camera1.colorbar = colorbar camera1.update(True) camera1.add_ellipse(centroid, ringrad_camcoord.value, ringrad_camcoord.value, 0., 0., color="red") # ax1.set_title("CT {} ({}) - Mean pixel charge" # .format(tel_id, geom_dict[tel_id].cam_id)) if muonparams[1] is not None: # continue #Comment this...(should ringwidthfrac also be *0.5?) ringwidthfrac = muonparams[1].ring_width / muonparams[ 0].ring_radius ringrad_inner = ringrad_camcoord * (1. - ringwidthfrac) ringrad_outer = ringrad_camcoord * (1. + ringwidthfrac) camera1.add_ellipse(centroid, ringrad_inner.value, ringrad_inner.value, 0., 0., color="magenta") camera1.add_ellipse(centroid, ringrad_outer.value, ringrad_outer.value, 0., 0., color="magenta") npads = 2 ax2 = fig.add_subplot(1, npads, npads) pred = muonparams[1].prediction if len(pred) != np.sum(muonparams[1].mask): print("Warning! Lengths do not match...len(pred)=", len(pred), "len(mask)=", np.sum(muonparams[1].mask)) # Numpy broadcasting - fill in the shape plotpred = np.zeros(image.shape) plotpred[muonparams[1].mask == True] = pred camera2 = plotter.draw_camera(tel_id, plotpred, ax2) c2maxmin = (max(plotpred) - min(plotpred)) if not c2maxmin: c2maxmin = 1. c2map_charge = colors.LinearSegmentedColormap.from_list( 'c2map_c', [(0 / c2maxmin, 'darkblue'), (np.abs(min(plotpred)) / c2maxmin, 'black'), (2.0 * np.abs(min(plotpred)) / c2maxmin, 'blue'), (2.5 * np.abs(min(plotpred)) / c2maxmin, 'green'), (1, 'yellow')]) camera2.pixels.set_cmap(c2map_charge) if not colorbar2: camera2.add_colorbar(ax=ax2, label=" [photo-electrons]") colorbar2 = camera2.colorbar else: camera2.colorbar = colorbar2 camera2.update(True) plt.pause(1.) # make shorter # plt.pause(0.1) # if pp is not None: # pp.savefig(fig) fig.savefig( str(args.output_path) + "_" + str(event.dl0.event_id) + '.png') plt.close()