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
71
72static const int DQUARK = 1;
73static const int UQUARK = 2;
74static const int SQUARK = 3;
75static const int CQUARK = 4;
76static const int BQUARK = 5;
77static const int TQUARK = 6;
78static const int BPRIME = 7; // 4th Generation quark
79static const int TPRIME = 8; // 4th Generation quark
80static const int QUARK_LIMIT = BPRIME; // Quark pdg_ids less than this are considered in (R-)Hadrons and Diquarks
81
82static const int ELECTRON = 11;
83static const int POSITRON = -ELECTRON;
84static const int NU_E = 12;
85static const int MUON = 13;
86static const int NU_MU = 14;
87static const int TAU = 15;
88static const int NU_TAU = 16;
89static const int LPRIME = 17; // 4th Generation charged lepton
90static const int NUPRIME = 18; // 4th Generation neutrino
91
92static const int GLUON = 21;
93// APID: 9 rather than 21 is used to denote a gluon/gluino in composite states. (From PDG 11g)
94static const int COMPOSITEGLUON = 9;
95static const int PHOTON = 22;
96static const int Z0BOSON = 23;
97static const int WPLUSBOSON = 24;
98static const int HIGGSBOSON = 25;
99static const int ZPRIME = 32; // Z′/Z^0_2
100static const int ZDBLPRIME = 33; // Z′′/Z^0_3
101static const int WPLUSPRIME = 34; // W ′/W^+_2
102static const int HIGGS2 = 35; // H^0/H^0_2 FIXME Any better ideas?
103static const int HIGGS3 = 36; // A^0/H^0_3 FIXME Any better ideas?
104static const int HIGGSPLUS = 37; // H^+
105static const int HIGGSPLUSPLUS = 38; // H^++
106static const int GRAVITON = 39;
107static const int HIGGS4 = 40; // a^0/H^0_4 FIXME Any better ideas?
108static const int LEPTOQUARK = 42;
109
114static const int DARKPHOTON = 60000;
115static const int MAVTOP = 60001;
116
117static const int PIPLUS = 211;
118static const int PIMINUS = -PIPLUS;
119static const int PI0 = 111;
120static const int K0L = 130;
121
122static const int K0S = 310;
123static const int K0 = 311;
124static const int KPLUS = 321;
125static const int DPLUS = 411;
126static const int DSTAR = 413;
127static const int D0 = 421;
128static const int DSPLUS = 431;
129static const int JPSI = 443;
130static const int B0 = 511;
131static const int BCPLUS = 541;
132static const int PROTON = 2212;
133static const int NEUTRON = 2112;
134static const int LAMBDA0 = 3122;
135static const int LAMBDACPLUS = 4122;
136static const int LAMBDAB0 = 5122;
137static const int PSI2S = 20443;
138
144static const int RH_NU_E = 9900012;
145static const int RH_NU_MU = 9900014;
146static const int RH_NU_TAU = 9900016;
147static const int WBOSON_LRSM = 9900024;
148
149static const int LEAD = 1000822080;
150static const int INDIUM = 1000491150;
151static const int KRYPTON = 1000360840;
152static const int CALCIUM = 1000200400;
153static const int ARGON = 1000180400;
154static const int MAGNESIUM = 1000120240;
155static const int NEON = 1000100200;
156static const int OXYGEN = 1000080160;
157static const int BORON = 1000050110;
158static const int HELIUM = 1000020040;
159
163static const int POMERON = 990;
164static const int ODDERON = 9990;
165static const int REGGEON = 110;
166
172static const int GEANTINOPLUS = 998;
173static const int GEANTINO0 = 999;
174
175
181template <class T> inline bool isQuark(const T& p) {return isQuark(p->pdg_id());}
182template <> inline bool isQuark(const int& p) { return p != 0 && (std::abs(p) <= TPRIME || std::abs(p) == MAVTOP);}
183template <> inline bool isQuark(const DecodedPID& p){ return isQuark(p.pid()); }
184
185// APID: the fourth generation quarks are not standard model quarks
186template <class T> inline bool isSMQuark(const T& p) {return isSMQuark(p->pdg_id());}
187template <> inline bool isSMQuark(const int& p) { return p != 0 && std::abs(p) <= TQUARK;}
188template <> inline bool isSMQuark(const DecodedPID& p){ return isSMQuark(p.pid()); }
189
190template <class T> inline bool isStrange(const T& p) {return isStrange(p->pdg_id());}
191template <> inline bool isStrange(const int& p){ return std::abs(p) == SQUARK;}
192
193template <class T> inline bool isCharm(const T& p){return isCharm(p->pdg_id());}
194template <> inline bool isCharm(const int& p){ return std::abs(p) == CQUARK;}
195
196template <class T> inline bool isBottom(const T& p){return isBottom(p->pdg_id());}
197template <> inline bool isBottom(const int& p){ return std::abs(p) == BQUARK;}
198
199template <class T> inline bool isTop(const T& p){return isTop(p->pdg_id());}
200template <> inline bool isTop(const int& p){ return std::abs(p) == TQUARK;}
201
203template <class T> inline bool isLepton(const T& p){return isLepton(p->pdg_id());}
204template <> inline bool isLepton(const int& p){ auto sp = std::abs(p); return sp >= ELECTRON && sp <= NUPRIME; }
205template <> inline bool isLepton(const DecodedPID& p){ return isLepton(p.pid()); }
206
208template <class T> inline bool isSMLepton(const T& p){return isSMLepton(p->pdg_id());}
209template <> inline bool isSMLepton(const int& p){ auto sp = std::abs(p); return sp >= ELECTRON && sp <= NU_TAU; }
210template <> inline bool isSMLepton(const DecodedPID& p){ return isSMLepton(p.pid()); }
211
213template <class T> inline bool isChLepton(const T& p){return isChLepton(p->pdg_id());}
214template <> inline bool isChLepton(const int& p){ auto sp = std::abs(p); return sp >= ELECTRON && sp <= LPRIME && sp%2 == 1; }
215
216template <class T> inline bool isElectron(const T& p){return isElectron(p->pdg_id());}
217template <> inline bool isElectron(const int& p){ return std::abs(p) == ELECTRON;}
218
219template <class T> inline bool isMuon(const T& p){return isMuon(p->pdg_id());}
220template <> inline bool isMuon(const int& p){ return std::abs(p) == MUON;}
221
222template <class T> inline bool isTau(const T& p){return isTau(p->pdg_id());}
223template <> inline bool isTau(const int& p){ return std::abs(p) == TAU;}
224
226template <class T> inline bool isNeutrino(const T& p){return isNeutrino(p->pdg_id());}
227template <> inline bool isNeutrino(const int& p){ auto sp = std::abs(p); return sp == NU_E || sp == NU_MU || sp == NU_TAU || sp == NUPRIME; }
228
229template <class T> inline bool isSMNeutrino(const T& p){return isSMNeutrino(p->pdg_id());}
230template <> inline bool isSMNeutrino(const int& p){ auto sp = std::abs(p); return sp == NU_E || sp == NU_MU || sp == NU_TAU; }
231
234template <class T> inline bool isFourthGeneration(const T& p){return isFourthGeneration(p->pdg_id());}
235template <> inline bool isFourthGeneration(const int& p) {return std::abs(p) == BPRIME || std::abs(p) == TPRIME || std::abs(p) == LPRIME || std::abs(p) == NUPRIME;}
236
241template <class T> inline bool isDiquark(const T& p){return isDiquark(p->pdg_id());}
242template <> inline bool isDiquark(const DecodedPID& p){
243 if ( p.ndigits() == 4 && p(0) >= p(1) && p(1) != 0 && p(2) == 0 && (p.last() == 1 || p.last() == 3)
244 && p.max_digit(2,4) < QUARK_LIMIT
245 ) return true;
246 return false;
247}
248template <> inline bool isDiquark(const int& p){ if (!hasAllowedNumberOfDigits(p,4)) return false; auto value_digits = DecodedPID(p); return isDiquark(value_digits);}
249
258template <class T> inline bool isMeson(const T& p){return isMeson(p->pdg_id());}
259template <> inline bool isMeson(const DecodedPID& p){
260 if (p.ndigits() < 3 ) return false;
261 if (p.ndigits() == 7 && (p(0) == 1 || p(0) == 2)) return false; // APID don't match SUSY particles
262 if (std::abs(p.pid()) == K0S) return true;
263 if (std::abs(p.pid()) == K0L) return true;
264 if (std::abs(p.pid()) == K0) return true;
265 if (p.last() % 2 != 1 ) return false;
266 if (p.max_digit(1,3) >= QUARK_LIMIT ) return false; // Ignore pdg_ids which would describe states including fourth generation quarks
267 if (p.min_digit(1,3) == 0 ) return false;
268 if (*(p.second.rbegin() + 2) < *(p.second.rbegin() + 1) ) return false; // Quark ordering (nq2 >= nq3)
269 if (*(p.second.rbegin() + 2) == *(p.second.rbegin() + 1) && p.pid() < 0 ) return false; // Illegal antiparticle check (nq2 == nq3)
270 if (p.ndigits() == 3 ) return true;
271 if (*(p.second.rbegin() + 3) != 0 ) return false; // Only two quarks! (nq1 == 0)
272 if (p.ndigits() == 5 && p(0) == 1 ) return true;
273 if (p.ndigits() == 5 && p(0) == 2 && p.last() > 1 ) return true;
274 if (p.ndigits() == 5 && p(0) == 3 && p.last() > 1 ) return true;
275 if (p.ndigits() == 6 && p.last() % 2 == 1 ) return true;
276 if (p.ndigits() == 7 && p(0) == 9 && p(1) == 0 ) return true;
277
278 return false;
279}
280template <> inline bool isMeson(const int& p){ auto value_digits = DecodedPID(p); return isMeson(value_digits);}
281
283template <class T> inline bool isQuarkonium(const T& p){return isQuarkonium(p->pdg_id());}
284template <> inline bool isQuarkonium(const DecodedPID& p) {
285 if (!isMeson(p)) return false; //< all quarkonia are mesons
286 return (*(p.second.rbegin() + 2) > SQUARK && p.last() > 0 && *(p.second.rbegin() + 1) == *(p.second.rbegin() + 2));
287}
288template <> inline bool isQuarkonium(const int& p){ auto value_digits = DecodedPID(p); return isQuarkonium(value_digits);}
289
292template <class T> inline bool isBaryon(const T& p){return isBaryon(p->pdg_id());}
293template <> inline bool isBaryon(const DecodedPID& p){
294 if (p.ndigits() < 4 ) return false;
295 if (p.max_digit(1,4) >= QUARK_LIMIT ) return false; // Ignore pdg_ids which would describe states including fourth generation quarks
296 if (p.min_digit(1,4) == 0) return false; // Ignore pdg_ids with zero for nq1, nq2, nq3
297 if (p.ndigits() == 4 && (p.last() == 2 || p.last() == 4|| p.last() == 6|| p.last() == 8) ) return true;
298
299 if (p.ndigits() == 5 && p(0) == 1 && (p.last() == 2 || p.last() == 4) ) return true;
300 if (p.ndigits() == 5 && p(0) == 3 && (p.last() == 2 || p.last() == 4) ) return true;
301
302 if (p.ndigits() == 6 ) {
303 if (p(0) == 1 && p(1) == 0 && p.last() == 2 ) return true;
304 if (p(0) == 1 && p(1) == 0 && p.last() == 4 ) return true;
305 if (p(0) == 1 && p(1) == 0 && p.last() == 6 ) return true;
306 if (p(0) == 1 && p(1) == 1 && p.last() == 2 ) return true;
307 if (p(0) == 1 && p(1) == 2 && p.last() == 4 ) return true;
308
309 if (p(0) == 2 && p(1) == 0 && p.last() == 2 ) return true;
310 if (p(0) == 2 && p(1) == 0 && p.last() == 4 ) return true;
311 if (p(0) == 2 && p(1) == 0 && p.last() == 6 ) return true;
312 if (p(0) == 2 && p(1) == 0 && p.last() == 8 ) return true;
313 if (p(0) == 2 && p(1) == 1 && p.last() == 2 ) return true;
314 }
315
316 if (p.ndigits() == 5 ) {
317 if (p(0) == 2 && p.last() == 2 ) return true;
318 if (p(0) == 2 && p.last() == 4 ) return true;
319 if (p(0) == 2 && p.last() == 6 ) return true;
320 if (p(0) == 5 && p.last() == 2 ) return true;
321 if (p(0) == 1 && p.last() == 6 ) return true;
322 if (p(0) == 4 && p.last() == 2 ) return true;
323 }
324 return false;
325}
326template <> inline bool isBaryon(const int& p){if (!hasAllowedNumberOfDigits(p,4,5,6)) return false; auto value_digits = DecodedPID(p); return isBaryon(value_digits);}
327
335template <class T> inline bool isTetraquark(const T& p){return isTetraquark(p->pdg_id());}
336template <> inline bool isTetraquark(const DecodedPID& p){
337 return (p.ndigits() == 9 && p(0) == 1 && p(5) == 0 &&
338 p.max_digit(1,3) < QUARK_LIMIT && p.min_digit(1,3) > 0 && // ignore 4th generation quarks for nq3 and nq4
339 p.max_digit(4,6) < QUARK_LIMIT && p.min_digit(4,6) > 0 && // ignore 4th generation quarks for nq1 and nq2
340 ( p(3) >= p(4) && p(6) >= p(7) ) && ( ( p(3) > p(6) ) || ( p(3) == p(6) && (p(4) >= p(7))))
341 );
342}
343template <> inline bool isTetraquark(const int& p){ if (!hasAllowedNumberOfDigits(p,9)) return false; auto value_digits = DecodedPID(p); return isTetraquark(value_digits);}
344
351// APID: states with fourth generation quarks are not pentaquarks
352template <class T> inline bool isPentaquark(const T& p){return isPentaquark(p->pdg_id());}
353template <> inline bool isPentaquark(const DecodedPID& p){
354 return (p.ndigits() == 9 && p(0) == 1 &&
355 p.max_digit(1,6) < QUARK_LIMIT && p.min_digit(1,6) > 0 && // ignore 4th generation (anti-)quarks
356 ( p(3) >= p(4) && p(4) >= p(5) && p(5) >= p(6)) );
357}
358template <> inline bool isPentaquark(const int& p){ if (!hasAllowedNumberOfDigits(p,9)) return false; auto value_digits = DecodedPID(p); return isPentaquark(value_digits);}
359
360// APID Mesons, Baryons, Tetraquarks and Pentaquarks are Hadrons
361template <class T> inline bool isHadron(const T& p){return isHadron(p->pdg_id());}
362template <> inline bool isHadron(const DecodedPID& p){ return isMeson(p) || isBaryon(p) || isTetraquark(p) || isPentaquark(p); }
363template <> inline bool isHadron(const int& p){ auto value_digits = DecodedPID(p); return isHadron(value_digits);}
364
365
369template <class T> inline bool isTrajectory(const T& p){return isTrajectory(p->pdg_id());}
370template <> inline bool isTrajectory(const int& p){ return std::abs(p) == POMERON || std::abs(p) == ODDERON || std::abs(p) == REGGEON; }
371
372
379template <class T> inline bool isBoson(const T& p){return isBoson(p->pdg_id());}
380template <> inline bool isBoson(const int& p){ auto sp = std::abs(p); return sp > 20 && sp < 41; }
381template <> inline bool isBoson(const DecodedPID& p){ return isBoson(p.pid()); }
382
383template <class T> inline bool isGluon(const T& p){return isGluon(p->pdg_id());}
384template <> inline bool isGluon(const int& p){ return p == GLUON; }
385
386template <class T> inline bool isPhoton(const T& p){return isPhoton(p->pdg_id());}
387template <> inline bool isPhoton(const int& p){ return p == PHOTON; }
388
389template <class T> inline bool isZ(const T& p){return isZ(p->pdg_id());}
390template <> inline bool isZ(const int& p){ return p == Z0BOSON; }
391
392template <class T> inline bool isW(const T& p){return isW(p->pdg_id());}
393template <> inline bool isW(const int& p){ return std::abs(p) == WPLUSBOSON; }
394
396template <class T> inline bool isHeavyBoson(const T& p){return isHeavyBoson(p->pdg_id());}
397template <> inline bool isHeavyBoson(const int& p){ return p == ZPRIME || p == ZDBLPRIME || std::abs(p) == WPLUSPRIME; }
398
400template <class T> inline bool isHiggs(const T& p){return isHiggs(p->pdg_id());}
401template <> inline bool isHiggs(const int& p){ return p == HIGGSBOSON; }
402
404template <class T> inline bool isMSSMHiggs(const T& p){return isMSSMHiggs(p->pdg_id());}
405template <> inline bool isMSSMHiggs(const int& p){ return p == HIGGS2 || p == HIGGS3 || std::abs(p) == HIGGSPLUS; }
406
407template <class T> inline bool isGraviton(const T& p) {return isGraviton(p->pdg_id());}
408template <> inline bool isGraviton(const int& p){ return p == GRAVITON; }
409
410template <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
411
418template <class T> inline bool isLeptoQuark(const T& p){return isLeptoQuark(p->pdg_id());}
419template <> inline bool isLeptoQuark(const int& p){ return std::abs(p) == LEPTOQUARK; }
420
421template <class T> inline bool isPythia8Specific(const T& p){ return isPythia8Specific(p->pdg_id());}
422template <> inline bool isPythia8Specific(const DecodedPID& p){ return (p.ndigits() == 7 && p(0) == 9 && p(1) == 9);}
423template <> inline bool isPythia8Specific(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isPythia8Specific(value_digits);}
424
430template <class T> inline bool isNeutrinoRH(const T& p){return isNeutrinoRH(p->pdg_id());}
431template <> 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);}
432
435template <class T> inline bool isGenSpecific(const T& p){return isGenSpecific(p->pdg_id());}
436template <> inline bool isGenSpecific(const int& p){
437 int ap = std::abs(p);
438 if (ap >= 81 && ap <= 100) return true;
439 if (ap >= 901 && ap <= 930) return true;
440 if (ap >= 998 && ap <= 999) return true;
441 if (ap >= 1901 && ap <= 1930) return true;
442 if (ap >= 2901 && ap <= 2930) return true;
443 if (ap >= 3901 && ap <= 3930) return true;
444 return false;
445}
446
447template <class T> inline bool isGeantino(const T& p){return isGeantino(p->pdg_id());}
448template <> inline bool isGeantino(const int& p){ return (std::abs(p) == GEANTINO0 || std::abs(p) == GEANTINOPLUS);}
449
451template <class T> inline bool isGlueball(const T& p) { return isGlueball(p->pdg_id()); }
452template <> inline bool isGlueball(const DecodedPID& p) {
453 if (p.ndigits() > 4) return false; // APID avoid classifying R-Glueballs as SM Glueballs
454 return
455 ( ( p.ndigits() == 3 && p(0) == COMPOSITEGLUON && p(1) == COMPOSITEGLUON && (p.last() == 1 || p.last() == 5) ) ||
456 ( p.ndigits() == 4 && p(0) == COMPOSITEGLUON && p(1) == COMPOSITEGLUON && p(2) == COMPOSITEGLUON && (p.last() == 3 || p.last() == 7) ) );
457}
458template <> inline bool isGlueball(const int& p) { if (!hasAllowedNumberOfDigits(p,3,4)) return false; auto value_digits = DecodedPID(p); return isGlueball(value_digits); }
459
460
466
467// APID: Super-partners of standard model quarks only
468template <class T> inline bool isSquark(const T& p) { return isSquark(p->pdg_id()); }
469template <> inline bool isSquark(const DecodedPID& p){
470 auto pp = p.shift(1); return (p.ndigits() == 7 && (p(0) == 1 || p(0) == 2) && isSMQuark(pp));
471}
472template <> inline bool isSquark(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isSquark(value_digits);}
473
474
475// APID: Super-partners of left-handed standard model quarks only
476template <class T> inline bool isSquarkLH(const T& p) { return isSquarkLH(p->pdg_id()); }
477template <> inline bool isSquarkLH(const DecodedPID& p){
478 auto pp = p.shift(1); return (p.ndigits() == 7 && p(0) == 1 && isSMQuark(pp));
479}
480template <> inline bool isSquarkLH(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isSquarkLH(value_digits);}
481
482
483// APID: Super-partners of right-handed standard model quarks only
484template <class T> inline bool isSquarkRH(const T& p) { return isSquarkRH(p->pdg_id()); }
485template <> inline bool isSquarkRH(const DecodedPID& p){
486 auto pp = p.shift(1); return (p.ndigits() == 7 && p(0) == 2 && isSMQuark(pp));
487}
488template <> inline bool isSquarkRH(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isSquarkRH(value_digits);}
489
490
491// APID: Super-partners of standard model leptons only
492template <class T> inline bool isSlepton(const T& p) { return isSlepton(p->pdg_id()); }
493template <> inline bool isSlepton(const DecodedPID& p){ auto pp = p.shift(1); return (p.ndigits() == 7 && (p(0) == 1 || p(0) == 2) && isSMLepton(pp));}
494template <> inline bool isSlepton(const int& p){ auto value_digits = DecodedPID(p); return isSlepton(value_digits);}
495
496
497// APID: Super-partners of left-handed standard model leptons only
498template <class T> inline bool isSleptonLH(const T& p) { return isSleptonLH(p->pdg_id()); }
499template <> inline bool isSleptonLH(const DecodedPID& p){
500 auto pp = p.shift(1); return (p.ndigits() == 7 && p(0) == 1 && isSMLepton(pp));
501}
502template <> inline bool isSleptonLH(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isSleptonLH(value_digits);}
503
504
505// APID: Super-partners of right-handed standard model leptons only
506template <class T> inline bool isSleptonRH(const T& p) { return isSleptonRH(p->pdg_id()); }
507template <> inline bool isSleptonRH(const DecodedPID& p){
508 auto pp = p.shift(1); return (p.ndigits() == 7 && p(0) == 2 && isSMLepton(pp));
509}
510template <> inline bool isSleptonRH(const int& p){ auto value_digits = DecodedPID(p); return isSleptonRH(value_digits);}
511
512
513// APID: Super-partners of gauge bosons including gravitons
514template <class T> inline bool isGaugino(const T& p) { return isGaugino(p->pdg_id()); }
515template <> inline bool isGaugino(const DecodedPID& p){
516 auto pp = p.shift(1); return (p.ndigits() == 7 && p(0) == 1 && isBoson(pp.pid()));
517}
518template <> inline bool isGaugino(const int& p){ auto value_digits = DecodedPID(p); return isGaugino(value_digits);}
519
520
521// APID: Super-partners of fundamental particles
522template <class T> inline bool isSuperpartner(const T& p) { return isSuperpartner(p->pdg_id()); }
523template <> inline bool isSuperpartner(const DecodedPID& p){
524 return isSlepton(p) || isSquark(p) || isGaugino(p);
525}
526template <> inline bool isSuperpartner(const int& p){ auto value_digits = DecodedPID(p); return isSuperpartner(value_digits);}
527
528
534template <class T> inline bool isTechnicolor(const T& p){return isTechnicolor(p->pdg_id());}
535template <>
536inline bool isTechnicolor(const DecodedPID& p) {
537 const auto& pp = (p.ndigits() == 7) ? p.shift(2) : DecodedPID(0);
538 return (p.ndigits() == 7 && p(0) == 3 && (p(1) == 0 || p(1) == 1) &&
539 (isQuark(pp) || isLepton(pp) || isBoson(pp) || isGlueball(pp) ||
540 isDiquark(pp) || isHadron(pp)));
541}
542template <> inline bool isTechnicolor(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isTechnicolor(value_digits);}
543
546template <class T> inline bool isExcited(const T& p){return isExcited(p->pdg_id());}
547template <>
548inline bool isExcited(const DecodedPID& p) {
549 const auto& pp = (p.ndigits() == 7) ? p.shift(2) : DecodedPID(0);
550 return (p.ndigits() == 7 && (p(0) == 4 && p(1) == 0) &&
551 (isLepton(pp) || isQuark(pp)));
552}
553template <> inline bool isExcited(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isExcited(value_digits);}
554
567
572template <class T> inline bool isRGlueball(const T& p) { return isRGlueball(p->pdg_id()); }
573template <> inline bool isRGlueball(const DecodedPID& p) {
574 if (p.ndigits() != 7 || p(0) != 1) return false;
575 auto pp = p.shift(1);
576 return
577 ( ( pp.ndigits() == 3 && pp(0) == COMPOSITEGLUON && pp(1) == COMPOSITEGLUON && (pp.last() == 1 || pp.last() == 3) ) ||
578 ( pp.ndigits() == 4 && pp(0) == COMPOSITEGLUON && pp(1) == COMPOSITEGLUON && pp(2) == COMPOSITEGLUON && (pp.last() == 1 || pp.last() == 5) ) );
579}
580template <> inline bool isRGlueball(const int& p) { if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isRGlueball(value_digits); }
581
582// APID Define R-Mesons as gluino-quark-antiquark and squark-antiquark bound states (ignore 4th generation squarks/quarks)
583// NB Current models only allow gluino-quark-antiquark, stop-antiquark and sbottom-antiquark states
584template <class T> inline bool isRMeson(const T& p) { return isRMeson(p->pdg_id()); }
585template <> inline bool isRMeson(const DecodedPID& p) {
586 if (!(p.ndigits() == 7 && (p(0) == 1 || p(0) == 2))) return false;
587 auto pp = p.shift(1);
588 return (
589 // Handle ~gluino-quark-antiquark states
590 (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)) ||
591 // Handle squark-antiquark states (previously called Smeson/mesoninos)
592 (pp.ndigits() == 3 && pp.min_digit(1,3) > 0 && pp.max_digit(1,3) < QUARK_LIMIT && pp(1) <= pp(0) && pp.last() == 2)
593 );
594}
595template <> inline bool isRMeson(const int& p) { if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isRMeson(value_digits); }
596
597// APID Define R-Baryons as gluino-quark-quark-quark and squark-quark-quark bound states (ignore 4th generation squarks/quarks)
598// NB Current models only allow gluino-quark-quark-quark, stop-quark-quark and sbottom-quark-quark states
599template <class T> inline bool isRBaryon(const T& p) { return isRBaryon(p->pdg_id()); }
600template <> inline bool isRBaryon(const DecodedPID& p) {
601 if (!(p.ndigits() == 7 && (p(0) == 1 || p(0) == 2))) return false;
602 auto pp = p.shift(1);
603 return (
604 // Handle ~gluino-quark-quark-quark states
605 (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)) ||
606 // Handle squark-quark-quark states (previously called Sbaryons)
607 (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))
608 );
609}
610template <> inline bool isRBaryon(const int& p) { if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isRBaryon(value_digits); }
611
612
613template <class T> inline bool isRHadron(const T& p) { return isRHadron(p->pdg_id()); }
614template <> inline bool isRHadron(const DecodedPID& p) {
615 return (isRBaryon(p) || isRMeson(p) || isRGlueball(p));
616}
617template <> inline bool isRHadron(const int& p) { auto value_digits = DecodedPID(p); return isRHadron(value_digits); }
618
619
620template <class T> inline bool hasSquark(const T& p, const int& q) { return hasSquark(p->pdg_id(), q); }
621template <> inline bool hasSquark(const DecodedPID& p, const int& q){
622 auto pp = p.shift(1); return (
623 (isSquark(p) || isRHadron(p))
624 && pp.ndigits() != 2 // skip lepton and boson super-partners by vetoing ndigits==2
625 && pp(0) == q // After shifting, the first digit will always represent the squark in R-Hadron (and squark) PIDs
626 );
627}
628template <> inline bool hasSquark(const int& p, const int& q){ auto value_digits = DecodedPID(p); return hasSquark(value_digits, q);}
629
630
631// APID Define isSUSY to return true for Superpartners of standard model particles and R-Hadrons
632// TODO Should this include the MSSM extended Higgs sector??
633template <class T> inline bool isSUSY(const T& p){return isSUSY(p->pdg_id());}
634template <> inline bool isSUSY(const DecodedPID& p){return (isSuperpartner(p) || isRHadron(p));}
635template <> inline bool isSUSY(const int& p){ auto value_digits = DecodedPID(p); return isSUSY(value_digits);}
636
637
645template <class T> inline bool isKK(const T& p){return isKK(p->pdg_id());}
646template <> inline bool isKK(const DecodedPID& p){return (p.ndigits() == 7 && (p(0) == 5 || p(0) == 6 ) && (p(1) != 9) );}
647template <> inline bool isKK(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isKK(value_digits);}
648
655template <class T> inline bool isMonopole(const T& p){return isMonopole(p->pdg_id());}
656template <> 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);}
657template <> inline bool isMonopole(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isMonopole(value_digits);}
658
668template <class T> inline bool isDM(const T& p){return isDM(p->pdg_id());}
669template <> inline bool isDM(const int& p){
670 auto sp = std::abs(p);
671 auto value_digits = DecodedPID(p);
672 return (sp >= 51 && sp <= 60) || (value_digits.ndigits() == 7 && value_digits(0) == 5 && value_digits(1) == 9) || sp == DARKPHOTON; }
673
678template <class T> inline bool isHiddenValley(const T& p){return isHiddenValley(p->pdg_id());}
679template <>
680inline bool isHiddenValley(const DecodedPID& p) {
681 const auto& pp = (p.ndigits() == 7) ? p.shift(2) : DecodedPID(0);
682 return (p.ndigits() == 7 && p(0) == 4 && p(1) == 9 &&
683 (isQuark(pp) || isLepton(pp) || isBoson(pp) || isGlueball(pp) ||
684 isDiquark(pp) || isHadron(pp)));
685}
686template <> inline bool isHiddenValley(const int& p){ if (!hasAllowedNumberOfDigits(p,7)) return false; auto value_digits = DecodedPID(p); return isHiddenValley(value_digits);}
687
694template <class T> inline bool isGenericMultichargedParticle(const T& p){return isGenericMultichargedParticle(p->pdg_id());}
695template <> 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);}
696template <> inline bool isGenericMultichargedParticle(const int& p){if (!hasAllowedNumberOfDigits(p,8)) return false; auto value_digits = DecodedPID(p); return isGenericMultichargedParticle(value_digits);}
697
712template <class T> inline bool isNucleus(const T& p){return isNucleus(p->pdg_id());}
713template <> inline bool isNucleus(const DecodedPID& p){
714 if (std::abs(p.pid()) == PROTON) return true;
715 if (p.ndigits() != 10) return false;
716 if (p(0) != 1 || p(1) != 0 ) return false;
717 // charge should always be less than or equal to baryon number
718 // the following line is A >= Z
719 const int A = p(8) + 10*p(7) + 100*p(6);
720 const int Z = p(5) + 10*p(4) + 100*p(3);
721 return ( A >= Z );
722}
723template <> inline bool isNucleus(const int& p){ auto value_digits = DecodedPID(p); return isNucleus(value_digits);}
724
725
726template <class T> inline bool hasQuark(const T& p, const int& q);
727template <> inline bool hasQuark(const DecodedPID& p, const int& q){
728 if (isQuark(p.pid())) { return (std::abs(p.pid()) == q );}
729 if (isMeson(p)) { return *(p.second.rbegin() + 1) == q ||*(p.second.rbegin()+2) ==q;}
730 if (isDiquark(p)) { auto i = std::find(p.second.rbegin() + 2,p.second.rbegin()+4,q); return (i!=p.second.rbegin()+4);}
731 if (isBaryon(p)) { auto i = std::find(p.second.rbegin() + 1,p.second.rbegin()+4,q); return (i!=p.second.rbegin()+4);}
732 if (isTetraquark(p)) { auto i = std::find(p.second.rbegin() + 1,p.second.rbegin()+5,q); return (i!=p.second.rbegin()+5);}
733 if (isPentaquark(p)) { auto i = std::find(p.second.rbegin() + 1,p.second.rbegin()+6,q); return (i!=p.second.rbegin()+6);}
734 if (isNucleus(p) && std::abs(p.pid()) != PROTON) { return (q == 1 || q == 2 || (q==3 && p(2) > 0));}
735 if (isSUSY(p)) { // APID SUSY case
736 auto pp = p.shift(1);
737 if ( pp.ndigits() == 1 ) { return false; } // Handle squarks
738 if ( pp.ndigits() == 3 ) { return (pp(1) == q); } // Handle ~q qbar pairs
739 if ( pp.ndigits() == 4 ) { return (pp(1) == q || pp(2) == q); } // Ignore gluinos and squarks
740 if ( pp.ndigits() == 5 ) { return (pp(1) == q || pp(2) == q || pp(3) == q); } // Ignore gluinos and squarks
741 if ( pp.ndigits() > 5 ) { pp = pp.shift(1); } // Drop gluinos and squarks
742 return hasQuark(pp, q); }
743 return false;
744}
745template <> inline bool hasQuark(const int& p, const int& q){ auto value_digits = DecodedPID(p); return hasQuark(value_digits, q);}
746
747template <class T> inline bool hasStrange(const T& p) { return hasQuark(p,SQUARK); }
748template <class T> inline bool hasCharm(const T& p) { return hasQuark(p,CQUARK); }
749template <class T> inline bool hasBottom(const T& p) { return hasQuark(p,BQUARK); }
750template <class T> inline bool hasTop(const T& p) { return hasQuark(p,TQUARK); }
751
752
753// APID: The baryon number is defined as:
754// B = (1/3)*( n_q - n_{qbar} )
755// where n_q⁠ is the number of quarks, and ⁠n_{qbar} is the number of
756// antiquarks. By convention, squarks have the same quantum numbers as
757// the corresponding quarks (modulo spin and R), so have baryon number
758// 1/3.
759template <class T> inline int baryonNumber3(const T& p) {return baryonNumber3(p->pdg_id());}
760template <> inline int baryonNumber3(const DecodedPID& p){
761 if (isQuark(p.pid())) { return (p.pid() > 0) ? 1 : - 1;}
762 if (isDiquark(p)) { return (p.pid() > 0) ? 2 : -2; }
763 if (isMeson(p) || isTetraquark(p)) { return 0; }
764 if (isBaryon(p) || isPentaquark(p)){ return (p.pid() > 0) ? 3 : -3; }
765 if (isNucleus(p)) {
766 const int result = 3*p(8) + 30*p(7) + 300*p(6);
767 return (p.pid() > 0) ? result : -result;
768 }
769 if (isSUSY(p)) {
770 auto pp = p.shift(1);
771 if (pp.ndigits() < 3 ) { return baryonNumber3(pp); } // super-partners of fundamental particles
772 if (pp(0) == COMPOSITEGLUON) {
773 if (pp(1) == COMPOSITEGLUON) { return 0; } // R-Glueballs
774 if ( pp.ndigits() == 4 ) { return 0; } // states with gluino-quark-antiquark
775 if ( pp.ndigits() == 5) { return (p.pid() > 0) ? 3 : -3; } // states with gluino-quark-quark-quark
776 }
777 if (pp.ndigits() == 3) { return 0; } // squark-antiquark
778 if (pp.ndigits() == 4) { return (p.pid() > 0) ? 3 : -3; } // states with squark-quark-quark
779 }
780 return 0;
781}
782template <> inline int baryonNumber3(const int& p){ auto value_digits = DecodedPID(p); return baryonNumber3(value_digits);}
783
784template <class T> inline double baryonNumber(const T& p) {return baryonNumber(p->pdg_id());}
785template <> inline double baryonNumber(const DecodedPID& p){ return static_cast<double>(baryonNumber3(p))/3.0;}
786template <> inline double baryonNumber(const int& p){ auto value_digits = DecodedPID(p); return static_cast<double>(baryonNumber3(value_digits))/3.0;}
787
788
789// APID: The strangeness of a particle is defined as:
790// S = − ( n_s − n_{sbar} )
791// where n_s represents the number of strange quarks and n_{sbar}
792// represents the number of strange antiquarks. By convention, strange
793// squarks have the same quantum numbers as strange quarks (modulo
794// spin and R), so have strangeness -1.
795static const std::array<int,10> is_strange = {
796 +0, +0, +0, -1, +0, +0, +0, +0, +0, +0 };
797template <class T> inline int strangeness(const T& p) {return strangeness(p->pdg_id());}
798template <> inline int strangeness(const DecodedPID& p){
799 if (isNucleus(p) && p.ndigits() == 10) { return (p.pid() > 0) ? -p(2) : p(2); }
800 if (isStrange(p.pid())) { return (p.pid() > 0) ? -1 : 1; }
801 if (!hasStrange(p) && !hasSquark(p,SQUARK)) { return 0; }
802 if (std::abs(p.pid()) == K0) { return (p.pid() > 0) ? 1 : -1; }
803 size_t nq = 0;
804 int sign = 1;
805 int signmult = 1;
806 int result=0;
807 bool classified = false;
808 if (!classified && isMeson(p)) { classified = true; nq = 2; if ((*(p.second.rbegin()+2)) == 2||(*(p.second.rbegin()+2)) == 4 ) { sign=-1;} signmult =-1; }
809 if (!classified && isDiquark(p)) {return is_strange.at(p(0))+is_strange.at(p(1)); }
810 if (!classified && isBaryon(p)) { classified = true; nq = 3; }
811 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)); }
812 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)); }
813 if (!classified && isSUSY(p)) {
814 nq = 0;
815 auto pp = p.shift(1);
816 if (pp.ndigits() < 3 ) { return strangeness(pp); } // super-partners of fundamental particles
817 if (pp(0) == COMPOSITEGLUON) {
818 if (pp(1) == COMPOSITEGLUON) { return 0; } // R-Glueballs
819 if ( pp.ndigits() == 4 || pp.ndigits() == 5) {
820 pp = pp.shift(1); // Remove gluino
821 }
822 }
823 if (pp.ndigits() == 3) { classified = true; nq = 2; if (p.last()%2==0) {sign = -1;} signmult = -1; } // states with quark-antiquark or squark-antiquark
824 if (pp.ndigits() == 4) { classified = true; nq = 3; } // states with quark-quark-quark or squark-quark-quark
825 }
826 for (auto r = p.second.rbegin() + 1; r != p.second.rbegin() + 1 + nq; ++r) {
827 result += is_strange.at(*r)*sign;
828 sign*=signmult;
829 }
830 return p.pid() > 0 ? result : -result;
831}
832template <> inline int strangeness(const int& p){ auto value_digits = DecodedPID(p); return strangeness(value_digits);}
833
834
835template <class T> inline int numberOfLambdas(const T& p) {return numberOfLambdas(p->pdg_id());}
836template <> inline int numberOfLambdas(const DecodedPID& p){
837 if (std::abs(p.pid()) == LAMBDA0) { return (p.pid() > 0) ? 1 : -1; }
838 if (isNucleus(p) && p.ndigits() == 10) { return (p.pid() > 0) ? p(2) : -p(2); }
839 return 0;
840}
841template <> inline int numberOfLambdas(const int& p){ auto value_digits = DecodedPID(p); return numberOfLambdas(value_digits);}
842
843
844template <class T> inline int numberOfProtons(const T& p) {return numberOfProtons(p->pdg_id());}
845template <> inline int numberOfProtons(const DecodedPID& p){
846 if (std::abs(p.pid()) == PROTON) { return (p.pid() > 0) ? 1 : -1; }
847 if (isNucleus(p)) {
848 const int result = p(5) + 10*p(4) + 100*p(3);
849 return (p.pid() > 0) ? result : -result;
850 }
851 return 0;
852}
853template <> inline int numberOfProtons(const int& p){ auto value_digits = DecodedPID(p); return numberOfProtons(value_digits);}
854
855
857template <class T> inline bool isBSM(const T& p){return isBSM(p->pdg_id());}
858template <> inline bool isBSM(const DecodedPID& p){
859 if (p.pid() == GRAVITON || std::abs(p.pid()) == MAVTOP || p.pid() == DARKPHOTON) return true;
860 if (std::abs(p.pid()) > 16 && std::abs(p.pid()) < 19) return true;
861 if (std::abs(p.pid()) > 31 && std::abs(p.pid()) < 39) return true;
862 if (std::abs(p.pid()) > 39 && std::abs(p.pid()) < 81) return true;
863 if (std::abs(p.pid()) > 6 && std::abs(p.pid()) < 9) return true;
864 if (isSUSY(p)) return true;
865 if (isNeutrinoRH(p.pid())) return true;
866 if (isGenericMultichargedParticle(p)) return true;
867 if (isTechnicolor(p)) return true;
868 if (isExcited(p)) return true;
869 if (isKK(p)) return true;
870 if (isHiddenValley(p)) return true;
871 if (isMonopole(p)) return true;
872 if (isDM(p.pid())) return true;
873 return false;
874}
875template <> inline bool isBSM(const int& p){
876 if (p == GRAVITON || std::abs(p) == MAVTOP || p == DARKPHOTON) return true;
877 if (std::abs(p) > 16 && std::abs(p) < 19) return true;
878 if (std::abs(p) > 31 && std::abs(p) < 38) return true;
879 if (std::abs(p) > 39 && std::abs(p) < 81) return true;
880 if (std::abs(p) > 6 && std::abs(p) < 9) return true;
881 auto value_digits = DecodedPID(p); return isBSM(value_digits);
882}
883
884template <class T> inline bool isTransportable(const T& p){return isTransportable(p->pdg_id());}
885template <> inline bool isTransportable(const DecodedPID& p){ return isPhoton(p.pid()) || isGeantino(p.pid()) || isHadron(p) || isLepton(p.pid()) || p.pid() == DARKPHOTON;}
886template <> inline bool isTransportable(const int& p){ auto value_digits = DecodedPID(p); return isTransportable(value_digits);}
887
889template <class T> inline bool isValid(const T& p){return isValid(p->pdg_id());}
890template <> inline bool isValid(const DecodedPID& p){
891 return p.pid() !=0 && ( isQuark(p) || isLepton(p) || isBoson(p) || isGlueball(p) ||
892 isTrajectory(p.pid()) || isGenSpecific(p.pid()) || isDiquark(p) ||
893 isBSM(p) || isHadron(p) || isNucleus(p) || isGeantino(p.pid()) ||
894 isPythia8Specific(p) ); }
895template <> inline bool isValid(const int& p){ if (!p) return false; if (std::abs(p) < 42) return true;
896 if (isGenSpecific(p)) return true;
897 auto value_digits = DecodedPID(p); return isValid(value_digits);
898}
899
900template <class T> inline int leadingQuark(const T& p) {return leadingQuark(p->pdg_id());}
901template <> inline int leadingQuark(const DecodedPID& p){
902 if (isQuark(p.pid())) { return std::abs(p.pid());}
903 if (isMeson(p)) { return p.max_digit(1,3);}
904 if (isDiquark(p)) { return p.max_digit(2,4);}
905 if (isBaryon(p)) { return p.max_digit(1,4);}
906 if (isTetraquark(p)) { return p.max_digit(1,5);}
907 if (isPentaquark(p)) { return p.max_digit(1,6);}
908 if (isSUSY(p)) { // APID SUSY case
909 auto pp = p.shift(1);
910 if ( pp.ndigits() == 1 ) { return 0; } // Handle squarks
911 if ( pp.ndigits() == 3 ) { pp = DecodedPID(pp(1)); } // Handle ~q qbar pairs
912 if ( pp.ndigits() > 3 ) { pp = pp.shift(1); } // Drop gluinos and squarks
913 return leadingQuark(pp); }
914 return 0;
915}
916
917template <> inline int leadingQuark(const int& p){ auto value_digits = DecodedPID(p); return leadingQuark(value_digits);}
918
919template <class T> inline bool isLightHadron(const T& p) { auto lq = leadingQuark(p); return (lq == DQUARK || lq == UQUARK||lq == SQUARK) && isHadron(p); }
920template <class T> inline bool isHeavyHadron(const T& p) { auto lq = leadingQuark(p); return (lq == CQUARK || lq == BQUARK || lq == TQUARK ) && isHadron(p); }
921template <class T> inline bool isStrangeHadron(const T& p) { return leadingQuark(p) == SQUARK && isHadron(p); }
922template <class T> inline bool isCharmHadron(const T& p) { return leadingQuark(p) == CQUARK && isHadron(p); }
923template <class T> inline bool isBottomHadron(const T& p) { return leadingQuark(p) == BQUARK && isHadron(p); }
924template <class T> inline bool isTopHadron(const T& p) { return leadingQuark(p) == TQUARK && isHadron(p); }
925
926template <class T> inline bool isLightMeson(const T& p) { auto lq = leadingQuark(p); return (lq == DQUARK || lq == UQUARK||lq == SQUARK) && isMeson(p); }
927template <class T> inline bool isHeavyMeson(const T& p) { auto lq = leadingQuark(p); return (lq == CQUARK || lq == BQUARK || lq == TQUARK) && isMeson(p); }
928template <class T> inline bool isStrangeMeson(const T& p) { return leadingQuark(p) == SQUARK && isMeson(p); }
929template <class T> inline bool isCharmMeson(const T& p) { return leadingQuark(p) == CQUARK && isMeson(p); }
930template <class T> inline bool isBottomMeson(const T& p) { return leadingQuark(p) == BQUARK && isMeson(p); }
931template <class T> inline bool isTopMeson(const T& p) { return leadingQuark(p) == TQUARK && isMeson(p); }
932
933template <class T> inline bool isCCbarMeson(const T& p) { return isCCbarMeson(p->pdg_id());}
934template <> inline bool isCCbarMeson(const DecodedPID& p) { return leadingQuark(p) == CQUARK && isMeson(p) && (*(p.second.rbegin()+2)) == CQUARK && (*(p.second.rbegin()+1)) == CQUARK; }
935template <> inline bool isCCbarMeson(const int& p) { return isCCbarMeson(DecodedPID(p)); }
936
937template <class T> inline bool isBBbarMeson(const T& p){ return isBBbarMeson(p->pdg_id());}
938template <> inline bool isBBbarMeson(const DecodedPID& p) { return leadingQuark(p) == BQUARK && isMeson(p) && (*(p.second.rbegin()+2)) == BQUARK && (*(p.second.rbegin()+1)) == BQUARK; }
939template <> inline bool isBBbarMeson(const int& p) { return isBBbarMeson(DecodedPID(p)); }
940
941
942template <class T> inline bool isLightBaryon(const T& p) { auto lq = leadingQuark(p); return (lq == DQUARK || lq == UQUARK||lq == SQUARK) && isBaryon(p); }
943template <class T> inline bool isHeavyBaryon(const T& p) { auto lq = leadingQuark(p); return (lq == CQUARK || lq == BQUARK || lq == TQUARK) && isBaryon(p); }
944template <class T> inline bool isStrangeBaryon(const T& p) { return leadingQuark(p) == SQUARK && isBaryon(p); }
945template <class T> inline bool isCharmBaryon(const T& p) { return leadingQuark(p) == CQUARK && isBaryon(p); }
946template <class T> inline bool isBottomBaryon(const T& p) { return leadingQuark(p) == BQUARK && isBaryon(p); }
947template <class T> inline bool isTopBaryon(const T& p) { return leadingQuark(p) == TQUARK && isBaryon(p); }
948
949
950// APID: This function selects B-Hadrons which predominantly decay weakly. (Commonly used definition in GeneratorFilters package.)
951// 5[1-4]1 L = J = 0, S = 0
952// 5[1-5][1-4]2 J = 1/2, n_r = 0, n_L =0
953template <class T> inline bool isWeaklyDecayingBHadron(const T& p) {return isWeaklyDecayingBHadron(p->pdg_id());}
954template <> inline bool isWeaklyDecayingBHadron(const int& p) {
955 const int pid = std::abs(p);
956 return ( pid == 511 || // B0
957 pid == 521 || // B+
958 pid == 531 || // B_s0
959 pid == 541 || // B_c+
960 pid == 5122 || // Lambda_b0
961 pid == 5132 || // Xi_b-
962 pid == 5232 || // Xi_b0
963 pid == 5112 || // Sigma_b-
964 pid == 5212 || // Sigma_b0
965 pid == 5222 || // Sigma_b+
966 pid == 5332 || // Omega_b-
967 pid == 5142 || // Xi_bc0
968 pid == 5242 || // Xi_bc+
969 pid == 5412 || // Xi'_bc0
970 pid == 5422 || // Xi'_bc+
971 pid == 5342 || // Omega_bc0
972 pid == 5432 || // Omega'_bc0
973 pid == 5442 || // Omega_bcc+
974 pid == 5512 || // Xi_bb-
975 pid == 5522 || // Xi_bb0
976 pid == 5532 || // Omega_bb-
977 pid == 5542 ); // Omega_bbc0
978}
979template <> inline bool isWeaklyDecayingBHadron(const DecodedPID& p){ return isWeaklyDecayingBHadron(p.pid()); }
980
981
982// APID: This function selects C-Hadrons which predominantly decay weakly. (Commonly used definition in GeneratorFilters package.)
983// 4[1-3]1 L = J = 0, S = 0
984// 4[1-4][1-3]2 J = 1/2, n_r = 0, n_L =0
985// NB Omitting pid = 4322 (Xi'_C+) a this undergoes an EM rather than
986// weak decay. (There was an old version of Herwig that decayed it
987// weakly, but this was fixed in Herwig 7.)
988template <class T> inline bool isWeaklyDecayingCHadron(const T& p) {return isWeaklyDecayingCHadron(p->pdg_id());}
989template <> inline bool isWeaklyDecayingCHadron(const int& p) {
990 const int pid = std::abs(p);
991 return ( pid == 411 || // D+
992 pid == 421 || // D0
993 pid == 431 || // Ds+
994 pid == 4122 || // Lambda_c+
995 pid == 4132 || // Xi_c0
996 pid == 4232 || // Xi_c+
997 pid == 4212 || // Xi_c0
998 pid == 4332 || // Omega_c0
999 pid == 4412 || // Xi_cc+
1000 pid == 4422 || // Xi_cc++
1001 pid == 4432 ); // Omega_cc+
1002}
1003template <> inline bool isWeaklyDecayingCHadron(const DecodedPID& p){ return isWeaklyDecayingCHadron(p.pid()); }
1004
1005
1006template <class T> inline int charge3( const T& p){return charge3(p->pdg_id());}
1007template <class T> inline double fractionalCharge(const T& p){return fractionalCharge(p->pdg_id());}
1008template <class T> inline double charge( const T& p){
1009 if (isGenericMultichargedParticle(p)) // BSM multi-charged particles might have a fractional charge that's not a multiple of 1/3
1010 return fractionalCharge(p);
1011 else
1012 return 1.0*charge3(p)/3.0;
1013}
1014template <class T> inline double threeCharge( const T& p){ return charge3(p);}
1015template <class T> inline bool isCharged( const T& p){ return charge3(p) != 0;}
1016
1017
1018template <> inline int charge3(const DecodedPID& p) {
1019 auto ap = std::abs(p.pid());
1020 if (ap < TABLESIZE ) return p.pid() > 0 ? triple_charge.at(ap) : -triple_charge.at(ap);
1021 if (ap == K0) return 0;
1022 if (ap == GEANTINO0) return 0;
1023 if (ap == GEANTINOPLUS) return p.pid() > 0 ? 3 : -3;
1024 if (ap == MAVTOP) return p.pid() > 0 ? 2 : -2;
1025 size_t nq = 0;
1026 int sign = 1;
1027 int signmult = 1;
1028 int result=0;
1029 bool classified = false;
1030 if (!classified && isMeson(p)) { classified = true; nq = 2; if ((*(p.second.rbegin()+2)) == 2||(*(p.second.rbegin()+2)) == 4 ) { sign=-1;} signmult =-1; }
1031 if (!classified && isDiquark(p)) {return triple_charge.at(p(0))+triple_charge.at(p(1)); }
1032 if (!classified && isBaryon(p)) { classified = true; nq = 3; }
1033 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)); }
1034 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)); }
1035 if (!classified && isNucleus(p)) { return 3*numberOfProtons(p);}
1036 if (!classified && isSUSY(p)) {
1037 nq = 0;
1038 auto pp = p.shift(1);
1039 if (pp.ndigits() < 3 ) { return charge3(pp); } // super-partners of fundamental particles
1040 if (pp(0) == COMPOSITEGLUON) {
1041 if (pp(1) == COMPOSITEGLUON) { return 0; } // R-Glueballs
1042 if ( pp.ndigits() == 4 || pp.ndigits() == 5) {
1043 pp = pp.shift(1); // Remove gluino
1044 }
1045 }
1046 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
1047 if (pp.ndigits() == 4) { classified = true; nq = 3; } // states with squark-quark-quark or quark-quark-quark
1048 }
1049 if (!classified && isHiddenValley(p)) { // Hidden Valley particles
1050 auto pp = p.shift(2);
1051 if (!classified && isMeson(pp)) { classified = true; nq = 2; if ((*(pp.second.rbegin()+2)) == 2||(*(pp.second.rbegin()+2)) == 4 ) { sign=-1;} signmult =-1; }
1052 if (!classified && isDiquark(pp)) {return triple_charge.at(pp(0))+triple_charge.at(pp(1)); }
1053 if (!classified && isBaryon(pp)) { classified = true; nq = 3; }
1054 }
1055 if (!classified && isExcited(p)) { //Excited/composite leptons/quarks
1056 auto pp = p.shift(2);
1057 auto ap = std::abs(pp.pid());
1058 if (ap < TABLESIZE ) return pp.pid() > 0 ? triple_charge.at(ap) : -triple_charge.at(ap);
1059 }
1060 if (!classified && isKK(p)) { // Kaluza-Klein particles
1061 auto pp = p.shift(2);
1062 auto ap = std::abs(pp.pid());
1063 if (ap < TABLESIZE ) return pp.pid() > 0 ? triple_charge.at(ap) : -triple_charge.at(ap);
1064
1065 }
1066 if (!classified && isDM(p.pid())) { //Dark Matter Particles
1067 if (p.ndigits() == 7){ // Determining the charges for the more elaborate, 7-digit DM codes
1068 auto pp = p.shift(3); // The first two digits indicate the particle is DM, the third indicates left/right-handedness (see 11(j))
1069 auto ap = std::abs(pp.pid());
1070 if (ap < TABLESIZE ) return pp.pid() > 0 ? triple_charge.at(ap) : -triple_charge.at(ap);
1071 }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
1072 }
1073 if (!classified && isMonopole(p)) {
1076 result = 3*(p(3)*100 + p(4)*10 + p(5));
1077 return ( (p.pid() > 0 && p(2) == 1) || (p.pid() < 0 && p(2) == 2) ) ? result : -result;
1078 }
1079 if (!classified && isGenericMultichargedParticle(p)) {
1080 double abs_charge = 0.0;
1081 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
1082 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
1083 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
1084 return p.pid() > 0 ? abs_threecharge : -1 * abs_threecharge;
1085 }
1086 for (auto r = p.second.rbegin() + 1; r != p.second.rbegin() + 1 + nq; ++r) {
1087 result += triple_charge.at(*r)*sign;
1088 sign*=signmult;
1089 }
1090 return p.pid() > 0 ? result : -result;
1091}
1092template <> inline int charge3(const int& p){
1093 int ap = std::abs(p);
1094 if (ap < TABLESIZE) return p > 0 ? triple_charge.at(ap):-triple_charge.at(ap);
1095 auto value_digits = DecodedPID(p);
1096 return charge3(value_digits);
1097}
1098
1099
1100template <class T> inline bool isNeutral( const T& p){ return p->pdg_id() != 0 && charge3(p) == 0;}
1101template <> inline bool isNeutral(const DecodedPID& p){ return p.pid() != 0 && charge3(p) == 0;}
1102template <> inline bool isNeutral(const int& p){ auto value_digits = DecodedPID(p); return isNeutral(value_digits);}
1103
1104
1105template <> inline double fractionalCharge(const DecodedPID& p) {
1106 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
1107 double abs_charge = 0;
1108 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
1109 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
1110 return p.pid() > 0 ? abs_charge : -1 * abs_charge;
1111}
1112template <> inline double fractionalCharge(const int& p){auto value_digits = DecodedPID(p); return fractionalCharge(value_digits);}
1113
1114// APID: Including Z' and Z'' as EM interacting.
1115template <class T> inline bool isEMInteracting(const T& p){return isEMInteracting(p->pdg_id());}
1116template <> 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));}
1117
1118template <class T> inline bool isParton(const T& p) { return isQuark(p)||isGluon(p);}
1119
1120// APID: Intended to return 2J
1121// Useful for G4ParticleDefinition constructor
1122template <class T> inline int spin2(const T& p) { return spin2(p->pdg_id()); }
1123template <> inline int spin2(const DecodedPID& p) {
1124 if (isSUSY(p)) {
1125 auto pp = p.shift(1);
1126 auto ap = std::abs(pp.pid());
1127 if (ap < TABLESIZE ) { return std::abs(double_spin.at(ap)-1); } // sparticles (0->1, 1 -> 0, 2->1, 4->3)
1128 return p.last()-1; // R-Hadrons (p.last() == 2J +1)
1129 }
1130 if (isHiddenValley(p)) { //Hidden Valley spins
1131 auto pp = p.shift(2);
1132 if (isHadron(pp)) { return pp.last()-1; } // Hadrons (p.last == 2J+1 - special cases handled above)
1133 }
1134 if (isKK(p)) { // Kaluza-Klein spins
1135 auto pp = p.shift(2);
1136 auto ap = std::abs(pp.pid());
1137 if (ap < TABLESIZE ) { return double_spin.at(ap); } // fundamental particles
1138 }
1139 if (isDM(std::abs(p.pid()))) { //DM spins
1140 if (p.ndigits() == 7) { // Determining the spins for the more elaborate, 7-digit DM codes
1141 auto pp = p.shift(3); // The first two digits indicate the particle is DM, the third indicates left/right-handedness (see 11(j))
1142 auto ap = std::abs(pp.pid());
1143 if (ap < TABLESIZE) { return double_spin.at(ap); } // fundamental particles
1144 }else if (std::abs(p.pid()) < TABLESIZE) { // Just to make sure the correct spin is returned for DM 51-60
1145 return std::abs(double_spin.at(std::abs(p.pid())));
1146 }
1147 }
1148 auto ap = std::abs(p.pid());
1149 if (ap == K0S) { return 0; }
1150 if (ap == K0L) { return 0; }
1151 if (ap == MAVTOP) { return 1; } // TODO check this
1152 if (ap == DARKPHOTON) { return 2; } // TODO check this
1153 if (ap < TABLESIZE ) { return double_spin.at(ap); } // fundamental particles
1154 if (isHadron(p)) { return p.last()-1; } // Hadrons (p.last == 2J+1 - special cases handled above)
1155 if (isMonopole(p)) { return 0; } // PDG 11i - For now no spin information is provided. Also matches the definition in the G4Extensions/Monopole package.
1156 if (isGenericMultichargedParticle(p)) { return 0; } // APID Matches the definition in the G4Extensions/Monopole package.
1157 if (isNucleus(p)) { return 1; } // TODO need to explicitly deal with nuclei
1158 return p.last() > 0 ? 1 : 0; // Anything else - best guess
1159}
1160template <> inline int spin2(const int& p){ auto value_digits = DecodedPID(p); return spin2(value_digits);}
1161
1162template <class T> inline double spin(const T& p) { return spin(p->pdg_id()); }
1163template <> inline double spin(const DecodedPID& p) { return 1.0*spin2(p)/2.0; }
1164template <> inline double spin(const int& p){ auto value_digits = DecodedPID(p); return spin(value_digits);}
1165
1166
1167// APID: Returns an unordered list of the quarks contained by the current particle
1168template <class T> inline std::vector<int> containedQuarks(const T& p) { return containedQuarks(p->pdg_id()); }
1169template <> inline std::vector<int> containedQuarks(const int& p) {
1170 auto pp = DecodedPID(p);
1171 std::vector<int> quarks;
1172 if (isQuark(pp.pid())) { quarks.push_back(std::abs(pp.pid())); }
1173 else if (isDiquark(pp)) { quarks.push_back(pp(0)); quarks.push_back(pp(1)); }
1174 else if (isMeson(pp)) { quarks.push_back(*(pp.second.rbegin() + 1)); quarks.push_back(*(pp.second.rbegin()+2)); }
1175 else if (isBaryon(pp)) { for (size_t digit = 1; digit < 4; ++digit) { quarks.push_back(*(pp.second.rbegin() + digit)); } }
1176 else if (isTetraquark(pp)) { for (size_t digit = 1; digit < 5; ++digit) { quarks.push_back(*(pp.second.rbegin() + digit)); } }
1177 else if (isPentaquark(pp)) { for (size_t digit = 1; digit < 6; ++digit) { quarks.push_back(*(pp.second.rbegin() + digit)); } }
1178 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));
1179 const int n_uquarks = A + Z; const int n_dquarks = 2*A - Z - L; const int n_squarks = L;
1180 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); }
1181 else if (isSUSY(pp)) { // APID SUSY case
1182 pp = pp.shift(1);
1183 if ( pp.ndigits() > 1 ) { // skip squarks
1184 if ( pp.ndigits() == 3 ) { pp = DecodedPID(pp(1)); } // Handle ~q qbar pairs
1185 if ( pp.ndigits() > 3 ) { pp = pp.shift(1); } // Drop gluinos and squarks
1186 return containedQuarks(pp.pid());
1187 }
1188 }
1189 return quarks;
1190}
1191template <> inline std::vector<int> containedQuarks(const DecodedPID& p) { return containedQuarks(p.pid()); }
1192
1193template <class T> inline bool isStrongInteracting(const T& p){return isStrongInteracting(p->pdg_id());}
1194template <> 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
1195
1196#endif
bool isGraviton(const T &p)
Definition AtlasPID.h:407
bool isSMLepton(const T &p)
APID: the fourth generation leptons are not standard model leptons.
Definition AtlasPID.h:208
bool isWeaklyDecayingBHadron(const T &p)
Definition AtlasPID.h:953
static const int GRAVITON
Definition AtlasPID.h:106
static const int HIGGSBOSON
Definition AtlasPID.h:98
static const int ZDBLPRIME
Definition AtlasPID.h:100
static const int CQUARK
Definition AtlasPID.h:75
int numberOfProtons(const T &p)
Definition AtlasPID.h:844
bool isCharm(const T &p)
Definition AtlasPID.h:193
bool hasStrange(const T &p)
Definition AtlasPID.h:747
static const int TABLESIZE
Definition AtlasPID.h:42
bool isBottomBaryon(const T &p)
Definition AtlasPID.h:946
static const int PHOTON
Definition AtlasPID.h:95
static const int TQUARK
Definition AtlasPID.h:77
double spin(const T &p)
Definition AtlasPID.h:1162
bool isBottomMeson(const T &p)
Definition AtlasPID.h:930
static const int K0
Definition AtlasPID.h:123
static const int TAU
Definition AtlasPID.h:87
static const int LEAD
Definition AtlasPID.h:149
bool isTau(const T &p)
Definition AtlasPID.h:222
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:572
bool isElectron(const T &p)
Definition AtlasPID.h:216
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:379
bool isBottom(const T &p)
Definition AtlasPID.h:196
static const int K0L
Definition AtlasPID.h:120
static const int MAVTOP
Definition AtlasPID.h:115
static const int ARGON
Definition AtlasPID.h:153
static const int BCPLUS
Definition AtlasPID.h:131
bool isStrange(const T &p)
Definition AtlasPID.h:190
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:546
bool isRBaryon(const T &p)
Definition AtlasPID.h:599
bool isSleptonLH(const T &p)
Definition AtlasPID.h:498
bool isSlepton(const T &p)
Definition AtlasPID.h:492
int strangeness(const T &p)
Definition AtlasPID.h:797
bool isTransportable(const T &p)
Definition AtlasPID.h:884
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:352
static const int NEUTRON
Definition AtlasPID.h:133
static const std::array< int, 10 > is_strange
Definition AtlasPID.h:795
static const std::array< int, TABLESIZE > triple_charge
Definition AtlasPID.h:43
static const int PIMINUS
Definition AtlasPID.h:118
bool isChLepton(const T &p)
APID: the fourth generation leptons are leptons.
Definition AtlasPID.h:213
bool hasTop(const T &p)
Definition AtlasPID.h:750
double baryonNumber(const T &p)
Definition AtlasPID.h:784
static const int REGGEON
Definition AtlasPID.h:165
static const int RH_NU_MU
Definition AtlasPID.h:145
static const int ELECTRON
Definition AtlasPID.h:82
static const int HIGGSPLUS
Definition AtlasPID.h:104
bool isStrangeHadron(const T &p)
Definition AtlasPID.h:921
bool isGluon(const T &p)
Definition AtlasPID.h:383
static const int BQUARK
Definition AtlasPID.h:76
int charge3(const T &p)
Definition AtlasPID.h:1006
double fractionalCharge(const T &p)
Definition AtlasPID.h:1007
static const int ZPRIME
Definition AtlasPID.h:99
static const int DQUARK
Definition AtlasPID.h:72
bool isLepton(const T &p)
APID: the fourth generation leptons are leptons.
Definition AtlasPID.h:203
bool isHiggs(const T &p)
APID: HIGGS boson is only one particle.
Definition AtlasPID.h:400
int numberOfLambdas(const T &p)
Definition AtlasPID.h:835
bool isLightBaryon(const T &p)
Definition AtlasPID.h:942
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:163
static const int ODDERON
Definition AtlasPID.h:164
bool isQuarkonium(const T &p)
APID states with s,sbar are not considered quarkonium.
Definition AtlasPID.h:283
bool isTopMeson(const T &p)
Definition AtlasPID.h:931
bool hasQuark(const T &p, const int &q)
static const int HIGGS3
Definition AtlasPID.h:103
static const int PIPLUS
Definition AtlasPID.h:117
bool isGaugino(const T &p)
Definition AtlasPID.h:514
bool isHeavyBoson(const T &p)
APID: Additional "Heavy"/"prime" versions of W and Z bosons (Used in MCTruthClassifier).
Definition AtlasPID.h:396
bool isTetraquark(const T &p)
PDG rule 14 The 9-digit tetra-quark codes are ±1nrnLnq1nq20nq3nq4nJ.
Definition AtlasPID.h:335
static const int WBOSON_LRSM
Definition AtlasPID.h:147
bool isCharged(const T &p)
Definition AtlasPID.h:1015
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:655
bool isHeavyMeson(const T &p)
Definition AtlasPID.h:927
bool isSMQuark(const T &p)
Definition AtlasPID.h:186
bool isFourthGeneration(const T &p)
Is this a 4th generation fermion?
Definition AtlasPID.h:234
static const int QUARK_LIMIT
Definition AtlasPID.h:80
bool isSuperpartner(const T &p)
Definition AtlasPID.h:522
bool isW(const T &p)
Definition AtlasPID.h:392
static const int POSITRON
Definition AtlasPID.h:83
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:678
bool hasBottom(const T &p)
Definition AtlasPID.h:749
constexpr std::array< int, 9 > MAX_DIGIT
Definition AtlasPID.h:18
static const int BPRIME
Definition AtlasPID.h:78
static const int K0S
Definition AtlasPID.h:122
static const int KRYPTON
Definition AtlasPID.h:151
bool isSquarkLH(const T &p)
Definition AtlasPID.h:476
static const int LEPTOQUARK
Definition AtlasPID.h:108
bool isGlueball(const T &p)
APID: Definition of Glueballs: SM glueballs 99X (X=1,5), 999Y (Y=3,7).
Definition AtlasPID.h:451
bool isLightHadron(const T &p)
Definition AtlasPID.h:919
static const int OXYGEN
Definition AtlasPID.h:156
static const int NUPRIME
Definition AtlasPID.h:90
bool isTechnicolor(const T &p)
PDG rule 11e Technicolor states have n = 3, with technifermions treated like ordinary fermions.
Definition AtlasPID.h:534
static const int NEON
Definition AtlasPID.h:155
double charge(const T &p)
Definition AtlasPID.h:1008
static const int DPLUS
Definition AtlasPID.h:125
bool isResonance(const T &p)
Definition AtlasPID.h:410
static const int UQUARK
Definition AtlasPID.h:73
bool isStrongInteracting(const T &p)
Definition AtlasPID.h:1193
bool isParton(const T &p)
Definition AtlasPID.h:1118
bool isCCbarMeson(const T &p)
Definition AtlasPID.h:933
static const int DSTAR
Definition AtlasPID.h:126
int baryonNumber3(const T &p)
Definition AtlasPID.h:759
static const int MAGNESIUM
Definition AtlasPID.h:154
static const int PROTON
Definition AtlasPID.h:132
constexpr bool hasAllowedNumberOfDigits(int p, Ns... digits)
Definition AtlasPID.h:20
static const int TPRIME
Definition AtlasPID.h:79
static const int NU_E
Definition AtlasPID.h:84
bool isBBbarMeson(const T &p)
Definition AtlasPID.h:937
bool isTopHadron(const T &p)
Definition AtlasPID.h:924
bool isEMInteracting(const T &p)
Definition AtlasPID.h:1115
bool isStrangeBaryon(const T &p)
Definition AtlasPID.h:944
static const int RH_NU_E
PDG Rule 12: Generator defined PDG ID values for right handed neutrinos and corresponding W+ boson fr...
Definition AtlasPID.h:144
bool hasCharm(const T &p)
Definition AtlasPID.h:748
bool isSleptonRH(const T &p)
Definition AtlasPID.h:506
static const int LAMBDAB0
Definition AtlasPID.h:136
bool isBottomHadron(const T &p)
Definition AtlasPID.h:923
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:181
std::vector< int > containedQuarks(const T &p)
Definition AtlasPID.h:1168
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:258
static const int Z0BOSON
Definition AtlasPID.h:96
static const int GEANTINOPLUS
PDG rule 10: Codes 81–100 are reserved for generator-specific pseudoparticles and concepts.
Definition AtlasPID.h:172
static const int SQUARK
Definition AtlasPID.h:74
bool isGeantino(const T &p)
Definition AtlasPID.h:447
bool isZ(const T &p)
Definition AtlasPID.h:389
static const int CALCIUM
Definition AtlasPID.h:152
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:241
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:694
bool isNeutrino(const T &p)
APID: the fourth generation neutrinos are neutrinos.
Definition AtlasPID.h:226
static const int DSPLUS
Definition AtlasPID.h:128
static const int PI0
Definition AtlasPID.h:119
static const int WPLUSPRIME
Definition AtlasPID.h:101
bool isRMeson(const T &p)
Definition AtlasPID.h:584
static const int GEANTINO0
Definition AtlasPID.h:173
static const int PSI2S
Definition AtlasPID.h:137
static const int BORON
Definition AtlasPID.h:157
static const int INDIUM
Definition AtlasPID.h:150
bool isTop(const T &p)
Definition AtlasPID.h:199
static const int GLUON
Definition AtlasPID.h:92
static const int COMPOSITEGLUON
Definition AtlasPID.h:94
static const int NU_MU
Definition AtlasPID.h:86
bool isSUSY(const T &p)
Definition AtlasPID.h:633
bool isCharmBaryon(const T &p)
Definition AtlasPID.h:945
static const int HIGGS2
Definition AtlasPID.h:102
static const int HELIUM
Definition AtlasPID.h:158
bool isSquarkRH(const T &p)
Definition AtlasPID.h:484
bool isPhoton(const T &p)
Definition AtlasPID.h:386
bool isHeavyBaryon(const T &p)
Definition AtlasPID.h:943
static const int RH_NU_TAU
Definition AtlasPID.h:146
double threeCharge(const T &p)
Definition AtlasPID.h:1014
bool isKK(const T &p)
PDG rule 11h A black hole in models with extra dimensions has code 5000040.
Definition AtlasPID.h:645
bool isCharmMeson(const T &p)
Definition AtlasPID.h:929
bool isNeutrinoRH(const T &p)
PDG Rule 12: APID: Helper function for right-handed neutrino states These are generator defined PDG I...
Definition AtlasPID.h:430
bool isBaryon(const T &p)
Table 43.2 APID: states with fourth generation quarks are not baryons.
Definition AtlasPID.h:292
static const int LAMBDA0
Definition AtlasPID.h:134
bool hasSquark(const T &p, const int &q)
Definition AtlasPID.h:620
int leadingQuark(const T &p)
Definition AtlasPID.h:900
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:418
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:130
bool isNucleus(const T &p)
PDG rule 16 Nuclear codes are given as 10-digit numbers ±10LZZZAAAI.
Definition AtlasPID.h:712
static const int LAMBDACPLUS
Definition AtlasPID.h:135
bool isSMNeutrino(const T &p)
Definition AtlasPID.h:229
bool isMSSMHiggs(const T &p)
APID: Additional Higgs bosons for MSSM (Used in MCTruthClassifier).
Definition AtlasPID.h:404
bool isSquark(const T &p)
PDG rule 11d Fundamental supersymmetric particles are identified by adding a nonzero n to the particl...
Definition AtlasPID.h:468
bool isTopBaryon(const T &p)
Definition AtlasPID.h:947
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:369
static const int KPLUS
Definition AtlasPID.h:124
static const int WPLUSBOSON
Definition AtlasPID.h:97
static const int HIGGSPLUSPLUS
Definition AtlasPID.h:105
static const int LPRIME
Definition AtlasPID.h:89
static const int DARKPHOTON
PDG Ids for Mavtop madgraph UFO model found under DarkX.
Definition AtlasPID.h:114
static const int JPSI
Definition AtlasPID.h:129
bool isCharmHadron(const T &p)
Definition AtlasPID.h:922
bool isRHadron(const T &p)
Definition AtlasPID.h:613
static const int NU_TAU
Definition AtlasPID.h:88
bool isHadron(const T &p)
Definition AtlasPID.h:361
bool isMuon(const T &p)
Definition AtlasPID.h:219
bool isLightMeson(const T &p)
Definition AtlasPID.h:926
bool isStrangeMeson(const T &p)
Definition AtlasPID.h:928
bool isHeavyHadron(const T &p)
Definition AtlasPID.h:920
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:435
bool isBSM(const T &p)
APID: graviton and all Higgs extensions are BSM.
Definition AtlasPID.h:857
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:668
bool isPythia8Specific(const T &p)
Definition AtlasPID.h:421
bool isNeutral(const T &p)
Definition AtlasPID.h:1100
static const std::array< int, TABLESIZE > double_spin
Definition AtlasPID.h:58
int spin2(const T &p)
Definition AtlasPID.h:1122
bool isWeaklyDecayingCHadron(const T &p)
Definition AtlasPID.h:988
static const int HIGGS4
Definition AtlasPID.h:107
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