Rivet API documentation

Rivet 4.1.3
ParticleIdUtils.hh
1// -*- C++ -*-
2//
3// This file is part of MCUtils -- https://gitlab.com/hepcedar/mcutils/
4// Copyright (C) 2013-2025 Andy Buckley <andy.buckley@cern.ch>
5//
6// Embedding of MCUtils code in other projects is permitted provided this
7// notice is retained and the MCUtils namespace and include path are changed.
8//
9#ifndef RIVET_PARTICLEIDUTILS_HH
10#define RIVET_PARTICLEIDUTILS_HH
11
14
15#include "Rivet/Math/MathUtils.hh"
16#include "Rivet/Tools/ParticleName.hh"
17#include <cassert>
18
19namespace Rivet {
20 namespace PID {
21
22
25
28 inline int abspid(int pid) {
29 return abs(pid);
30 }
31
32
33 // /// Compile-time int^int power-raising function
34 // template <size_t N>
35 // inline int _intpow(int x) { return x * _intpow<N-1>(x); }
36 // template <>
37 // inline int _intpow<0>(int x) { return 1; }
38
40 // inline size_t _pow10(unsigned int power) {
41 // return (size_t) std::pow(10.0, power);
42 // }
44 inline size_t _pow10(unsigned int power) {
45 //assert(power >= 0 && "_pow10 only defined for positive powers");
46 assert(power < 16 && "_pow10 only defined for powers < 16");
47 static const size_t POWS10[] = {1,
48 10,
49 100,
50 1000,
51 10000,
52 100000,
53 1000000,
54 10000000,
55 100000000,
56 1000000000,
57 10000000000,
58 100000000000,
59 1000000000000,
60 10000000000000,
61 100000000000000,
62 1000000000000000,
63 10000000000000000};
64 return POWS10[power];
65 }
66 // /// Raise 10 to an integer power (constexpr)
67 // inline constexpr size_t _pow10(unsigned int power) {
68 // assert(power >= 0 && "_pow10 only defined for positive powers");
69 // return (power > 0) ? 10*_pow10(power-1) : 1;
70 // }
71
74 enum Location { nj = 1, nq3, nq2, nq1, nl, nr, n, n8, n9, n10 };
75
81 inline unsigned short _digit(Location loc, int pid) {
82 const int div = _pow10(loc - 1);
83 return (abs(pid) / div) % 10;
84 }
85
87 inline int _extraBits(int pid) {
88 return abs(pid) / 10000000;
89 }
90
93 inline int _fundamentalID(int pid) {
94 if (_extraBits(pid) > 0) return 0;
95 if (_digit(nq2, pid) == 0 && _digit(nq1, pid) == 0) {
96 return abs(pid) % 10000;
97 }
98 else if (abs(pid) <= 100) {
99 return abs(pid);
100 }
101 else {
102 return 0;
103 }
104 }
105
107
108
109 // Forward declaration
110 inline bool isBSM(int pid);
111
112
115
124 inline bool isNucleus(int pid) {
125 // A proton can also be a Hydrogen nucleus
126 if (abs(pid) == 2212) return true;
127 // New standard: +/- 10LZZZAAAI
128 if (_digit(n10, pid) == 1 && _digit(n9, pid) == 0) {
129 // charge should always be less than or equal to baryon number
130 // the following line is A >= Z
131 if ((abs(pid) / 10) % 1000 >= (abs(pid) / 10000) % 1000) return true;
132 }
133 return false;
134 }
135
138 inline int nuclZ(int pid) {
139 // A proton can also be a Hydrogen nucleus
140 if (abs(pid) == 2212) {
141 return 1;
142 }
143 if (isNucleus(pid)) return (abs(pid) / 10000) % 1000;
144 return 0;
145 }
146
147 inline int Z(int pid) {
148 return nuclZ(pid);
149 }
150
153 inline int nuclA(int pid) {
154 // a proton can also be a Hydrogen nucleus
155 if (abs(pid) == 2212) {
156 return 1;
157 }
158 if (isNucleus(pid)) return (abs(pid) / 10) % 1000;
159 return 0;
160 }
161
162 inline int A(int pid) {
163 return nuclA(pid);
164 }
165
168 inline int nuclNlambda(int pid) {
169 // a proton can also be a Hydrogen nucleus
170 if (abs(pid) == 2212) {
171 return 0;
172 }
173 if (isNucleus(pid)) return _digit(n8, pid);
174 return 0;
175 }
176
177 inline int lambda(int pid) {
178 return nuclNlambda(pid);
179 }
180
182
183
186
188 inline bool isQuark(int pid) {
189 return in_closed_range(abs(pid), 1, 8);
190 }
191
193 inline bool isGluon(int pid) {
194 return pid == GLUON;
195 }
196
198 inline bool isParton(int pid) {
199 return isGluon(pid) || isQuark(pid);
200 }
201
202
204 inline bool isPhoton(int pid) {
205 return pid == PHOTON;
206 }
207
209 inline bool isElectron(int pid) {
210 return abs(pid) == ELECTRON;
211 }
212
214 inline bool isMuon(int pid) {
215 return abs(pid) == MUON;
216 }
217
219 inline bool isTau(int pid) {
220 return abs(pid) == TAU;
221 }
222
224 inline bool isChargedLepton(int pid) {
225 const long apid = abs(pid);
226 return apid == 11 || apid == 13 || apid == 15 || apid == 17;
227 }
228
230 inline bool isChLepton(int pid) {
231 return isChargedLepton(pid);
232 }
233
235 inline bool isNeutrino(int pid) {
236 const long apid = abs(pid);
237 return apid == 12 || apid == 14 || apid == 16 || apid == 18;
238 }
239
240
242 inline bool isWplus(int pid) {
243 return pid == WPLUSBOSON;
244 }
245
247 inline bool isWminus(int pid) {
248 return pid == WMINUSBOSON;
249 }
250
252 inline bool isW(int pid) {
253 return abs(pid) == WPLUSBOSON;
254 }
255
257 inline bool isZ(int pid) {
258 return pid == Z0BOSON;
259 }
260
262 inline bool isHiggs(int pid) {
263 return pid == HIGGSBOSON
264 || pid == 26; //< @todo Check on 26 still needed? (used in HERWIG SUSY, for example)
265 }
266
268
269
271 inline bool isGraviton(int pid) {
272 return pid == GRAVITON;
273 }
274
275
276 // /// Determine if the PID is that of a d/dbar
277 // inline bool isDown(int pid) { return abs(pid) == DQUARK; }
278
279 // /// Determine if the PID is that of a u/ubar
280 // inline bool isUp(int pid) { return abs(pid) == UQUARK; }
281
283 inline bool isStrange(int pid) {
284 return abs(pid) == SQUARK;
285 }
286
288 inline bool isCharm(int pid) {
289 return abs(pid) == CQUARK;
290 }
291
293 inline bool isBottom(int pid) {
294 return abs(pid) == BQUARK;
295 }
296
298 inline bool isTop(int pid) {
299 return abs(pid) == TQUARK;
300 }
301
303
304
307
309 inline bool isReggeon(int pid) {
310 return pid == 110 || pid == 990 || pid == 9990;
311 }
312
314 inline bool isMeson(int pid) {
315 if (_extraBits(pid) > 0) return false;
316 if (isBSM(pid)) return false;
317 const int aid = abs(pid);
318 if (aid == 130 || aid == 310 || aid == 210) return true; //< special cases for kaons
319 if (aid <= 100) return false;
320 if (_digit(nq1, pid) != 0) return false;
321 if (_digit(nq2, pid) == 0) return false;
322 if (_digit(nq3, pid) == 0) return false;
323 if (_digit(nq2, pid) < _digit(nq3, pid)) return false;
324 // EvtGen uses some odd numbers
326 if (aid == 150 || aid == 350 || aid == 510 || aid == 530) return true;
327 // Pomeron, Reggeon, etc.
328 if (isReggeon(pid)) return false; //true; //< WTF?
329 // Check for illegal antiparticles
330 if (_digit(nj, pid) > 0 && _digit(nq3, pid) > 0 && _digit(nq2, pid) > 0 && _digit(nq1, pid) == 0) {
331 return !(_digit(nq3, pid) == _digit(nq2, pid) && pid < 0);
332 }
333 return false;
334 }
335
337 inline bool isBaryon(int pid) {
338 if (_extraBits(pid) > 0) return false;
339 if (isBSM(pid)) return false;
340 if (abs(pid) <= 100) return false;
341 if (_fundamentalID(pid) <= 100 && _fundamentalID(pid) > 0) return false;
342 if (abs(pid) == 2110 || abs(pid) == 2210)
343 return true;
344 if (_digit(nj, pid) == 0) return false;
345 if (_digit(nq1, pid) == 0 || _digit(nq2, pid) == 0 || _digit(nq3, pid) == 0) return false;
346 return true;
348 // if ((_digit(nq1,pid) >= _digit(nq2,pid) && _digit(nq2,pid) >= _digit(nq3,pid)) ||
349 // (_digit(nq1,pid) > _digit(nq3,pid) && _digit(nq3,pid) > _digit(nq2,pid)) || //< case 6b for lighter quarks in J=1
350 // (_digit(nq3,pid) > _digit(nq1,pid) && _digit(nq1,pid) > _digit(nq2,pid))) //< case 6e for extra states in excited multiplets
351 // return true;
352 // return false;
353 }
354
355 // Check to see if this is a valid diquark
356 inline bool isDiquark(int pid) {
357 if (_extraBits(pid) > 0) return false;
358 if (isBSM(pid)) return false;
359 if (abs(pid) <= 100) return false;
360 if (_fundamentalID(pid) <= 100 && _fundamentalID(pid) > 0) return false;
361 if (_digit(nq1, pid) == 0) return false;
362 if (_digit(nq2, pid) == 0) return false;
363 if (_digit(nq3, pid) != 0) return false;
364 if (_digit(nq1, pid) < _digit(nq2, pid)) return false;
365 if (_digit(nj, pid) > 0 && _digit(nq3, pid) == 0 && _digit(nq2, pid) > 0 && _digit(nq1, pid) > 0)
366 return true; // diquark signature
367 // EvtGen uses the diquarks for quark pairs, so, for instance, 5501 is a valid "diquark" for EvtGen
368 // if (_digit(nj) == 1 && _digit(nq2) == _digit(nq1)) { // illegal
369 // return false;
370 // } else {
371 // return true;
372 // }
373 return false;
374 }
376 inline bool isDiQuark(int pid) {
377 return isDiquark(pid);
378 }
379
381 inline bool isPentaquark(int pid) {
382 // a pentaquark is of the form 9abcdej,
383 // where j is the spin and a, b, c, d, and e are quarks
384 if (_extraBits(pid) > 0) return false;
385 if (isBSM(pid)) return false;
386 if (_digit(n, pid) != 9) return false;
387 if (_digit(nr, pid) == 9 || _digit(nr, pid) == 0) return false;
388 if (_digit(nj, pid) == 9 || _digit(nl, pid) == 0) return false;
389 if (_digit(nq1, pid) == 0) return false;
390 if (_digit(nq2, pid) == 0) return false;
391 if (_digit(nq3, pid) == 0) return false;
392 if (_digit(nj, pid) == 0) return false;
393 // check ordering
394 if (_digit(nq2, pid) > _digit(nq1, pid)) return false;
395 if (_digit(nq1, pid) > _digit(nl, pid)) return false;
396 if (_digit(nl, pid) > _digit(nr, pid)) return false;
397 return true;
398 }
399
405 inline bool isQuarkonium(int pid) {
406 if (!isMeson(pid)) return false; //< all quarkonia are mesons
407 if (_digit(nq1, pid) != 0) return false;
408 const int fq = _digit(nq2, pid);
409 return (fq > 3 && _digit(nj, pid) > 0 && _digit(nq3, pid) == fq);
410 }
411
415 inline bool isHadron(int pid) {
416 if (_extraBits(pid) > 0) return false;
417 if (isBSM(pid) > 0) return false;
418 if (isMeson(pid)) return true;
419 if (isBaryon(pid)) return true;
420 if (isPentaquark(pid)) return true;
421 return false;
422 }
423
425
426
429
433 inline bool isLepton(int pid) {
434 if (_extraBits(pid) > 0) return false;
435 if (isBSM(pid) > 0) return false;
436 if (_fundamentalID(pid) >= 11 && _fundamentalID(pid) <= 18) return true;
437 return false;
438 }
439
441 inline bool isBSMBoson(int pid) {
442 return in_closed_range(abs(pid), 32, 37);
443 }
444
446 inline bool isSMFundamental(int pid) {
447 return isQuark(pid) || isLepton(pid) || isGluon(pid) || isPhoton(pid) || isW(pid) || isZ(pid)
449 }
450
454 inline bool isSUSY(int pid) {
455 // Fundamental SUSY particles have n = 1 or 2
456 if (_extraBits(pid) > 0) return false;
457 if (_digit(n, pid) != 1 && _digit(n, pid) != 2) return false;
458 if (_digit(nr, pid) != 0) return false;
459 // Check fundamental part for SM PID on which it is based
460 const int fundId = _fundamentalID(pid);
461 if (fundId == 0) return false;
462 if (_digit(n, pid) == 1) { // most superpartners, incl LH sfermions
463 return isSMFundamental(fundId);
464 }
465 else if (_digit(n, pid) == 2) { // RH sfermions
466 return isQuark(fundId) || isChargedLepton(fundId);
467 }
468 return true;
469 }
470
472 inline bool isRHadron(int pid) {
473 // An R-hadron is of the form 10abcdj,
474 // where j is the spin and a, b, c, and d are quarks or gluons
475 if (_extraBits(pid) > 0) return false;
476 if (_digit(n, pid) != 1) return false;
477 if (_digit(nr, pid) != 0) return false;
478 // Make sure this isn't a SUSY particle
479 if (isSUSY(pid)) return false;
480 // All R-hadrons have at least 3 core digits
481 if (_digit(nq2, pid) == 0) return false;
482 if (_digit(nq3, pid) == 0) return false;
483 if (_digit(nj, pid) == 0) return false;
484 return true;
485 }
486
487 inline bool isRhadron(int pid) {
488 return isRHadron(pid);
489 }
490
492 inline bool isTechnicolor(int pid) {
493 if (_extraBits(pid) > 0) return false;
494 return _digit(n, pid) == 3;
495 }
496
498 inline bool isExcited(int pid) {
499 if (_extraBits(pid) > 0) return false;
500 return _digit(n, pid) == 4 && _digit(nr, pid) == 0;
501 }
502
504 inline bool isKK(int pid) {
505 if (_extraBits(pid) > 0) return false;
506 const int ndigit = _digit(n, pid);
507 return ndigit == 5 || ndigit == 6;
508 }
509
511 inline bool isLeptoQuark(int pid) {
512 // Many UFO models are extending the PDG standards... is this going to be official?
513 return abs(pid) == 42;
514 }
515
520 inline bool isDarkMatter(int pid) {
521 const int ndigit = _digit(n, pid);
522 const int nrdigit = _digit(nr, pid);
523 if ((ndigit == 0 && nrdigit == 0) || (ndigit == 5 && nrdigit == 9))
524 return in_closed_range(abs(_fundamentalID(pid)), 50, 60);
525 return false;
526 }
527
528 inline bool isDM(int pid) {
529 return isDarkMatter(pid);
530 }
531
533 inline bool isHiddenValley(int pid) {
534 return (_digit(n, pid) == 4 && _digit(nr, pid) == 9);
535 }
536
538 inline bool isExotic(int pid) {
539 // From the PDG definition, 40-80 reserved for exotic particles
540 // Some overlap with ranges from other functions (e.g. isDM)
541 // Also covers R0 (41)
542 return in_closed_range(abs(pid), 40, 80);
543 }
544
546 inline bool isFourthGen(int pid) {
547 return abs(pid) == BPRIME || abs(pid) == TPRIME || abs(pid) == LPRIME || abs(pid) == NUPRIME;
548 }
549
551 inline bool isMagMonopole(int pid) {
552 if (_digit(n, pid) != 4) return false;
553 if (_digit(nr, pid) != 1) return false;
554 if (_digit(nl, pid) != 1 && _digit(nl, pid) != 2) return false;
555 // Require at least 1 core digit
556 // NOT TRUE! Electrically neutral monopoles are possible
557 // if (_digit(nq3,pid) == 0) return false;
558 // Always have spin zero for now
559 if (_digit(nj, pid) != 0) return false;
560 return true;
561 }
562
563 inline bool isDyon(int pid) {
564 return isMagMonopole(pid);
565 }
566
569 inline bool isQBall(int pid) {
570 if (_extraBits(pid) != 1) return false;
571 if (_digit(n, pid) != 0) return false;
572 if (_digit(nr, pid) != 0) return false;
573 // Check the core number
574 if ((abs(pid) / 10) % 10000 == 0) return false;
575 // These particles have spin zero for now
576 if (_digit(nj, pid) != 0) return false;
577 return true;
578 }
579
580 inline bool isQball(int pid) {
581 return isQBall(pid);
582 }
583
585 inline bool isExcitedLepton(int pid) {
586 if (!isExcited(pid)) return false;
587 return isLepton(_fundamentalID(pid));
588 }
589
591 inline bool isBlackHole(int pid) {
592 if (_digit(n, pid) != 5 && _digit(n, pid) != 6) return false;
593 if (_digit(nl, pid) != 0) return false;
594 return _fundamentalID(pid) == 40;
595 }
596
598 inline bool isAECO(int pid) {
599 if (_digit(n, pid) != 1) return false;
600 if (_digit(nr, pid) != 0) return false;
601 if (_digit(nl, pid) != 0) return false;
602 if (_digit(nj, pid) != 0) return false;
603 return true;
604 }
605
607 inline bool isBSM(int pid) {
608 return isSUSY(pid) || isRHadron(pid) || isTechnicolor(pid) || isExcited(pid) || isKK(pid)
611 || isAECO(pid);
612 }
613
615 inline bool _isValid(int pid) {
616 // Starting with 99 means anything goes (but nothing is known)
617 if (_digit(n, pid) == 9 && _digit(nr, pid) == 9) return true;
618 // Check that extra bits are only used for nuclei
619 if (_extraBits(pid) > 0) return (isNucleus(pid) || isQball(pid));
620 // Check that it fits into a standard non-nucleus convention
621 if (isBSM(pid)) return true;
622 if (isHadron(pid)) return true;
623 if (_digit(n, pid) == 9 && _digit(nr, pid) == 0)
624 return false; // could only have been a tentative hadron, but !isHadron
625 if (isDiquark(pid)) return true;
626 if (isPentaquark(pid)) return true;
627 if (isReggeon(pid)) return true;
628 // // Quark digit orderings required by the standard
629 // if (_digit(nq1,pid) != 0 && _digit(nq1,pid) < _digit(nq2,pid)) return false;
630 // if (_digit(nq2,pid) != 0 && _digit(nq2,pid) < _digit(nq3,pid)) return false;
631 // Final check on fundamental ID
632 return (_fundamentalID(pid) > 0);
633 }
634 inline bool isValid(int pid) {
635 return _isValid(pid);
636 }
637
639
640
643
644 inline bool _hasQ(int pid, int q) {
645 if (abs(pid) == q) return true; //< trivial case!
646 if (!_isValid(pid)) return false;
647 // if (_extraBits(pid) > 0) return false;
648 // if (_fundamentalID(pid) > 0) return false;
649 if (isMagMonopole(pid)) return false;
650 if (isRHadron(pid)) {
651 int iz = 7;
652 for (int i = 6; i > 1; --i) {
653 if (_digit(Location(i), pid) == 0) {
654 iz = i;
655 }
656 else if (i == iz - 1) {
657 // ignore squark or gluino
658 }
659 else {
660 if (_digit(Location(i), pid) == q) return true;
661 }
662 }
663 return false;
664 }
665 if (_digit(nq3, pid) == q || _digit(nq2, pid) == q || _digit(nq1, pid) == q) return true;
666 if (isPentaquark(pid)) {
667 if (_digit(nl, pid) == q || _digit(nr, pid) == q) return true;
668 }
669 return false;
670 }
671
673 inline bool hasDown(int pid) {
674 return (isHadron(pid) || isQuark(pid)) && _hasQ(pid, 1);
675 }
676
677 inline bool hasUp(int pid) {
678 return (isHadron(pid) || isQuark(pid)) && _hasQ(pid, 2);
679 }
680
681 inline bool hasStrange(int pid) {
682 return (isHadron(pid) || isQuark(pid)) && _hasQ(pid, 3);
683 }
684
685 inline bool hasCharm(int pid) {
686 return (isHadron(pid) || isQuark(pid)) && _hasQ(pid, 4);
687 }
688
689 inline bool hasBottom(int pid) {
690 return (isHadron(pid) || isQuark(pid)) && _hasQ(pid, 5);
691 }
692
693 inline bool hasTop(int pid) {
694 return (isHadron(pid) || isQuark(pid)) && _hasQ(pid, 6);
695 }
696
698
699
702
704 inline bool isHeavyFlavor(int pid) {
705 if (!isHadron(pid) && !isQuark(pid)) return false;
706 return hasCharm(pid) || hasBottom(pid) || hasTop(pid);
707 }
708
709 inline bool isHeavyFlavour(int pid) {
710 return isHeavyFlavor(pid);
711 }
712
713
714 // /// Determine if the particle is a light-flavour hadron or parton
715 // inline bool isLightFlavor(int pid) {
716 // return !isHeavyFlavor();
717 // }
718
719
721 inline bool isHeavyParton(int pid) {
722 return isParton(pid) && isHeavyFlavor(pid);
723 }
724
726 inline bool isLightParton(int pid) {
727 return isParton(pid) && !isHeavyFlavor(pid);
728 }
729
730
732 inline bool isHeavyMeson(int pid) {
733 return isMeson(pid) && isHeavyFlavor(pid);
734 }
735
737 inline bool isHeavyBaryon(int pid) {
738 return isBaryon(pid) && isHeavyFlavor(pid);
739 }
740
742 inline bool isHeavyHadron(int pid) {
743 return isHadron(pid) && isHeavyFlavor(pid);
744 }
745
747 inline bool isLightMeson(int pid) {
748 return isMeson(pid) && !isHeavyFlavor(pid);
749 }
750
752 inline bool isLightBaryon(int pid) {
753 return isBaryon(pid) && !isHeavyFlavor(pid);
754 }
755
757 inline bool isLightHadron(int pid) {
758 return isHadron(pid) && !isHeavyFlavor(pid);
759 }
760
761
763 inline bool isBottomMeson(int pid) {
764 return hasBottom(pid) && isMeson(pid);
765 }
766
768 inline bool isBottomBaryon(int pid) {
769 return hasBottom(pid) && isBaryon(pid);
770 }
771
773 inline bool isBottomHadron(int pid) {
774 return hasBottom(pid) && isHadron(pid);
775 }
776
777
782 inline bool isCharmMeson(int pid) {
783 return isMeson(pid) && hasCharm(pid) && !hasBottom(pid);
784 }
785
791 inline bool isCharmBaryon(int pid) {
792 return isBaryon(pid) && hasCharm(pid) && !hasBottom(pid);
793 }
794
800 inline bool isCharmHadron(int pid) {
801 return isHadron(pid) && hasCharm(pid) && !hasBottom(pid);
802 }
803
804
809 inline bool isStrangeMeson(int pid) {
810 return isMeson(pid) && hasStrange(pid) && !(hasBottom(pid) || hasCharm(pid));
811 }
812
817 inline bool isStrangeBaryon(int pid) {
818 return isBaryon(pid) && hasStrange(pid) && !(hasBottom(pid) || hasCharm(pid));
819 }
820
825 inline bool isStrangeHadron(int pid) {
826 return isHadron(pid) && hasStrange(pid) && !(hasBottom(pid) || hasCharm(pid));
827 }
828
830
831
834
836 inline int jSpin(int pid) {
837 const int fund = _fundamentalID(pid);
838 if (fund > 0) {
839 // some of these are known
840 if (fund > 0 && fund < 7) return 2;
841 if (fund == 9) return 3;
842 if (fund > 10 && fund < 17) return 2;
843 if (fund > 20 && fund < 25) return 3;
844 return 0;
845 }
846 else if (_extraBits(pid) > 0) {
847 return 0;
848 }
849 return abs(pid) % 10;
850 }
851
853 inline int sSpin(int pid) {
854 // Handle invalid cases first
855 if (!isMeson(pid)) return 0;
856 if (_digit(n, pid) == 9 && _digit(nr, pid) == 0) return 0; // tentative ID
857 // Special generic DM particles with defined spins
858 const int fund = _fundamentalID(pid);
859 if (fund == 51 || fund == 54) return 1;
860 if (fund == 52) return 2;
861 if (fund == 53 || fund == 55) return 3;
862 // Calculate from nl and nj digits
863 const int inl = _digit(nl, pid);
864 const int js = _digit(nj, pid);
865 if (inl == 0 && js >= 3)
866 return 1;
867 else if (inl == 0 && js == 1)
868 return 0;
869 else if (inl == 1 && js >= 3)
870 return 0;
871 else if (inl == 2 && js >= 3)
872 return 1;
873 else if (inl == 1 && js == 1)
874 return 1;
875 else if (inl == 3 && js >= 3)
876 return 1;
877 // Default to zero
878 return 0;
879 }
880
882 inline int lSpin(int pid) {
883 // Handle invalid cases first
884 if (!isMeson(pid)) return 0;
885 if (_digit(n, pid) == 9 && _digit(nr, pid) == 0) return 0; // tentative ID
886 // Calculate from nl and nj digits
887 const int inl = _digit(nl, pid);
888 const int js = _digit(nj, pid);
889 if (inl == 0 && js == 3)
890 return 0;
891 else if (inl == 0 && js == 5)
892 return 1;
893 else if (inl == 0 && js == 7)
894 return 2;
895 else if (inl == 0 && js == 9)
896 return 3;
897 else if (inl == 0 && js == 1)
898 return 0;
899 else if (inl == 1 && js == 3)
900 return 1;
901 else if (inl == 1 && js == 5)
902 return 2;
903 else if (inl == 1 && js == 7)
904 return 3;
905 else if (inl == 1 && js == 9)
906 return 4;
907 else if (inl == 2 && js == 3)
908 return 1;
909 else if (inl == 2 && js == 5)
910 return 2;
911 else if (inl == 2 && js == 7)
912 return 3;
913 else if (inl == 2 && js == 9)
914 return 4;
915 else if (inl == 1 && js == 1)
916 return 1;
917 else if (inl == 3 && js == 3)
918 return 2;
919 else if (inl == 3 && js == 5)
920 return 3;
921 else if (inl == 3 && js == 7)
922 return 4;
923 else if (inl == 3 && js == 9)
924 return 5;
925 // Default to zero
926 return 0;
927 }
928
930
931
934
936 inline int charge3(int pid) {
937 static int ch100[100] = {-1, 2, -1, 2, -1, 2, -1, 2, 0, 0, -3, 0, -3, 0, -3, 0, -3, 0, 0, 0,
938 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 0, 0,
939 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 6, 0, 0, 0, 0, 0, 0,
940 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
941 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
942 const int ida = abs(pid);
943 // Shortcuts for common particles
944 if (pid == 21 || pid == 22) return 0; // gluon and photon
945 if (ida == 211) return std::signbit(pid) ? -3 : 3; // charged pion
946 if (pid == 111) return 0; // neutral pion
947 // if (ida == 12 || ida == 14 || ida == 16) return 0; // neutrinos
948 // if (ida == 11 || ida == 13 || ida == 15) return std::signbit(pid) ? +3 : -3; // leptons
949 // if (ida == 1 || ida == 3 || ida == 5) return std::signbit(pid) ? +1 : -1; // quarks
950 // if (ida == 2 || ida == 4 || ida == 6) return std::signbit(pid) ? -2 : +2; // quarks
951 // Standard decoding
952 const unsigned short q1 = _digit(nq1, pid);
953 const unsigned short q2 = _digit(nq2, pid);
954 const unsigned short q3 = _digit(nq3, pid);
955 const unsigned short ql = _digit(nl, pid);
956 const int sid = _fundamentalID(pid);
957 int ch3 = 0;
958 if (ida == 0 || _extraBits(pid) > 0) { // ion or illegal
959 return 0;
960 }
961 else if (sid > 0 && sid <= 100) { // Use table
962 if (ida == 1000017 || ida == 1000018 || ida == 1000034)
963 ch3 = 0;
964 else if (ida > 1000050 && ida <= 1000060)
965 ch3 = 0; // ?
966 else if (ida > 50 && ida <= 60)
967 ch3 = 0; // Generic DM
968 else if (ida == 5100061 || ida == 5100062)
969 ch3 = 6;
970 else
971 ch3 = ch100[sid - 1];
972 }
973 else if (_digit(nj, pid) == 0) { // KL, Ks, or undefined
974 return 0;
975 }
976 else if (isMeson(pid)) { // Mesons
977 ch3 = ((q2 == 3 || q2 == 5) ? -1 : 1) * (ch100[q2 - 1] - ch100[q3 - 1]);
978 }
979 else if (isBaryon(pid)) { // Baryons
980 ch3 = ch100[q3 - 1] + ch100[q2 - 1] + ch100[q1 - 1];
981 }
982 else if (isQBall(pid)) { // QBall
983 ch3 = 3 * ((ida / 10) % 10000);
984 }
985 else if (isHiddenValley(pid)) { // Hidden Valley
986 return 0;
987 }
988 else if (isDyon(pid)) { // Dyon
989 ch3 = 3 * ((ida / 10) % 1000) * (ql == 2 ? -1 : 1); //< NB. charge is flipped at the end if pid < 0
990 }
991 else if (isRHadron(pid)) { // R-hadron
993 if (q1 == 0 || q1 == 9) { //< gluino+q+qbar
994 if (q2 == 3 || q2 == 5) {
995 ch3 = ch100[q3 - 1] - ch100[q2 - 1];
996 }
997 else {
998 ch3 = ch100[q2 - 1] - ch100[q3 - 1];
999 }
1000 }
1001 else if (ql == 0) { //< squark+q+q
1002 ch3 = ch100[q3 - 1] + ch100[q2 - 1] + ch100[q1 - 1];
1003 }
1004 else if (_digit(nr, pid) == 0) { //< squark+q+q+q
1005 ch3 = ch100[q3 - 1] + ch100[q2 - 1] + ch100[q1 - 1] + ch100[ql - 1];
1006 }
1007 }
1008 else if (isDiQuark(pid)) { // Diquarks
1009 ch3 = ch100[q2 - 1] + ch100[q1 - 1];
1010 }
1011 else { // Unknown
1012 return 0;
1013 }
1014 if (pid < 0) ch3 *= -1;
1015 return ch3;
1016 }
1017
1020 inline int threeCharge(int pid) {
1021 return charge3(pid);
1022 }
1023
1025 inline int abscharge3(int pid) {
1026 return std::abs(charge3(pid));
1027 }
1028
1030 inline double charge(int pid) {
1031 return charge3(pid) / 3.0;
1032 }
1033
1035 inline double abscharge(int pid) {
1036 return std::abs(charge(pid));
1037 }
1038
1040
1041
1044
1046 inline bool isCharged(int pid) {
1047 return charge3(pid) != 0;
1048 }
1049
1051 inline bool isNeutral(int pid) {
1052 return charge3(pid) == 0;
1053 }
1054
1056
1057
1060
1062 inline bool isStrongInteracting(int pid) {
1063 return isParton(pid) || isHadron(pid);
1064 }
1065
1067 inline bool isEMInteracting(int pid) {
1068 return isCharged(pid) || isPhoton(pid);
1069 }
1070
1075 inline bool isWeakInteracting(int pid) {
1076 return !isGluon(pid) && !isGraviton(pid);
1077 }
1078
1080
1081
1084
1086 inline bool isGenSpecific(int pid) {
1087 return in_range(pid, 80, 101);
1088 }
1089
1093 inline bool isResonance(int pid) {
1094 return isW(pid) || isZ(pid) || isHiggs(pid) || isTop(pid);
1095 }
1096
1101 inline bool isTransportable(int pid) {
1102 // return !isResonance(pid) && !isParton(pid) && !isGenSpecific(pid);
1103 return isPhoton(pid) || isHadron(pid) || isLepton(pid);
1104 }
1105
1107
1108
1112
1113 inline bool isSameSign(PdgId a, PdgId b) {
1114 return a * b >= 0;
1115 }
1116 inline bool isOppSign(PdgId a, PdgId b) {
1117 return !isSameSign(a, b);
1118 }
1119 inline bool isSameFlav(PdgId a, PdgId b) {
1120 return abs(a) == abs(b);
1121 }
1122 inline bool isOppFlav(PdgId a, PdgId b) {
1123 return !isSameFlav(a, b);
1124 }
1125
1126 inline bool isOSSF(PdgId a, PdgId b) {
1127 return isOppSign(a, b) && isSameFlav(a, b);
1128 }
1129 inline bool isSSSF(PdgId a, PdgId b) {
1130 return isSameSign(a, b) && isSameFlav(a, b);
1131 }
1132 inline bool isOSOF(PdgId a, PdgId b) {
1133 return isOppSign(a, b) && isOppFlav(a, b);
1134 }
1135 inline bool isSSOF(PdgId a, PdgId b) {
1136 return isSameSign(a, b) && isOppFlav(a, b);
1137 }
1138
1140
1141
1142 }
1143}
1144
1145#endif
int sSpin(int pid)
sSpin returns 2S+1, where S is the spin
Definition ParticleIdUtils.hh:853
int jSpin(int pid)
jSpin returns 2J+1, where J is the total spin
Definition ParticleIdUtils.hh:836
int lSpin(int pid)
lSpin returns 2L+1, where L is the orbital angular momentum
Definition ParticleIdUtils.hh:882
bool isCharged(int pid)
Determine if the particle is electrically charged.
Definition ParticleIdUtils.hh:1046
bool isNeutral(int pid)
Determine if the particle is electrically neutral.
Definition ParticleIdUtils.hh:1051
int threeCharge(int pid)
Definition ParticleIdUtils.hh:1020
int abscharge3(int pid)
Return the absolute value of 3 times the EM charge.
Definition ParticleIdUtils.hh:1025
double charge(int pid)
Return the EM charge (as floating point).
Definition ParticleIdUtils.hh:1030
double abscharge(int pid)
Return the EM charge (as floating point).
Definition ParticleIdUtils.hh:1035
int charge3(int pid)
Three times the EM charge (as integer).
Definition ParticleIdUtils.hh:936
bool isBottom(int pid)
Determine if the PID is that of a b/bbar.
Definition ParticleIdUtils.hh:293
bool isParton(int pid)
Determine if the PID is that of a parton (quark or gluon).
Definition ParticleIdUtils.hh:198
bool isW(int pid)
Determine if the PID is that of a W+-.
Definition ParticleIdUtils.hh:252
bool isWminus(int pid)
Determine if the PID is that of a W-.
Definition ParticleIdUtils.hh:247
bool isZ(int pid)
Determine if the PID is that of a Z0.
Definition ParticleIdUtils.hh:257
bool isMuon(int pid)
Determine if the PID is that of an muon or antimuon.
Definition ParticleIdUtils.hh:214
bool isHiggs(int pid)
Determine if the PID is that of an SM/lightest SUSY Higgs.
Definition ParticleIdUtils.hh:262
bool isCharm(int pid)
Determine if the PID is that of a c/cbar.
Definition ParticleIdUtils.hh:288
bool isGraviton(int pid)
Is this a graviton?
Definition ParticleIdUtils.hh:271
bool isChLepton(int pid)
Definition ParticleIdUtils.hh:230
bool isTau(int pid)
Determine if the PID is that of an tau or antitau.
Definition ParticleIdUtils.hh:219
bool isGluon(int pid)
Determine if the PID is that of a gluon.
Definition ParticleIdUtils.hh:193
bool isWplus(int pid)
Determine if the PID is that of a W+.
Definition ParticleIdUtils.hh:242
bool isPhoton(int pid)
Determine if the PID is that of a photon.
Definition ParticleIdUtils.hh:204
bool isNeutrino(int pid)
Determine if the PID is that of a neutrino.
Definition ParticleIdUtils.hh:235
bool isElectron(int pid)
Determine if the PID is that of an electron or positron.
Definition ParticleIdUtils.hh:209
bool isChargedLepton(int pid)
Determine if the PID is that of a charged lepton.
Definition ParticleIdUtils.hh:224
bool isQuark(int pid)
Determine if the PID is that of a quark.
Definition ParticleIdUtils.hh:188
bool isTop(int pid)
Determine if the PID is that of a t/tbar.
Definition ParticleIdUtils.hh:298
bool isStrange(int pid)
Determine if the PID is that of an s/sbar.
Definition ParticleIdUtils.hh:283
bool isRHadron(int pid)
Is this an R-hadron?
Definition ParticleIdUtils.hh:472
bool isQBall(int pid)
Definition ParticleIdUtils.hh:569
bool isSMFundamental(int pid)
Is this an SM fundamental particle?
Definition ParticleIdUtils.hh:446
bool isMagMonopole(int pid)
Is this from a magnetic monopole or dyon?
Definition ParticleIdUtils.hh:551
bool isLepton(int pid)
Definition ParticleIdUtils.hh:433
bool isSUSY(int pid)
Is this a fundamental SUSY particle?
Definition ParticleIdUtils.hh:454
bool isKK(int pid)
Is this a Kaluza-Klein excitation?
Definition ParticleIdUtils.hh:504
bool isRhadron(int pid)
Alias.
Definition ParticleIdUtils.hh:487
bool isExotic(int pid)
Is this an exotic particle?
Definition ParticleIdUtils.hh:538
bool isTechnicolor(int pid)
Is this a technicolor particle?
Definition ParticleIdUtils.hh:492
bool isLeptoQuark(int pid)
Is this a lepto-quark?
Definition ParticleIdUtils.hh:511
bool isAECO(int pid)
Is this an anomalously electrically charged particle (AECO)?
Definition ParticleIdUtils.hh:598
bool isExcitedLepton(int pid)
Is this an excited lepton?
Definition ParticleIdUtils.hh:585
bool isBSM(int pid)
Is this a BSM particle (including graviton)?
Definition ParticleIdUtils.hh:607
bool isFourthGen(int pid)
Is this a 4th generation particle?
Definition ParticleIdUtils.hh:546
bool isBSMBoson(int pid)
Is this a valid BSM boson (SUSY Higgs, W', Z')?
Definition ParticleIdUtils.hh:441
bool isExcited(int pid)
Is this an excited (composite) quark or lepton?
Definition ParticleIdUtils.hh:498
bool isDM(int pid)
Convenience alias.
Definition ParticleIdUtils.hh:528
bool isBlackHole(int pid)
Is this a black hole?
Definition ParticleIdUtils.hh:591
bool isHiddenValley(int pid)
Is this a Hidden Valley particle?
Definition ParticleIdUtils.hh:533
bool isQball(int pid)
Alias.
Definition ParticleIdUtils.hh:580
bool isDyon(int pid)
Just treat a dyon as an alias for magmonopole for now.
Definition ParticleIdUtils.hh:563
bool isDarkMatter(int pid)
Definition ParticleIdUtils.hh:520
bool isEMInteracting(int pid)
Determine if the PID is that of a electromagnetically interacting particle.
Definition ParticleIdUtils.hh:1067
bool isWeakInteracting(int pid)
Definition ParticleIdUtils.hh:1075
bool isStrongInteracting(int pid)
Determine if the PID is that of a strongly interacting particle.
Definition ParticleIdUtils.hh:1062
int lambda(int pid)
Definition ParticleIdUtils.hh:177
int nuclA(int pid)
Definition ParticleIdUtils.hh:153
int Z(int pid)
Definition ParticleIdUtils.hh:147
int A(int pid)
Definition ParticleIdUtils.hh:162
int nuclNlambda(int pid)
Definition ParticleIdUtils.hh:168
bool isNucleus(int pid)
Is this a nucleus PID?
Definition ParticleIdUtils.hh:124
int nuclZ(int pid)
Definition ParticleIdUtils.hh:138
bool isResonance(int pid)
Definition ParticleIdUtils.hh:1093
bool isGenSpecific(int pid)
Determine if the PID is in the generator-specific range.
Definition ParticleIdUtils.hh:1086
bool isTransportable(int pid)
Definition ParticleIdUtils.hh:1101
bool isLightHadron(int pid)
Determine if the PID is that of a light flavour (not b or c) hadron.
Definition ParticleIdUtils.hh:757
bool isCharmHadron(int pid)
Definition ParticleIdUtils.hh:800
bool isStrangeBaryon(int pid)
Definition ParticleIdUtils.hh:817
bool isHeavyFlavor(int pid)
Determine if the particle is a heavy flavour hadron or parton.
Definition ParticleIdUtils.hh:704
bool isHeavyHadron(int pid)
Determine if the PID is that of a heavy flavour (b or c) hadron.
Definition ParticleIdUtils.hh:742
bool isCharmMeson(int pid)
Determine if the PID is that of a c-meson.
Definition ParticleIdUtils.hh:782
bool isStrangeHadron(int pid)
Definition ParticleIdUtils.hh:825
bool isCharmBaryon(int pid)
Determine if the PID is that of a c-baryon.
Definition ParticleIdUtils.hh:791
bool isHeavyBaryon(int pid)
Determine if the PID is that of a heavy flavour (b or c) baryon.
Definition ParticleIdUtils.hh:737
bool isHeavyMeson(int pid)
Determine if the PID is that of a heavy flavour (b or c) meson.
Definition ParticleIdUtils.hh:732
bool isLightBaryon(int pid)
Determine if the PID is that of a light flavour (not b or c) baryon.
Definition ParticleIdUtils.hh:752
bool isBottomBaryon(int pid)
Determine if the PID is that of a b-baryon.
Definition ParticleIdUtils.hh:768
bool isLightParton(int pid)
Determine if the PID is that of a light parton (u,d,s).
Definition ParticleIdUtils.hh:726
bool isStrangeMeson(int pid)
Definition ParticleIdUtils.hh:809
bool isHeavyParton(int pid)
Determine if the PID is that of a heavy parton (c,b,t).
Definition ParticleIdUtils.hh:721
bool isBottomHadron(int pid)
Determine if the PID is that of a b-hadron.
Definition ParticleIdUtils.hh:773
bool isHeavyFlavour(int pid)
British-spelling alias for isHeavyFlavor.
Definition ParticleIdUtils.hh:709
bool isBottomMeson(int pid)
Determine if the PID is that of a b-meson.
Definition ParticleIdUtils.hh:763
bool isLightMeson(int pid)
Determine if the PID is that of a light flavour (not b or c) meson.
Definition ParticleIdUtils.hh:747
bool hasUp(int pid)
Does this particle contain an up quark?
Definition ParticleIdUtils.hh:677
bool hasTop(int pid)
Does this particle contain a top quark?
Definition ParticleIdUtils.hh:693
bool hasBottom(int pid)
Does this particle contain a bottom quark?
Definition ParticleIdUtils.hh:689
bool hasStrange(int pid)
Does this particle contain a strange quark?
Definition ParticleIdUtils.hh:681
bool hasDown(int pid)
Does this particle contain a down quark?
Definition ParticleIdUtils.hh:673
bool hasCharm(int pid)
Does this particle contain a charm quark?
Definition ParticleIdUtils.hh:685
bool isBaryon(int pid)
Check to see if this is a valid baryon.
Definition ParticleIdUtils.hh:337
bool isDiQuark(int pid)
Definition ParticleIdUtils.hh:376
bool isPentaquark(int pid)
Check to see if this is a valid pentaquark.
Definition ParticleIdUtils.hh:381
bool isMeson(int pid)
Check to see if this is a valid meson.
Definition ParticleIdUtils.hh:314
bool isHadron(int pid)
Definition ParticleIdUtils.hh:415
bool isReggeon(int pid)
Is this a pomeron, odderon, or generic reggeon?
Definition ParticleIdUtils.hh:309
bool isQuarkonium(int pid)
Definition ParticleIdUtils.hh:405
Location
Definition ParticleIdUtils.hh:74
int abspid(int pid)
Definition ParticleIdUtils.hh:28
int pid(const Particle &p)
Unbound function access to PID code.
Definition ParticleUtils.hh:23
Definition LHCbCommon.hh:9
std::enable_if_t< std::is_arithmetic_v< N1 > &&std::is_arithmetic_v< N2 > &&std::is_arithmetic_v< N3 >, bool > in_range(N1 val, N2 low, N3 high)
Boolean function to determine if value is within the given range.
Definition MathUtils.hh:203
std::enable_if_t< std::is_arithmetic_v< N1 > &&std::is_arithmetic_v< N2 > &&std::is_arithmetic_v< N3 >, bool > in_closed_range(N1 val, N2 low, N3 high)
Boolean function to determine if value is within the given range.
Definition MathUtils.hh:213