Coverage for src/km3pipe/mc.py: 69%
51 statements
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-08 03:14 +0000
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-08 03:14 +0000
1# Filename: mc.py
2# pylint: disable=C0103
3"""
4Monte Carlo related things.
6"""
7import particle
8import numpy as np
10from .logger import get_logger
12__author__ = "Tamas Gal and Moritz Lotze"
13__copyright__ = "Copyright 2016, Tamas Gal and the KM3NeT collaboration."
14__credits__ = []
15__license__ = "MIT"
16__maintainer__ = "Tamas Gal and Moritz Lotze"
17__email__ = "tgal@km3net.de"
18__status__ = "Development"
20log = get_logger(__name__) # pylint: disable=C0103
23def geant2pdg(geant_code):
24 """Convert GEANT particle ID to PDG"""
25 try:
26 return particle.Geant3ID(geant_code).to_pdgid()
27 except KeyError:
28 return 0
31def pdg2name(pdg_id):
32 """Convert PDG ID to human readable names"""
33 try:
34 return particle.Particle.from_pdgid(pdg_id).name
35 except particle.particle.particle.InvalidParticle:
36 log.debug("No particle with PDG ID %d found!" % pdg_id)
37 return "N/A"
40def name2pdg(name):
41 """Return best match of a PDG ID for the given name"""
42 return particle.Particle.from_string(name)
45def most_energetic(df):
46 """Grab most energetic particle from mc_tracks dataframe."""
47 idx = df.groupby(["event_id"])["energy"].transform(max) == df["energy"]
48 return df[idx].reindex()
51def leading_particle(df):
52 """Grab leading particle (neutrino, most energetic bundle muon).
54 Note: selecting the most energetic mc particle does not always select
55 the neutrino! In some sub-percent cases, the post-interaction
56 secondaries can have more energy than the incoming neutrino!
58 aanet convention: mc_tracks[0] = neutrino
59 so grab the first row
61 if the first row is not unique (neutrinos are unique), it's a muon bundle
62 grab the most energetic then
63 """
64 leading = df.groupby("event_id", as_index=False).first()
65 unique = leading.type.unique()
67 if len(unique) == 1 and unique[0] == 0:
68 leading = most_energetic(df)
69 return leading
72def get_flavor(pdg_types):
73 """Build a 'flavor' from the 'type' column."""
74 pd = km3pipe.extras.pandas()
76 return pd.Series(pdg_types).apply(pdg2name)
79def _p_eq_nu(pdg_type):
80 return np.abs(pdg_type) in {12, 14, 16}
83def _p_eq_mu(pdg_type):
84 return pdg_type == -13
87def is_neutrino(pdg_types):
88 """flavor string -> is_neutrino"""
89 pd = km3pipe.extras.pandas()
91 return pd.Series(pdg_types).apply(_p_eq_nu)
94def is_muon(pdg_types):
95 """flavor string -> is_neutrino"""
96 pd = km3pipe.extras.pandas()
98 return pd.Series(pdg_types).apply(_p_eq_mu)
101def convert_mc_times_to_jte_times(times_mc, evt_timestamp_in_ns, evt_mc_time):
102 """
103 Function that converts MC times to JTE times.
105 Parameters
106 ----------
107 times_mc : np.ndarray
108 Time array with MC times.
109 evt_timestamp_in_ns : int
110 Total timestamp of the event in nanoseconds.
111 evt_mc_time : int
112 Mc time of the event in nanoseconds.
114 Returns
115 -------
116 ndarray
117 Converted time array with JTE times.
118 """
119 # needs to be cast to normal ndarray (not recarray), or else we
120 # would get invalid type promotion
121 times_mc = np.array(times_mc).astype(float)
122 times_jte = times_mc - evt_timestamp_in_ns + evt_mc_time
123 return times_jte