Example #1
0
    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
Example #2
0
    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
Example #3
0
    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)
Example #4
0
    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.
Example #5
0
    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()
Example #6
0
    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()
Example #7
0
 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()
Example #8
0
 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
Example #9
0
    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()
Example #10
0
    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
Example #11
0
 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
Example #12
0
    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)
Example #13
0
 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
Example #14
0
    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)
Example #15
0
    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)
Example #16
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)
Example #17
0
    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)
Example #18
0
 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
Example #19
0
    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)
Example #20
0
    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
Example #21
0
    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
Example #22
0
    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)
Example #23
0
    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()
Example #24
0
    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
Example #25
0
    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
Example #26
0
 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))
Example #27
0
    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
Example #28
0
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)
Example #29
0
    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
Example #30
0
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 []