Version: SMASH-3.1
scatteractionmulti.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2020-2023
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
11 
12 #include <map>
13 
14 #include "gsl/gsl_sf_ellint.h"
15 
16 #include "smash/crosssections.h"
17 #include "smash/integrate.h"
18 #include "smash/logging.h"
19 #include "smash/parametrizations.h"
20 #include "smash/pow.h"
21 
22 namespace smash {
23 static constexpr int LScatterActionMulti = LogArea::ScatterActionMulti::id;
24 
25 ScatterActionMulti::ScatterActionMulti(const ParticleList& in_plist,
26  double time)
27  : Action(in_plist, time), total_probability_(0.) {}
28 
29 void ScatterActionMulti::add_reaction(CollisionBranchPtr p) {
30  add_process<CollisionBranch>(p, reaction_channels_, total_probability_);
31 }
32 
33 void ScatterActionMulti::add_reactions(CollisionBranchList pv) {
34  add_processes<CollisionBranch>(std::move(pv), reaction_channels_,
36 }
37 
39  double xsec_scaling = 1.0;
40  for (const ParticleData& in_part : incoming_particles_) {
41  xsec_scaling *= in_part.xsec_scaling_factor();
42  }
43  return total_probability_ * xsec_scaling;
44 }
45 
47  double xsec_scaling = 1.0;
48  for (const ParticleData& in_part : incoming_particles_) {
49  xsec_scaling *= in_part.xsec_scaling_factor();
50  }
51  return partial_probability_ * xsec_scaling;
52 }
53 
55  double dt, const double gcell_vol,
56  const MultiParticleReactionsBitSet incl_multi) {
57  // 3 -> m
58  if (incoming_particles_.size() == 3) {
59  // 3 -> 1
60  if (incl_multi[IncludedMultiParticleReactions::Meson_3to1] == 1) {
62  incoming_particles_[2])) {
63  // 3pi -> omega
64  const ParticleTypePtr type_omega = ParticleType::try_find(0x223);
65  if (type_omega) {
66  add_reaction(std::make_unique<CollisionBranch>(
67  *type_omega,
68  probability_three_to_one(*type_omega, dt, gcell_vol,
69  type_omega->spin_degeneracy()),
71  }
72  // 3pi -> phi
73  const ParticleTypePtr type_phi = ParticleType::try_find(0x333);
74  if (type_phi) {
75  add_reaction(std::make_unique<CollisionBranch>(
76  *type_phi,
77  probability_three_to_one(*type_phi, dt, gcell_vol,
78  type_phi->spin_degeneracy()),
80  }
82  incoming_particles_[2])) {
83  // eta2pi -> eta-prime
84  const ParticleTypePtr type_eta_prime = ParticleType::try_find(0x331);
85 
86  int sym_factor_in = 1;
87  if (incoming_particles_[0].type() == incoming_particles_[1].type() ||
88  incoming_particles_[1].type() == incoming_particles_[2].type() ||
89  incoming_particles_[2].type() == incoming_particles_[0].type()) {
90  sym_factor_in = 2; // 2 factorial
91  }
92 
93  if (type_eta_prime) {
94  add_reaction(std::make_unique<CollisionBranch>(
95  *type_eta_prime,
97  *type_eta_prime, dt, gcell_vol,
98  sym_factor_in * type_eta_prime->spin_degeneracy()),
100  }
101  }
102  }
103  // 3 -> 2
104  if (incl_multi[IncludedMultiParticleReactions::Deuteron_3to2] == 1) {
105  const PdgCode pdg_a = incoming_particles_[0].pdgcode();
106  const PdgCode pdg_b = incoming_particles_[1].pdgcode();
107  const PdgCode pdg_c = incoming_particles_[2].pdgcode();
108  const ParticleTypePtr type_deuteron =
110  const ParticleTypePtr type_anti_deuteron =
112 
113  const int spin_factor_inc = pdg_a.spin_degeneracy() *
114  pdg_b.spin_degeneracy() *
115  pdg_c.spin_degeneracy();
116 
117  if (type_deuteron && type_anti_deuteron) {
118  // πpn → πd
119  if ((pdg_a.is_pion() && pdg_b == pdg::p && pdg_c == pdg::n) ||
120  (pdg_a.is_pion() && pdg_b == pdg::n && pdg_c == pdg::p) ||
121  (pdg_a == pdg::p && pdg_b.is_pion() && pdg_c == pdg::n) ||
122  (pdg_a == pdg::n && pdg_b.is_pion() && pdg_c == pdg::p) ||
123  (pdg_a == pdg::p && pdg_b == pdg::n && pdg_c.is_pion()) ||
124  (pdg_a == pdg::n && pdg_b == pdg::p && pdg_c.is_pion())) {
125  // Get type of incoming π
126  ParticleList::iterator it = std::find_if(
128  [](ParticleData x) { return x.is_pion(); });
129  const ParticleType& type_pi = it->type();
130 
131  const double spin_degn =
132  react_degen_factor(spin_factor_inc, type_pi.spin_degeneracy(),
133  type_deuteron->spin_degeneracy());
134 
135  add_reaction(std::make_unique<CollisionBranch>(
136  type_pi, *type_deuteron,
137  probability_three_to_two(type_pi, *type_deuteron, dt, gcell_vol,
138  spin_degn),
140  }
141 
142  // πp̅n̅ → πd̅
143  if ((pdg_a.is_pion() && pdg_b == -pdg::p && pdg_c == -pdg::n) ||
144  (pdg_a.is_pion() && pdg_b == -pdg::n && pdg_c == -pdg::p) ||
145  (pdg_a == -pdg::p && pdg_b.is_pion() && pdg_c == -pdg::n) ||
146  (pdg_a == -pdg::n && pdg_b.is_pion() && pdg_c == -pdg::p) ||
147  (pdg_a == -pdg::p && pdg_b == -pdg::n && pdg_c.is_pion()) ||
148  (pdg_a == -pdg::n && pdg_b == -pdg::p && pdg_c.is_pion())) {
149  // Get type of incoming π
150  ParticleList::iterator it = std::find_if(
152  [](ParticleData x) { return x.is_pion(); });
153  const ParticleType& type_pi = it->type();
154 
155  const double spin_degn =
156  react_degen_factor(spin_factor_inc, type_pi.spin_degeneracy(),
157  type_anti_deuteron->spin_degeneracy());
158 
159  add_reaction(std::make_unique<CollisionBranch>(
160  type_pi, *type_anti_deuteron,
161  probability_three_to_two(type_pi, *type_anti_deuteron, dt,
162  gcell_vol, spin_degn),
164  }
165 
166  // Nnp → Nd, N̅np → N̅d
167  if ((pdg_a.is_nucleon() && pdg_b == pdg::p && pdg_c == pdg::n) ||
168  (pdg_a.is_nucleon() && pdg_b == pdg::n && pdg_c == pdg::p) ||
169  (pdg_a == pdg::p && pdg_b.is_nucleon() && pdg_c == pdg::n) ||
170  (pdg_a == pdg::n && pdg_b.is_nucleon() && pdg_c == pdg::p) ||
171  (pdg_a == pdg::p && pdg_b == pdg::n && pdg_c.is_nucleon()) ||
172  (pdg_a == pdg::n && pdg_b == pdg::p && pdg_c.is_nucleon())) {
173  int symmetry_factor = 1; // already true for N̅np → N̅d case
174 
175  ParticleList::iterator it =
176  std::find_if(incoming_particles_.begin(),
177  incoming_particles_.end(), [](ParticleData x) {
178  return x.pdgcode().antiparticle_sign() == -1;
179  });
180  if (it == incoming_particles_.end()) {
181  /* Meaning no anti-N found by find_if,
182  * therefore not N̅np → N̅d, but Nnp → Nd. */
183  symmetry_factor = 2; // for Nnp → Nd (2 factorial)
184  // It is already clear here that we have a double of two N
185  if (pdg_a == pdg_b) {
186  it = incoming_particles_.begin();
187  } else {
188  // If a and b are not the double, then c has to be part of it
189  it = incoming_particles_.begin() + 2;
190  }
191  }
192  const ParticleType& type_N = it->type();
193 
194  const double spin_degn =
195  react_degen_factor(spin_factor_inc, type_N.spin_degeneracy(),
196  type_deuteron->spin_degeneracy());
197 
198  add_reaction(std::make_unique<CollisionBranch>(
199  type_N, *type_deuteron,
200  probability_three_to_two(type_N, *type_deuteron, dt, gcell_vol,
201  symmetry_factor * spin_degn),
203  }
204 
205  // Np̅n̅ → Nd̅, N̅p̅n̅ → N̅d̅
206  if ((pdg_a.is_nucleon() && pdg_b == -pdg::p && pdg_c == -pdg::n) ||
207  (pdg_a.is_nucleon() && pdg_b == -pdg::n && pdg_c == -pdg::p) ||
208  (pdg_a == -pdg::p && pdg_b.is_nucleon() && pdg_c == -pdg::n) ||
209  (pdg_a == -pdg::n && pdg_b.is_nucleon() && pdg_c == -pdg::p) ||
210  (pdg_a == -pdg::p && pdg_b == -pdg::n && pdg_c.is_nucleon()) ||
211  (pdg_a == -pdg::n && pdg_b == -pdg::p && pdg_c.is_nucleon())) {
212  int symmetry_factor = 1; // already true for Np̅n̅ → Nd̅ case
213 
214  ParticleList::iterator it =
215  std::find_if(incoming_particles_.begin(),
216  incoming_particles_.end(), [](ParticleData x) {
217  return x.pdgcode().antiparticle_sign() == 1;
218  });
219  if (it == incoming_particles_.end()) {
220  /* Meaning no N found by find_if,
221  * therefore not Np̅n̅ → Nd̅, but N̅p̅n̅ → N̅d̅. */
222  symmetry_factor = 2; // for N̅p̅n̅ → N̅d̅ (2 factorial)
223  // It is already clear here that we have a double of two N̅
224  if (pdg_a == pdg_b) {
225  it = incoming_particles_.begin();
226  } else {
227  // If a and b are not the double, then c has to be part of it
228  it = incoming_particles_.begin() + 2;
229  }
230  }
231  const ParticleType& type_N = it->type();
232 
233  const double spin_degn =
234  react_degen_factor(spin_factor_inc, type_N.spin_degeneracy(),
235  type_anti_deuteron->spin_degeneracy());
236 
237  add_reaction(std::make_unique<CollisionBranch>(
238  type_N, *type_anti_deuteron,
239  probability_three_to_two(type_N, *type_anti_deuteron, dt,
240  gcell_vol, symmetry_factor * spin_degn),
242  }
243  }
244  }
245  }
246  // 4 -> 2
247  if (incoming_particles_.size() == 4 &&
249  std::map<PdgCode, int> c; // counts incoming PdgCodes
250  int spin_factor_inc = 1;
251  for (const ParticleData& data : incoming_particles_) {
252  c[data.pdgcode()]++;
253  spin_factor_inc *= data.pdgcode().spin_degeneracy();
254  }
255  // Nucleons, antinucleons, and pions can catalyze
256  const int n_possible_catalysts_incoming =
257  c[pdg::n] + c[pdg::p] + c[-pdg::p] + c[-pdg::n] + c[pdg::pi_p] +
258  c[pdg::pi_z] + c[pdg::pi_m];
259 
260  for (PdgCode pdg_nucleus :
263  const ParticleTypePtr type_nucleus = ParticleType::try_find(pdg_nucleus);
264  // Nucleus can be formed if and only if:
265  // 1) Incoming particles contain enough components (like p, n, Lambda)
266  // 2) In (incoming particles - components) there is still a catalyst
267  // This is including the situation like nnpp. Can be that t(nnp) is formed
268  // and p is catalyst, can be that he-3(ppn) is formed and n is catalyst.
269  // Both reactions should be added.
270  const int n_nucleus_components_that_can_be_catalysts =
271  pdg_nucleus.nucleus_p() + pdg_nucleus.nucleus_ap() +
272  pdg_nucleus.nucleus_n() + pdg_nucleus.nucleus_an();
273  const bool incoming_contain_nucleus_components =
274  c[pdg::p] >= pdg_nucleus.nucleus_p() &&
275  c[-pdg::p] >= pdg_nucleus.nucleus_ap() &&
276  c[pdg::n] >= pdg_nucleus.nucleus_n() &&
277  c[-pdg::n] >= pdg_nucleus.nucleus_an() &&
278  c[pdg::Lambda] >= pdg_nucleus.nucleus_La() &&
279  c[-pdg::Lambda] >= pdg_nucleus.nucleus_aLa();
280  const bool can_form_nucleus =
281  type_nucleus && incoming_contain_nucleus_components &&
282  n_possible_catalysts_incoming -
283  n_nucleus_components_that_can_be_catalysts ==
284  1;
285 
286  if (!can_form_nucleus) {
287  continue;
288  }
289  // Find the catalyst
290  std::map<PdgCode, int> catalyst_count = c;
291  catalyst_count[pdg::p] -= pdg_nucleus.nucleus_p();
292  catalyst_count[-pdg::p] -= pdg_nucleus.nucleus_ap();
293  catalyst_count[pdg::n] -= pdg_nucleus.nucleus_n();
294  catalyst_count[-pdg::n] -= pdg_nucleus.nucleus_an();
295  catalyst_count[pdg::Lambda] -= pdg_nucleus.nucleus_La();
296  catalyst_count[-pdg::Lambda] -= pdg_nucleus.nucleus_aLa();
297  PdgCode pdg_catalyst = PdgCode::invalid();
298  for (const auto i : catalyst_count) {
299  if (i.second == 1) {
300  pdg_catalyst = i.first;
301  break;
302  }
303  }
304  if (pdg_catalyst == PdgCode::invalid()) {
305  logg[LScatterActionMulti].error("Something went wrong while forming",
306  pdg_nucleus, " from ",
308  }
309  const ParticleTypePtr type_catalyst =
310  ParticleType::try_find(pdg_catalyst);
311  const double spin_degn =
312  react_degen_factor(spin_factor_inc, type_catalyst->spin_degeneracy(),
313  type_nucleus->spin_degeneracy());
314  double symmetry_factor = 1.0;
315  for (const auto i : c) {
316  symmetry_factor *= (i.second == 3) ? 6.0 // 3!
317  : (i.second == 2) ? 2.0 // 2!
318  : 1.0;
319  if (i.second > 3 || i.second < 0) {
320  logg[LScatterActionMulti].error("4<->2 error, incoming particles ",
322  }
323  }
324 
325  add_reaction(std::make_unique<CollisionBranch>(
326  *type_catalyst, *type_nucleus,
327  probability_four_to_two(*type_catalyst, *type_nucleus, dt, gcell_vol,
328  symmetry_factor * spin_degn),
330  }
331  }
332  // 5 -> 2
333  if (incoming_particles_.size() == 5) {
334  if (incl_multi[IncludedMultiParticleReactions::NNbar_5to2] == 1) {
336  const int spin_factor_inc =
337  incoming_particles_[0].pdgcode().spin_degeneracy() *
338  incoming_particles_[1].pdgcode().spin_degeneracy() *
339  incoming_particles_[2].pdgcode().spin_degeneracy() *
340  incoming_particles_[3].pdgcode().spin_degeneracy() *
341  incoming_particles_[4].pdgcode().spin_degeneracy();
342  const double symmetry_factor = 4.0; // 2! * 2!
343 
345  const ParticleTypePtr type_anti_p = ParticleType::try_find(-pdg::p);
347  const ParticleTypePtr type_anti_n = ParticleType::try_find(-pdg::n);
348 
349  const double spin_degn =
350  react_degen_factor(spin_factor_inc, type_p->spin_degeneracy(),
351  type_anti_p->spin_degeneracy());
352 
353  if (type_p && type_n) {
354  const double prob = probability_five_to_two(
355  type_p->mass(), dt, gcell_vol,
356  symmetry_factor * spin_degn); // same for ppbar and nnbar
357  add_reaction(std::make_unique<CollisionBranch>(
358  *type_p, *type_anti_p, prob,
360  add_reaction(std::make_unique<CollisionBranch>(
361  *type_n, *type_anti_n, prob,
363  }
364  }
365  }
366  }
367 }
368 
370  logg[LScatterActionMulti].debug("Incoming particles for ScatterActionMulti: ",
372 
373  /* Decide for a particular final state. */
374  const CollisionBranch* proc =
375  choose_channel<CollisionBranch>(reaction_channels_, total_probability_);
376  process_type_ = proc->get_type();
378  partial_probability_ = proc->weight();
379 
380  logg[LScatterActionMulti].debug("Chosen channel: ", process_type_,
382 
383  switch (process_type_) {
385  /* n->1 annihilation */
386  annihilation();
387  break;
391  /* n->2 scattering */
392  n_to_two();
393  break;
394  default:
396  "ScatterActionMulti::generate_final_state: Invalid process type " +
397  std::to_string(static_cast<int>(process_type_)) + " was requested.");
398  }
399 
400  /* The production point of the new particles. */
401  FourVector middle_point = get_interaction_point();
402 
403  for (ParticleData& new_particle : outgoing_particles_) {
404  // Boost to the computational frame
405  new_particle.boost_momentum(
407  /* Set positions of the outgoing particles */
408  new_particle.set_4position(middle_point);
409  }
410 }
411 
412 double ScatterActionMulti::calculate_I3(const double sqrts) const {
413  const double m1 = incoming_particles_[0].type().mass();
414  const double m2 = incoming_particles_[1].type().mass();
415  const double m3 = incoming_particles_[2].type().mass();
416 
417  if (sqrts < m1 + m2 + m3) {
418  return 0.0;
419  }
420  const double x1 = (m1 - m2) * (m1 - m2), x2 = (m1 + m2) * (m1 + m2),
421  x3 = (sqrts - m3) * (sqrts - m3),
422  x4 = (sqrts + m3) * (sqrts + m3);
423  const double qmm = x3 - x1, qmp = x3 - x2, qpm = x4 - x1, qpp = x4 - x2;
424  const double kappa = std::sqrt(qpm * qmp / (qpp * qmm));
425  const double tmp = std::sqrt(qmm * qpp);
426  const double c1 =
427  4.0 * m1 * m2 * std::sqrt(qmm / qpp) * (x4 - m3 * sqrts + m1 * m2);
428  const double c2 = 0.5 * (m1 * m1 + m2 * m2 + m3 * m3 + sqrts * sqrts) * tmp;
429  const double c3 = 8 * m1 * m2 / tmp *
430  ((m1 * m1 + m2 * m2) * (m3 * m3 + sqrts * sqrts) -
431  2 * m1 * m1 * m2 * m2 - 2 * m3 * m3 * sqrts * sqrts);
432  const double c4 =
433  -8 * m1 * m2 / tmp * smash::pow_int(sqrts * sqrts - m3 * m3, 2);
434  const double precision = 1.e-6;
435  const double res =
436  c1 * gsl_sf_ellint_Kcomp(kappa, precision) +
437  c2 * gsl_sf_ellint_Ecomp(kappa, precision) +
438  c3 * gsl_sf_ellint_Pcomp(kappa, -qmp / qmm, precision) +
439  c4 * gsl_sf_ellint_Pcomp(kappa, -x1 * qmp / (x2 * qmm), precision);
440  return res;
441 }
442 
444  const ParticleType& type_out, double dt, const double gcell_vol,
445  const int degen_sym_factor) const {
446  const double e1 = incoming_particles_[0].momentum().x0();
447  const double e2 = incoming_particles_[1].momentum().x0();
448  const double e3 = incoming_particles_[2].momentum().x0();
449  const double sqrts = sqrt_s();
450 
451  const double gamma_decay = type_out.get_partial_width(
452  sqrts, {&incoming_particles_[0].type(), &incoming_particles_[1].type(),
453  &incoming_particles_[2].type()});
454 
455  const double I_3 = calculate_I3(sqrts);
456  const double ph_sp_3 =
457  1. / (8 * M_PI * M_PI * M_PI) * 1. / (16 * sqrts * sqrts) * I_3;
458 
459  const double spec_f_val = type_out.spectral_function(sqrts);
460 
461  return dt / (gcell_vol * gcell_vol) * M_PI / (4. * e1 * e2 * e3) *
462  gamma_decay / ph_sp_3 * spec_f_val * std::pow(hbarc, 5.0) *
463  degen_sym_factor;
464 }
465 
467  const ParticleType& type_out1, const ParticleType& type_out2, double dt,
468  const double gcell_vol, const double degen_sym_factor) const {
469  const double e1 = incoming_particles_[0].momentum().x0();
470  const double e2 = incoming_particles_[1].momentum().x0();
471  const double e3 = incoming_particles_[2].momentum().x0();
472  const double m4 = type_out1.mass();
473  const double m5 = type_out2.mass();
474 
475  const double sqrts = sqrt_s();
476  const double xs =
477  CrossSections::two_to_three_xs(type_out1, type_out2, sqrts) / gev2_mb;
478  const double lamb = lambda_tilde(sqrts * sqrts, m4 * m4, m5 * m5);
479 
480  const double I_3 = calculate_I3(sqrts);
481  const double ph_sp_3 =
482  1. / (8 * M_PI * M_PI * M_PI) * 1. / (16 * sqrts * sqrts) * I_3;
483 
484  return dt / (gcell_vol * gcell_vol) * 1. / (4. * e1 * e2 * e3) * lamb /
485  (ph_sp_3 * 8 * M_PI * sqrts * sqrts) * xs * std::pow(hbarc, 5.0) *
486  degen_sym_factor;
487 }
488 
490  const ParticleType& type_out1, const ParticleType& type_out2, double dt,
491  const double gcell_vol, const double degen_sym_factor) const {
492  const double e1 = incoming_particles_[0].momentum().x0();
493  const double e2 = incoming_particles_[1].momentum().x0();
494  const double e3 = incoming_particles_[2].momentum().x0();
495  const double e4 = incoming_particles_[3].momentum().x0();
496  const double m5 = type_out1.mass();
497  const double m6 = type_out2.mass();
498 
499  const double man_s = sqrt_s() * sqrt_s();
500  const double xs =
501  CrossSections::two_to_four_xs(type_out1, type_out2, sqrt_s()) / gev2_mb;
502  const double lamb = lambda_tilde(man_s, m5 * m5, m6 * m6);
503  const double ph_sp_4 = parametrizaton_phi4(man_s);
504 
505  return dt / std::pow(gcell_vol, 3.0) * 1. / (16. * e1 * e2 * e3 * e4) * xs /
506  (4. * M_PI * man_s) * lamb / ph_sp_4 * std::pow(hbarc, 8.0) *
507  degen_sym_factor;
508 }
509 
510 double ScatterActionMulti::parametrizaton_phi4(const double man_s) const {
511  int n_nucleons = 0, n_pions = 0, n_lambdas = 0;
512  double sum_m = 0.0, prod_m = 1.0;
513  for (const ParticleData& data : incoming_particles_) {
514  const PdgCode pdg = data.type().pdgcode();
515  n_nucleons += pdg.is_nucleon(); // including anti-nucleons
516  n_pions += pdg.is_pion();
517  n_lambdas += pdg.is_Lambda(); // including anti-Lambda
518  sum_m += data.type().mass();
519  prod_m *= data.type().mass();
520  }
521  const double x = 1.0 - sum_m / std::sqrt(man_s);
522  const double x2 = x * x;
523  const double x3 = x2 * x;
524  double g = -1.0;
525 
526  if (n_nucleons == 3 && n_pions == 1) { // NNNpi
527  g = (1.0 + 0.862432 * x - 3.4853 * x2 + 1.70259 * x3) /
528  (1.0 + 0.387376 * x - 1.34128 * x2 + 0.154489 * x3);
529  } else if (n_nucleons == 4) { // NNNN
530  g = (1.0 - 1.72285 * x + 0.728331 * x2) /
531  (1.0 - 0.967146 * x - 0.0103633 * x2);
532  } else if (n_nucleons == 2 && n_lambdas == 1 && n_pions == 1) { // LaNNpi
533  g = (1.0 + 0.937064 * x - 3.56864 * x2 + 1.721 * x3) /
534  (1.0 + 0.365202 * x - 1.2854 * x2 + 0.138444 * x3);
535  } else if (n_nucleons == 3 && n_lambdas == 1) { // LaNNN
536  g = (1.0 + 0.882401 * x - 3.4074 * x2 + 1.62454 * x3) /
537  (1.0 + 1.61741 * x - 2.12543 * x2 - 0.0902067 * x3);
538  }
539 
540  if (g > 0.0) {
541  return (std::sqrt(prod_m) * sum_m * sum_m * std::pow(x, 3.5) * g) /
542  (840. * std::sqrt(2) * std::pow(M_PI, 4.0) * std::pow(1 - x, 4.0));
543  } else {
544  logg[LScatterActionMulti].error("parametrizaton_phi4: no parametrization ",
545  "available for ", incoming_particles_);
546  return 0.0;
547  }
548 }
549 
551  const double mout, double dt, const double gcell_vol,
552  const double degen_sym_factor) const {
553  const double e1 = incoming_particles_[0].momentum().x0();
554  const double e2 = incoming_particles_[1].momentum().x0();
555  const double e3 = incoming_particles_[2].momentum().x0();
556  const double e4 = incoming_particles_[3].momentum().x0();
557  const double e5 = incoming_particles_[4].momentum().x0();
558 
559  const double man_s = sqrt_s() * sqrt_s();
560  const double lamb = lambda_tilde(man_s, mout * mout, mout * mout);
561  const double ph_sp_5 = parametrizaton_phi5_pions(man_s);
562 
563  // Matching the NNbar anihilation cross section defintion for 2-to-5
564  const double xs =
565  std::max(0., ppbar_total(man_s) - ppbar_elastic(man_s)) / gev2_mb;
566 
567  return dt / std::pow(gcell_vol, 4.0) * 1. / (32. * e1 * e2 * e3 * e4 * e5) *
568  xs / (4. * M_PI * man_s) * lamb / ph_sp_5 * std::pow(hbarc, 11.0) *
569  degen_sym_factor;
570 }
571 
572 double ScatterActionMulti::parametrizaton_phi5_pions(const double man_s) const {
573  // see function documentation for parameter naming
574  const double s_zero = 25 * pion_mass * pion_mass;
575  const double fit_a = 2.1018e-10;
576  const double fit_alpha = 1.982;
577  return fit_a * std::pow(man_s - s_zero, 5.0) *
578  std::pow(1 + man_s / s_zero, -fit_alpha);
579 }
580 
582  if (outgoing_particles_.size() != 1) {
583  std::string s =
584  "Annihilation: "
585  "Incorrect number of particles in final state: ";
586  s += std::to_string(outgoing_particles_.size()) + ".";
587  throw InvalidScatterActionMulti(s);
588  }
589  // Set the momentum of the formed particle in its rest frame.
590  outgoing_particles_[0].set_4momentum(
591  total_momentum_of_outgoing_particles().abs(), 0., 0., 0.);
592  // Make sure to assign formation times before boost to the computational frame
594 
595  logg[LScatterActionMulti].debug("Momentum of the new particle: ",
596  outgoing_particles_[0].momentum());
597 }
598 
601  // Make sure to assign formation times before boost to the computational frame
604  "->2 scattering:", incoming_particles_,
605  " -> ", outgoing_particles_);
606 }
607 
609  const ParticleData& data_a, const ParticleData& data_b,
610  const ParticleData& data_c) const {
611  // We want a combination of pi+, pi- and pi0
612  const PdgCode pdg_a = data_a.pdgcode();
613  const PdgCode pdg_b = data_b.pdgcode();
614  const PdgCode pdg_c = data_c.pdgcode();
615 
616  return (pdg_a.is_pion() && pdg_b.is_pion() && pdg_c.is_pion()) &&
617  (pdg_a != pdg_b && pdg_b != pdg_c && pdg_c != pdg_a);
618 }
619 
621  const ParticleData& data_b,
622  const ParticleData& data_c) const {
623  // We want a combination of pi0, pi0 and eta or pi+, pi- and eta
624  const PdgCode pdg_a = data_a.pdgcode();
625  const PdgCode pdg_b = data_b.pdgcode();
626  const PdgCode pdg_c = data_c.pdgcode();
627 
628  return (pdg_a == pdg::pi_z && pdg_b == pdg::pi_z && pdg_c == pdg::eta) ||
629  (pdg_a == pdg::pi_z && pdg_b == pdg::eta && pdg_c == pdg::pi_z) ||
630  (pdg_a == pdg::eta && pdg_b == pdg::pi_z && pdg_c == pdg::pi_z) ||
631 
632  (pdg_a == pdg::eta && pdg_b == pdg::pi_m && pdg_c == pdg::pi_p) ||
633  (pdg_a == pdg::eta && pdg_b == pdg::pi_p && pdg_c == pdg::pi_m) ||
634  (pdg_a == pdg::pi_m && pdg_b == pdg::pi_p && pdg_c == pdg::eta) ||
635  (pdg_a == pdg::pi_m && pdg_b == pdg::eta && pdg_c == pdg::pi_p) ||
636  (pdg_a == pdg::pi_p && pdg_b == pdg::pi_m && pdg_c == pdg::eta) ||
637  (pdg_a == pdg::pi_p && pdg_b == pdg::eta && pdg_c == pdg::pi_m);
638 }
639 
642  const bool all_inc_pi =
644  [](const ParticleData& data) { return data.is_pion(); });
645  const int no_of_piz = std::count_if(
647  [](const ParticleData& data) { return data.pdgcode() == pdg::pi_z; });
648 
649  int total_state_charge = 0;
650  for (const ParticleData& part : incoming_particles_) {
651  total_state_charge += part.pdgcode().charge();
652  }
653 
654  return (all_inc_pi && total_state_charge == 0 && no_of_piz == 1);
655 }
656 
657 void ScatterActionMulti::format_debug_output(std::ostream& out) const {
658  out << "MultiParticleScatter of " << incoming_particles_;
659  if (outgoing_particles_.empty()) {
660  out << " (not performed)";
661  } else {
662  out << " to " << outgoing_particles_;
663  }
664 }
665 
666 } // namespace smash
Action is the base class for a generic process that takes a number of incoming particles and transfor...
Definition: action.h:35
void sample_2body_phasespace()
Sample the full 2-body phase-space (masses, momenta, angles) in the center-of-mass frame for the fina...
Definition: action.cc:302
FourVector total_momentum_of_outgoing_particles() const
Calculate the total kinetic momentum of the outgoing particles.
Definition: action.cc:157
void assign_formation_time_to_outgoing_particles()
Assign the formation time to the outgoing particles.
Definition: action.cc:188
ParticleList outgoing_particles_
Initially this stores only the PDG codes of final-state particles.
Definition: action.h:363
double sqrt_s() const
Determine the total energy in the center-of-mass frame [GeV].
Definition: action.h:271
ParticleList incoming_particles_
List with data of incoming particles.
Definition: action.h:355
FourVector get_interaction_point() const
Get the interaction point.
Definition: action.cc:68
static double lambda_tilde(double a, double b, double c)
Little helper function that calculates the lambda function (sometimes written with a tilde to better ...
Definition: action.h:315
ProcessType process_type_
type of process
Definition: action.h:372
CollisionBranch is a derivative of ProcessBranch, which is used to represent particular final-state c...
ProcessType get_type() const override
static double two_to_three_xs(const ParticleType &type_in1, const ParticleType &type_in2, double sqrts)
Determine 2->3 cross section for the scattering of the given particle types.
static double two_to_four_xs(const ParticleType &type_in1, const ParticleType &type_in2, double sqrts)
Determine 2->4 cross section for the scattering of the given particle types.
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:33
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:58
PdgCode pdgcode() const
Get the pdgcode of the particle.
Definition: particledata.h:87
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 spectral_function(double m) const
Full spectral function of the resonance (relativistic Breit-Wigner distribution with mass-dependent ...
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...
static const ParticleTypePtr try_find(PdgCode pdgcode)
Returns the ParticleTypePtr for the given pdgcode.
Definition: particletype.cc:89
unsigned int spin_degeneracy() const
Definition: particletype.h:195
double mass() const
Definition: particletype.h:145
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
Definition: pdgcode.h:111
bool is_pion() const
Definition: pdgcode.h:457
bool is_nucleon() const
Definition: pdgcode.h:397
static PdgCode invalid()
PdgCode 0x0 is guaranteed not to be valid by the PDG standard, but it passes all tests here,...
Definition: pdgcode.h:758
bool is_Lambda() const
Definition: pdgcode.h:441
unsigned int spin_degeneracy() const
Definition: pdgcode.h:644
ParticleList particle_list() const
double weight() const
Thrown when ScatterActionMulti is called to perform with unknown combination of incoming and outgoing...
double probability_four_to_two(const ParticleType &type_out1, const ParticleType &type_out2, double dt, const double gcell_vol, const double degen_sym_factor=1.0) const
Calculate the probability for a 4-to-2 reaction according to the stochastic collision criterion as gi...
double total_probability_
Total probability of reaction.
bool two_pions_eta(const ParticleData &data_a, const ParticleData &data_b, const ParticleData &data_c) const
Check wether the three incoming particles are π⁺,π⁻,η or π⁰,π⁰,η in any order.
double probability_three_to_one(const ParticleType &type_out, double dt, const double gcell_vol, const int degen_sym_factor=1) const
Calculate the probability for a 3m-to-1 reaction according to the stochastic collision criterion as g...
bool all_incoming_particles_are_pions_have_zero_charge_only_one_piz() const
Check if 5 incoming particles match intial pion state for 5-to-2, which is pi+ pi- pi+ pi- pi0 in ord...
void generate_final_state() override
Generate the final-state of the multi-particle scattering process.
double get_partial_weight() const override
Get the partial probability for the chosen channel (scaled with the cross section scaling factors of ...
double react_degen_factor(const int spin_factor_inc, const int spin_degen_out1, const int spin_degen_out2) const
Determine the spin degeneracy factor ( ) for the N->2 reaction.
void format_debug_output(std::ostream &out) const override
Writes information about this action to the out stream.
void add_reactions(CollisionBranchList pv)
Add several new reaction channels at once.
void add_possible_reactions(double dt, const double gcell_vol, const MultiParticleReactionsBitSet incl_multi)
Add all possible multi-particle reactions for the given incoming particles.
double probability_five_to_two(const double m_out, double dt, const double gcell_vol, const double degen_sym_factor=1.0) const
Calculate the probability for a 5-to-2 reaction according to the stochastic collision criterion as gi...
CollisionBranchList reaction_channels_
List of possible collisions.
double probability_three_to_two(const ParticleType &type_out1, const ParticleType &type_out2, double dt, const double gcell_vol, const double degen_sym_factor=1.0) const
Calculate the probability for a 3-to-2 reaction according to the stochastic collision criterion as gi...
double calculate_I3(const double sqrts) const
Calculate the integration necessary for the three-body phase space.
double parametrizaton_phi5_pions(const double man_s) const
Calculate the parametrized 5-pion phase space.
double get_total_weight() const override
Get the total probability for the reaction (scaled with the cross section scaling factors of the inco...
bool three_different_pions(const ParticleData &data_a, const ParticleData &data_b, const ParticleData &data_c) const
Check wether the three incoming particles are π⁺,π⁻,π⁰ in any order.
ScatterActionMulti(const ParticleList &in_plist, double time)
Construct a ScatterActionMulti object.
void add_reaction(CollisionBranchPtr p)
Add a new reaction channel.
double partial_probability_
Partial probability of the chosen outgoing channel.
void n_to_two()
Perform a n->2 process.
void annihilation()
Perform a n->1 annihilation process.
double parametrizaton_phi4(const double man_s) const
Calculate the parametrized 4-body relativistic phase space integral.
std::bitset< 4 > MultiParticleReactionsBitSet
Container for the n to m reactions in the code.
@ NNbar_5to2
@ A3_Nuclei_4to2
@ Deuteron_3to2
@ Meson_3to1
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
constexpr int pi_p
π⁺.
constexpr int64_t antideuteron
Anti-deuteron in decimal digits.
constexpr int64_t triton
Triton.
constexpr int64_t antihe3
Anti-He-3.
constexpr int p
Proton.
constexpr int64_t hypertriton
Hypertriton.
constexpr int64_t antihypertriton
Anti-Hypertriton.
constexpr int eta
η.
constexpr int64_t antitriton
Anti-triton.
constexpr int pi_z
π⁰.
constexpr int n
Neutron.
constexpr int64_t deuteron
Deuteron.
constexpr int Lambda
Λ.
constexpr int pi_m
π⁻.
constexpr int64_t he3
He-3.
Definition: action.h:24
constexpr double gev2_mb
GeV^-2 <-> mb conversion factor.
Definition: constants.h:31
double ppbar_total(double mandelstam_s)
ppbar total cross section parametrization Source: Bass:1998ca
static constexpr int LScatterActionMulti
double ppbar_elastic(double mandelstam_s)
ppbar elastic cross section parametrization Source: Bass:1998ca
@ MultiParticleThreeToTwo
See here for a short description.
@ MultiParticleThreeMesonsToOne
See here for a short description.
@ MultiParticleFourToTwo
See here for a short description.
@ MultiParticleFiveToTwo
See here for a short description.
bool all_of(Container &&c, UnaryPredicate &&p)
Convenience wrapper for std::all_of that operates on a complete container.
Definition: algorithms.h:80
constexpr T pow_int(const T base, unsigned const exponent)
Efficient template for calculating integer powers using squaring.
Definition: pow.h:23
constexpr double pion_mass
Pion mass in GeV.
Definition: constants.h:65
constexpr double hbarc
GeV <-> fm conversion factor.
Definition: constants.h:25