def __init__(self, costh, pmodel=(pm.HillasGaisser2012, 'H3a'), hadr='SIBYLL2.3c', barr_mods=(), depth=1950*Units.m, density=('CORSIKA', ('SouthPole', 'December')), debug_level=1): """Initializes the nuVeto object for a particular costheta, CR Flux, hadronic model, barr parameters, and depth Note: A separate MCEq instance needs to be created for each combination of __init__'s arguments. To access pmodel and hadr, use mceq.pm_params and mceq.yields_params Args: costh (float): Cos(theta), the cosine of the neutrino zenith at the detector pmodel (tuple(CR model class, arguments)): CR Flux hadr (str): hadronic interaction model barr_mods: barr parameters depth (float): the depth at which the veto probability is computed below the ice """ self.costh = costh self.pmodel = pmodel self.geom = Geometry(depth) theta = np.degrees(np.arccos(self.geom.cos_theta_eff(self.costh))) config.debug_level = debug_level # config.enable_em = False config.enable_muon_energy_loss = False config.return_as = 'total energy' config.adv_set['allowed_projectiles'] = [2212, 2112, 211, -211, 321, -321, 130, -2212, -2112]#, 11, 22] config.ctau = 2.5 self.mceq = MCEqRun( # provide the string of the interaction model interaction_model=hadr, # primary cosmic ray flux model # support a tuple (primary model class (not instance!), arguments) primary_model=pmodel, # zenith angle \theta in degrees, measured positively from vertical direction at surface theta_deg=theta, # atmospheric density model density_model=density) if len(barr_mods) > 0: for barr_mod in barr_mods: # Modify proton-air -> mod[0] self.mceq.set_mod_pprod(2212, BARR[barr_mod[0]].pdg, barr_unc, barr_mod) # Populate the modifications to the matrices by re-filling the interaction matrix self.mceq.regenerate_matrices(skip_decay_matrix=True) X_vec = np.logspace(np.log10(2e-3), np.log10(self.mceq.density_model.max_X), 12) self.dX_vec = np.diff(X_vec) self.X_vec = 10**centers(np.log10(X_vec))
def __init__(self, costh, pmodel=(pm.HillasGaisser2012, 'H3a'), hadr='SIBYLL2.3c', barr_mods=(), depth=1950 * Units.m, density=('CORSIKA', ('SouthPole', 'June'))): """Initializes the nuVeto object for a particular costheta, CR Flux, hadronic model, barr parameters, and depth Note: A separate MCEq instance needs to be created for each combination of __init__'s arguments. To access pmodel and hadr, use mceq.pm_params and mceq.yields_params Args: costh (float): Cos(theta), the cosine of the neutrino zenith at the detector pmodel (tuple(CR model class, arguments)): CR Flux hadr (str): hadronic interaction model barr_mods: barr parameters depth (float): the depth at which the veto probability is computed below the ice """ self.costh = costh self.pmodel = pmodel self.geom = Geometry(depth) theta = np.degrees(np.arccos(self.geom.cos_theta_eff(self.costh))) MCEq.core.dbg = 0 MCEq.kernels.dbg = 0 MCEq.density_profiles.dbg = 0 MCEq.data.dbg = 0 self.mceq = MCEqRun( # provide the string of the interaction model interaction_model=hadr, # atmospheric density model density_model=density, # primary cosmic ray flux model # support a tuple (primary model class (not instance!), arguments) primary_model=pmodel, # zenith angle \theta in degrees, measured positively from vertical direction theta_deg=theta, enable_muon_energy_loss=False, **mceq_config_without(['enable_muon_energy_loss', 'density_model'])) for barr_mod in barr_mods: # Modify proton-air -> mod[0] self.mceq.set_mod_pprod(2212, BARR[barr_mod[0]].pdg, barr_unc, barr_mod) # Populate the modifications to the matrices by re-filling the interaction matrix self.mceq._init_default_matrices(skip_D_matrix=True) X_vec = np.logspace(np.log10(2e-3), np.log10(self.mceq.density_model.max_X), 12) self.dX_vec = np.diff(X_vec) self.X_vec = 10**centers(np.log10(X_vec))
def test_some_angles(): import mceq_config as config from MCEq.core import MCEqRun import crflux.models as pm import numpy as np config.debug_level = 5 config.kernel_config = 'numpy' config.cuda_gpu_id = 0 config.mkl_threads = 2 mceq = MCEqRun(interaction_model='SIBYLL23C', theta_deg=0., primary_model=(pm.HillasGaisser2012, 'H3a')) nmu = [] for theta in [0., 30., 60., 90]: mceq.set_theta_deg(theta) mceq.solve() nmu.append( np.sum( mceq.get_solution('mu+', 0, integrate=True) + mceq.get_solution('mu-', 0, integrate=True))) print(nmu) assert np.allclose(nmu, [ 59787.31805017808, 60908.05990627792, 66117.91267025097, 69664.26521920023 ])
def __init__(self, interaction_model='SIBYLL23C', theta_angles=np.rad2deg(np.arccos(np.linspace(0.5,0,3))), ): r''' ''' self._mceq = MCEqRun( interaction_model=interaction_model, theta_deg=0., primary_model=(pm.GlobalSplineFitBeta, '/Users/mhuber/AtmosphericShowers/Data/GSF_spline_20171007.pkl.bz2') ) self.e_grid = self._mceq.e_grid # get the flux estimates self.flux_keys = ['numu_conv','numu_pr','numu_total', 'mu_conv','mu_pr','mu_total', 'nue_conv','nue_pr','nue_total', 'nutau_pr'] self.fluxes = self._calc_fluxes(theta_angles) self.flux_tcks = dict()
def run_MCEq( primary_model, interaction_model="SIBYLL2.3c", density_profiles=[ ("MSIS00_IC", ("SouthPole", "January")), ("MSIS00_IC", ("SouthPole", "July")), ], particle_ids=["total_numu", "total_antinumu"], cosz_lim=[-1.0, 1.0], cosz_steps=50, emag=3, ): # define equidistant grid in cos(theta) with cosz_steps steps theta_grid = np.arccos(np.linspace(cosz_lim[0], cosz_lim[1], cosz_steps)) theta_grid *= 180.0 / np.pi # temporarily result dict flux_for_density = {} ## loop over all density profiles #for density in density_profiles: for density in tqdm(density_profiles, desc="Density"): print "=" * 60 print "Current atmosphere model:", density[0], "--", density[1][ 0], density[1][1] print "-" * 60 # set atmosphere model string for result dictionary if density[1][1] is not None: density_str = density[0] + density[1][0] + density[1][1] else: density_str = density[0] + density[1][0] # update mceq_config with the current atmosphere model config["density_model"] = density # create instance of MCEqRun class mceq_run = MCEqRun( interaction_model=interaction_model, primary_model=primary_model, theta_deg=0.0, # updated later **config) # obtain energy grid (fixed) of the solution for the x-axis of the plots e_grid = mceq_run.e_grid # update dictionary flux_for_density[density_str] = {} for flux_str in particle_ids: flux_for_density[density_str][flux_str] = np.zeros( (len(theta_grid), len(e_grid))) ## loop over all theta bins #for theta_id, theta in enumerate(theta_grid): for theta_id, theta in enumerate(tqdm(theta_grid, desc="Theta")): print "-" * 60 print "Current theta:", theta # Set/update the zenith angle mceq_run.set_theta_deg(theta) # Run the solver mceq_run.solve() # get fluxes flux_solutions = get_solutions(mceq_run, particle_ids, mag=emag) # store fluxes in result dictionary' for flux_str in particle_ids: flux_for_density[density_str][flux_str][ theta_id, :] = flux_solutions[flux_str] #print flux_for_density[density_str][flux_str][theta_id,:] # average density models: fluxes = {} for flux_str in particle_ids: fluxes[flux_str] = np.zeros((len(theta_grid), len(e_grid))) for flux_str in particle_ids: for density in flux_for_density.keys(): # loop over all density models fluxes[flux_str] += flux_for_density[density][flux_str] fluxes[flux_str] /= len(flux_for_density.keys()) * 1.0 # add e_grid and theta_grid #fluxes["e_grid"] = e_grid #fluxes["theta_grid"] = theta_grid return fluxes
def get_angle_flux(angle, mag=0): """ angle should be in degrees! returns a dicitionary with the energies and the fluxes for each neutrino type """ if not (isinstance(angle, float) or isinstance(angle, int)): raise TypeError("Arg 'angle' should be {}, got {}".format( float, type(angle))) if not (angle <= 180. and angle >= 0.): raise ValueError("Invalid zenith angle {} deg".format(angle)) flux = {} mceq = MCEqRun( interaction_model='SIBYLL23C', primary_model=(HawkBPL, 0.), # primary_model = (crf.HillasGaisser2012, 'H3a'), theta_deg=angle) mceq.solve() flux['e_grid'] = mceq.e_grid flux['nue_flux'] = mceq.get_solution('nue', mag) + mceq.get_solution( 'pr_nue', mag) flux['nue_bar_flux'] = mceq.get_solution( 'antinue', mag) + mceq.get_solution('pr_antinue', mag) flux['numu_flux'] = mceq.get_solution('numu', mag) + mceq.get_solution( 'pr_numu', mag) flux['numu_bar_flux'] = mceq.get_solution( 'antinumu', mag) + mceq.get_solution('pr_antinumu', mag) flux['nutau_flux'] = mceq.get_solution('nutau', mag) + mceq.get_solution( 'pr_nutau', mag) flux['nutau_bar_flux'] = mceq.get_solution( 'antinutau', mag) + mceq.get_solution('pr_antinutau', mag) obj = open("temp_mceq_flux.dat".format(angle), 'w') # obj.write("# E[Gev] Phi_nue[Gev/cm2/s/sr] Phi_numu[Gev/cm2/s/sr] Phi_nutau[Gev/cm2/s/sr] Phi_nue_bar Phi_numu_bar Phi_nutau_bar\n") for i in range(len(flux['e_grid'])): obj.write(str(flux['e_grid'][i])) obj.write(' ') obj.write(str(flux['nue_flux'][i])) obj.write(' ') obj.write(str(flux['numu_flux'][i])) obj.write(' ') obj.write(str(flux['nutau_flux'][i])) obj.write(' ') obj.write(str(flux['nue_bar_flux'][i])) obj.write(' ') obj.write(str(flux['numu_bar_flux'][i])) obj.write(' ') obj.write(str(flux['nutau_bar_flux'][i])) obj.write('\n') obj.close()
e = numpy.sqrt(p**2 + m**2) - m # Kinetic energy (GeV) j = (e + m) / p # Jacobian factor for going from dphi / dp # to dphi / dE (almost 1 ...) f = (data[:, 3] + data[:, 7]) * j # Flux (1/(GeV m^2 s sr)) df = numpy.sqrt(data[:, 4]**2 + data[:, 5]**2 + # Flux uncertainty data[:, 8]**2 + data[:, 9]**2) * j return ExperimentalData(e, f * 1E-04, df * 1E-04) bess = load_bess('BESS_TEV.txt') # Simulate the flux using MCEq mceq = MCEqRun(interaction_model='SIBYLL23C', primary_model=(crf.GlobalSplineFitBeta, None), density_model=('MSIS00', ('Tokyo', 'October')), theta_deg=0) cos_theta = 0.95 theta = numpy.arccos(cos_theta) * 180 / numpy.pi mceq.set_theta_deg(theta) altitude = numpy.array((30., )) X_grid = mceq.density_model.h2X(altitude * 1E+02) def weight(xmat, egrid, name, c): return (1 + c) * numpy.ones_like(xmat) mceq.set_mod_pprod(2212, 211, weight, ('a', 0.141)) # Coefficients taken
def _compute_outputs(self, inputs=None): """Compute histograms for output channels.""" logging.debug('Entering mceq._compute_outputs') primary_model = split(self.params['primary_model'].value, ',') if len(primary_model) != 2: raise ValueError('primary_model is not of length 2, instead is of ' 'length {0}'.format(len(primary_model))) primary_model[0] = eval('pm.' + primary_model[0]) density_model = (self.params['density_model'].value, (self.params['location'].value, self.params['season'].value)) mceq_run = MCEqRun( interaction_model=str(self.params['interaction_model'].value), primary_model=primary_model, theta_deg=0.0, density_model=density_model, **mceq_config.mceq_config_without(['density_model'])) # Power of energy to scale the flux (the results will be returned as E**mag * flux) mag = 0 # Obtain energy grid (fixed) of the solution for the x-axis of the plots e_grid = mceq_run.e_grid # Dictionary for results flux = OrderedDict() for nu in self.output_names: flux[nu] = [] binning = self.output_binning cz_binning = binning.dims[binning.index('coszen', use_basenames=True)] en_binning = binning.dims[binning.index('energy', use_basenames=True)] cz_centers = cz_binning.weighted_centers.m angles = (np.arccos(cz_centers) * ureg.radian).m_as('degrees') for theta in angles: mceq_run.set_theta_deg(theta) mceq_run.solve() flux['nue'].append(mceq_run.get_solution('total_nue', mag)) flux['nuebar'].append(mceq_run.get_solution('total_antinue', mag)) flux['numu'].append(mceq_run.get_solution('total_numu', mag)) flux['numubar'].append(mceq_run.get_solution( 'total_antinumu', mag)) for nu in flux.iterkeys(): flux[nu] = np.array(flux[nu]) smoothing = self.params['smoothing'].value.m en_centers = en_binning.weighted_centers.m_as('GeV') spline_flux = self.bivariate_spline(flux, cz_centers, e_grid, smooth=smoothing) ev_flux = self.bivariate_evaluate(spline_flux, cz_centers, en_centers) for nu in ev_flux: ev_flux[nu] = ev_flux[nu] * ureg('cm**-2 s**-1 sr**-1 GeV**-1') mapset = [] for nu in ev_flux.iterkeys(): mapset.append(Map(name=nu, hist=ev_flux[nu], binning=binning)) return MapSet(mapset)
def generate_table(interaction_model=None, primary_model=None, density_model=None): interaction_model = interaction_model or 'SIBYLL23C' primary_model = primary_model or 'H3a' density_model = density_model or 'USStd' tag = '-'.join((interaction_model.lower(), primary_model.lower(), density_model.lower())) weights = None if interaction_model == 'YFM': # Use weights from Yanez et al., 2019 (https://arxiv.org/abs/1909.08365) interaction_model = 'SIBYLL23C' weights = {211: 0.141, -211: 0.116, 321: 0.402, -321: 0.583} if primary_model == 'GSF': primary_model = (crf.GlobalSplineFitBeta, None) elif primary_model == 'H3a': primary_model = (crf.HillasGaisser2012, 'H3a') elif primary_model == 'PolyGonato': primary_model = (crf.PolyGonato, None) else: raise ValueError(f'Invalid primary model: {primary_model}') if density_model == 'USStd': density_model = ('CORSIKA', ('USStd', None)) elif density_model.startswith('MSIS00'): density_model = ('MSIS00', density_model.split('-')[1:]) else: raise ValueError(f'Invalid density model: {density_model}') config.e_min = 1E-01 config.enable_default_tracking = False config.enable_muon_energy_loss = True mceq = MCEqRun(interaction_model=interaction_model, primary_model=primary_model, density_model=density_model, theta_deg=0) if weights: def weight(xmat, egrid, name, c): return (1 + c) * numpy.ones_like(xmat) for pid, w in weights.items(): mceq.set_mod_pprod(2212, pid, weight, ('a', w)) mceq.regenerate_matrices(skip_decay_matrix=True) energy = mceq.e_grid cos_theta = numpy.linspace(0, 1, 51) altitude = numpy.linspace(0, 9E+03, 10) data = numpy.zeros((altitude.size, cos_theta.size, energy.size, 2)) for ic, ci in enumerate(cos_theta): print(f'processing {ci:.2f}') theta = numpy.arccos(ci) * 180 / numpy.pi mceq.set_theta_deg(theta) X_grid = mceq.density_model.h2X(altitude[::-1] * 1E+02) mceq.solve(int_grid=X_grid) for index, _ in enumerate(altitude): mu_m = mceq.get_solution('mu-', grid_idx=index) * 1E+04 mu_p = mceq.get_solution('mu+', grid_idx=index) * 1E+04 K = (mu_m > 0) & (mu_p > 0) data[altitude.size - 1 - index, ic, K, 0] = mu_m[K] data[altitude.size - 1 - index, ic, K, 1] = mu_p[K] # Dump the data grid to a litle endian binary file data = data.astype('f4').flatten() with open(f'data/simulated/flux-mceq-{tag}.table', 'wb') as f: numpy.array((energy.size, cos_theta.size, altitude.size), dtype='i8').astype('<i8').tofile(f) numpy.array((energy[0], energy[-1], cos_theta[0], cos_theta[-1], altitude[0], altitude[-1]), dtype='f8').astype('<f8').tofile(f) data.astype('<f4').tofile(f)
def __get_spline__( interaction_model, primary_model, months, theta_grid, theta_grid_cos, ): """Get MCEq spline for the provided settings Parameters ---------- interaction_model : str The interaction model. This is passed on to `MCEqRun`. primary_model : str The primary model to use. Must be one of: GST_3-gen, GST_4-gen, H3a, H4a, poly-gonato, TIG, ZS, ZSP, GH months : list of str The months for which to solve the cascade equations. These must be provided as a list of month names, e.g. ['January', 'August']. A list of splines will be returned of the same length as `months`. theta_grid : array_like The grid points in theta to evaluate on in degrees. If `theta_grid_cos` is True, this is instead cos(theta). theta_grid_cos : bool If True, `theta_grid` is interpreted as cos(theta), i.e. arccos() is applied first. Returns ------- dict The result of MCEq together with the fitted splines. See documentation of `get_spline()` for more details. Raises ------ AttributeError If the provided `primary_model` is unknown. """ log.info('\tCalculating \'{}\' \'{}\''.format(interaction_model, primary_model)) import mceq_config from MCEq import version from MCEq.core import MCEqRun import crflux.models as pm config_updates = { 'h_obs': 1000., 'debug_level': 1, } if 'MKL_PATH' in os.environ: config_updates['MKL_path'] = os.environ['MKL_PATH'] splines = {} pmodels = { "GST_3-gen": (pm.GaisserStanevTilav, "3-gen"), "GST_4-gen": (pm.GaisserStanevTilav, "4-gen"), "H3a": (pm.HillasGaisser2012, "H3a"), "H4a": (pm.HillasGaisser2012, "H4a"), "poly-gonato": (pm.PolyGonato, False), "TIG": (pm.Thunman, None), "ZS": (pm.ZatsepinSokolskaya, 'default'), "ZSP": (pm.ZatsepinSokolskaya, 'pamela'), "GH": (pm.GaisserHonda, None), } for i, month in enumerate(months): config_updates['density_model'] = ('MSIS00_IC', ('SouthPole', month)) # update settings in mceq_config # Previous method mceq_config.config is deprecated and resulted # in pickle errors for deepcopy. for name, value in config_updates.items(): setattr(mceq_config, name, value) try: pmodel = pmodels[primary_model] except KeyError: raise AttributeError( 'primary_model {} unknown. options: {}'.format( primary_model, pmodels.keys())) mceq_run = MCEqRun(interaction_model=interaction_model, primary_model=pmodel, theta_deg=0.0, **config_updates) e_grid = np.log10(deepcopy(mceq_run.e_grid)) spline_dicts, flux_dicts = __solve_month__(mceq_run, e_grid, theta_grid, theta_grid_cos) splines[i] = {} splines[i]['total_spline_dict'] = spline_dicts[0] splines[i]['conv_spline_dict'] = spline_dicts[1] splines[i]['pr_spline_dict'] = spline_dicts[2] splines[i]['total_flux_dict'] = flux_dicts[0] splines[i]['conv_flux_dict'] = flux_dicts[1] splines[i]['pr_flux_dict'] = flux_dicts[2] splines[i]['config_updates'] = deepcopy(config_updates) splines[i]['mceq_version'] = version.__version__ splines[i]['ic3_labels_version'] = ic3_labels.__version__ splines[i]['e_grid'] = e_grid splines[i]['theta_grid'] = theta_grid return splines
def get_initial_state(energies, zeniths, n_nu, kwargs): """ This either loads the initial state, or generates it. Loading it is waaaay quicker. Possible issue! If you run a bunch of jobs and don't already have this flux generated, bad stuff can happen. I'm imagining issues where a bunch of jobs waste time making this, and then all try to write to the same file Very bad. Big crash. Very Fail """ path = os.path.join(config["datapath"], config["mceq_flux"]) if os.path.exists(path): # print("Loading MCEq Flux") f = open(path, 'rb') inistate = pickle.load(f) f.close() else: # print("Generating MCEq Flux") inistate = np.zeros(shape=(angular_bins, energy_bins, 2, n_nu)) mceq = MCEqRun(interaction_model=config["interaction_model"], primary_model=(crf.HillasGaisser2012, 'H3a'), theta_deg=0.) r_e = 6.378e6 # meters ic_depth = 1.5e3 # meters mag = 0. # power energy is raised to and then used to scale the flux for angle_bin in range(angular_bins): # get the MCEq angle from the icecube zenith angle angle_deg = asin( sin(pi - acos(zeniths[angle_bin])) * (r_e - ic_depth) / r_e) angle_deg = angle_deg * 180. / pi if angle_deg > 180.: angle_deg = 180. print("Evaluating {} deg Flux".format(angle_deg)) # for what it's worth, if you try just making a new MCEqRun for each angle, you get a memory leak. # so you need to manually set the angle mceq.set_theta_deg(angle_deg) mceq.solve() flux = {} flux['e_grid'] = mceq.e_grid flux['nue_flux'] = mceq.get_solution( 'nue', mag) + mceq.get_solution('pr_nue', mag) flux['nue_bar_flux'] = mceq.get_solution( 'antinue', mag) + mceq.get_solution('pr_antinue', mag) flux['numu_flux'] = mceq.get_solution( 'numu', mag) + mceq.get_solution('pr_numu', mag) flux['numu_bar_flux'] = mceq.get_solution( 'antinumu', mag) + mceq.get_solution('pr_antinumu', mag) flux['nutau_flux'] = mceq.get_solution( 'nutau', mag) + mceq.get_solution('pr_nutau', mag) flux['nutau_bar_flux'] = mceq.get_solution( 'antinutau', mag) + mceq.get_solution('pr_antinutau', mag) for neut_type in range(2): for flavor in range(n_nu): flav_key = get_key(flavor, neut_type) if flav_key == "": continue for energy_bin in range(energy_bins): # (account for the difference in units between mceq and nusquids! ) inistate[angle_bin][energy_bin][neut_type][ flavor] = get_closest( energies[energy_bin] / un.GeV, flux['e_grid'], flux[flav_key]) if np.min(inistate) < 0: raise ValueError( "Found negative value in the input from MCEq {}".format( np.min(inistate))) # save it now f = open(path, 'wb') pickle.dump(inistate, f, -1) f.close() return (inistate)
from __future__ import print_function import mceq_config as config from MCEq.core import MCEqRun import crflux.models as pm import numpy as np config.debug_level = 1 config.kernel_config = 'numpy' config.cuda_gpu_id = 0 config.set_mkl_threads(4) mceq = MCEqRun( interaction_model='SIBYLL23C', theta_deg=0., primary_model=(pm.HillasGaisser2012, 'H3a')) def test_config_and_file_download(): import mceq_config as config import os # Import of config triggers data download assert config.mceq_db_fname in os.listdir(config.data_dir) def test_some_angles(): nmu = [] for theta in [0., 30., 60., 90]: mceq.set_theta_deg(theta) mceq.solve()
def make_plots(): Emin = 1 * un.GeV Emax = 10 * un.PeV energies = nsq.logspace(Emin, Emax, 100) angles = nsq.linspace(-0.99, -0.98, 2) # just look at straight up/down # get MCEq flux there mag = 0. angle = 0. #degrees mceq = MCEqRun(interaction_model='SIBYLL23C', primary_model=(crf.HillasGaisser2012, 'H3a'), theta_deg=0.) mceq.solve() n_nu = 3 inistate = np.zeros(shape=(2, len(energies), 2, n_nu)) flux = {} flux['e_grid'] = mceq.e_grid flux['nue_flux'] = mceq.get_solution('nue', mag) + mceq.get_solution( 'pr_nue', mag) flux['nue_bar_flux'] = mceq.get_solution( 'antinue', mag) + mceq.get_solution('pr_antinue', mag) flux['numu_flux'] = mceq.get_solution('numu', mag) + mceq.get_solution( 'pr_numu', mag) flux['numu_bar_flux'] = mceq.get_solution( 'antinumu', mag) + mceq.get_solution('pr_antinumu', mag) flux['nutau_flux'] = mceq.get_solution('nutau', mag) + mceq.get_solution( 'pr_nutau', mag) flux['nutau_bar_flux'] = mceq.get_solution( 'antinutau', mag) + mceq.get_solution('pr_antinutau', mag) # propagate it with nusquids for neut_type in range(2): for flavor in range(n_nu): flav_key = get_key(flavor, neut_type) if flav_key == "": continue for energy_bin in range(len(energies)): inistate[0][energy_bin][neut_type][flavor] = get_closest( energies[energy_bin] / un.GeV, flux['e_grid'], flux[flav_key]) inistate[1][energy_bin][neut_type][flavor] = get_closest( energies[energy_bin] / un.GeV, flux['e_grid'], flux[flav_key]) nus_atm = nsq.nuSQUIDSAtm(angles, energies, n_nu, nsq.NeutrinoType.both, True) nus_atm.Set_MixingAngle(0, 1, 0.563942) nus_atm.Set_MixingAngle(0, 2, 0.154085) nus_atm.Set_MixingAngle(1, 2, 0.785398) nus_atm.Set_SquareMassDifference(1, 7.65e-05) nus_atm.Set_SquareMassDifference(2, 0.00247) nus_atm.SetNeutrinoCrossSections(xs) #settting some zenith angle stuff nus_atm.Set_rel_error(1.0e-6) nus_atm.Set_abs_error(1.0e-6) #nus_atm.Set_GSL_step(gsl_odeiv2_step_rk4) nus_atm.Set_GSL_step(nsq.GSL_STEP_FUNCTIONS.GSL_STEP_RK4) # we load in the initial state. Generating or Loading from a file nus_atm.Set_initial_state(inistate, nsq.Basis.flavor) print("Done setting initial state") # we turn off the progress bar for jobs run on the cobalts nus_atm.Set_ProgressBar(False) nus_atm.Set_IncludeOscillations(True) print("Evolving State") nus_atm.EvolveState() # Evaluate the flux at the energies, flavors, and shit we care about eval_flux = {} for flavor in range(3): for nute in range(2): key = get_key(flavor, nute) if key == "": continue eval_flux[key] = np.zeros(len(energies)) for energy in range(len(energies)): powed = energies[energy] eval_flux[key][energy] = nus_atm.EvalFlavor( flavor, -0.985, powed, nute) # multiply the fluxes with total cross sections at that energy conv_flux = {} for flavor in flavors.keys(): if flavor == "electron": i_flav = 0 elif flavor == "muon": i_flav = 1 else: i_flav = 2 for neut_type in neut_types.keys(): if neut_type == "neutrino": i_neut = 0 else: i_neut = 1 eval_key = get_key(i_flav, i_neut) for current in currents.keys(): conv_key = "_".join([flavor, neut_type, current]) conv_flux[conv_key] = np.zeros(len(energies)) for energy in range(len(energies)): powed = energies[energy] conv_flux[conv_key][ energy] = eval_flux[eval_key][energy] * get_total_flux( powed, flavors[flavor], neut_types[neut_type], currents[current]) # sum up the cascades and compare them with the cross sections casc_fluxes = np.zeros(len(energies)) track_fluxes = np.zeros(len(energies)) for key in conv_flux: if is_cascade(key): casc_fluxes += conv_flux[key] else: track_fluxes += conv_flux[key] plt.plot(energies / un.GeV, casc_fluxes, label="Cascades") plt.plot(energies / un.GeV, track_fluxes, label="Tracks") plt.xscale('log') plt.xlim([10**2, 10**7]) plt.yscale('log') plt.legend() plt.xlabel("Energy [GeV]", size=14) plt.ylabel(r"Flux$\cdot\sigma_{total}$ [s GeV sr]$^{-1}$", size=14) plt.show()
def SetupMCEq(rawpositions, rawdensities, Settings={}): ad = den_p.GeneralizedTarget() densities = [] positions = [] if (rawpositions[0] > 0): positions.append(0) densities.append(rawdensities[0]) for i in range(0, len(rawdensities)): if not np.isnan(rawdensities[i]): densities.append(rawdensities[i]) positions.append(rawpositions[i]) # ad.len_target=positions[-1] ad.set_length(positions[-1] - positions[0]) for i in range(0, len(densities) - 1): ad.add_material(positions[i], densities[i], 'Layer' + str(i)) ad.print_table() if Settings['PrimaryModel'] == 'HillasGaisser_H3a': PrimaryObject = pm.HillasGaisser2012 PrimaryString = 'H3a' if Settings['PrimaryModel'] == 'HillasGaisser_H4a': PrimaryObject = pm.HillasGaisser2012 PrimaryString = 'H4a' if Settings['PrimaryModel'] == 'GaisserHonda': PrimaryObject = pm.GaisserHonda PrimaryString = None if Settings['PrimaryModel'] == 'CombinedGHAndHG_H3a': PrimaryObject = pm.CombinedGHandHG PrimaryString = "H3a" if Settings['PrimaryModel'] == 'CombinedGHAndHG_H4a': PrimaryObject = pm.CombinedGHandHG PrimaryString = "H4a" if Settings['PrimaryModel'] == 'PolyGonato': PrimaryObject = pm.PolyGonato PrimaryString = None if Settings['PrimaryModel'] == 'Thunman': PrimaryObject = pm.Thunman PrimaryString = None if Settings['PrimaryModel'] == 'ZatsepinSokolskaya': PrimaryObject = pm.ZatsepinSokolskaya PrimaryString = None mceq_run = MCEqRun( interaction_model=Settings['HadronicModel'], primary_model=(PrimaryObject, PrimaryString), #Do not provide any default values to avoid unnecessary initilizations theta_deg=0., density_model=('GeneralizedTarget', None), # Expand the rest of parameters **mceq_config_without(['density_model', 'integrator'])) # config['integrator'] = 'odepack' mceq_run.density_model = ad res_group = [ "mu+", "mu-", "pi_mu+", "pi_mu-", "k_mu+", "k_mu-", "pr_mu+", "pr_mu-" ] mceq_run.set_obs_particles(res_group) return [mceq_run, ad]
assert issubclass( CRModel, crf.PrimaryFlux), "Unknown primary cosmic ray spectrum model" # define CR model parameters if args.cosmic_ray_model == "HillasGaisser2012": CR_vers = "H3a" elif args.cosmic_ray_model == "GaisserStanevTilav": CR_vers = "4-gen" else: CR_vers = None mceq_run = MCEqRun( #provide the string of the interaction model interaction_model=interaction_model, #primary cosmic ray flux model #support a tuple (primary model class (not instance!), arguments) primary_model=(CRModel, CR_vers), # Zenith angle in degrees. 0=vertical, 90=horizontal theta_deg=0., #GPU device id **config) # Some global settings. One can play around with them, but there # is currently no good reason why # Primary proton projectile (neutron is included automatically # vie isospin symmetries) primary_particle = 2212 # The parameter delta for finite differences computation delta = 0.001 # Energy grid will be truncated below this value (saves some # memory and interpolation speed, but not really needed, I think)
r += MCEq_obj.set_mod_pprod(2112, 311, mod_linear, (fac_k0,), delay_init=True) r += MCEq_obj.set_mod_pprod(2112, -311, mod_linear, (fac_k0,), delay_init=True) r += MCEq_obj.set_mod_pprod(2112, 130, mod_linear, (fac_k0l,), delay_init=True) r += MCEq_obj.set_mod_pprod(2112, 310, mod_linear, (fac_k0s,), delay_init=True) if r > 0: MCEq_obj._init_default_matrices(skip_D_matrix=True) #pmodel = (pm.HillasGaisser2012, "H3a") # (pm.Thunman, None) # (pm.GaisserStanevTilav, "3-gen") # (PolyGonato, False) pmodel = (pm.HillasGaisser2012, "H3a") # (pm.Thunman, None) # (pm.GaisserStanevTilav, "3-gen") # (PolyGonato, False) mceq_run_January = MCEqRun(interaction_model='DPMJET-III', density_model=('MSIS00_IC',('SouthPole','January')), primary_model=pmodel, theta_deg=theta_use, **mceq_config_without(['density_model']) ) mceq_run_January.unset_mod_pprod(dont_fill=False) #Power of energy to scale the flux mag = 3 #obtain energy grid (nver changes) of the solution for the x-axis of the plots e_grid_January = mceq_run_January.e_grid #e_grid = mceq_run_January.y.e_grid #mceq_run.unset_mod_pprod() #mod_0 = (0.0,0.0,0.0,0.0,0.0,0.0,0.0,mceq_run_January ) mod_0 = (-1.0,-1.0, mceq_run_January ) apply_mod_p(*mod_0) mceq_run_January.y.print_mod_pprod()
class nuVeto(object): """Class for computing the neutrino passing fraction i.e. (1-(Veto probability))""" def __init__(self, costh, pmodel=(pm.HillasGaisser2012, 'H3a'), hadr='SIBYLL2.3c', barr_mods=(), depth=1950 * Units.m, density=('CORSIKA', ('SouthPole', 'December')), debug_level=1): """Initializes the nuVeto object for a particular costheta, CR Flux, hadronic model, barr parameters, and depth Note: A separate MCEq instance needs to be created for each combination of __init__'s arguments. To access pmodel and hadr, use mceq.pm_params and mceq.yields_params Args: costh (float): Cos(theta), the cosine of the neutrino zenith at the detector pmodel (tuple(CR model class, arguments)): CR Flux hadr (str): hadronic interaction model barr_mods: barr parameters depth (float): the depth at which the veto probability is computed below the ice """ self.costh = costh self.pmodel = pmodel self.geom = Geometry(depth) theta = np.degrees(np.arccos(self.geom.cos_theta_eff(self.costh))) if density[0] == 'MSIS00_IC': print('Passing "MSIS00_IC" assumes IceCube-centered coordinates, ' 'which obviates the depth used here. Switching to "MSIS00" ' 'for identical results.') density = ('MSIS00', density[1]) config.debug_level = debug_level # config.enable_em = False config.enable_muon_energy_loss = False config.return_as = 'total energy' config.adv_set['allowed_projectiles'] = [ 2212, 2112, 211, -211, 321, -321, 130, -2212, -2112 ] #, 11, 22] config.ctau = 2.5 self.mceq = MCEqRun( # provide the string of the interaction model interaction_model=hadr, # primary cosmic ray flux model # support a tuple (primary model class (not instance!), arguments) primary_model=pmodel, # zenith angle \theta in degrees, measured positively from vertical direction at surface theta_deg=theta, # atmospheric density model density_model=density) if len(barr_mods) > 0: for barr_mod in barr_mods: # Modify proton-air -> mod[0] self.mceq.set_mod_pprod(2212, BARR[barr_mod[0]].pdg, barr_unc, barr_mod) # Populate the modifications to the matrices by re-filling the interaction matrix self.mceq.regenerate_matrices(skip_decay_matrix=True) X_vec = np.logspace(np.log10(2e-3), np.log10(self.mceq.density_model.max_X), 12) self.dX_vec = np.diff(X_vec) self.X_vec = 10**centers(np.log10(X_vec)) @staticmethod def categ_to_mothers(categ, daughter): """Get the parents for this category""" rcharge = '-' if 'bar' in daughter else '+' lcharge = '+' if 'bar' in daughter else '-' rbar = 'bar' if 'bar' in daughter else '' lbar = '' if 'bar' in daughter else 'bar' if categ == 'conv': mothers = ['pi' + rcharge, 'K' + rcharge, 'K_L0'] if 'nu_tau' in daughter: mothers = [] elif 'nu_e' in daughter: mothers.extend(['K_S0', 'mu' + rcharge]) elif 'nu_mu' in daughter: mothers.extend(['mu' + lcharge]) elif categ == 'pr': if 'nu_tau' in daughter: mothers = ['D' + rcharge, 'D_s' + rcharge] else: mothers = ['D' + rcharge, 'D_s' + rcharge, 'D' + rbar + '0' ] #, 'Lambda'+lbar+'0']#, 'Lambda_c'+rcharge] elif categ == 'total': mothers = nuVeto.categ_to_mothers( 'conv', daughter) + nuVeto.categ_to_mothers('pr', daughter) else: mothers = [ categ, ] return mothers @staticmethod def esamp(enu, accuracy): """ returns the sampling of parent energies for a given enu """ # TODO: replace 1e8 with MMC-prpl interpolated bounds return np.logspace(np.log10(enu), np.log10(enu + 1e8), int(1000 * accuracy)) @staticmethod def projectiles(): """Get allowed pimaries""" pdg_ids = config.adv_set['allowed_projectiles'] namer = ParticleProperties.modtab.pdg2modname allowed = [] for pdg_id in pdg_ids: allowed.append(namer[pdg_id]) try: allowed.append(namer[-pdg_id]) except KeyError: continue return allowed @staticmethod def nbody(fpath, esamp, enu, fn, l_ice): with np.load(fpath) as dfile: xmus = centers(dfile['xedges']) xnus = np.concatenate([xmus, [1]]) vals = np.nan_to_num(dfile['histograms']) ddec = interpolate.RegularGridInterpolator((xnus, xmus), vals, bounds_error=False, fill_value=None) emu_mat = xmus[:, None] * esamp[None, :] * Units.GeV pmu_mat = ddec(np.stack(np.meshgrid(enu / esamp, xmus), axis=-1)) reaching = 1 - np.sum(pmu_mat * fn.prpl( np.stack([emu_mat, np.ones(emu_mat.shape) * l_ice], axis=-1)), axis=0) reaching[reaching < 0.] = 0. return reaching @staticmethod @lru_cache(2**12) def psib(l_ice, mother, enu, accuracy, prpl): """ returns the suppression factor due to the sibling muon """ esamp = nuVeto.esamp(enu, accuracy) fn = MuonProb(prpl) if mother in ['D0', 'D0-bar']: reaching = nuVeto.nbody( resource_filename('nuVeto', 'data/decay_distributions/D0_numu.npz'), esamp, enu, fn, l_ice) elif mother in ['D+', 'D-']: reaching = nuVeto.nbody( resource_filename('nuVeto', 'data/decay_distributions/D+_numu.npz'), esamp, enu, fn, l_ice) elif mother in ['Ds+', 'Ds-']: reaching = nuVeto.nbody( resource_filename('nuVeto', 'data/decay_distributions/Ds_numu.npz'), esamp, enu, fn, l_ice) elif mother == 'K0L': reaching = nuVeto.nbody( resource_filename('nuVeto', 'data/decay_distributions/K0L_numu.npz'), esamp, enu, fn, l_ice) else: # Assuming muon energy is E_parent - E_nu reaching = 1. - fn.prpl( list(zip((esamp - enu) * Units.GeV, [l_ice] * len(esamp)))) return reaching @lru_cache(maxsize=2**12) def get_dNdEE(self, mother, daughter): """Differential parent-->neutrino (mother--daughter) yield""" ihijo = 20 e_grid = self.mceq.e_grid delta = self.mceq.e_widths x_range = e_grid[ihijo] / e_grid rr = ParticleProperties.rr(mother, daughter) dNdEE_edge = ParticleProperties.br_2body(mother, daughter) / (1 - rr) dN_mat = self.mceq._decays.get_matrix( (ParticleProperties.pdg_id[mother], 0), (ParticleProperties.pdg_id[daughter], 0)) dNdEE = dN_mat[ihijo] * e_grid / delta logx = np.log10(x_range) logx_width = -np.diff(logx)[0] good = (logx + logx_width / 2 < np.log10(1 - rr)) & (x_range >= 5.e-2) x_low = x_range[x_range < 5e-2] dNdEE_low = np.array([dNdEE[good][-1]] * x_low.size) dNdEE_interp = lambda x_: interpolate.pchip( np.concatenate([[1 - rr], x_range[good], x_low])[::-1], np.concatenate([[dNdEE_edge], dNdEE[good], dNdEE_low])[::-1], extrapolate=True)(x_) * np.heaviside(1 - rr - x_, 1) return x_range, dNdEE, dNdEE_interp @lru_cache(maxsize=2**12) def grid_sol(self, ecr=None, particle=None): """MCEq grid solution for \\frac{dN_{CR,p}}_{dE_p}""" if ecr is not None: self.mceq.set_single_primary_particle(ecr, particle) else: self.mceq.set_primary_model(*self.pmodel) self.mceq.solve(int_grid=self.X_vec, grid_var="X") return self.mceq.grid_sol @lru_cache(maxsize=2**12) def nmu(self, ecr, particle, prpl='ice_allm97_step_1'): """Poisson probability of getting no muons""" grid_sol = self.grid_sol(ecr, particle) l_ice = self.geom.overburden(self.costh) mu = np.abs(self.get_solution('mu-', grid_sol)) + np.abs( self.get_solution( 'mu+', grid_sol)) # np.abs hack to prevent negative fluxes fn = MuonProb(prpl) coords = list( zip(self.mceq.e_grid * Units.GeV, [l_ice] * len(self.mceq.e_grid))) ### DEBUG ### # if np.trapz(mu*fn.prpl(coords)*self.mceq.e_grid, np.log(self.mceq.e_grid)) < 0: # import pdb # pdb.set_trace() ### return np.trapz(mu * fn.prpl(coords) * self.mceq.e_grid, np.log(self.mceq.e_grid)) @lru_cache(maxsize=2**12) def get_rescale_phi(self, mother, ecr=None, particle=None): """Flux of the mother at all heights""" grid_sol = self.grid_sol( ecr, particle ) # MCEq solution (fluxes tabulated as a function of height) dX = self.dX_vec * Units.gr / Units.cm**2 rho = self.mceq.density_model.X2rho( self.X_vec) * Units.gr / Units.cm**3 inv_decay_length_array = ( ParticleProperties.mass_dict[mother] / (self.mceq.e_grid[:, None] * Units.GeV)) / ( ParticleProperties.lifetime_dict[mother] * rho[None, :]) rescale_phi = dX[None, :] * inv_decay_length_array * self.get_solution( mother, grid_sol, grid_idx=False).T return rescale_phi def get_integrand(self, categ, daughter, enu, accuracy, prpl, ecr=None, particle=None): """flux*yield""" esamp = self.esamp(enu, accuracy) mothers = self.categ_to_mothers(categ, daughter) nums = np.zeros((len(esamp), len(self.X_vec))) dens = np.zeros((len(esamp), len(self.X_vec))) for mother in mothers: dNdEE = self.get_dNdEE(mother, daughter)[-1] rescale_phi = self.get_rescale_phi(mother, ecr, particle) # DEBUG # from matplotlib import pyplot as plt # plt.plot(np.log(self.mceq.e_grid[rescale_phi[:,0]>0]), # np.log(rescale_phi[:,0][rescale_phi[:,0]>0])) # rescale_phi = np.array([interpolate.interp1d(self.mceq.e_grid, rescale_phi[:,i], kind='quadratic', bounds_error=False, fill_value=0)(esamp) for i in range(rescale_phi.shape[1])]).T ### # TODO: optimize to only run when esamp[0] is non-zero rescale_phi = np.exp( np.array([ interpolate.interp1d( np.log(self.mceq.e_grid[rescale_phi[:, i] > 0]), np.log(rescale_phi[:, i][rescale_phi[:, i] > 0]), kind='quadratic', bounds_error=False, fill_value=-np.inf)(np.log(esamp)) if np.count_nonzero(rescale_phi[:, i] > 0) > 2 else [ -np.inf, ] * esamp.shape[0] for i in range(rescale_phi.shape[1]) ])).T # DEBUG # print rescale_phi.min(), rescale_phi.max() # print np.log(esamp) # plt.plot(np.log(esamp), # np.log(rescale_phi[:,0]), label='intp') # plt.legend() # import pdb # pdb.set_trace() ### if 'nu_mu' in daughter: # muon accompanies nu_mu only pnmsib = self.psib(self.geom.overburden(self.costh), mother, enu, accuracy, prpl) else: pnmsib = np.ones(len(esamp)) dnde = dNdEE(enu / esamp) / esamp nums += (dnde * pnmsib)[:, None] * rescale_phi dens += (dnde)[:, None] * rescale_phi return nums, dens def get_solution(self, particle_name, grid_sol, mag=0., grid_idx=None): """Retrieves solution of the calculation on the energy grid. Args: particle_name (str): The name of the particle such, e.g. ``total_mu+`` for the total flux spectrum of positive muons or ``pr_antinumu`` for the flux spectrum of prompt anti muon neutrinos mag (float, optional): 'magnification factor': the solution is multiplied by ``sol`` :math:`= \\Phi \\cdot E^{mag}` grid_idx (int, optional): if the integrator has been configured to save intermediate solutions on a depth grid, then ``grid_idx`` specifies the index of the depth grid for which the solution is retrieved. If not specified the flux at the surface is returned integrate (bool, optional): return averge particle number instead of flux (multiply by bin width) Returns: (numpy.array): flux of particles on energy grid :attr:`e_grid` """ # MCEq index conversion ref = self.mceq.pman.pname2pref p_pdg = ParticleProperties.pdg_id[particle_name] reduce_res = True if grid_idx is None: # Surface only case sol = np.array([grid_sol[-1]]) xv = np.array([self.X_vec[-1]]) elif isinstance(grid_idx, bool) and not grid_idx: # Whole solution case sol = np.asarray(grid_sol) xv = np.asarray(self.X_vec) reduce_res = False elif grid_idx >= len(self.mceq.grid_sol): # Surface only case sol = np.array([grid_sol[-1]]) xv = np.array([self.X_vec[-1]]) else: # Particular height case sol = np.array([grid_sol[grid_idx]]) xv = np.array([self.X_vec[grid_idx]]) # MCEq solution for particle direct = sol[:, ref[particle_name].lidx:ref[particle_name].uidx] res = np.zeros(direct.shape) rho_air = 1. / self.mceq.density_model.r_X2rho(xv) # meson decay length decayl = ((self.mceq.e_grid * Units.GeV) / ParticleProperties.mass_dict[particle_name] * ParticleProperties.lifetime_dict[particle_name] / Units.cm) # number of targets per cm2 ndens = rho_air * Units.Na / Units.mol_air sec = self.mceq.pman[p_pdg] prim2mceq = { 'p+-bar': 'pbar-', 'n0-bar': 'nbar0', 'D0-bar': 'Dbar0', 'Lambda0-bar': 'Lambdabar0' } for prim in self.projectiles(): if prim in prim2mceq: _ = prim2mceq[prim] else: _ = prim prim_flux = sol[:, ref[_].lidx:ref[_].uidx] proj = self.mceq.pman[ParticleProperties.pdg_id[prim]] prim_xs = proj.inel_cross_section() try: int_yields = proj.hadr_yields[sec] res += np.sum(int_yields[None, :, :] * prim_flux[:, None, :] * prim_xs[None, None, :] * ndens[:, None, None], axis=2) except KeyError as e: continue res *= decayl[None, :] # combine with direct res[direct != 0] = direct[direct != 0] if particle_name[:-1] == 'mu': for _ in ['k_' + particle_name, 'pi_' + particle_name]: res += sol[:, ref[_ + '_l'].lidx:ref[_ + '_l'].uidx] res += sol[:, ref[_ + '_r'].lidx:ref[_ + '_r'].uidx] res *= self.mceq.e_grid[None, :]**mag if reduce_res: res = res[0] return res def get_fluxes(self, enu, kind='conv nu_mu', accuracy=3.5, prpl='ice_allm97_step_1', corr_only=False): """Returns the flux and passing fraction for a particular neutrino energy, flux, and p_light """ # prpl = probability of reaching * probability of light # prpl -> None ==> median for muon reaching categ, daughter = kind.split() esamp = self.esamp(enu, accuracy) # Correlated only (no need for the unified calculation here) [really just for testing] passed = 0 total = 0 if corr_only: # sum performs the dX integral nums, dens = self.get_integrand(categ, daughter, enu, accuracy, prpl) num = np.sum(nums, axis=1) den = np.sum(dens, axis=1) passed = integrate.trapz(num, esamp) total = integrate.trapz(den, esamp) return passed, total pmodel = self.pmodel[0](self.pmodel[1]) #loop over primary particles for particle in pmodel.nucleus_ids: # A continuous input energy range is allowed between # :math:`50*A~ \\text{GeV} < E_\\text{nucleus} < 10^{10}*A \\text{GeV}`. # ecrs --> Energy of cosmic ray primaries # amu --> atomic mass of primary # evaluation points in E_CR ecrs = amu(particle) * np.logspace(2, 10, int(10 * accuracy)) # pnm --> probability of no muon (just a poisson probability) nmu = [self.nmu(ecr, particle, prpl) for ecr in ecrs] # nmufn --> fine grid interpolation of pnm nmufn = interpolate.interp1d(ecrs, nmu, kind='linear', assume_sorted=True, bounds_error=False, fill_value=(0, np.nan)) # nums --> numerator nums = [] # dens --> denominator dens = [] # istart --> integration starting point, the lowest energy index for the integral istart = max(0, np.argmax(ecrs > enu) - 1) for ecr in ecrs[istart:]: # integral in primary energy (E_CR) # cr_flux --> cosmic ray flux # phim2 --> units of flux * m^2 (look it up in the units) cr_flux = pmodel.nucleus_flux(particle, ecr.item()) * Units.phim2 # poisson exp(-Nmu) [last term in eq 12] pnmarr = np.exp(-nmufn(ecr - esamp)) num_ecr = 0 # single entry in nums den_ecr = 0 # single entry in dens # dEp # integral in Ep nums_ecr, dens_ecr = self.get_integrand( categ, daughter, enu, accuracy, prpl, ecr, particle) num_ecr = integrate.trapz( np.sum(nums_ecr, axis=1) * pnmarr, esamp) den_ecr = integrate.trapz(np.sum(dens_ecr, axis=1), esamp) nums.append(num_ecr * cr_flux / Units.phicm2) dens.append(den_ecr * cr_flux / Units.phicm2) # dEcr passed += integrate.trapz(nums, ecrs[istart:]) total += integrate.trapz(dens, ecrs[istart:]) return passed, total
def Solve_mceqs(): ### This function solves matrix cascade equations using MCEq. Please ### note that MCEq can do a lot more than what is currently used ### in this script. For more information and options, visit: ### https://github.com/afedynitch/MCEq import crflux.models as crf from MCEq.core import config, MCEqRun def Convert_name(particle): # MCEq can't handle "bar"s in particle names. It wants "anti"s instead. if 'bar' in particle[0]: pname = (particle[0].replace('_', '_anti') if '_' in particle[0] else 'anti' + particle[0]) pname = pname.replace('bar', '') else: pname = particle[0] return pname # Cosmic ray flux at the top of the atmosphere: primary_model = (HawkBPL, 0.) # High-energy hadronic interaction model: interaction_model = 'SIBYLL23C' # Zenith angles: zenith_deg = np.append(np.arange(0., 90., 10), 89) mceq = MCEqRun(interaction_model = interaction_model, primary_model = primary_model, theta_deg = 0.) mceq.pman.track_leptons_from([(130,0)], 'K0L_') mceq.pman.track_leptons_from([(310,0)], 'K0S_') # mceq.pman.print_particle_tables(0) mceq._resize_vectors_and_restore() mceq.regenerate_matrices() config.excpt_on_missing_particle = True energy = mceq.e_grid ## Solve the equation systems for all zenith angles: solutions = [[] for particle in particles] for angle in zenith_deg: print( '\n=== Solving MCEq for BPL ' + interaction_model + ' ' + str(angle) + ' deg' ) mceq.set_theta_deg(angle) mceq.solve() # Obtain solution for all chosen particles: print('Obtaining solution for:') for p, particle in enumerate(particles): print(particle[0]) solutions[p].append(mceq.get_solution(Convert_name(particle), mag=0)) # mag is a multiplication factor in order to stress steaper # parts of the spectrum. Don't store magnified fluxes in nuflux # (keep mag=0)! # Save solutions to file particle-wise: for p, particle in enumerate(particles): savename = name + '_' + particle[0] headr = ( savename.replace('_', '\t') + '\n' 'energy [GeV]\t' + ' '.join([str(z) + ' deg\t' for z in zenith_deg]) ) solutions[p].insert(0, energy) solutions[p] = np.array(solutions[p]) np.savetxt( dirname + '/data/' + savename + '.dat', np.transpose(solutions[p]), fmt='%.8e', header=headr, delimiter='\t' )