The Gaudi Framework  master (181af51f)
Loading...
Searching...
No Matches
ParticleID.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2023 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11#include <Gaudi/ParticleID.h>
12#include <array>
13#include <iostream>
14#include <sstream>
15
23
24namespace {
25 typedef std::array<unsigned int, 8> DATA;
26 inline DATA decode( const Gaudi::ParticleID& pid ) {
27 unsigned int m_extra = pid.abspid() / 10000000;
28 unsigned int m_n = pid.digit( Gaudi::ParticleID::n );
29 unsigned int m_nr = pid.digit( Gaudi::ParticleID::nr );
30 unsigned int m_nl = pid.digit( Gaudi::ParticleID::nl );
31 unsigned int m_nq1 = pid.digit( Gaudi::ParticleID::nq1 );
32 unsigned int m_nq2 = pid.digit( Gaudi::ParticleID::nq2 );
33 unsigned int m_nq3 = pid.digit( Gaudi::ParticleID::nq3 );
34 unsigned int m_nj = pid.digit( Gaudi::ParticleID::nj );
35 unsigned int aid = pid.abspid();
36
37 // Switch gluons to 0.
38 if ( m_nq1 == 9 ) m_nq1 = 0;
39 // Special particles with 99 code.
40 if ( m_n == 9 && m_nr == 9 ) {
41 // Translate the color-octet quarkonia numbering scheme from Pythia.
42 if ( m_nl > 3 ) {
43 std::swap( m_nl, m_nq3 );
44 m_nj = m_nq1 % 2 ? 1 : 3;
45 m_nq1 = 0;
46 m_nq2 = m_nq3;
47 }
48 // Handle the X(3872) states.
49 else if ( m_nl != 0 ) {
50 m_nr = 0;
51 }
52 // Map left-right symmetry for double charged Higgses from Pythia.
53 else if ( !m_nq2 && m_nq3 > 2 ) {
54 m_nq3 = 0;
55 m_nj = 9;
56 }
57 }
58 // The PDG hidden valley scheme.
59 else if ( m_n == 4 && m_nr == 9 && m_nq2 ) {
60 m_nq3 = m_nq2;
61 }
62 // The K0S/L and B0L/H.
63 else if ( aid == 130 || aid == 310 || aid == 150 || aid == 510 ) {
64 m_nl = 1;
65 m_nj = 1;
66 }
67 // Technical photons.
68 else if ( aid == 10022 || aid == 20022 ) {
69 m_nl = 0;
70 }
71 // Old heavy ion convention for hydrogen-2 nucleus.
72 else if ( m_extra == 45 ) {
73 m_extra = 100;
74 m_n = 0;
75 m_nr = 0;
76 m_nl = 1;
77 m_nq1 = 0;
78 m_nq2 = 0;
79 m_nq3 = 2;
80 m_nj = 0;
81 }
82 // Old heavy ion convention for hydrogen-3 nucleus.
83 else if ( m_extra == 46 ) {
84 m_extra = 100;
85 m_n = 0;
86 m_nr = 0;
87 m_nl = 1;
88 m_nq1 = 0;
89 m_nq2 = 0;
90 m_nq3 = 3;
91 m_nj = 0;
92 }
93 // Old heavy ion convention for helium-4 nucleus.
94 else if ( m_extra == 47 ) {
95 m_extra = 100;
96 m_n = 0;
97 m_nr = 0;
98 m_nl = 2;
99 m_nq1 = 0;
100 m_nq2 = 0;
101 m_nq3 = 4;
102 m_nj = 0;
103 }
104 // Old heavy ion convention for helium-3 nucleus.
105 else if ( m_extra == 49 ) {
106 m_extra = 100;
107 m_n = 0;
108 m_nr = 0;
109 m_nl = 2;
110 m_nq1 = 0;
111 m_nq2 = 0;
112 m_nq3 = 3;
113 m_nj = 0;
114 }
115 // The EvtGen particles Xsd (30343), Xsu (30353), and Xss (30363)
116 // which break the PDG conventions.
117 else if ( aid == 30343 ) {
118 m_nq1 = 2;
119 m_nq2 = 3;
120 m_nq3 = 1;
121 } else if ( aid == 30353 ) {
122 m_nq1 = 2;
123 m_nq2 = 3;
124 m_nq3 = 2;
125 } else if ( aid == 30363 ) {
126 m_nq1 = 2;
127 m_nq2 = 3;
128 m_nq3 = 3;
129 }
130 // Specific BSM particles.
131 else if ( aid == 1009002 ) {
132 m_nq1 = 0;
133 m_nq3 = 2;
134 m_nj = 1;
135 } else if ( aid == 1000542 ) {
136 m_nq1 = 5;
137 m_nq2 = 5;
138 m_nq3 = 5;
139 } else if ( aid == 1000522 ) {
140 m_nq1 = 1;
141 m_nq2 = 1;
142 m_nq3 = 1;
143 } else if ( aid == 1000039 ) {
144 m_n = 9;
145 m_nr = 9;
146 m_nq3 = 1;
147 m_nj = 0;
148 } else if ( aid == 3100021 ) {
149 m_nq1 = 1;
150 m_nq2 = 1;
151 m_nq3 = 2;
152 }
153 //
154 return { m_extra, m_nj, m_nq3, m_nq2, m_nq1, m_nl, m_nr, m_n };
155 }
156} // namespace
157// Return everything beyond the 7th PDG ID digit.
159 const unsigned int m_extra = abspid() / 10000000;
160 return 45 == m_extra ? 100u : 46 == m_extra ? 100u : 47 == m_extra ? 100u : 49 == m_extra ? 100u : m_extra;
161}
162/* Return the fundamental ID.
163 * This is 0 for nuclie, mesons, baryons, and di-quarks.
164 * Otherwise, this is the first two digits of the PDG ID
165 */
167 //
168 DATA data = decode( *this );
169 const unsigned int m_extra = data[0];
170 const unsigned int m_nl = data[Gaudi::ParticleID::nl];
171 const unsigned int m_nq1 = data[Gaudi::ParticleID::nq1];
172 const unsigned int m_nq2 = data[Gaudi::ParticleID::nq2];
173 const unsigned int m_nq3 = data[Gaudi::ParticleID::nq3];
174 const unsigned int m_nj = data[Gaudi::ParticleID::nj];
175 //
176 return !m_extra && !( m_nl + m_nq1 + m_nq2 ) ? 10 * m_nq3 + m_nj : 0;
177}
178// Return if the PID is valid.
180 // Nuclei, geantino, and intermediate.
181 if ( extraBits() ) {
182 return m_pid == 480000000 || m_pid == -990000000 || isNucleus();
183 }
184 // Standard model particles.
185 else if ( abspid() < 100 || isHadron() || isDiQuark() ) {
186 return true;
187 }
188 // Beyond the standard model particles.
189 else {
190 return !isSM();
191 }
192}
193// Return if the PID is from the standard model.
195 DATA data = decode( *this );
196 const unsigned int m_n = data[Gaudi::ParticleID::n];
197 const unsigned int m_nr = data[Gaudi::ParticleID::nr];
198 //
199 return m_n < 1 || ( m_n == 9 && m_nr != 9 );
200}
201// Return if the PID is for a meson.
203 //
204 if ( !isSM() ) { return false; }
205 //
206 DATA data = decode( *this );
207 const unsigned int m_nq1 = data[Gaudi::ParticleID::nq1];
208 const unsigned int m_nq2 = data[Gaudi::ParticleID::nq2];
209 const unsigned int m_nq3 = data[Gaudi::ParticleID::nq3];
210 const unsigned int m_nj = data[Gaudi::ParticleID::nj];
211 //
212 return m_nq1 == 0 && m_nq2 != 0 && m_nq3 != 0 && m_nj != 0 && !( pid() < 0 && m_nq2 == m_nq3 );
213}
214// Return if the PID is for a baryon.
216 //
217 if ( !isSM() ) { return false; }
218 //
219 DATA data = decode( *this );
220 const unsigned int m_nq1 = data[Gaudi::ParticleID::nq1];
221 const unsigned int m_nq2 = data[Gaudi::ParticleID::nq2];
222 const unsigned int m_nq3 = data[Gaudi::ParticleID::nq3];
223 const unsigned int m_nj = data[Gaudi::ParticleID::nj];
224 //
225 return m_nq1 != 0 && m_nq2 != 0 && m_nq3 != 0 && m_nj != 0;
226}
227// Return if the PID is for a di-quark.
229 //
230 if ( !isSM() ) { return false; }
231 //
232 DATA data = decode( *this );
233 const unsigned int m_nq1 = data[Gaudi::ParticleID::nq1];
234 const unsigned int m_nq2 = data[Gaudi::ParticleID::nq2];
235 const unsigned int m_nq3 = data[Gaudi::ParticleID::nq3];
236 const unsigned int m_nj = data[Gaudi::ParticleID::nj];
237 //
238 return m_nq1 != 0 && m_nq2 != 0 && m_nq3 == 0 && m_nj != 0 && !( m_nj == 1 && m_nq1 == m_nq2 );
239}
240// Return if the PID is for a hadron.
241bool Gaudi::ParticleID::isHadron() const { return isMeson() || isBaryon(); }
242// Return if the PID is for a lepton.
244 const unsigned int apid = abspid();
245 return 11 <= apid && apid <= 18;
246}
247// Return if the PID is for a nucleus.
248bool Gaudi::ParticleID::isNucleus() const { return 100 <= extraBits() && Z() <= A(); }
249// Return if the PID is for a bare quark.
251 const unsigned int apid = abspid();
253}
254// Return if the PID is a particle with quarks, but not a nucleus.
255bool Gaudi::ParticleID::hasQuarks() const { return !extraBits() && !fundamentalID(); }
256// Return if the PID is a particle containing a specified quark flavor.
257bool Gaudi::ParticleID::hasQuark( const Quark& q ) const {
258 if ( abspid() == q ) { return true; }
259 if ( !hasQuarks() ) { return false; }
260 //
261 DATA data = decode( *this );
262 const unsigned int m_nq1 = data[Gaudi::ParticleID::nq1];
263 const unsigned int m_nq2 = data[Gaudi::ParticleID::nq2];
264 const unsigned int m_nq3 = data[Gaudi::ParticleID::nq3];
265 //
266 return q == m_nq3 || q == m_nq2 || q == m_nq1;
267}
268// Return three times the charge, in units of e+, valid for all particles.
270 // Lookup table for charges. The Xu+ (43) and Xu0 (44) break the PDG
271 // conventions and are EvtGen specific. The c-hadron (84), b-hadron
272 // (85), t-hadron (86), b'-hadron (87), are LHCb specific but within
273 // the acceptable 81 - 100 range. A double charged Higgs is inserted
274 // as 9 and a gravintino as 10.
275 static const int q[101] = { 0, -1, 2, -1, 2, -1, 2, -1, 2, 6, 0, // 1 - 10.
276 -3, 0, -3, 0, -3, 0, -3, 0, 0, 0, // 11 - 20.
277 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, // 21 - 30.
278 0, 0, 0, 3, 0, 0, 3, 0, 0, 0, // 31 - 40.
279 0, -1, 0, 3, 0, 0, 0, 0, 0, 0, // 41 - 50.
280 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 51 - 60.
281 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 61 - 70.
282 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 71 - 80.
283 0, 0, 0, 2, -1, 2, -1, 0, 0, 0, // 81 - 90.
284 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // 91 - 100.
285 const unsigned int fid = fundamentalID();
286 int charge = 0;
287 //
288 DATA data = decode( *this );
289 const unsigned int m_nq1 = data[Gaudi::ParticleID::nq1];
290 const unsigned int m_nq2 = data[Gaudi::ParticleID::nq2];
291 const unsigned int m_nq3 = data[Gaudi::ParticleID::nq3];
292
293 // Nuclei.
294 if ( isNucleus() ) {
295 charge = 3 * Z();
296 }
297 // Fundamental particles from the charge table.
298 else if ( fid ) {
299 charge = q[fid];
300 }
301 // Mesons.
302 else if ( !m_nq1 ) {
303 charge = abs( q[m_nq2] - q[m_nq3] );
304 }
305 // Everything else.
306 else {
307 charge = q[m_nq3] + q[m_nq2] + q[m_nq1];
308 }
309
310 return ( pid() < 0 ? -1 : 1 ) * charge;
311}
312// Return 2J+1, where J is the total spin, valid for all particles.
314 // Lookup table for spins. The Xu+ (43) and Xu0 (44) break the PDG
315 // conventions and are EvtGen specific. The c-hadron (84), b-hadron
316 // (85), t-hadron (86), b'-hadron (87), are LHCb specific but within
317 // the acceptable 81 - 100 range. A double charged Higgs is inserted
318 // as 9 and a gravintino is inserted as 10.
319 static const unsigned int j[101] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 4, // 1 - 10.
320 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, // 11 - 20.
321 3, 3, 3, 3, 1, 0, 0, 0, 0, 0, // 21 - 30.
322 0, 3, 3, 3, 1, 1, 1, 1, 5, 0, // 31 - 40.
323 3, 1, 0, 0, 1, 1, 0, 0, 0, 0, // 41 - 50.
324 1, 2, 3, 1, 3, 1, 1, 1, 1, 1, // 51 - 60.
325 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 61 - 70.
326 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 71 - 80.
327 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 81 - 90.
328 0, 0, 3, 0, 0, 0, 0, 0, 0, 0 }; // 91 - 100.
329 const unsigned int fid = fundamentalID();
330 int spin = 0;
331 //
332 DATA data = decode( *this );
333 const unsigned int m_n = data[Gaudi::ParticleID::n];
334 const unsigned int m_nq3 = data[Gaudi::ParticleID::nq3];
335 const unsigned int m_nj = data[Gaudi::ParticleID::nj];
336 //
337 // Fundamental particles from the spin table.
338 if ( fid ) {
339 // Supersymmetric particles.
340 if ( m_n == 1 || m_n == 2 || m_n == 3 ) {
341 spin = j[fid] % 2 + 1;
342 }
343 // Standard particles.
344 else {
345 spin = j[fid];
346 }
347 }
348 // Nuclei.
349 else if ( isNucleus() ) {
350 spin = m_nq3 % 2 + 1;
351 }
352 // Everything else.
353 else {
354 spin = m_nj;
355 }
356 //
357 return spin;
358}
359
360// Return 2S+1, where S is the spin, valid only for mesons.
362 //
363 if ( !isMeson() ) { return 0; }
364 //
365 DATA data = decode( *this );
366 const unsigned int m_n = data[Gaudi::ParticleID::n];
367 const unsigned int m_nl = data[Gaudi::ParticleID::nl];
368 const unsigned int m_nj = data[Gaudi::ParticleID::nj];
369 //
370 if ( m_n == 9 ) {
371 return 0;
372 } else if ( m_nj == 1 ) {
373 return m_nl;
374 } else if ( m_nl == 1 ) {
375 return 0;
376 } else {
377 return 1;
378 }
379}
380
381// Return 2L+1, where L is the orbital angular momentum, valid only for mesons.
383 //
384 if ( !isMeson() ) { return 0; }
385 //
386 DATA data = decode( *this );
387 const unsigned int m_n = data[Gaudi::ParticleID::n];
388 const unsigned int m_nl = data[Gaudi::ParticleID::nl];
389 const unsigned int m_nj = data[Gaudi::ParticleID::nj];
390 //
391 if ( m_n == 9 ) {
392 return 0;
393 } else if ( m_nj == 1 ) {
394 return m_nl;
395 } else if ( m_nl == 0 ) {
396 return ( m_nj - 3 ) / 2;
397 } else if ( m_nl == 3 ) {
398 return ( m_nj + 1 ) / 2;
399 } else {
400 return ( m_nj - 1 ) / 2;
401 }
402}
403// Return the atomic number for a nucleus.
405 if ( extraBits() < 100 ) { return 0; }
406 //
407 DATA data = decode( *this );
408 //
409 const unsigned int m_n = data[Gaudi::ParticleID::n];
410 const unsigned int m_nr = data[Gaudi::ParticleID::nr];
411 const unsigned int m_nl = data[Gaudi::ParticleID::nl];
412 //
413 return m_n * 100 + m_nr * 10 + m_nl;
414}
415// Return the nucleon number for a nucleus.
417 if ( extraBits() < 100 ) { return 0; }
418 //
419 DATA data = decode( *this );
420 const unsigned int m_nq1 = data[Gaudi::ParticleID::nq1];
421 const unsigned int m_nq2 = data[Gaudi::ParticleID::nq2];
422 const unsigned int m_nq3 = data[Gaudi::ParticleID::nq3];
423 //
424 return m_nq1 * 100 + m_nq2 * 10 + m_nq3;
425}
426// Return the number of strange quarks for a nucleus.
428 const unsigned int m_extra = extraBits();
429 return 100 <= m_extra ? m_extra - 100 : 0;
430}
431// Fill a stream with the PID.
432std::ostream& Gaudi::ParticleID::fillStream( std::ostream& s ) const {
433 return s << "Gaudi.ParticleID(" << m_pid << ")";
434}
435// Return the PID stream representation as a string.
436std::string Gaudi::ParticleID::toString() const {
437 std::ostringstream s;
438 fillStream( s );
439 return s.str();
440}
441
442// Fill a stream with the PID digit enumeration.
443std::ostream& Gaudi::ParticleID::printLocation( const long l, std::ostream& s ) {
444 switch ( l ) {
446 return s << "Gaudi.ParticleID.nj";
448 return s << "Gaudi.ParticleID.nq3";
450 return s << "Gaudi.ParticleID.nq2";
452 return s << "Gaudi.ParticleID.nq1";
454 return s << "Gaudi.ParticleID.nl";
456 return s << "Gaudi.ParticleID.nr";
458 return s << "Gaudi.ParticleID.n";
460 return s << "Gaudi.ParticleID.n8";
462 return s << "Gaudi.ParticleID.n9";
464 return s << "Gaudi.ParticleID.n10";
465 default:;
466 }
467 return s << "Gaudi.ParticleID.Location(" << l << ")";
468}
469
470// Return the PID digit enumeration stream representation as a string.
471std::string Gaudi::ParticleID::printLocation( const long l ) {
472 std::ostringstream s;
473 printLocation( l, s );
474 return s.str();
475}
476
477// Fill a stream with the PID quark enumeration.
478std::ostream& Gaudi::ParticleID::printQuark( const long q, std::ostream& s ) {
479 switch ( q ) {
481 return s << "Gaudi.ParticleID.down";
483 return s << "Gaudi.ParticleID.up";
485 return s << "Gaudi.ParticleID.strange";
487 return s << "Gaudi.ParticleID.charm";
489 return s << "Gaudi.ParticleID.bottom";
491 return s << "Gaudi.ParticleID.top";
493 return s << "Gaudi.ParticleID.bottom_prime";
495 return s << "Gaudi.ParticleID.top_prime";
496 default:;
497 }
498 return s << "Gaudi.ParticleID.Quark(" << q << ")";
499}
500
501// Return the PID quark enumeration stream representation as a string.
502std::string Gaudi::ParticleID::printQuark( const long q ) {
503 std::ostringstream s;
504 printQuark( q, s );
505 return s.str();
506}
Holds PDG + LHCb extension particle code, following the PDG particle numbering scheme (pdg....
Definition ParticleID.h:43
bool isHadron() const
Return if the PID is for a hadron.
std::string toString() const
Return the PID stream representation as a string.
int Z() const
Return the atomic number for a nucleus.
int extraBits() const
Return everything beyond the 7th PDG ID digit.
static std::ostream & printLocation(const long l, std::ostream &s)
Fill a stream with the PID digit enumeration.
bool hasQuarks() const
Return if the PID is a particle with quarks, but not a nucleus.
bool isSM() const
Return if the PID is from the standard model.
int fundamentalID() const
Return the fundamental ID.
bool isDiQuark() const
Return if the PID is for a di-quark.
int jSpin() const
Return 2J+1, where J is the total spin, valid for all particles.
bool isValid() const
Return if the PID is valid.
static std::ostream & printQuark(const long q, std::ostream &s)
Fill a stream with the PID quark enumeration.
bool isQuark() const
Return if the PID is for a bare quark.
constexpr unsigned int abspid() const
Absolute value of the PDG ID.
Definition ParticleID.h:56
int nLambda() const
Return the number of strange quarks for a nucleus.
bool isBaryon() const
Return if the PID is for a baryon.
bool isNucleus() const
Return if the PID is for a nucleus.
int lSpin() const
Return 2L+1, where L is the orbital angular momentum, valid only for mesons.
bool hasQuark(const Quark &q) const
Return if the PID is a particle containing a specified quark flavor.
int pid() const
Retrieve the PDG ID.
Definition ParticleID.h:54
bool isMeson() const
Return if the PID is for a meson.
int m_pid
PDG ID.
Definition ParticleID.h:155
constexpr unsigned short digit(const Location &loc) const
Return the digit for a given PDG ID digit location.
Definition ParticleID.h:125
int A() const
Return the nucleon number for a nucleus.
int threeCharge() const
Return three times the charge, in units of e+, valid for all particles.
int sSpin() const
Return 2S+1, where S is the spin, valid only for mesons.
bool isLepton() const
Return if the PID is for a lepton.
std::ostream & fillStream(std::ostream &s) const
Fill a stream with the PID.
Quark
Quark PDG IDs.
Definition ParticleID.h:48
void swap(GaudiUtils::VectorMap< KEY, VALUE, KEYCOMPARE, ALLOCATOR > &left, GaudiUtils::VectorMap< KEY, VALUE, KEYCOMPARE, ALLOCATOR > &right)
the definition of specialized algorithm for swapping
Definition VectorMap.h:726