class AeffServiceMC: ''' Takes the weighted effective area files, and creates a dictionary of the 2D effective area in terms of energy and coszen, for each flavor (nue,nue_bar,numu,...) and interaction type (CC, NC) ''' def __init__(self, ebins, czbins, aeff_weight_file=None, **kwargs): self.ebins = ebins self.czbins = czbins logging.info('Initializing AeffServiceMC...') logging.info('Opening file: %s' % (aeff_weight_file)) try: fh = h5py.File(find_resource(aeff_weight_file), 'r') except IOError, e: logging.error("Unable to open aeff_weight_file %s" % aeff_weight_file) logging.error(e) sys.exit(1) self.aeff_dict = {} logging.info("Creating effective area dict...") for flavor in [ 'nue', 'nue_bar', 'numu', 'numu_bar', 'nutau', 'nutau_bar' ]: flavor_dict = {} logging.debug("Working on %s effective areas" % flavor) for int_type in ['cc', 'nc']: weighted_aeff = np.array(fh[flavor + '/' + int_type + '/weighted_aeff']) true_energy = np.array(fh[flavor + '/' + int_type + '/true_energy']) true_coszen = np.array(fh[flavor + '/' + int_type + '/true_coszen']) bins = (self.ebins, self.czbins) aeff_hist, _, _ = np.histogram2d(true_energy, true_coszen, weights=weighted_aeff, bins=bins) # Divide by bin widths to convert to aeff: ebin_sizes = get_bin_sizes(ebins) czbin_sizes = 2.0 * np.pi * get_bin_sizes(czbins) bin_sizes = np.meshgrid(czbin_sizes, ebin_sizes) aeff_hist /= np.abs(bin_sizes[0] * bin_sizes[1]) flavor_dict[int_type] = aeff_hist self.aeff_dict[flavor] = flavor_dict return
def get_aeff1D(data,cuts_list,ebins,files_per_run,mcnu='MCNeutrino', nc=False,solid_angle=None): ''' Return 1D Aeff directly from simulations (using OneWeight) as a histogram, including the error bars. \params: * data - data table from a hdf5 PyTables file. * cuts_list - np array of indices for events passing selection cuts * ebins - energy bin edges in GeV that the Aeff histogram will be formed from * files_per_run - file number normalization to correctly calculate simulation weight for Aeff. Should be number of simulation files per run for flavour. * mcnu - Monte Carlo neutrino field/key in hdf5 file to use for MC true information. * solid_angle - total solid angle to integrate over. Most of the time, we only calculate Aeff for upgoing events, so we do half the 4pi solid angle of the whole sky, which would be 2.0*np.pi * nc - set this flag to true if we are using NC files. ''' #if not nc: nfiles = len(set(data.root.I3EventHeader.col('Run')))*files_per_run logging.info("runs: %s"%str(set(data.root.I3EventHeader.col('Run')))) logging.info("num runs: %d"%len(set(data.root.I3EventHeader.col('Run')))) total_events = data.root.I3MCWeightDict.col('NEvents')[cuts_list]*nfiles/2.0 # NOTE: solid_angle should be coordinated with get_arb_cuts(cut_sim_down=bool) sim_wt_array = (data.root.I3MCWeightDict.col('OneWeight')[cuts_list]/ total_events/solid_angle) # Not sure why nu_<> cc needs __getattr__ and only NC combined # file needs __getattribute__?? try: egy_array = data.root.__getattr__(mcnu).col('energy')[cuts_list] except: egy_array = data.root.__getattribute__(mcnu).col('energy')[cuts_list] aeff,xedges = np.histogram(egy_array,weights=sim_wt_array,bins=ebins) egy_bin_widths = get_bin_sizes(ebins) aeff /= egy_bin_widths aeff*=1.0e-4 # [cm^2] -> [m^2] unweighted_events,xedges = np.histogram(egy_array,bins=ebins) # So that the error calculation comes out right without divide by zeros... unweighted_events = [1. if val < 1.0 else val for val in unweighted_events] aeff_error = np.divide(aeff,np.sqrt(unweighted_events)) logging.debug("percent error on aeff: %s"%str(np.nan_to_num(aeff/aeff_error))) return aeff,aeff_error,xedges
def get_flux(self, ebins, czbins, prim): '''Get the flux in units [m^-2 s^-1] for the given bin edges in energy and cos(zenith) and the primary.''' #Evaluate the flux at the bin centers evals = get_bin_centers(ebins) czvals = get_bin_centers(czbins) # Get the spline interpolation, which is in # log(flux) as function of log(E), cos(zenith) return_table = bisplev(np.log10(evals), czvals, self.spline_dict[prim]) return_table = np.power(10., return_table).T #Flux is given per sr and GeV, so we need to multiply #by bin width in both dimensions #Get the bin size in both dimensions ebin_sizes = get_bin_sizes(ebins) czbin_sizes = 2.*np.pi*get_bin_sizes(czbins) bin_sizes = np.meshgrid(ebin_sizes, czbin_sizes) return_table *= np.abs(bin_sizes[0]*bin_sizes[1]) return return_table.T
def get_flux(self, ebins, czbins, prim): """Get the flux in units [m^-2 s^-1] for the given bin edges in energy and cos(zenith) and the primary.""" #Evaluate the flux at the bin centers evals = get_bin_centers(ebins) czvals = get_bin_centers(czbins) # Get the spline interpolation, which is in # log(flux) as function of log(E), cos(zenith) return_table = bisplev(np.log10(evals), czvals, self.spline_dict[prim]) return_table = np.power(10., return_table).T #Flux is given per sr and GeV, so we need to multiply #by bin width in both dimensions #Get the bin size in both dimensions ebin_sizes = get_bin_sizes(ebins) czbin_sizes = 2. * np.pi * get_bin_sizes(czbins) bin_sizes = np.meshgrid(ebin_sizes, czbin_sizes) return_table *= np.abs(bin_sizes[0] * bin_sizes[1]) return return_table.T
def _get_reco_kernels(self, flipback=True, e_reco_scale=None, cz_reco_scale=None, **kwargs): """ Use the parametrization functions to calculate the actual reco kernels (i.e. 4D histograms). If flipback==True, the zenith angle part that goes below the zenith will be mirrored back in. """ if all([hasattr(self, 'kernels'), e_reco_scale==1., cz_reco_scale==1.]): logging.info('Using existing kernels for reconstruction') return self.kernels logging.info('Creating parametrized reconstruction kernels') # get binning information evals, esizes = get_bin_centers(self.ebins), get_bin_sizes(self.ebins) czvals, czsizes = get_bin_centers(self.czbins), get_bin_sizes(self.czbins) czbins = self.czbins n_e, n_cz = len(evals), len(czvals) # prepare for folding back at lower edge if not is_linear(self.czbins): logging.warn("cos(zenith) bins have different " "sizes! Unable to fold around edge " "of histogram, will not do that.") flipback = False if flipback: czvals = np.append(czvals-(self.czbins[-1]-self.czbins[0]), czvals) czbins = np.append(czbins[:-1]-(self.czbins[-1]-self.czbins[0]), czbins) czsizes = np.append(czsizes, czsizes) # get properly scaled parametrization, initialize kernels parametrization = self.apply_reco_scales(e_reco_scale, cz_reco_scale) kernel_dict = {} for flavour in parametrization: kernel_dict[flavour] = {} for int_type in ['cc', 'nc']: logging.debug('Calculating parametrized reconstruction kernel for %s %s' %(flavour, int_type)) # create empty kernel kernel = np.zeros((n_e, n_cz, n_e, n_cz)) # quick handle to parametrization e_pars = parametrization[flavour][int_type]['energy'] cz_pars = parametrization[flavour][int_type]['coszen'] # loop over every bin in true (energy, coszen) for (i, j) in itertools.product(range(n_e), range(n_cz)): e_kern_cdf = double_gauss(self.ebins, loc1=e_pars['loc1'][i,j]+evals[i], width1=e_pars['width1'][i,j], loc2=e_pars['loc2'][i,j]+evals[i], width2=e_pars['width2'][i,j], fraction=e_pars['fraction'][i,j]) e_kern_int = np.sum(e_kern_cdf) offset = n_cz if flipback else 0 cz_kern_cdf = double_gauss(czbins, loc1=cz_pars['loc1'][i,j]+czvals[j+offset], width1=cz_pars['width1'][i,j], loc2=cz_pars['loc2'][i,j]+czvals[j+offset], width2=cz_pars['width2'][i,j], fraction=cz_pars['fraction'][i,j]) cz_kern_int = np.sum(cz_kern_cdf) if flipback: # fold back cz_kern_cdf = cz_kern_cdf[:len(czbins)/2][::-1] + cz_kern_cdf[len(czbins)/2:] kernel[i,j] = np.outer(e_kern_cdf, cz_kern_cdf) kernel_dict[flavour][int_type] = copy(kernel) kernel_dict['ebins'] = self.ebins kernel_dict['czbins'] = self.czbins return kernel_dict
def _get_reco_kernels(self, flipback=True, e_reco_scale=None, cz_reco_scale=None, **kwargs): """ Use the parametrization functions to calculate the actual reco kernels (i.e. 4D histograms). If flipback==True, the zenith angle part that goes below the zenith will be mirrored back in. """ if all([ hasattr(self, 'kernels'), e_reco_scale == 1., cz_reco_scale == 1. ]): logging.info('Using existing kernels for reconstruction') return self.kernels logging.info('Creating parametrized reconstruction kernels') # get binning information evals, esizes = get_bin_centers(self.ebins), get_bin_sizes(self.ebins) czvals, czsizes = get_bin_centers(self.czbins), get_bin_sizes( self.czbins) czbins = self.czbins n_e, n_cz = len(evals), len(czvals) # prepare for folding back at lower edge if not is_linear(self.czbins): logging.warn("cos(zenith) bins have different " "sizes! Unable to fold around edge " "of histogram, will not do that.") flipback = False if flipback: czvals = np.append(czvals - (self.czbins[-1] - self.czbins[0]), czvals) czbins = np.append( czbins[:-1] - (self.czbins[-1] - self.czbins[0]), czbins) czsizes = np.append(czsizes, czsizes) # get properly scaled parametrization, initialize kernels parametrization = self.apply_reco_scales(e_reco_scale, cz_reco_scale) kernel_dict = {} for flavour in parametrization: kernel_dict[flavour] = {} for int_type in ['cc', 'nc']: logging.debug( 'Calculating parametrized reconstruction kernel for %s %s' % (flavour, int_type)) # create empty kernel kernel = np.zeros((n_e, n_cz, n_e, n_cz)) # quick handle to parametrization e_pars = parametrization[flavour][int_type]['energy'] cz_pars = parametrization[flavour][int_type]['coszen'] # loop over every bin in true (energy, coszen) for (i, j) in itertools.product(range(n_e), range(n_cz)): e_kern_cdf = double_gauss( self.ebins, loc1=e_pars['loc1'][i, j] + evals[i], width1=e_pars['width1'][i, j], loc2=e_pars['loc2'][i, j] + evals[i], width2=e_pars['width2'][i, j], fraction=e_pars['fraction'][i, j]) e_kern_int = np.sum(e_kern_cdf) offset = n_cz if flipback else 0 cz_kern_cdf = double_gauss( czbins, loc1=cz_pars['loc1'][i, j] + czvals[j + offset], width1=cz_pars['width1'][i, j], loc2=cz_pars['loc2'][i, j] + czvals[j + offset], width2=cz_pars['width2'][i, j], fraction=cz_pars['fraction'][i, j]) cz_kern_int = np.sum(cz_kern_cdf) if flipback: # fold back cz_kern_cdf = cz_kern_cdf[:len(czbins) / 2][::-1] + cz_kern_cdf[ len(czbins) / 2:] kernel[i, j] = np.outer(e_kern_cdf, cz_kern_cdf) kernel_dict[flavour][int_type] = copy(kernel) kernel_dict['ebins'] = self.ebins kernel_dict['czbins'] = self.czbins return kernel_dict