def dNdec_dxlab(self, kin_energy, sec_pdg, verbose=True, **kwargs): r"""Returns :math:`dN/dx_{\rm Lab}` for interaction energy close to ``kin_energy`` for hadron-air collisions. The function respects modifications applied via :func:`_set_mod_pprod`. Args: kin_energy (float): approximate interaction energy prim_pdg (int): PDG ID of projectile sec_pdg (int): PDG ID of secondary particle verbose (bool): print out the closest energy Returns: (numpy.array, numpy.array): :math:`x_{\rm Lab}`, :math:`dN/dx_{\rm Lab}` """ eidx = (np.abs(self._energy_grid.c - kin_energy)).argmin() en = self._energy_grid.c[eidx] info(10, 'Nearest energy, index: ', en, eidx, condition=verbose) m = self.decay_dists[sec_pdg] xl_grid = (self._energy_grid.c[:eidx + 1]) / en xl_dist = en * xl_grid * m[:eidx + 1, eidx] / self._energy_grid.w[:eidx + 1] return xl_grid, xl_dist
def decay_z_factor(self, parent_pdg, child_pdg): """Energy dependent Z-factor according to Lipari (1993).""" proj = self.pman[parent_pdg] sec = self.pman[child_pdg] if proj.is_stable: raise Exception('{0} does not decay.'.format(proj.name)) info( 10, 'Computing e-dependent decay Zfactor for {0} -> {1}'.format( proj.name, sec.name)) if not proj.is_child(sec): raise Exception('{0} is not a a child particle of {1}.'.format( sec.name, proj.name)) cr_gamma = self.pmodel.nucleon_gamma(self.e_grid) zfac = np.zeros(self.dim) zfac = np.zeros_like(self.e_grid) for p_eidx, e in enumerate(self.e_grid): # if e < min_energy: # min_idx = p_eidx + 1 # continue xlab, xdist = proj.dNdec_dxlab(e, sec) zfac[p_eidx] = np.trapz(xlab**(-cr_gamma[p_eidx] - 2.) * xdist, x=xlab) return zfac
def set_mod_pprod(self, prim_pdg, sec_pdg, x_func, x_func_args, delay_init=False): """Sets combination of projectile/secondary for error propagation. The production spectrum of ``sec_pdg`` in interactions of ``prim_pdg`` is modified according to the function passed to :func:`InteractionYields.init_mod_matrix` Args: prim_pdg (int): interacting (primary) particle PDG ID sec_pdg (int): secondary particle PDG ID x_func (object): reference to function x_func_args (tuple): arguments passed to ``x_func`` delay_init (bool): Prevent init of mceq matrices if you are planning to add more modifications """ info( 1, '{0}/{1}, {2}, {3}'.format(prim_pdg, sec_pdg, x_func.__name__, str(x_func_args))) init = self._interactions._set_mod_pprod(prim_pdg, sec_pdg, x_func, x_func_args) # Need to regenerate matrices completely return int(init)
def __init__(self, location, season): if location != 'SouthPole': info(2, 'location forced to the South Pole') location = 'SouthPole' MSIS00Atmosphere.__init__(self, location, season) # Allow for upgoing zenith angles self.max_theta = 180.
def set_decay_channels(self, decay_db): """Attaches the references to the decay yield tables to each unstable particle""" info(5, 'Setting decay info for particles.') for p in self.all_particles: p.set_decay_channels(decay_db, self) self._restore_tracking_setup() self._update_particle_tables()
def _init_categories(self, particle_pdg_list): """Determines the list of particles for calculation and returns lists of instances of :class:`data.MCEqParticle` . The particles which enter this list are those, which have a defined index in the SIBYLL 2.3 interaction model. Included are most relevant baryons and mesons and some of their high mass states. More details about the particles which enter the calculation can be found in :mod:`ParticleDataTool`. Returns: (tuple of lists of :class:`data.MCEqParticle`): (all particles, cascade particles, resonances) """ from MCEq.particlemanager import MCEqParticle info(5, "Generating particle list.") if particle_pdg_list is not None: particles = particle_pdg_list else: from particletools.tables import SibyllParticleTable modtab = SibyllParticleTable() particles = modtab.baryons + modtab.mesons + modtab.leptons # Remove duplicates particles = sorted(list(set(particles))) # Initialize particle objects particle_list = [ MCEqParticle(pdg, hel, self._energy_grid, self._cs_db) for pdg, hel in particles ] # Sort by critical energy (= int_len ~== dec_length ~ int_cs/tau) particle_list.sort(key=lambda x: x.E_crit, reverse=False) # Cascade particles will "live" on the grid and have an mceqidx assigned self.cascade_particles = [ p for p in particle_list if not p.is_resonance ] self.cascade_particles = sorted(self.cascade_particles, key=lambda p: abs(p.pdg_id[0])) # These particles will only exist implicitely and integated out self.resonances = [p for p in particle_list if p.is_resonance] # Assign an mceqidx (position in state vector) to each explicit particle # Resonances will kepp the default mceqidx = -1 for mceqidx, h in enumerate(self.cascade_particles): h.mceqidx = mceqidx self.all_particles = self.cascade_particles + self.resonances self._update_particle_tables()
def set_cs(self, cs_db): """Set cross section adn recalculate the dependent variables""" info(11, 'Obtaining cross sections for', self.pdg_id) self.current_cross_sections = cs_db.iam self.cs = cs_db[self.pdg_id[0]] if sum(self.cs) > 0: self.can_interact = True else: self.can_interact = False self._critical_energy() self._calculate_mixing_energy()
def set_IC79_day(self, IC79_day): import datetime if IC79_day > self.IC79_days: raise Exception(self.__class__.__name__ + "::set_IC79_day(): IC79_day above range.") target_day = self._get_y_doy(self.dates[self.IC79_start] + datetime.timedelta(days=IC79_day)) info(2, 'setting IC79_day', IC79_day) self.h, self.dens = self.interp_tab_d[target_day] _, self.temp = self.interp_tab_t[target_day] self.date = self.dates[target_day] # Compatibility with caching self.season = self.date
def unset_mod_pprod(self, dont_fill=False): """Removes modifications from :func:`MCEqRun.set_mod_pprod`. Args: skip_fill (bool): If `true` do not regenerate matrices (has to be done at a later step by hand) """ from collections import defaultdict info(1, 'Particle production modifications reset to defaults.') self._interactions.mod_pprod = defaultdict(lambda: {}) # Need to regenerate matrices completely if not dont_fill: self.regenerate_matrices()
def set_density_model(self, density_config): """Sets model of the atmosphere. To choose, for example, a CORSIKA parametrization for the Southpole in January, do the following:: mceq_instance.set_density_model(('CORSIKA', ('PL_SouthPole', 'January'))) More details about the choices can be found in :mod:`MCEq.geometry.density_profiles`. Calling this method will issue a recalculation of the interpolation and the integration path. Args: density_config (tuple of strings): (parametrization type, arguments) """ import MCEq.geometry.density_profiles as dprof base_model, model_config = density_config available_models = [ 'MSIS00', 'MSIS00_IC', 'CORSIKA', 'AIRS', 'Isothermal', 'GeneralizedTarget' ] if base_model not in available_models: info(0, 'Unknown density model. Available choices are:\n', '\n'.join(available_models)) raise Exception('Choose a different profile.') info(1, 'Setting density profile to', base_model, model_config) if base_model == 'MSIS00': self.density_model = dprof.MSIS00Atmosphere(*model_config) elif base_model == 'MSIS00_IC': self.density_model = dprof.MSIS00IceCubeCentered(*model_config) elif base_model == 'CORSIKA': self.density_model = dprof.CorsikaAtmosphere(*model_config) elif base_model == 'AIRS': self.density_model = dprof.AIRSAtmosphere(*model_config) elif base_model == 'Isothermal': self.density_model = dprof.IsothermalAtmosphere(*model_config) elif base_model == 'GeneralizedTarget': self.density_model = dprof.GeneralizedTarget() else: raise Exception('Unknown atmospheric base model.') self.density_config = density_config if self.theta_deg is not None and base_model != 'GeneralizedTarget': self.set_theta_deg(self.theta_deg) elif base_model == 'GeneralizedTarget': self.integration_path = None
def track_interactions(self, tracking_particle): secondaries_d = {} for s in self.hadr_secondaries: secondaries_d[s.pdg_id] = s if tracking_particle.pdg_id not in list(secondaries_d): info( 17, 'Parent particle {0} does not produce {1} at the vertex'. format(self.name, tracking_particle.name)) return False # Copy the decay distribution from original PDG self.hadr_secondaries.append(tracking_particle) self.hadr_yields[tracking_particle] = self.hadr_yields[secondaries_d[ tracking_particle.pdg_id]] return True
def _follow_chains(self, p, pprod_mat, p_orig, idcs, propmat, reclev=0): """Some recursive magic. """ info(40, reclev * '\t', 'entering with', p.name) # print 'orig, p', p_orig.pdg_id, p.pdg_id for d in p.children: info(40, reclev * '\t', 'following to', d.name) if not d.is_resonance: # print 'adding stuff', p_orig.pdg_id, p.pdg_id, d.pdg_id dprop = self._zero_mat() p._assign_decay_idx(d, idcs, d.hadridx, dprop) propmat[(d.mceqidx, p_orig.mceqidx)] += dprop.dot(pprod_mat) if config.debug_level >= 20: pstr = 'res' dstr = 'Mchain' if idcs == p.hadridx: pstr = 'prop' dstr = 'Mprop' info( 40, reclev * '\t', 'setting {0}[({1},{3})->({2},{4})]'.format( dstr, p_orig.name, d.name, pstr, 'prop')) if d.is_mixed or d.is_resonance: dres = self._zero_mat() p._assign_decay_idx(d, idcs, d.residx, dres) reclev += 1 self._follow_chains(d, dres.dot(pprod_mat), p_orig, d.residx, propmat, reclev) else: info(20, reclev * '\t', '\t terminating at', d.name)
def track_decays(self, tracking_particle): children_d = {} for c in self.children: children_d[c.pdg_id] = c if tracking_particle.pdg_id not in list(children_d): info( 17, 'Parent particle {0} does not decay into {1}'.format( self.name, tracking_particle.name)) return False # Copy the decay distribution from original PDG self.children.append(tracking_particle) self.decay_dists[tracking_particle] = self.decay_dists[children_d[ tracking_particle.pdg_id]] return True
def _average_operator(self, op_mat): """Averages the continuous loss operator by performing 1/max_step explicit euler steps""" n_steps = int(1. / config.loss_step_for_average) info( 10, 'Averaging continuous loss using {0} intermediate steps.'.format( n_steps)) op_step = np.eye( self._energy_grid.d) + op_mat * config.loss_step_for_average return np.linalg.matrix_power(op_step, n_steps) - np.eye( self._energy_grid.d)
def calculate_density_spline(self, n_steps=2000): """Calculates and stores a spline of :math:`\\rho(X)`. Args: n_steps (int, optional): number of :math:`X` values to use for interpolation Raises: Exception: if :func:`set_theta` was not called before. """ from scipy.integrate import cumtrapz from time import time from scipy.interpolate import UnivariateSpline if self.theta_deg is None: raise Exception('zenith angle not set') else: info( 5, 'Calculating spline of rho(X) for zenith {0:4.1f} degrees.'. format(self.theta_deg)) thrad = self.thrad path_length = self.geom.l(thrad) vec_rho_l = np.vectorize( lambda delta_l: self.get_density(self.geom.h(delta_l, thrad))) dl_vec = np.linspace(0, path_length, n_steps) now = time() # Calculate integral for each depth point X_int = cumtrapz(vec_rho_l(dl_vec), dl_vec) # dl_vec = dl_vec[1:] info(5, '.. took {0:1.2f}s'.format(time() - now)) # Save depth value at h_obs self._max_X = X_int[-1] self._max_den = self.get_density(self.geom.h(0, thrad)) # Interpolate with bi-splines without smoothing h_intp = [self.geom.h(dl, thrad) for dl in reversed(dl_vec[1:])] X_intp = [X for X in reversed(X_int[1:])] self._s_h2X = UnivariateSpline(h_intp, np.log(X_intp), k=2, s=0.0) self._s_X2rho = UnivariateSpline(X_int, vec_rho_l(dl_vec), k=2, s=0.0) self._s_lX2h = UnivariateSpline(np.log(X_intp)[::-1], h_intp[::-1], k=2, s=0.0)
def _fill_matrices(self, skip_decay_matrix=False): """Generates the interaction and decay matrices from scratch. """ from collections import defaultdict # Fill decay matrix blocks if not skip_decay_matrix or self.dec_m is None: # Initialize empty D matrix self.D_blocks = defaultdict(lambda: self._zero_mat()) for p in self._pman.cascade_particles: # Fill parts of the D matrix related to p as mother if not p.is_stable and bool(p.children) and not p.is_tracking: self._follow_chains(p, np.diag(np.ones((self.dim))), p, p.hadridx, self.D_blocks, reclev=0) else: info(20, p.name, 'stable or not added to D matrix') # Initialize empty C blocks self.C_blocks = defaultdict(lambda: self._zero_mat()) for p in self._pman.cascade_particles: # if p doesn't interact, skip interaction matrices if not p.is_projectile: if p.is_hadron: info( 1, 'No interactions by {0} ({1}).'.format( p.name, p.pdg_id)) continue for s in p.hadr_secondaries: # if s not in self.pman.cascade_particles: # print 'Doing nothing with', p.pdg_id, s.pdg_id # continue if not s.is_resonance: cmat = self._zero_mat() p._assign_hadr_dist_idx(s, p.hadridx, s.hadridx, cmat) self.C_blocks[(s.mceqidx, p.mceqidx)] += cmat cmat = self._zero_mat() p._assign_hadr_dist_idx(s, p.hadridx, s.residx, cmat) self._follow_chains(s, cmat, p, s.residx, self.C_blocks, reclev=1)
def set_theta(self, theta_deg, force_spline_calc=True): self._msis.set_location_coord(longitude=0., latitude=self.latitude(theta_deg)) info( 1, 'latitude = {0:5.2f} for zenith angle = {1:5.2f}'.format( self.latitude(theta_deg), theta_deg)) if theta_deg > 90.: info( 1, 'theta = {0:5.2f} below horizon. using theta = {1:5.2f}'. format(theta_deg, 180. - theta_deg)) theta_deg = 180. - theta_deg MSIS00Atmosphere.set_theta(self, theta_deg, force_spline_calc=force_spline_calc)
def sum_lr(lep_str, prefix): result = np.zeros(self.dim) nsuccess = 0 for ls in lep_str, lep_str + '_l', lep_str + '_r': if prefix + ls not in ref: info( 15, 'No separate left and right handed particles,', 'or, unavailable particle prefix {0}.'.format(prefix + ls)) continue result += sol[ref[prefix + ls].lidx:ref[prefix + ls].uidx] nsuccess += 1 if nsuccess == 0 and config.excpt_on_missing_particle: raise Exception( 'Requested particle {0} not found.'.format(particle_name)) return result
def print_table(self, min_dbg_lev=0): """Prints table of materials to standard output. """ templ = '{0:^3} | {1:15} | {2:^9.3g} | {3:^9.3g} | {4:^8.5g}' info(min_dbg_lev, '********************* List of materials ***********************', no_caller=True) head = '{0:3} | {1:15} | {2:9} | {3:9} | {4:9}'.format( 'no', 'name', 'start [cm]', 'end [cm]', 'density [g/cm**3]') info(min_dbg_lev, '-' * len(head), no_caller=True) info(min_dbg_lev, head, no_caller=True) info(min_dbg_lev, '-' * len(head), no_caller=True) for nm, mat in enumerate(self.mat_list): info(min_dbg_lev, templ.format(nm, mat[3], mat[0], mat[1], mat[2]), no_caller=True)
def add_hadronic_production_channel(self, child, int_matrix): """Add a new particle that is produced in hadronic interactions. The int_matrix is expected to be in the correct shape and scale as the other interaction (dN/dE(i,j)) matrices. Energy conservation is not checked. """ if not self.is_projectile: raise Exception('The particle should be a projectile.') if child in self.hadr_secondaries: info(1, 'Child {0} has been already added.'.format(child.name)) return self.hadr_secondaries.append(child) self.hadr_yields[child] = int_matrix
def set_primary_model(self, mclass, tag): """Sets primary flux model. This functions is quick and does not require re-generation of matrices. Args: interaction_model (:class:`CRFluxModel.PrimaryFlux`): reference to primary model **class** tag (tuple): positional argument list for model class """ info(1, mclass.__name__, tag if tag is not None else '') # Save primary flux model for restauration after interaction model changes self._restore_initial_condition = (self.set_primary_model, mclass, tag) # Initialize primary model object self.pmodel = mclass(tag) self.get_nucleon_spectrum = np.vectorize(self.pmodel.p_and_n_flux) try: self.dim_states except AttributeError: self.finalize_pmodel = True # Save initial condition minimal_energy = 3. if (2212, 0) in self.pman: e_tot = self._energy_grid.c + self.pman[(2212, 0)].mass else: info( 10, 'No protons in eqn system, quering primary flux with kinetic energy.' ) e_tot = self._energy_grid.c min_idx = np.argmin(np.abs(e_tot - minimal_energy)) self._phi0 *= 0 p_top, n_top = self.get_nucleon_spectrum(e_tot[min_idx:])[1:] if (2212, 0) in self.pman: self._phi0[min_idx + self.pman[(2212, 0)].lidx:self.pman[( 2212, 0)].uidx] = 1e-4 * p_top else: info( 1, 'Warning protons not part of equation system, can not set primary flux.' ) if (2112, 0) in self.pman and not self.pman[(2112, 0)].is_resonance: self._phi0[min_idx + self.pman[(2112, 0)].lidx:self.pman[( 2112, 0)].uidx] = 1e-4 * n_top elif (2212, 0) in self.pman: info(2, 'Neutrons not part of equation system,', 'substituting initial flux with protons.') self._phi0[min_idx + self.pman[(2212, 0)].lidx:self.pman[( 2212, 0)].uidx] += 1e-4 * n_top
def _restore_tracking_setup(self): """Restores the setup of tracking particles after model changes.""" info(10, 'Restoring tracking particle setup') if not self.tracking_relations and config.enable_default_tracking: self._init_default_tracking() return # Clear tracking_relations for this initialization self.tracking_relations = [] for pid, cid, alias, int_dec in self._tracking_requested: if pid not in self.pdg2pref: info(15, 'Can not restore {0}, since not in particle list.') continue self.add_tracking_particle([pid], cid, alias, int_dec)
def set_cross_sections_db(self, cs_db): """Sets the inelastic cross section to each interacting particle. This applies to most of the hadrons and does not imply that the particle becomes a projectile. parents need in addition defined hadronic channels. """ info(5, 'Setting cross section particle variables.') if self.current_cross_sections == cs_db.iam: info(10, 'Same cross section model not applied to particles.') return for p in self.cascade_particles: p.set_cs(cs_db) self.current_cross_sections = cs_db.iam self._update_particle_tables()
def _calculate_integration_path(self, int_grid, grid_var, force=False): if (self.integration_path and np.alltrue(int_grid == self.int_grid) and np.alltrue(self.grid_var == grid_var) and not force): info(5, 'skipping calculation.') return self.int_grid, self.grid_var = int_grid, grid_var if grid_var != 'X': raise NotImplementedError( 'the choice of grid variable other than the depth X are not possible, yet.' ) max_X = self.density_model.max_X ri = self.density_model.r_X2rho max_lint = self.matrix_builder.max_lint max_ldec = self.matrix_builder.max_ldec info(2, 'X_surface = {0:7.2f}g/cm2'.format(max_X)) dX_vec = [] rho_inv_vec = [] X = 0.0 step = 0 grid_step = 0 grid_idcs = [] # The factor 0.95 means 5% inbound from stability margin of the # Euler intergrator. if (max_ldec * ri(config.max_density) > max_lint and config.leading_process == 'decays'): info(3, "using decays as leading eigenvalues") delta_X = lambda X: 0.95 / (max_ldec * ri(X)) else: info(2, "using interactions as leading eigenvalues") delta_X = lambda X: 0.95 / max_lint dXmax = config.dXmax while X < max_X: dX = min(delta_X(X), dXmax) if (np.any(int_grid) and (grid_step < len(int_grid)) and (X + dX >= int_grid[grid_step])): dX = int_grid[grid_step] - X grid_idcs.append(step) grid_step += 1 dX_vec.append(dX) rho_inv_vec.append(ri(X)) X = X + dX step += 1 # Integrate dX_vec = np.array(dX_vec) rho_inv_vec = np.array(rho_inv_vec) self.integration_path = len(dX_vec), dX_vec, rho_inv_vec, grid_idcs
def z_factor(self, projectile_pdg, secondary_pdg, definition='primary_e'): """Energy dependent Z-factor according to Thunman et al. (1996)""" proj = self.pman[projectile_pdg] sec = self.pman[secondary_pdg] if not proj.is_projectile: raise Exception('{0} is not a projectile particle.'.format( proj.name)) info( 10, 'Computing e-dependent Zfactor for {0} -> {1}'.format( proj.name, sec.name)) if not proj.is_secondary(sec): raise Exception('{0} is not a secondary particle of {1}.'.format( sec.name, proj.name)) if proj == 2112: nuc_flux = self.pmodel.p_and_n_flux(self.e_grid)[2] else: nuc_flux = self.pmodel.p_and_n_flux(self.e_grid)[1] zfac = np.zeros(self.dim) smat = proj.hadr_yields[sec] proj_cs = proj.inel_cross_section() zfac = np.zeros_like(self.e_grid) # Definition wrt CR energy (different from Thunman) on x-axis if definition == 'primary_e': min_energy = 2. for p_eidx, e in enumerate(self.e_grid): if e < min_energy: min_idx = p_eidx + 1 continue zfac[p_eidx] = np.sum( smat[min_idx:p_eidx + 1, p_eidx] * nuc_flux[p_eidx] / nuc_flux[min_idx:p_eidx + 1] * proj_cs[p_eidx] / proj_cs[min_idx:p_eidx + 1]) return zfac else: # Like in Thunman et al. 1996 for p_eidx, _ in enumerate(self.e_grid): zfac[p_eidx] = np.sum(smat[p_eidx, p_eidx:] * nuc_flux[p_eidx:] / nuc_flux[p_eidx] * proj_cs[p_eidx:] / proj_cs[p_eidx]) return zfac
def n_e(self, grid_idx=None, min_energy_cutoff=1e-1): """Returns muon number at a grid step above an energy threshold for counting.""" ie_min = np.argmin( np.abs(self.e_bins - self.e_bins[self.e_bins >= min_energy_cutoff][0])) info( 10, 'Energy cutoff for muon number calculation {0:4.3e} GeV'.format( self.e_bins[ie_min])) info( 15, 'First bin is between {0:3.2e} and {1:3.2e} with midpoint {2:3.2e}' .format(self.e_bins[ie_min], self.e_bins[ie_min + 1], self.e_grid[ie_min])) return np.sum( self.get_solution('e+', mag=0, integrate=True, grid_idx=grid_idx) + self.get_solution('e-', mag=0, integrate=True, grid_idx=grid_idx))
def add_decay_channel(self, child, dec_matrix, force=False): """Add a decay channel. The branching ratios are not renormalized and one needs to take care of this externally. """ if self.is_stable: raise Exception('Cannot add decay channel to stable particle.') if child in self.children and not force: info(1, 'Child {0} has been already added.'.format(child.name)) return elif child in self.children and force: info(1, 'Overwriting decay matrix of child {0}.'.format(child.name)) self.decay_dists[child] = dec_matrix return self.children.append(child) self.decay_dists[child] = dec_matrix
def solv_numpy(nsteps, dX, rho_inv, int_m, dec_m, phi, grid_idcs): """:mod:`numpy` implementation of forward-euler integration. Args: nsteps (int): number of integration steps dX (numpy.array[nsteps]): vector of step-sizes :math:`\\Delta X_i` in g/cm**2 rho_inv (numpy.array[nsteps]): vector of density values :math:`\\frac{1}{\\rho(X_i)}` int_m (numpy.array): interaction matrix :eq:`int_matrix` in dense or sparse representation dec_m (numpy.array): decay matrix :eq:`dec_matrix` in dense or sparse representation phi (numpy.array): initial state vector :math:`\\Phi(X_0)` Returns: numpy.array: state vector :math:`\\Phi(X_{nsteps})` after integration """ grid_sol = [] grid_step = 0 imc = int_m dmc = dec_m dxc = dX ric = rho_inv phc = phi dXaccum = 0. from time import time start = time() for step in range(nsteps): phc += (imc.dot(phc) + dmc.dot(ric[step] * phc)) * dxc[step] dXaccum += dxc[step] if (grid_idcs and grid_step < len(grid_idcs) and grid_idcs[grid_step] == step): grid_sol.append(np.copy(phc)) grid_step += 1 info( 2, "Performance: {0:6.2f}ms/iteration".format(1e3 * (time() - start) / float(nsteps))) return phc, np.array(grid_sol)
def set_theta_deg(self, theta_deg): """Sets zenith angle :math:`\\theta` as seen from a detector. Currently only 'down-going' angles (0-90 degrees) are supported. Args: atm_config (tuple of strings): (parametrization type, location string, season string) """ info(2, 'Zenith angle {0:6.2f}'.format(theta_deg)) if self.density_config[0] == 'GeneralizedTarget': raise Exception('GeneralizedTarget does not support angles.') if self.density_model.theta_deg == theta_deg: info(2, 'Theta selection correponds to cached value, skipping calc.') return self.density_model.set_theta(theta_deg) self.integration_path = None
def solv_CUDA_sparse(nsteps, dX, rho_inv, context, phi, grid_idcs): """`NVIDIA CUDA cuSPARSE <https://developer.nvidia.com/cusparse>`_ implementation of forward-euler integration. Function requires a working :mod:`accelerate` installation. Args: nsteps (int): number of integration steps dX (numpy.array[nsteps]): vector of step-sizes :math:`\\Delta X_i` in g/cm**2 rho_inv (numpy.array[nsteps]): vector of density values :math:`\\frac{1}{\\rho(X_i)}` int_m (numpy.array): interaction matrix :eq:`int_matrix` in dense or sparse representation dec_m (numpy.array): decay matrix :eq:`dec_matrix` in dense or sparse representation phi (numpy.array): initial state vector :math:`\\Phi(X_0)` mu_loss_handler (object): object of type :class:`SemiLagrangianEnergyLosses` Returns: numpy.array: state vector :math:`\\Phi(X_{nsteps})` after integration """ c = context c.set_phi(phi) grid_step = 0 from time import time start = time() if len(grid_idcs) > 0: c.alloc_grid_sol(phi.shape[0], len(grid_idcs)) for step in range(nsteps): c.solve_step(rho_inv[step], dX[step]) if (grid_idcs and grid_step < len(grid_idcs) and grid_idcs[grid_step] == step): c.dump_sol() grid_step += 1 info( 2, "Performance: {0:6.2f}ms/iteration".format(1e3 * (time() - start) / float(nsteps))) return c.get_phi(), c.get_gridsol() if len(grid_idcs) > 0 else []