10 #ifndef SRC_INCLUDE_SMASH_PDGCODE_H_
11 #define SRC_INCLUDE_SMASH_PDGCODE_H_
25 #include <type_traits>
115 using std::invalid_argument::invalid_argument;
131 explicit PdgCode(
const std::string& codestring) {
145 if (codenumber < 0) {
147 codenumber = -codenumber;
157 digits_.antiparticle_ = ((abscode & 0x80000000u) != 0);
216 template <
typename T>
218 typename std::enable_if_t<std::is_integral_v<T> && 4 <
sizeof(T),
220 :
PdgCode{std::invoke([&codenumber]() {
221 std::stringstream stream;
223 if (codenumber < 0) {
225 codenumber = -codenumber;
227 stream << sign << std::hex << codenumber;
252 if (digits_.n_ > 9) {
255 if (digits_.n_R_ > 9) {
258 if (digits_.n_L_ > 9) {
261 if (digits_.n_q1_ > 6) {
264 if (digits_.n_q2_ > 6) {
267 if (digits_.n_q3_ > 6) {
270 if (digits_.n_J_ > 15) {
287 if (baryon_number() == 0) {
289 if ((digits_.n_J_ % 2 == 0) && dump() != 0x130 && dump() != 0x310) {
291 " (meson with even n_J)");
294 if ((digits_.n_J_ % 2 != 0) || digits_.n_J_ == 0) {
296 " (baryon with odd n_J)");
300 if (digits_.n_J_ == 0 && dump() != 0x0) {
301 throw InvalidPdgCode(
"Invalid PDG code " +
string() +
" (n_J==0)");
306 if (digits_.antiparticle_ && !has_antiparticle()) {
308 " (cannot be negative)");
313 inline std::uint32_t
dump()
const {
315 return (dump_ & 0x8fffffff);
319 inline std::int32_t
code()
const {
return antiparticle_sign() * ucode(); }
323 std::stringstream ss;
331 result.
digits_.antiparticle_ = !digits_.antiparticle_;
341 if (std::abs(pdgcode_decimal) > 1E7) {
344 int a = pdgcode_decimal;
345 int hex_pdg = 0, tmp = 1;
347 hex_pdg += (a % 10) * tmp;
362 assert(digits_.is_nucleus_ == nucleus_.is_nucleus_);
363 return nucleus_.is_nucleus_;
368 return (digits_.n_q3_ != 0 && digits_.n_q2_ != 0 && !is_nucleus());
373 return (digits_.n_q1_ == 0 && digits_.n_q2_ == 0 && digits_.n_q3_ == 1 &&
379 return (is_lepton() && digits_.n_J_ % 2 == 0);
384 return is_meson() && digits_.n_q2_ == 4 && digits_.n_q3_ == 4;
390 return static_cast<int>(nucleus_.A_) * antiparticle_sign();
392 if (!is_hadron() || digits_.n_q1_ == 0) {
395 return antiparticle_sign();
398 inline bool is_baryon()
const {
return is_hadron() && digits_.n_q1_ != 0; }
401 inline bool is_meson()
const {
return is_hadron() && digits_.n_q1_ == 0; }
405 const auto abs_code = std::abs(code());
411 const auto abs_code = std::abs(code());
412 return (abs_code ==
pdg::p);
417 const auto abs_code = std::abs(code());
418 return (abs_code ==
pdg::n);
423 const auto abs_code = std::abs(code());
429 const auto abs_code = std::abs(code());
435 inline bool is_hyperon()
const {
return is_hadron() && digits_.n_q1_ == 3; }
439 return is_hyperon() && digits_.n_q2_ == 3 && digits_.n_q3_ == 3;
444 return is_hyperon() && digits_.n_q2_ == 3 && digits_.n_q3_ != 3;
449 return is_hyperon() && digits_.n_q2_ == 1 && digits_.n_q3_ == 2;
454 return is_hyperon() && digits_.n_q2_ != 3 && !is_Lambda();
459 const auto abs_code = std::abs(code());
466 const auto abs_code = std::abs(code());
472 const auto c = code();
484 const auto c = code();
490 const auto abs_code = std::abs(code());
499 const auto abs_code = std::abs(code());
505 return is_nucleus() && nucleus_.A_ == 2 && nucleus_.Z_ == 1 &&
506 nucleus_.n_Lambda_ == 0 && nucleus_.I_ == 0;
511 return is_nucleus() && nucleus_.A_ == 3 && nucleus_.Z_ == 1 &&
512 nucleus_.n_Lambda_ == 0 && nucleus_.I_ == 0;
524 return (baryon_number() != 0) || (digits_.n_q2_ != digits_.n_q3_);
526 return digits_.n_q3_ == 1;
538 return net_quark_number(2) - net_quark_number(1);
550 return std::abs(strangeness()) / 3.;
551 }
else if (is_meson()) {
554 if (digits_.n_q3_ == 3 && digits_.n_q2_ == 3) {
557 return std::abs(strangeness()) / 2.;
575 return std::abs(charmness()) / 3.;
576 }
else if (is_meson()) {
579 if (digits_.n_q3_ == 4 && digits_.n_q2_ == 4) {
582 return std::abs(charmness()) / 2.;
600 return std::abs(bottomness()) / 3.;
601 }
else if (is_meson()) {
604 if (digits_.n_q3_ == 5 && digits_.n_q2_ == 5) {
607 return std::abs(bottomness()) / 2.;
618 return (frac_charm() != 0) || (frac_bottom() != 0);
633 inline int charmness()
const {
return +net_quark_number(4); }
640 inline int bottomness()
const {
return -net_quark_number(5); }
651 if (is_hadron() || is_nucleus()) {
658 for (
int i = 1; i < 7; i++) {
661 Q += (i % 2 == 0 ? 2 : -1) * net_quark_number(i);
668 if (digits_.n_q3_ == 1) {
669 return -1 * (digits_.n_J_ % 2) * antiparticle_sign();
675 if ((dump_ & 0x0000ffff) == 0x24) {
676 return antiparticle_sign();
691 inline unsigned int spin()
const {
696 if (nucleus_.A_ == 2) {
699 }
else if (nucleus_.A_ == 3) {
704 }
else if (nucleus_.A_ == 4) {
708 throw std::runtime_error(
"Unknown spin of nucleus.");
714 if (digits_.n_J_ == 0) {
717 return digits_.n_J_ - 1;
724 return digits_.n_q3_;
728 if (is_hadron() && digits_.n_J_ > 0) {
735 return (digits_.antiparticle_ ? -1 : +1);
739 if (!is_hadron() || is_nucleus()) {
742 return chunks_.quarks_;
755 std::array<int, 3> result = {
static_cast<int>(digits_.n_q1_),
756 static_cast<int>(digits_.n_q2_),
757 static_cast<int>(digits_.n_q3_)};
760 if (digits_.n_q1_ != 0 && digits_.antiparticle_) {
761 for (
size_t i = 0; i < 3; i++) {
762 result[i] = -result[i];
766 if (digits_.n_q1_ == 0) {
768 if (digits_.n_q2_ == digits_.n_q3_) {
769 result[2] = -result[2];
772 if (digits_.antiparticle_) {
773 result[1] = -result[1];
776 result[2] = -result[2];
780 if (digits_.n_q2_ != digits_.n_q3_ && digits_.n_q2_ % 2 == 1) {
781 for (
int i = 1; i <= 2; i++) {
782 result[i] = -result[i];
802 bool contains_enough_valence_quarks(
int valence_quarks_required)
const;
815 return dump_ < rhs.
dump_;
830 return code() == -rhs.
code();
855 return antiparticle_sign() *
856 (nucleus_.I_ + 10 * nucleus_.A_ + 10000 * nucleus_.Z_ +
857 10000000 * nucleus_.n_Lambda_ + 1000000000);
860 int n_J_2 = digits_.n_J_;
865 return antiparticle_sign() *
866 (n_J_2 + digits_.n_q3_ * 10 + digits_.n_q2_ * 100 +
867 digits_.n_q1_ * 1000 + digits_.n_L_ * 10000 +
868 digits_.n_R_ * 100000 + digits_.n_ * 1000000 + n_J_1 * 10000000);
874 chunks_.excitation_ = 0;
900 bool contains_quark(
int quark)
const;
912 int net_quark_number(
const int quark)
const;
916 return (is_nucleus() && !nucleus_.antiparticle_) ? nucleus_.Z_ : 0;
920 return (is_nucleus() && !nucleus_.antiparticle_)
921 ? nucleus_.A_ - nucleus_.Z_ - nucleus_.n_Lambda_
926 return (is_nucleus() && !nucleus_.antiparticle_) ? nucleus_.n_Lambda_ : 0;
930 return (is_nucleus() && nucleus_.antiparticle_) ? nucleus_.Z_ : 0;
934 return (is_nucleus() && nucleus_.antiparticle_)
935 ? nucleus_.A_ - nucleus_.Z_ - nucleus_.n_Lambda_
940 return (is_nucleus() && nucleus_.antiparticle_) ? nucleus_.n_Lambda_ : 0;
943 int nucleus_A()
const {
return is_nucleus() ? nucleus_.A_ : 0; }
957 #if defined(LITTLE_ENDIAN_ARCHITECTURE) || defined(DOXYGEN)
971 std::uint32_t
n_ : 4, : 2;
976 #elif defined(BIG_ENDIAN_ARCHITECTURE)
977 bool antiparticle_ : 1;
978 bool is_nucleus_ : 1, : 2;
979 std::uint32_t n_ : 4;
980 std::uint32_t n_R_ : 4;
981 std::uint32_t n_L_ : 4;
982 std::uint32_t n_q1_ : 4;
983 std::uint32_t n_q2_ : 4;
984 std::uint32_t n_q3_ : 4;
985 std::uint32_t n_J_ : 4;
987 #error Endianness macro of the machine not defined.
1000 #if defined(LITTLE_ENDIAN_ARCHITECTURE) || defined(DOXYGEN)
1006 #elif defined(BIG_ENDIAN_ARCHITECTURE)
1007 std::uint32_t : 4, excitation_ : 12;
1008 std::uint32_t quarks_ : 12, : 4;
1010 #error Endianness macro of the machine not defined.
1015 #if defined(LITTLE_ENDIAN_ARCHITECTURE) || defined(DOXYGEN)
1021 bool antiparticle_ : 1;
1022 #elif defined(BIG_ENDIAN_ARCHITECTURE)
1023 bool antiparticle_ : 1;
1024 bool is_nucleus_ : 1;
1025 std::uint32_t I_ : 4;
1026 std::uint32_t A_ : 10;
1027 std::uint32_t Z_ : 10;
1028 std::uint32_t n_Lambda_ : 6;
1030 #error Endianness macro of the machine not defined.
1039 inline std::uint32_t
ucode()
const {
return (dump_ & 0x0fffffff); }
1049 if (48 <= inp && inp <= 57) {
1053 if (65 <= inp && inp <= 70) {
1054 return inp - 65 + 10;
1057 if (97 <= inp && inp <= 102) {
1058 return inp - 97 + 10;
1060 throw InvalidPdgCode(
"PdgCode: Invalid character " + std::string(&inp, 1) +
1088 digits_.n_ = digits_.n_R_ = digits_.n_L_ = digits_.n_q1_ = digits_.n_q2_ =
1089 digits_.n_q3_ = digits_.n_J_ = digits_.is_nucleus_ = 0;
1090 size_t length = codestring.size();
1092 throw InvalidPdgCode(
"Empty string does not contain PDG Code\n");
1097 if (codestring[c] ==
'-') {
1098 digits_.antiparticle_ =
true;
1100 }
else if (codestring[c] ==
'+') {
1101 digits_.antiparticle_ =
false;
1105 unsigned int sign = c;
1108 if (length == 10 + sign) {
1109 nucleus_.is_nucleus_ =
true;
1110 if (codestring[c] !=
'1' || codestring[c + 1] !=
'0') {
1112 "\" should start with 10\n");
1116 std::array<int, 8> digits;
1117 for (
int i = 0; i < 8; i++) {
1118 digits[i] = get_digit_from_char(codestring[c + i]);
1120 nucleus_.n_Lambda_ = digits[0];
1121 nucleus_.Z_ = 100 * digits[1] + 10 * digits[2] + digits[3];
1122 nucleus_.A_ = 100 * digits[4] + 10 * digits[5] + digits[6];
1123 nucleus_.I_ = digits[7];
1128 if (length > 8 + sign) {
1130 "\" too long for PDG Code\n");
1134 if (length > 7 + sign) {
1135 digits_.n_J_ += get_digit_from_char(codestring[c++]);
1138 if (length > 6 + sign) {
1139 digits_.n_ = get_digit_from_char(codestring[c++]);
1142 if (length > 5 + sign) {
1143 digits_.n_R_ = get_digit_from_char(codestring[c++]);
1146 if (length > 4 + sign) {
1147 digits_.n_L_ = get_digit_from_char(codestring[c++]);
1150 if (length > 3 + sign) {
1151 digits_.n_q1_ = get_digit_from_char(codestring[c++]);
1152 if (digits_.n_q1_ > 6) {
1153 throw InvalidPdgCode(
"Invalid PDG code " + codestring +
" (n_q1>6)");
1157 if (length > 2 + sign) {
1158 digits_.n_q2_ = get_digit_from_char(codestring[c++]);
1159 if (digits_.n_q2_ > 6) {
1160 throw InvalidPdgCode(
"Invalid PDG code " + codestring +
" (n_q2>6)");
1164 if (length > 1 + sign) {
1165 digits_.n_q3_ = get_digit_from_char(codestring[c++]);
1166 if (digits_.n_q3_ > 6) {
1167 throw InvalidPdgCode(
"Invalid PDG code " + codestring +
" (n_q3>6)");
1171 if (length > sign) {
1172 digits_.n_J_ += get_digit_from_char(codestring[c++]);
1175 "String \"" + codestring +
1176 "\" only consists of a sign, that is no valid PDG Code\n");
1193 bool ap = digits_.antiparticle_;
1194 dump_ = abscode & 0x0fffffff;
1195 digits_.antiparticle_ = ap;
1196 int test = test_code();
1199 " in PDG Code " +
string());
1205 static_assert(
sizeof(PdgCode) == 4,
"should fit into 32 bit integer");
1213 std::istream&
operator>>(std::istream& is, PdgCode& code);
1219 std::ostream&
operator<<(std::ostream& is,
const PdgCode& code);
1223 const auto c1 = pdg1.
code();
1224 const auto c2 = pdg2.
code();
1225 const auto min = std::min(c1, c2);
1226 const auto max = std::max(c1, c2);
1227 return (max == 0x11 && min == -0x11) || (max == 0x13 && min == -0x13) ||
1228 (max == 0x12 && min == -0x11) || (max == 0x11 && min == -0x12);
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
std::uint32_t quarks_
The quark digits n_q{1,2,3}_.
bool is_Nstar1535() const
std::int32_t code() const
int antiparticle_sign() const
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...
bool operator!=(const PdgCode rhs) const
int nucleus_n() const
Number of neutrons in nucleus.
int baryon_number() const
PdgCode(const std::uint32_t abscode)
Receive an unsigned integer and process it into a PDG Code.
std::uint32_t n_q1_
first quark field. 0 for mesons.
bool is_charmonia() const
bool is_Dstar2007() const
PdgCode(const std::string &codestring)
Initialize using a string The string is interpreted as a hexadecimal number, i.e.,...
int nucleus_ap() const
Number of antiprotons in nucleus.
int nucleus_an() const
Number of antineutrons in nucleus.
std::array< int, 3 > quark_content() const
The return is always an array of three numbers, which are pdgcodes of quarks: 1 - d,...
std::uint32_t n_q3_
third quark field
unsigned int spin() const
bool antiparticle_
first bit: stores the sign.
bool is_Sigmastar() const
std::uint32_t dump() const
Dumps the bitfield into an unsigned integer.
std::uint32_t n_
first field: "counter"
double frac_charm() const
std::uint32_t n_J_
spin quantum number .
static PdgCode from_decimal(const int pdgcode_decimal)
Construct PDG code from decimal number.
bool is_antiparticle_of(const PdgCode rhs) const
std::uint32_t bool is_nucleus_
1 for nuclei, 0 for the rest
struct smash::PdgCode::@0::@2 digits_
The single digits collection of the code.
int nucleus_p() const
Number of protons in nucleus.
int32_t get_decimal() const
void set_fields(std::uint32_t abscode)
Sets the bitfield from an unsigned integer.
void check() const
Do all sorts of validity checks.
std::string string() const
int test_code() const
Checks the integer for invalid hex digits.
PdgCode get_antiparticle() const
Construct the antiparticle to a given PDG code.
int nucleus_La() const
Number of Lambdas in nucleus.
double frac_bottom() const
bool operator==(const PdgCode rhs) const
PdgCode()
Standard initializer.
int nucleus_A() const
Nucleus mass number.
static PdgCode invalid()
PdgCode 0x0 is guaranteed not to be valid by the PDG standard, but it passes all tests here,...
int nucleus_aLa() const
Number of anti-Lambdas in nucleus.
bool operator<(const PdgCode rhs) const
Sorts PDG Codes according to their numeric value.
PdgCode(std::int32_t codenumber)
Receive a signed integer and process it into a PDG Code.
void deexcite()
Remove all excitation, except spin. Sign and quark content remains.
std::uint32_t n_L_
"angular momentum"
void set_from_string(const std::string &codestring)
Set the PDG code from the given string.
std::uint32_t ucode() const
std::uint32_t n_R_
"radial excitation"
std::uint32_t dump_
The bitfield dumped into a single integer.
double frac_strange() const
bool has_antiparticle() const
std::uint32_t get_digit_from_char(const char inp) const
bool is_heavy_flavor() const
std::int32_t quarks() const
std::uint32_t n_q2_
second quark field
unsigned int spin_degeneracy() const
std::uint32_t excitation_
The excitation digits n_, n_R_, n_L_.
int charge() const
The charge of the particle.
std::ostream & operator<<(std::ostream &is, const PdgCode &code)
Writes the textual representation of the PDG code to the output stream.
constexpr int Delta_pp
Δ⁺⁺.
constexpr int Dstar_p
D*(2010)⁺.
constexpr int Sigma_star_z
Σ*⁰
constexpr int N1535_z
N(1535)⁰.
constexpr int Sigma_star_p
Σ*⁺
constexpr int Sigma_star_m
Σ*⁻
constexpr int N1535_p
N(1535)⁺.
constexpr int Dstar_z
D*(2007)⁰.
bool is_dilepton(const PdgCode pdg1, const PdgCode pdg2)
std::istream & operator>>(std::istream &is, PdgCode &code)
Sets the PDG code from the textual representation in the input stream.
bool has_lepton_pair(const PdgCode pdg1, const PdgCode pdg2, const PdgCode pdg3)
std::string to_string(ThermodynamicQuantity quantity)
Convert a ThermodynamicQuantity enum value to its corresponding string.
thrown for invalid inputs