ATLAS Offline Software
Loading...
Searching...
No Matches
AtlasPID.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4#ifndef TRUTHUTILS_ATLASPID_H
5#define TRUTHUTILS_ATLASPID_H
6#include <vector>
7#include <cmath>
8#include <algorithm>
9#include <array>
10#include <cstdlib>
11#include <cstddef>
16
17constexpr std::array<int, 9> MIN_DIGIT = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
18constexpr std::array<int, 9> MAX_DIGIT = {9, 99, 999, 9999, 99999, 999999, 9999999,99999999, 999999999};
19template <typename... Ns>
20constexpr bool hasAllowedNumberOfDigits(int p, Ns... digits) {
21 return ((std::abs(p) >= MIN_DIGIT[digits - 1] && std::abs(p) <= MAX_DIGIT[digits - 1]) || ...);
22}
23
24class DecodedPID: public std::pair<int,std::vector<int>> {
25public:
26 inline DecodedPID(const int& p){
27 this->first=p;
28 this->second.reserve(10);
29 int ap = std::abs(p);
30 for(; ap; ap/=10) this->second.push_back( ap%10 );
31 std::reverse(this->second.begin(), this->second.end());
32 }
33 inline DecodedPID shift(const size_t n) const { return DecodedPID(this->first%int(std::pow(10,ndigits()-n)));}
34 inline const int& operator()(const size_t n) const { return this->second.at(n);}
35 inline const int& last() const { return this->second.back();}
36 inline const int& pid() const { return this->first;}
37 inline int max_digit(const int m, const int n) const { return *std::max_element(second.rbegin() + m, second.rbegin() + n);}
38 inline int min_digit(const int m, const int n) const { return *std::min_element(second.rbegin() + m, second.rbegin() + n);}
39 inline size_t ndigits() const { return this->second.size();}
40};
41
42static const int TABLESIZE = 100;
43static const std::array<int,TABLESIZE> triple_charge = {
44 +0, -1, +2, -1, +2, -1, +2, -1, +2, +0,
45 +0, -3, +0, -3, +0, -3, +0, -3, +0, +0,
46 +0, +0, +0, +0, +3, +0, +0, +0, +0, +0,
47 +0, +0, +0, +0, +3, +0, +0, +3, +6, +0,
48 +0, +0, -1, +0, +0, +0, +0, +0, +0, +0,
49 +0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
50 +0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
51 +0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
52 +0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
53 +0, +0, +0, +0, +0, +0, +0, +0, +0, +0
54};
55
56//Note: The PDG rules assign the range 51-60 for generic DM, with explicit spins defined for 51-55.
57// To keep the rest of this range consistent within ATLAS, 56, 57 and 58 are assigned spins 0, +1/2, +1 (respectively) as seen in https://arxiv.org/abs/2504.10597v2
58static const std::array<int,TABLESIZE> double_spin = {
59 +0, +1, +1, +1, +1, +1, +1, +1, +1, +0,
60 +0, +1, +1, +1, +1, +1, +1, +1, +1, +0,
61 +2, +2, +2, +2, +2, +0, +0, +0, +0, +0,
62 +0, +0, +2, +2, +2, +0, +0, +0, +0, +4,
63 +0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
64 +0, +0, +1, +2, +0, +2, +0, +1, +2, +0,
65 +0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
66 +0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
67 +0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
68 +0, +0, +0, +0, +0, +0, +0, +0, +0, +0
69};
70
73
74static const int DQUARK = 1;
75static const int UQUARK = 2;
76static const int SQUARK = 3;
77static const int CQUARK = 4;
78static const int BQUARK = 5;
79static const int TQUARK = 6;
82static const int BPRIME = 7; // 4th Generation quark
83static const int TPRIME = 8; // 4th Generation quark
84static const int QUARK_LIMIT = BPRIME; // Quark pdg_ids less than this are considered in (R-)Hadrons and Diquarks
85
86static const int ELECTRON = 11;
87static const int POSITRON = -ELECTRON;
88static const int NU_E = 12;
89static const int MUON = 13;
90static const int NU_MU = 14;
91static const int TAU = 15;
92static const int NU_TAU = 16;
93static const int LPRIME = 17; // 4th Generation charged lepton
94static const int NUPRIME = 18; // 4th Generation neutrino
95
96static const int GLUON = 21;
97// APID: 9 rather than 21 is used to denote a gluon/gluino in composite states. (From PDG 11g)
98static const int COMPOSITEGLUON = 9;
99static const int PHOTON = 22;
100static const int Z0BOSON = 23;
101static const int WPLUSBOSON = 24;
102static const int HIGGSBOSON = 25;
103static const int ZPRIME = 32; // Z′/Z^0_2
104static const int ZDBLPRIME = 33; // Z′′/Z^0_3
105static const int WPLUSPRIME = 34; // W ′/W^+_2
106static const int HIGGS2 = 35; // H^0/H^0_2 FIXME Any better ideas?
107static const int HIGGS3 = 36; // A^0/H^0_3 FIXME Any better ideas?
108static const int HIGGSPLUS = 37; // H^+
109static const int HIGGSPLUSPLUS = 38; // H^++
110static const int GRAVITON = 39;
111static const int HIGGS4 = 40; // a^0/H^0_4 FIXME Any better ideas?
112static const int LEPTOQUARK = 42;
113
118static const int DARKPHOTON = 60000;
119static const int MAVTOP = 60001;
120
121static const int PIPLUS = 211;
122static const int PIMINUS = -PIPLUS;
123static const int PI0 = 111;
124static const int K0L = 130;
125
126static const int K0S = 310;
127static const int K0 = 311;
128static const int KPLUS = 321;
129static const int DPLUS = 411;
130static const int DSTAR = 413;
131static const int D0 = 421;
132static const int DSPLUS = 431;
133static const int JPSI = 443;
134static const int B0 = 511;
135static const int BCPLUS = 541;
136static const int PROTON = 2212;
137static const int NEUTRON = 2112;
138static const int LAMBDA0 = 3122;
139static const int LAMBDACPLUS = 4122;
140static const int LAMBDAB0 = 5122;
141static const int PSI2S = 20443;
142
150static const int RH_NU_E = 9900012;
151static const int RH_NU_MU = 9900014;
152static const int RH_NU_TAU = 9900016;
153static const int WBOSON_LRSM = 9900024;
154
155static const int LEAD = 1000822080;
156static const int INDIUM = 1000491150;
157static const int KRYPTON = 1000360840;
158static const int CALCIUM = 1000200400;
159static const int ARGON = 1000180400;
160static const int MAGNESIUM = 1000120240;
161static const int NEON = 1000100200;
162static const int OXYGEN = 1000080160;
163static const int BORON = 1000050110;
164static const int HELIUM = 1000020040;
165
169static const int POMERON = 990;
170static const int ODDERON = 9990;
171static const int REGGEON = 110;
172
178static const int GEANTINOPLUS = 998;
179static const int GEANTINO0 = 999;
180
181
187template <class T> inline bool isQuark(const T& p) {return isQuark(p->pdg_id());}
188template <> inline bool isQuark(const int& p) { return p != 0 && (std::abs(p) <= TPRIME || std::abs(p) == MAVTOP);}
189template <> inline bool isQuark(const DecodedPID& p){ return isQuark(p.pid()); }
190
191// APID: the fourth generation quarks are not standard model quarks
192template <class T> inline bool isSMQuark(const T& p) {return isSMQuark(p->pdg_id());}
193template <> inline bool isSMQuark(const int& p) { return p != 0 && std::abs(p) <= TQUARK;}
194template <> inline bool isSMQuark(const DecodedPID& p){ return isSMQuark(p.pid()); }
195
196template <class T> inline bool isStrange(const T& p) {return isStrange(p->pdg_id());}
197template <> inline bool isStrange(const int& p){ return std::abs(p) == SQUARK;}
198
199template <class T> inline bool isCharm(const T& p){return isCharm(p->pdg_id());}
200template <> inline bool isCharm(const int& p){ return std::abs(p) == CQUARK;}
201
202template <class T> inline bool isBottom(const T& p){return isBottom(p->pdg_id());}
203template <> inline bool isBottom(const int& p){ return std::abs(p) == BQUARK;}
204
205template <class T> inline bool isTop(const T& p){return isTop(p->pdg_id());}
206template <> inline bool isTop(const int& p){ return std::abs(p) == TQUARK;}
207
209template <class T> inline bool isLepton(const T& p){return isLepton(p->pdg_id());}
210template <> inline bool isLepton(const int& p){ auto sp = std::abs(p); return sp >= ELECTRON && sp <= NUPRIME; }
211template <> inline bool isLepton(const DecodedPID& p){ return isLepton(p.pid()); }
212
214template <class T> inline bool isSMLepton(const T& p){return isSMLepton(p->pdg_id());}
215template <> inline bool isSMLepton(const int& p){ auto sp = std::abs(p); return sp >= ELECTRON && sp <= NU_TAU; }
216template <> inline bool isSMLepton(const DecodedPID& p){ return isSMLepton(p.pid()); }
217
219template <class T> inline bool isChLepton(const T& p){return isChLepton(p->pdg_id());}
220template <> inline bool isChLepton(const int& p){ auto sp = std::abs(p); return sp >= ELECTRON && sp <= LPRIME && sp%2 == 1; }
221
222template <class T> inline bool isElectron(const T& p){return isElectron(p->pdg_id());}
223template <> inline bool isElectron(const int& p){ return std::abs(p) == ELECTRON;}
224
225template <class T> inline bool isMuon(const T& p){return isMuon(p->pdg_id());}
226template <> inline bool isMuon(const int& p){ return std::abs(p) == MUON;}
227
228template <class T> inline bool isTau(const T& p){return isTau(p->pdg_id());}
229template <> inline bool isTau(const int& p){ return std::abs(p) == TAU;}
230
232template <class T> inline bool isNeutrino(const T& p){return isNeutrino(p->pdg_id());}
233template <> inline bool isNeutrino(const int& p){ auto sp = std::abs(p); return sp == NU_E || sp == NU_MU || sp == NU_TAU || sp == NUPRIME; }
234
235template <class T> inline bool isSMNeutrino(const T& p){return isSMNeutrino(p->pdg_id());}
236template <> inline bool isSMNeutrino(const int& p){ auto sp = std::abs(p); return sp == NU_E || sp == NU_MU || sp == NU_TAU; }
237
240template <class T> inline bool isFourthGeneration(const T& p){return isFourthGeneration(p->pdg_id());}
241template <> inline bool isFourthGeneration(const int& p) {return std::abs(p) == BPRIME || std::abs(p) == TPRIME || std::abs(p) == LPRIME || std::abs(p) == NUPRIME;}
242
247template <class T> inline bool isDiquark(const T& p){return isDiquark(p->pdg_id());}
248template <> inline bool isDiquark(const DecodedPID& p){
249 if ( p.ndigits() == 4 && p(0) >= p(1) && p(1) != 0 && p(2) == 0 && (p.last() == 1 || p.last() == 3)
250 && p.max_digit(2,4) < QUARK_LIMIT
251 ) return true;
252 return false;
253}
254template <> inline bool isDiquark(const int& p){ if (!hasAllowedNumberOfDigits(p,4)) return false; auto value_digits = DecodedPID(p); return isDiquark(value_digits);}
255
270template <class T> inline bool isMeson(const T& p){return isMeson(p->pdg_id());}
271template <> inline bool isMeson(const DecodedPID& p){
272 if (p.ndigits() < 3 ) return false;
273 if (p.ndigits() == 7 && (p(0) == 1 || p(0) == 2)) return false; // APID don't match SUSY particles
274 if (std::abs(p.pid()) == K0S) return true;
275 if (std::abs(p.pid()) == K0L) return true;
276 if (std::abs(p.pid()) == K0) return true;
277 if (p.last() % 2 != 1 ) return false;
278 if (p.max_digit(1,3) >= QUARK_LIMIT ) return false; // Ignore pdg_ids which would describe states including fourth generation quarks
279 if (p.min_digit(1,3) == 0 ) return false;
280 if (*(p.second.rbegin() + 2) < *(p.second.rbegin() + 1) ) return false; // Quark ordering (nq2 >= nq3)
281 if (*(p.second.rbegin() + 2) == *(p.second.rbegin() + 1) && p.pid() < 0 ) return false; // Illegal antiparticle check (nq2 == nq3)
282 if (p.ndigits() == 3 ) return true;
283 if (*(p.second.rbegin() + 3) != 0 ) return false; // Only two quarks! (nq1 == 0)
284 if (p.ndigits() == 5 && p(0) == 1 ) return true;
285 if (p.ndigits() == 5 && p(0) == 2 && p.last() > 1 ) return true;
286 if (p.ndigits() == 5 && p(0) == 3 && p.last() > 1 ) return true;
287 if (p.ndigits() == 6 && p.last() % 2 == 1 ) return true;
288 if (p.ndigits() == 7 && p(0) == 9 && p(1) == 0 ) return true;
289
290 return false;
291}
292template <> inline bool isMeson(const int& p){ auto value_digits = DecodedPID(p); return isMeson(value_digits);}
293
295template <class T> inline bool isQuarkonium(const T& p){return isQuarkonium(p->pdg_id());}
296template <> inline bool isQuarkonium(const DecodedPID& p) {
297 if (!isMeson(p)) return false; //< all quarkonia are mesons
298 return (*(p.second.rbegin() + 2) > SQUARK && p.last() > 0 && *(p.second.rbegin() + 1) == *(p.second.rbegin() + 2));
299}
300template <> inline bool isQuarkonium(const int& p){ auto value_digits = DecodedPID(p); return isQuarkonium(value_digits);}
301
304template <class T> inline bool isBaryon(const T& p){return isBaryon(p->pdg_id());}
305template <> inline bool isBaryon(const DecodedPID& p){
306 if (p.ndigits() < 4 ) return false;
307 if (p.max_digit(1,4) >= QUARK_LIMIT ) return false; // Ignore pdg_ids which would describe states including fourth generation quarks
308 if (p.min_digit(1,4) == 0) return false; // Ignore pdg_ids with zero for nq1, nq2, nq3
309 if (p.ndigits() == 4 && (p.last() == 2 || p.last() == 4|| p.last() == 6|| p.last() == 8) ) return true;
310
311 if (p.ndigits() == 5 && p(0) == 1 && (p.last() == 2 || p.last() == 4) ) return true;
312 if (p.ndigits() == 5 && p(0) == 3 && (p.last() == 2 || p.last() == 4) ) return true;
313
314 if (p.ndigits() == 6 ) {
315 if (p(0) == 1 && p(1) == 0 && p.last() == 2 ) return true;
316 if (p(0) == 1 && p(1) == 0 && p.last() == 4 ) return true;
317 if (p(0) == 1 && p(1) == 0 && p.last() == 6 ) return true;
318 if (p(0) == 1 && p(1) == 1 && p.last() == 2 ) return true;
319 if (p(0) == 1 && p(1) == 2 && p.last() == 4 ) return true;
320
321 if (p(0) == 2 && p(1) == 0 && p.last() == 2 ) return true;
322 if (p(0) == 2 && p(1) == 0 && p.last() == 4 ) return true;
323 if (p(0) == 2 && p(1) == 0 && p.last() == 6 ) return true;
324 if (p(0) == 2 && p(1) == 0 && p.last() == 8 ) return true;
325 if (p(0) == 2 && p(1) == 1 && p.last() == 2 ) return true;
326 }
327
328 if (p.ndigits() == 5 ) {
329 if (p(0) == 2 && p.last() == 2 ) return true;
330 if (p(0) == 2 && p.last() == 4 ) return true;
331 if (p(0) == 2 && p.last() == 6 ) return true;
332 if (p(0) == 5 && p.last() == 2 ) return true;
333 if (p(0) == 1 && p.last() == 6 ) return true;
334 if (p(0) == 4 && p.last() == 2 ) return true;
335 }
336 return false;
337}
338template <> inline bool isBaryon(const int& p){if (!hasAllowedNumberOfDigits(p,4,5,6)) return false; auto value_digits = DecodedPID(p); return isBaryon(value_digits);}
339
347template <class T> inline bool isTetraquark(const T& p){return isTetraquark(p->pdg_id());}
348template <> inline bool isTetraquark(const DecodedPID& p){
349 return (p.ndigits() == 9 && p(0) == 1 && p(5) == 0 &&
350 p.max_digit(1,3) < QUARK_LIMIT && p.min_digit(1,3) > 0 && // ignore 4th generation quarks for nq3 and nq4
351 p.max_digit(4,6) < QUARK_LIMIT && p.min_digit(4,6) > 0 && // ignore 4th generation quarks for nq1 and nq2
352 ( p(3) >= p(4) && p(6) >= p(7) ) && ( ( p(3) > p(6) ) || ( p(3) == p(6) && (p(4) >= p(7))))
353 );
354}
355template <> inline bool isTetraquark(const int& p){ if (!hasAllowedNumberOfDigits(p,9)) return false; auto value_digits = DecodedPID(p); return isTetraquark(value_digits);}
356
363// APID: states with fourth generation quarks are not pentaquarks
364template <class T> inline bool isPentaquark(const T& p){return isPentaquark(p->pdg_id());}
365template <> inline bool isPentaquark(const DecodedPID& p){
366 return (p.ndigits() == 9 && p(0) == 1 &&
367 p.max_digit(1,6) < QUARK_LIMIT && p.min_digit(1,6) > 0 && // ignore 4th generation (anti-)quarks
368 ( p(3) >= p(4) && p(4) >= p(5) && p(5) >= p(6)) );
369}
370template <> inline bool isPentaquark(const int& p){ if (!hasAllowedNumberOfDigits(p,9)) return false; auto value_digits = DecodedPID(p); return isPentaquark(value_digits);}
371
372// APID Mesons, Baryons, Tetraquarks and Pentaquarks are Hadrons
373template <class T> inline bool isHadron(const T& p){return isHadron(p->pdg_id());}
374template <> inline bool isHadron(const DecodedPID& p){ return isMeson(p) || isBaryon(p) || isTetraquark(p) || isPentaquark(p); }
375template <> inline bool isHadron(const int& p){ auto value_digits = DecodedPID(p); return isHadron(value_digits);}
376
377
381template <class T> inline bool isTrajectory(const T& p){return isTrajectory(p->pdg_id());}
382template <> inline bool isTrajectory(const int& p){ return std::abs(p) == POMERON || std::abs(p) == ODDERON || std::abs(p) == REGGEON; }
383
384
391template <class T> inline bool isBoson(const T& p){return isBoson(p->pdg_id());}
392template <> inline bool isBoson(const int& p){ auto sp = std::abs(p); return sp > 20 && sp < 41; }
393template <> inline bool isBoson(const DecodedPID& p){ return isBoson(p.pid()); }
394
395template <class T> inline bool isGluon(const T& p){return isGluon(p->pdg_id());}
396template <> inline bool isGluon(const int& p){ return p == GLUON; }
397
398template <class T> inline bool isPhoton(const T& p){return isPhoton(p->pdg_id());}
399template <> inline bool isPhoton(const int& p){ return p == PHOTON; }
400
401template <class T> inline bool isZ(const T& p){return isZ(p->pdg_id());}
402template <> inline bool isZ(const int& p){ return p == Z0BOSON; }
403
404template <class T> inline bool isW(const T& p){return isW(p->pdg_id());}
405template <> inline bool isW(const int& p){ return std::abs(p) == WPLUSBOSON; }
406
408template <class T> inline bool isHeavyBoson(const T& p){return isHeavyBoson(p->pdg_id());}
409template <> inline bool isHeavyBoson(const int& p){ return p == ZPRIME || p == ZDBLPRIME || std::abs(p) == WPLUSPRIME; }
410
412template <class T> inline bool isHiggs(const T& p){return isHiggs(p->pdg_id());}
413template <> inline bool isHiggs(const int& p){ return p == HIGGSBOSON; }
414
416template <class T> inline bool isMSSMHiggs(const T& p){return isMSSMHiggs(p->pdg_id());}
417template <> inline bool isMSSMHiggs(const int& p){ return p == HIGGS2 || p == HIGGS3 || std::abs(p) == HIGGSPLUS; }
418
419template <class T> inline bool isGraviton(const T& p) {return isGraviton(p->pdg_id());}
420template <> inline bool isGraviton(const int& p){ return p == GRAVITON; }
421
422template <class T> inline bool isResonance(const T& p) { return isZ(p) || isW(p) || isHiggs(p) || isTop(p); } // APID: not including t' (pdg_id=8), Z', Z'' and W'+ or BSM Higgs bosons
423
430template <class T> inline bool isLeptoQuark(const T& p){return isLeptoQuark(p->pdg_id());}
431template <> inline bool isLeptoQuark(const int& p){ return std::abs(p) == LEPTOQUARK; }
432
433template <class T> inline bool isPythia8Specific(const T& p){ return isPythia8Specific(p->pdg_id());}
434template <> inline bool isPythia8Specific(const DecodedPID& p){ return (p.ndigits() == 7 && p(0) == 9 && p(1) == 9);}
435template <> inline bool isPythia8Specific(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isPythia8Specific(value_digits);}
436
444template <class T> inline bool isNeutrinoRH(const T& p){return isNeutrinoRH(p->pdg_id());}
445template <> inline bool isNeutrinoRH(const int& p){ return (std::abs(p) == RH_NU_E || std::abs(p) == RH_NU_MU|| std::abs(p) == RH_NU_TAU);}
446
449template <class T> inline bool isGenSpecific(const T& p){return isGenSpecific(p->pdg_id());}
450template <> inline bool isGenSpecific(const int& p){
451 int ap = std::abs(p);
452 if (ap >= 81 && ap <= 100) return true;
453 if (ap >= 901 && ap <= 930) return true;
454 if (ap >= 998 && ap <= 999) return true;
455 if (ap >= 1901 && ap <= 1930) return true;
456 if (ap >= 2901 && ap <= 2930) return true;
457 if (ap >= 3901 && ap <= 3930) return true;
458 return false;
459}
460
461template <class T> inline bool isGeantino(const T& p){return isGeantino(p->pdg_id());}
462template <> inline bool isGeantino(const int& p){ return (std::abs(p) == GEANTINO0 || std::abs(p) == GEANTINOPLUS);}
463
468template <class T> inline bool isGlueball(const T& p) { return isGlueball(p->pdg_id()); }
469template <> inline bool isGlueball(const DecodedPID& p) {
470 if (p.ndigits() > 4) return false; // APID avoid classifying R-Glueballs as SM Glueballs
471 return
472 ( ( p.ndigits() == 3 && p(0) == COMPOSITEGLUON && p(1) == COMPOSITEGLUON && (p.last() == 1 || p.last() == 5) ) ||
473 ( p.ndigits() == 4 && p(0) == COMPOSITEGLUON && p(1) == COMPOSITEGLUON && p(2) == COMPOSITEGLUON && (p.last() == 3 || p.last() == 7) ) );
474}
475template <> inline bool isGlueball(const int& p) { if (!hasAllowedNumberOfDigits(p,3,4)) return false; auto value_digits = DecodedPID(p); return isGlueball(value_digits); }
476
477
483
484// APID: Super-partners of standard model quarks only
485template <class T> inline bool isSquark(const T& p) { return isSquark(p->pdg_id()); }
486template <> inline bool isSquark(const DecodedPID& p){
487 auto pp = p.shift(1); return (p.ndigits() == 7 && (p(0) == 1 || p(0) == 2) && isSMQuark(pp));
488}
489template <> inline bool isSquark(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isSquark(value_digits);}
490
491
492// APID: Super-partners of left-handed standard model quarks only
493template <class T> inline bool isSquarkLH(const T& p) { return isSquarkLH(p->pdg_id()); }
494template <> inline bool isSquarkLH(const DecodedPID& p){
495 auto pp = p.shift(1); return (p.ndigits() == 7 && p(0) == 1 && isSMQuark(pp));
496}
497template <> inline bool isSquarkLH(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isSquarkLH(value_digits);}
498
499
500// APID: Super-partners of right-handed standard model quarks only
501template <class T> inline bool isSquarkRH(const T& p) { return isSquarkRH(p->pdg_id()); }
502template <> inline bool isSquarkRH(const DecodedPID& p){
503 auto pp = p.shift(1); return (p.ndigits() == 7 && p(0) == 2 && isSMQuark(pp));
504}
505template <> inline bool isSquarkRH(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isSquarkRH(value_digits);}
506
507
508// APID: Super-partners of standard model leptons only
509template <class T> inline bool isSlepton(const T& p) { return isSlepton(p->pdg_id()); }
510template <> inline bool isSlepton(const DecodedPID& p){ auto pp = p.shift(1); return (p.ndigits() == 7 && (p(0) == 1 || p(0) == 2) && isSMLepton(pp));}
511template <> inline bool isSlepton(const int& p){ auto value_digits = DecodedPID(p); return isSlepton(value_digits);}
512
513
514// APID: Super-partners of left-handed standard model leptons only
515template <class T> inline bool isSleptonLH(const T& p) { return isSleptonLH(p->pdg_id()); }
516template <> inline bool isSleptonLH(const DecodedPID& p){
517 auto pp = p.shift(1); return (p.ndigits() == 7 && p(0) == 1 && isSMLepton(pp));
518}
519template <> inline bool isSleptonLH(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isSleptonLH(value_digits);}
520
521
522// APID: Super-partners of right-handed standard model leptons only
523template <class T> inline bool isSleptonRH(const T& p) { return isSleptonRH(p->pdg_id()); }
524template <> inline bool isSleptonRH(const DecodedPID& p){
525 auto pp = p.shift(1); return (p.ndigits() == 7 && p(0) == 2 && isSMLepton(pp));
526}
527template <> inline bool isSleptonRH(const int& p){ auto value_digits = DecodedPID(p); return isSleptonRH(value_digits);}
528
529
530// APID: Super-partners of gauge bosons including gravitons
531template <class T> inline bool isGaugino(const T& p) { return isGaugino(p->pdg_id()); }
532template <> inline bool isGaugino(const DecodedPID& p){
533 auto pp = p.shift(1); return (p.ndigits() == 7 && p(0) == 1 && isBoson(pp.pid()));
534}
535template <> inline bool isGaugino(const int& p){ auto value_digits = DecodedPID(p); return isGaugino(value_digits);}
536
537
538// APID: Super-partners of fundamental particles
539template <class T> inline bool isSuperpartner(const T& p) { return isSuperpartner(p->pdg_id()); }
540template <> inline bool isSuperpartner(const DecodedPID& p){
541 return isSlepton(p) || isSquark(p) || isGaugino(p);
542}
543template <> inline bool isSuperpartner(const int& p){ auto value_digits = DecodedPID(p); return isSuperpartner(value_digits);}
544
545
551template <class T> inline bool isTechnicolor(const T& p){return isTechnicolor(p->pdg_id());}
552template <>
553inline bool isTechnicolor(const DecodedPID& p) {
554 const auto& pp = (p.ndigits() == 7) ? p.shift(2) : DecodedPID(0);
555 return (p.ndigits() == 7 && p(0) == 3 && (p(1) == 0 || p(1) == 1) &&
556 (isQuark(pp) || isLepton(pp) || isBoson(pp) || isGlueball(pp) ||
557 isDiquark(pp) || isHadron(pp)));
558}
559template <> inline bool isTechnicolor(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isTechnicolor(value_digits);}
560
563template <class T> inline bool isExcited(const T& p){return isExcited(p->pdg_id());}
564template <>
565inline bool isExcited(const DecodedPID& p) {
566 const auto& pp = (p.ndigits() == 7) ? p.shift(2) : DecodedPID(0);
567 return (p.ndigits() == 7 && (p(0) == 4 && p(1) == 0) &&
568 (isLepton(pp) || isQuark(pp)));
569}
570template <> inline bool isExcited(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isExcited(value_digits);}
571
584
589template <class T> inline bool isRGlueball(const T& p) { return isRGlueball(p->pdg_id()); }
590template <> inline bool isRGlueball(const DecodedPID& p) {
591 if (p.ndigits() != 7 || p(0) != 1) return false;
592 auto pp = p.shift(1);
593 return
594 ( ( pp.ndigits() == 3 && pp(0) == COMPOSITEGLUON && pp(1) == COMPOSITEGLUON && (pp.last() == 1 || pp.last() == 3) ) ||
595 ( pp.ndigits() == 4 && pp(0) == COMPOSITEGLUON && pp(1) == COMPOSITEGLUON && pp(2) == COMPOSITEGLUON && (pp.last() == 1 || pp.last() == 5) ) );
596}
597template <> inline bool isRGlueball(const int& p) { if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isRGlueball(value_digits); }
598
599// APID Define R-Mesons as gluino-quark-antiquark and squark-antiquark bound states (ignore 4th generation squarks/quarks)
600// NB Current models only allow gluino-quark-antiquark, stop-antiquark and sbottom-antiquark states
601template <class T> inline bool isRMeson(const T& p) { return isRMeson(p->pdg_id()); }
602template <> inline bool isRMeson(const DecodedPID& p) {
603 if (!(p.ndigits() == 7 && (p(0) == 1 || p(0) == 2))) return false;
604 auto pp = p.shift(1);
605 return (
606 // Handle ~gluino-quark-antiquark states
607 (pp.ndigits() == 4 && p(0) == 1 && pp(0) == COMPOSITEGLUON && pp.min_digit(1,3) > 0 && pp.max_digit(1,3) < QUARK_LIMIT && pp(2) <= pp(1) && (pp.last() == 1 || pp.last() == 3)) ||
608 // Handle squark-antiquark states (previously called Smeson/mesoninos)
609 (pp.ndigits() == 3 && pp.min_digit(1,3) > 0 && pp.max_digit(1,3) < QUARK_LIMIT && pp(1) <= pp(0) && pp.last() == 2)
610 );
611}
612template <> inline bool isRMeson(const int& p) { if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isRMeson(value_digits); }
613
614// APID Define R-Baryons as gluino-quark-quark-quark and squark-quark-quark bound states (ignore 4th generation squarks/quarks)
615// NB Current models only allow gluino-quark-quark-quark, stop-quark-quark and sbottom-quark-quark states
616template <class T> inline bool isRBaryon(const T& p) { return isRBaryon(p->pdg_id()); }
617template <> inline bool isRBaryon(const DecodedPID& p) {
618 if (!(p.ndigits() == 7 && (p(0) == 1 || p(0) == 2))) return false;
619 auto pp = p.shift(1);
620 return (
621 // Handle ~gluino-quark-quark-quark states
622 (pp.ndigits() == 5 && p(0) == 1 && pp(0) == COMPOSITEGLUON && pp.min_digit(1,4) > 0 && pp.max_digit(1,4) < QUARK_LIMIT && pp(2) <= pp(1) && pp(3) <= pp(2) && (pp.last() == 2 || pp.last() == 4)) ||
623 // Handle squark-quark-quark states (previously called Sbaryons)
624 (pp.ndigits() == 4 && pp.min_digit(1,4) > 0 && pp.max_digit(1,4) < QUARK_LIMIT && pp(1) <= pp(0) && pp(2) <= pp(1) && (pp.last() == 1 || pp.last() == 3))
625 );
626}
627template <> inline bool isRBaryon(const int& p) { if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isRBaryon(value_digits); }
628
629
630template <class T> inline bool isRHadron(const T& p) { return isRHadron(p->pdg_id()); }
631template <> inline bool isRHadron(const DecodedPID& p) {
632 return (isRBaryon(p) || isRMeson(p) || isRGlueball(p));
633}
634template <> inline bool isRHadron(const int& p) { auto value_digits = DecodedPID(p); return isRHadron(value_digits); }
635
636
637template <class T> inline bool hasSquark(const T& p, const int& q) { return hasSquark(p->pdg_id(), q); }
638template <> inline bool hasSquark(const DecodedPID& p, const int& q){
639 auto pp = p.shift(1); return (
640 (isSquark(p) || isRHadron(p))
641 && pp.ndigits() != 2 // skip lepton and boson super-partners by vetoing ndigits==2
642 && pp(0) == q // After shifting, the first digit will always represent the squark in R-Hadron (and squark) PIDs
643 );
644}
645template <> inline bool hasSquark(const int& p, const int& q){ auto value_digits = DecodedPID(p); return hasSquark(value_digits, q);}
646
647
648// APID Define isSUSY to return true for Superpartners of standard model particles and R-Hadrons
649// TODO Should this include the MSSM extended Higgs sector??
650template <class T> inline bool isSUSY(const T& p){return isSUSY(p->pdg_id());}
651template <> inline bool isSUSY(const DecodedPID& p){return (isSuperpartner(p) || isRHadron(p));}
652template <> inline bool isSUSY(const int& p){ auto value_digits = DecodedPID(p); return isSUSY(value_digits);}
653
654
662template <class T> inline bool isKK(const T& p){return isKK(p->pdg_id());}
663template <> inline bool isKK(const DecodedPID& p){return (p.ndigits() == 7 && (p(0) == 5 || p(0) == 6 ) && (p(1) != 9) );}
664template <> inline bool isKK(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isKK(value_digits);}
665
672template <class T> inline bool isMonopole(const T& p){return isMonopole(p->pdg_id());}
673template <> inline bool isMonopole(const DecodedPID& p){return (p.ndigits() == 7 && p(0) == 4 && p(1) == 1 && (p(2) == 1 || p(2) == 2 ) && p(6) == 0);}
674template <> inline bool isMonopole(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isMonopole(value_digits);}
675
685template <class T> inline bool isDM(const T& p){return isDM(p->pdg_id());}
686template <> inline bool isDM(const int& p){
687 auto sp = std::abs(p);
688 auto value_digits = DecodedPID(p);
689 return (sp >= 51 && sp <= 60) || (value_digits.ndigits() == 7 && value_digits(0) == 5 && value_digits(1) == 9) || sp == DARKPHOTON; }
690
695template <class T> inline bool isHiddenValley(const T& p){return isHiddenValley(p->pdg_id());}
696template <>
697inline bool isHiddenValley(const DecodedPID& p) {
698 const auto& pp = (p.ndigits() == 7) ? p.shift(2) : DecodedPID(0);
699 return (p.ndigits() == 7 && p(0) == 4 && p(1) == 9 &&
700 (isQuark(pp) || isLepton(pp) || isBoson(pp) || isGlueball(pp) ||
701 isDiquark(pp) || isHadron(pp)));
702}
703template <> inline bool isHiddenValley(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isHiddenValley(value_digits);}
704
711template <class T> inline bool isGenericMultichargedParticle(const T& p){return isGenericMultichargedParticle(p->pdg_id());}
712template <> inline bool isGenericMultichargedParticle(const DecodedPID& p){return (p.ndigits() == 8 && (p(0) == 1 || p(0) == 2) && p(1) == 0 && p(2) == 0 && p(7) == 0);}
713template <> inline bool isGenericMultichargedParticle(const int& p){if (!hasAllowedNumberOfDigits(p,8)) return false; auto value_digits = DecodedPID(p); return isGenericMultichargedParticle(value_digits);}
714
729template <class T> inline bool isNucleus(const T& p){return isNucleus(p->pdg_id());}
730template <> inline bool isNucleus(const DecodedPID& p){
731 if (std::abs(p.pid()) == PROTON) return true;
732 if (p.ndigits() != 10) return false;
733 if (p(0) != 1 || p(1) != 0 ) return false;
734 // charge should always be less than or equal to baryon number
735 // the following line is A >= Z
736 const int A = p(8) + 10*p(7) + 100*p(6);
737 const int Z = p(5) + 10*p(4) + 100*p(3);
738 return ( A >= Z );
739}
740template <> inline bool isNucleus(const int& p){ auto value_digits = DecodedPID(p); return isNucleus(value_digits);}
741
742
743template <class T> inline bool hasQuark(const T& p, const int& q);
744template <> inline bool hasQuark(const DecodedPID& p, const int& q){
745 if (isQuark(p.pid())) { return (std::abs(p.pid()) == q );}
746 if (isMeson(p)) { return *(p.second.rbegin() + 1) == q ||*(p.second.rbegin()+2) ==q;}
747 if (isDiquark(p)) { auto i = std::find(p.second.rbegin() + 2,p.second.rbegin()+4,q); return (i!=p.second.rbegin()+4);}
748 if (isBaryon(p)) { auto i = std::find(p.second.rbegin() + 1,p.second.rbegin()+4,q); return (i!=p.second.rbegin()+4);}
749 if (isTetraquark(p)) { auto i = std::find(p.second.rbegin() + 1,p.second.rbegin()+5,q); return (i!=p.second.rbegin()+5);}
750 if (isPentaquark(p)) { auto i = std::find(p.second.rbegin() + 1,p.second.rbegin()+6,q); return (i!=p.second.rbegin()+6);}
751 if (isNucleus(p) && std::abs(p.pid()) != PROTON) { return (q == 1 || q == 2 || (q==3 && p(2) > 0));}
752 if (isSUSY(p)) { // APID SUSY case
753 auto pp = p.shift(1);
754 if ( pp.ndigits() == 1 ) { return false; } // Handle squarks
755 if ( pp.ndigits() == 3 ) { return (pp(1) == q); } // Handle ~q qbar pairs
756 if ( pp.ndigits() == 4 ) { return (pp(1) == q || pp(2) == q); } // Ignore gluinos and squarks
757 if ( pp.ndigits() == 5 ) { return (pp(1) == q || pp(2) == q || pp(3) == q); } // Ignore gluinos and squarks
758 if ( pp.ndigits() > 5 ) { pp = pp.shift(1); } // Drop gluinos and squarks
759 return hasQuark(pp, q); }
760 return false;
761}
762template <> inline bool hasQuark(const int& p, const int& q){ auto value_digits = DecodedPID(p); return hasQuark(value_digits, q);}
763
764template <class T> inline bool hasStrange(const T& p) { return hasQuark(p,SQUARK); }
765template <class T> inline bool hasCharm(const T& p) { return hasQuark(p,CQUARK); }
766template <class T> inline bool hasBottom(const T& p) { return hasQuark(p,BQUARK); }
767template <class T> inline bool hasTop(const T& p) { return hasQuark(p,TQUARK); }
768
769
770// APID: The baryon number is defined as:
771// B = (1/3)*( n_q - n_{qbar} )
772// where n_q⁠ is the number of quarks, and ⁠n_{qbar} is the number of
773// antiquarks. By convention, squarks have the same quantum numbers as
774// the corresponding quarks (modulo spin and R), so have baryon number
775// 1/3.
776template <class T> inline int baryonNumber3(const T& p) {return baryonNumber3(p->pdg_id());}
777template <> inline int baryonNumber3(const DecodedPID& p){
778 if (isQuark(p.pid())) { return (p.pid() > 0) ? 1 : - 1;}
779 if (isDiquark(p)) { return (p.pid() > 0) ? 2 : -2; }
780 if (isMeson(p) || isTetraquark(p)) { return 0; }
781 if (isBaryon(p) || isPentaquark(p)){ return (p.pid() > 0) ? 3 : -3; }
782 if (isNucleus(p)) {
783 const int result = 3*p(8) + 30*p(7) + 300*p(6);
784 return (p.pid() > 0) ? result : -result;
785 }
786 if (isSUSY(p)) {
787 auto pp = p.shift(1);
788 if (pp.ndigits() < 3 ) { return baryonNumber3(pp); } // super-partners of fundamental particles
789 if (pp(0) == COMPOSITEGLUON) {
790 if (pp(1) == COMPOSITEGLUON) { return 0; } // R-Glueballs
791 if ( pp.ndigits() == 4 ) { return 0; } // states with gluino-quark-antiquark
792 if ( pp.ndigits() == 5) { return (p.pid() > 0) ? 3 : -3; } // states with gluino-quark-quark-quark
793 }
794 if (pp.ndigits() == 3) { return 0; } // squark-antiquark
795 if (pp.ndigits() == 4) { return (p.pid() > 0) ? 3 : -3; } // states with squark-quark-quark
796 }
797 return 0;
798}
799template <> inline int baryonNumber3(const int& p){ auto value_digits = DecodedPID(p); return baryonNumber3(value_digits);}
800
801template <class T> inline double baryonNumber(const T& p) {return baryonNumber(p->pdg_id());}
802template <> inline double baryonNumber(const DecodedPID& p){ return static_cast<double>(baryonNumber3(p))/3.0;}
803template <> inline double baryonNumber(const int& p){ auto value_digits = DecodedPID(p); return static_cast<double>(baryonNumber3(value_digits))/3.0;}
804
805
806// APID: The strangeness of a particle is defined as:
807// S = − ( n_s − n_{sbar} )
808// where n_s represents the number of strange quarks and n_{sbar}
809// represents the number of strange antiquarks. By convention, strange
810// squarks have the same quantum numbers as strange quarks (modulo
811// spin and R), so have strangeness -1.
812static const std::array<int,10> is_strange = {
813 +0, +0, +0, -1, +0, +0, +0, +0, +0, +0 };
814template <class T> inline int strangeness(const T& p) {return strangeness(p->pdg_id());}
815template <> inline int strangeness(const DecodedPID& p){
816 if (isNucleus(p) && p.ndigits() == 10) { return (p.pid() > 0) ? -p(2) : p(2); }
817 if (isStrange(p.pid())) { return (p.pid() > 0) ? -1 : 1; }
818 if (!hasStrange(p) && !hasSquark(p,SQUARK)) { return 0; }
819 if (std::abs(p.pid()) == K0) { return (p.pid() > 0) ? 1 : -1; }
820 size_t nq = 0;
821 int sign = 1;
822 int signmult = 1;
823 int result=0;
824 bool classified = false;
825 if (!classified && isMeson(p)) { classified = true; nq = 2; if ((*(p.second.rbegin()+2)) == 2||(*(p.second.rbegin()+2)) == 4 ) { sign=-1;} signmult =-1; }
826 if (!classified && isDiquark(p)) {return is_strange.at(p(0))+is_strange.at(p(1)); }
827 if (!classified && isBaryon(p)) { classified = true; nq = 3; }
828 if (!classified && isTetraquark(p)){ return is_strange.at(p(3)) + is_strange.at(p(4)) - is_strange.at(p(6)) - is_strange.at(p(7)); }
829 if (!classified && isPentaquark(p)){ return is_strange.at(p(3)) + is_strange.at(p(4)) + is_strange.at(p(5)) + is_strange.at(p(6)) - is_strange.at(p(7)); }
830 if (!classified && isSUSY(p)) {
831 nq = 0;
832 auto pp = p.shift(1);
833 if (pp.ndigits() < 3 ) { return strangeness(pp); } // super-partners of fundamental particles
834 if (pp(0) == COMPOSITEGLUON) {
835 if (pp(1) == COMPOSITEGLUON) { return 0; } // R-Glueballs
836 if ( pp.ndigits() == 4 || pp.ndigits() == 5) {
837 pp = pp.shift(1); // Remove gluino
838 }
839 }
840 if (pp.ndigits() == 3) { classified = true; nq = 2; if (p.last()%2==0) {sign = -1;} signmult = -1; } // states with quark-antiquark or squark-antiquark
841 if (pp.ndigits() == 4) { classified = true; nq = 3; } // states with quark-quark-quark or squark-quark-quark
842 }
843 for (auto r = p.second.rbegin() + 1; r != p.second.rbegin() + 1 + nq; ++r) {
844 result += is_strange.at(*r)*sign;
845 sign*=signmult;
846 }
847 return p.pid() > 0 ? result : -result;
848}
849template <> inline int strangeness(const int& p){ auto value_digits = DecodedPID(p); return strangeness(value_digits);}
850
851
852template <class T> inline int numberOfLambdas(const T& p) {return numberOfLambdas(p->pdg_id());}
853template <> inline int numberOfLambdas(const DecodedPID& p){
854 if (std::abs(p.pid()) == LAMBDA0) { return (p.pid() > 0) ? 1 : -1; }
855 if (isNucleus(p) && p.ndigits() == 10) { return (p.pid() > 0) ? p(2) : -p(2); }
856 return 0;
857}
858template <> inline int numberOfLambdas(const int& p){ auto value_digits = DecodedPID(p); return numberOfLambdas(value_digits);}
859
860
861template <class T> inline int numberOfProtons(const T& p) {return numberOfProtons(p->pdg_id());}
862template <> inline int numberOfProtons(const DecodedPID& p){
863 if (std::abs(p.pid()) == PROTON) { return (p.pid() > 0) ? 1 : -1; }
864 if (isNucleus(p)) {
865 const int result = p(5) + 10*p(4) + 100*p(3);
866 return (p.pid() > 0) ? result : -result;
867 }
868 return 0;
869}
870template <> inline int numberOfProtons(const int& p){ auto value_digits = DecodedPID(p); return numberOfProtons(value_digits);}
871
872
874template <class T> inline bool isBSM(const T& p){return isBSM(p->pdg_id());}
875template <> inline bool isBSM(const DecodedPID& p){
876 if (p.pid() == GRAVITON || std::abs(p.pid()) == MAVTOP || p.pid() == DARKPHOTON) return true;
877 if (std::abs(p.pid()) > 16 && std::abs(p.pid()) < 19) return true;
878 if (std::abs(p.pid()) > 31 && std::abs(p.pid()) < 39) return true;
879 if (std::abs(p.pid()) > 39 && std::abs(p.pid()) < 81) return true;
880 if (std::abs(p.pid()) > 6 && std::abs(p.pid()) < 9) return true;
881 if (isSUSY(p)) return true;
882 if (isNeutrinoRH(p.pid())) return true;
883 if (isGenericMultichargedParticle(p)) return true;
884 if (isTechnicolor(p)) return true;
885 if (isExcited(p)) return true;
886 if (isKK(p)) return true;
887 if (isHiddenValley(p)) return true;
888 if (isMonopole(p)) return true;
889 if (isDM(p.pid())) return true;
890 return false;
891}
892template <> inline bool isBSM(const int& p){
893 if (p == GRAVITON || std::abs(p) == MAVTOP || p == DARKPHOTON) return true;
894 if (std::abs(p) > 16 && std::abs(p) < 19) return true;
895 if (std::abs(p) > 31 && std::abs(p) < 38) return true;
896 if (std::abs(p) > 39 && std::abs(p) < 81) return true;
897 if (std::abs(p) > 6 && std::abs(p) < 9) return true;
898 auto value_digits = DecodedPID(p); return isBSM(value_digits);
899}
900
901template <class T> inline bool isTransportable(const T& p){return isTransportable(p->pdg_id());}
902template <> inline bool isTransportable(const DecodedPID& p){ return isPhoton(p.pid()) || isGeantino(p.pid()) || isHadron(p) || isLepton(p.pid()) || p.pid() == DARKPHOTON;}
903template <> inline bool isTransportable(const int& p){ auto value_digits = DecodedPID(p); return isTransportable(value_digits);}
904
906template <class T> inline bool isValid(const T& p){return isValid(p->pdg_id());}
907template <> inline bool isValid(const DecodedPID& p){
908 return p.pid() !=0 && ( isQuark(p) || isLepton(p) || isBoson(p) || isGlueball(p) ||
909 isTrajectory(p.pid()) || isGenSpecific(p.pid()) || isDiquark(p) ||
910 isBSM(p) || isHadron(p) || isNucleus(p) || isGeantino(p.pid()) ||
911 isPythia8Specific(p) ); }
912template <> inline bool isValid(const int& p){ if (!p) return false; if (std::abs(p) < 42) return true;
913 if (isGenSpecific(p)) return true;
914 auto value_digits = DecodedPID(p); return isValid(value_digits);
915}
916
917template <class T> inline int leadingQuark(const T& p) {return leadingQuark(p->pdg_id());}
918template <> inline int leadingQuark(const DecodedPID& p){
919 if (isQuark(p.pid())) { return std::abs(p.pid());}
920 if (isMeson(p)) { return p.max_digit(1,3);}
921 if (isDiquark(p)) { return p.max_digit(2,4);}
922 if (isBaryon(p)) { return p.max_digit(1,4);}
923 if (isTetraquark(p)) { return p.max_digit(1,5);}
924 if (isPentaquark(p)) { return p.max_digit(1,6);}
925 if (isSUSY(p)) { // APID SUSY case
926 auto pp = p.shift(1);
927 if ( pp.ndigits() == 1 ) { return 0; } // Handle squarks
928 if ( pp.ndigits() == 3 ) { pp = DecodedPID(pp(1)); } // Handle ~q qbar pairs
929 if ( pp.ndigits() > 3 ) { pp = pp.shift(1); } // Drop gluinos and squarks
930 return leadingQuark(pp); }
931 return 0;
932}
933
934template <> inline int leadingQuark(const int& p){ auto value_digits = DecodedPID(p); return leadingQuark(value_digits);}
935
936template <class T> inline bool isLightHadron(const T& p) { auto lq = leadingQuark(p); return (lq == DQUARK || lq == UQUARK||lq == SQUARK) && isHadron(p); }
937template <class T> inline bool isHeavyHadron(const T& p) { auto lq = leadingQuark(p); return (lq == CQUARK || lq == BQUARK || lq == TQUARK ) && isHadron(p); }
938template <class T> inline bool isStrangeHadron(const T& p) { return leadingQuark(p) == SQUARK && isHadron(p); }
939template <class T> inline bool isCharmHadron(const T& p) { return leadingQuark(p) == CQUARK && isHadron(p); }
940template <class T> inline bool isBottomHadron(const T& p) { return leadingQuark(p) == BQUARK && isHadron(p); }
941template <class T> inline bool isTopHadron(const T& p) { return leadingQuark(p) == TQUARK && isHadron(p); }
942
943template <class T> inline bool isLightMeson(const T& p) { auto lq = leadingQuark(p); return (lq == DQUARK || lq == UQUARK||lq == SQUARK) && isMeson(p); }
944template <class T> inline bool isHeavyMeson(const T& p) { auto lq = leadingQuark(p); return (lq == CQUARK || lq == BQUARK || lq == TQUARK) && isMeson(p); }
945template <class T> inline bool isStrangeMeson(const T& p) { return leadingQuark(p) == SQUARK && isMeson(p); }
946template <class T> inline bool isCharmMeson(const T& p) { return leadingQuark(p) == CQUARK && isMeson(p); }
947template <class T> inline bool isBottomMeson(const T& p) { return leadingQuark(p) == BQUARK && isMeson(p); }
948template <class T> inline bool isTopMeson(const T& p) { return leadingQuark(p) == TQUARK && isMeson(p); }
949
950template <class T> inline bool isCCbarMeson(const T& p) { return isCCbarMeson(p->pdg_id());}
951template <> inline bool isCCbarMeson(const DecodedPID& p) { return leadingQuark(p) == CQUARK && isMeson(p) && (*(p.second.rbegin()+2)) == CQUARK && (*(p.second.rbegin()+1)) == CQUARK; }
952template <> inline bool isCCbarMeson(const int& p) { return isCCbarMeson(DecodedPID(p)); }
953
954template <class T> inline bool isBBbarMeson(const T& p){ return isBBbarMeson(p->pdg_id());}
955template <> inline bool isBBbarMeson(const DecodedPID& p) { return leadingQuark(p) == BQUARK && isMeson(p) && (*(p.second.rbegin()+2)) == BQUARK && (*(p.second.rbegin()+1)) == BQUARK; }
956template <> inline bool isBBbarMeson(const int& p) { return isBBbarMeson(DecodedPID(p)); }
957
958
959template <class T> inline bool isLightBaryon(const T& p) { auto lq = leadingQuark(p); return (lq == DQUARK || lq == UQUARK||lq == SQUARK) && isBaryon(p); }
960template <class T> inline bool isHeavyBaryon(const T& p) { auto lq = leadingQuark(p); return (lq == CQUARK || lq == BQUARK || lq == TQUARK) && isBaryon(p); }
961template <class T> inline bool isStrangeBaryon(const T& p) { return leadingQuark(p) == SQUARK && isBaryon(p); }
962template <class T> inline bool isCharmBaryon(const T& p) { return leadingQuark(p) == CQUARK && isBaryon(p); }
963template <class T> inline bool isBottomBaryon(const T& p) { return leadingQuark(p) == BQUARK && isBaryon(p); }
964template <class T> inline bool isTopBaryon(const T& p) { return leadingQuark(p) == TQUARK && isBaryon(p); }
965
966
967// APID: This function selects B-Hadrons which predominantly decay weakly. (Commonly used definition in GeneratorFilters package.)
968// 5[1-4]1 L = J = 0, S = 0
969// 5[1-5][1-4]2 J = 1/2, n_r = 0, n_L =0
970template <class T> inline bool isWeaklyDecayingBHadron(const T& p) {return isWeaklyDecayingBHadron(p->pdg_id());}
971template <> inline bool isWeaklyDecayingBHadron(const int& p) {
972 const int pid = std::abs(p);
973 return ( pid == 511 || // B0
974 pid == 521 || // B+
975 pid == 531 || // B_s0
976 pid == 541 || // B_c+
977 pid == 5122 || // Lambda_b0
978 pid == 5132 || // Xi_b-
979 pid == 5232 || // Xi_b0
980 pid == 5112 || // Sigma_b-
981 pid == 5212 || // Sigma_b0
982 pid == 5222 || // Sigma_b+
983 pid == 5332 || // Omega_b-
984 pid == 5142 || // Xi_bc0
985 pid == 5242 || // Xi_bc+
986 pid == 5412 || // Xi'_bc0
987 pid == 5422 || // Xi'_bc+
988 pid == 5342 || // Omega_bc0
989 pid == 5432 || // Omega'_bc0
990 pid == 5442 || // Omega_bcc+
991 pid == 5512 || // Xi_bb-
992 pid == 5522 || // Xi_bb0
993 pid == 5532 || // Omega_bb-
994 pid == 5542 ); // Omega_bbc0
995}
996template <> inline bool isWeaklyDecayingBHadron(const DecodedPID& p){ return isWeaklyDecayingBHadron(p.pid()); }
997
998
999// APID: This function selects C-Hadrons which predominantly decay weakly. (Commonly used definition in GeneratorFilters package.)
1000// 4[1-3]1 L = J = 0, S = 0
1001// 4[1-4][1-3]2 J = 1/2, n_r = 0, n_L =0
1002// NB Omitting pid = 4322 (Xi'_C+) as this undergoes an EM rather than
1003// weak decay. (There was an old version of Herwig that decayed it
1004// weakly, but this was fixed in Herwig 7.)
1005template <class T> inline bool isWeaklyDecayingCHadron(const T& p) {return isWeaklyDecayingCHadron(p->pdg_id());}
1006template <> inline bool isWeaklyDecayingCHadron(const int& p) {
1007 const int pid = std::abs(p);
1008 return ( pid == 411 || // D+
1009 pid == 421 || // D0
1010 pid == 431 || // Ds+
1011 pid == 4122 || // Lambda_c+
1012 pid == 4132 || // Xi_c0
1013 pid == 4232 || // Xi_c+
1014 pid == 4212 || // Sigma_c+
1015 pid == 4332 || // Omega_c0
1016 pid == 4412 || // Xi_cc+
1017 pid == 4422 || // Xi_cc++
1018 pid == 4432 ); // Omega_cc+
1019}
1020template <> inline bool isWeaklyDecayingCHadron(const DecodedPID& p){ return isWeaklyDecayingCHadron(p.pid()); }
1021
1022
1023template <class T> inline int charge3( const T& p){return charge3(p->pdg_id());}
1024template <class T> inline double fractionalCharge(const T& p){return fractionalCharge(p->pdg_id());}
1025template <class T> inline double charge( const T& p){
1026 if (isGenericMultichargedParticle(p)) // BSM multi-charged particles might have a fractional charge that's not a multiple of 1/3
1027 return fractionalCharge(p);
1028 else
1029 return 1.0*charge3(p)/3.0;
1030}
1031template <class T> inline double threeCharge( const T& p){ return charge3(p);}
1032template <class T> inline bool isCharged( const T& p){ return charge3(p) != 0;}
1033
1034
1035template <> inline int charge3(const DecodedPID& p) {
1036 auto ap = std::abs(p.pid());
1037 if (ap < TABLESIZE ) return p.pid() > 0 ? triple_charge.at(ap) : -triple_charge.at(ap);
1038 if (ap == K0) return 0;
1039 if (ap == GEANTINO0) return 0;
1040 if (ap == GEANTINOPLUS) return p.pid() > 0 ? 3 : -3;
1041 if (ap == MAVTOP) return p.pid() > 0 ? 2 : -2;
1042 size_t nq = 0;
1043 int sign = 1;
1044 int signmult = 1;
1045 int result=0;
1046 bool classified = false;
1047 if (!classified && isMeson(p)) { classified = true; nq = 2; if ((*(p.second.rbegin()+2)) == 2||(*(p.second.rbegin()+2)) == 4 ) { sign=-1;} signmult =-1; }
1048 if (!classified && isDiquark(p)) {return triple_charge.at(p(0))+triple_charge.at(p(1)); }
1049 if (!classified && isBaryon(p)) { classified = true; nq = 3; }
1050 if (!classified && isTetraquark(p)){ return triple_charge.at(p(3)) + triple_charge.at(p(4)) - triple_charge.at(p(6)) - triple_charge.at(p(7)); }
1051 if (!classified && isPentaquark(p)){ return triple_charge.at(p(3)) + triple_charge.at(p(4)) + triple_charge.at(p(5)) + triple_charge.at(p(6)) - triple_charge.at(p(7)); }
1052 if (!classified && isNucleus(p)) { return 3*numberOfProtons(p);}
1053 if (!classified && isSUSY(p)) {
1054 nq = 0;
1055 auto pp = p.shift(1);
1056 if (pp.ndigits() < 3 ) { return charge3(pp); } // super-partners of fundamental particles
1057 if (pp(0) == COMPOSITEGLUON) {
1058 if (pp(1) == COMPOSITEGLUON) { return 0; } // R-Glueballs
1059 if ( pp.ndigits() == 4 || pp.ndigits() == 5) {
1060 pp = pp.shift(1); // Remove gluino
1061 }
1062 }
1063 if (pp.ndigits() == 3) { classified = true; nq = 2; if (p.last()%2==0) {sign = -1;} signmult = -1; } // states with squark-antiquark or quark-anti-quark
1064 if (pp.ndigits() == 4) { classified = true; nq = 3; } // states with squark-quark-quark or quark-quark-quark
1065 }
1066 if (!classified && isHiddenValley(p)) { // Hidden Valley particles
1067 auto pp = p.shift(2);
1068 if (!classified && isMeson(pp)) { classified = true; nq = 2; if ((*(pp.second.rbegin()+2)) == 2||(*(pp.second.rbegin()+2)) == 4 ) { sign=-1;} signmult =-1; }
1069 if (!classified && isDiquark(pp)) {return triple_charge.at(pp(0))+triple_charge.at(pp(1)); }
1070 if (!classified && isBaryon(pp)) { classified = true; nq = 3; }
1071 }
1072 if (!classified && isExcited(p)) { //Excited/composite leptons/quarks
1073 auto pp = p.shift(2);
1074 auto ap = std::abs(pp.pid());
1075 if (ap < TABLESIZE ) return pp.pid() > 0 ? triple_charge.at(ap) : -triple_charge.at(ap);
1076 }
1077 if (!classified && isKK(p)) { // Kaluza-Klein particles
1078 auto pp = p.shift(2);
1079 auto ap = std::abs(pp.pid());
1080 if (ap < TABLESIZE ) return pp.pid() > 0 ? triple_charge.at(ap) : -triple_charge.at(ap);
1081
1082 }
1083 if (!classified && isDM(p.pid())) { //Dark Matter Particles
1084 if (p.ndigits() == 7){ // Determining the charges for the more elaborate, 7-digit DM codes
1085 auto pp = p.shift(3); // The first two digits indicate the particle is DM, the third indicates left/right-handedness (see 11(j))
1086 auto ap = std::abs(pp.pid());
1087 if (ap < TABLESIZE ) return pp.pid() > 0 ? triple_charge.at(ap) : -triple_charge.at(ap);
1088 }else if (std::abs(p.pid()) < TABLESIZE) return p.pid() > 0 ? triple_charge.at(ap) : -triple_charge.at(ap); // Just to make sure the correct charge is returned for DM 51-60
1089 }
1090 if (!classified && isMonopole(p)) {
1093 result = 3*(p(3)*100 + p(4)*10 + p(5));
1094 return ( (p.pid() > 0 && p(2) == 1) || (p.pid() < 0 && p(2) == 2) ) ? result : -result;
1095 }
1096 if (!classified && isGenericMultichargedParticle(p)) {
1097 double abs_charge = 0.0;
1098 if (p(0) == 1) abs_charge = p(3)*100. + p(4)*10. + p(5)*1 + p(6)*0.1; // multi-charged particle PDG ID is +/-100XXXY0, where the charge is XXX.Y
1099 if (p(0) == 2) abs_charge = (p(3)*10. + p(4))/(p(5)*10.0 + p(6)); // multi-charged particle PDG ID is +/-200XXYY0, where the charge is XX/YY
1100 int abs_threecharge = static_cast<int>(std::round(abs_charge * 3.)); // the multi-charged particles might have a fractional charge that's not a multiple of 1/3, in that case round to the closest multiple of 1/3 for charge3 and threecharge
1101 return p.pid() > 0 ? abs_threecharge : -1 * abs_threecharge;
1102 }
1103 for (auto r = p.second.rbegin() + 1; r != p.second.rbegin() + 1 + nq; ++r) {
1104 result += triple_charge.at(*r)*sign;
1105 sign*=signmult;
1106 }
1107 return p.pid() > 0 ? result : -result;
1108}
1109template <> inline int charge3(const int& p){
1110 int ap = std::abs(p);
1111 if (ap < TABLESIZE) return p > 0 ? triple_charge.at(ap):-triple_charge.at(ap);
1112 auto value_digits = DecodedPID(p);
1113 return charge3(value_digits);
1114}
1115
1116
1117template <class T> inline bool isNeutral( const T& p){ return p->pdg_id() != 0 && charge3(p) == 0;}
1118template <> inline bool isNeutral(const DecodedPID& p){ return p.pid() != 0 && charge3(p) == 0;}
1119template <> inline bool isNeutral(const int& p){ auto value_digits = DecodedPID(p); return isNeutral(value_digits);}
1120
1121
1122template <> inline double fractionalCharge(const DecodedPID& p) {
1123 if(!isGenericMultichargedParticle(p)) return 1.0*charge3(p)/3.0; // this method is written for multi-charged particles, still make sure other cases are handled properly
1124 double abs_charge = 0;
1125 if (p(0) == 1) abs_charge = p(3)*100. + p(4)*10. + p(5)*1 + p(6)*0.1; // multi-charged particle PDG ID is +/-100XXXY0, where the charge is XXX.Y
1126 if (p(0) == 2) abs_charge = (p(3)*10. + p(4))/(p(5)*10.0 + p(6)); // multi-charged particle PDG ID is +/-200XXYY0, where the charge is XX/YY
1127 return p.pid() > 0 ? abs_charge : -1 * abs_charge;
1128}
1129template <> inline double fractionalCharge(const int& p){auto value_digits = DecodedPID(p); return fractionalCharge(value_digits);}
1130
1131// APID: Including Z' and Z'' as EM interacting.
1132template <class T> inline bool isEMInteracting(const T& p){return isEMInteracting(p->pdg_id());}
1133template <> inline bool isEMInteracting(const int& p) {return (isPhoton(p) || isZ(p) || p == ZPRIME || p == ZDBLPRIME || std::abs(charge(p))>std::numeric_limits<double>::epsilon() || isMonopole(p));}
1134
1135template <class T> inline bool isParton(const T& p) { return isQuark(p)||isGluon(p);}
1136
1137// APID: Intended to return 2J
1138// Useful for G4ParticleDefinition constructor
1139template <class T> inline int spin2(const T& p) { return spin2(p->pdg_id()); }
1140template <> inline int spin2(const DecodedPID& p) {
1141 if (isSUSY(p)) {
1142 auto pp = p.shift(1);
1143 auto ap = std::abs(pp.pid());
1144 if (ap < TABLESIZE ) { return std::abs(double_spin.at(ap)-1); } // sparticles (0->1, 1 -> 0, 2->1, 4->3)
1145 return p.last()-1; // R-Hadrons (p.last() == 2J +1)
1146 }
1147 if (isHiddenValley(p)) { //Hidden Valley spins
1148 auto pp = p.shift(2);
1149 if (isHadron(pp)) { return pp.last()-1; } // Hadrons (p.last == 2J+1 - special cases handled above)
1150 }
1151 if (isKK(p)) { // Kaluza-Klein spins
1152 auto pp = p.shift(2);
1153 auto ap = std::abs(pp.pid());
1154 if (ap < TABLESIZE ) { return double_spin.at(ap); } // fundamental particles
1155 }
1156 if (isDM(std::abs(p.pid()))) { //DM spins
1157 if (p.ndigits() == 7) { // Determining the spins for the more elaborate, 7-digit DM codes
1158 auto pp = p.shift(3); // The first two digits indicate the particle is DM, the third indicates left/right-handedness (see 11(j))
1159 auto ap = std::abs(pp.pid());
1160 if (ap < TABLESIZE) { return double_spin.at(ap); } // fundamental particles
1161 }else if (std::abs(p.pid()) < TABLESIZE) { // Just to make sure the correct spin is returned for DM 51-60
1162 return std::abs(double_spin.at(std::abs(p.pid())));
1163 }
1164 }
1165 auto ap = std::abs(p.pid());
1166 if (ap == K0S) { return 0; }
1167 if (ap == K0L) { return 0; }
1168 if (ap == MAVTOP) { return 1; } // TODO check this
1169 if (ap == DARKPHOTON) { return 2; } // TODO check this
1170 if (ap < TABLESIZE ) { return double_spin.at(ap); } // fundamental particles
1171 if (isHadron(p)) { return p.last()-1; } // Hadrons (p.last == 2J+1 - special cases handled above)
1172 if (isMonopole(p)) { return 0; } // PDG 11i - For now no spin information is provided. Also matches the definition in the G4Extensions/Monopole package.
1173 if (isGenericMultichargedParticle(p)) { return 0; } // APID Matches the definition in the G4Extensions/Monopole package.
1174 if (isNucleus(p)) { return 1; } // TODO need to explicitly deal with nuclei
1175 return p.last() > 0 ? 1 : 0; // Anything else - best guess
1176}
1177template <> inline int spin2(const int& p){ auto value_digits = DecodedPID(p); return spin2(value_digits);}
1178
1179template <class T> inline double spin(const T& p) { return spin(p->pdg_id()); }
1180template <> inline double spin(const DecodedPID& p) { return 1.0*spin2(p)/2.0; }
1181template <> inline double spin(const int& p){ auto value_digits = DecodedPID(p); return spin(value_digits);}
1182
1183
1184// APID: Returns an unordered list of the quarks contained by the current particle
1185template <class T> inline std::vector<int> containedQuarks(const T& p) { return containedQuarks(p->pdg_id()); }
1186template <> inline std::vector<int> containedQuarks(const int& p) {
1187 auto pp = DecodedPID(p);
1188 std::vector<int> quarks;
1189 if (isQuark(pp.pid())) { quarks.push_back(std::abs(pp.pid())); }
1190 else if (isDiquark(pp)) { quarks.push_back(pp(0)); quarks.push_back(pp(1)); }
1191 else if (isMeson(pp)) { quarks.push_back(*(pp.second.rbegin() + 1)); quarks.push_back(*(pp.second.rbegin()+2)); }
1192 else if (isBaryon(pp)) { for (size_t digit = 1; digit < 4; ++digit) { quarks.push_back(*(pp.second.rbegin() + digit)); } }
1193 else if (isTetraquark(pp)) { for (size_t digit = 1; digit < 5; ++digit) { quarks.push_back(*(pp.second.rbegin() + digit)); } }
1194 else if (isPentaquark(pp)) { for (size_t digit = 1; digit < 6; ++digit) { quarks.push_back(*(pp.second.rbegin() + digit)); } }
1195 else if (isNucleus(pp)) { const int A = std::abs(baryonNumber3(pp)/3); const int Z = std::abs(numberOfProtons(pp)); const int L = std::abs(numberOfLambdas(pp));
1196 const int n_uquarks = A + Z; const int n_dquarks = 2*A - Z - L; const int n_squarks = L;
1197 quarks.reserve(3*A); quarks.insert(quarks.end(), n_dquarks, 1); quarks.insert(quarks.end(), n_uquarks, 2); quarks.insert(quarks.end(), n_squarks, 3); }
1198 else if (isSUSY(pp)) { // APID SUSY case
1199 pp = pp.shift(1);
1200 if ( pp.ndigits() > 1 ) { // skip squarks
1201 if ( pp.ndigits() == 3 ) { pp = DecodedPID(pp(1)); } // Handle ~q qbar pairs
1202 if ( pp.ndigits() > 3 ) { pp = pp.shift(1); } // Drop gluinos and squarks
1203 return containedQuarks(pp.pid());
1204 }
1205 }
1206 return quarks;
1207}
1208template <> inline std::vector<int> containedQuarks(const DecodedPID& p) { return containedQuarks(p.pid()); }
1209
1210template <class T> inline bool isStrongInteracting(const T& p){return isStrongInteracting(p->pdg_id());}
1211template <> inline bool isStrongInteracting(const int& p) { return (isGluon(p) || isQuark(p) || isDiquark(p) || isGlueball(p) || isLeptoQuark(p) || isHadron(p) || isRHadron(p));} // APID: Glueballs and R-Hadrons are also strong-interacting
1212
1213#endif
bool isGraviton(const T &p)
Definition AtlasPID.h:419
bool isSMLepton(const T &p)
APID: the fourth generation leptons are not standard model leptons.
Definition AtlasPID.h:214
bool isWeaklyDecayingBHadron(const T &p)
Definition AtlasPID.h:970
static const int GRAVITON
Definition AtlasPID.h:110
static const int HIGGSBOSON
Definition AtlasPID.h:102
static const int ZDBLPRIME
Definition AtlasPID.h:104
static const int CQUARK
Definition AtlasPID.h:77
int numberOfProtons(const T &p)
Definition AtlasPID.h:861
bool isCharm(const T &p)
Definition AtlasPID.h:199
bool hasStrange(const T &p)
Definition AtlasPID.h:764
static const int TABLESIZE
Definition AtlasPID.h:42
bool isBottomBaryon(const T &p)
Definition AtlasPID.h:963
static const int PHOTON
Definition AtlasPID.h:99
static const int TQUARK
Definition AtlasPID.h:79
double spin(const T &p)
Definition AtlasPID.h:1179
bool isBottomMeson(const T &p)
Definition AtlasPID.h:947
static const int K0
Definition AtlasPID.h:127
static const int TAU
Definition AtlasPID.h:91
static const int LEAD
Definition AtlasPID.h:155
bool isTau(const T &p)
Definition AtlasPID.h:228
bool isRGlueball(const T &p)
PDG rule 11g: Within several scenarios of new physics, it is possible to have colored particles suffi...
Definition AtlasPID.h:589
bool isElectron(const T &p)
Definition AtlasPID.h:222
bool isBoson(const T &p)
PDG rule 9: Two-digit numbers in the range 21–30 are provided for the Standard Model gauge and Higgs ...
Definition AtlasPID.h:391
bool isBottom(const T &p)
Definition AtlasPID.h:202
static const int K0L
Definition AtlasPID.h:124
static const int MAVTOP
Definition AtlasPID.h:119
static const int ARGON
Definition AtlasPID.h:159
static const int BCPLUS
Definition AtlasPID.h:135
bool isStrange(const T &p)
Definition AtlasPID.h:196
bool isExcited(const T &p)
PDG rule 11f Excited (composite) quarks and leptons are identified by setting n= 4 and nr= 0.
Definition AtlasPID.h:563
bool isRBaryon(const T &p)
Definition AtlasPID.h:616
bool isSleptonLH(const T &p)
Definition AtlasPID.h:515
bool isSlepton(const T &p)
Definition AtlasPID.h:509
int strangeness(const T &p)
Definition AtlasPID.h:814
bool isTransportable(const T &p)
Definition AtlasPID.h:901
bool isPentaquark(const T &p)
PDG rule 15 The 9-digit penta-quark codes are ±1nrnLnq1nq2nq3nq4nq5nJ, sorted such that nq1≥nq2≥nq3≥n...
Definition AtlasPID.h:364
static const int NEUTRON
Definition AtlasPID.h:137
static const std::array< int, 10 > is_strange
Definition AtlasPID.h:812
static const std::array< int, TABLESIZE > triple_charge
Definition AtlasPID.h:43
static const int PIMINUS
Definition AtlasPID.h:122
bool isChLepton(const T &p)
APID: the fourth generation leptons are leptons.
Definition AtlasPID.h:219
bool hasTop(const T &p)
Definition AtlasPID.h:767
double baryonNumber(const T &p)
Definition AtlasPID.h:801
static const int REGGEON
Definition AtlasPID.h:171
static const int RH_NU_MU
Definition AtlasPID.h:151
static const int ELECTRON
Definition AtlasPID.h:86
static const int HIGGSPLUS
Definition AtlasPID.h:108
bool isStrangeHadron(const T &p)
Definition AtlasPID.h:938
bool isGluon(const T &p)
Definition AtlasPID.h:395
static const int BQUARK
Definition AtlasPID.h:78
int charge3(const T &p)
Definition AtlasPID.h:1023
double fractionalCharge(const T &p)
Definition AtlasPID.h:1024
static const int ZPRIME
Definition AtlasPID.h:103
static const int DQUARK
PDG Rule 1: Particles are given positive numbers, antiparticles negative numbers.
Definition AtlasPID.h:74
bool isLepton(const T &p)
APID: the fourth generation leptons are leptons.
Definition AtlasPID.h:209
bool isHiggs(const T &p)
APID: HIGGS boson is only one particle.
Definition AtlasPID.h:412
int numberOfLambdas(const T &p)
Definition AtlasPID.h:852
bool isLightBaryon(const T &p)
Definition AtlasPID.h:959
static const int POMERON
PDG rule 8: The pomeron and odderon trajectories and a generic reggeon trajectory of states in QCD ar...
Definition AtlasPID.h:169
static const int ODDERON
Definition AtlasPID.h:170
bool isQuarkonium(const T &p)
APID: states with s,sbar are not considered quarkonium.
Definition AtlasPID.h:295
bool isTopMeson(const T &p)
Definition AtlasPID.h:948
bool hasQuark(const T &p, const int &q)
static const int HIGGS3
Definition AtlasPID.h:107
static const int PIPLUS
Definition AtlasPID.h:121
bool isGaugino(const T &p)
Definition AtlasPID.h:531
bool isHeavyBoson(const T &p)
APID: Additional "Heavy"/"prime" versions of W and Z bosons (Used in MCTruthClassifier).
Definition AtlasPID.h:408
bool isTetraquark(const T &p)
PDG rule 14 The 9-digit tetra-quark codes are ±1nrnLnq1nq20nq3nq4nJ.
Definition AtlasPID.h:347
static const int WBOSON_LRSM
Definition AtlasPID.h:153
bool isCharged(const T &p)
Definition AtlasPID.h:1032
bool isMonopole(const T &p)
PDG rule 11i Magnetic monopoles and dyons are assumed to have one unit of Dirac monopole charge and a...
Definition AtlasPID.h:672
bool isHeavyMeson(const T &p)
Definition AtlasPID.h:944
bool isSMQuark(const T &p)
Definition AtlasPID.h:192
bool isFourthGeneration(const T &p)
Is this a 4th generation fermion?
Definition AtlasPID.h:240
static const int QUARK_LIMIT
Definition AtlasPID.h:84
bool isSuperpartner(const T &p)
Definition AtlasPID.h:539
bool isW(const T &p)
Definition AtlasPID.h:404
static const int POSITRON
Definition AtlasPID.h:87
bool isHiddenValley(const T &p)
PDG rule 11k Hidden Valley particles have n = 4 and n_r = 9, and trailing numbers in agreement with t...
Definition AtlasPID.h:695
bool hasBottom(const T &p)
Definition AtlasPID.h:766
constexpr std::array< int, 9 > MAX_DIGIT
Definition AtlasPID.h:18
static const int BPRIME
PDG Rule 11a: The standard fourth generation of fermions is included by analogy with the first three.
Definition AtlasPID.h:82
static const int K0S
Definition AtlasPID.h:126
static const int KRYPTON
Definition AtlasPID.h:157
bool isSquarkLH(const T &p)
Definition AtlasPID.h:493
static const int LEPTOQUARK
Definition AtlasPID.h:112
bool isGlueball(const T &p)
PDG rule 7: The gluon, when considered as a gauge boson, has official number 21.
Definition AtlasPID.h:468
bool isLightHadron(const T &p)
Definition AtlasPID.h:936
static const int OXYGEN
Definition AtlasPID.h:162
static const int NUPRIME
Definition AtlasPID.h:94
bool isTechnicolor(const T &p)
PDG rule 11e Technicolor states have n = 3, with technifermions treated like ordinary fermions.
Definition AtlasPID.h:551
static const int NEON
Definition AtlasPID.h:161
double charge(const T &p)
Definition AtlasPID.h:1025
static const int DPLUS
Definition AtlasPID.h:129
bool isResonance(const T &p)
Definition AtlasPID.h:422
static const int UQUARK
Definition AtlasPID.h:75
bool isStrongInteracting(const T &p)
Definition AtlasPID.h:1210
bool isParton(const T &p)
Definition AtlasPID.h:1135
bool isCCbarMeson(const T &p)
Definition AtlasPID.h:950
static const int DSTAR
Definition AtlasPID.h:130
int baryonNumber3(const T &p)
Definition AtlasPID.h:776
static const int MAGNESIUM
Definition AtlasPID.h:160
static const int PROTON
Definition AtlasPID.h:136
constexpr bool hasAllowedNumberOfDigits(int p, Ns... digits)
Definition AtlasPID.h:20
static const int TPRIME
Definition AtlasPID.h:83
static const int NU_E
Definition AtlasPID.h:88
bool isBBbarMeson(const T &p)
Definition AtlasPID.h:954
bool isTopHadron(const T &p)
Definition AtlasPID.h:941
bool isEMInteracting(const T &p)
Definition AtlasPID.h:1132
bool isStrangeBaryon(const T &p)
Definition AtlasPID.h:961
static const int RH_NU_E
PDG Rule 12: Occasionally program authors add their own states.
Definition AtlasPID.h:150
bool hasCharm(const T &p)
Definition AtlasPID.h:765
bool isSleptonRH(const T &p)
Definition AtlasPID.h:523
static const int LAMBDAB0
Definition AtlasPID.h:140
bool isBottomHadron(const T &p)
Definition AtlasPID.h:940
bool isQuark(const T &p)
PDG rule 2: Quarks and leptons are numbered consecutively starting from 1 and 11 respectively; to do ...
Definition AtlasPID.h:187
std::vector< int > containedQuarks(const T &p)
Definition AtlasPID.h:1185
bool isMeson(const T &p)
Table 43.1 PDG rule 5a: The numbers specifying the meson’s quark content conform to the convention nq...
Definition AtlasPID.h:270
static const int Z0BOSON
Definition AtlasPID.h:100
static const int GEANTINOPLUS
PDG rule 10: Codes 81–100 are reserved for generator-specific pseudoparticles and concepts.
Definition AtlasPID.h:178
static const int SQUARK
Definition AtlasPID.h:76
bool isGeantino(const T &p)
Definition AtlasPID.h:461
bool isZ(const T &p)
Definition AtlasPID.h:401
static const int CALCIUM
Definition AtlasPID.h:158
bool isDiquark(const T &p)
PDG rule 4 Diquarks have 4-digit numbers with nq1 >= nq2 and nq3 = 0 APID: states with top quarks are...
Definition AtlasPID.h:247
bool isGenericMultichargedParticle(const T &p)
In addition, there is a need to identify ”Q-ball” and similar very exotic (multi-charged) particles w...
Definition AtlasPID.h:711
bool isNeutrino(const T &p)
APID: the fourth generation neutrinos are neutrinos.
Definition AtlasPID.h:232
static const int DSPLUS
Definition AtlasPID.h:132
static const int PI0
Definition AtlasPID.h:123
static const int WPLUSPRIME
Definition AtlasPID.h:105
bool isRMeson(const T &p)
Definition AtlasPID.h:601
static const int GEANTINO0
Definition AtlasPID.h:179
static const int PSI2S
Definition AtlasPID.h:141
static const int BORON
Definition AtlasPID.h:163
static const int INDIUM
Definition AtlasPID.h:156
bool isTop(const T &p)
Definition AtlasPID.h:205
static const int GLUON
Definition AtlasPID.h:96
static const int COMPOSITEGLUON
Definition AtlasPID.h:98
static const int NU_MU
Definition AtlasPID.h:90
bool isSUSY(const T &p)
Definition AtlasPID.h:650
bool isCharmBaryon(const T &p)
Definition AtlasPID.h:962
static const int HIGGS2
Definition AtlasPID.h:106
static const int HELIUM
Definition AtlasPID.h:164
bool isSquarkRH(const T &p)
Definition AtlasPID.h:501
bool isPhoton(const T &p)
Definition AtlasPID.h:398
bool isHeavyBaryon(const T &p)
Definition AtlasPID.h:960
static const int RH_NU_TAU
Definition AtlasPID.h:152
double threeCharge(const T &p)
Definition AtlasPID.h:1031
bool isKK(const T &p)
PDG rule 11h A black hole in models with extra dimensions has code 5000040.
Definition AtlasPID.h:662
bool isCharmMeson(const T &p)
Definition AtlasPID.h:946
bool isNeutrinoRH(const T &p)
PDG rule 12: Occasionally program authors add their own states.
Definition AtlasPID.h:444
bool isBaryon(const T &p)
Table 43.2 APID: states with fourth generation quarks are not baryons.
Definition AtlasPID.h:304
static const int LAMBDA0
Definition AtlasPID.h:138
bool hasSquark(const T &p, const int &q)
Definition AtlasPID.h:637
int leadingQuark(const T &p)
Definition AtlasPID.h:917
bool isLeptoQuark(const T &p)
PDG rule 11c: “One-of-a-kind” exotic particles are assigned numbers in the range 41–80.
Definition AtlasPID.h:430
constexpr std::array< int, 9 > MIN_DIGIT
Implementation of classification functions according to PDG2022.
Definition AtlasPID.h:17
static const int B0
Definition AtlasPID.h:134
bool isNucleus(const T &p)
PDG rule 16 Nuclear codes are given as 10-digit numbers ±10LZZZAAAI.
Definition AtlasPID.h:729
static const int LAMBDACPLUS
Definition AtlasPID.h:139
bool isSMNeutrino(const T &p)
Definition AtlasPID.h:235
bool isMSSMHiggs(const T &p)
APID: Additional Higgs bosons for MSSM (Used in MCTruthClassifier).
Definition AtlasPID.h:416
bool isSquark(const T &p)
PDG rule 11d Fundamental supersymmetric particles are identified by adding a nonzero n to the particl...
Definition AtlasPID.h:485
bool isTopBaryon(const T &p)
Definition AtlasPID.h:964
bool isTrajectory(const T &p)
PDG rule 8: The pomeron and odderon trajectories and a generic reggeon trajectory of states in QCD ar...
Definition AtlasPID.h:381
static const int KPLUS
Definition AtlasPID.h:128
static const int WPLUSBOSON
Definition AtlasPID.h:101
static const int HIGGSPLUSPLUS
Definition AtlasPID.h:109
static const int LPRIME
Definition AtlasPID.h:93
static const int DARKPHOTON
PDG Ids for Mavtop madgraph UFO model found under DarkX.
Definition AtlasPID.h:118
static const int JPSI
Definition AtlasPID.h:133
bool isCharmHadron(const T &p)
Definition AtlasPID.h:939
bool isRHadron(const T &p)
Definition AtlasPID.h:630
static const int NU_TAU
Definition AtlasPID.h:92
bool isHadron(const T &p)
Definition AtlasPID.h:373
bool isMuon(const T &p)
Definition AtlasPID.h:225
bool isLightMeson(const T &p)
Definition AtlasPID.h:943
bool isStrangeMeson(const T &p)
Definition AtlasPID.h:945
bool isHeavyHadron(const T &p)
Definition AtlasPID.h:937
bool isGenSpecific(const T &p)
Main Table for MC internal use 81–100,901–930,998-999,1901–1930,2901–2930, and 3901–3930.
Definition AtlasPID.h:449
bool isBSM(const T &p)
APID: graviton and all Higgs extensions are BSM.
Definition AtlasPID.h:874
bool isDM(const T &p)
PDG rule 11j: The nature of Dark Matter (DM) is not known, and therefore a definitive classification ...
Definition AtlasPID.h:685
bool isPythia8Specific(const T &p)
Definition AtlasPID.h:433
bool isNeutral(const T &p)
Definition AtlasPID.h:1117
static const std::array< int, TABLESIZE > double_spin
Definition AtlasPID.h:58
int spin2(const T &p)
Definition AtlasPID.h:1139
bool isWeaklyDecayingCHadron(const T &p)
Definition AtlasPID.h:1005
static const int HIGGS4
Definition AtlasPID.h:111
static Double_t sp
int sign(int a)
xAOD::Muon MUON
D3PD INCLUDES.
int min_digit(const int m, const int n) const
Definition AtlasPID.h:38
DecodedPID shift(const size_t n) const
Definition AtlasPID.h:33
int max_digit(const int m, const int n) const
Definition AtlasPID.h:37
const int & pid() const
Definition AtlasPID.h:36
size_t ndigits() const
Definition AtlasPID.h:39
DecodedPID(const int &p)
Definition AtlasPID.h:26
const int & last() const
Definition AtlasPID.h:35
const int & operator()(const size_t n) const
Definition AtlasPID.h:34
int r
Definition globals.cxx:22
void reverse(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of reverse for DataVector/List.
hold the test vectors and ease the comparison