Skip to content

Hadron Cascades

Hadron_Cascade

Hadron_Cascade()

Hadronic cascade light yield calculator.

Calculates Cherenkov light production from hadronic showers using the Aachen parametrization. Handles charged pions, kaons, protons, and neutrons with electromagnetic fraction and muon production.

Attributes:

Name Type Description
_medium dict

Medium properties dictionary

_n float

Refractive index

_radlength float

Radiation length in g/cm²

_Lrad float

Radiation length in cm

_params dict

Parametrization coefficients

cherenkov_angle_distro Callable

Angular distribution calculator

track_lengths Callable

Track length calculator

long_profile Callable

Longitudinal profile calculator

em_fraction Callable

EM fraction calculator

muon_production Callable

Muon production calculator

Examples:

>>> from fennel.hadron_cascades import Hadron_Cascade
>>> had = Hadron_Cascade()
>>> track_len, track_dev = had.track_lengths(100.0, particle=211)
>>> em_frac = had.em_fraction(100.0, particle=211)
Notes
  • Parametrization based on GEANT4 simulations
  • Accounts for EM fraction and muon production
  • Supports both NumPy and JAX backends

Initialize the hadronic cascade calculator.

Loads parametrization data and muon production splines, configures calculation methods based on JAX availability.

Raises:

Type Description
ValueError

If parametrization is not implemented or muon data not found

ImportError

If JAX mode enabled but not installed

Source code in fennel/hadron_cascades.py
def __init__(self) -> None:
    """
    Initialize the hadronic cascade calculator.

    Loads parametrization data and muon production splines,
    configures calculation methods based on JAX availability.

    Raises
    ------
    ValueError
        If parametrization is not implemented or muon data not found
    ImportError
        If JAX mode enabled but not installed
    """
    if not config["general"]["enable logging"]:
        _log.disabled = True
    _log.debug("Constructing a hadron cascade object")
    self._medium = config["mediums"][config["scenario"]["medium"]]
    self._n = self._medium["refractive index"]
    self._radlength = self._medium["radiation length"]
    self._Lrad = self._radlength / self._medium["density"]
    if config["scenario"]["parametrization"] == "aachen":
        _log.info("Loading the aachen parametrization")
        param_file = pkgutil.get_data(
            __name__, "data/%s.pkl" % config["scenario"]["parametrization"]
        )
        self._params = pickle.loads(param_file)["hadron cascade"]
        muon_data = pkgutil.get_data(
            __name__,
            "data/%s_muon_production.pkl" % (config["scenario"]["parametrization"]),
        )
        if muon_data is None:
            raise ValueError("Muon production data not found!")
        self.__muon_prod_dict = pickle.loads(muon_data)
        _log.debug("Constructing spline dictionary")
        self.__muon_prod_spl_pars = {}
        for pdg_id in config["simulation"]["hadron particles"]:
            self.__muon_prod_spl_pars[pdg_id] = {
                "alpha": UnivariateSpline(
                    self.__muon_prod_dict[pdg_id][0],
                    self.__muon_prod_dict[pdg_id][1],
                    k=1,
                    s=0,
                    ext=3,
                ),
                "beta": UnivariateSpline(
                    self.__muon_prod_dict[pdg_id][0],
                    self.__muon_prod_dict[pdg_id][2],
                    k=1,
                    s=0,
                    ext=3,
                ),
                "gamma": UnivariateSpline(
                    self.__muon_prod_dict[pdg_id][0],
                    self.__muon_prod_dict[pdg_id][3],
                    k=1,
                    s=0,
                    ext=3,
                ),
            }
    else:
        raise ValueError(
            "Hadronic parametrization "
            + config["scenario"]["parametrization"]
            + " not implemented!"
        )
    if config["general"]["jax"]:
        _log.info("Running with JAX functions")
        self.cherenkov_angle_distro = self._symmetric_angle_distro_jax
        self.track_lengths = self._track_lengths_fetcher_jax
        self.em_fraction = self._em_fraction_fetcher_jax
        self.long_profile = self._log_profile_func_fetcher_jax
        self.muon_production = self._muon_production_fetcher_jax
    else:
        _log.info("Running with basic functions")
        self.cherenkov_angle_distro = self._symmetric_angle_distro
        self.track_lengths = self._track_lengths_fetcher
        self.em_fraction = self._em_fraction_fetcher
        self.long_profile = self._log_profile_func_fetcher
        self.muon_production = self._muon_production_fetcher