Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Corsika7ID (+converter) and Particle.from_nucleus() #426

Merged
merged 30 commits into from
Oct 27, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
598bc33
add Particle.from_nuclear_info +test for that
The-Ludwig Oct 11, 2022
907130b
add Corsika7ID
The-Ludwig Oct 11, 2022
d21ab99
add documentation to corsika/gen_conversion_table
The-Ludwig Oct 11, 2022
bb32bc4
add Corsika7Id.from_particle_description
The-Ludwig Oct 11, 2022
114957c
add Corsika7ID to exports
The-Ludwig Oct 11, 2022
2c9d834
change README for Corsika7ID and from_nucleus_info
The-Ludwig Oct 11, 2022
b498fe5
change README changes more readable
The-Ludwig Oct 11, 2022
6d8b65b
added copyright header
The-Ludwig Oct 11, 2022
cada05c
changed order of imports
The-Ludwig Oct 11, 2022
98d14bf
style: pre-commit fixes
pre-commit-ci[bot] Oct 11, 2022
d03cdd6
add tests for gen_conversion_table
The-Ludwig Oct 11, 2022
13b352c
udpate README.rst to simplilfy language on corsika doc
The-Ludwig Oct 21, 2022
fed51ca
Update README.rst
eduardo-rodrigues Oct 21, 2022
841192f
Update src/particle/particle/particle.py
eduardo-rodrigues Oct 21, 2022
643fc36
Update src/particle/corsika/corsika7id.py
eduardo-rodrigues Oct 21, 2022
d6b172e
Update src/particle/corsika/corsika7id.py
eduardo-rodrigues Oct 21, 2022
346207a
Update src/particle/corsika/corsika7id.py
eduardo-rodrigues Oct 21, 2022
9f24f4e
Update src/particle/corsika/corsika7id.py
eduardo-rodrigues Oct 21, 2022
809b344
Update src/particle/corsika/gen_conversion_table.py
eduardo-rodrigues Oct 21, 2022
f7176b2
style: pre-commit fixes
pre-commit-ci[bot] Oct 21, 2022
abc30e3
Apply fast implemented suggestions from code review
The-Ludwig Oct 21, 2022
9ef867b
style: pre-commit fixes
pre-commit-ci[bot] Oct 21, 2022
59e3b8b
implement suggestions
pre-commit-ci[bot] Oct 21, 2022
4e42800
Apply suggestions from code review
eduardo-rodrigues Oct 25, 2022
addf9e0
Apply suggestions from code review
eduardo-rodrigues Oct 25, 2022
019298e
Apply suggestions from code review
eduardo-rodrigues Oct 25, 2022
cdd6eaf
restore unneeded update of pdgid_to_lhcbname.csv
The-Ludwig Oct 25, 2022
0dfc02b
clearify error message in to_pdgid
The-Ludwig Oct 25, 2022
aa9dc93
Apply suggestions from code review
eduardo-rodrigues Oct 25, 2022
cffa874
supress pylint warnings
The-Ludwig Oct 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ or, say, the name used in EvtGen, you can get a particle directly.
>>>
>>> Particle.from_evtgen_name("J/psi")
<Particle: name="J/psi(1S)", pdgid=443, mass=3096.900 ± 0.006 MeV>
>>>
>>> Particle.from_nucleus_info(a=12, z=6)
The-Ludwig marked this conversation as resolved.
Show resolved Hide resolved
<Particle: name="C12", pdgid=1000060120, mass=11177.9291399 MeV>

A similar method exists to get a list of particles from a PDG style name:

Expand Down Expand Up @@ -312,7 +315,7 @@ Possible use cases are the following:
.. code-block:: python

>>> from particle import Particle
>>> from particle import Geant3ID, PythiaID
>>> from particle import Geant3ID, PythiaID, Corsika7ID
eduardo-rodrigues marked this conversation as resolved.
Show resolved Hide resolved
>>>
>>> g3id = Geant3ID(8)
>>> p = Particle.from_pdgid(g3id.to_pdgid())
Expand All @@ -328,6 +331,24 @@ Possible use cases are the following:
>>> p.name
'pi+'

>>> cid = Corsika7ID(5)
>>> p = Particle.from_pdgid(cid.to_pdgid())
>>> p.name
'mu+'

Corsika7
eduardo-rodrigues marked this conversation as resolved.
Show resolved Hide resolved
^^^^^^^^

The ``Corsika7ID`` class implements some features to make it easier to work with Corsika7 output.
The-Ludwig marked this conversation as resolved.
Show resolved Hide resolved
For a full featureset, look into the ``particle.corsika`` module.
eduardo-rodrigues marked this conversation as resolved.
Show resolved Hide resolved

``Corsika7ID.from_particle_description(from_particle_description: int)`` returns ``(Corsika7ID, bool)``
to automatically parse the ``particle_description`` from the Corsika7 particle data sub-block.

``Corsika7ID.is_particle()`` checks if the id refers to an actual particle or something else (like additional information).
eduardo-rodrigues marked this conversation as resolved.
Show resolved Hide resolved

``Corsika7ID.to_pdgid()`` converts the ``Corsika7ID`` to a ``PDGID`` if possible.


Getting started: experiment-specific modules
--------------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions src/particle/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@

import sys

# Direct access to other ID classes
from .geant import Geant3ID

# Direct access to Particle literals
# Direct access to Particle (the CSV file is not read until a particle is accessed)
from .particle import InvalidParticle, Particle, ParticleNotFound, literals
Expand All @@ -19,6 +16,8 @@
# Direct access to PDGID and other ID classes
from .pdgid import PDGID
from .pythia import PythiaID
from .corsika import Corsika7ID
from .geant import Geant3ID

# Convenient access to the version number
from .version import version as __version__
Expand All @@ -32,6 +31,7 @@
__all__ = (
"Charge",
"Geant3ID",
"Corsika7ID",
The-Ludwig marked this conversation as resolved.
Show resolved Hide resolved
"Inv",
"InvalidParticle",
"PDGID",
Expand Down
2 changes: 2 additions & 0 deletions src/particle/converters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from __future__ import annotations

from .corsika import Corsika72PDGIDBiMap
from .evtgen import EvtGen2PDGNameMap, EvtGenName2PDGIDBiMap, PDG2EvtGenNameMap
from .geant import Geant2PDGIDBiMap
from .pythia import Pythia2PDGIDBiMap
Expand All @@ -16,6 +17,7 @@
"PDG2EvtGenNameMap",
"Geant2PDGIDBiMap",
"Pythia2PDGIDBiMap",
"Corsika72PDGIDBiMap",
)


Expand Down
26 changes: 26 additions & 0 deletions src/particle/converters/corsika.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright (c) 2018-2022, Eduardo Rodrigues and Henry Schreiner.
#
# Distributed under the 3-clause BSD license, see accompanying file LICENSE
# or https://github.com/scikit-hep/particle for details.


from __future__ import annotations

from ..corsika import Corsika7ID
from ..pdgid import PDGID
from .bimap import BiMap

Corsika72PDGIDBiMap = BiMap(PDGID, Corsika7ID)
Corsika72PDGIDBiMap.__doc__ = """
Bi-bidirectional map between PDG and Corsika7 IDs.

Examples
--------
>>> cid = Corsika72PDGIDBiMap[PDGID(-13)]
>>> cid
<Corsika7ID: 13>

>>> cid = Corsika72PDGIDBiMap[Corsika7ID(5)]
>>> cid
<PDGID: -13>
"""
15 changes: 15 additions & 0 deletions src/particle/corsika/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright (c) 2018-2022, Eduardo Rodrigues and Henry Schreiner.
#
# Distributed under the 3-clause BSD license, see accompanying file LICENSE
# or https://github.com/scikit-hep/particle for details.


from __future__ import annotations

from .corsika7id import Corsika7ID

__all__ = ("Corsika7ID",)


def __dir__() -> tuple[str, ...]:
return __all__
168 changes: 168 additions & 0 deletions src/particle/corsika/corsika7id.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# Copyright (c) 2018-2022, Eduardo Rodrigues and Henry Schreiner.
#
# Distributed under the 3-clause BSD license, see accompanying file LICENSE
# or https://github.com/scikit-hep/particle for details.

"""
Class representing a Corsika7 ID.

Note
----
Corsika8 uses Geant3 Particle IDs.
"""


from __future__ import annotations

import csv
from typing import TypeVar

from .. import data
from ..exceptions import MatchingIDNotFound
from ..pdgid import PDGID

Self = TypeVar("Self", bound="Corsika7ID")


with data.basepath.joinpath("pdgid_to_corsika7id.csv").open() as _f:
_bimap = {
int(v["CORSIKA7ID"]): int(v["PDGID"])
for v in csv.DictReader(line for line in _f if not line.startswith("#"))
}

# Some Corsika ID's are not really particles
The-Ludwig marked this conversation as resolved.
Show resolved Hide resolved
The-Ludwig marked this conversation as resolved.
Show resolved Hide resolved
_non_particles = {
71: "η → γγ",
72: "η → 3π◦",
73: "η → π+π−π◦",
74: "η → π+π−γ",
75: "μ+ add. info.",
76: "μ− add. info.",
85: "decaying μ+ at start",
86: "decaying μ− at start",
95: "decaying μ+ at end",
96: "decaying μ− at end",
}


class Corsika7ID(int):
"""
Holds a Corsika7 ID.

Examples
--------
>>> cid = Corsika7ID(6)

>>> from particle import Particle
>>> p = Particle.from_pdgid(cid.to_pdgid())

>>> (p,) = Particle.finditer(pdgid=cid.to_pdgid())
>>> p.name
'mu-'
"""
The-Ludwig marked this conversation as resolved.
Show resolved Hide resolved

@classmethod
def from_pdgid(cls: type[Self], pdgid: int) -> Self:
"""
Constructor from a PDGID.
"""
for k, v in _bimap.items():
if v == pdgid:
return cls(k)
raise MatchingIDNotFound(f"Non-existent Corsika7ID for input PDGID {pdgid}!")

@classmethod
def from_particle_description(
cls: type[Self], particle_description: int
) -> tuple[Self, bool]:
"""
Constructor from the particle description returned by Corsika7
in the particle data sub-block, mother particle data sub-block or
the grandmother particle data sub-block.

Returns
-------
eduardo-rodrigues marked this conversation as resolved.
Show resolved Hide resolved
Corsika7ID: The Corsika7 id
bool: If the particle is a (grand)motherparticle.
eduardo-rodrigues marked this conversation as resolved.
Show resolved Hide resolved
"""
cid = abs(particle_description) // 1000
ismother = particle_description < 0

if cls._is_non_particle_id(cid):
return cls(cid), ismother

# this catches the case, of nuclei with no known PDGid
The-Ludwig marked this conversation as resolved.
Show resolved Hide resolved
if cid >= 200 and cid < 5699:
return cls(cid), ismother

if cid in _bimap:
return cls(cid), ismother

raise MatchingIDNotFound(
f"Non-existent Corsika7ID for particle_description {particle_description}!"
eduardo-rodrigues marked this conversation as resolved.
Show resolved Hide resolved
)

@classmethod
def _is_non_particle_id(cls: type[Self], id: int) -> bool:
"""
returns True if the id is a valid id, but not a particle, False otherwise.
The-Ludwig marked this conversation as resolved.
Show resolved Hide resolved
"""
return id in _non_particles or id // 1000 == 8888 or id == 9900

def is_particle(self) -> bool:
"""
Returns if the corsikaid really belongs to a particle, since some are for example additional information.
The-Ludwig marked this conversation as resolved.
Show resolved Hide resolved
"""
iid = int(self)

return not self._is_non_particle_id(iid)

def name(self) -> str:
The-Ludwig marked this conversation as resolved.
Show resolved Hide resolved
"""
Returns a human readable name of the Corsika ID.
eduardo-rodrigues marked this conversation as resolved.
Show resolved Hide resolved
This also works for non-particles (is_particle()==false).

Raises
------
ParticleNotFound
If it is a 'valid' PDG particle, but unknown.
This for example happens with strange nuclei, which are not in the nuclei list.
"""
from ..particle.particle import Particle

if self.is_particle():
return str(Particle.from_pdgid(self.to_pdgid()).name)

iid = int(self)

if iid in _non_particles:
return _non_particles[iid]

if iid // 1000 == 8888:
return "weights of preceding particle (MULTITHIN option)"

if iid == 9900:
return "Cherenkov photons on particle output file"

raise RuntimeError("This should be unreachable.")

def to_pdgid(self) -> PDGID:
"""
Raises
------
InvalidParticle
If it is a valid Corsika particle, but not a valid PDGid particle.
The-Ludwig marked this conversation as resolved.
Show resolved Hide resolved
"""
from ..particle.particle import InvalidParticle

if self not in _bimap:
raise InvalidParticle(
f"The Corsika7Id {self} is not a valid PDGID particle."
The-Ludwig marked this conversation as resolved.
Show resolved Hide resolved
)
return PDGID(_bimap[self])

def __repr__(self) -> str:
return f"<{self.__class__.__name__}: {int(self):d}>"

def __str__(self) -> str:
return repr(self)
The-Ludwig marked this conversation as resolved.
Show resolved Hide resolved
Loading