def plot_Crab_SED(ax, percentage, emin, emax, **kwargs): """ Plot a percentage of the Crab SED to compare with the achieved sensitivity Parameters -------- ax: `matplotlib.pyplot.axis` percentage: `float` percentage of the Crab Nebula to be plotted emin: `float` minimum energy emax: `float` maximum energy Returns -------- ax: `matplotlib.pyplot.axis` """ En = np.logspace(np.log10(emin.to_value()), np.log10(emax.to_value()), 40) * u.GeV dFdE = percentage / 100. * crab_magic(En)[0] ax.loglog(En, (dFdE * En * En).to(u.TeV / (u.cm * u.cm * u.s)), color='gray', **kwargs) return ax
def plot_Crab_SED(ax, percentage, emin, emax, **kwargs): """ Parameters -------- Returns -------- """ En = np.logspace(np.log10(emin.to_value()), np.log10(emax.to_value()), 40) * u.GeV dFdE = percentage / 100. * crab_magic(En)[0] ax.loglog(En, (dFdE * En * En).to(u.TeV / (u.cm * u.cm * u.s)), color='gray', **kwargs) return ax
def plot_sensitivity(ax, e, sensitivity): """ Parameters -------- Returns -------- """ mask = sensitivity < 1e100 emed = np.sqrt(e[1:] * e[:-1]) dFdE = crab_magic(emed[mask]) ax.loglog(emed[mask], sensitivity[mask] / 100 * (dFdE[0] * emed[mask] * emed[mask]).to(u.TeV / (u.cm * u.cm * u.s)), label='Sensitivity')
def plot_sensitivity(ax, e, sensitivity): """ Parameters -------- Returns -------- """ mask = sensitivity<1e100 emed = np.sqrt(e[1:] * e[:-1]) binsize = (e[1:]-e[:-1])/2 dFdE = crab_magic(emed[mask]) #ax.loglog(emed[mask], # sensitivity[mask] / 100 * (dFdE[0] * emed[mask] * emed[mask]).to(u.TeV / (u.cm * u.cm * u.s)), label = 'Sensitivity', marker) ax.set_yscale("log") ax.set_xscale("log") ax.errorbar(emed[mask].to_value(), (sensitivity[mask] / 100 * (dFdE[0] * emed[mask] * emed[mask]).to(u.TeV / (u.cm * u.cm * u.s))).to_value(), xerr=binsize[mask].to_value(), marker='o')
def sens(simtelfile_gammas, simtelfile_protons, dl2_file_g, dl2_file_p, nfiles_gammas, nfiles_protons, eb, gcut, tcut, noff, obstime = 50 * 3600 * u.s): """ Main function to calculate the sensitivity given a MC dataset Parameters --------- simtelfile_gammas: `string` path to simtelfile of gammas with mc info simtelfile_protons: `string` path to simtelfile of protons with mc info dl2_file_g: `string` path to h5 file of reconstructed gammas dl2_file_p: `string' path to h5 file of reconstructed protons nfiles_gammas: `int` number of simtel gamma files reconstructed nfiles_protons: `int` number of simtel proton files reconstructed eb: `int` number of bins in energy gb: `int` number of bins in gammaness tb: `int` number of bins in theta2 noff: `float` ratio between the background and the signal region obstime: `Quantity` Observation time in seconds TODO: Give files as input in a configuration file! Returns E: `array` center of energy bins sensitivity: `array` sensitivity per energy bin --------- """ # Read simulated and reconstructed values gammaness_g, theta2_g, e_reco_g, e_true_g, mc_par_g, events_g = process_mc(simtelfile_gammas, dl2_file_g, 'gamma') gammaness_p, angdist2_p, e_reco_p, e_true_p, mc_par_p, events_p = process_mc(simtelfile_protons, dl2_file_p, 'proton') mc_par_g['sim_ev'] = mc_par_g['sim_ev']*nfiles_gammas mc_par_p['sim_ev'] = mc_par_p['sim_ev']*nfiles_protons #Pass units to GeV and cm2 mc_par_g['emin'] = mc_par_g['emin'].to(u.GeV) mc_par_g['emax'] = mc_par_g['emax'].to(u.GeV) mc_par_p['emin'] = mc_par_p['emin'].to(u.GeV) mc_par_p['emax'] = mc_par_p['emax'].to(u.GeV) mc_par_g['area_sim'] = mc_par_g['area_sim'].to(u.cm**2) mc_par_p['area_sim'] = mc_par_p['area_sim'].to(u.cm**2) #Set binning for sensitivity calculation emin_sens = 10**1 * u.GeV #mc_par_g['emin'] emax_sens = 10**5 * u.GeV #mc_par_g['emax'] E = np.logspace(np.log10(emin_sens.to_value()), np.log10(emax_sens.to_value()), eb + 1) * u.GeV #Number of simulated events per energy bin """ bins, n_sim_bin = power_law_integrated_distribution(emin_sens.to_value(), emax_sens.to_value(), mc_par_g['sim_ev'], mc_par_g['sp_idx'], eb+1) """ # Extract spectral parameters dFdE, crab_par = crab_hegra(E) dFdEd0, proton_par = proton_bess(E) bins = np.logspace(np.log10(emin_sens.to_value()), np.log10(emax_sens.to_value()), eb+1) y0 = mc_par_g['sim_ev'] / (mc_par_g['emax'].to_value()**(mc_par_g['sp_idx'] + 1) \ - mc_par_g['emin'].to_value()**(mc_par_g['sp_idx'] + 1)) \ * (mc_par_g['sp_idx'] + 1) y = y0 * (bins[1:]**(crab_par['alpha'] + 1) - bins[:-1]**(crab_par['alpha'] + 1)) / (crab_par['alpha'] + 1) n_sim_bin = y # Rates and weights rate_g = rate(mc_par_g['emin'], mc_par_g['emax'], crab_par['alpha'], mc_par_g['cone'], mc_par_g['area_sim'], crab_par['f0'], crab_par['e0']) rate_p = rate(mc_par_p['emin'], mc_par_p['emax'], proton_par['alpha'], mc_par_p['cone'], mc_par_p['area_sim'], proton_par['f0'], proton_par['e0']) w_g = weight(mc_par_g['emin'], mc_par_g['emax'], mc_par_g['sp_idx'], crab_par['alpha'], rate_g, mc_par_g['sim_ev'], crab_par['e0']) w_p = weight(mc_par_p['emin'], mc_par_p['emax'], mc_par_p['sp_idx'], proton_par['alpha'], rate_p, mc_par_p['sim_ev'], proton_par['e0']) e_reco_gw = ((e_reco_g / crab_par['e0'])**(crab_par['alpha'] - mc_par_g['sp_idx'])) \ * w_g e_reco_pw = ((e_reco_p / proton_par['e0'])**(proton_par['alpha'] - mc_par_p['sp_idx'])) \ * w_p p_contained, ang_area_p = ring_containment(angdist2_p, 0.4 * u.deg, 0.2 * u.deg) # FIX: ring_radius and ring_halfwidth should have units of deg # FIX: hardcoded at the moment, but ring_radius should be read from # the gamma file (point-like) or given as input (diffuse). # FIX: ring_halfwidth should be given as input area_ratio_p = np.pi * tcut / ang_area_p # ratio between the area where we search for protons ang_area_p # and the area where we search for gammas math.pi * t # Arrays to contain the number of gammas and hadrons for different cuts final_gamma = np.ndarray(shape=(eb)) final_hadrons = np.ndarray(shape=(eb)) pre_gamma = np.ndarray(shape=(eb)) pre_hadrons = np.ndarray(shape=(eb)) ngamma_per_ebin = np.ndarray(eb) nhadron_per_ebin = np.ndarray(eb) # Weight events and count number of events per bin: for i in range(0,eb): # binning in energy eg_w_sum = np.sum(e_reco_gw[(e_reco_g < E[i+1]) & (e_reco_g > E[i]) \ & (gammaness_g > gcut[i]) & (theta2_g < tcut[i])]) ep_w_sum = np.sum(e_reco_pw[(e_reco_p < E[i+1]) & (e_reco_p > E[i]) \ & (gammaness_p > gcut[i]) & p_contained]) final_gamma[i] = eg_w_sum * obstime final_hadrons[i] = ep_w_sum * obstime * area_ratio_p[i] pre_gamma[i] = e_reco_g[(e_reco_g < E[i+1]) & (e_reco_g > E[i]) \ & (gammaness_g > gcut[i]) & (theta2_g < tcut[i])].shape[0] pre_hadrons[i] = e_reco_p[(e_reco_p < E[i+1]) & (e_reco_p > E[i]) \ & (gammaness_p > gcut[i]) & p_contained].shape[0] ngamma_per_ebin[i] = np.sum(e_reco_gw[(e_reco_g < E[i+1]) & (e_reco_g > E[i])]) * obstime nhadron_per_ebin[i] = np.sum(e_reco_pw[(e_reco_p < E[i+1]) & (e_reco_p > E[i])]) * obstime nex_5sigma, sens = calculate_sensitivity_lima_1d(final_gamma, final_hadrons * noff, 1/noff, eb) # Avoid bins which are empty or have too few events: min_num_events = 10 min_pre_events = 10 # Minimum number of gamma and proton events in a bin to be taken into account for minimization for i in range(0, eb): conditions = (not np.isfinite(sens[i])) or (sens[i]<=0) \ or (final_hadrons[i] < min_num_events) \ or (pre_gamma[i] < min_pre_events) \ or (pre_hadrons[i] < min_pre_events) if conditions: sens[i] = np.inf #Quantities to show in the results sensitivity = np.ndarray(shape=eb) nex_min = np.ndarray(shape=eb) eff_g = np.ndarray(shape=eb) eff_p = np.ndarray(shape=eb) ngammas = np.ndarray(shape=eb) nhadrons = np.ndarray(shape=eb) gammarate = np.ndarray(shape=eb) hadronrate = np.ndarray(shape=eb) eff_area = np.ndarray(shape=eb) nevents_gamma = np.ndarray(shape=eb) nevents_proton = np.ndarray(shape=eb) # Calculate the minimum sensitivity per energy bin for i in range(0,eb): ngammas[i] = final_gamma[i] nhadrons[i] = final_hadrons[i] gammarate[i] = final_gamma[i]/(obstime.to(u.min)).to_value() hadronrate[i] = final_hadrons[i]/(obstime.to(u.min)).to_value() nex_min[i] = nex_5sigma[i] sensitivity[i] = sens[i] eff_g[i] = final_gamma[i]/ngamma_per_ebin[i] eff_p[i] = final_hadrons[i]/nhadron_per_ebin[i] e_aftercuts = e_true_g[(e_true_g < E[i+1]) & (e_true_g > E[i]) \ & (gammaness_g > gcut[i]) & (theta2_g < tcut[i])] e_aftercuts_p = e_true_p[(e_true_p < E[i+1]) & (e_true_p > E[i]) \ & (gammaness_p > gcut[i]) & p_contained] e_aftercuts_w = np.sum(np.power(e_aftercuts, crab_par['alpha']-mc_par_g['sp_idx'])) e_w = np.sum(np.power(e_true_g[(e_true_g < E[i+1]) & (e_true_g > E[i])], crab_par['alpha']-mc_par_g['sp_idx'])) eff_area[i] = e_aftercuts_w.to_value() / n_sim_bin[i] * mc_par_g['area_sim'].to(u.m**2).to_value() nevents_gamma[i] = e_aftercuts.shape[0] nevents_proton[i] = e_aftercuts_p.shape[0] #Compute sensitivity in flux units emed = np.sqrt(E[1:] * E[:-1]) dFdE, par = crab_magic(emed) sens_flux = sensitivity / 100 * (dFdE * emed * emed).to(u.erg / (u.cm**2 * u.s)) list_of_tuples = list(zip(E[:E.shape[0]-2].to_value(), E[1:].to_value(), gcut, tcut, ngammas, nhadrons, gammarate, hadronrate, nex_min, sens_flux.to_value(), eff_area, eff_g, eff_p, nevents_gamma, nevents_proton)) result = pd.DataFrame(list_of_tuples, columns=['ebin_low', 'ebin_up', 'gammaness_cut', 'theta2_cut', 'n_gammas', 'n_hadrons', 'gamma_rate', 'hadron_rate', 'nex_min', 'sensitivity','eff_area', 'eff_gamma', 'eff_hadron', 'nevents_g', 'nevents_p']) units = [E.unit, E.unit,"", tcut.unit,"", "", u.min**-1, u.min**-1, "", sens_flux.unit, mc_par_g['area_sim'].to(u.m**2).unit, "", "", "", ""] """ sens_minimization_plot(eb, gb, tb, E, sens) plot_positions_survived_events(events_g, events_p, gammaness_g, gammaness_p, theta2_g, p_contained, sens, E, eb, gcut, tcut) """ # Build dataframe of events that survive the cuts: events = pd.concat((events_g, events_p)) dl2 = pd.DataFrame(columns=events.keys()) for i in range(0,eb): df_bin = events[(10**events.mc_energy < E[i+1]) & (10**events.mc_energy > E[i]) \ & (events.gammaness > gcut[i]) & (events.theta2 < tcut[i])] dl2 = pd.concat((dl2, df_bin)) return E, sensitivity, result, units, dl2