PDG Python API: decay query#
import pdg
PDG = pdg.connect()
This creates a PdgApi
instance containing the following type of objects:
{type(obj) for obj in PDG.get_all()}
{pdg.data.PdgLifetime,
pdg.data.PdgMass,
pdg.data.PdgProperty,
pdg.data.PdgWidth,
pdg.decay.PdgBranchingFraction,
pdg.particle.PdgParticleList}
In this example, we ask the question which particles can decay to a final state with three equal particles? For this, we use PdgBranchingFraction
s, which contain information about particle decays in their description
:
jpsi_decay = PDG.get("M070.313/2023")
type(jpsi_decay)
pdg.decay.PdgBranchingFraction
jpsi_decay.description
'J/psi(1S) --> rho(1700) pi --> pi+ pi- pi0'
So, let’s pull all the decay descriptions from the PDG and do some clean up with str.strip()
and set
:
from pdg.decay import PdgBranchingFraction
all_decays = {obj for obj in PDG.get_all() if isinstance(obj, PdgBranchingFraction)}
decay_descriptions = {dec.description.strip() for dec in all_decays}
len(decay_descriptions)
7245
To get more insight into the decay products, we create a new set
of decay descriptions, but now describe each item as an initial state with a tuple
of decay products. We again have to do a bit of cleaning here. The final state description sometimes contains digits, like "3pi0"
, which we want to be rendered as ("pi0", "pi0", "pi0")
.
Note that we decay all state descriptions in the decay chain into account. For example,
"J/psi(1S) --> rho(1700) pi --> pi+ pi- pi0"
has two ‘final’ states:
("rho(1700)", "pi")
("pi+", "pi-", "pi0")
Show code cell source
def create_final_state(description: str) -> tuple[str, ...]:
items = []
for particle in description.split():
particle = particle.strip()
if particle in {"", ","}:
continue
multiplier = particle[0]
if multiplier.isdigit():
particles = int(multiplier) * particle[1:]
items.extend(particles)
else:
items.append(particle)
return tuple(sorted(items))
decays: set[tuple[str, tuple[str, ...]]] = set()
for description in decay_descriptions:
initial_state, *final_states = description.split(" --> ")
initial_state = initial_state.strip()
decays.update(
(initial_state, create_final_state(final_state)) for final_state in final_states
)
len(decays)
7359
Now selecting the three-body decays is an easy matter using filters on comprehensions.
2194
[('B0', ('K0S', 'K0S', 'K0S')),
('B0', ('a', 'a', 'a')),
('B_s()0', ('a', 'a', 'a')),
('B_s()0', ('phi', 'phi', 'phi')),
('J/psi(1S)', ('g', 'g', 'g')),
('J/psi(1S)', ('gamma', 'gamma', 'gamma')),
('Upsilon(1S)', ('g', 'g', 'g')),
('Upsilon(2S)', ('g', 'g', 'g')),
('Upsilon(3S)', ('g', 'g', 'g')),
('Z', ('g', 'g', 'g')),
('Z', ('gamma', 'gamma', 'gamma')),
('a_1(1260)', ('pi0', 'pi0', 'pi0')),
('a_1(1640)', ('pi', 'pi', 'pi')),
('pi_1(1600)', ('pi', 'pi', 'pi')),
('pi_2(1670)', ('pi0', 'pi0', 'pi0')),
('psi(2S)', ('g', 'g', 'g'))]
Finally, and optionally, we can filter out final states that are not well defined, such as g g g
, by checking whether they are defined in the PDG database.
Show code cell source
from pdg.errors import PdgAmbiguousValueError, PdgNoDataError
for initial_state, final_state in sorted(equal_state_3body_decays):
try:
for name in (initial_state, *final_state):
PDG.get_particle_by_name(name)
except (PdgAmbiguousValueError, PdgNoDataError):
pass
else:
print(f"{initial_state:>20} → {' '.join(final_state)}")
J/psi(1S) → g g g
J/psi(1S) → gamma gamma gamma
Upsilon(1S) → g g g
Upsilon(2S) → g g g
Upsilon(3S) → g g g
Z → g g g
Z → gamma gamma gamma
psi(2S) → g g g
Warning
Not all final state in the description
s can be programmatically deciphered as individual particles. One could try to use regular expressions, but it’s hard to cover all cases. Consider for instance the following case which contains \(S\) and \(D\) waves.
[dec for dec in decay_descriptions if dec.startswith("a_1(1260)")]
['a_1(1260) --> K^*(892) K',
'a_1(1260) --> ( rho(1450) pi )(S-wave) , rho --> pi pi',
'a_1(1260) --> f_2(1270) pi , f_2() --> pi pi',
'a_1(1260) --> f_0(500) pi , f_0() --> pi pi',
'a_1(1260) --> f_0(980) pi , f_0() --> pi pi',
'a_1(1260) --> pi0 pi0 pi0',
'a_1(1260) --> pi+ pi- pi0',
'a_1(1260) --> ( rho(1450) pi )(D-wave) , rho --> pi pi',
'a_1(1260) --> pi gamma',
'a_1(1260) --> ( rho pi )(D-wave) , rho --> pi pi',
'a_1(1260) --> 3 pi',
'a_1(1260) --> f_0(1370) pi , f_0() --> pi pi',
'a_1(1260) --> K K pi',
'a_1(1260) --> ( rho pi )(S-wave) , rho --> pi pi']
Additionally, not all decays seem to be included. Here is an attempt to find \(J/\psi \to \pi^0 \pi^0 \pi^0\).
Show code cell source
['J/psi(1S) --> 2(pi+ pi- pi0)',
'J/psi(1S) --> 2(pi+ pi- pi0) eta',
'J/psi(1S) --> 2(pi+ pi-) 3pi0',
'J/psi(1S) --> 2(pi+ pi-) pi0',
'J/psi(1S) --> 3(pi+ pi-) pi0',
'J/psi(1S) --> 4(pi+ pi-) pi0',
'J/psi(1S) --> K+ K- pi0 pi0 pi0',
'J/psi(1S) --> K0S K+- pi-+ pi+ pi-',
'J/psi(1S) --> K0S K+- pi-+ pi0 pi0',
'J/psi(1S) --> K^*(892)+ K0S pi- + c.c. --> K0S K0S pi+ pi-',
'J/psi(1S) --> K^*(892)0 K- pi+ + c.c. --> K+ K- pi+ pi-',
'J/psi(1S) --> K_2^*(1430)0 K- pi+ + c.c. --> K+ K- pi+ pi-',
'J/psi(1S) --> a_2(1320)+ pi- pi0 + c.c --> 2 (pi+ pi- ) pi0',
'J/psi(1S) --> a_2(1320)0 pi+ pi- --> 2 (pi+ pi- ) pi0',
'J/psi(1S) --> eta pi+ pi- 3 pi0',
'J/psi(1S) --> eta pi+ pi- pi0',
'J/psi(1S) --> gamma pi+ pi- 2pi0',
'J/psi(1S) --> omega 3 pi0',
'J/psi(1S) --> omega pi+ pi+ pi- pi-',
'J/psi(1S) --> omega pi+ pi- 2pi0',
'J/psi(1S) --> omega pi+ pi- pi0',
'J/psi(1S) --> omega pi0 --> pi+ pi- pi0',
'J/psi(1S) --> p pbar pi+ pi- pi0',
'J/psi(1S) --> phi f_1(1285) --> phi pi0 f_0(980) --> phi 3pi0',
'J/psi(1S) --> phi f_1(1285) --> phi pi0 f_0(980) --> phi pi0 pi+ pi-',
'J/psi(1S) --> phi pi0 f_0(980) --> phi pi0 p0 pi0',
'J/psi(1S) --> phi pi0 f_0(980) --> phi pi0 pi+ pi-',
'J/psi(1S) --> pi+ pi- 3pi0',
'J/psi(1S) --> pi+ pi- 4 pi0',
'J/psi(1S) --> pi+ pi- pi0',
'J/psi(1S) --> pi+ pi- pi0 K+ K-',
'J/psi(1S) --> pi+ pi- pi0 pi0 eta',
'J/psi(1S) --> rho(1450) pi --> pi+ pi- pi0',
'J/psi(1S) --> rho(1700) pi --> pi+ pi- pi0',
'J/psi(1S) --> rho(2150) pi --> pi+ pi- pi0',
'J/psi(1S) --> rho+ K+ K- pi- + c.c --> K+ K- pi+ pi- pi0',
'J/psi(1S) --> rho+ rho- pi+ pi- pi0',
'J/psi(1S) --> rho+- pi-+ pi+ pi- 2pi0',
'J/psi(1S) --> rho+- pi-+ pi0 pi0',
'J/psi(1S) --> rho_3(1690) pi --> pi+ pi- pi0']