File indexing completed on 2025-12-16 09:23:02
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Definitions/ParticleData.hpp"
0010 #include "Acts/Definitions/PdgParticle.hpp"
0011 #include "Acts/Utilities/MathHelpers.hpp"
0012
0013 #include <algorithm>
0014 #include <array>
0015 #include <cmath>
0016 #include <ostream>
0017 #include <ranges>
0018 #include <utility>
0019 #include <vector>
0020
0021
0022
0023
0024
0025
0026
0027 namespace Acts {
0028 namespace {
0029
0030 class DecodedPID : public std::pair<int, std::vector<int>> {
0031 public:
0032 explicit DecodedPID(const int& p) {
0033 this->first = p;
0034 this->second.reserve(10);
0035 int ap = std::abs(p);
0036 for (; ap != 0; ap /= 10) {
0037 this->second.push_back(ap % 10);
0038 }
0039 std::ranges::reverse(this->second);
0040 }
0041 inline DecodedPID shift(const std::size_t n) const {
0042 return DecodedPID(this->first %
0043 static_cast<int>(std::pow(10, ndigits() - n)));
0044 }
0045 inline const int& operator()(const std::size_t n) const {
0046 return this->second.at(n);
0047 }
0048 inline const int& last() const { return this->second.back(); }
0049 inline const int& pid() const { return this->first; }
0050 inline int max_digit(const int m, const int n) const {
0051 return *std::max_element(second.rbegin() + m, second.rbegin() + n);
0052 }
0053 inline int min_digit(const int m, const int n) const {
0054 return *std::min_element(second.rbegin() + m, second.rbegin() + n);
0055 }
0056 inline std::size_t ndigits() const { return this->second.size(); }
0057 };
0058
0059 const int TABLESIZE = 100;
0060 const std::array<int, TABLESIZE> triple_charge = {
0061 +0, -1, +2, -1, +2, -1, +2, -1, +2, +0, +0, -3, +0, -3, +0, -3, +0,
0062 -3, +0, +0, +0, +0, +0, +0, +3, +0, +0, +0, +0, +0, +0, +0, +0, +0,
0063 +3, +0, +0, +3, +6, +0, +0, +0, -1, +0, +0, +0, +0, +0, +0, +0, +0,
0064 +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
0065 +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
0066 +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0};
0067
0068 const int DQUARK = 1;
0069 const int UQUARK = 2;
0070 const int SQUARK = 3;
0071 const int CQUARK = 4;
0072 const int BQUARK = 5;
0073 const int TQUARK = 6;
0074
0075 const int ELECTRON = 11;
0076 const int MUON = 13;
0077 const int TAU = 15;
0078
0079 const int GLUON = 21;
0080
0081
0082 const int COMPOSITEGLUON = 9;
0083 const int PHOTON = 22;
0084 const int Z0BOSON = 23;
0085 const int ZPRIME = 32;
0086 const int ZDBLPRIME = 33;
0087 const int LEPTOQUARK = 42;
0088
0089
0090
0091
0092
0093 const int MAVTOP = 60001;
0094
0095 const int K0L = 130;
0096
0097 const int K0S = 310;
0098 const int K0 = 311;
0099 const int PROTON = 2212;
0100
0101
0102
0103
0104
0105
0106
0107 const int GEANTINOPLUS = 998;
0108 const int GEANTINO0 = 999;
0109
0110
0111
0112
0113
0114
0115 bool isQuark(int p) {
0116 return p != 0 && (std::abs(p) <= 8 || std::abs(p) == MAVTOP);
0117 }
0118
0119 bool isSMQuark(int p) {
0120 return p != 0 && std::abs(p) <= TQUARK;
0121 }
0122
0123
0124
0125
0126 bool isDiquark(const DecodedPID& p) {
0127 if (p.ndigits() == 4 && p(0) >= p(1) && p(2) == 0 && p.last() % 2 == 1 &&
0128 p.max_digit(2, 4) <= TQUARK) {
0129 return true;
0130 }
0131 return false;
0132 }
0133
0134
0135
0136
0137
0138
0139
0140
0141 bool isMeson(const DecodedPID& p) {
0142 if (p.ndigits() < 3) {
0143 return false;
0144 }
0145 if (p.ndigits() == 7 && (p(0) == 1 || p(0) == 2)) {
0146 return false;
0147 }
0148 if (std::abs(p.pid()) == K0S) {
0149 return true;
0150 }
0151 if (std::abs(p.pid()) == K0L) {
0152 return true;
0153 }
0154 if (std::abs(p.pid()) == K0) {
0155 return true;
0156 }
0157 if (p.last() % 2 != 1) {
0158 return false;
0159 }
0160 if (p.max_digit(1, 3) >= 6) {
0161 return false;
0162 }
0163 if (p.max_digit(1, 3) == 0) {
0164 return false;
0165 }
0166 if (p.ndigits() > 3 && *(p.second.rbegin() + 3) != 0) {
0167 return false;
0168 }
0169
0170 if (p.ndigits() == 3 && p(0) == p(1) && p.pid() < 0) {
0171 return false;
0172 }
0173 if (p.ndigits() == 5 && p(2) == p(3) && p.pid() < 0) {
0174 return false;
0175 }
0176 if (p.ndigits() == 7 && p(4) == p(5) && p.pid() < 0) {
0177 return false;
0178 }
0179
0180 if (p.ndigits() == 3 && p(0) >= p(1) && p(1) != 0) {
0181 return true;
0182 }
0183 if (p.ndigits() == 5 && p(2) >= p(3) && p(3) != 0 && p(0) == 1 && p(1) == 0) {
0184 return true;
0185 }
0186 if (p.ndigits() == 5 && p(2) >= p(3) && p(3) != 0 && p(0) == 2 && p(1) == 0 &&
0187 p.last() > 1) {
0188 return true;
0189 }
0190 if (p.ndigits() == 5 && p(2) >= p(3) && p(3) != 0 && p(0) == 3 && p(1) == 0 &&
0191 p.last() > 1) {
0192 return true;
0193 }
0194
0195 if (p.ndigits() == 6 && p(3) >= p(4) && p(4) != 0 && p.last() % 2 == 1) {
0196 return true;
0197 }
0198
0199 if (p.ndigits() == 7 && p(0) == 9 && p(1) == 0 && p(4) >= p(5) && p(5) != 0) {
0200 return true;
0201 }
0202
0203 return false;
0204 }
0205
0206
0207 bool isBaryon(const DecodedPID& p) {
0208 if (p.ndigits() < 4) {
0209 return false;
0210 }
0211 if (p.max_digit(1, 4) >= 6) {
0212 return false;
0213 }
0214 if (p.min_digit(1, 4) == 0) {
0215 return false;
0216 }
0217 if (p.ndigits() == 4 &&
0218 (p.last() == 2 || p.last() == 4 || p.last() == 6 || p.last() == 8)) {
0219 return true;
0220 }
0221
0222 if (p.ndigits() == 5 && p(0) == 1 && (p.last() == 2 || p.last() == 4)) {
0223 return true;
0224 }
0225 if (p.ndigits() == 5 && p(0) == 3 && (p.last() == 2 || p.last() == 4)) {
0226 return true;
0227 }
0228
0229 if (p.ndigits() == 6) {
0230 if (p(0) == 1 && p(1) == 0 && p.last() == 2) {
0231 return true;
0232 }
0233 if (p(0) == 1 && p(1) == 1 && p.last() == 2) {
0234 return true;
0235 }
0236 if (p(0) == 1 && p(1) == 2 && p.last() == 4) {
0237 return true;
0238 }
0239
0240 if (p(0) == 2 && p(1) == 0 && p.last() == 2) {
0241 return true;
0242 }
0243 if (p(0) == 2 && p(1) == 0 && p.last() == 4) {
0244 return true;
0245 }
0246 if (p(0) == 2 && p(1) == 1 && p.last() == 2) {
0247 return true;
0248 }
0249
0250 if (p(0) == 1 && p(1) == 0 && p.last() == 4) {
0251 return true;
0252 }
0253 if (p(0) == 1 && p(1) == 0 && p.last() == 6) {
0254 return true;
0255 }
0256 if (p(0) == 2 && p(1) == 0 && p.last() == 6) {
0257 return true;
0258 }
0259 if (p(0) == 2 && p(1) == 0 && p.last() == 8) {
0260 return true;
0261 }
0262 }
0263
0264 if (p.ndigits() == 5) {
0265 if (p(0) == 2 && p.last() == 2) {
0266 return true;
0267 }
0268 if (p(0) == 2 && p.last() == 4) {
0269 return true;
0270 }
0271 if (p(0) == 2 && p.last() == 6) {
0272 return true;
0273 }
0274 if (p(0) == 5 && p.last() == 2) {
0275 return true;
0276 }
0277 if (p(0) == 1 && p.last() == 6) {
0278 return true;
0279 }
0280 if (p(0) == 4 && p.last() == 2) {
0281 return true;
0282 }
0283 }
0284 return false;
0285 }
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297 bool isTetraquark(const DecodedPID& p) {
0298 return (p.ndigits() == 9 && p(0) == 1 && p(5) == 0 &&
0299 p.max_digit(1, 3) <= 6 && p.min_digit(1, 3) > 0 &&
0300 p.max_digit(1 + 3, 3 + 3) <= 6 && p.min_digit(1 + 3, 3 + 3) > 0 &&
0301 (p(3) >= p(4) && p(6) >= p(7)) &&
0302 ((p(3) > p(6)) || (p(3) == p(6) && (p(4) >= p(7)))));
0303 }
0304
0305
0306
0307
0308
0309
0310
0311 bool isPentaquark(const DecodedPID& p) {
0312 return (p.ndigits() == 9 && p(0) == 1 && p.max_digit(1, 6) <= 6 &&
0313 p.min_digit(1, 6) > 0 &&
0314 (p(3) >= p(4) && p(4) >= p(5) && p(5) >= p(6)));
0315 }
0316
0317
0318 bool isHadron(const DecodedPID& p) {
0319 return isMeson(p) || isBaryon(p) || isTetraquark(p) || isPentaquark(p);
0320 }
0321
0322
0323
0324
0325
0326
0327
0328
0329 bool isGluon(int p) {
0330 return p == GLUON;
0331 }
0332
0333 bool isPhoton(int p) {
0334 return p == PHOTON;
0335 }
0336
0337 bool isZ(int p) {
0338 return p == Z0BOSON;
0339 }
0340
0341
0342
0343
0344
0345
0346
0347 bool isLeptoQuark(int p) {
0348 return std::abs(p) == LEPTOQUARK;
0349 }
0350
0351
0352
0353
0354 bool isGenSpecific(int p) {
0355 if (p >= 81 && p <= 100) {
0356 return true;
0357 }
0358 if (p >= 901 && p <= 930) {
0359 return true;
0360 }
0361 if (p >= 998 && p <= 999) {
0362 return true;
0363 }
0364 if (p >= 1901 && p <= 1930) {
0365 return true;
0366 }
0367 if (p >= 2901 && p <= 2930) {
0368 return true;
0369 }
0370 if (p >= 3901 && p <= 3930) {
0371 return true;
0372 }
0373 return false;
0374 }
0375
0376 bool isGeantino(int p) {
0377 return (std::abs(p) == GEANTINO0 || std::abs(p) == GEANTINOPLUS);
0378 }
0379
0380
0381 bool isGlueball(const DecodedPID& p) {
0382 if (p.ndigits() > 4) {
0383 return false;
0384 }
0385 return ((p.ndigits() == 3 && p(0) == COMPOSITEGLUON &&
0386 p(1) == COMPOSITEGLUON && (p(2) == 1 || p(2) == 5)) ||
0387 (p.ndigits() == 4 && p(0) == COMPOSITEGLUON &&
0388 p(1) == COMPOSITEGLUON && p(2) == COMPOSITEGLUON &&
0389 (p(3) == 3 || p(3) == 7)));
0390 }
0391
0392
0393
0394
0395
0396
0397
0398
0399 bool isSUSY(const DecodedPID& p) {
0400 return (p.ndigits() == 7 && (p(0) == 1 || p(0) == 2) &&
0401 !isGenSpecific(p.shift(2).pid()));
0402 }
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429 bool isRGlueball(const DecodedPID& p) {
0430 if (p.ndigits() != 7 || p(0) != 1) {
0431 return false;
0432 }
0433 auto pp = p.shift(1);
0434 return ((pp.ndigits() == 3 && pp(0) == COMPOSITEGLUON &&
0435 pp(1) == COMPOSITEGLUON && (pp(2) == 1 || pp(2) == 3)) ||
0436 (pp.ndigits() == 4 && pp(0) == COMPOSITEGLUON &&
0437 pp(1) == COMPOSITEGLUON && pp(2) == COMPOSITEGLUON &&
0438 (pp(3) == 1 || pp(3) == 5)));
0439 }
0440
0441
0442
0443
0444 bool isRMeson(const DecodedPID& p) {
0445 if (!(p.ndigits() == 7 && (p(0) == 1 || p(0) == 2))) {
0446 return false;
0447 }
0448 auto pp = p.shift(1);
0449 return (
0450
0451 (pp.ndigits() == 4 && pp(0) == COMPOSITEGLUON &&
0452 pp.max_digit(1, 3) < COMPOSITEGLUON && pp(2) <= pp(1) &&
0453 isSMQuark(pp(1)) && isSMQuark(pp(2)) &&
0454 (pp.last() == 1 || pp.last() == 3)) ||
0455
0456 (pp.ndigits() == 3 && pp.max_digit(1, 3) < COMPOSITEGLUON &&
0457 pp(1) <= pp(0) && isSMQuark(pp(0)) && isSMQuark(pp(1)) &&
0458 pp.last() == 2));
0459 }
0460
0461
0462
0463
0464
0465 bool isRBaryon(const DecodedPID& p) {
0466 if (!(p.ndigits() == 7 && (p(0) == 1 || p(0) == 2))) {
0467 return false;
0468 }
0469 auto pp = p.shift(1);
0470 return (
0471
0472 (pp.ndigits() == 5 && pp(0) == COMPOSITEGLUON &&
0473 pp.max_digit(1, 4) < COMPOSITEGLUON && pp(2) <= pp(1) &&
0474 pp(3) <= pp(2) && isSMQuark(pp(1)) && isSMQuark(pp(2)) &&
0475 isSMQuark(pp(3)) && (pp.last() == 2 || pp.last() == 4)) ||
0476
0477 (pp.ndigits() == 4 && pp.max_digit(1, 4) < COMPOSITEGLUON &&
0478 pp(1) <= pp(0) && pp(2) <= pp(1) && isSMQuark(pp(0)) &&
0479 isSMQuark(pp(1)) && isSMQuark(pp(2)) &&
0480 (pp.last() == 1 || pp.last() == 3)));
0481 }
0482
0483
0484
0485
0486
0487
0488
0489
0490 bool isMonopole(const DecodedPID& p) {
0491 return (p.ndigits() == 7 && p(0) == 4 && p(1) == 1 &&
0492 (p(2) == 1 || p(2) == 2) && p(6) == 0);
0493 }
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504 bool isGenericMultichargedParticle(const DecodedPID& p) {
0505 return (p.ndigits() == 8 && (p(0) == 1 || p(0) == 2) && p(1) == 0 &&
0506 p(2) == 0 && p(7) == 0);
0507 }
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523 bool isNucleus(const DecodedPID& p) {
0524 if (std::abs(p.pid()) == PROTON) {
0525 return true;
0526 }
0527 return (p.ndigits() == 10 && p(0) == 1 && p(1) == 0);
0528 }
0529
0530 int numberOfProtons(const DecodedPID& p) {
0531 if (std::abs(p.pid()) == PROTON) {
0532 return (p.pid() > 0) ? 1 : -1;
0533 }
0534 if (isNucleus(p)) {
0535 const int result = p(5) + 10 * p(4) + 100 * p(3);
0536 return (p.pid() > 0) ? result : -result;
0537 }
0538 return 0;
0539 }
0540
0541 inline int leadingQuark(const DecodedPID& p) {
0542 if (isQuark(p.pid())) {
0543 return std::abs(p.pid());
0544 }
0545 if (isMeson(p)) {
0546 return p.max_digit(1, 3);
0547 }
0548 if (isDiquark(p)) {
0549 return p.max_digit(2, 4);
0550 }
0551 if (isBaryon(p)) {
0552 return p.max_digit(1, 4);
0553 }
0554 if (isTetraquark(p)) {
0555 return p.max_digit(1, 5);
0556 }
0557 if (isPentaquark(p)) {
0558 return p.max_digit(1, 6);
0559 }
0560 if (isSUSY(p)) {
0561 auto pp = p.shift(1);
0562 if (pp.ndigits() == 1) {
0563 return 0;
0564 }
0565 if (pp.ndigits() == 3) {
0566 pp = DecodedPID(pp(1));
0567 }
0568 if (pp.ndigits() > 3) {
0569 pp = pp.shift(1);
0570 }
0571 return leadingQuark(pp);
0572 }
0573 return 0;
0574 }
0575
0576 bool isLightMeson(const DecodedPID& p) {
0577 auto lq = leadingQuark(p);
0578 return (lq == DQUARK || lq == UQUARK || lq == SQUARK) && isMeson(p);
0579 }
0580
0581 bool isStrangeMeson(const DecodedPID& p) {
0582 return leadingQuark(p) == SQUARK && isMeson(p);
0583 }
0584
0585 bool isCharmMeson(const DecodedPID& p) {
0586 return leadingQuark(p) == CQUARK && isMeson(p);
0587 }
0588
0589 bool isBottomMeson(const DecodedPID& p) {
0590 return leadingQuark(p) == BQUARK && isMeson(p);
0591 }
0592
0593 inline bool isCCbarMeson(const DecodedPID& p) {
0594 return leadingQuark(p) == CQUARK && isMeson(p) &&
0595 (*(p.second.rbegin() + 2)) == CQUARK &&
0596 (*(p.second.rbegin() + 1)) == CQUARK;
0597 }
0598
0599 inline bool isBBbarMeson(const DecodedPID& p) {
0600 return leadingQuark(p) == BQUARK && isMeson(p) &&
0601 (*(p.second.rbegin() + 2)) == BQUARK &&
0602 (*(p.second.rbegin() + 1)) == BQUARK;
0603 }
0604
0605 bool isLightBaryon(const DecodedPID& p) {
0606 auto lq = leadingQuark(p);
0607 return (lq == DQUARK || lq == UQUARK || lq == SQUARK) && isBaryon(p);
0608 }
0609
0610 bool isStrangeBaryon(const DecodedPID& p) {
0611 return leadingQuark(p) == SQUARK && isBaryon(p);
0612 }
0613
0614 bool isCharmBaryon(const DecodedPID& p) {
0615 return leadingQuark(p) == CQUARK && isBaryon(p);
0616 }
0617
0618 bool isBottomBaryon(const DecodedPID& p) {
0619 return leadingQuark(p) == BQUARK && isBaryon(p);
0620 }
0621
0622 double fractionalCharge(const DecodedPID& p);
0623 int charge3(const DecodedPID& p);
0624
0625 double charge(const DecodedPID& p) {
0626 if (isGenericMultichargedParticle(
0627 p)) {
0628
0629 return fractionalCharge(p);
0630 } else {
0631 return 1.0 * charge3(p) / 3.0;
0632 }
0633 }
0634
0635 int charge3(const DecodedPID& p) {
0636 auto ap = std::abs(p.pid());
0637 if (ap < TABLESIZE) {
0638 return copySign(triple_charge.at(ap), p.pid());
0639 }
0640 if (ap == K0) {
0641 return 0;
0642 }
0643 if (ap == GEANTINO0) {
0644 return 0;
0645 }
0646 if (ap == GEANTINOPLUS) {
0647 return copySign(3, p.pid());
0648 }
0649 if (ap == MAVTOP) {
0650 return copySign(2, p.pid());
0651 }
0652 std::size_t nq = 0;
0653 int sign = 1;
0654 int signmult = 1;
0655 int result = 0;
0656 bool classified = false;
0657 if (!classified && isMeson(p)) {
0658 classified = true;
0659 nq = 2;
0660 if ((*(p.second.rbegin() + 2)) == 2 || (*(p.second.rbegin() + 2)) == 4) {
0661 sign = -1;
0662 }
0663 signmult = -1;
0664 }
0665 if (!classified && isDiquark(p)) {
0666 return triple_charge.at(p(0)) + triple_charge.at(p(1));
0667 }
0668 if (!classified && isBaryon(p)) {
0669 classified = true;
0670 nq = 3;
0671 }
0672 if (!classified && isTetraquark(p)) {
0673 return triple_charge.at(p(3)) + triple_charge.at(p(4)) -
0674 triple_charge.at(p(6)) - triple_charge.at(p(7));
0675 }
0676 if (!classified && isPentaquark(p)) {
0677 return triple_charge.at(p(3)) + triple_charge.at(p(4)) +
0678 triple_charge.at(p(5)) + triple_charge.at(p(6)) -
0679 triple_charge.at(p(7));
0680 }
0681 if (!classified && isNucleus(p)) {
0682 return 3 * numberOfProtons(p);
0683 }
0684 if (!classified && isSUSY(p)) {
0685 nq = 0;
0686 auto pp = p.shift(1);
0687 if (pp.ndigits() < 3) {
0688 return charge3(pp);
0689 }
0690 if (pp(0) == COMPOSITEGLUON) {
0691 if (pp(1) == COMPOSITEGLUON) {
0692 return 0;
0693 }
0694 if (pp.ndigits() == 4 || pp.ndigits() == 5) {
0695 pp = pp.shift(1);
0696 }
0697 }
0698 if (pp.ndigits() == 3) {
0699 classified = true;
0700 nq = 2;
0701 if (p.last() % 2 == 0) {
0702 sign = -1;
0703 }
0704 signmult = -1;
0705 }
0706 if (pp.ndigits() == 4) {
0707 classified = true;
0708 nq = 3;
0709 }
0710 }
0711 if (!classified && isMonopole(p)) {
0712
0713
0714
0715
0716 result = 3 * (p(3) * 100 + p(4) * 10 + p(5));
0717 return ((p.pid() > 0 && p(2) == 1) || (p.pid() < 0 && p(2) == 2)) ? result
0718 : -result;
0719 }
0720 if (!classified && isGenericMultichargedParticle(p)) {
0721 double abs_charge = 0.0;
0722 if (p(0) == 1) {
0723 abs_charge = p(3) * 100. + p(4) * 10. + p(5) * 1 +
0724 p(6) * 0.1;
0725
0726 }
0727 if (p(0) == 2) {
0728 abs_charge = (p(3) * 10. + p(4)) /
0729 (p(5) * 10.0 + p(6));
0730
0731 }
0732 int abs_threecharge = static_cast<int>(std::round(
0733 abs_charge *
0734 3.));
0735
0736
0737 return copySign(abs_threecharge, p.pid());
0738 }
0739 for (auto r = p.second.rbegin() + 1; r != p.second.rbegin() + 1 + nq; ++r) {
0740 result += triple_charge.at(*r) * sign;
0741 sign *= signmult;
0742 }
0743 return copySign(result, p.pid());
0744 }
0745 double fractionalCharge(const DecodedPID& p) {
0746 if (!isGenericMultichargedParticle(p)) {
0747 return 1.0 * charge3(p) /
0748 3.0;
0749
0750 }
0751 double abs_charge = 0;
0752 if (p(0) == 1) {
0753 abs_charge = p(3) * 100. + p(4) * 10. + p(5) * 1 +
0754 p(6) * 0.1;
0755 }
0756
0757 if (p(0) == 2) {
0758 abs_charge =
0759 (p(3) * 10. + p(4)) /
0760 (p(5) * 10.0 + p(6));
0761 }
0762
0763 return copySign(abs_charge, p.pid());
0764 }
0765
0766
0767 bool isEMInteracting(const DecodedPID& p) {
0768 return (isPhoton(p.pid()) || isZ(p.pid()) || p.pid() == ZPRIME ||
0769 p.pid() == ZDBLPRIME ||
0770 std::abs(charge(p)) > std::numeric_limits<double>::epsilon() ||
0771 isMonopole(p));
0772 }
0773
0774 bool isRHadron(const DecodedPID& p) {
0775 return (isRBaryon(p) || isRMeson(p) || isRGlueball(p));
0776 }
0777
0778 bool isStrongInteracting(const DecodedPID& p) {
0779 return (isGluon(p.pid()) || isQuark(p.pid()) || isDiquark(p) ||
0780 isGlueball(p) || isLeptoQuark(p.pid()) || isHadron(p) ||
0781 isRHadron(p));
0782 }
0783
0784 }
0785
0786
0787 bool ParticleIdHelper::isHadron(PdgParticle pdg) {
0788 DecodedPID p(pdg);
0789 return isMeson(p) || isBaryon(p) || isTetraquark(p) || isPentaquark(p);
0790 }
0791
0792
0793 bool ParticleIdHelper::isLepton(PdgParticle pdg) {
0794 auto sp = std::abs(pdg);
0795 return sp >= 11 && sp <= 18;
0796 }
0797
0798 bool ParticleIdHelper::isMuon(PdgParticle pdg) {
0799 return std::abs(pdg) == MUON;
0800 }
0801
0802 bool ParticleIdHelper::isElectron(PdgParticle pdg) {
0803 return std::abs(pdg) == ELECTRON;
0804 }
0805
0806 bool ParticleIdHelper::isPhoton(PdgParticle pdg) {
0807 return std::abs(pdg) == PHOTON;
0808 }
0809
0810 bool ParticleIdHelper::isTau(PdgParticle pdg) {
0811 return std::abs(pdg) == TAU;
0812 }
0813
0814 HadronType ParticleIdHelper::hadronType(PdgParticle pdg) {
0815 DecodedPID p(pdg);
0816
0817 using enum HadronType;
0818
0819 if (isBBbarMeson(p)) {
0820 return BBbarMeson;
0821 }
0822 if (isCCbarMeson(p)) {
0823 return CCbarMeson;
0824 }
0825 if (isBottomMeson(p)) {
0826 return BottomMeson;
0827 }
0828 if (isCharmMeson(p)) {
0829 return CharmedMeson;
0830 }
0831 if (isBottomBaryon(p)) {
0832 return BottomBaryon;
0833 }
0834 if (isCharmBaryon(p)) {
0835 return CharmedBaryon;
0836 }
0837 if (isStrangeBaryon(p)) {
0838 return StrangeBaryon;
0839 }
0840 if (isLightBaryon(p)) {
0841 return LightBaryon;
0842 }
0843 if (isStrangeMeson(p)) {
0844 return StrangeMeson;
0845 }
0846 if (isLightMeson(p)) {
0847 return LightMeson;
0848 }
0849
0850 return Unknown;
0851 }
0852
0853
0854 bool ParticleIdHelper::isQuark(PdgParticle pdg) {
0855 return pdg != 0 && (std::abs(pdg) <= 8 || std::abs(pdg) == MAVTOP);
0856 }
0857
0858
0859 bool ParticleIdHelper::isInteracting(PdgParticle pdg) {
0860 DecodedPID p(pdg);
0861 return isStrongInteracting(p) || isEMInteracting(p) || isGeantino(pdg);
0862 }
0863
0864 std::ostream& operator<<(std::ostream& os, HadronType hadron) {
0865 switch (hadron) {
0866 using enum HadronType;
0867 case Hadron:
0868 return os << "Hadron";
0869 case BBbarMeson:
0870 return os << "BBbarMeson";
0871 case CCbarMeson:
0872 return os << "CCbarMeson";
0873 case BottomMeson:
0874 return os << "BottomMeson";
0875 case BottomBaryon:
0876 return os << "BottomBaryon";
0877 case CharmedMeson:
0878 return os << "CharmedMeson";
0879 case CharmedBaryon:
0880 return os << "CharmedBaryon";
0881 case StrangeMeson:
0882 return os << "StrangeMeson";
0883 case StrangeBaryon:
0884 return os << "StrangeBaryon";
0885 case LightMeson:
0886 return os << "LightMeson";
0887 case LightBaryon:
0888 return os << "LightBaryon";
0889 case Unknown:
0890 return os << "Unknown";
0891 }
0892 return os;
0893 }
0894
0895 PdgParticle parsePdgParticle(const std::string& name) {
0896 if (name == "e-") {
0897 return eElectron;
0898 } else if (name == "e+") {
0899 return ePositron;
0900 } else if (name == "mu-") {
0901 return eMuon;
0902 } else if (name == "mu+") {
0903 return eAntiMuon;
0904 } else if (name == "tau-") {
0905 return eTau;
0906 } else if (name == "tau+") {
0907 return eAntiTau;
0908 } else if (name == "gamma") {
0909 return eGamma;
0910 } else if (name == "pi0") {
0911 return ePionZero;
0912 } else if (name == "pi+") {
0913 return ePionPlus;
0914 } else if (name == "pi-") {
0915 return ePionMinus;
0916 } else if (name == "K+") {
0917 return eKaonPlus;
0918 } else if (name == "K-") {
0919 return eKaonMinus;
0920 } else if (name == "n") {
0921 return eNeutron;
0922 } else if (name == "n~") {
0923 return eAntiNeutron;
0924 } else if (name == "p") {
0925 return eProton;
0926 } else if (name == "p~") {
0927 return eAntiProton;
0928 } else if (name == "Pb") {
0929 return eLead;
0930 } else {
0931 throw std::invalid_argument("Unknown particle name: " + name);
0932 }
0933 }
0934 }