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