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