Version: SMASH-3.1
particletype.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2020,2022-2023
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/particletype.h"
11 
12 #include <assert.h>
13 
14 #include <algorithm>
15 #include <map>
16 #include <vector>
17 
18 #include "smash/constants.h"
19 #include "smash/decaymodes.h"
20 #include "smash/distributions.h"
21 #include "smash/formfactors.h"
22 #include "smash/inputfunctions.h"
23 #include "smash/integrate.h"
24 #include "smash/iomanipulators.h"
25 #include "smash/isoparticletype.h"
26 #include "smash/logging.h"
28 #include "smash/stringfunctions.h"
29 
30 namespace smash {
31 static constexpr int LParticleType = LogArea::ParticleType::id;
32 static constexpr int LResonances = LogArea::Resonances::id;
33 
34 namespace {
36 const ParticleTypeList *all_particle_types = nullptr;
38 ParticleTypePtrList nucleons_list;
40 ParticleTypePtrList anti_nucs_list;
42 ParticleTypePtrList deltas_list;
44 ParticleTypePtrList anti_deltas_list;
46 ParticleTypePtrList baryon_resonances_list;
48 ParticleTypePtrList light_nuclei_list;
49 } // unnamed namespace
50 
51 const ParticleTypeList &ParticleType::list_all() {
52  assert(all_particle_types);
53  return *all_particle_types;
54 }
55 
56 // For performance reasons one might want to inline this function.
58  // Calculate the offset via pointer subtraction:
59  const auto offset = this - std::addressof(list_all()[0]);
60  // Since we're using uint16_t for storing the index better be safe than sorry:
61  // The offset must fit into the data type. If this ever fails we got a lot
62  // more particle types than initially expected and you have to increase the
63  // ParticleTypePtr storage to uint32_t.
64  assert(offset >= 0 && offset < 0xffff);
65  // After the assertion above the down-cast to uint16_t is safe:
66  return ParticleTypePtr(static_cast<uint16_t>(offset));
67 }
68 
69 ParticleTypePtrList &ParticleType::list_nucleons() { return nucleons_list; }
70 
71 ParticleTypePtrList &ParticleType::list_anti_nucleons() {
72  return anti_nucs_list;
73 }
74 
75 ParticleTypePtrList &ParticleType::list_Deltas() { return deltas_list; }
76 
77 ParticleTypePtrList &ParticleType::list_anti_Deltas() {
78  return anti_deltas_list;
79 }
80 
81 ParticleTypePtrList &ParticleType::list_baryon_resonances() {
83 }
84 
85 ParticleTypePtrList &ParticleType::list_light_nuclei() {
86  return light_nuclei_list;
87 }
88 
90  const auto found = std::lower_bound(
92  [](const ParticleType &l, const PdgCode &r) { return l.pdgcode() < r; });
93  if (found == all_particle_types->end() || found->pdgcode() != pdgcode) {
94  return {}; // The default constructor creates an invalid pointer.
95  }
96  return &*found;
97 }
98 
100  const auto found = ParticleType::try_find(pdgcode);
101  if (!found) {
102  throw PdgNotFoundFailure("PDG code " + pdgcode.string() + " not found!");
103  }
104  return *found;
105 }
106 
108  const auto found = ParticleType::try_find(pdgcode);
109  return found;
110 }
111 
112 bool ParticleType::exists(const std::string &name) {
113  const auto found =
114  std::find_if(all_particle_types->begin(), all_particle_types->end(),
115  [&](const ParticleType &p) { return p.name() == name; });
116  if (found == all_particle_types->end()) {
117  return false;
118  }
119  return true;
120 }
121 
122 ParticleType::ParticleType(std::string n, double m, double w, Parity p,
123  PdgCode id)
124  : name_(n),
125  mass_(m),
126  width_(w),
127  parity_(p),
128  pdgcode_(id),
129  min_mass_kinematic_(-1.),
130  min_mass_spectral_(-1.),
131  charge_(pdgcode_.charge()),
132  isospin_(-1),
133  I3_(pdgcode_.isospin3()) {}
134 
143 static std::string antiname(const std::string &name, PdgCode code) {
144  std::string basename, charge;
145 
146  if (name.find("⁺⁺") != std::string::npos) {
147  basename = name.substr(0, name.length() - sizeof("⁺⁺") + 1);
148  charge = "⁻⁻";
149  } else if (name.find("⁺") != std::string::npos) {
150  basename = name.substr(0, name.length() - sizeof("⁺") + 1);
151  charge = "⁻";
152  } else if (name.find("⁻⁻") != std::string::npos) {
153  basename = name.substr(0, name.length() - sizeof("⁻⁻") + 1);
154  charge = "⁺⁺";
155  } else if (name.find("⁻") != std::string::npos) {
156  basename = name.substr(0, name.length() - sizeof("⁻") + 1);
157  charge = "⁺";
158  } else if (name.find("⁰") != std::string::npos) {
159  basename = name.substr(0, name.length() - sizeof("⁰") + 1);
160  charge = "⁰";
161  } else {
162  basename = name;
163  charge = "";
164  }
165 
166  // baryons & strange mesons: insert a bar
167  if (code.baryon_number() != 0 || code.strangeness() != 0) {
168  constexpr char bar[] = "\u0305";
169  basename.insert(utf8::sequence_length(basename.begin()), bar);
170  }
171 
172  return basename + charge;
173 }
174 
182 static std::string chargestr(int charge) {
183  switch (charge) {
184  case 2:
185  return "⁺⁺";
186  case 1:
187  return "⁺";
188  case 0:
189  return "⁰";
190  case -1:
191  return "⁻";
192  case -2:
193  return "⁻⁻";
194  default:
195  throw std::runtime_error("Invalid charge " + std::to_string(charge));
196  }
197 }
198 
199 void ParticleType::create_type_list(const std::string &input) { // {{{
200  static ParticleTypeList type_list;
201  type_list.clear(); // in case LoadFailure was thrown and caught and we should
202  // try again
203  for (const Line &line : line_parser(input)) {
204  std::istringstream lineinput(line.text);
205  std::string name;
206  double mass, width;
207  std::string parity_string;
208  std::vector<std::string> pdgcode_strings;
209  // We expect at most 4 PDG codes per multiplet.
210  pdgcode_strings.reserve(4);
211  lineinput >> name >> mass >> width >> parity_string;
212  Parity parity;
213  bool fail = false;
214  if (parity_string == "+") {
216  } else if (parity_string == "-") {
218  } else {
219  fail = true;
220  }
221  if (lineinput.fail() || fail) {
223  "While loading the ParticleType data:\nFailed to convert the input "
224  "string to the expected data types.",
225  line));
226  }
227  // read additional PDG codes (if present)
228  while (!lineinput.eof()) {
229  pdgcode_strings.push_back("");
230  lineinput >> pdgcode_strings.back();
231  if (lineinput.fail()) {
233  "While loading the ParticleType data:\nFailed to convert the input "
234  "string to the expected data types.",
235  line));
236  }
237  }
238  if (pdgcode_strings.size() < 1) {
240  "While loading the ParticleType data:\nFailed to convert the input "
241  "string due to missing PDG code.",
242  line));
243  }
244  std::vector<PdgCode> pdgcode;
245  pdgcode.resize(pdgcode_strings.size());
246  std::transform(pdgcode_strings.begin(), pdgcode_strings.end(),
247  pdgcode.begin(),
248  [](const std::string &s) { return PdgCode(s); });
249  ensure_all_read(lineinput, line);
250 
251  // Check if provided masses are the same as hardcoded ones, if present
253  throw std::runtime_error("Nucleon mass in input file different from " +
254  std::to_string(nucleon_mass));
255  }
256  if (pdgcode[0].is_pion() && !almost_equal(mass, pion_mass)) {
257  throw std::runtime_error("Pion mass in input file different from " +
258  std::to_string(pion_mass));
259  }
260  if (pdgcode[0].is_kaon() && !almost_equal(mass, kaon_mass)) {
261  throw std::runtime_error("Kaon mass in input file different from " +
262  std::to_string(kaon_mass));
263  }
264  if (pdgcode[0].is_omega() && !almost_equal(mass, omega_mass)) {
265  throw std::runtime_error("Omega mass in input file different from " +
266  std::to_string(omega_mass));
267  }
268  if (pdgcode[0].is_Delta() && !almost_equal(mass, delta_mass)) {
269  throw std::runtime_error("Delta mass in input file different from " +
270  std::to_string(delta_mass));
271  }
273  throw std::runtime_error("Deuteron mass in input file different from " +
274  std::to_string(deuteron_mass));
275  }
276 
277  // add all states to type list
278  for (size_t i = 0; i < pdgcode.size(); i++) {
279  std::string full_name = name;
280  if (pdgcode.size() > 1) {
281  // for multiplets: add charge string to name
282  full_name += chargestr(pdgcode[i].charge());
283  }
284  type_list.emplace_back(full_name, mass, width, parity, pdgcode[i]);
285  logg[LParticleType].debug()
286  << "Setting particle type: " << type_list.back();
287  if (pdgcode[i].has_antiparticle()) {
288  /* add corresponding antiparticle */
289  PdgCode anti = pdgcode[i].get_antiparticle();
290  // For bosons the parity does not change, for fermions it gets inverted.
291  const auto anti_parity = (anti.spin() % 2 == 0) ? parity : -parity;
292  full_name = antiname(full_name, pdgcode[i]);
293  type_list.emplace_back(full_name, mass, width, anti_parity, anti);
294  logg[LParticleType].debug()
295  << "Setting antiparticle type: " << type_list.back();
296  }
297  }
298  }
299  type_list.shrink_to_fit();
300 
301  /* Sort the type list by PDG code. */
302  std::sort(type_list.begin(), type_list.end());
303 
304  /* Look for duplicates. */
305  PdgCode prev_pdg = 0;
306  for (const auto &t : type_list) {
307  if (t.pdgcode() == prev_pdg) {
308  throw ParticleType::LoadFailure("Duplicate PdgCode in particles.txt: " +
309  t.pdgcode().string());
310  }
311  prev_pdg = t.pdgcode();
312  }
313 
314  if (all_particle_types != nullptr) {
315  throw std::runtime_error("Error: Type list was already built!");
316  }
317  all_particle_types = &type_list; // note that type_list is a function-local
318  // static and thus will live on until after
319  // main().
320 
321  // create all isospin multiplets
322  for (const auto &t : type_list) {
324  }
325  // link the multiplets to the types
326  for (auto &t : type_list) {
327  t.iso_multiplet_ = IsoParticleType::find(t);
328  }
329 
330  // Create nucleons/anti-nucleons list
331  if (IsoParticleType::exists("N")) {
332  for (const auto &state : IsoParticleType::find("N").get_states()) {
333  nucleons_list.push_back(state);
334  anti_nucs_list.push_back(state->get_antiparticle());
335  }
336  }
337 
338  // Create deltas list
339  if (IsoParticleType::exists("Δ")) {
340  for (const auto &state : IsoParticleType::find("Δ").get_states()) {
341  deltas_list.push_back(state);
342  anti_deltas_list.push_back(state->get_antiparticle());
343  }
344  }
345 
346  // Create baryon resonances list
347  for (const ParticleType &type_resonance : ParticleType::list_all()) {
348  /* Only loop over baryon resonances. */
349  if (type_resonance.is_stable() ||
350  type_resonance.pdgcode().baryon_number() != 1) {
351  continue;
352  }
353  baryon_resonances_list.push_back(&type_resonance);
354  baryon_resonances_list.push_back(type_resonance.get_antiparticle());
355  }
356 
357  for (const ParticleType &type : ParticleType::list_all()) {
358  if (type.is_nucleus()) {
359  light_nuclei_list.push_back(&type);
360  }
361  }
362 } /*}}}*/
363 
365  if (unlikely(min_mass_kinematic_ < 0.)) {
366  /* If the particle is stable, min. mass is just the mass. */
368  /* Otherwise, find the lowest mass value needed in any decay mode */
369  if (!is_stable()) {
370  for (const auto &mode : decay_modes().decay_mode_list()) {
371  min_mass_kinematic_ = std::min(min_mass_kinematic_, mode->threshold());
372  }
373  }
374  }
375  return min_mass_kinematic_;
376 }
377 
379  if (unlikely(min_mass_spectral_ < 0.)) {
380  /* If the particle is stable or it has a non-zero spectral function value at
381  * the minimum mass that is allowed by kinematics, min_mass_spectral is just
382  * the min_mass_kinetic. */
384  /* Otherwise, find the lowest mass value where spectral function has a
385  * non-zero value by bisection.*/
386  if (!is_stable() &&
388  // find a right bound that has non-zero spectral function for bisection
389  const double m_step = 0.01;
390  double right_bound_bis;
391  for (unsigned int i = 0;; i++) {
392  right_bound_bis = min_mass_kinematic() + m_step * i;
393  if (this->spectral_function(right_bound_bis) > really_small) {
394  break;
395  }
396  }
397  // bisection
398  const double precision = 1E-6;
399  double left_bound_bis = right_bound_bis - m_step;
400  while (right_bound_bis - left_bound_bis > precision) {
401  const double mid = (left_bound_bis + right_bound_bis) / 2.0;
402  if (this->spectral_function(mid) > really_small) {
403  right_bound_bis = mid;
404  } else {
405  left_bound_bis = mid;
406  }
407  }
408  min_mass_spectral_ = right_bound_bis;
409  }
410  }
411  return min_mass_spectral_;
412 }
413 
415  if (isospin_ < 0) {
418  : 0;
419  }
420  return isospin_;
421 }
422 
423 double ParticleType::partial_width(const double m,
424  const DecayBranch *mode) const {
425  if (m < mode->threshold()) {
426  return 0.;
427  }
428  double partial_width_at_pole = width_at_pole() * mode->weight();
429  return mode->type().width(mass(), partial_width_at_pole, m);
430 }
431 
433  const auto offset = this - std::addressof(list_all()[0]);
434  const auto &modes = (*DecayModes::all_decay_modes)[offset];
435  assert(is_stable() || !modes.is_empty());
436  return modes;
437 }
438 
439 double ParticleType::total_width(const double m) const {
440  double w = 0.;
441  if (is_stable()) {
442  return w;
443  }
444  /* Loop over decay modes and sum up all partial widths. */
445  const auto &modes = decay_modes().decay_mode_list();
446  for (unsigned int i = 0; i < modes.size(); i++) {
447  w = w + partial_width(m, modes[i].get());
448  }
449  if (w < width_cutoff) {
450  return 0.;
451  }
452  return w;
453 }
454 
456  for (const ParticleType &ptype : ParticleType::list_all()) {
457  if (!ptype.is_stable() && ptype.decay_modes().is_empty()) {
458  throw std::runtime_error(
459  "Unstable particle " + ptype.name() +
460  " has no decay chanels! Either add one to it in decaymodes file or "
461  "set it's width to 0 in particles file.");
462  }
463  if (ptype.is_dprime() && !ParticleType::try_find(pdg::deuteron)) {
464  throw std::runtime_error(
465  "d' cannot be used without deuteron. Modify input particles file "
466  "accordingly.");
467  }
468  }
469 }
470 
472  WhichDecaymodes wh) const {
473  switch (wh) {
474  case WhichDecaymodes::All: {
475  return true;
476  }
478  return !t.is_dilepton_decay();
479  }
481  return t.is_dilepton_decay();
482  }
483  default:
484  throw std::runtime_error(
485  "Problem in selecting decaymodes in wanted_decaymode()");
486  }
487 }
488 
490  const ThreeVector x,
491  WhichDecaymodes wh) const {
492  const auto &decay_mode_list = decay_modes().decay_mode_list();
493  /* Determine whether the decay is affected by the potentials. If it's
494  * affected, read the values of the potentials at the position of the
495  * particle */
496  FourVector UB = FourVector();
497  FourVector UI3 = FourVector();
498  if (UB_lat_pointer != nullptr) {
499  UB_lat_pointer->value_at(x, UB);
500  }
501  if (UI3_lat_pointer != nullptr) {
502  UI3_lat_pointer->value_at(x, UI3);
503  }
504  /* Loop over decay modes and calculate all partial widths. */
505  DecayBranchList partial;
506  partial.reserve(decay_mode_list.size());
507  for (unsigned int i = 0; i < decay_mode_list.size(); i++) {
508  /* Calculate the sqare root s of the final state particles. */
509  const auto FinalTypes = decay_mode_list[i]->type().particle_types();
510  double scale_B = 0.0;
511  double scale_I3 = 0.0;
512  if (pot_pointer != nullptr) {
513  scale_B += pot_pointer->force_scale(*this).first;
514  scale_I3 += pot_pointer->force_scale(*this).second * isospin3_rel();
515  for (const auto &finaltype : FinalTypes) {
516  scale_B -= pot_pointer->force_scale(*finaltype).first;
517  scale_I3 -= pot_pointer->force_scale(*finaltype).second *
518  finaltype->isospin3_rel();
519  }
520  }
521  double sqrt_s = (p + UB * scale_B + UI3 * scale_I3).abs();
522 
523  const double w = partial_width(sqrt_s, decay_mode_list[i].get());
524  if (w > 0.) {
525  if (wanted_decaymode(decay_mode_list[i]->type(), wh)) {
526  partial.push_back(
527  std::make_unique<DecayBranch>(decay_mode_list[i]->type(), w));
528  }
529  }
530  }
531  return partial;
532 }
533 
534 double ParticleType::get_partial_width(const double m,
535  const ParticleTypePtrList dlist) const {
536  /* Get all decay modes. */
537  const auto &decaymodes = decay_modes().decay_mode_list();
538 
539  /* Find the right one(s) and add up corresponding widths. */
540  double w = 0.;
541  for (const auto &mode : decaymodes) {
542  double partial_width_at_pole = width_at_pole() * mode->weight();
543  if (mode->type().has_particles(dlist)) {
544  w += mode->type().width(mass(), partial_width_at_pole, m);
545  }
546  }
547  return w;
548 }
549 
551  const ParticleData &p_a,
552  const ParticleData &p_b) const {
553  /* Get all decay modes. */
554  const auto &decaymodes = decay_modes().decay_mode_list();
555 
556  /* Find the right one(s) and add up corresponding widths. */
557  double w = 0.;
558  for (const auto &mode : decaymodes) {
559  double partial_width_at_pole = width_at_pole() * mode->weight();
560  const ParticleTypePtrList l = {&p_a.type(), &p_b.type()};
561  if (mode->type().has_particles(l)) {
562  w += mode->type().in_width(mass(), partial_width_at_pole, m,
563  p_a.effective_mass(), p_b.effective_mass());
564  }
565  }
566  return w;
567 }
568 
569 double ParticleType::spectral_function(double m) const {
570  if (norm_factor_ < 0.) {
571  /* Initialize the normalization factor
572  * by integrating over the unnormalized spectral function. */
573  static /*thread_local (see #3075)*/ Integrator integrate;
574  const double width = width_at_pole();
575  const double m_pole = mass();
576  // We transform the integral using m = m_min + width_pole * tan(x), to
577  // make it definite and to avoid numerical issues.
578  const double x_min = std::atan((min_mass_kinematic() - m_pole) / width);
579  norm_factor_ = 1. / integrate(x_min, M_PI / 2., [&](double x) {
580  const double tanx = std::tan(x);
581  const double m_x = m_pole + width * tanx;
582  const double jacobian = width * (1.0 + tanx * tanx);
583  return spectral_function_no_norm(m_x) * jacobian;
584  });
585  }
587 }
588 
590  /* The spectral function is a relativistic Breit-Wigner function
591  * with mass-dependent width. Here: without normalization factor. */
592  const double resonance_width = total_width(m);
593  if (resonance_width < ParticleType::width_cutoff) {
594  return 0.;
595  }
596  return breit_wigner(m, mass(), resonance_width);
597 }
598 
600  /* The spectral function is a relativistic Breit-Wigner function.
601  * This variant is using a constant width (evaluated at the pole mass). */
602  const double resonance_width = width_at_pole();
603  if (resonance_width < ParticleType::width_cutoff) {
604  return 0.;
605  }
606  return breit_wigner(m, mass(), resonance_width);
607 }
608 
610  return breit_wigner_nonrel(m, mass(), width_at_pole());
611 }
612 
613 /* Resonance mass sampling for 2-particle final state */
614 double ParticleType::sample_resonance_mass(const double mass_stable,
615  const double cms_energy,
616  int L) const {
617  /* largest possible mass: Use 'nextafter' to make sure it is not above the
618  * physical limit by numerical error. */
619  const double max_mass = std::nextafter(cms_energy - mass_stable, 0.);
620 
621  // smallest possible mass to find non-zero spectral function contributions
622  const double min_mass = this->min_mass_spectral();
623 
624  // largest possible cm momentum (from smallest mass)
625  const double pcm_max = pCM(cms_energy, mass_stable, min_mass);
626  const double blw_max = pcm_max * blatt_weisskopf_sqr(pcm_max, L);
627  /* The maximum of the spectral-function ratio 'usually' happens at the
628  * largest mass. However, this is not always the case, therefore we need
629  * and additional fudge factor (determined automatically). Additionally,
630  * a heuristic knowledge is used that usually such mass exist that
631  * spectral_function(m) > spectral_function_simple(m). */
632  const double sf_ratio_max =
633  std::max(1., this->spectral_function(max_mass) /
634  this->spectral_function_simple(max_mass));
635 
636  double mass_res, val;
637  // outer loop: repeat if maximum is too small
638  do {
639  const double q_max = sf_ratio_max * this->max_factor1_;
640  const double max = blw_max * q_max; // maximum value for rejection sampling
641  // inner loop: rejection sampling
642  do {
643  // sample mass from a simple Breit-Wigner (aka Cauchy) distribution
644  mass_res = random::cauchy(this->mass(), this->width_at_pole() / 2.,
645  this->min_mass_spectral(), max_mass);
646  // determine cm momentum for this case
647  const double pcm = pCM(cms_energy, mass_stable, mass_res);
648  const double blw = pcm * blatt_weisskopf_sqr(pcm, L);
649  // determine ratio of full to simple spectral function
650  const double q = this->spectral_function(mass_res) /
651  this->spectral_function_simple(mass_res);
652  val = q * blw;
653  } while (val < random::uniform(0., max));
654 
655  // check that we are using the proper maximum value
656  if (val > max) {
657  logg[LResonances].debug(
658  "maximum is being increased in sample_resonance_mass: ",
659  this->max_factor1_, " ", val / max, " ", this->pdgcode(), " ",
660  mass_stable, " ", cms_energy, " ", mass_res);
661  this->max_factor1_ *= val / max;
662  } else {
663  break; // maximum ok, exit loop
664  }
665  } while (true);
666 
667  return mass_res;
668 }
669 
670 /* Resonance mass sampling for 2-particle final state with two resonances. */
671 std::pair<double, double> ParticleType::sample_resonance_masses(
672  const ParticleType &t2, const double cms_energy, int L) const {
673  const ParticleType &t1 = *this;
674  /* Sample resonance mass from the distribution
675  * used for calculating the cross section. */
676  const double max_mass_1 =
677  std::nextafter(cms_energy - t2.min_mass_spectral(), 0.);
678  const double max_mass_2 =
679  std::nextafter(cms_energy - t1.min_mass_spectral(), 0.);
680  // largest possible cm momentum (from smallest mass)
681  const double pcm_max =
682  pCM(cms_energy, t1.min_mass_spectral(), t2.min_mass_spectral());
683  const double blw_max = pcm_max * blatt_weisskopf_sqr(pcm_max, L);
684 
685  double mass_1, mass_2, val;
686  // outer loop: repeat if maximum is too small
687  do {
688  // maximum value for rejection sampling (determined automatically)
689  const double max = blw_max * t1.max_factor2_;
690  // inner loop: rejection sampling
691  do {
692  // sample mass from a simple Breit-Wigner (aka Cauchy) distribution
693  mass_1 = random::cauchy(t1.mass(), t1.width_at_pole() / 2.,
694  t1.min_mass_spectral(), max_mass_1);
695  mass_2 = random::cauchy(t2.mass(), t2.width_at_pole() / 2.,
696  t2.min_mass_spectral(), max_mass_2);
697  // determine cm momentum for this case
698  const double pcm = pCM(cms_energy, mass_1, mass_2);
699  const double blw = pcm * blatt_weisskopf_sqr(pcm, L);
700  // determine ratios of full to simple spectral function
701  const double q1 =
702  t1.spectral_function(mass_1) / t1.spectral_function_simple(mass_1);
703  const double q2 =
704  t2.spectral_function(mass_2) / t2.spectral_function_simple(mass_2);
705  val = q1 * q2 * blw;
706  } while (val < random::uniform(0., max));
707 
708  if (val > max) {
709  logg[LResonances].debug(
710  "maximum is being increased in sample_resonance_masses: ",
711  t1.max_factor2_, " ", val / max, " ", t1.pdgcode(), " ", t2.pdgcode(),
712  " ", cms_energy, " ", mass_1, " ", mass_2);
713  t1.max_factor2_ *= val / max;
714  } else {
715  break; // maximum ok, exit loop
716  }
717  } while (true);
718 
719  return {mass_1, mass_2};
720 }
721 
723  if (is_stable()) {
724  std::stringstream err;
725  err << "Particle " << *this << " is stable, so it makes no"
726  << " sense to print its spectral function, etc.";
727  throw std::runtime_error(err.str());
728  }
729 
730  double rightmost_pole = 0.0;
731  const auto &decaymodes = decay_modes().decay_mode_list();
732  for (const auto &mode : decaymodes) {
733  double pole_mass_sum = 0.0;
734  for (const ParticleTypePtr p : mode->type().particle_types()) {
735  pole_mass_sum += p->mass();
736  }
737  if (pole_mass_sum > rightmost_pole) {
738  rightmost_pole = pole_mass_sum;
739  }
740  }
741 
742  std::cout << "# mass m[GeV], width w(m) [GeV],"
743  << " spectral function(m^2)*m [GeV^-1] of " << *this << std::endl;
744  constexpr double m_step = 0.02;
745  const double m_min = min_mass_spectral();
746  // An empirical value used to stop the printout. Assumes that spectral
747  // function decays at high mass, which is true for all known resonances.
748  constexpr double spectral_function_threshold = 8.e-3;
749  std::cout << std::fixed << std::setprecision(5);
750  for (unsigned int i = 0;; i++) {
751  const double m = m_min + m_step * i;
752  const double w = total_width(m), sf = spectral_function(m);
753  if (m > rightmost_pole * 2 && sf < spectral_function_threshold) {
754  break;
755  }
756  std::cout << m << " " << w << " " << sf << std::endl;
757  }
758 }
759 
760 std::ostream &operator<<(std::ostream &out, const ParticleType &type) {
761  const PdgCode &pdg = type.pdgcode();
762  return out << type.name() << std::setfill(' ') << std::right
763  << "[ mass:" << field<6> << type.mass()
764  << ", width:" << field<6> << type.width_at_pole()
765  << ", PDG:" << field<6> << pdg
766  << ", charge:" << field<3> << pdg.charge()
767  << ", spin:" << field<2> << pdg.spin() << "/2 ]";
768 }
769 
770 /*
771  * This is valid for two particles of the same species because the comparison
772  * operator for smart pointers compares the pointed object. In this case, the
773  * `std::set<ParticleTypePtr> incoming` will contain one element instead of two.
774  */
775 ParticleTypePtrList list_possible_resonances(const ParticleTypePtr type_a,
776  const ParticleTypePtr type_b) {
777  static std::map<std::set<ParticleTypePtr>, ParticleTypePtrList>
778  map_possible_resonances_of;
779  std::set<ParticleTypePtr> incoming{type_a, type_b};
780  const ParticleTypePtrList incoming_types = {type_a, type_b};
781  // Fill map if set is not yet present
782  if (map_possible_resonances_of.count(incoming) == 0) {
783  logg[LResonances].debug()
784  << "Filling map of compatible resonances for ptypes " << type_a->name()
785  << " " << type_b->name();
786  ParticleTypePtrList resonance_list{};
787  // The tests below are redundant as the decay modes already obey them, but
788  // they are quicker to check and so improve performance.
789  for (const ParticleType &resonance : ParticleType::list_all()) {
790  /* Not a resonance, go to next type of particle */
791  if (resonance.is_stable()) {
792  continue;
793  }
794  // Same resonance as in the beginning, ignore
795  if ((resonance.pdgcode() == type_a->pdgcode()) ||
796  (resonance.pdgcode() == type_b->pdgcode())) {
797  continue;
798  }
799  // Check for charge conservation.
800  if (resonance.charge() != type_a->charge() + type_b->charge()) {
801  continue;
802  }
803  // Check for baryon-number conservation.
804  if (resonance.baryon_number() !=
805  type_a->baryon_number() + type_b->baryon_number()) {
806  continue;
807  }
808  // Check for strangeness conservation.
809  if (resonance.strangeness() !=
810  type_a->strangeness() + type_b->strangeness()) {
811  continue;
812  }
813  const auto &decaymodes = resonance.decay_modes().decay_mode_list();
814  for (const auto &mode : decaymodes) {
815  if (mode->type().has_particles(incoming_types)) {
816  resonance_list.push_back(&resonance);
817  break;
818  }
819  }
820  }
821  // Here `resonance_list` can be empty, corresponding to the case where there
822  // are no possible resonances.
823  map_possible_resonances_of[incoming] = resonance_list;
824  }
825 
826  return map_possible_resonances_of[incoming];
827 }
828 
829 } // namespace smash
DecayBranch is a derivative of ProcessBranch, which is used to represent decay channels.
const DecayType & type() const
The DecayModes class is used to store and update information about decay branches (i....
Definition: decaymodes.h:29
const DecayBranchList & decay_mode_list() const
Definition: decaymodes.h:63
DecayType is the abstract base class for all decay types.
Definition: decaytype.h:23
virtual bool is_dilepton_decay() const
Definition: decaytype.h:82
virtual double width(double m0, double G0, double m) const =0
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:33
A C++ interface for numerical integration in one dimension with the GSL CQUAD integration functions.
Definition: integrate.h:106
static bool exists(const std::string &name)
Returns whether the ParticleType with the given pdgcode exists.
static const IsoParticleType & find(const std::string &name)
Returns the IsoParticleType object for the given name.
int isospin() const
Returns twice the total isospin of the multiplet.
static void create_multiplet(const ParticleType &type)
Add a new multiplet to the global list of IsoParticleTypes, which contains type.
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:58
const ParticleType & type() const
Get the type of the particle.
Definition: particledata.h:128
double effective_mass() const
Get the particle's effective mass.
Definition: particledata.cc:24
A pointer-like interface to global references to ParticleType objects.
Definition: particletype.h:676
Particle type contains the static properties of a particle species.
Definition: particletype.h:98
double min_mass_spectral_
minimum mass, where the spectral function is non-zero Mutable, because it is initialized at first cal...
Definition: particletype.h:641
bool is_pion() const
Definition: particletype.h:219
double min_mass_spectral() const
The minimum mass of the resonance, where the spectral function is non-zero.
IsoParticleType * iso_multiplet_
Container for the isospin multiplet information.
Definition: particletype.h:653
const DecayModes & decay_modes() const
double spectral_function(double m) const
Full spectral function of the resonance (relativistic Breit-Wigner distribution with mass-dependent ...
double sample_resonance_mass(const double mass_stable, const double cms_energy, int L=0) const
Resonance mass sampling for 2-particle final state with one resonance (type given by 'this') and one ...
double get_partial_width(const double m, const ParticleTypePtrList dlist) const
Get the mass-dependent partial width of a resonance with mass m, decaying into two given daughter par...
int strangeness() const
Definition: particletype.h:213
static const ParticleTypePtr try_find(PdgCode pdgcode)
Returns the ParticleTypePtr for the given pdgcode.
Definition: particletype.cc:89
void dump_width_and_spectral_function() const
Prints out width and spectral function versus mass to the standard output.
double total_width(const double m) const
Get the mass-dependent total width of a particle with mass m.
bool wanted_decaymode(const DecayType &t, WhichDecaymodes wh) const
Helper Function that containes the if-statement logic that decides if a decay mode is either a hadron...
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode.
Definition: particletype.cc:99
double min_mass_kinematic() const
The minimum mass of the resonance that is kinematically allowed.
PdgCode pdgcode() const
Definition: particletype.h:157
static bool exists(PdgCode pdgcode)
static void check_consistency()
double max_factor2_
Maximum factor for double-res mass sampling, cf. sample_resonance_masses.
Definition: particletype.h:658
const std::string & name() const
Definition: particletype.h:142
double min_mass_kinematic_
minimum kinematically allowed mass of the particle Mutable, because it is initialized at first call o...
Definition: particletype.h:634
int32_t charge() const
The charge of the particle.
Definition: particletype.h:189
double spectral_function_no_norm(double m) const
Full spectral function without normalization factor.
static ParticleTypePtrList & list_nucleons()
Definition: particletype.cc:69
static ParticleTypePtrList & list_anti_nucleons()
Definition: particletype.cc:71
static const ParticleTypeList & list_all()
Definition: particletype.cc:51
bool is_stable() const
Definition: particletype.h:246
int isospin_
Isospin of the particle; filled automatically from pdgcode_.
Definition: particletype.h:648
double isospin3_rel() const
Definition: particletype.h:180
bool is_Delta() const
Definition: particletype.h:225
double spectral_function_simple(double m) const
This one is the most simple form of the spectral function, using a Cauchy distribution (non-relativis...
double width_at_pole() const
Definition: particletype.h:151
static ParticleTypePtrList & list_anti_Deltas()
Definition: particletype.cc:77
PdgCode pdgcode_
PDG Code of the particle.
Definition: particletype.h:627
bool has_antiparticle() const
Definition: particletype.h:160
ParticleType(std::string n, double m, double w, Parity p, PdgCode id)
Creates a fully initialized ParticleType object.
bool is_nucleon() const
Definition: particletype.h:216
double mass() const
Definition: particletype.h:145
static ParticleTypePtrList & list_baryon_resonances()
Definition: particletype.cc:81
static constexpr double width_cutoff
Decay width cutoff for considering a particle as stable.
Definition: particletype.h:108
DecayBranchList get_partial_widths(const FourVector p, const ThreeVector x, WhichDecaymodes wh) const
Get all the mass-dependent partial decay widths of a particle with mass m.
static ParticleTypePtrList & list_Deltas()
Definition: particletype.cc:75
bool is_deuteron() const
Definition: particletype.h:252
double get_partial_in_width(const double m, const ParticleData &p_a, const ParticleData &p_b) const
Get the mass-dependent partial in-width of a resonance with mass m, decaying into two given daughter ...
bool is_kaon() const
Definition: particletype.h:222
static void create_type_list(const std::string &particles)
Initialize the global ParticleType list (list_all) from the given input data.
int isospin() const
Returns twice the isospin vector length .
double norm_factor_
This normalization factor ensures that the spectral function is normalized to unity,...
Definition: particletype.h:644
int baryon_number() const
Definition: particletype.h:210
ParticleTypePtr operator&() const
Returns an object that acts like a pointer, except that it requires only 2 bytes and inhibits pointer...
Definition: particletype.cc:57
double max_factor1_
Maximum factor for single-res mass sampling, cf. sample_resonance_mass.
Definition: particletype.h:656
double spectral_function_const_width(double m) const
std::pair< double, double > sample_resonance_masses(const ParticleType &t2, const double cms_energy, int L=0) const
Resonance mass sampling for 2-particle final state with two resonances.
static ParticleTypePtrList & list_light_nuclei()
Definition: particletype.cc:85
double partial_width(const double m, const DecayBranch *mode) const
Get the mass-dependent partial decay width of a particle with mass m in a particular decay mode.
Parity parity() const
Definition: particletype.h:154
double mass_
pole mass of the particle
Definition: particletype.h:621
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
Definition: pdgcode.h:111
int baryon_number() const
Definition: pdgcode.h:381
unsigned int spin() const
Definition: pdgcode.h:608
int strangeness() const
Definition: pdgcode.h:543
std::string string() const
Definition: pdgcode.h:325
PdgCode get_antiparticle() const
Construct the antiparticle to a given PDG code.
Definition: pdgcode.h:332
bool is_hadron() const
Definition: pdgcode.h:370
int charge() const
The charge of the particle.
Definition: pdgcode.h:567
static std::pair< double, int > force_scale(const ParticleType &data)
Evaluates the scaling factor of the forces acting on the particles.
Definition: potentials.cc:156
double weight() const
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
Collection of useful constants that are known at compile time.
std::ostream & operator<<(std::ostream &out, const ActionPtr &action)
Convenience: dereferences the ActionPtr to Action.
Definition: action.h:547
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
#define unlikely(x)
Tell the branch predictor that this expression is likely false.
Definition: macros.h:16
ParticleTypePtrList deltas_list
Global pointer to the Particle Type list of deltas.
Definition: particletype.cc:42
ParticleTypePtrList baryon_resonances_list
Global pointer to the Particle Type list of baryon resonances.
Definition: particletype.cc:46
const ParticleTypeList * all_particle_types
Global pointer to the Particle Type list.
Definition: particletype.cc:36
ParticleTypePtrList anti_deltas_list
Global pointer to the Particle Type list of anti-deltas.
Definition: particletype.cc:44
ParticleTypePtrList light_nuclei_list
Global pointer to the Particle Type list of light nuclei.
Definition: particletype.cc:48
ParticleTypePtrList anti_nucs_list
Global pointer to the Particle Type list of anti-nucleons.
Definition: particletype.cc:40
ParticleTypePtrList nucleons_list
Global pointer to the Particle Type list of nucleons.
Definition: particletype.cc:38
constexpr int p
Proton.
constexpr int n
Neutron.
constexpr int64_t deuteron
Deuteron.
T uniform(T min, T max)
Definition: random.h:88
T cauchy(T pole, T width, T min, T max)
Draws a random number from a Cauchy distribution (sometimes also called Lorentz or non-relativistic B...
Definition: random.h:307
std::iterator_traits< octet_iterator >::difference_type sequence_length(octet_iterator lead_it)
Given an iterator to the beginning of a UTF-8 sequence, return the length of the next UTF-8 code poin...
Definition: action.h:24
constexpr double delta_mass
Delta mass in GeV.
Definition: constants.h:86
T pCM(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:79
ParticleTypePtrList list_possible_resonances(const ParticleTypePtr type_a, const ParticleTypePtr type_b)
Lists the possible resonances that decay into two particles.
void ensure_all_read(std::istream &input, const Line &line)
Makes sure that nothing is left to read from this line.
static Integrator integrate
Definition: decaytype.cc:143
double breit_wigner(double m, double pole, double width)
Returns a relativistic Breit-Wigner distribution.
static std::string antiname(const std::string &name, PdgCode code)
Construct an antiparticle name-string from the given name-string for the particle and its PDG code.
build_vector_< Line > line_parser(const std::string &input)
Helper function for parsing particles.txt and decaymodes.txt.
Parity
Represent the parity of a particle type.
Definition: particletype.h:25
@ Neg
Negative parity.
@ Pos
Positive parity.
constexpr double deuteron_mass
Deuteron mass in GeV.
Definition: constants.h:92
constexpr double nucleon_mass
Nucleon mass in GeV.
Definition: constants.h:58
double blatt_weisskopf_sqr(const double p_ab, const int L)
Definition: formfactors.h:35
static constexpr int LResonances
Potentials * pot_pointer
Pointer to a Potential class.
constexpr double pion_mass
Pion mass in GeV.
Definition: constants.h:65
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:37
std::string build_error_string(std::string message, const Line &line)
Builds a meaningful error message.
constexpr double kaon_mass
Kaon mass in GeV.
Definition: constants.h:72
RectangularLattice< FourVector > * UB_lat_pointer
Pointer to the skyrme potential on the lattice.
double breit_wigner_nonrel(double m, double pole, double width)
Returns a non-relativistic Breit-Wigner distribution, which is essentially a Cauchy distribution with...
static std::string chargestr(int charge)
Construct a charge string, given the charge as integer.
bool almost_equal(const N x, const N y)
Checks two numbers for relative approximate equality.
Definition: numerics.h:44
constexpr double omega_mass
omega mass in GeV.
Definition: constants.h:79
RectangularLattice< FourVector > * UI3_lat_pointer
Pointer to the symmmetry potential on the lattice.
WhichDecaymodes
Decide which decay mode widths are returned in get partical widths.
Definition: particletype.h:33
@ Hadronic
Ignore dilepton decay modes widths.
@ Dileptons
Only return dilepton decays widths.
@ All
All decay mode widths.
static constexpr int LParticleType
Line consists of a line number and the contents of that line.