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 the usual workflow, you make use of the StateTransitionManager
. By default, if you do not specify the particles
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_particle_definitions.yml
.
Here, we call this method directly to illustrate what happens (we use io.load_pdg()
, which loads a subset):
from expertsystem import io
particle_db = io.load_pdg()
print("Number of loaded particles:", len(particle_db))
Number of loaded particles: 519
In the following, we illustrate how to use the methods of the ParticleCollection
class to find and ‘modify’ Particle
s 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,
spin=1.0,
mass=1.019461,
width=0.004248999999999999,
isospin=Spin(0.0, 0.0),
parity=Parity(-1),
c_parity=Parity(-1),
g_parity=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)'(1525)",
'f(2)(1270)',
'f(2)(1950)',
'f(2)(2010)',
'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)+',
'K(2)(1820)0',
'Lambda(1820)~',
'Lambda(1830)~',
'Lambda(1890)~'}
subset = particle_db.filter(lambda p: p.is_lepton())
subset.names
{'e+',
'e-',
'mu+',
'mu-',
'nu(e)',
'nu(e)~',
'nu(mu)',
'nu(mu)~',
'nu(tau)',
'nu(tau)~',
'tau+',
'tau-'}
In each of these examples, we call the names
property. This is just to only display the names, sorted alphabetically. The full representation of a ParticleCollection
looks like this:
particle_db.filter(lambda p: p.name.startswith("pi") and len(p.name) == 3)
ParticleCollection({Particle(
name="pi0",
pid=111,
spin=0.0,
mass=0.1349768,
width=7.73e-09,
isospin=Spin(1.0, 0.0),
parity=Parity(-1),
c_parity=Parity(+1),
g_parity=Parity(-1),
), Particle(
name="pi-",
pid=-211,
spin=0.0,
mass=0.13957039000000002,
width=2.5284e-17,
charge=-1,
isospin=Spin(1.0, -1.0),
parity=Parity(-1),
g_parity=Parity(-1),
), Particle(
name="pi+",
pid=211,
spin=0.0,
mass=0.13957039000000002,
width=2.5284e-17,
charge=1,
isospin=Spin(1.0, 1.0),
parity=Parity(-1),
g_parity=Parity(-1),
)})
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,
spin=0.5,
mass=1.65,
width=0.125,
charge=1,
isospin=Spin(0.5, 0.5),
baryon_number=1,
parity=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 expertsystem.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 expertsystem.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,
spin=0.5,
mass=1.65,
width=0.2,
charge=-1,
isospin=Spin(0.5, -0.5),
baryon_number=-1,
parity=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)
525
particle_db.filter(lambda p: "EpEm" in p.name).names
{'EpEm (4180 MeV)', 'EpEm (4220 MeV)', 'EpEm (4420 MeV)', 'EpEm (4600 MeV)'}
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:
particle_db += io.load("additional_particles.yml")
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 expertsystem.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-"]
io.write(output, "particle_list_selection.yml")
output.names
{'J/psi(1S)',
'f(0)(1370)',
'f(0)(1500)',
'f(0)(1710)',
'f(0)(500)',
'f(0)(980)',
'gamma',
'pi+',
'pi-',
'pi0'}
As a side note, the expertsystem
provides JSON schemas (e.g. yaml/particle-list.json
) to validate()
your particle list files (see also jsonschema.validate()
):
import yaml
with open("dumped_particle_list.yaml") as stream:
definition = yaml.load(stream, Loader=yaml.SafeLoader)
io.validate(definition)
In addition, if you have installed the expertsystem
in [Editable mode](install:Editable mode) and use VSCode, your YAML particle list are checked automatically in the GUI.