Vectores de Lorentz, IDs de partículas PDG, agrupamiento de jets, ¡ay!#
Vectores de Lorentz#
Siguiendo con la filosofía de “muchos paquetes pequeños”, los vectores 2D/3D/Lorentz son manejados por un paquete llamado Vector. Aquí es donde puedes encontrar cálculos como deltaR
y transformaciones de coordenadas.
import vector
uno = vector.obj(px=1, py=0, pz=0)
dos = vector.obj(px=0, py=1, pz=1)
uno + dos
MomentumObject3D(px=1, py=1, pz=1)
uno.deltaR(dos)
np.float64(1.8011719796199461)
uno.to_rhophieta()
MomentumObject3D(pt=1.0, phi=0.0, eta=0.0)
dos.to_rhophieta()
MomentumObject3D(pt=1.0, phi=1.5707963267948966, eta=0.881373587019543)
Para integrarse con el resto del ecosistema, Vector debe ser una librería orientada a arreglos. Los arreglos de vectores 2D/3D/Lorentz se procesan en masa.
MomentumNumpy2D
, MomentumNumpy3D
, MomentumNumpy4D
son subtipos de arreglos NumPy: los arreglos de NumPy pueden ser convertidos a estos tipos y obtener todas las funciones vectoriales.
import skhep_testdata, uproot
import awkward as ak
import vector
tree = uproot.open(skhep_testdata.data_path("uproot-Zmumu.root"))["events"]
uno = ak.to_numpy(tree.arrays(filter_name=["E1", "p[xyz]1"]))
dos = ak.to_numpy(tree.arrays(filter_name=["E2", "p[xyz]2"]))
uno.dtype.names = ("E", "px", "py", "pz")
dos.dtype.names = ("E", "px", "py", "pz")
uno = uno.view(vector.MomentumNumpy4D)
dos = dos.view(vector.MomentumNumpy4D)
uno + dos
MomentumNumpy4D([( -7.0508504 , 1.31371932, -116.3919462 , 142.82374098),
( -6.07723788, 0.86288157, -117.74020834, 144.54679534),
( -5.76527367, 0.72893471, -117.22250173, 143.92770728), ...,
(-35.664423 , -24.9064416 , -226.76744871, 250.05025691),
(-36.41664408, -25.19899466, -228.38003444, 251.853268 ),
(-36.30874217, -25.19705013, -228.65597631, 252.14934978)],
shape=(2304,), dtype=[('x', '<f8'), ('y', '<f8'), ('z', '<f8'), ('t', '<f8')])
uno.deltaR(dos)
array([3.10530402, 3.10550819, 3.10547199, ..., 2.81363587, 2.81359933,
2.81354694], shape=(2304,))
uno.to_rhophieta()
MomentumNumpy3D([(44.7322, 2.74126 , -1.21769), (38.8311, -0.440873 , -1.05139),
(38.8311, -0.440873 , -1.05139), ...,
(32.3997, 0.0370275, -1.57044), (32.3997, 0.0370275, -1.57044),
(32.5076, 0.0369644, -1.57078)],
shape=(2304,), dtype=[('rho', '<f8'), ('phi', '<f8'), ('eta', '<f8')])
dos.to_rhophieta()
MomentumNumpy3D([(37.7582, -0.441078, -1.05138), (44.7322, 2.74126 , -1.21769),
(44.3927, 2.7413 , -1.21776), ...,
(72.8781, -2.77524 , -1.4827 ), (73.6852, -2.77519 , -1.48227),
(73.6852, -2.77519 , -1.48227)],
shape=(2304,), dtype=[('rho', '<f8'), ('phi', '<f8'), ('eta', '<f8')])
Después de llamar a vector.register_awkward()
, "Momentum2D"
, "Momentum3D"
, "Momentum4D"
son nombres de registros que Awkward Array reconocerá para obtener todas las funciones vectoriales.
vector.register_awkward()
tree = uproot.open(skhep_testdata.data_path("uproot-HZZ.root"))["events"]
array = tree.arrays(filter_name=["Muon_E", "Muon_P[xyz]"])
muones = ak.zip(
{"px": array.Muon_Px, "py": array.Muon_Py, "pz": array.Muon_Pz, "E": array.Muon_E},
with_name="Momentum4D",
)
mu1, mu2 = ak.unzip(ak.combinations(muones, 2))
mu1 + mu2
[[{x: -15.2, y: -11, z: -19.5, t: 94.2}], [], [{x: 49.8, y: 8.08, z: 48.1, t: 102}], [{x: 98.8, y: -99.8, z: 739, t: 758}], [{x: 84.9, y: 92.7, z: -69.6, t: 172}], [{x: 3.43, y: 10.3, z: 28.3, t: 97}], [{x: 42.1, y: -47, z: -151, t: 172}], [], [{x: -41.7, y: 87.6, z: 18.2, t: 133}], [{x: -85.1, y: 18.1, z: 112, t: 172}], ..., [], [], [], [{x: 2.94, y: 18.4, z: -262, t: 273}], [], [], [], [], []] ----------------------------------------- type: 2421 * var * Momentum4D[ x: float32, y: float32, z: float32, t: float32 ]
mu1.deltaR(mu2)
[[2.95], [], [2.13], [1.14], [1.43], [3.44], [1.49], [], [2.87], [1.86], ..., [], [], [], [2.76], [], [], [], [], []] -------------------------- type: 2421 * var * float32
muones.to_rhophieta()
[[{rho: 54.2, phi: -2.92, eta: -0.15, px: -52.9, py: -11.7}, {...}], [{rho: 24.4, phi: -1.6, eta: 0.754, px: -0.816, py: -24.4}], [{rho: 53.6, phi: -0.417, eta: 0.207, px: 49, py: -21.7}, {...}], [{rho: 88.6, phi: -1.32, eta: 2.22, px: 22.1, py: -85.8}, {...}], [{rho: 81, phi: 0.979, eta: -0.955, px: 45.2, py: 67.2}, {rho: ..., ...}], [{rho: 41.6, phi: 1.35, eta: -0.345, px: 9.23, py: 40.6}, {...}], [{rho: 44.4, phi: -1.28, eta: -1.76, px: 12.5, py: -42.5}, {...}], [{rho: 38.4, phi: -0.43, eta: 2.11, px: 34.9, py: -16}], [{rho: 106, phi: 2.09, eta: 0.329, px: -53.2, py: 92}, {rho: 12.3, ...}], [{rho: 85.5, phi: 2.47, eta: 0.6, px: -67, py: 53.2}, {rho: 39.5, ...}], ..., [{rho: 35.3, phi: 1.13, eta: -2.19, px: 14.9, py: 32}], [{rho: 42.6, phi: -2.17, eta: -0.437, px: -24.2, py: -35}], [{rho: 43.2, phi: -1.79, eta: -1.19, px: -9.2, py: -42.2}], [{rho: 45, phi: 0.696, eta: -1.92, px: 34.5, py: 28.8}, {rho: 33.2, ...}], [{rho: 41.9, phi: -2.79, eta: 1.18, px: -39.3, py: -14.6}], [{rho: 37.8, phi: -0.384, eta: 2.15, px: 35.1, py: -14.2}], [{rho: 33.5, phi: -2.67, eta: -1.24, px: -29.8, py: -15.3}], [{rho: 63.6, phi: 1.55, eta: 1.67, px: 1.14, py: 63.6}], [{rho: 42.9, phi: -0.98, eta: 1.06, px: 23.9, py: -35.7}]] --------------------------------------------------------------------------- type: 2421 * var * Momentum3D[ rho: float32, phi: float32, eta: float32, px: float32, py: float32 ]
Propiedades de partículas e identificadores PDG#
La librería Particle proporciona todas las masas de partículas, anchos de decaimiento y más del PDG. Además, contiene una serie de herramientas para consultar programáticamente las propiedades de las partículas y usar varios esquemas de identificación.
import particle
from hepunits import GeV
particle.Particle.findall("pi")
[<Particle: name="pi0", pdgid=111, mass=134.9768 ± 0.0005 MeV>,
<Particle: name="pi+", pdgid=211, mass=139.57039 ± 0.00018 MeV>,
<Particle: name="pi-", pdgid=-211, mass=139.57039 ± 0.00018 MeV>,
<Particle: name="pi(2)(1670)0", pdgid=10115, mass=1670.6 + 2.9 - 1.2 MeV>,
<Particle: name="pi(2)(1670)+", pdgid=10215, mass=1670.6 + 2.9 - 1.2 MeV>,
<Particle: name="pi(2)(1670)-", pdgid=-10215, mass=1670.6 + 2.9 - 1.2 MeV>,
<Particle: name="pi(1300)0", pdgid=100111, mass=1300 ± 100 MeV>,
<Particle: name="pi(1300)+", pdgid=100211, mass=1300 ± 100 MeV>,
<Particle: name="pi(1300)-", pdgid=-100211, mass=1300 ± 100 MeV>,
<Particle: name="pi(1)(1400)0", pdgid=9000113, mass=None>,
<Particle: name="pi(1)(1400)+", pdgid=9000213, mass=None>,
<Particle: name="pi(1)(1400)-", pdgid=-9000213, mass=None>,
<Particle: name="pi(1800)0", pdgid=9010111, mass=1810 + 9 - 11 MeV>,
<Particle: name="pi(1)(1600)0", pdgid=9010113, mass=1645 + 40 - 17 MeV>,
<Particle: name="pi(1800)+", pdgid=9010211, mass=1810 + 9 - 11 MeV>,
<Particle: name="pi(1800)-", pdgid=-9010211, mass=1810 + 9 - 11 MeV>,
<Particle: name="pi(1)(1600)+", pdgid=9010213, mass=1645 + 40 - 17 MeV>,
<Particle: name="pi(1)(1600)-", pdgid=-9010213, mass=1645 + 40 - 17 MeV>]
boson_z = particle.Particle.from_name("Z0")
boson_z.mass / GeV, boson_z.width / GeV
(91.188, 2.4955)
print(boson_z.describe())
Name: Z0 ID: 23 Latex: $Z^{0}$
Mass = 91188.0 ± 2.0 MeV
Width = 2495.5 ± 2.3 MeV
Q (charge) = 0 J (total angular) = 1.0 P (space parity) = None
C (charge parity) = None I (isospin) = None G (G-parity) = None
Antiparticle name: Z0 (antiparticle status: Same)
particle.Particle.from_pdgid(111)
particle.Particle.findall(
lambda p: p.pdgid.is_meson and p.pdgid.has_strange and p.pdgid.has_charm
)
[<Particle: name="D(s)+", pdgid=431, mass=1968.35 ± 0.07 MeV>,
<Particle: name="D(s)-", pdgid=-431, mass=1968.35 ± 0.07 MeV>,
<Particle: name="D(s)*+", pdgid=433, mass=2112.2 ± 0.4 MeV>,
<Particle: name="D(s)*-", pdgid=-433, mass=2112.2 ± 0.4 MeV>,
<Particle: name="D(s2)*(2573)+", pdgid=435, mass=2569.1 ± 0.8 MeV>,
<Particle: name="D(s2)*(2573)-", pdgid=-435, mass=2569.1 ± 0.8 MeV>,
<Particle: name="D(s0)*(2317)+", pdgid=10431, mass=2317.8 ± 0.5 MeV>,
<Particle: name="D(s0)*(2317)-", pdgid=-10431, mass=2317.8 ± 0.5 MeV>,
<Particle: name="D(s1)(2536)+", pdgid=10433, mass=2535.11 ± 0.06 MeV>,
<Particle: name="D(s1)(2536)-", pdgid=-10433, mass=2535.11 ± 0.06 MeV>,
<Particle: name="D(s1)(2460)+", pdgid=20433, mass=2459.5 ± 0.6 MeV>,
<Particle: name="D(s1)(2460)-", pdgid=-20433, mass=2459.5 ± 0.6 MeV>]
print(particle.PDGID(211).info())
A None
J 0.0
L 0
S 0
Z None
abspid 211
charge 1.0
has_bottom False
has_charm False
has_down True
has_fundamental_anti False
has_strange False
has_top False
has_up True
is_Qball False
is_Rhadron False
is_SUSY False
is_baryon False
is_diquark False
is_dyon False
is_excited_quark_or_lepton False
is_gauge_boson_or_higgs False
is_generator_specific False
is_hadron True
is_lepton False
is_meson True
is_nucleus False
is_pentaquark False
is_quark False
is_sm_gauge_boson_or_higgs False
is_sm_lepton False
is_sm_quark False
is_special_particle False
is_technicolor False
is_valid True
j_spin 1
l_spin 1
s_spin 1
three_charge 3
pdgid = particle.Corsika7ID(11).to_pdgid()
particle.Particle.from_pdgid(pdgid)
Agrupamiento de jets#
En una colisión pp de alta energía, por ejemplo, se produce una lluvia de hadrones que se agrupan en jets
de partículas, y este método/proceso se llama agrupamiento de jets (jet-clustering). El algoritmo de agrupamiento de jets anti-kt es uno de los algoritmos utilizados para combinar partículas/hadrones que están cerca entre sí en jets.
Algunas personas necesitan realizar agrupamiento de jets a nivel de análisis. El paquete fastjet hace posible hacerlo un array (Awkward) a la vez.
import skhep_testdata, uproot
import awkward as ak
import particle
from hepunits import GeV
import vector
vector.register_awkward()
picodst = uproot.open(
"https://pivarski-princeton.s3.amazonaws.com/pythia_ppZee_run17emb.picoDst.root:PicoDst"
)
px, py, pz = ak.unzip(
picodst.arrays(filter_name=["Track/Track.mPMomentum[XYZ]"], entry_stop=100)
)
probable_mass = particle.Particle.from_name("pi+").mass / GeV
pseudojets = ak.zip(
{"px": px, "py": py, "pz": pz, "mass": probable_mass}, with_name="Momentum4D"
)
good_pseudojets = pseudojets[pseudojets.pt > 0.1]
import fastjet
jetdef = fastjet.JetDefinition(fastjet.antikt_algorithm, 1.0)
clusterseq = fastjet.ClusterSequence(good_pseudojets, jetdef)
clusterseq.inclusive_jets()
ak.num(good_pseudojets), ak.num(clusterseq.inclusive_jets())
#--------------------------------------------------------------------------
# FastJet release 3.4.0
# M. Cacciari, G.P. Salam and G. Soyez
# A software package for jet finding and analysis at colliders
# http://fastjet.fr
#
# Please cite EPJC72(2012)1896 [arXiv:1111.6097] if you use this package
# for scientific work and optionally PLB641(2006)57 [hep-ph/0512210].
#
# FastJet is provided without warranty under the GNU GPL v2 or higher.
# It uses T. Chan's closest pair algorithm, S. Fortune's Voronoi code,
# CGAL and 3rd party plugin jet algorithms. See COPYING file for details.
#--------------------------------------------------------------------------
(<Array [24, 19, 13, 36, 39, 48, ..., 57, 41, 35, 34, 20, 93] type='100 * int64'>,
<Array [8, 6, 6, 7, 8, 9, 8, 7, ..., 9, 8, 7, 6, 7, 4, 11] type='100 * int64'>)