30                           ParticleTypePtrList particle_types) {
    34     if (type == &mode->type()) {
    35       mode->set_weight(mode->weight() + ratio);
    40   decay_modes_.push_back(make_unique<DecayBranch>(*type, ratio));
    44                                       ParticleTypePtrList particle_types,
    46   assert(all_decay_types != 
nullptr);
    49   for (
const auto &type : *all_decay_types) {
    50     if (type->has_mother(mother) && type->has_particles(particle_types) &&
    51         type->angular_momentum() == L) {
    57   switch (particle_types.size()) {
    60                       particle_types[1]->pdgcode())) {
    61         all_decay_types->emplace_back(
    62             make_unique<TwoBodyDecayDilepton>(particle_types, L));
    63       } 
else if (particle_types[0]->is_stable() &&
    64                  particle_types[1]->is_stable()) {
    65         all_decay_types->emplace_back(
    66             make_unique<TwoBodyDecayStable>(particle_types, L));
    67       } 
else if (particle_types[0]->is_stable() ||
    68                  particle_types[1]->is_stable()) {
    69         all_decay_types->emplace_back(
    70             make_unique<TwoBodyDecaySemistable>(particle_types, L));
    72         all_decay_types->emplace_back(
    73             make_unique<TwoBodyDecayUnstable>(particle_types, L));
    78                           particle_types[1]->pdgcode(),
    79                           particle_types[2]->pdgcode())) {
    80         all_decay_types->emplace_back(
    81             make_unique<ThreeBodyDecayDilepton>(mother, particle_types, L));
    83         all_decay_types->emplace_back(
    84             make_unique<ThreeBodyDecay>(particle_types, L));
    89           "DecayModes::get_decay_type was instructed to add a decay mode "    91           std::to_string(particle_types.size()) +
    92           " particles. This is an invalid input.");
    95   return all_decay_types->back().get();
    99   const auto &log = logger<LogArea::DecayModes>();
   101   bool is_large_renormalization = 
false;
   103     sum += mode->weight();
   106     log.debug(
"Particle ", name,
   107               ": Extremely small renormalization constant: ", sum,
   108               "\n=> Skipping the renormalization.");
   110     is_large_renormalization = (std::abs(sum - 1.) > 0.01);
   111     log.debug(
"Particle ", name, 
": Renormalizing decay modes with ", sum);
   112     double new_sum = 0.0;
   113     for (
auto &mode : decay_modes_) {
   114       mode->set_weight(mode->weight() / sum);
   115       new_sum += mode->weight();
   117     log.debug(
"After renormalization sum of ratios is ", new_sum);
   119   return is_large_renormalization;
   139   int min_L = std::min(std::abs(s0 - s1 - s2), std::abs(s0 - s1 + s2));
   140   min_L = std::min(min_L, std::abs(s0 + s1 - s2));
   141   if (min_L % 2 != 0) {
   142     throw std::runtime_error(
   143         "min_angular_momentum: sum of spins should be integer");
   150       std::min(std::abs(s0 - s1 + s2 + s3), std::abs(s0 + s1 - s2 + s3));
   151   min_L = std::min(min_L, std::abs(s0 + s1 + s2 - s3));
   152   min_L = std::min(min_L, std::abs(s0 - s1 - s2 + s3));
   153   min_L = std::min(min_L, std::abs(s0 - s1 + s2 - s3));
   154   min_L = std::min(min_L, std::abs(s0 + s1 - s2 - s3));
   155   min_L = std::min(min_L, std::abs(s0 - s1 - s2 - s3));
   156   if (min_L % 2 != 0) {
   157     throw std::runtime_error(
   158         "min_angular_momentum: sum of spins should be integer");
   164   const auto &log = logger<LogArea::DecayModes>();
   167   static std::vector<DecayTypePtr> decaytypes;
   171   all_decay_types = &decaytypes;
   173   static std::vector<DecayModes> decaymodes;
   179   ParticleTypePtrList mother_states;
   180   std::vector<DecayModes> decay_modes_to_add;  
   181   int total_large_renormalized = 0;
   183   const auto end_of_decaymodes = [&]() {
   184     if (isotype_mother == 
nullptr) {  
   188     for (
size_t m = 0; m < mother_states.size(); m++) {
   189       if (decay_modes_to_add[m].
is_empty() && !mother_states[m]->is_stable()) {
   191                             mother_states[m]->name());
   193       bool is_large_renorm =
   194           decay_modes_to_add[m].renormalize(mother_states[m]->name());
   195       total_large_renormalized += is_large_renorm;
   196       PdgCode pdgcode = mother_states[m]->pdgcode();
   198       decaymodes[
find_offset(pdgcode)] = std::move(decay_modes_to_add[m]);
   202       log.debug(
"generating decay modes for anti-multiplet: " +
   203                 isotype_mother->
name());
   204       for (
const auto &state : mother_states) {
   205         PdgCode pdg = state->pdgcode();
   211           ParticleTypePtrList list = mode->particle_types();
   212           for (
auto &type : list) {
   213             if (type->has_antiparticle()) {
   214               type = type->get_antiparticle();
   217           decay_modes_anti.
add_mode(&type_anti, mode->weight(),
   218                                     mode->angular_momentum(), list);
   226   uint64_t linenumber = 1;
   228     const auto trimmed = 
trim(line.text);
   229     assert(!trimmed.empty());  
   231     if (trimmed.find_first_of(
" \t") == std::string::npos) {
   234       std::string name = 
trim(line.text);
   237       decay_modes_to_add.clear();
   238       decay_modes_to_add.resize(mother_states.size());
   239       log.debug(
"reading decay modes for " + name);
   241       for (
size_t m = 0; m < mother_states.size(); m++) {
   242         PdgCode pdgcode = mother_states[m]->pdgcode();
   245                             " in decaymodes.txt:" + std::to_string(linenumber));
   249       std::istringstream lineinput(line.text);
   250       std::vector<std::string> decay_particles;
   251       decay_particles.reserve(3);
   258         throw LoadFailure(
"Invalid angular momentum '" + std::to_string(L) +
   259                           "' in decaymodes.txt:" + std::to_string(line.number) +
   260                           ": '" + line.text + 
"'");
   267         decay_particles.emplace_back(name);
   269         const bool is_multiplet = isotype;
   271         if (!is_multiplet && !is_state) {
   274               " is neither an isospin multiplet nor a particle." + 
" (line " +
   275               std::to_string(linenumber) + 
": \"" + trimmed + 
"\")");
   277         const bool is_hadronic_multiplet =
   278             is_multiplet && isotype->get_states()[0]->is_hadron();
   279         multi &= is_hadronic_multiplet;
   283       bool is_strong_decay;
   284       const int s0 = isotype_mother->
spin();
   290         switch (decay_particles.size()) {
   296             parity = isotype_daughter_1.
parity() * isotype_daughter_2.
parity();
   297             is_strong_decay = isotype_daughter_1.
is_hadron() &&
   299             const int s1 = isotype_daughter_1.
spin();
   300             const int s2 = isotype_daughter_2.
spin();
   302             max_L = (s0 + s1 + s2) / 2;
   304             bool forbidden_by_isospin = 
true;
   305             for (
size_t m = 0; m < mother_states.size(); m++) {
   306               for (
const auto &daughter1 : isotype_daughter_1.
get_states()) {
   307                 for (
const auto &daughter2 : isotype_daughter_2.
get_states()) {
   310                       *daughter1, *daughter2, *mother_states[m]);
   314                         "decay mode generated: " + mother_states[m]->name() +
   315                         " -> " + daughter1->name() + 
" " + daughter2->name() +
   316                         " (" + std::to_string(ratio * cg_sqr) + 
")");
   317                     decay_modes_to_add[m].add_mode(mother_states[m],
   319                                                    {daughter1, daughter2});
   320                     forbidden_by_isospin = 
false;
   325             if (forbidden_by_isospin) {
   327               s << 
",\nwhere isospin mother: " << isotype_mother->
isospin()
   328                 << 
", daughters: " << isotype_daughter_1.
isospin() << 
" "   329                 << isotype_daughter_2.
isospin();
   331                                  " decay mode is forbidden by isospin: \"" +
   332                                  line.text + 
"\"" + s.str());
   343             parity = isotype_daughter_1.
parity() * isotype_daughter_2.
parity() *
   344                      isotype_daughter_3.
parity();
   345             is_strong_decay = isotype_daughter_1.
is_hadron() &&
   348             const int s1 = isotype_daughter_1.
spin();
   349             const int s2 = isotype_daughter_2.
spin();
   350             const int s3 = isotype_daughter_2.
spin();
   352             max_L = (s0 + s1 + s2 + s3) / 2;
   354             for (
size_t m = 0; m < mother_states.size(); m++) {
   355               for (
const auto &daughter1 : isotype_daughter_1.
get_states()) {
   356                 for (
const auto &daughter2 : isotype_daughter_2.
get_states()) {
   357                   for (
const auto &daughter3 :
   360                         *daughter1, *daughter2, *daughter3, *mother_states[m]);
   364                           "decay mode generated: " + mother_states[m]->name() +
   365                           " -> " + daughter1->name() + 
" " + daughter2->name() +
   366                           " " + daughter3->name() + 
" (" +
   367                           std::to_string(ratio * cg_sqr) + 
")");
   368                       decay_modes_to_add[m].add_mode(
   369                           mother_states[m], ratio * cg_sqr, L,
   370                           {daughter1, daughter2, daughter3});
   379             throw std::runtime_error(
   380                 "References to isospin multiplets only "   381                 "allowed in two-body or three-body decays: " +
   382                 line.text + 
" (line " + std::to_string(linenumber) + 
": \"" +
   388         ParticleTypePtrList types;
   391         is_strong_decay = 
true;
   392         for (
auto part : decay_particles) {
   395           } 
catch (std::runtime_error &e) {
   396             throw std::runtime_error(std::string() + e.what() + 
" (line " +
   397                                      std::to_string(linenumber) + 
": \"" +
   400           charge += types.back()->charge();
   401           parity *= types.back()->parity();
   402           is_strong_decay &= types.back()->is_hadron();
   404         if (types.size() == 2) {
   405           const int s1 = types[0]->spin();
   406           const int s2 = types[1]->spin();
   408           max_L = (s0 + s1 + s2) / 2;
   409         } 
else if (types.size() == 3) {
   410           const int s1 = types[0]->spin();
   411           const int s2 = types[1]->spin();
   412           const int s3 = types[2]->spin();
   414           max_L = (s0 + s1 + s2 + s3) / 2;
   417                              " decay mode has an invalid number of particles"   418                              " in the final state " +
   419                              "(line " + std::to_string(linenumber) + 
": \"" +
   422         bool no_decays = 
true;
   423         for (
size_t m = 0; m < mother_states.size(); m++) {
   424           if (mother_states[m]->charge() == charge) {
   425             log.debug(
"decay mode found: " + mother_states[m]->name() + 
" -> " +
   426                       std::to_string(decay_particles.size()));
   427             decay_modes_to_add[m].add_mode(mother_states[m], ratio, L, types);
   433                              " decay mode violates charge conservation " +
   434                              "(line " + std::to_string(linenumber) + 
": \"" +
   443       if (is_strong_decay && parity != mother_states[0]->parity()) {
   445                            " decay mode violates parity conservation " +
   446                            "(line " + std::to_string(linenumber) + 
": \"" +
   450       if (L < min_L || L > max_L) {
   452             mother_states[0]->name() +
   453             " decay mode violates angular momentum conservation: " +
   454             std::to_string(L) + 
" not in [" + std::to_string(min_L) + 
", " +
   455             std::to_string(max_L) + 
"] (line " + std::to_string(linenumber) +
   456             ": \"" + trimmed + 
"\")");
   466   for (
const auto &mother : particles) {
   467     if (mother.is_stable()) {
   470     const auto &decays = mother.decay_modes().decay_mode_list();
   471     for (
const auto &decay : decays) {
   472       if (mother.mass() <= decay->threshold()) {
   474         s << mother.name() << 
" →  ";
   475         for (
const auto p : decay->particle_types()) {
   478         s << 
" with " << mother.mass() << 
" ≤ " << decay->threshold();
   480             "For all decays, the minimum mass of daughters"   481             "must be smaller\nthan the mother's pole mass "   482             "(Manley-Saleski Ansatz)\n"   483             "Violated by the following decay: " +
   488   if (total_large_renormalized > 0) {
   489     log.warn(
"Branching ratios of ", total_large_renormalized,
   490              " hadrons were renormalized by more than 1% to have sum 1.");
 static const IsoParticleType & find(const std::string &name)
Returns the IsoParticleType object for the given name. 
bool renormalize(const std::string &name)
Renormalize the branching ratios to add up to 1. 
std::string trim(const std::string &s)
Strip leading and trailing whitespaces. 
static bool exists(PdgCode pdgcode)
constexpr double really_small
Numerical error tolerance. 
unsigned int spin() const 
Returns twice the spin of the multiplet. 
bool is_dilepton(const PdgCode pdg1, const PdgCode pdg2)
static void load_decaymodes(const std::string &input)
Loads the DecayModes map as described in the input string. 
Collection of useful constants that are known at compile time. 
bool has_lepton_pair(const PdgCode pdg1, const PdgCode pdg2, const PdgCode pdg3)
int isospin() const 
Returns twice the total isospin of the multiplet. 
Parity
Represent the parity of a particle type. 
static DecayType * get_decay_type(ParticleTypePtr mother, ParticleTypePtrList particle_types, int L)
Retrieve a decay type. 
PdgCode get_antiparticle() const 
Construct the antiparticle to a given PDG code. 
const DecayBranchList & decay_mode_list() const 
DecayType is the abstract base class for all decay types. 
double isospin_clebsch_gordan_sqr_3to1(const ParticleType &p_a, const ParticleType &p_b, const ParticleType &p_c, const ParticleType &Res)
Calculate the squared isospin Clebsch-Gordan coefficient for three particles p_a, p_b and p_c couplin...
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode. 
static const ParticleTypeList & list_all()
static int min_angular_momentum(int s0, int s1, int s2)
Particle type contains the static properties of a particle species. 
IsoParticleType is a class to represent isospin multiplets. 
void add_mode(ParticleTypePtr mother, double ratio, int L, ParticleTypePtrList particle_types)
Add a decay mode using all necessary information. 
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number. 
double isospin_clebsch_gordan_sqr_2to1(const ParticleType &p_a, const ParticleType &p_b, const ParticleType &Res)
Calculate the squared isospin Clebsch-Gordan coefficient for two particles p_a and p_b coupling to a ...
const std::string & name() const 
Returns the name of the multiplet. 
std::vector< DecayTypePtr > * all_decay_types
Global pointer to the decay types list. 
static const IsoParticleType * try_find(const std::string &name)
Returns the IsoParticleType pointer for the given name. 
static const ParticleTypePtr find_state(const std::string &name)
Returns the ParticleType object for the given name, by first finding the correct multiplet and then l...
DecayBranchList decay_modes_
Vector of decay modes. 
build_vector_< Line > line_parser(const std::string &input)
Helper function for parsing particles.txt and decaymodes.txt. 
bool has_anti_multiplet() const 
Check if there is a multiplet of antiparticles, which is different from the original multiplet...
ParticleTypePtrList get_states() const 
Returns list of states that form part of the multiplet. 
std::size_t find_offset(PdgCode pdg)
Passes back the address offset of a particletype in the list of all particles. 
A pointer-like interface to global references to ParticleType objects. 
The DecayModes class is used to store and update information about decay branches (i...
static std::vector< DecayModes > * all_decay_modes
A list of all DecayModes objects using the same indexing as all_particle_types. 
Line consists of a line number and the contents of that line.