Version: SMASH-1.8
scatteractionsfinder.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2019
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
11 
12 #include <algorithm>
13 #include <map>
14 #include <vector>
15 
16 #include "smash/configuration.h"
17 #include "smash/constants.h"
18 #include "smash/crosssections.h"
19 #include "smash/cxx14compat.h"
20 #include "smash/decaymodes.h"
22 #include "smash/isoparticletype.h"
23 #include "smash/logging.h"
24 #include "smash/macros.h"
25 #include "smash/particles.h"
26 #include "smash/scatteraction.h"
28 #include "smash/stringfunctions.h"
29 
30 namespace smash {
31 static constexpr int LFindScatter = LogArea::FindScatter::id;
233  Configuration config, const ExperimentParameters& parameters,
234  const std::vector<bool>& nucleon_has_interacted, int N_tot, int N_proj)
235  : coll_crit_(config.take({"Collision_Term", "Collision_Criterion"},
237  elastic_parameter_(
238  config.take({"Collision_Term", "Elastic_Cross_Section"}, -1.)),
239  testparticles_(parameters.testparticles),
240  isotropic_(config.take({"Collision_Term", "Isotropic"}, false)),
241  two_to_one_(parameters.two_to_one),
242  incl_set_(parameters.included_2to2),
243  low_snn_cut_(parameters.low_snn_cut),
244  strings_switch_(parameters.strings_switch),
245  use_AQM_(parameters.use_AQM),
246  strings_with_probability_(parameters.strings_with_probability),
247  nnbar_treatment_(parameters.nnbar_treatment),
248  nucleon_has_interacted_(nucleon_has_interacted),
249  N_tot_(N_tot),
250  N_proj_(N_proj),
251  string_formation_time_(config.take(
252  {"Collision_Term", "String_Parameters", "Formation_Time"}, 1.)) {
253  if (coll_crit_ == CollisionCriterion::Stochastic &&
254  !(is_constant_elastic_isotropic())) {
255  throw std::invalid_argument(
256  "The stochastic collision criterion is only supported for elastic (and "
257  "isotropic)\n2-to-2 reactions of one particle species. Change you "
258  "config accordingly.");
259  }
260  if (is_constant_elastic_isotropic()) {
261  logg[LFindScatter].info(
262  "Constant elastic isotropic cross-section mode:", " using ",
263  elastic_parameter_, " mb as maximal cross-section.");
264  }
265  if (strings_switch_) {
266  auto subconfig = config["Collision_Term"]["String_Parameters"];
267  string_process_interface_ = make_unique<StringProcess>(
268  subconfig.take({"String_Tension"}, 1.0), string_formation_time_,
269  subconfig.take({"Gluon_Beta"}, 0.5),
270  subconfig.take({"Gluon_Pmin"}, 0.001),
271  subconfig.take({"Quark_Alpha"}, 2.0),
272  subconfig.take({"Quark_Beta"}, 7.0),
273  subconfig.take({"Strange_Supp"}, 0.16),
274  subconfig.take({"Diquark_Supp"}, 0.036),
275  subconfig.take({"Sigma_Perp"}, 0.42),
276  subconfig.take({"StringZ_A_Leading"}, 0.2),
277  subconfig.take({"StringZ_B_Leading"}, 2.0),
278  subconfig.take({"StringZ_A"}, 2.0), subconfig.take({"StringZ_B"}, 0.55),
279  subconfig.take({"String_Sigma_T"}, 0.5),
280  subconfig.take({"Form_Time_Factor"}, 1.0),
281  subconfig.take({"Mass_Dependent_Formation_Times"}, false),
282  subconfig.take({"Prob_proton_to_d_uu"}, 1. / 3.),
283  subconfig.take({"Separate_Fragment_Baryon"}, true),
284  subconfig.take({"Popcorn_Rate"}, 0.15));
285  }
286 }
287 
289  const ParticleData& data_a, const ParticleData& data_b, double dt,
290  const std::vector<FourVector>& beam_momentum, const double cell_vol) const {
291  /* If the two particles
292  * 1) belong to the two colliding nuclei
293  * 2) are within the same nucleus
294  * 3) both of them have never experienced any collisons,
295  * then the collision between them are banned. */
296  assert(data_a.id() >= 0);
297  assert(data_b.id() >= 0);
298  if (data_a.id() < N_tot_ && data_b.id() < N_tot_ &&
299  ((data_a.id() < N_proj_ && data_b.id() < N_proj_) ||
300  (data_a.id() >= N_proj_ && data_b.id() >= N_proj_)) &&
301  !(nucleon_has_interacted_[data_a.id()] ||
302  nucleon_has_interacted_[data_b.id()])) {
303  return nullptr;
304  }
305 
306  // Determine time of collision.
307  const double time_until_collision =
308  collision_time(data_a, data_b, dt, beam_momentum);
309 
310  // Check that collision happens in this timestep.
311  if (time_until_collision < 0. || time_until_collision >= dt) {
312  return nullptr;
313  }
314 
315  // Create ScatterAction object.
316  ScatterActionPtr act = make_unique<ScatterAction>(
317  data_a, data_b, time_until_collision, isotropic_, string_formation_time_);
318 
319  if (strings_switch_) {
320  act->set_string_interface(string_process_interface_.get());
321  }
322 
324  // No grid or search in cell
325  if (cell_vol < really_small) {
326  return nullptr;
327  }
328 
329  // Add various subprocesses.
330  act->add_all_scatterings(elastic_parameter_, two_to_one_, incl_set_,
333 
334  const double xs = act->cross_section() * fm2_mb;
335 
336  // Relative velocity calculation, see e.g. \iref{Seifert:2017oyb}, eq. (5)
337  const double m1 = act->incoming_particles()[0].effective_mass();
338  const double m1_sqr = m1 * m1;
339  const double m2 = act->incoming_particles()[1].effective_mass();
340  const double m2_sqr = m2 * m2;
341  const double e1 = act->incoming_particles()[0].momentum().x0();
342  const double e2 = act->incoming_particles()[1].momentum().x0();
343  const double m_s = act->mandelstam_s();
344  const double lambda = (m_s - m1_sqr - m2_sqr) * (m_s - m1_sqr - m2_sqr) -
345  4. * m1_sqr * m2_sqr;
346  const double v_rel = std::sqrt(lambda) / (2. * e1 * e2);
347 
348  // Collision probability, see e.g. \iref{Xu:2004mz}, eq. (11)
349  const double p_22 = xs * v_rel * dt / (cell_vol * testparticles_);
350 
351  logg[LFindScatter].debug(
352  "Stochastic collison criterion parameters:\np_22 = ", p_22,
353  ", xs = ", xs, ", v_rel = ", v_rel, ", dt = ", dt,
354  ", cell_vol = ", cell_vol, ", testparticles = ", testparticles_);
355 
356  if (p_22 > 1.) {
357  std::stringstream err;
358  err << "Probability larger than 1 for stochastic rates. ( P = " << p_22
359  << " )\nUse smaller timesteps.";
360  throw std::runtime_error(err.str());
361  }
362 
363  // probability criterion
364  double random_no = random::uniform(0., 1.);
365  if (random_no > p_22) {
366  return nullptr;
367  }
368 
370  // just collided with this particle
371  if (data_a.id_process() > 0 && data_a.id_process() == data_b.id_process()) {
372  logg[LFindScatter].debug("Skipping collided particles at time ",
373  data_a.position().x0(), " due to process ",
374  data_a.id_process(), "\n ", data_a, "\n<-> ",
375  data_b);
376 
377  return nullptr;
378  }
379 
380  const double distance_squared = act->transverse_distance_sqr();
381 
382  // Don't calculate cross section if the particles are very far apart.
383  if (distance_squared >= max_transverse_distance_sqr(testparticles_)) {
384  return nullptr;
385  }
386 
387  // Add various subprocesses.
388  act->add_all_scatterings(elastic_parameter_, two_to_one_, incl_set_,
391 
392  // Cross section for collision criterion
393  double cross_section_criterion = act->cross_section() * fm2_mb * M_1_PI /
394  static_cast<double>(testparticles_);
395 
396  // Take cross section scaling factors into account
397  cross_section_criterion *= data_a.xsec_scaling_factor(time_until_collision);
398  cross_section_criterion *= data_b.xsec_scaling_factor(time_until_collision);
399 
400  // distance criterion according to cross_section
401  if (distance_squared >= cross_section_criterion) {
402  return nullptr;
403  }
404 
405  logg[LFindScatter].debug("particle distance squared: ", distance_squared,
406  "\n ", data_a, "\n<-> ", data_b);
407  }
408 
409  // Using std::move here is redundant with newer compilers, but required for
410  // supporting GCC 4.8. Once we drop this support, std::move should be removed.
411  return std::move(act);
412 }
413 
415  const ParticleList& search_list, double dt, const double cell_vol,
416  const std::vector<FourVector>& beam_momentum) const {
417  std::vector<ActionPtr> actions;
418  for (const ParticleData& p1 : search_list) {
419  for (const ParticleData& p2 : search_list) {
420  if (p1.id() < p2.id()) {
421  // Check if a collision is possible.
422  ActionPtr act = check_collision(p1, p2, dt, beam_momentum, cell_vol);
423  if (act) {
424  actions.push_back(std::move(act));
425  }
426  }
427  }
428  }
429  return actions;
430 }
431 
433  const ParticleList& search_list, const ParticleList& neighbors_list,
434  double dt, const std::vector<FourVector>& beam_momentum) const {
435  std::vector<ActionPtr> actions;
437  // Only search in cells
438  return actions;
439  }
440  for (const ParticleData& p1 : search_list) {
441  for (const ParticleData& p2 : neighbors_list) {
442  assert(p1.id() != p2.id());
443  // Check if a collision is possible.
444  ActionPtr act = check_collision(p1, p2, dt, beam_momentum);
445  if (act) {
446  actions.push_back(std::move(act));
447  }
448  }
449  }
450  return actions;
451 }
452 
454  const ParticleList& search_list, const Particles& surrounding_list,
455  double dt, const std::vector<FourVector>& beam_momentum) const {
456  std::vector<ActionPtr> actions;
458  // Only search in cells
459  return actions;
460  }
461  for (const ParticleData& p2 : surrounding_list) {
462  /* don't look for collisions if the particle from the surrounding list is
463  * also in the search list */
464  auto result = std::find_if(
465  search_list.begin(), search_list.end(),
466  [&p2](const ParticleData& p) { return p.id() == p2.id(); });
467  if (result != search_list.end()) {
468  continue;
469  }
470  for (const ParticleData& p1 : search_list) {
471  // Check if a collision is possible.
472  ActionPtr act = check_collision(p1, p2, dt, beam_momentum);
473  if (act) {
474  actions.push_back(std::move(act));
475  }
476  }
477  }
478  return actions;
479 }
480 
482  constexpr double time = 0.0;
483 
484  const size_t N_isotypes = IsoParticleType::list_all().size();
485  const size_t N_pairs = N_isotypes * (N_isotypes - 1) / 2;
486 
487  std::cout << N_isotypes << " iso-particle types." << std::endl;
488  std::cout << "They can make " << N_pairs << " pairs." << std::endl;
489  std::vector<double> momentum_scan_list = {0.1, 0.3, 0.5, 1.0,
490  2.0, 3.0, 5.0, 10.0};
491  for (const IsoParticleType& A_isotype : IsoParticleType::list_all()) {
492  for (const IsoParticleType& B_isotype : IsoParticleType::list_all()) {
493  if (&A_isotype > &B_isotype) {
494  continue;
495  }
496  bool any_nonzero_cs = false;
497  std::vector<std::string> r_list;
498  for (const ParticleTypePtr A_type : A_isotype.get_states()) {
499  for (const ParticleTypePtr B_type : B_isotype.get_states()) {
500  if (A_type > B_type) {
501  continue;
502  }
503  ParticleData A(*A_type), B(*B_type);
504  for (auto mom : momentum_scan_list) {
505  A.set_4momentum(A.pole_mass(), mom, 0.0, 0.0);
506  B.set_4momentum(B.pole_mass(), -mom, 0.0, 0.0);
507  ScatterActionPtr act = make_unique<ScatterAction>(
508  A, B, time, isotropic_, string_formation_time_);
509  if (strings_switch_) {
510  act->set_string_interface(string_process_interface_.get());
511  }
512  act->add_all_scatterings(elastic_parameter_, two_to_one_, incl_set_,
516  const double total_cs = act->cross_section();
517  if (total_cs <= 0.0) {
518  continue;
519  }
520  any_nonzero_cs = true;
521  for (const auto& channel : act->collision_channels()) {
522  const auto type = channel->get_type();
523  std::string r;
524  if (is_string_soft_process(type) ||
525  type == ProcessType::StringHard) {
526  r = A_type->name() + B_type->name() + std::string(" → strings");
527  } else {
528  std::string r_type =
529  (type == ProcessType::Elastic)
530  ? std::string(" (el)")
531  : (channel->get_type() == ProcessType::TwoToTwo)
532  ? std::string(" (inel)")
533  : std::string(" (?)");
534  r = A_type->name() + B_type->name() + std::string(" → ") +
535  channel->particle_types()[0]->name() +
536  channel->particle_types()[1]->name() + r_type;
537  }
538  isoclean(r);
539  r_list.push_back(r);
540  }
541  }
542  }
543  }
544  std::sort(r_list.begin(), r_list.end());
545  r_list.erase(std::unique(r_list.begin(), r_list.end()), r_list.end());
546  if (any_nonzero_cs) {
547  for (auto r : r_list) {
548  std::cout << r;
549  if (r_list.back() != r) {
550  std::cout << ", ";
551  }
552  }
553  std::cout << std::endl;
554  }
555  }
556  }
557 }
558 
562  std::string name_;
563 
566 
568  double mass_;
569 
578  FinalStateCrossSection(const std::string& name, double cross_section,
579  double mass)
580  : name_(name), cross_section_(cross_section), mass_(mass) {}
581 };
582 
583 namespace decaytree {
584 
596 struct Node {
597  public:
599  std::string name_;
600 
602  double weight_;
603 
605  ParticleTypePtrList initial_particles_;
606 
608  ParticleTypePtrList final_particles_;
609 
611  ParticleTypePtrList state_;
612 
614  std::vector<Node> children_;
615 
617  Node(const Node&) = delete;
619  Node(Node&&) = default;
620 
631  Node(const std::string& name, double weight,
632  ParticleTypePtrList&& initial_particles,
633  ParticleTypePtrList&& final_particles, ParticleTypePtrList&& state,
634  std::vector<Node>&& children)
635  : name_(name),
636  weight_(weight),
637  initial_particles_(std::move(initial_particles)),
638  final_particles_(std::move(final_particles)),
639  state_(std::move(state)),
640  children_(std::move(children)) {}
641 
653  Node& add_action(const std::string& name, double weight,
654  ParticleTypePtrList&& initial_particles,
655  ParticleTypePtrList&& final_particles) {
656  // Copy parent state and update it.
657  ParticleTypePtrList state(state_);
658  for (const auto& p : initial_particles) {
659  state.erase(std::find(state.begin(), state.end(), p));
660  }
661  for (const auto& p : final_particles) {
662  state.push_back(p);
663  }
664  // Sort the state to normalize the output.
665  std::sort(state.begin(), state.end(),
667  return a->name() < b->name();
668  });
669  // Push new node to children.
670  Node new_node(name, weight, std::move(initial_particles),
671  std::move(final_particles), std::move(state), {});
672  children_.emplace_back(std::move(new_node));
673  return children_.back();
674  }
675 
677  void print() const { print_helper(0); }
678 
682  std::vector<FinalStateCrossSection> final_state_cross_sections() const {
683  std::vector<FinalStateCrossSection> result;
684  final_state_cross_sections_helper(0, result, "", 1.);
685  return result;
686  }
687 
688  private:
695  void print_helper(uint64_t depth) const {
696  for (uint64_t i = 0; i < depth; i++) {
697  std::cout << " ";
698  }
699  std::cout << name_ << " " << weight_ << std::endl;
700  for (const auto& child : children_) {
701  child.print_helper(depth + 1);
702  }
703  }
704 
717  uint64_t depth, std::vector<FinalStateCrossSection>& result,
718  const std::string& name, double weight,
719  bool show_intermediate_states = false) const {
720  // The first node corresponds to the total cross section and has to be
721  // ignored. The second node corresponds to the partial cross section. All
722  // further nodes correspond to branching ratios.
723  if (depth > 0) {
724  weight *= weight_;
725  }
726 
727  std::string new_name;
728  double mass = 0.;
729 
730  if (show_intermediate_states) {
731  new_name = name;
732  if (!new_name.empty()) {
733  new_name += "->";
734  }
735  new_name += name_;
736  new_name += "{";
737  } else {
738  new_name = "";
739  }
740  for (const auto& s : state_) {
741  new_name += s->name();
742  mass += s->mass();
743  }
744  if (show_intermediate_states) {
745  new_name += "}";
746  }
747 
748  if (children_.empty()) {
749  result.emplace_back(FinalStateCrossSection(new_name, weight, mass));
750  return;
751  }
752  for (const auto& child : children_) {
753  child.final_state_cross_sections_helper(depth + 1, result, new_name,
754  weight, show_intermediate_states);
755  }
756  }
757 };
758 
767 static std::string make_decay_name(const std::string& res_name,
768  const DecayBranchPtr& decay,
769  ParticleTypePtrList& final_state) {
770  std::stringstream name;
771  name << "[" << res_name << "->";
772  for (const auto& p : decay->particle_types()) {
773  name << p->name();
774  final_state.push_back(p);
775  }
776  name << "]";
777  return name.str();
778 }
779 
787 static void add_decays(Node& node, double sqrts) {
788  // If there is more than one unstable particle in the current state, then
789  // there will be redundant paths in the decay tree, corresponding to
790  // reorderings of the decays. To avoid double counting, we normalize by the
791  // number of possible decay orderings. Normalizing by the number of unstable
792  // particles recursively corresponds to normalizing by the factorial that
793  // gives the number of reorderings.
794  //
795  // Ideally, the redundant paths should never be added to the decay tree, but
796  // we never have more than two redundant paths, so it probably does not matter
797  // much.
798  uint32_t n_unstable = 0;
799  double sqrts_minus_masses = sqrts;
800  for (const ParticleTypePtr ptype : node.state_) {
801  if (!ptype->is_stable()) {
802  n_unstable += 1;
803  }
804  sqrts_minus_masses -= ptype->mass();
805  }
806  const double norm =
807  n_unstable != 0 ? 1. / static_cast<double>(n_unstable) : 1.;
808 
809  for (const ParticleTypePtr ptype : node.state_) {
810  if (!ptype->is_stable()) {
811  const double sqrts_decay = sqrts_minus_masses + ptype->mass();
812  bool can_decay = false;
813  for (const auto& decay : ptype->decay_modes().decay_mode_list()) {
814  // Make sure to skip kinematically impossible decays.
815  // In principle, we would have to integrate over the mass of the
816  // resonance, but as an approximation we just assume it at its pole.
817  double final_state_mass = 0.;
818  for (const auto& p : decay->particle_types()) {
819  final_state_mass += p->mass();
820  }
821  if (final_state_mass > sqrts_decay) {
822  continue;
823  }
824  can_decay = true;
825 
826  ParticleTypePtrList parts;
827  const auto name = make_decay_name(ptype->name(), decay, parts);
828  auto& new_node = node.add_action(name, norm * decay->weight(), {ptype},
829  std::move(parts));
830  add_decays(new_node, sqrts_decay);
831  }
832  if (!can_decay) {
833  // Remove final-state cross sections with resonances that cannot
834  // decay due to our "mass = pole mass" approximation.
835  node.weight_ = 0;
836  return;
837  }
838  }
839  }
840 }
841 
842 } // namespace decaytree
843 
849 static void deduplicate(std::vector<FinalStateCrossSection>& final_state_xs) {
850  std::sort(final_state_xs.begin(), final_state_xs.end(),
851  [](const FinalStateCrossSection& a,
852  const FinalStateCrossSection& b) { return a.name_ < b.name_; });
853  auto current = final_state_xs.begin();
854  while (current != final_state_xs.end()) {
855  auto adjacent = std::adjacent_find(
856  current, final_state_xs.end(),
857  [](const FinalStateCrossSection& a, const FinalStateCrossSection& b) {
858  return a.name_ == b.name_;
859  });
860  current = adjacent;
861  if (adjacent != final_state_xs.end()) {
862  adjacent->cross_section_ += (adjacent + 1)->cross_section_;
863  final_state_xs.erase(adjacent + 1);
864  }
865  }
866 }
867 
869  const ParticleType& a, const ParticleType& b, double m_a, double m_b,
870  bool final_state, std::vector<double>& plab) const {
871  typedef std::vector<std::pair<double, double>> xs_saver;
872  std::map<std::string, xs_saver> xs_dump;
873  std::map<std::string, double> outgoing_total_mass;
874 
875  ParticleData a_data(a), b_data(b);
876  int n_momentum_points = 200;
877  constexpr double momentum_step = 0.02;
878  /*
879  // Round to output precision.
880  for (auto& p : plab) {
881  p = std::floor((p * 100000) + 0.5) / 100000;
882  }
883  */
884  if (plab.size() > 0) {
885  n_momentum_points = plab.size();
886  // Remove duplicates.
887  std::sort(plab.begin(), plab.end());
888  plab.erase(std::unique(plab.begin(), plab.end()), plab.end());
889  }
890  for (int i = 0; i < n_momentum_points; i++) {
891  double momentum;
892  if (plab.size() > 0) {
893  momentum = pCM_from_s(s_from_plab(plab.at(i), m_a, m_b), m_a, m_b);
894  } else {
895  momentum = momentum_step * (i + 1);
896  }
897  a_data.set_4momentum(m_a, momentum, 0.0, 0.0);
898  b_data.set_4momentum(m_b, -momentum, 0.0, 0.0);
899  const double sqrts = (a_data.momentum() + b_data.momentum()).abs();
900  const ParticleList incoming = {a_data, b_data};
901  ScatterActionPtr act = make_unique<ScatterAction>(
902  a_data, b_data, 0., isotropic_, string_formation_time_);
903  if (strings_switch_) {
904  act->set_string_interface(string_process_interface_.get());
905  }
906  act->add_all_scatterings(elastic_parameter_, two_to_one_, incl_set_,
909  decaytree::Node tree(a.name() + b.name(), act->cross_section(), {&a, &b},
910  {&a, &b}, {&a, &b}, {});
911  const CollisionBranchList& processes = act->collision_channels();
912  for (const auto& process : processes) {
913  const double xs = process->weight();
914  if (xs <= 0.0) {
915  continue;
916  }
917  if (!final_state) {
918  std::stringstream process_description_stream;
919  process_description_stream << *process;
920  const std::string& description = process_description_stream.str();
921  double m_tot = 0.0;
922  for (const auto& ptype : process->particle_types()) {
923  m_tot += ptype->mass();
924  }
925  outgoing_total_mass[description] = m_tot;
926  if (!xs_dump[description].empty() &&
927  std::abs(xs_dump[description].back().first - sqrts) <
928  really_small) {
929  xs_dump[description].back().second += xs;
930  } else {
931  xs_dump[description].push_back(std::make_pair(sqrts, xs));
932  }
933  } else {
934  std::stringstream process_description_stream;
935  process_description_stream << *process;
936  const std::string& description = process_description_stream.str();
937  ParticleTypePtrList initial_particles = {&a, &b};
938  ParticleTypePtrList final_particles = process->particle_types();
939  auto& process_node =
940  tree.add_action(description, xs, std::move(initial_particles),
941  std::move(final_particles));
942  decaytree::add_decays(process_node, sqrts);
943  }
944  }
945  xs_dump["total"].push_back(std::make_pair(sqrts, act->cross_section()));
946  // Total cross-section should be the first in the list -> negative mass
947  outgoing_total_mass["total"] = -1.0;
948  if (final_state) {
949  // tree.print();
950  auto final_state_xs = tree.final_state_cross_sections();
951  deduplicate(final_state_xs);
952  for (const auto& p : final_state_xs) {
953  // Don't print empty columns.
954  //
955  // FIXME(steinberg): The better fix would be to not have them in the
956  // first place.
957  if (p.name_ == "") {
958  continue;
959  }
960  outgoing_total_mass[p.name_] = p.mass_;
961  xs_dump[p.name_].push_back(std::make_pair(sqrts, p.cross_section_));
962  }
963  }
964  }
965  // Get rid of cross sections that are zero.
966  // (This only happens if their is a resonance in the final state that cannot
967  // decay with our simplified assumptions.)
968  for (auto it = begin(xs_dump); it != end(xs_dump);) {
969  // Sum cross section over all energies.
970  const xs_saver& xs = (*it).second;
971  double sum = 0;
972  for (const auto& p : xs) {
973  sum += p.second;
974  }
975  if (sum == 0.) {
976  it = xs_dump.erase(it);
977  } else {
978  ++it;
979  }
980  }
981 
982  // Nice ordering of channels by summed pole mass of products
983  std::vector<std::string> all_channels;
984  for (const auto channel : xs_dump) {
985  all_channels.push_back(channel.first);
986  }
987  std::sort(all_channels.begin(), all_channels.end(),
988  [&](const std::string& str_a, const std::string& str_b) {
989  return outgoing_total_mass[str_a] < outgoing_total_mass[str_b];
990  });
991 
992  // Print header
993  std::cout << "# Dumping partial " << a.name() << b.name()
994  << " cross-sections in mb, energies in GeV" << std::endl;
995  std::cout << " sqrt_s";
996  // Align everything to 16 unicode characters.
997  // This should be enough for the longest channel name (7 final-state
998  // particles).
999  for (const auto channel : all_channels) {
1000  std::cout << utf8::fill_left(channel, 16, ' ');
1001  }
1002  std::cout << std::endl;
1003 
1004  // Print out all partial cross-sections in mb
1005  for (int i = 0; i < n_momentum_points; i++) {
1006  double momentum;
1007  if (plab.size() > 0) {
1008  momentum = pCM_from_s(s_from_plab(plab.at(i), m_a, m_b), m_a, m_b);
1009  } else {
1010  momentum = momentum_step * (i + 1);
1011  }
1012  a_data.set_4momentum(m_a, momentum, 0.0, 0.0);
1013  b_data.set_4momentum(m_b, -momentum, 0.0, 0.0);
1014  const double sqrts = (a_data.momentum() + b_data.momentum()).abs();
1015  std::printf("%9.6f", sqrts);
1016  for (const auto channel : all_channels) {
1017  const xs_saver energy_and_xs = xs_dump[channel];
1018  size_t j = 0;
1019  for (; j < energy_and_xs.size() && energy_and_xs[j].first < sqrts; j++) {
1020  }
1021  double xs = 0.0;
1022  if (j < energy_and_xs.size() &&
1023  std::abs(energy_and_xs[j].first - sqrts) < really_small) {
1024  xs = energy_and_xs[j].second;
1025  }
1026  std::printf("%16.6f", xs); // Same alignment as in the header.
1027  }
1028  std::printf("\n");
1029  }
1030 }
1031 
1032 } // namespace smash
smash::ScatterActionsFinder::low_snn_cut_
const double low_snn_cut_
Elastic collsions between two nucleons with sqrt_s below low_snn_cut_ are excluded.
Definition: scatteractionsfinder.h:311
smash::decaytree::Node
Node of a decay tree, representing a possible action (2-to-2 or 1-to-2).
Definition: scatteractionsfinder.cc:596
smash
Definition: action.h:24
smash::decaytree::Node::print_helper
void print_helper(uint64_t depth) const
Internal helper function for print, to be called recursively to print all nodes.
Definition: scatteractionsfinder.cc:695
smash::ProcessType::StringHard
hard string process involving 2->2 QCD process by PYTHIA.
smash::decaytree::Node::Node
Node(const std::string &name, double weight, ParticleTypePtrList &&initial_particles, ParticleTypePtrList &&final_particles, ParticleTypePtrList &&state, std::vector< Node > &&children)
Definition: scatteractionsfinder.cc:631
smash::ParticleData::xsec_scaling_factor
double xsec_scaling_factor(double delta_time=0.) const
Return the cross section scaling factor at a given time.
Definition: particledata.cc:74
smash::ParticleData::momentum
const FourVector & momentum() const
Get the particle's 4-momentum.
Definition: particledata.h:142
smash::ScatterActionsFinder::string_formation_time_
const double string_formation_time_
Parameter for formation time.
Definition: scatteractionsfinder.h:329
smash::decaytree::Node::final_state_cross_sections
std::vector< FinalStateCrossSection > final_state_cross_sections() const
Definition: scatteractionsfinder.cc:682
smash::ParticleData::pole_mass
double pole_mass() const
Get the particle's pole mass ("on-shell").
Definition: particledata.h:99
smash::ScatterActionsFinder::elastic_parameter_
const double elastic_parameter_
Elastic cross section parameter (in mb).
Definition: scatteractionsfinder.h:298
smash::ScatterActionsFinder::string_process_interface_
std::unique_ptr< StringProcess > string_process_interface_
Class that deals with strings, interfacing Pythia.
Definition: scatteractionsfinder.h:294
smash::decaytree::Node::final_particles_
ParticleTypePtrList final_particles_
Final-state particle types in this action.
Definition: scatteractionsfinder.cc:608
smash::ParticleData
Definition: particledata.h:52
smash::DecayModes::decay_mode_list
const DecayBranchList & decay_mode_list() const
Definition: decaymodes.h:63
smash::ParticleData::id
int32_t id() const
Get the id of the particle.
Definition: particledata.h:70
smash::decaytree::Node::final_state_cross_sections_helper
void final_state_cross_sections_helper(uint64_t depth, std::vector< FinalStateCrossSection > &result, const std::string &name, double weight, bool show_intermediate_states=false) const
Internal helper function for final_state_cross_sections, to be called recursively to calculate all fi...
Definition: scatteractionsfinder.cc:716
smash::s_from_plab
double s_from_plab(double plab, double m_P, double m_T)
Convert p_lab to Mandelstam-s for a fixed-target setup, with a projectile of mass m_P and momentum pl...
Definition: kinematics.h:224
cxx14compat.h
smash::ScatterActionsFinder::testparticles_
const int testparticles_
Number of test particles.
Definition: scatteractionsfinder.h:300
smash::utf8::fill_left
std::string fill_left(const std::string &s, size_t width, char fill=' ')
Fill string with characters to the left until the given width is reached.
Definition: stringfunctions.cc:47
smash::is_string_soft_process
bool is_string_soft_process(ProcessType p)
Check if a given process type is a soft string excitation.
Definition: processbranch.cc:18
smash::ScatterActionsFinder::incl_set_
const ReactionsBitSet incl_set_
List of included 2<->2 reactions.
Definition: scatteractionsfinder.h:306
smash::ScatterActionsFinder::find_actions_in_cell
ActionList find_actions_in_cell(const ParticleList &search_list, double dt, const double cell_vol, const std::vector< FourVector > &beam_momentum) const override
Search for all the possible collisions within one cell.
Definition: scatteractionsfinder.cc:414
macros.h
smash::decaytree::Node::Node
Node(const Node &)=delete
Cannot be copied.
smash::ScatterActionsFinder::strings_with_probability_
const bool strings_with_probability_
Decide whether to implement string fragmentation based on a probability.
Definition: scatteractionsfinder.h:317
smash::ParticleType::mass
double mass() const
Definition: particletype.h:144
experimentparameters.h
smash::FinalStateCrossSection
Represent a final-state cross section.
Definition: scatteractionsfinder.cc:560
smash::ScatterActionsFinder::two_to_one_
const bool two_to_one_
Enable 2->1 processes.
Definition: scatteractionsfinder.h:304
smash::decaytree::Node::children_
std::vector< Node > children_
Possible actions after this action.
Definition: scatteractionsfinder.cc:614
smash::FinalStateCrossSection::FinalStateCrossSection
FinalStateCrossSection(const std::string &name, double cross_section, double mass)
Construct a final-state cross section.
Definition: scatteractionsfinder.cc:578
smash::LFindScatter
static constexpr int LFindScatter
Definition: scatteractionsfinder.cc:31
smash::ScatterActionsFinder::nucleon_has_interacted_
const std::vector< bool > & nucleon_has_interacted_
Parameter to record whether the nucleon has experienced a collision or not.
Definition: scatteractionsfinder.h:323
smash::decaytree::Node::weight_
double weight_
Weight (cross section or branching ratio).
Definition: scatteractionsfinder.cc:602
smash::ParticleData::id_process
uint32_t id_process() const
Get the id of the last action.
Definition: particledata.h:118
smash::ProcessType::TwoToTwo
2->2 inelastic scattering
smash::FinalStateCrossSection::mass_
double mass_
Total mass of final state particles.
Definition: scatteractionsfinder.cc:568
smash::ScatterActionsFinder::dump_cross_sections
void dump_cross_sections(const ParticleType &a, const ParticleType &b, double m_a, double m_b, bool final_state, std::vector< double > &plab) const
Print out partial cross-sections of all processes that can occur in the collision of a(mass = m_a) an...
Definition: scatteractionsfinder.cc:868
smash::ScatterActionsFinder::max_transverse_distance_sqr
double max_transverse_distance_sqr(int testparticles) const
The maximal distance over which particles can interact, related to the number of test particles and t...
Definition: scatteractionsfinder.h:216
smash::ParticleData::set_4momentum
void set_4momentum(const FourVector &momentum_vector)
Set the particle's 4-momentum directly.
Definition: particledata.h:148
smash::logg
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
smash::FinalStateCrossSection::cross_section_
double cross_section_
Corresponding cross section in mb.
Definition: scatteractionsfinder.cc:565
smash::decaytree::Node::print
void print() const
Print the decay tree starting with this node.
Definition: scatteractionsfinder.cc:677
smash::deduplicate
static void deduplicate(std::vector< FinalStateCrossSection > &final_state_xs)
Deduplicate the final-state cross sections by summing.
Definition: scatteractionsfinder.cc:849
smash::really_small
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:37
smash::ParticleType::decay_modes
const DecayModes & decay_modes() const
Definition: particletype.cc:428
smash::Configuration
Interface to the SMASH configuration files.
Definition: configuration.h:464
crosssections.h
smash::ParticleTypePtr
Definition: particletype.h:663
smash::ScatterActionsFinder::collision_time
double collision_time(const ParticleData &p1, const ParticleData &p2, double dt, const std::vector< FourVector > &beam_momentum) const
Determine the collision time of the two particles.
Definition: scatteractionsfinder.h:78
smash::isoclean
void isoclean(std::string &s)
Remove ⁺, ⁻, ⁰ from string.
Definition: stringfunctions.cc:92
smash::ScatterActionsFinder::nnbar_treatment_
const NNbarTreatment nnbar_treatment_
Switch for NNbar reactions.
Definition: scatteractionsfinder.h:319
CollisionCriterion::Stochastic
Stochastic Criteiron.
smash::ScatterActionsFinder::strings_switch_
const bool strings_switch_
Switch to turn off string excitation.
Definition: scatteractionsfinder.h:313
smash::FourVector::x0
double x0() const
Definition: fourvector.h:303
isoparticletype.h
smash::IsoParticleType
Definition: isoparticletype.h:27
smash::ParticleType::is_stable
bool is_stable() const
Definition: particletype.h:236
smash::ParticleData::position
const FourVector & position() const
Get the particle's position in Minkowski space.
Definition: particledata.h:188
smash::ParticleType
Definition: particletype.h:97
smash::ParticleType::name
const std::string & name() const
Definition: particletype.h:141
smash::ScatterActionsFinder::ScatterActionsFinder
ScatterActionsFinder(Configuration config, const ExperimentParameters &parameters, const std::vector< bool > &nucleon_has_interacted, int N_tot, int N_proj)
Constructor of the finder with the given parameters.
Definition: scatteractionsfinder.cc:232
smash::decaytree::add_decays
static void add_decays(Node &node, double sqrts)
Add nodes for all decays possible from the given node and all of its children.
Definition: scatteractionsfinder.cc:787
smash::ScatterActionsFinder::find_actions_with_neighbors
ActionList find_actions_with_neighbors(const ParticleList &search_list, const ParticleList &neighbors_list, double dt, const std::vector< FourVector > &beam_momentum) const override
Search for all the possible collisions among the neighboring cells.
Definition: scatteractionsfinder.cc:432
smash::decaytree::make_decay_name
static std::string make_decay_name(const std::string &res_name, const DecayBranchPtr &decay, ParticleTypePtrList &final_state)
Generate name for decay and update final state.
Definition: scatteractionsfinder.cc:767
smash::ScatterActionsFinder::isotropic_
const bool isotropic_
Do all collisions isotropically.
Definition: scatteractionsfinder.h:302
particles.h
smash::Particles
Definition: particles.h:33
scatteractionphoton.h
smash::decaytree::Node::initial_particles_
ParticleTypePtrList initial_particles_
Initial-state particle types in this action.
Definition: scatteractionsfinder.cc:605
smash::ScatterActionsFinder::use_AQM_
const bool use_AQM_
Switch to control whether to use AQM or not.
Definition: scatteractionsfinder.h:315
smash::fm2_mb
constexpr double fm2_mb
mb <-> fm^2 conversion factor.
Definition: constants.h:28
constants.h
logging.h
smash::ProcessType::Elastic
elastic scattering: particles remain the same, only momenta change
configuration.h
smash::decaytree::Node::name_
std::string name_
Name for printing.
Definition: scatteractionsfinder.cc:599
smash::decaytree::Node::add_action
Node & add_action(const std::string &name, double weight, ParticleTypePtrList &&initial_particles, ParticleTypePtrList &&final_particles)
Add an action to the children of this node.
Definition: scatteractionsfinder.cc:653
smash::ExperimentParameters
Helper structure for Experiment.
Definition: experimentparameters.h:23
smash::pdg::p
constexpr int p
Proton.
Definition: pdgcode_constants.h:28
smash::random::uniform
T uniform(T min, T max)
Definition: random.h:88
smash::ScatterActionsFinder::dump_reactions
void dump_reactions() const
Prints out all the 2-> n (n > 1) reactions with non-zero cross-sections between all possible pairs of...
Definition: scatteractionsfinder.cc:481
scatteractionsfinder.h
smash::ScatterActionsFinder::N_tot_
const int N_tot_
Record the total number of the nucleons in the two colliding nuclei.
Definition: scatteractionsfinder.h:325
CollisionCriterion::Geometric
(Default) geometric criterion.
smash::ScatterActionsFinder::check_collision
ActionPtr check_collision(const ParticleData &data_a, const ParticleData &data_b, double dt, const std::vector< FourVector > &beam_momentum={}, const double cell_vol=0.0) const
Check for a single pair of particles (id_a, id_b) if a collision will happen in the next timestep and...
Definition: scatteractionsfinder.cc:288
smash::ScatterActionsFinder::N_proj_
const int N_proj_
Record the number of the nucleons in the projectile.
Definition: scatteractionsfinder.h:327
scatteraction.h
smash::FinalStateCrossSection::name_
std::string name_
Name of the final state.
Definition: scatteractionsfinder.cc:562
stringfunctions.h
smash::ScatterActionsFinder::coll_crit_
const CollisionCriterion coll_crit_
Specifies which collision criterion is used.
Definition: scatteractionsfinder.h:296
smash::IsoParticleType::list_all
static const IsoParticleTypeList & list_all()
Returns a list of all IsoParticleTypes.
Definition: isoparticletype.cc:43
smash::decaytree::Node::state_
ParticleTypePtrList state_
Particle types corresponding to the global state after this action.
Definition: scatteractionsfinder.cc:611
smash::ScatterActionsFinder::find_actions_with_surrounding_particles
ActionList find_actions_with_surrounding_particles(const ParticleList &search_list, const Particles &surrounding_list, double dt, const std::vector< FourVector > &beam_momentum) const override
Search for all the possible secondary collisions between the outgoing particles and the rest.
Definition: scatteractionsfinder.cc:453
smash::pCM_from_s
T pCM_from_s(const T s, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:66
decaymodes.h