Version: SMASH-2.2
scatteractionmulti.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2021
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
11 
12 #include <gsl/gsl_sf_ellint.h>
13 
14 #include <map>
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(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(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(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 = ParticleType::try_find(pdg::d);
109  const ParticleTypePtr type_anti_deuteron =
111 
112  const int spin_factor_inc = pdg_a.spin_degeneracy() *
113  pdg_b.spin_degeneracy() *
114  pdg_c.spin_degeneracy();
115 
116  if (type_deuteron && type_anti_deuteron) {
117  // πpn → πd
118  if ((pdg_a.is_pion() && pdg_b == pdg::p && pdg_c == pdg::n) ||
119  (pdg_a.is_pion() && pdg_b == pdg::n && pdg_c == pdg::p) ||
120  (pdg_a == pdg::p && pdg_b.is_pion() && pdg_c == pdg::n) ||
121  (pdg_a == pdg::n && pdg_b.is_pion() && pdg_c == pdg::p) ||
122  (pdg_a == pdg::p && pdg_b == pdg::n && pdg_c.is_pion()) ||
123  (pdg_a == pdg::n && pdg_b == pdg::p && pdg_c.is_pion())) {
124  // Get type of incoming π
125  ParticleList::iterator it = std::find_if(
127  [](ParticleData x) { return x.is_pion(); });
128  const ParticleType& type_pi = it->type();
129 
130  const double spin_degn =
131  react_degen_factor(spin_factor_inc, type_pi.spin_degeneracy(),
132  type_deuteron->spin_degeneracy());
133 
134  add_reaction(make_unique<CollisionBranch>(
135  type_pi, *type_deuteron,
136  probability_three_to_two(type_pi, *type_deuteron, dt, gcell_vol,
137  spin_degn),
139  }
140 
141  // πp̅n̅ → πd̅
142  if ((pdg_a.is_pion() && pdg_b == -pdg::p && pdg_c == -pdg::n) ||
143  (pdg_a.is_pion() && pdg_b == -pdg::n && pdg_c == -pdg::p) ||
144  (pdg_a == -pdg::p && pdg_b.is_pion() && pdg_c == -pdg::n) ||
145  (pdg_a == -pdg::n && pdg_b.is_pion() && pdg_c == -pdg::p) ||
146  (pdg_a == -pdg::p && pdg_b == -pdg::n && pdg_c.is_pion()) ||
147  (pdg_a == -pdg::n && pdg_b == -pdg::p && pdg_c.is_pion())) {
148  // Get type of incoming π
149  ParticleList::iterator it = std::find_if(
151  [](ParticleData x) { return x.is_pion(); });
152  const ParticleType& type_pi = it->type();
153 
154  const double spin_degn =
155  react_degen_factor(spin_factor_inc, type_pi.spin_degeneracy(),
156  type_anti_deuteron->spin_degeneracy());
157 
158  add_reaction(make_unique<CollisionBranch>(
159  type_pi, *type_anti_deuteron,
160  probability_three_to_two(type_pi, *type_anti_deuteron, dt,
161  gcell_vol, spin_degn),
163  }
164 
165  // Nnp → Nd, N̅np → N̅d
166  if ((pdg_a.is_nucleon() && pdg_b == pdg::p && pdg_c == pdg::n) ||
167  (pdg_a.is_nucleon() && pdg_b == pdg::n && pdg_c == pdg::p) ||
168  (pdg_a == pdg::p && pdg_b.is_nucleon() && pdg_c == pdg::n) ||
169  (pdg_a == pdg::n && pdg_b.is_nucleon() && pdg_c == pdg::p) ||
170  (pdg_a == pdg::p && pdg_b == pdg::n && pdg_c.is_nucleon()) ||
171  (pdg_a == pdg::n && pdg_b == pdg::p && pdg_c.is_nucleon())) {
172  int symmetry_factor = 1; // already true for N̅np → N̅d case
173 
174  ParticleList::iterator it =
175  std::find_if(incoming_particles_.begin(),
176  incoming_particles_.end(), [](ParticleData x) {
177  return x.pdgcode().antiparticle_sign() == -1;
178  });
179  if (it == incoming_particles_.end()) {
180  /* Meaning no anti-N found by find_if,
181  * therefore not N̅np → N̅d, but Nnp → Nd. */
182  symmetry_factor = 2; // for Nnp → Nd (2 factorial)
183  // It is already clear here that we have a double of two N
184  if (pdg_a == pdg_b) {
185  it = incoming_particles_.begin();
186  } else {
187  // If a and b are not the double, then c has to be part of it
188  it = incoming_particles_.begin() + 2;
189  }
190  }
191  const ParticleType& type_N = it->type();
192 
193  const double spin_degn =
194  react_degen_factor(spin_factor_inc, type_N.spin_degeneracy(),
195  type_deuteron->spin_degeneracy());
196 
197  add_reaction(make_unique<CollisionBranch>(
198  type_N, *type_deuteron,
199  probability_three_to_two(type_N, *type_deuteron, dt, gcell_vol,
200  symmetry_factor * spin_degn),
202  }
203 
204  // Np̅n̅ → Nd̅, N̅p̅n̅ → N̅d̅
205  if ((pdg_a.is_nucleon() && pdg_b == -pdg::p && pdg_c == -pdg::n) ||
206  (pdg_a.is_nucleon() && pdg_b == -pdg::n && pdg_c == -pdg::p) ||
207  (pdg_a == -pdg::p && pdg_b.is_nucleon() && pdg_c == -pdg::n) ||
208  (pdg_a == -pdg::n && pdg_b.is_nucleon() && pdg_c == -pdg::p) ||
209  (pdg_a == -pdg::p && pdg_b == -pdg::n && pdg_c.is_nucleon()) ||
210  (pdg_a == -pdg::n && pdg_b == -pdg::p && pdg_c.is_nucleon())) {
211  int symmetry_factor = 1; // already true for Np̅n̅ → Nd̅ case
212 
213  ParticleList::iterator it =
214  std::find_if(incoming_particles_.begin(),
215  incoming_particles_.end(), [](ParticleData x) {
216  return x.pdgcode().antiparticle_sign() == 1;
217  });
218  if (it == incoming_particles_.end()) {
219  /* Meaning no N found by find_if,
220  * therefore not Np̅n̅ → Nd̅, but N̅p̅n̅ → N̅d̅. */
221  symmetry_factor = 2; // for N̅p̅n̅ → N̅d̅ (2 factorial)
222  // It is already clear here that we have a double of two N̅
223  if (pdg_a == pdg_b) {
224  it = incoming_particles_.begin();
225  } else {
226  // If a and b are not the double, then c has to be part of it
227  it = incoming_particles_.begin() + 2;
228  }
229  }
230  const ParticleType& type_N = it->type();
231 
232  const double spin_degn =
233  react_degen_factor(spin_factor_inc, type_N.spin_degeneracy(),
234  type_anti_deuteron->spin_degeneracy());
235 
236  add_reaction(make_unique<CollisionBranch>(
237  type_N, *type_anti_deuteron,
238  probability_three_to_two(type_N, *type_anti_deuteron, dt,
239  gcell_vol, symmetry_factor * spin_degn),
241  }
242  }
243  }
244  }
245  // 4 -> 2
246  if (incoming_particles_.size() == 4 &&
248  std::map<PdgCode, int> c; // counts incoming PdgCodes
249  int spin_factor_inc = 1;
250  for (const ParticleData& data : incoming_particles_) {
251  c[data.pdgcode()]++;
252  spin_factor_inc *= data.pdgcode().spin_degeneracy();
253  }
254  // Nucleons, antinucleons, and pions can catalyze
255  const int n_possible_catalysts_incoming =
256  c[pdg::n] + c[pdg::p] + c[-pdg::p] + c[-pdg::n] + c[pdg::pi_p] +
257  c[pdg::pi_z] + c[pdg::pi_m];
258 
259  for (PdgCode pdg_nucleus :
262  const ParticleTypePtr type_nucleus = ParticleType::try_find(pdg_nucleus);
263  // Nucleus can be formed if and only if:
264  // 1) Incoming particles contain enough components (like p, n, Lambda)
265  // 2) In (incoming particles - components) there is still a catalyst
266  // This is including the situation like nnpp. Can be that t(nnp) is formed
267  // and p is catalyst, can be that he-3(ppn) is formed and n is catalyst.
268  // Both reactions should be added.
269  const int n_nucleus_components_that_can_be_catalysts =
270  pdg_nucleus.nucleus_p() + pdg_nucleus.nucleus_ap() +
271  pdg_nucleus.nucleus_n() + pdg_nucleus.nucleus_an();
272  const bool incoming_contain_nucleus_components =
273  c[pdg::p] >= pdg_nucleus.nucleus_p() &&
274  c[-pdg::p] >= pdg_nucleus.nucleus_ap() &&
275  c[pdg::n] >= pdg_nucleus.nucleus_n() &&
276  c[-pdg::n] >= pdg_nucleus.nucleus_an() &&
277  c[pdg::Lambda] >= pdg_nucleus.nucleus_La() &&
278  c[-pdg::Lambda] >= pdg_nucleus.nucleus_aLa();
279  const bool can_form_nucleus =
280  type_nucleus && incoming_contain_nucleus_components &&
281  n_possible_catalysts_incoming -
282  n_nucleus_components_that_can_be_catalysts ==
283  1;
284 
285  if (!can_form_nucleus) {
286  continue;
287  }
288  // Find the catalyst
289  std::map<PdgCode, int> catalyst_count = c;
290  catalyst_count[pdg::p] -= pdg_nucleus.nucleus_p();
291  catalyst_count[-pdg::p] -= pdg_nucleus.nucleus_ap();
292  catalyst_count[pdg::n] -= pdg_nucleus.nucleus_n();
293  catalyst_count[-pdg::n] -= pdg_nucleus.nucleus_an();
294  catalyst_count[pdg::Lambda] -= pdg_nucleus.nucleus_La();
295  catalyst_count[-pdg::Lambda] -= pdg_nucleus.nucleus_aLa();
296  PdgCode pdg_catalyst = PdgCode::invalid();
297  for (const auto i : catalyst_count) {
298  if (i.second == 1) {
299  pdg_catalyst = i.first;
300  break;
301  }
302  }
303  if (pdg_catalyst == PdgCode::invalid()) {
304  logg[LScatterActionMulti].error("Something went wrong while forming",
305  pdg_nucleus, " from ",
307  }
308  const ParticleTypePtr type_catalyst =
309  ParticleType::try_find(pdg_catalyst);
310  const double spin_degn =
311  react_degen_factor(spin_factor_inc, type_catalyst->spin_degeneracy(),
312  type_nucleus->spin_degeneracy());
313  double symmetry_factor = 1.0;
314  for (const auto i : c) {
315  symmetry_factor *= (i.second == 3) ? 6.0 // 3!
316  : (i.second == 2) ? 2.0 // 2!
317  : 1.0;
318  if (i.second > 3 || i.second < 0) {
319  logg[LScatterActionMulti].error("4<->2 error, incoming particles ",
321  }
322  }
323 
324  add_reaction(make_unique<CollisionBranch>(
325  *type_catalyst, *type_nucleus,
326  probability_four_to_two(*type_catalyst, *type_nucleus, dt, gcell_vol,
327  symmetry_factor * spin_degn),
329  }
330  }
331  // 5 -> 2
332  if (incoming_particles_.size() == 5) {
333  if (incl_multi[IncludedMultiParticleReactions::NNbar_5to2] == 1) {
335  const int spin_factor_inc =
336  incoming_particles_[0].pdgcode().spin_degeneracy() *
337  incoming_particles_[1].pdgcode().spin_degeneracy() *
338  incoming_particles_[2].pdgcode().spin_degeneracy() *
339  incoming_particles_[3].pdgcode().spin_degeneracy() *
340  incoming_particles_[4].pdgcode().spin_degeneracy();
341  const double symmetry_factor = 4.0; // 2! * 2!
342 
344  const ParticleTypePtr type_anti_p = ParticleType::try_find(-pdg::p);
346  const ParticleTypePtr type_anti_n = ParticleType::try_find(-pdg::n);
347 
348  const double spin_degn =
349  react_degen_factor(spin_factor_inc, type_p->spin_degeneracy(),
350  type_anti_p->spin_degeneracy());
351 
352  if (type_p && type_n) {
353  const double prob = probability_five_to_two(
354  type_p->mass(), dt, gcell_vol,
355  symmetry_factor * spin_degn); // same for ppbar and nnbar
356  add_reaction(make_unique<CollisionBranch>(
357  *type_p, *type_anti_p, prob,
359  add_reaction(make_unique<CollisionBranch>(
360  *type_n, *type_anti_n, prob,
362  }
363  }
364  }
365  }
366 }
367 
369  logg[LScatterActionMulti].debug("Incoming particles for ScatterActionMulti: ",
371 
372  /* Decide for a particular final state. */
373  const CollisionBranch* proc =
374  choose_channel<CollisionBranch>(reaction_channels_, total_probability_);
375  process_type_ = proc->get_type();
377  partial_probability_ = proc->weight();
378 
379  logg[LScatterActionMulti].debug("Chosen channel: ", process_type_,
381 
382  switch (process_type_) {
384  /* n->1 annihilation */
385  annihilation();
386  break;
390  /* n->2 scattering */
391  n_to_two();
392  break;
393  default:
395  "ScatterActionMulti::generate_final_state: Invalid process type " +
396  std::to_string(static_cast<int>(process_type_)) + " was requested.");
397  }
398 
399  /* The production point of the new particles. */
400  FourVector middle_point = get_interaction_point();
401 
402  for (ParticleData& new_particle : outgoing_particles_) {
403  // Boost to the computational frame
404  new_particle.boost_momentum(
406  /* Set positions of the outgoing particles */
407  new_particle.set_4position(middle_point);
408  }
409 }
410 
411 double ScatterActionMulti::calculate_I3(const double sqrts) const {
412  const double m1 = incoming_particles_[0].type().mass();
413  const double m2 = incoming_particles_[1].type().mass();
414  const double m3 = incoming_particles_[2].type().mass();
415 
416  if (sqrts < m1 + m2 + m3) {
417  return 0.0;
418  }
419  const double x1 = (m1 - m2) * (m1 - m2), x2 = (m1 + m2) * (m1 + m2),
420  x3 = (sqrts - m3) * (sqrts - m3),
421  x4 = (sqrts + m3) * (sqrts + m3);
422  const double qmm = x3 - x1, qmp = x3 - x2, qpm = x4 - x1, qpp = x4 - x2;
423  const double kappa = std::sqrt(qpm * qmp / (qpp * qmm));
424  const double tmp = std::sqrt(qmm * qpp);
425  const double c1 =
426  4.0 * m1 * m2 * std::sqrt(qmm / qpp) * (x4 - m3 * sqrts + m1 * m2);
427  const double c2 = 0.5 * (m1 * m1 + m2 * m2 + m3 * m3 + sqrts * sqrts) * tmp;
428  const double c3 = 8 * m1 * m2 / tmp *
429  ((m1 * m1 + m2 * m2) * (m3 * m3 + sqrts * sqrts) -
430  2 * m1 * m1 * m2 * m2 - 2 * m3 * m3 * sqrts * sqrts);
431  const double c4 =
432  -8 * m1 * m2 / tmp * smash::pow_int(sqrts * sqrts - m3 * m3, 2);
433  const double precision = 1.e-6;
434  const double res =
435  c1 * gsl_sf_ellint_Kcomp(kappa, precision) +
436  c2 * gsl_sf_ellint_Ecomp(kappa, precision) +
437  c3 * gsl_sf_ellint_Pcomp(kappa, -qmp / qmm, precision) +
438  c4 * gsl_sf_ellint_Pcomp(kappa, -x1 * qmp / (x2 * qmm), precision);
439  return res;
440 }
441 
443  const ParticleType& type_out, double dt, const double gcell_vol,
444  const int degen_sym_factor) const {
445  const double e1 = incoming_particles_[0].momentum().x0();
446  const double e2 = incoming_particles_[1].momentum().x0();
447  const double e3 = incoming_particles_[2].momentum().x0();
448  const double sqrts = sqrt_s();
449 
450  const double gamma_decay = type_out.get_partial_width(
451  sqrts, {&incoming_particles_[0].type(), &incoming_particles_[1].type(),
452  &incoming_particles_[2].type()});
453 
454  const double I_3 = calculate_I3(sqrts);
455  const double ph_sp_3 =
456  1. / (8 * M_PI * M_PI * M_PI) * 1. / (16 * sqrts * sqrts) * I_3;
457 
458  const double spec_f_val = type_out.spectral_function(sqrts);
459 
460  return dt / (gcell_vol * gcell_vol) * M_PI / (4. * e1 * e2 * e3) *
461  gamma_decay / ph_sp_3 * spec_f_val * std::pow(hbarc, 5.0) *
462  degen_sym_factor;
463 }
464 
466  const ParticleType& type_out1, const ParticleType& type_out2, double dt,
467  const double gcell_vol, const double degen_sym_factor) const {
468  const double e1 = incoming_particles_[0].momentum().x0();
469  const double e2 = incoming_particles_[1].momentum().x0();
470  const double e3 = incoming_particles_[2].momentum().x0();
471  const double m4 = type_out1.mass();
472  const double m5 = type_out2.mass();
473 
474  const double sqrts = sqrt_s();
475  const double xs =
476  CrossSections::two_to_three_xs(type_out1, type_out2, sqrts) / gev2_mb;
477  const double lamb = lambda_tilde(sqrts * sqrts, m4 * m4, m5 * m5);
478 
479  const double I_3 = calculate_I3(sqrts);
480  const double ph_sp_3 =
481  1. / (8 * M_PI * M_PI * M_PI) * 1. / (16 * sqrts * sqrts) * I_3;
482 
483  return dt / (gcell_vol * gcell_vol) * 1. / (4. * e1 * e2 * e3) * lamb /
484  (ph_sp_3 * 8 * M_PI * sqrts * sqrts) * xs * std::pow(hbarc, 5.0) *
485  degen_sym_factor;
486 }
487 
489  const ParticleType& type_out1, const ParticleType& type_out2, double dt,
490  const double gcell_vol, const double degen_sym_factor) const {
491  const double e1 = incoming_particles_[0].momentum().x0();
492  const double e2 = incoming_particles_[1].momentum().x0();
493  const double e3 = incoming_particles_[2].momentum().x0();
494  const double e4 = incoming_particles_[3].momentum().x0();
495  const double m5 = type_out1.mass();
496  const double m6 = type_out2.mass();
497 
498  const double man_s = sqrt_s() * sqrt_s();
499  const double xs =
500  CrossSections::two_to_four_xs(type_out1, type_out2, sqrt_s()) / gev2_mb;
501  const double lamb = lambda_tilde(man_s, m5 * m5, m6 * m6);
502  const double ph_sp_4 = parametrizaton_phi4(man_s);
503 
504  return dt / std::pow(gcell_vol, 3.0) * 1. / (16. * e1 * e2 * e3 * e4) * xs /
505  (4. * M_PI * man_s) * lamb / ph_sp_4 * std::pow(hbarc, 8.0) *
506  degen_sym_factor;
507 }
508 
509 double ScatterActionMulti::parametrizaton_phi4(const double man_s) const {
510  int n_nucleons = 0, n_pions = 0, n_lambdas = 0;
511  double sum_m = 0.0, prod_m = 1.0;
512  for (const ParticleData& data : incoming_particles_) {
513  const PdgCode pdg = data.type().pdgcode();
514  n_nucleons += pdg.is_nucleon(); // including anti-nucleons
515  n_pions += pdg.is_pion();
516  n_lambdas += pdg.is_Lambda(); // including anti-Lambda
517  sum_m += data.type().mass();
518  prod_m *= data.type().mass();
519  }
520  const double x = 1.0 - sum_m / std::sqrt(man_s);
521  const double x2 = x * x;
522  const double x3 = x2 * x;
523  double g = -1.0;
524 
525  if (n_nucleons == 3 && n_pions == 1) { // NNNpi
526  g = (1.0 + 0.862432 * x - 3.4853 * x2 + 1.70259 * x3) /
527  (1.0 + 0.387376 * x - 1.34128 * x2 + 0.154489 * x3);
528  } else if (n_nucleons == 4) { // NNNN
529  g = (1.0 - 1.72285 * x + 0.728331 * x2) /
530  (1.0 - 0.967146 * x - 0.0103633 * x2);
531  } else if (n_nucleons == 2 && n_lambdas == 1 && n_pions == 1) { // LaNNpi
532  g = (1.0 + 0.937064 * x - 3.56864 * x2 + 1.721 * x3) /
533  (1.0 + 0.365202 * x - 1.2854 * x2 + 0.138444 * x3);
534  } else if (n_nucleons == 3 && n_lambdas == 1) { // LaNNN
535  g = (1.0 + 0.882401 * x - 3.4074 * x2 + 1.62454 * x3) /
536  (1.0 + 1.61741 * x - 2.12543 * x2 - 0.0902067 * x3);
537  }
538 
539  if (g > 0.0) {
540  return (std::sqrt(prod_m) * sum_m * sum_m * std::pow(x, 3.5) * g) /
541  (840. * std::sqrt(2) * std::pow(M_PI, 4.0) * std::pow(1 - x, 4.0));
542  } else {
543  logg[LScatterActionMulti].error("parametrizaton_phi4: no parametrization ",
544  "available for ", incoming_particles_);
545  return 0.0;
546  }
547 }
548 
550  const double mout, double dt, const double gcell_vol,
551  const double degen_sym_factor) const {
552  const double e1 = incoming_particles_[0].momentum().x0();
553  const double e2 = incoming_particles_[1].momentum().x0();
554  const double e3 = incoming_particles_[2].momentum().x0();
555  const double e4 = incoming_particles_[3].momentum().x0();
556  const double e5 = incoming_particles_[4].momentum().x0();
557 
558  const double man_s = sqrt_s() * sqrt_s();
559  const double lamb = lambda_tilde(man_s, mout * mout, mout * mout);
560  const double ph_sp_5 = parametrizaton_phi5_pions(man_s);
561 
562  // Matching the NNbar anihilation cross section defintion for 2-to-5
563  const double xs =
564  std::max(0., ppbar_total(man_s) - ppbar_elastic(man_s)) / gev2_mb;
565 
566  return dt / std::pow(gcell_vol, 4.0) * 1. / (32. * e1 * e2 * e3 * e4 * e5) *
567  xs / (4. * M_PI * man_s) * lamb / ph_sp_5 * std::pow(hbarc, 11.0) *
568  degen_sym_factor;
569 }
570 
571 double ScatterActionMulti::parametrizaton_phi5_pions(const double man_s) const {
572  // see function documentation for parameter naming
573  const double s_zero = 25 * pion_mass * pion_mass;
574  const double fit_a = 2.1018e-10;
575  const double fit_alpha = 1.982;
576  return fit_a * std::pow(man_s - s_zero, 5.0) *
577  std::pow(1 + man_s / s_zero, -fit_alpha);
578 }
579 
581  if (outgoing_particles_.size() != 1) {
582  std::string s =
583  "Annihilation: "
584  "Incorrect number of particles in final state: ";
585  s += std::to_string(outgoing_particles_.size()) + ".";
586  throw InvalidScatterActionMulti(s);
587  }
588  // Set the momentum of the formed particle in its rest frame.
589  outgoing_particles_[0].set_4momentum(
590  total_momentum_of_outgoing_particles().abs(), 0., 0., 0.);
591  // Make sure to assign formation times before boost to the computational frame
593 
594  logg[LScatterActionMulti].debug("Momentum of the new particle: ",
595  outgoing_particles_[0].momentum());
596 }
597 
600  // Make sure to assign formation times before boost to the computational frame
603  "->2 scattering:", incoming_particles_,
604  " -> ", outgoing_particles_);
605 }
606 
608  const ParticleData& data_a, const ParticleData& data_b,
609  const ParticleData& data_c) const {
610  // We want a combination of pi+, pi- and pi0
611  const PdgCode pdg_a = data_a.pdgcode();
612  const PdgCode pdg_b = data_b.pdgcode();
613  const PdgCode pdg_c = data_c.pdgcode();
614 
615  return (pdg_a.is_pion() && pdg_b.is_pion() && pdg_c.is_pion()) &&
616  (pdg_a != pdg_b && pdg_b != pdg_c && pdg_c != pdg_a);
617 }
618 
620  const ParticleData& data_b,
621  const ParticleData& data_c) const {
622  // We want a combination of pi0, pi0 and eta or pi+, pi- and eta
623  const PdgCode pdg_a = data_a.pdgcode();
624  const PdgCode pdg_b = data_b.pdgcode();
625  const PdgCode pdg_c = data_c.pdgcode();
626 
627  return (pdg_a == pdg::pi_z && pdg_b == pdg::pi_z && pdg_c == pdg::eta) ||
628  (pdg_a == pdg::pi_z && pdg_b == pdg::eta && pdg_c == pdg::pi_z) ||
629  (pdg_a == pdg::eta && pdg_b == pdg::pi_z && pdg_c == pdg::pi_z) ||
630 
631  (pdg_a == pdg::eta && pdg_b == pdg::pi_m && pdg_c == pdg::pi_p) ||
632  (pdg_a == pdg::eta && pdg_b == pdg::pi_p && pdg_c == pdg::pi_m) ||
633  (pdg_a == pdg::pi_m && pdg_b == pdg::pi_p && pdg_c == pdg::eta) ||
634  (pdg_a == pdg::pi_m && pdg_b == pdg::eta && pdg_c == pdg::pi_p) ||
635  (pdg_a == pdg::pi_p && pdg_b == pdg::pi_m && pdg_c == pdg::eta) ||
636  (pdg_a == pdg::pi_p && pdg_b == pdg::eta && pdg_c == pdg::pi_m);
637 }
638 
641  const bool all_inc_pi =
643  [](const ParticleData& data) { return data.is_pion(); });
644  const int no_of_piz = std::count_if(
646  [](const ParticleData& data) { return data.pdgcode() == pdg::pi_z; });
647 
648  int total_state_charge = 0;
649  for (const ParticleData& part : incoming_particles_) {
650  total_state_charge += part.pdgcode().charge();
651  }
652 
653  return (all_inc_pi && total_state_charge == 0 && no_of_piz == 1);
654 }
655 
656 void ScatterActionMulti::format_debug_output(std::ostream& out) const {
657  out << "MultiParticleScatter of " << incoming_particles_;
658  if (outgoing_particles_.empty()) {
659  out << " (not performed)";
660  } else {
661  out << " to " << outgoing_particles_;
662  }
663 }
664 
665 } // 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:300
FourVector total_momentum_of_outgoing_particles() const
Calculate the total kinetic momentum of the outgoing particles.
Definition: action.cc:155
void assign_formation_time_to_outgoing_particles()
Assign the formation time to the outgoing particles.
Definition: action.cc:186
ParticleList outgoing_particles_
Initially this stores only the PDG codes of final-state particles.
Definition: action.h:348
double sqrt_s() const
Determine the total energy in the center-of-mass frame [GeV].
Definition: action.h:266
ParticleList incoming_particles_
List with data of incoming particles.
Definition: action.h:340
FourVector get_interaction_point() const
Get the interaction point.
Definition: action.cc:67
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:310
ProcessType process_type_
type of process
Definition: action.h:357
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:671
Particle type contains the static properties of a particle species.
Definition: particletype.h:97
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:194
double mass() const
Definition: particletype.h:144
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
Definition: pdgcode.h:108
bool is_pion() const
Definition: pdgcode.h:384
bool is_nucleon() const
Definition: pdgcode.h:324
static PdgCode invalid()
PdgCode 0x0 is guaranteed not to be valid by the PDG standard, but it passes all tests here,...
Definition: pdgcode.h:679
bool is_Lambda() const
Definition: pdgcode.h:368
unsigned int spin_degeneracy() const
Definition: pdgcode.h:565
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
π⁺.
const PdgCode triton(PdgCode::from_decimal(1000010030))
Triton.
constexpr int p
Proton.
const PdgCode d(PdgCode::from_decimal(1000010020))
Deuteron.
constexpr int eta
η.
const PdgCode he3(PdgCode::from_decimal(1000020030))
He-3.
const PdgCode antihe3(PdgCode::from_decimal(-1000020030))
Anti-He-3.
constexpr int pi_z
π⁰.
constexpr int n
Neutron.
const PdgCode antitriton(PdgCode::from_decimal(-1000010030))
Anti-triton.
constexpr int Lambda
Λ.
constexpr int pi_m
π⁻.
const PdgCode hypertriton(PdgCode::from_decimal(1010010030))
Hypertriton.
const PdgCode antid(PdgCode::from_decimal(-1000010020))
Anti-deuteron in decimal digits.
const PdgCode antihypertriton(PdgCode::from_decimal(-1010010030))
Anti-Hypertriton.
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
@ MultiParticleThreeMesonsToOne
multi particle scattering
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