Version: SMASH-3.1
pdgcode.h
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2024
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #ifndef SRC_INCLUDE_SMASH_PDGCODE_H_
11 #define SRC_INCLUDE_SMASH_PDGCODE_H_
12 
13 #include <algorithm>
14 #include <array>
15 #include <cassert>
16 #include <cstdint>
17 #include <cstdlib>
18 #include <functional>
19 #include <iomanip>
20 #include <iosfwd>
21 #include <iostream>
22 #include <sstream>
23 #include <stdexcept>
24 #include <string>
25 #include <type_traits>
26 
27 #include "pdgcode_constants.h"
28 
29 namespace smash {
30 
111 class PdgCode {
112  public:
117  struct InvalidPdgCode : public std::invalid_argument {
118  using std::invalid_argument::invalid_argument;
119  };
120 
121  /****************************************************************************
122  * *
123  * First, the constructors *
124  * *
125  ****************************************************************************/
126 
128  PdgCode() : dump_(0x0) {}
134  explicit PdgCode(const std::string& codestring) {
135  set_from_string(codestring);
136  }
137 
146  PdgCode(std::int32_t codenumber) : dump_(0x0) { // NOLINT(runtime/explicit)
147  digits_.antiparticle_ = false;
148  if (codenumber < 0) {
149  digits_.antiparticle_ = true;
150  codenumber = -codenumber;
151  }
152  set_fields(codenumber);
153  }
158  explicit PdgCode(const std::uint32_t abscode) : dump_(0x0) {
159  // use the first bit for the antiparticle_ boolean.
160  digits_.antiparticle_ = ((abscode & 0x80000000u) != 0);
161  set_fields(abscode);
162  }
163 
219  template <typename T>
220  PdgCode(T codenumber, // NOLINT(runtime/explicit)
221  typename std::enable_if_t<std::is_integral_v<T> && 4 < sizeof(T),
222  bool> = true)
223  : PdgCode{std::invoke([&codenumber]() {
224  std::stringstream stream;
225  char sign = '+';
226  if (codenumber < 0) {
227  sign = '-';
228  codenumber = -codenumber;
229  }
230  stream << sign << std::hex << codenumber;
231  return stream.str();
232  })} {}
233 
234  /****************************************************************************
235  * *
236  * test function and export functions *
237  * *
238  ****************************************************************************/
239 
253  inline int test_code() const {
254  int fail = 0;
255  if (digits_.n_ > 9) {
256  fail |= 1 << 6;
257  }
258  if (digits_.n_R_ > 9) {
259  fail |= 1 << 5;
260  }
261  if (digits_.n_L_ > 9) {
262  fail |= 1 << 4;
263  }
264  if (digits_.n_q1_ > 6) {
265  fail |= 1 << 3;
266  }
267  if (digits_.n_q2_ > 6) {
268  fail |= 1 << 2;
269  }
270  if (digits_.n_q3_ > 6) {
271  fail |= 1 << 1;
272  }
273  if (digits_.n_J_ > 15) {
274  fail |= 1;
275  }
276  return fail;
277  }
278 
287  void check() const {
288  // n_J must be odd for mesons and even for baryons (and cannot be zero)
289  if (is_hadron()) {
290  if (baryon_number() == 0) {
291  // mesons: special cases K0_L=0x130 and K0_S=0x310
292  if ((digits_.n_J_ % 2 == 0) && dump() != 0x130 && dump() != 0x310) {
293  throw InvalidPdgCode("Invalid PDG code " + string() +
294  " (meson with even n_J)");
295  }
296  } else {
297  if ((digits_.n_J_ % 2 != 0) || digits_.n_J_ == 0) {
298  throw InvalidPdgCode("Invalid PDG code " + string() +
299  " (baryon with odd n_J)");
300  }
301  }
302  } else {
303  if (digits_.n_J_ == 0 && dump() != 0x0) {
304  throw InvalidPdgCode("Invalid PDG code " + string() + " (n_J==0)");
305  }
306  }
307  /* The antiparticle flag only makes sense for particle types
308  * that have an antiparticle. */
309  if (digits_.antiparticle_ && !has_antiparticle()) {
310  throw InvalidPdgCode("Invalid PDG code " + string() +
311  " (cannot be negative)");
312  }
313  }
314 
316  inline std::uint32_t dump() const {
317  // this cuts the three unused bits.
318  return (dump_ & 0x8fffffff);
319  }
320 
322  inline std::int32_t code() const { return antiparticle_sign() * ucode(); }
323 
325  inline std::string string() const {
326  std::stringstream ss;
327  ss << get_decimal();
328  return ss.str();
329  }
330 
333  PdgCode result = *this;
334  result.digits_.antiparticle_ = !digits_.antiparticle_;
335  return result;
336  }
337 
342  static PdgCode from_decimal(const int pdgcode_decimal) {
343  // Nucleus and special codes with 2J+1 > 9
344  if (std::abs(pdgcode_decimal) > 1E7) {
345  return PdgCode(std::to_string(pdgcode_decimal));
346  }
347  int a = pdgcode_decimal;
348  int hex_pdg = 0, tmp = 1;
349  while (a) {
350  hex_pdg += (a % 10) * tmp;
351  tmp *= 16;
352  a = a / 10;
353  }
354  return PdgCode(hex_pdg);
355  }
356 
357  /****************************************************************************
358  * *
359  * accessors of various properties *
360  * *
361  ****************************************************************************/
362 
364  inline bool is_nucleus() const {
365  assert(digits_.is_nucleus_ == nucleus_.is_nucleus_);
366  return nucleus_.is_nucleus_;
367  }
368 
370  inline bool is_hadron() const {
371  return (digits_.n_q3_ != 0 && digits_.n_q2_ != 0 && !is_nucleus());
372  }
373 
375  inline bool is_lepton() const {
376  return (digits_.n_q1_ == 0 && digits_.n_q2_ == 0 && digits_.n_q3_ == 1 &&
377  !is_nucleus());
378  }
379 
381  inline int baryon_number() const {
382  if (is_nucleus()) {
383  return static_cast<int>(nucleus_.A_) * antiparticle_sign();
384  }
385  if (!is_hadron() || digits_.n_q1_ == 0) {
386  return 0;
387  }
388  return antiparticle_sign();
389  }
391  inline bool is_baryon() const { return is_hadron() && digits_.n_q1_ != 0; }
392 
394  inline bool is_meson() const { return is_hadron() && digits_.n_q1_ == 0; }
395 
397  inline bool is_nucleon() const {
398  const auto abs_code = std::abs(code());
399  return (abs_code == pdg::p || abs_code == pdg::n);
400  }
401 
403  inline bool is_proton() const {
404  const auto abs_code = std::abs(code());
405  return (abs_code == pdg::p);
406  }
407 
409  inline bool is_neutron() const {
410  const auto abs_code = std::abs(code());
411  return (abs_code == pdg::n);
412  }
413 
415  inline bool is_Nstar1535() const {
416  const auto abs_code = std::abs(code());
417  return (abs_code == pdg::N1535_p || abs_code == pdg::N1535_z);
418  }
419 
421  inline bool is_Delta() const {
422  const auto abs_code = std::abs(code());
423  return (abs_code == pdg::Delta_pp || abs_code == pdg::Delta_p ||
424  abs_code == pdg::Delta_z || abs_code == pdg::Delta_m);
425  }
426 
428  inline bool is_hyperon() const { return is_hadron() && digits_.n_q1_ == 3; }
429 
431  inline bool is_Omega() const {
432  return is_hyperon() && digits_.n_q2_ == 3 && digits_.n_q3_ == 3;
433  }
434 
436  inline bool is_Xi() const {
437  return is_hyperon() && digits_.n_q2_ == 3 && digits_.n_q3_ != 3;
438  }
439 
441  inline bool is_Lambda() const {
442  return is_hyperon() && digits_.n_q2_ == 1 && digits_.n_q3_ == 2;
443  }
444 
446  inline bool is_Sigma() const {
447  return is_hyperon() && digits_.n_q2_ != 3 && !is_Lambda();
448  }
449 
451  inline bool is_kaon() const {
452  const auto abs_code = std::abs(code());
453  return (abs_code == pdg::K_p) || (abs_code == pdg::K_z);
454  }
455 
457  inline bool is_pion() const {
458  const auto c = code();
459  return (c == pdg::pi_z) || (c == pdg::pi_p) || (c == pdg::pi_m);
460  }
461 
463  inline bool is_omega() const {
464  const auto c = code();
465  return c == pdg::omega;
466  }
467 
469  inline bool is_rho() const {
470  const auto c = code();
471  return (c == pdg::rho_z) || (c == pdg::rho_p) || (c == pdg::rho_m);
472  }
473 
475  inline bool is_deuteron() const {
476  return is_nucleus() && nucleus_.A_ == 2 && nucleus_.Z_ == 1 &&
477  nucleus_.n_Lambda_ == 0 && nucleus_.I_ == 0;
478  }
479 
481  inline bool is_triton() const {
482  return is_nucleus() && nucleus_.A_ == 3 && nucleus_.Z_ == 1 &&
483  nucleus_.n_Lambda_ == 0 && nucleus_.I_ == 0;
484  }
485 
490  bool has_antiparticle() const {
491  if (is_nucleus()) {
492  return true;
493  }
494  if (is_hadron()) {
495  return (baryon_number() != 0) || (digits_.n_q2_ != digits_.n_q3_);
496  } else {
497  return digits_.n_q3_ == 1; // leptons!
498  }
499  }
500 
506  inline int isospin3() const {
507  /* net_quark_number(2) is the number of u quarks,
508  * net_quark_number(1) is the number of d quarks. */
509  return net_quark_number(2) - net_quark_number(1);
510  }
511 
519  inline double frac_strange() const {
520  /* The quarkonium state has 0 net strangeness
521  * but there are actually 2 strange quarks out of 2 total */
522  if (is_hadron() && digits_.n_q3_ == 3 && digits_.n_q2_ == 3) {
523  return 1.;
524  } else {
525  // For all other cases, there isn't both a strange and anti-strange
526  if (is_baryon()) {
527  return std::abs(strangeness()) / 3.;
528  } else if (is_meson()) {
529  return std::abs(strangeness()) / 2.;
530  } else {
531  /* If not baryon or meson, this should be 0, as AQM does not
532  * extend to non-hadrons */
533  return 0.;
534  }
535  }
536  }
537 
543  inline int strangeness() const { return -net_quark_number(3); }
544 
550  inline int charmness() const { return +net_quark_number(4); }
551 
557  inline int bottomness() const { return -net_quark_number(5); }
558 
567  int charge() const {
568  if (is_hadron() || is_nucleus()) {
569  // Q will accumulate 3*charge (please excuse the upper case. I
570  // want to distinguish this from q which might be interpreted as
571  // shorthand for "quark".)
572  int Q = 0;
573  /* This loops over d,u,s,c,b,t quarks (the latter can be safely ignored,
574  * but I don't think this will be a bottle neck. */
575  for (int i = 1; i < 7; i++) {
576  /* u,c,t quarks have charge = 2/3 e, while d,s,b quarks have -1/3 e.
577  * The antiparticle sign is already in net_quark_number. */
578  Q += (i % 2 == 0 ? 2 : -1) * net_quark_number(i);
579  }
580  return Q / 3;
581  }
582  /* non-hadron:
583  * Leptons: 11, 13, 15 are e, μ, τ and have a charge -1, while
584  * 12, 14, 16 are the neutrinos that have no charge. */
585  if (digits_.n_q3_ == 1) {
586  return -1 * (digits_.n_J_ % 2) * antiparticle_sign();
587  }
588  /* Bosons: 24 is the W+, all else is uncharged.
589  * we ignore the first digits so that this also finds strange gauge
590  * boson "resonances" (in particular, \f$\tilde \chi_1^+\f$ with PDG
591  * Code 1000024). */
592  if ((dump_ & 0x0000ffff) == 0x24) {
593  return antiparticle_sign();
594  }
595  // default (this includes all other Bosons) is 0.
596  return 0;
597  }
598 
608  inline unsigned int spin() const {
609  if (is_nucleus()) {
610  // Generally spin of a nucleus cannot be simply guessed, it should be
611  // provided from some table. However, here we only care about a
612  // limited set of light nuclei with A <= 4.
613  if (nucleus_.A_ == 2) {
614  // Deuteron spin is 1
615  return 2;
616  } else if (nucleus_.A_ == 3) {
617  // Tritium and He-3 spin are 1/2
618  // Hypertriton spin is not firmly determined, but decay branching ratios
619  // indicate spin 1/2
620  return 1;
621  } else if (nucleus_.A_ == 4) {
622  // He-4 spin is 0
623  return 0;
624  }
625  throw std::runtime_error("Unknown spin of nucleus.");
626  // Alternative possibility is to guess 1/2 for fermions and 0 for bosons
627  // as 2 * (nucleus_.A_ % 2).
628  }
629 
630  if (is_hadron()) {
631  if (digits_.n_J_ == 0) {
632  return 0; // special cases: K0_L=0x130 & K0_S=0x310
633  } else {
634  return digits_.n_J_ - 1;
635  }
636  }
637  /* this assumes that we only have white particles (no single
638  * quarks): Electroweak fermions have 11-17, so the
639  * second-to-last-digit is the spin. The same for the Bosons: they
640  * have 21-29 and 2spin = 2 (this fails for the Higgs). */
641  return digits_.n_q3_;
642  }
644  inline unsigned int spin_degeneracy() const {
645  if (is_hadron() && digits_.n_J_ > 0) {
646  return digits_.n_J_;
647  }
648  return spin() + 1;
649  }
651  inline int antiparticle_sign() const {
652  return (digits_.antiparticle_ ? -1 : +1);
653  }
655  inline std::int32_t quarks() const {
656  if (!is_hadron() || is_nucleus()) {
657  return 0;
658  }
659  return chunks_.quarks_;
660  }
661 
671  std::array<int, 3> quark_content() const {
672  std::array<int, 3> result = {static_cast<int>(digits_.n_q1_),
673  static_cast<int>(digits_.n_q2_),
674  static_cast<int>(digits_.n_q3_)};
675  if (is_hadron()) {
676  // Antibaryons
677  if (digits_.n_q1_ != 0 && digits_.antiparticle_) {
678  for (size_t i = 0; i < 3; i++) {
679  result[i] = -result[i];
680  }
681  }
682  // Mesons
683  if (digits_.n_q1_ == 0) {
684  // Own antiparticle
685  if (digits_.n_q2_ == digits_.n_q3_) {
686  result[2] = -result[2];
687  } else {
688  // Like pi-
689  if (digits_.antiparticle_) {
690  result[1] = -result[1];
691  // Like pi+
692  } else {
693  result[2] = -result[2];
694  }
695  }
696  // add extra minus sign according to the pdg convention
697  if (digits_.n_q2_ != digits_.n_q3_ && digits_.n_q2_ % 2 == 1) {
698  for (int i = 1; i <= 2; i++) {
699  result[i] = -result[i];
700  }
701  }
702  }
703  } else {
704  result = {0, 0, 0};
705  }
706  return result;
707  }
708 
719  bool contains_enough_valence_quarks(int valence_quarks_required) const;
720 
721  /****************************************************************************
722  * *
723  * operations with more than one PDG Code *
724  * *
725  ****************************************************************************/
726 
731  inline bool operator<(const PdgCode rhs) const {
732  return dump_ < rhs.dump_;
733  /* the complex thing to do here is to calculate:
734  * code() < rhs.code()
735  * but for getting a total order that's overkill. The uint32_t value in
736  * dump_ works just fine. */
737  }
738 
740  inline bool operator==(const PdgCode rhs) const { return dump_ == rhs.dump_; }
741 
743  inline bool operator!=(const PdgCode rhs) const { return !(*this == rhs); }
744 
746  inline bool is_antiparticle_of(const PdgCode rhs) const {
747  return code() == -rhs.code();
748  }
749 
751  friend std::istream& operator>>(std::istream& is, PdgCode& code);
752 
758  static PdgCode invalid() { return PdgCode(0x0); }
759 
769  int32_t get_decimal() const {
770  if (is_nucleus()) {
771  // ±10LZZZAAAI
772  return antiparticle_sign() *
773  (nucleus_.I_ + 10 * nucleus_.A_ + 10000 * nucleus_.Z_ +
774  10000000 * nucleus_.n_Lambda_ + 1000000000);
775  }
776  int n_J_1 = 0;
777  int n_J_2 = digits_.n_J_;
778  if (n_J_2 > 9) {
779  n_J_1 = n_J_2 - 9;
780  n_J_2 = 9;
781  }
782  return antiparticle_sign() *
783  (n_J_2 + digits_.n_q3_ * 10 + digits_.n_q2_ * 100 +
784  digits_.n_q1_ * 1000 + digits_.n_L_ * 10000 +
785  digits_.n_R_ * 100000 + digits_.n_ * 1000000 + n_J_1 * 10000000);
786  }
787 
789  void deexcite() {
790  if (!is_nucleus()) {
791  chunks_.excitation_ = 0;
792  } else {
793  nucleus_.I_ = 0;
794  }
795  }
796 
807  int net_quark_number(const int quark) const;
808 
810  int nucleus_p() const {
811  return (is_nucleus() && !nucleus_.antiparticle_) ? nucleus_.Z_ : 0;
812  }
814  int nucleus_n() const {
815  return (is_nucleus() && !nucleus_.antiparticle_)
816  ? nucleus_.A_ - nucleus_.Z_ - nucleus_.n_Lambda_
817  : 0;
818  }
820  int nucleus_La() const {
821  return (is_nucleus() && !nucleus_.antiparticle_) ? nucleus_.n_Lambda_ : 0;
822  }
824  int nucleus_ap() const {
825  return (is_nucleus() && nucleus_.antiparticle_) ? nucleus_.Z_ : 0;
826  }
828  int nucleus_an() const {
829  return (is_nucleus() && nucleus_.antiparticle_)
830  ? nucleus_.A_ - nucleus_.Z_ - nucleus_.n_Lambda_
831  : 0;
832  }
834  int nucleus_aLa() const {
835  return (is_nucleus() && nucleus_.antiparticle_) ? nucleus_.n_Lambda_ : 0;
836  }
838  int nucleus_A() const { return is_nucleus() ? nucleus_.A_ : 0; }
839 
840  private:
846  union {
851  struct {
852 #if defined(LITTLE_ENDIAN_ARCHITECTURE) || defined(DOXYGEN)
854  std::uint32_t n_J_ : 4;
856  std::uint32_t n_q3_ : 4;
858  std::uint32_t n_q2_ : 4;
860  std::uint32_t n_q1_ : 4;
862  std::uint32_t n_L_ : 4;
864  std::uint32_t n_R_ : 4;
866  std::uint32_t n_ : 4, : 2;
868  bool is_nucleus_ : 1;
870  bool antiparticle_ : 1;
871 #elif defined(BIG_ENDIAN_ARCHITECTURE) // reverse ordering
872  bool antiparticle_ : 1;
873  bool is_nucleus_ : 1, : 2;
874  std::uint32_t n_ : 4;
875  std::uint32_t n_R_ : 4;
876  std::uint32_t n_L_ : 4;
877  std::uint32_t n_q1_ : 4;
878  std::uint32_t n_q2_ : 4;
879  std::uint32_t n_q3_ : 4;
880  std::uint32_t n_J_ : 4;
881 #else
882 #error Endianness macro of the machine not defined.
883 #endif
884  } digits_;
889  std::uint32_t dump_;
894  struct {
895 #if defined(LITTLE_ENDIAN_ARCHITECTURE) || defined(DOXYGEN)
896  std::uint32_t : 4;
898  std::uint32_t quarks_ : 12;
900  std::uint32_t excitation_ : 12, : 4;
901 #elif defined(BIG_ENDIAN_ARCHITECTURE) // reverse ordering
902  std::uint32_t : 4, excitation_ : 12;
903  std::uint32_t quarks_ : 12, : 4;
904 #else
905 #error Endianness macro of the machine not defined.
906 #endif
907  } chunks_;
909  struct {
910 #if defined(LITTLE_ENDIAN_ARCHITECTURE) || defined(DOXYGEN)
911  std::uint32_t n_Lambda_ : 6;
912  std::uint32_t Z_ : 10;
913  std::uint32_t A_ : 10;
914  std::uint32_t I_ : 4;
915  bool is_nucleus_ : 1;
916  bool antiparticle_ : 1;
917 #elif defined(BIG_ENDIAN_ARCHITECTURE) // reverse ordering
918  bool antiparticle_ : 1;
919  bool is_nucleus_ : 1;
920  std::uint32_t I_ : 4;
921  std::uint32_t A_ : 10;
922  std::uint32_t Z_ : 10;
923  std::uint32_t n_Lambda_ : 6;
924 #else
925 #error Endianness macro of the machine not defined.
926 #endif
927  } nucleus_;
928  };
929 
934  inline std::uint32_t ucode() const { return (dump_ & 0x0fffffff); }
935 
942  inline std::uint32_t get_digit_from_char(const char inp) const {
943  // Decimal digit
944  if (48 <= inp && inp <= 57) {
945  return inp - 48;
946  }
947  // Hexdecimal digit, uppercase
948  if (65 <= inp && inp <= 70) {
949  return inp - 65 + 10;
950  }
951  // Hexdecimal digit, lowercase
952  if (97 <= inp && inp <= 102) {
953  return inp - 97 + 10;
954  }
955  throw InvalidPdgCode("PdgCode: Invalid character " + std::string(&inp, 1) +
956  " found.\n");
957  }
958 
980  inline void set_from_string(const std::string& codestring) {
981  dump_ = 0;
982  // Implicit with the above: digits_.antiparticle_ = false;
983  digits_.n_ = digits_.n_R_ = digits_.n_L_ = digits_.n_q1_ = digits_.n_q2_ =
984  digits_.n_q3_ = digits_.n_J_ = digits_.is_nucleus_ = 0;
985  size_t length = codestring.size();
986  if (length < 1) {
987  throw InvalidPdgCode("Empty string does not contain PDG Code\n");
988  }
989  int c = 0;
990  /* Look at current character; if it is a + or minus sign, read it
991  * and advance to next char. */
992  if (codestring[c] == '-') {
993  digits_.antiparticle_ = true;
994  ++c;
995  } else if (codestring[c] == '+') {
996  digits_.antiparticle_ = false;
997  ++c;
998  }
999  // Save if the first character was a sign:
1000  unsigned int sign = c;
1001 
1002  // Nucleus
1003  if (length == 10 + sign) {
1004  nucleus_.is_nucleus_ = true;
1005  if (codestring[c] != '1' || codestring[c + 1] != '0') {
1006  throw InvalidPdgCode("Pdg code of nucleus \"" + codestring +
1007  "\" should start with 10\n");
1008  }
1009  c += 2;
1010  // ±10LZZZAAAI is the standard for nuclei
1011  std::array<int, 8> digits;
1012  for (int i = 0; i < 8; i++) {
1013  digits[i] = get_digit_from_char(codestring[c + i]);
1014  }
1015  nucleus_.n_Lambda_ = digits[0];
1016  nucleus_.Z_ = 100 * digits[1] + 10 * digits[2] + digits[3];
1017  nucleus_.A_ = 100 * digits[4] + 10 * digits[5] + digits[6];
1018  nucleus_.I_ = digits[7];
1019  return;
1020  }
1021 
1022  // Codestring shouldn't be longer than 8 + sign, except for nuclei
1023  if (length > 8 + sign) {
1024  throw InvalidPdgCode("String \"" + codestring +
1025  "\" too long for PDG Code\n");
1026  }
1027  /* Please note that in what follows, we actually need c++, not ++c.
1028  * first digit is used for n_J if the last digit is not enough. */
1029  if (length > 7 + sign) {
1030  digits_.n_J_ += get_digit_from_char(codestring[c++]);
1031  }
1032  // Codestring has 7 digits? 7th from last goes in n_.
1033  if (length > 6 + sign) {
1034  digits_.n_ = get_digit_from_char(codestring[c++]);
1035  }
1036  // It has 6 or 7 digits? 6th from last is n_R_.
1037  if (length > 5 + sign) {
1038  digits_.n_R_ = get_digit_from_char(codestring[c++]);
1039  }
1040  // 5th from last is n_L_.
1041  if (length > 4 + sign) {
1042  digits_.n_L_ = get_digit_from_char(codestring[c++]);
1043  }
1044  // 4th from last is n_q1_.
1045  if (length > 3 + sign) {
1046  digits_.n_q1_ = get_digit_from_char(codestring[c++]);
1047  if (digits_.n_q1_ > 6) {
1048  throw InvalidPdgCode("Invalid PDG code " + codestring + " (n_q1>6)");
1049  }
1050  }
1051  // 3rd from last is n_q2_.
1052  if (length > 2 + sign) {
1053  digits_.n_q2_ = get_digit_from_char(codestring[c++]);
1054  if (digits_.n_q2_ > 6) {
1055  throw InvalidPdgCode("Invalid PDG code " + codestring + " (n_q2>6)");
1056  }
1057  }
1058  // Next to last is n_q3_.
1059  if (length > 1 + sign) {
1060  digits_.n_q3_ = get_digit_from_char(codestring[c++]);
1061  if (digits_.n_q3_ > 6) {
1062  throw InvalidPdgCode("Invalid PDG code " + codestring + " (n_q3>6)");
1063  }
1064  }
1065  // Last digit is the spin degeneracy.
1066  if (length > sign) {
1067  digits_.n_J_ += get_digit_from_char(codestring[c++]);
1068  } else {
1069  throw InvalidPdgCode(
1070  "String \"" + codestring +
1071  "\" only consists of a sign, that is no valid PDG Code\n");
1072  }
1073  check();
1074  }
1075 
1085  inline void set_fields(std::uint32_t abscode) {
1086  /* "dump_ =" overwrites antiparticle_, but this needs to have been set
1087  * already, so we carry it around the assignment. */
1088  bool ap = digits_.antiparticle_;
1089  dump_ = abscode & 0x0fffffff;
1090  digits_.antiparticle_ = ap;
1091  int test = test_code();
1092  if (test > 0) {
1093  throw InvalidPdgCode("Invalid digits " + std::to_string(test) +
1094  " in PDG Code " + string());
1095  }
1096  check();
1097  }
1098 };
1099 
1100 static_assert(sizeof(PdgCode) == 4, "should fit into 32 bit integer");
1101 
1108 std::istream& operator>>(std::istream& is, PdgCode& code);
1114 std::ostream& operator<<(std::ostream& is, const PdgCode& code);
1115 
1117 inline bool is_dilepton(const PdgCode pdg1, const PdgCode pdg2) {
1118  const auto c1 = pdg1.code();
1119  const auto c2 = pdg2.code();
1120  const auto min = std::min(c1, c2);
1121  const auto max = std::max(c1, c2);
1122  return (max == 0x11 && min == -0x11) || (max == 0x13 && min == -0x13);
1123 }
1124 
1129 inline bool has_lepton_pair(const PdgCode pdg1, const PdgCode pdg2,
1130  const PdgCode pdg3) {
1131  return is_dilepton(pdg1, pdg2) || is_dilepton(pdg1, pdg3) ||
1132  is_dilepton(pdg2, pdg3);
1133 }
1134 
1135 } // namespace smash
1136 
1137 #endif // SRC_INCLUDE_SMASH_PDGCODE_H_
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
Definition: pdgcode.h:111
std::uint32_t quarks_
The quark digits n_q{1,2,3}_.
Definition: pdgcode.h:898
bool is_Nstar1535() const
Definition: pdgcode.h:415
std::int32_t code() const
Definition: pdgcode.h:322
bool is_omega() const
Definition: pdgcode.h:463
bool is_rho() const
Definition: pdgcode.h:469
int antiparticle_sign() const
Definition: pdgcode.h:651
PdgCode(T codenumber, typename std::enable_if_t< std::is_integral_v< T > &&4< sizeof(T), bool >=true)
The creation of PdgCode instances for nuclei that have a 10-digits code cannot be done using the inte...
Definition: pdgcode.h:220
bool operator!=(const PdgCode rhs) const
Definition: pdgcode.h:743
int nucleus_n() const
Number of neutrons in nucleus.
Definition: pdgcode.h:814
int baryon_number() const
Definition: pdgcode.h:381
bool is_meson() const
Definition: pdgcode.h:394
PdgCode(const std::uint32_t abscode)
Receive an unsigned integer and process it into a PDG Code.
Definition: pdgcode.h:158
std::uint32_t n_q1_
first quark field. 0 for mesons.
Definition: pdgcode.h:860
bool is_Sigma() const
Definition: pdgcode.h:446
PdgCode(const std::string &codestring)
Initialize using a string The string is interpreted as a hexadecimal number, i.e.,...
Definition: pdgcode.h:134
int nucleus_ap() const
Number of antiprotons in nucleus.
Definition: pdgcode.h:824
int nucleus_an() const
Number of antineutrons in nucleus.
Definition: pdgcode.h:828
int bottomness() const
Definition: pdgcode.h:557
std::array< int, 3 > quark_content() const
The return is always an array of three numbers, which are pdgcodes of quarks: 1 - d,...
Definition: pdgcode.h:671
std::uint32_t n_q3_
third quark field
Definition: pdgcode.h:856
unsigned int spin() const
Definition: pdgcode.h:608
bool is_pion() const
Definition: pdgcode.h:457
bool is_kaon() const
Definition: pdgcode.h:451
bool antiparticle_
first bit: stores the sign.
Definition: pdgcode.h:870
std::uint32_t dump() const
Dumps the bitfield into an unsigned integer.
Definition: pdgcode.h:316
std::uint32_t Z_
Definition: pdgcode.h:912
std::uint32_t n_
first field: "counter"
Definition: pdgcode.h:866
bool is_lepton() const
Definition: pdgcode.h:375
bool is_hyperon() const
Definition: pdgcode.h:428
std::uint32_t n_J_
spin quantum number .
Definition: pdgcode.h:854
bool is_nucleus() const
Definition: pdgcode.h:364
bool is_deuteron() const
Definition: pdgcode.h:475
bool is_proton() const
Definition: pdgcode.h:403
static PdgCode from_decimal(const int pdgcode_decimal)
Construct PDG code from decimal number.
Definition: pdgcode.h:342
bool is_nucleus_
Definition: pdgcode.h:915
bool is_antiparticle_of(const PdgCode rhs) const
Definition: pdgcode.h:746
std::uint32_t bool is_nucleus_
1 for nuclei, 0 for the rest
Definition: pdgcode.h:866
int charmness() const
Definition: pdgcode.h:550
int strangeness() const
Definition: pdgcode.h:543
struct smash::PdgCode::@0::@2 digits_
The single digits collection of the code.
int nucleus_p() const
Number of protons in nucleus.
Definition: pdgcode.h:810
int32_t get_decimal() const
Definition: pdgcode.h:769
bool is_baryon() const
Definition: pdgcode.h:391
void set_fields(std::uint32_t abscode)
Sets the bitfield from an unsigned integer.
Definition: pdgcode.h:1085
int isospin3() const
Definition: pdgcode.h:506
void check() const
Do all sorts of validity checks.
Definition: pdgcode.h:287
bool is_nucleon() const
Definition: pdgcode.h:397
std::string string() const
Definition: pdgcode.h:325
int test_code() const
Checks the integer for invalid hex digits.
Definition: pdgcode.h:253
PdgCode get_antiparticle() const
Construct the antiparticle to a given PDG code.
Definition: pdgcode.h:332
int nucleus_La() const
Number of Lambdas in nucleus.
Definition: pdgcode.h:820
bool is_hadron() const
Definition: pdgcode.h:370
bool operator==(const PdgCode rhs) const
Definition: pdgcode.h:740
PdgCode()
Standard initializer.
Definition: pdgcode.h:128
int nucleus_A() const
Nucleus mass number.
Definition: pdgcode.h:838
static PdgCode invalid()
PdgCode 0x0 is guaranteed not to be valid by the PDG standard, but it passes all tests here,...
Definition: pdgcode.h:758
int nucleus_aLa() const
Number of anti-Lambdas in nucleus.
Definition: pdgcode.h:834
bool operator<(const PdgCode rhs) const
Sorts PDG Codes according to their numeric value.
Definition: pdgcode.h:731
PdgCode(std::int32_t codenumber)
Receive a signed integer and process it into a PDG Code.
Definition: pdgcode.h:146
bool is_Omega() const
Definition: pdgcode.h:431
std::uint32_t A_
Definition: pdgcode.h:913
bool is_neutron() const
Definition: pdgcode.h:409
void deexcite()
Remove all excitation, except spin. Sign and quark content remains.
Definition: pdgcode.h:789
std::uint32_t n_L_
"angular momentum"
Definition: pdgcode.h:862
void set_from_string(const std::string &codestring)
Set the PDG code from the given string.
Definition: pdgcode.h:980
bool is_triton() const
Definition: pdgcode.h:481
std::uint32_t ucode() const
Definition: pdgcode.h:934
std::uint32_t n_R_
"radial excitation"
Definition: pdgcode.h:864
std::uint32_t dump_
The bitfield dumped into a single integer.
Definition: pdgcode.h:889
bool is_Delta() const
Definition: pdgcode.h:421
std::uint32_t n_Lambda_
Definition: pdgcode.h:911
double frac_strange() const
Definition: pdgcode.h:519
bool has_antiparticle() const
Definition: pdgcode.h:490
bool is_Lambda() const
Definition: pdgcode.h:441
std::uint32_t get_digit_from_char(const char inp) const
Definition: pdgcode.h:942
bool is_Xi() const
Definition: pdgcode.h:436
std::int32_t quarks() const
Definition: pdgcode.h:655
std::uint32_t I_
Definition: pdgcode.h:914
std::uint32_t n_q2_
second quark field
Definition: pdgcode.h:858
unsigned int spin_degeneracy() const
Definition: pdgcode.h:644
std::uint32_t excitation_
The excitation digits n_, n_R_, n_L_.
Definition: pdgcode.h:900
int charge() const
The charge of the particle.
Definition: pdgcode.h:567
std::ostream & operator<<(std::ostream &is, const PdgCode &code)
Writes the textual representation of the PDG code to the output stream.
Definition: pdgcode.cc:88
constexpr int pi_p
π⁺.
constexpr int rho_p
ρ⁺.
constexpr int Delta_p
Δ⁺.
constexpr int rho_m
ρ⁻.
constexpr int Delta_pp
Δ⁺⁺.
constexpr int K_p
K⁺.
constexpr int K_z
K⁰.
constexpr int p
Proton.
constexpr int omega
ω.
constexpr int N1535_z
N(1535)⁰.
constexpr int pi_z
π⁰.
constexpr int n
Neutron.
constexpr int Delta_m
Δ⁻.
constexpr int Delta_z
Δ⁰.
constexpr int rho_z
ρ⁰.
constexpr int pi_m
π⁻.
constexpr int N1535_p
N(1535)⁺.
Definition: action.h:24
bool is_dilepton(const PdgCode pdg1, const PdgCode pdg2)
Definition: pdgcode.h:1117
std::istream & operator>>(std::istream &is, PdgCode &code)
Sets the PDG code from the textual representation in the input stream.
Definition: pdgcode.cc:14
bool has_lepton_pair(const PdgCode pdg1, const PdgCode pdg2, const PdgCode pdg3)
Definition: pdgcode.h:1129
thrown for invalid inputs
Definition: pdgcode.h:117