def get_combined_xsec(fpath, ver=None): """Load the cross-section values from a ROOT file and instantiate a CombinedSpline object.""" # NOTE: ROOT import here as it is optional but still want to import # module for e.g. building docs import ROOT fpath = find_resource(fpath) logging.info('Loading GENIE ROOT cross-section file %s', fpath) # Name of neutrino flavours in the ROOT file. flavs = ('nu_e', 'nu_mu', 'nu_tau', 'nu_e_bar', 'nu_mu_bar', 'nu_tau_bar') rfile = ROOT.TFile.Open(fpath, 'read') # pylint: disable=no-member xsec_splines = FlavIntData() for flav in flavs: for int_ in ALL_NUINT_TYPES: xsec_splines[flav, int_] = {} for part in ('O16', 'H1'): str_repr = flav + '_' + part + '/' + 'tot_' + str(int_) xsec_splines[flav + str(int_)][part] = \ ROOT.gDirectory.Get(str_repr) # pylint: disable=no-member rfile.Close() def eval_spl(spline, binning, out_units=ureg.m**2, x_energy_scale=1, **kwargs): init_names = ['true_energy'] init_units = [ureg.GeV] if set(binning.names) != set(init_names): raise ValueError('Input binning names {0} does not match ' 'instantiation binning names ' '{1}'.format(binning.names, init_names)) if set(map(str, binning.units)) != set(map(str, init_units)): for name in init_names: binning[name].to(init_units) bin_centers = [x.m for x in binning.weighted_centers][0] nu_O16, nu_H1 = [], [] for e_val in bin_centers: nu_O16.append(spline['O16'].Eval(e_val)) nu_H1.append(spline['H1'].Eval(e_val)) nu_O16, nu_H1 = map(np.array, (nu_O16, nu_H1)) nu_xsec = ((0.8879 * nu_O16) + (0.1121 * nu_H1)) * 1E-38 * ureg.cm**2 nu_xsec_hist = nu_xsec.to(out_units).magnitude return Map(hist=nu_xsec_hist, binning=binning, **kwargs) def validate_spl(binning): if np.all(binning.true_energy.midpoints.m > 1E3): raise ValueError('Energy value {0} out of range in array ' '{0}'.format(binning.true_energy)) inXSec = [] for flav in flavs: for int_ in ALL_NUINT_TYPES: flavint = NuFlavInt(flav + str(int_)) xsec = Spline(name=str(flavint), spline=xsec_splines[flavint], eval_spl=eval_spl, validate_spl=validate_spl) inXSec.append(xsec) return CombinedSpline(inXSec, interactions=True, ver=ver)
def test_Events(): """Unit tests for Events class""" from pisa.utils.flavInt import NuFlavInt # Instantiate empty object events = Events() # Instantiate from PISA events HDF5 file events = Events( 'events/events__vlvnt__toy_1_to_80GeV_spidx1.0_cz-1_to_1_1e2evts_set0__unjoined__with_fluxes_honda-2015-spl-solmin-aa.hdf5' ) # Apply a simple cut events = events.applyCut('(true_coszen <= 0.5) & (true_energy <= 70)') for fi in events.flavints: assert np.max(events[fi]['true_coszen']) <= 0.5 assert np.max(events[fi]['true_energy']) <= 70 # Apply an "inbounds" cut via a OneDimBinning true_e_binning = OneDimBinning(name='true_energy', num_bins=80, is_log=True, domain=[10, 60] * ureg.GeV) events = events.keepInbounds(true_e_binning) for fi in events.flavints: assert np.min(events[fi]['true_energy']) >= 10 assert np.max(events[fi]['true_energy']) <= 60 # Apply an "inbounds" cut via a MultiDimBinning true_e_binning = OneDimBinning(name='true_energy', num_bins=80, is_log=True, domain=[20, 50] * ureg.GeV) true_cz_binning = OneDimBinning(name='true_coszen', num_bins=40, is_lin=True, domain=[-0.8, 0]) mdb = MultiDimBinning([true_e_binning, true_cz_binning]) events = events.keepInbounds(mdb) for fi in events.flavints: assert np.min(events[fi]['true_energy']) >= 20 assert np.max(events[fi]['true_energy']) <= 50 assert np.min(events[fi]['true_coszen']) >= -0.8 assert np.max(events[fi]['true_coszen']) <= 0 # Now try to apply a cut that fails on one flav/int (since the field will # be missing) and make sure that the cut did not get applied anywhere in # the end (i.e., it is rolled back) sub_evts = events['nutaunc'] sub_evts.pop('true_energy') events['nutaunc'] = sub_evts try: events = events.applyCut('(true_energy >= 30) & (true_energy <= 40)') except Exception: pass else: raise Exception('Should not have been able to apply the cut!') for fi in events.flavints: if fi == NuFlavInt('nutaunc'): continue assert np.min(events[fi]['true_energy']) < 30 logging.info( '<< PASS : test_Events >> (note:' ' "[ ERROR] Events object is in an inconsistent state. Reverting cut' ' for all flavInts." message above **is expected**.)')
def _compute_nominal_transforms(self): """Compute cross-section transforms.""" logging.info('Updating xsec.genie cross-section histograms...') self.load_xsec_splines() livetime = self._ev_param(self.params['livetime'].value) ice_p = self._ev_param(self.params['ice_p'].value) fid_vol = self._ev_param(self.params['fid_vol'].value) mr_h20 = self._ev_param(self.params['mr_h20'].value) x_energy_scale = self.params['x_energy_scale'].value input_binning = self.input_binning ebins = input_binning.true_energy for idx, name in enumerate(input_binning.names): if 'true_energy' in name: e_idx = idx xsec_transforms = {} for flav in self.input_names: for int_ in ALL_NUINT_TYPES: flavint = flav + '_' + str(int_) logging.debug('Obtaining cross-sections for %s', flavint) xsec_map = self.xsec.get_map(flavint, MultiDimBinning([ebins]), x_energy_scale=x_energy_scale) def func(idx): if idx == e_idx: return xsec_map.hist return tuple(range(input_binning.shape[idx])) num_dims = input_binning.num_dims xsec_trns = np.meshgrid(*map(func, range(num_dims)), indexing='ij')[e_idx] xsec_trns *= (livetime * fid_vol * (ice_p / mr_h20) * (6.022140857e+23 / ureg.mol)) xsec_transforms[NuFlavInt(flavint)] = xsec_trns nominal_transforms = [] for flavint_group in self.transform_groups: flav_names = [str(flav) for flav in flavint_group.flavs] for input_name in self.input_names: if input_name not in flav_names: continue xform_array = [] for flavint in flavint_group.flavints: if flavint in xsec_transforms: xform_array.append(xsec_transforms[flavint]) xform_array = reduce(add, xform_array) xform = BinnedTensorTransform( input_names=input_name, output_name=str(flavint_group), input_binning=input_binning, output_binning=self.output_binning, xform_array=xform_array) nominal_transforms.append(xform) return TransformSet(transforms=nominal_transforms)