Particle database#
In PWA, you usually want to search for special resonances, possibly even some not listed in the PDG. In this notebook, we go through a few ways to add or overwrite Particle instances in the database with your own particle definitions.
Loading the default database#
In Generate transitions, we made use of the StateTransitionManager. By default, if you do not specify the particle_db argument, the StateTransitionManager calls the function load_default_particles(). This functions returns a ParticleCollection instance with Particle definitions from the PDG, along with additional definitions that are provided in the file additional_definitions.yml.
Here, we call this method directly to illustrate what happens (we use load_pdg(), which loads a subset):
The function load_pdg() uses a flag source to determine the source of the particle definitions. If source is set to "pdg", it loads particle definitions from the pdg package provided by PDG. If source is set to "particle", it loads the particle definitions from the particle package, which is provided by scikit-hep.
from qrules.particle import load_pdg
particle_db = load_pdg()
print("Number of loaded particles:", len(particle_db))
Number of loaded particles: 541
particle_db_pdg = load_pdg(source="pdg")
print("Number of particles loaded from PDG:", len(particle_db_pdg))
Number of particles loaded from PDG: 569
One can see on one hand that the number of loaded Particle definitions from the pdg package is currently greater than the number of particles loaded from the particle package and on the other hand, that loading the ParticleCollection instance takes significantly more time due to it using SQLite to store the particle data.
Warning
As of writing the pdg package does not support LaTeX names for particles (particledatagroup/api#42).
In the following, we illustrate how to use the methods of the ParticleCollection class to find and ‘modify’ Particles and add() them back to the ParticleCollection.
Finding particles#
The ParticleCollection class offers some methods to search for particles by name or by PID (see find()):
particle_db.find(333)
Particle(
name='phi(1020)',
pid=333,
latex='\\phi(1020)',
spin=Fraction(1, 1),
mass=1.01946,
width=0.004248999999999999,
isospin=Spin(0, 0),
parity=+-1,
c_parity=+-1,
g_parity=+-1,
)
With filter(), you can perform more sophisticated searches. This is done by either passing a function or lambda.
subset = particle_db.filter(lambda p: p.name.startswith("f(2)"))
subset.names
['f(2)(1270)',
"f(2)'(1525)",
'f(2)(1565)',
'f(2)(1950)',
'f(2)(2010)',
'f(2)(2150)',
'f(2)(2300)',
'f(2)(2340)']
subset = particle_db.filter(
lambda p: p.strangeness == 1 and p.spin >= 1 and p.mass > 1.8 and p.mass < 1.9
)
subset.names
['K(2)(1820)0',
'K(2)(1820)+',
'Lambda(1820)~',
'Lambda(1830)~',
'Lambda(1890)~']
subset = particle_db.filter(lambda p: p.is_lepton())
subset.names
['e-',
'e+',
'mu-',
'mu+',
'nu(mu)~',
'nu(tau)',
'nu(tau)~',
'nu(e)~',
'nu(e)',
'nu(mu)',
'tau-',
'tau+']
Note that in each of these examples, we call the names property. This is just to only display the names, sorted alphabetically, otherwise the output becomes a bit of a mess:
particle_db.filter(lambda p: p.name.startswith("pi") and len(p.name) == 3)
ParticleCollection({
Particle(
name='pi-',
pid=-211,
latex='\\pi^{-}',
spin=Fraction(0, 1),
mass=0.13957039000000002,
width=2.5284e-17,
charge=-1,
isospin=Spin(1, -1),
parity=+-1,
g_parity=+-1,
),
Particle(
name='pi0',
pid=111,
latex='\\pi^{0}',
spin=Fraction(0, 1),
mass=0.1349768,
width=7.81e-09,
isospin=Spin(1, 0),
parity=+-1,
c_parity=+1,
g_parity=+-1,
),
Particle(
name='pi+',
pid=211,
latex='\\pi^{+}',
spin=Fraction(0, 1),
mass=0.13957039000000002,
width=2.5284e-17,
charge=1,
isospin=Spin(1, +1),
parity=+-1,
g_parity=+-1,
),
})
LaTeX representation#
Particles also contain a latex tag. Here, we use ipython to render them nicely as mathematical symbols:
from IPython.display import Math
sigmas = particle_db.filter(lambda p: p.name.startswith("Sigma") and p.charmness == 1)
Math(", ".join(p.latex or p.name for p in sigmas))
Adding custom particle definitions through Python#
A quick way to modify or overwrite particles, is through your Python script or notebook. Notice that the instances in the database are Particle instances:
N1650_plus = particle_db["N(1650)+"]
N1650_plus
Particle(
name='N(1650)+',
pid=32212,
latex='N(1650)^{+}',
spin=Fraction(1, 2),
mass=1.65,
width=0.125,
charge=1,
isospin=Spin(1/2, +1/2),
baryon_number=1,
parity=+-1,
)
The instances in the database are immutable. Therefore, if you want to modify, say, the width, you have to create a new Particle instance from the particle you want to modify and add() it back to the database. You can do this with create_particle():
from qrules.particle import create_particle
new_N1650_plus = create_particle(
template_particle=N1650_plus, name="Modified N(1650)+", width=0.2
)
particle_db.add(new_N1650_plus)
particle_db["Modified N(1650)+"].width
0.2
You often also want to add the antiparticle of the particle you modified to the database. Using create_antiparticle(), it is easy to create the corresponding antiparticle object.
from qrules.particle import create_antiparticle
new_N1650_minus = create_antiparticle(new_N1650_plus, new_name="Modified N(1650)-")
particle_db.add(new_N1650_minus)
particle_db["Modified N(1650)-"]
Particle(
name='Modified N(1650)-',
pid=-32212,
latex='\\overline{N(1650)^{+}}',
spin=Fraction(1, 2),
mass=1.65,
width=0.2,
charge=-1,
isospin=Spin(1/2, -1/2),
baryon_number=-1,
parity=+1,
)
When adding additional particles you may need for your research, it is easiest to work with an existing particle as template. Let’s say we want to study \(e^+e^-\) collisions of several energies:
energies_mev = {4180, 4220, 4420, 4600}
template_particle = particle_db["J/psi(1S)"]
for energy_mev in energies_mev:
energy_gev = energy_mev / 1e3
new_particle = create_particle(
template_particle,
name=f"EpEm ({energy_mev} MeV)",
mass=energy_gev,
)
particle_db.add(new_particle)
len(particle_db)
547
particle_db.filter(lambda p: "EpEm" in p.name).names
['EpEm (4180 MeV)', 'EpEm (4220 MeV)', 'EpEm (4420 MeV)', 'EpEm (4600 MeV)']
Of course, it’s also possible to add any kind of custom Particle, as long as its quantum numbers comply with the gellmann_nishijima() rule:
from qrules.particle import Particle
custom = Particle(
name="custom",
pid=99999,
latex=R"p_\mathrm{custom}",
spin=1.0,
mass=1,
charge=1,
isospin=(1.5, 0.5),
charmness=1,
)
custom
Particle(
name='custom',
pid=99999,
latex='p_\\mathrm{custom}',
spin=Fraction(1, 1),
mass=1.0,
charge=1,
isospin=Spin(3/2, +1/2),
charmness=1,
)
548
Loading custom definitions from a YAML file#
It’s also possible to add particles from a config file, with io.load(). Existing entries remain and if the imported file of particle definitions contains a particle with the same name, it is overwritten in the database.
It’s easiest to work with YAML. Here, we use the provided additional_particles.yml example file:
from qrules import io
from qrules.particle import ParticleCollection
additional_particles = io.load("additional_particles.yml")
assert isinstance(additional_particles, ParticleCollection)
particle_db += additional_particles
Writing to YAML#
You can also dump the existing particle lists to YAML. You do this with the io.write() function.
io.write(instance=particle_db, filename="dumped_particle_list.yaml")
Note that the function write can dump any ParticleCollection to an output file, also a specific subset.
from qrules.particle import ParticleCollection
output = ParticleCollection()
output += particle_db["J/psi(1S)"]
output += particle_db.find(22) # gamma
output += particle_db.filter(lambda p: p.name.startswith("f(0)"))
output += particle_db["pi0"]
output += particle_db["pi+"]
output += particle_db["pi-"]
output += particle_db["custom"]
io.write(output, "particle_list_selection.yml")
output.names
['custom',
'f(0)(500)',
'f(0)(980)',
'f(0)(1370)',
'f(0)(1500)',
'f(0)(1710)',
'f(0)(2020)',
'gamma',
'J/psi(1S)',
'pi0',
'pi-',
'pi+']
As a side note, qrules provides JSON schemas (reaction/particle-validation.json) to validate your particle list files (see also jsonschema.validators.validate()). If you have installed qrules as an Editable installation and use VSCode, your YAML particle list are checked automatically in the GUI.