"""Primary particle definition."""
import logging
from particle import Corsika7ID, InvalidParticle, Particle
[docs]
class PrimaryParticle:
"""
Primary particle definition using CORSIKA7, eventio, or PDG ID.
Uses a dictionary to map particle common names to CORSIKA7 IDs.
Particles not found in the dictionary are searched in the PDG particle database.
Parameters
----------
particle_id_type : str
Type of the primary particle ID ('corsika7_id', 'common_name', or 'pdg_id').
particle_id : int or str
The actual ID of the primary particle.
"""
_valid_types = {
"corsika7_id": "corsika7_id",
"common_name": "name",
"pdg_id": "pdg_id",
"eventio_id": "eventio_id",
}
def __init__(self, particle_id_type=None, particle_id=None):
self._logger = logging.getLogger(__name__)
self._corsika7_id = None
self._name = None
self._pdg_id = None
self._pdg_name = None
self._eventio_id = None
if (particle_id_type is None) != (particle_id is None):
raise ValueError("Both 'particle_id_type' and 'particle_id' must be provided together.")
if particle_id_type:
try:
setattr(self, self._valid_types[particle_id_type], particle_id)
except KeyError as exc:
raise ValueError(
f"Particle ID type must be one of {set(self._valid_types)}"
) from exc
def __str__(self):
"""Return a string representation of the primary particle."""
return f"{self.name} ({self.corsika7_id}, {self.pdg_id}, {self.pdg_name})"
@property
def corsika7_id(self):
"""CORSIKA7 ID of the primary particle."""
return self._corsika7_id
@corsika7_id.setter
def corsika7_id(self, value):
"""Set CORSIKA7 ID of the primary particle."""
for name, ids in self.particle_names().items():
if value == ids["corsika7_id"]:
self._corsika7_id = int(value)
self._name = name
self._pdg_id = ids["pdg_id"]
self._pdg_name = ids["pdg_name"]
return
# no particle found - check PDG
try:
self._pdg_id = Corsika7ID(value).to_pdgid().numerator
self._pdg_name = Particle.findall(pdgid=self._pdg_id)[0].name
self._name = Corsika7ID(value).name()
except (IndexError, InvalidParticle) as exc:
raise ValueError(f"Invalid CORSIKA7 ID: {value}") from exc
self._corsika7_id = int(value)
@property
def eventio_id(self):
"""
EventIO ID of the primary particle.
0 (gamma), 1(e-), 2(mu-), 100*A+Z for nucleons and nuclei, negative for antimatter.
"""
return self._eventio_id
@eventio_id.setter
def eventio_id(self, value):
"""Set EventIO ID of the primary particle."""
mapping = {
0: 1,
1: 3,
-1: 2,
2: 6,
-2: 5,
101: 14,
-101: 15,
}
try:
self.corsika7_id = mapping.get(value, value)
except (ValueError, InvalidParticle) as exc:
raise ValueError(f"Invalid EventIO ID: {value}") from exc
self._eventio_id = value
@property
def name(self):
"""Common name of the primary particle."""
return self._name
@name.setter
def name(self, value):
"""Set common name of the primary particle."""
particles = self.particle_names()
if value.lower() in particles:
self._name = value.lower()
self._corsika7_id = particles[self._name]["corsika7_id"]
self._pdg_id = particles[self._name]["pdg_id"]
self._pdg_name = particles[self._name]["pdg_name"]
return
pdg_list = Particle.findall(lambda p: value in p.name)
if len(pdg_list) == 1:
self._pdg_id = pdg_list[0].pdgid.numerator
self._pdg_name = pdg_list[0].name
self._corsika7_id = Corsika7ID.from_pdgid(self._pdg_id).numerator
self._name = Corsika7ID.from_pdgid(self._pdg_id).name()
return
if len(pdg_list) > 1:
raise ValueError(f"Found more than one particle with name {value}: {pdg_list}")
raise ValueError(f"Invalid particle name: {value}")
@property
def pdg_id(self):
"""PDG ID of the primary particle."""
return self._pdg_id
@pdg_id.setter
def pdg_id(self, value):
"""Set PDG ID of the primary particle."""
# check if particle is in the default particle dictionary
for name, ids in self.particle_names().items():
if value == ids["pdg_id"]:
self._corsika7_id = ids["corsika7_id"]
self._name = name
self._pdg_id = value
self._pdg_name = ids["pdg_name"]
return
# no particle found - check PDG
try:
self._pdg_id = Particle.findall(pdgid=value)[0].pdgid.numerator
self._pdg_name = Particle.findall(pdgid=value)[0].name
except IndexError as exc:
raise ValueError(f"Invalid DPG ID: {value}") from exc
self._corsika7_id = Corsika7ID.from_pdgid(self._pdg_id).numerator
self._name = Corsika7ID.from_pdgid(self._pdg_id).name()
@property
def pdg_name(self):
"""PDG name of the primary particle."""
return self._pdg_name
[docs]
@staticmethod
def particle_names():
"""
Primary particles including common names, CORSIKA7 IDs, and PDG IDs.
Returns
-------
dict
Dictionary of particle names, CORSIKA7 IDs, and PDG IDs.
"""
particles = {
"gamma": {"corsika7_id": 1},
"electron": {"corsika7_id": 3},
"positron": {"corsika7_id": 2},
"muon+": {"corsika7_id": 5},
"muon-": {"corsika7_id": 6},
"proton": {"corsika7_id": 14},
"neutron": {"corsika7_id": 13},
"helium": {"corsika7_id": 402},
"carbon": {"corsika7_id": 601},
"nitrogen": {"corsika7_id": 1407},
"silicon": {"corsika7_id": 2814},
"iron": {"corsika7_id": 5626},
}
for _, ids in particles.items():
ids["pdg_id"] = Corsika7ID(ids["corsika7_id"]).to_pdgid().numerator
ids["pdg_name"] = Particle.findall(pdgid=ids["pdg_id"])[0].name
return particles