Version: SMASH-2.0
scatteractionsfinder.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2020
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/constants.h"
17 #include "smash/cxx14compat.h"
18 #include "smash/decaymodes.h"
19 #include "smash/logging.h"
20 #include "smash/scatteraction.h"
23 #include "smash/stringfunctions.h"
24 
25 namespace smash {
26 static constexpr int LFindScatter = LogArea::FindScatter::id;
297  Configuration config, const ExperimentParameters& parameters,
298  const std::vector<bool>& nucleon_has_interacted, int N_tot, int N_proj)
299  : coll_crit_(parameters.coll_crit),
300  elastic_parameter_(
301  config.take({"Collision_Term", "Elastic_Cross_Section"}, -1.)),
302  testparticles_(parameters.testparticles),
303  isotropic_(config.take({"Collision_Term", "Isotropic"}, false)),
304  two_to_one_(parameters.two_to_one),
305  incl_set_(parameters.included_2to2),
306  incl_multi_set_(parameters.included_multi),
307  scale_xs_(parameters.scale_xs),
308  additional_el_xs_(parameters.additional_el_xs),
309  low_snn_cut_(parameters.low_snn_cut),
310  strings_switch_(parameters.strings_switch),
311  use_AQM_(parameters.use_AQM),
312  strings_with_probability_(parameters.strings_with_probability),
313  nnbar_treatment_(parameters.nnbar_treatment),
314  box_length_(parameters.box_length),
315  nucleon_has_interacted_(nucleon_has_interacted),
316  N_tot_(N_tot),
317  N_proj_(N_proj),
318  string_formation_time_(config.take(
319  {"Collision_Term", "String_Parameters", "Formation_Time"}, 1.)),
320  maximum_cross_section_(parameters.maximum_cross_section),
321  only_warn_for_high_prob_(config.take(
322  {"Collision_Term", "Only_Warn_For_High_Probability"}, false)) {
323  if (is_constant_elastic_isotropic()) {
324  logg[LFindScatter].info(
325  "Constant elastic isotropic cross-section mode:", " using ",
326  elastic_parameter_, " mb as maximal cross-section.");
327  }
328  if (incl_multi_set_.any() && coll_crit_ != CollisionCriterion::Stochastic) {
329  throw std::invalid_argument(
330  "Multi-body reactions (like e.g. 3->1 or 3->2) are only possible with "
331  "the stochastic "
332  "collision "
333  "criterion. Change your config accordingly.");
334  }
335 
336  if (incl_multi_set_[IncludedMultiParticleReactions::Deuteron_3to2] == 1 &&
338  incl_set_[IncludedReactions::NDeuteron_to_Ndprime] == 1)) {
339  throw std::invalid_argument(
340  "To prevent double counting it is not possible to enable deuteron 3->2 "
341  "reactions\nand reactions involving the d' at the same time\ni.e. to "
342  "include `Deuteron_3to2` in `Multi_Particle_Reactions` and\n "
343  "\"PiDeuteron_to_pidprime\" "
344  "or \"NDeuteron_to_Ndprime\" in `Included_2to2` at the same time.\n"
345  "Change your config accordingly.");
346  }
347 
348  if (strings_switch_) {
349  auto subconfig = config["Collision_Term"]["String_Parameters"];
350  string_process_interface_ = make_unique<StringProcess>(
351  subconfig.take({"String_Tension"}, 1.0), string_formation_time_,
352  subconfig.take({"Gluon_Beta"}, 0.5),
353  subconfig.take({"Gluon_Pmin"}, 0.001),
354  subconfig.take({"Quark_Alpha"}, 2.0),
355  subconfig.take({"Quark_Beta"}, 7.0),
356  subconfig.take({"Strange_Supp"}, 0.16),
357  subconfig.take({"Diquark_Supp"}, 0.036),
358  subconfig.take({"Sigma_Perp"}, 0.42),
359  subconfig.take({"StringZ_A_Leading"}, 0.2),
360  subconfig.take({"StringZ_B_Leading"}, 2.0),
361  subconfig.take({"StringZ_A"}, 2.0), subconfig.take({"StringZ_B"}, 0.55),
362  subconfig.take({"String_Sigma_T"}, 0.5),
363  subconfig.take({"Form_Time_Factor"}, 1.0),
364  subconfig.take({"Mass_Dependent_Formation_Times"}, false),
365  subconfig.take({"Prob_proton_to_d_uu"}, 1. / 3.),
366  subconfig.take({"Separate_Fragment_Baryon"}, true),
367  subconfig.take({"Popcorn_Rate"}, 0.15));
368  }
369 }
370 
372  const ParticleData& data_a, const ParticleData& data_b, double dt,
373  const std::vector<FourVector>& beam_momentum,
374  const double gcell_vol) const {
375  /* If the two particles
376  * 1) belong to the two colliding nuclei
377  * 2) are within the same nucleus
378  * 3) both of them have never experienced any collisons,
379  * then the collision between them are banned. */
380  assert(data_a.id() >= 0);
381  assert(data_b.id() >= 0);
382  if (data_a.id() < N_tot_ && data_b.id() < N_tot_ &&
383  ((data_a.id() < N_proj_ && data_b.id() < N_proj_) ||
384  (data_a.id() >= N_proj_ && data_b.id() >= N_proj_)) &&
385  !(nucleon_has_interacted_[data_a.id()] ||
386  nucleon_has_interacted_[data_b.id()])) {
387  return nullptr;
388  }
389 
390  // No grid or search in cell means no collision for stochastic criterion
392  gcell_vol < really_small) {
393  return nullptr;
394  }
395 
396  // Determine time of collision.
397  const double time_until_collision =
398  collision_time(data_a, data_b, dt, beam_momentum);
399 
400  // Check that collision happens in this timestep.
401  if (time_until_collision < 0. || time_until_collision >= dt) {
402  return nullptr;
403  }
404 
405  // Create ScatterAction object.
406  ScatterActionPtr act = make_unique<ScatterAction>(
407  data_a, data_b, time_until_collision, isotropic_, string_formation_time_,
408  box_length_);
409 
411  act->set_stochastic_pos_idx();
412  }
413 
414  if (strings_switch_) {
415  act->set_string_interface(string_process_interface_.get());
416  }
417 
418  // Distance squared calculation not needed for stochastic criterion
419  const double distance_squared =
421  ? act->transverse_distance_sqr()
423  ? act->cov_transverse_distance_sqr()
424  : 0.0;
425 
426  // Don't calculate cross section if the particles are very far apart.
427  // Not needed for stochastic criterion because of cell structure.
429  distance_squared >= max_transverse_distance_sqr(testparticles_)) {
430  return nullptr;
431  }
432 
433  // Add various subprocesses.
434  act->add_all_scatterings(elastic_parameter_, two_to_one_, incl_set_,
438 
439  double xs =
440  act->cross_section() * fm2_mb / static_cast<double>(testparticles_);
441 
442  // Take cross section scaling factors into account
443  xs *= data_a.xsec_scaling_factor(time_until_collision);
444  xs *= data_b.xsec_scaling_factor(time_until_collision);
445 
447  const double v_rel = act->relative_velocity();
448  /* Collision probability for 2-particle scattering, see e.g.
449  * \iref{Xu:2004mz}, eq. (11) */
450  const double prob = xs * v_rel * dt / gcell_vol;
451 
452  logg[LFindScatter].debug(
453  "Stochastic collison criterion parameters (2-particles):\nprob = ",
454  prob, ", xs = ", xs, ", v_rel = ", v_rel, ", dt = ", dt,
455  ", gcell_vol = ", gcell_vol, ", testparticles = ", testparticles_);
456 
457  if (prob > 1.) {
458  std::stringstream err;
459  err << "Probability larger than 1 for stochastic rates. ( P_22 = " << prob
460  << " )\nConsider using smaller timesteps.";
462  logg[LFindScatter].warn(err.str());
463  } else {
464  throw std::runtime_error(err.str());
465  }
466  }
467 
468  // probability criterion
469  double random_no = random::uniform(0., 1.);
470  if (random_no > prob) {
471  return nullptr;
472  }
473 
476  // just collided with this particle
477  if (data_a.id_process() > 0 && data_a.id_process() == data_b.id_process()) {
478  logg[LFindScatter].debug("Skipping collided particles at time ",
479  data_a.position().x0(), " due to process ",
480  data_a.id_process(), "\n ", data_a, "\n<-> ",
481  data_b);
482 
483  return nullptr;
484  }
485 
486  // Cross section for collision criterion
487  const double cross_section_criterion = xs * M_1_PI;
488 
489  // distance criterion according to cross_section
490  if (distance_squared >= cross_section_criterion) {
491  return nullptr;
492  }
493 
494  logg[LFindScatter].debug("particle distance squared: ", distance_squared,
495  "\n ", data_a, "\n<-> ", data_b);
496  }
497 
498  // Using std::move here is redundant with newer compilers, but required for
499  // supporting GCC 4.8. Once we drop this support, std::move should be removed.
500  return std::move(act);
501 }
502 
504  const ParticleList& plist, double dt, const double gcell_vol) const {
505  /* If the two particles
506  * 1) belong to the two colliding nuclei
507  * 2) are within the same nucleus
508  * 3) both of them have never experienced any collisons,
509  * then the collision between them are banned also for multi-particle
510  * interactions. */
511  if (std::all_of(
512  plist.begin(), plist.end(),
513  [&](const ParticleData& data) { return data.id() < N_tot_; }) &&
514  (std::all_of(
515  plist.begin(), plist.end(),
516  [&](const ParticleData& data) { return data.id() < N_proj_; }) ||
517  std::all_of(
518  plist.begin(), plist.end(),
519  [&](const ParticleData& data) { return data.id() >= N_proj_; })) &&
520  std::none_of(plist.begin(), plist.end(), [&](const ParticleData& data) {
521  return nucleon_has_interacted_[data.id()];
522  })) {
523  return nullptr;
524  }
525 
526  // No grid or search in cell
527  if (gcell_vol < really_small) {
528  return nullptr;
529  }
530 
531  /* Optimisation for later: Already check here at the beginning
532  * if collision with plist is possible before constructing actions. */
533 
534  // 1. Determine time of collision.
535  const double time_until_collision = dt * random::uniform(0., 1.);
536 
537  // 2. Create ScatterAction object.
538  ScatterActionMultiPtr act =
539  make_unique<ScatterActionMulti>(plist, time_until_collision);
540 
541  act->set_stochastic_pos_idx();
542 
543  // 3. Add possible final states (dt and gcell_vol for probability calculation)
544  act->add_possible_reactions(dt, gcell_vol, incl_multi_set_);
545 
546  /* 4. Return total collision probability
547  * Scales with 1 over the number of testpartciles to the power of the
548  * number of incoming particles - 1) */
549  const double prob =
550  act->get_total_weight() / std::pow(testparticles_, plist.size() - 1);
551 
552  // 5. Check that probability is smaller than one
553  if (prob > 1.) {
554  std::stringstream err;
555  err << "Probability larger than 1 for stochastic rates. ( P_nm = " << prob
556  << " )\nConsider using smaller timesteps.";
558  logg[LFindScatter].warn(err.str());
559  } else {
560  throw std::runtime_error(err.str());
561  }
562  }
563 
564  // 6. Perform probability decisions
565  double random_no = random::uniform(0., 1.);
566  if (random_no > prob) {
567  return nullptr;
568  }
569 
570  return std::move(act);
571 }
572 
574  const ParticleList& search_list, double dt, const double gcell_vol,
575  const std::vector<FourVector>& beam_momentum) const {
576  std::vector<ActionPtr> actions;
577  for (const ParticleData& p1 : search_list) {
578  for (const ParticleData& p2 : search_list) {
579  // Check for 2 particle scattering
580  if (p1.id() < p2.id()) {
581  ActionPtr act =
582  check_collision_two_part(p1, p2, dt, beam_momentum, gcell_vol);
583  if (act) {
584  actions.push_back(std::move(act));
585  }
586  }
587  if (incl_multi_set_.any()) {
588  // Also, check for 3 particle scatterings with stochastic criterion
589  for (const ParticleData& p3 : search_list) {
590  if (p1.id() < p2.id() && p2.id() < p3.id()) {
591  ActionPtr act =
592  check_collision_multi_part({p1, p2, p3}, dt, gcell_vol);
593  if (act) {
594  actions.push_back(std::move(act));
595  }
596  }
597  }
598  }
599  }
600  }
601 
602  return actions;
603 }
604 
606  const ParticleList& search_list, const ParticleList& neighbors_list,
607  double dt, const std::vector<FourVector>& beam_momentum) const {
608  std::vector<ActionPtr> actions;
610  // Only search in cells
611  return actions;
612  }
613  for (const ParticleData& p1 : search_list) {
614  for (const ParticleData& p2 : neighbors_list) {
615  assert(p1.id() != p2.id());
616  // Check if a collision is possible.
617  ActionPtr act = check_collision_two_part(p1, p2, dt, beam_momentum);
618  if (act) {
619  actions.push_back(std::move(act));
620  }
621  }
622  }
623  return actions;
624 }
625 
627  const ParticleList& search_list, const Particles& surrounding_list,
628  double dt, const std::vector<FourVector>& beam_momentum) const {
629  std::vector<ActionPtr> actions;
631  // Only search in cells
632  return actions;
633  }
634  for (const ParticleData& p2 : surrounding_list) {
635  /* don't look for collisions if the particle from the surrounding list is
636  * also in the search list */
637  auto result = std::find_if(
638  search_list.begin(), search_list.end(),
639  [&p2](const ParticleData& p) { return p.id() == p2.id(); });
640  if (result != search_list.end()) {
641  continue;
642  }
643  for (const ParticleData& p1 : search_list) {
644  // Check if a collision is possible.
645  ActionPtr act = check_collision_two_part(p1, p2, dt, beam_momentum);
646  if (act) {
647  actions.push_back(std::move(act));
648  }
649  }
650  }
651  return actions;
652 }
653 
655  constexpr double time = 0.0;
656 
657  const size_t N_isotypes = IsoParticleType::list_all().size();
658  const size_t N_pairs = N_isotypes * (N_isotypes - 1) / 2;
659 
660  std::cout << N_isotypes << " iso-particle types." << std::endl;
661  std::cout << "They can make " << N_pairs << " pairs." << std::endl;
662  std::vector<double> momentum_scan_list = {0.1, 0.3, 0.5, 1.0,
663  2.0, 3.0, 5.0, 10.0};
664  for (const IsoParticleType& A_isotype : IsoParticleType::list_all()) {
665  for (const IsoParticleType& B_isotype : IsoParticleType::list_all()) {
666  if (&A_isotype > &B_isotype) {
667  continue;
668  }
669  bool any_nonzero_cs = false;
670  std::vector<std::string> r_list;
671  for (const ParticleTypePtr A_type : A_isotype.get_states()) {
672  for (const ParticleTypePtr B_type : B_isotype.get_states()) {
673  if (A_type > B_type) {
674  continue;
675  }
676  ParticleData A(*A_type), B(*B_type);
677  for (auto mom : momentum_scan_list) {
678  A.set_4momentum(A.pole_mass(), mom, 0.0, 0.0);
679  B.set_4momentum(B.pole_mass(), -mom, 0.0, 0.0);
680  ScatterActionPtr act = make_unique<ScatterAction>(
681  A, B, time, isotropic_, string_formation_time_);
682  if (strings_switch_) {
683  act->set_string_interface(string_process_interface_.get());
684  }
685  act->add_all_scatterings(
690  const double total_cs = act->cross_section();
691  if (total_cs <= 0.0) {
692  continue;
693  }
694  any_nonzero_cs = true;
695  for (const auto& channel : act->collision_channels()) {
696  const auto type = channel->get_type();
697  std::string r;
698  if (is_string_soft_process(type) ||
699  type == ProcessType::StringHard) {
700  r = A_type->name() + B_type->name() + std::string(" → strings");
701  } else {
702  std::string r_type =
703  (type == ProcessType::Elastic)
704  ? std::string(" (el)")
705  : (channel->get_type() == ProcessType::TwoToTwo)
706  ? std::string(" (inel)")
707  : std::string(" (?)");
708  r = A_type->name() + B_type->name() + std::string(" → ") +
709  channel->particle_types()[0]->name() +
710  channel->particle_types()[1]->name() + r_type;
711  }
712  isoclean(r);
713  r_list.push_back(r);
714  }
715  }
716  }
717  }
718  std::sort(r_list.begin(), r_list.end());
719  r_list.erase(std::unique(r_list.begin(), r_list.end()), r_list.end());
720  if (any_nonzero_cs) {
721  for (auto r : r_list) {
722  std::cout << r;
723  if (r_list.back() != r) {
724  std::cout << ", ";
725  }
726  }
727  std::cout << std::endl;
728  }
729  }
730  }
731 }
732 
736  std::string name_;
737 
740 
742  double mass_;
743 
752  FinalStateCrossSection(const std::string& name, double cross_section,
753  double mass)
754  : name_(name), cross_section_(cross_section), mass_(mass) {}
755 };
756 
757 namespace decaytree {
758 
770 struct Node {
771  public:
773  std::string name_;
774 
776  double weight_;
777 
779  ParticleTypePtrList initial_particles_;
780 
782  ParticleTypePtrList final_particles_;
783 
785  ParticleTypePtrList state_;
786 
788  std::vector<Node> children_;
789 
791  Node(const Node&) = delete;
793  Node(Node&&) = default;
794 
805  Node(const std::string& name, double weight,
806  ParticleTypePtrList&& initial_particles,
807  ParticleTypePtrList&& final_particles, ParticleTypePtrList&& state,
808  std::vector<Node>&& children)
809  : name_(name),
810  weight_(weight),
811  initial_particles_(std::move(initial_particles)),
812  final_particles_(std::move(final_particles)),
813  state_(std::move(state)),
814  children_(std::move(children)) {}
815 
827  Node& add_action(const std::string& name, double weight,
828  ParticleTypePtrList&& initial_particles,
829  ParticleTypePtrList&& final_particles) {
830  // Copy parent state and update it.
831  ParticleTypePtrList state(state_);
832  for (const auto& p : initial_particles) {
833  state.erase(std::find(state.begin(), state.end(), p));
834  }
835  for (const auto& p : final_particles) {
836  state.push_back(p);
837  }
838  // Sort the state to normalize the output.
839  std::sort(state.begin(), state.end(),
841  return a->name() < b->name();
842  });
843  // Push new node to children.
844  Node new_node(name, weight, std::move(initial_particles),
845  std::move(final_particles), std::move(state), {});
846  children_.emplace_back(std::move(new_node));
847  return children_.back();
848  }
849 
851  void print() const { print_helper(0); }
852 
856  std::vector<FinalStateCrossSection> final_state_cross_sections() const {
857  std::vector<FinalStateCrossSection> result;
858  final_state_cross_sections_helper(0, result, "", 1.);
859  return result;
860  }
861 
862  private:
869  void print_helper(uint64_t depth) const {
870  for (uint64_t i = 0; i < depth; i++) {
871  std::cout << " ";
872  }
873  std::cout << name_ << " " << weight_ << std::endl;
874  for (const auto& child : children_) {
875  child.print_helper(depth + 1);
876  }
877  }
878 
891  uint64_t depth, std::vector<FinalStateCrossSection>& result,
892  const std::string& name, double weight,
893  bool show_intermediate_states = false) const {
894  // The first node corresponds to the total cross section and has to be
895  // ignored. The second node corresponds to the partial cross section. All
896  // further nodes correspond to branching ratios.
897  if (depth > 0) {
898  weight *= weight_;
899  }
900 
901  std::string new_name;
902  double mass = 0.;
903 
904  if (show_intermediate_states) {
905  new_name = name;
906  if (!new_name.empty()) {
907  new_name += "->";
908  }
909  new_name += name_;
910  new_name += "{";
911  } else {
912  new_name = "";
913  }
914  for (const auto& s : state_) {
915  new_name += s->name();
916  mass += s->mass();
917  }
918  if (show_intermediate_states) {
919  new_name += "}";
920  }
921 
922  if (children_.empty()) {
923  result.emplace_back(FinalStateCrossSection(new_name, weight, mass));
924  return;
925  }
926  for (const auto& child : children_) {
927  child.final_state_cross_sections_helper(depth + 1, result, new_name,
928  weight, show_intermediate_states);
929  }
930  }
931 };
932 
941 static std::string make_decay_name(const std::string& res_name,
942  const DecayBranchPtr& decay,
943  ParticleTypePtrList& final_state) {
944  std::stringstream name;
945  name << "[" << res_name << "->";
946  for (const auto& p : decay->particle_types()) {
947  name << p->name();
948  final_state.push_back(p);
949  }
950  name << "]";
951  return name.str();
952 }
953 
961 static void add_decays(Node& node, double sqrts) {
962  // If there is more than one unstable particle in the current state, then
963  // there will be redundant paths in the decay tree, corresponding to
964  // reorderings of the decays. To avoid double counting, we normalize by the
965  // number of possible decay orderings. Normalizing by the number of unstable
966  // particles recursively corresponds to normalizing by the factorial that
967  // gives the number of reorderings.
968  //
969  // Ideally, the redundant paths should never be added to the decay tree, but
970  // we never have more than two redundant paths, so it probably does not matter
971  // much.
972  uint32_t n_unstable = 0;
973  double sqrts_minus_masses = sqrts;
974  for (const ParticleTypePtr ptype : node.state_) {
975  if (!ptype->is_stable()) {
976  n_unstable += 1;
977  }
978  sqrts_minus_masses -= ptype->mass();
979  }
980  const double norm =
981  n_unstable != 0 ? 1. / static_cast<double>(n_unstable) : 1.;
982 
983  for (const ParticleTypePtr ptype : node.state_) {
984  if (!ptype->is_stable()) {
985  const double sqrts_decay = sqrts_minus_masses + ptype->mass();
986  bool can_decay = false;
987  for (const auto& decay : ptype->decay_modes().decay_mode_list()) {
988  // Make sure to skip kinematically impossible decays.
989  // In principle, we would have to integrate over the mass of the
990  // resonance, but as an approximation we just assume it at its pole.
991  double final_state_mass = 0.;
992  for (const auto& p : decay->particle_types()) {
993  final_state_mass += p->mass();
994  }
995  if (final_state_mass > sqrts_decay) {
996  continue;
997  }
998  can_decay = true;
999 
1000  ParticleTypePtrList parts;
1001  const auto name = make_decay_name(ptype->name(), decay, parts);
1002  auto& new_node = node.add_action(name, norm * decay->weight(), {ptype},
1003  std::move(parts));
1004  add_decays(new_node, sqrts_decay);
1005  }
1006  if (!can_decay) {
1007  // Remove final-state cross sections with resonances that cannot
1008  // decay due to our "mass = pole mass" approximation.
1009  node.weight_ = 0;
1010  return;
1011  }
1012  }
1013  }
1014 }
1015 
1016 } // namespace decaytree
1017 
1023 static void deduplicate(std::vector<FinalStateCrossSection>& final_state_xs) {
1024  std::sort(final_state_xs.begin(), final_state_xs.end(),
1025  [](const FinalStateCrossSection& a,
1026  const FinalStateCrossSection& b) { return a.name_ < b.name_; });
1027  auto current = final_state_xs.begin();
1028  while (current != final_state_xs.end()) {
1029  auto adjacent = std::adjacent_find(
1030  current, final_state_xs.end(),
1031  [](const FinalStateCrossSection& a, const FinalStateCrossSection& b) {
1032  return a.name_ == b.name_;
1033  });
1034  current = adjacent;
1035  if (adjacent != final_state_xs.end()) {
1036  adjacent->cross_section_ += (adjacent + 1)->cross_section_;
1037  final_state_xs.erase(adjacent + 1);
1038  }
1039  }
1040 }
1041 
1043  const ParticleType& a, const ParticleType& b, double m_a, double m_b,
1044  bool final_state, std::vector<double>& plab) const {
1045  typedef std::vector<std::pair<double, double>> xs_saver;
1046  std::map<std::string, xs_saver> xs_dump;
1047  std::map<std::string, double> outgoing_total_mass;
1048 
1049  ParticleData a_data(a), b_data(b);
1050  int n_momentum_points = 200;
1051  constexpr double momentum_step = 0.02;
1052  /*
1053  // Round to output precision.
1054  for (auto& p : plab) {
1055  p = std::floor((p * 100000) + 0.5) / 100000;
1056  }
1057  */
1058  if (plab.size() > 0) {
1059  n_momentum_points = plab.size();
1060  // Remove duplicates.
1061  std::sort(plab.begin(), plab.end());
1062  plab.erase(std::unique(plab.begin(), plab.end()), plab.end());
1063  }
1064  for (int i = 0; i < n_momentum_points; i++) {
1065  double momentum;
1066  if (plab.size() > 0) {
1067  momentum = pCM_from_s(s_from_plab(plab.at(i), m_a, m_b), m_a, m_b);
1068  } else {
1069  momentum = momentum_step * (i + 1);
1070  }
1071  a_data.set_4momentum(m_a, momentum, 0.0, 0.0);
1072  b_data.set_4momentum(m_b, -momentum, 0.0, 0.0);
1073  const double sqrts = (a_data.momentum() + b_data.momentum()).abs();
1074  const ParticleList incoming = {a_data, b_data};
1075  ScatterActionPtr act = make_unique<ScatterAction>(
1076  a_data, b_data, 0., isotropic_, string_formation_time_);
1077  if (strings_switch_) {
1078  act->set_string_interface(string_process_interface_.get());
1079  }
1080  act->add_all_scatterings(elastic_parameter_, two_to_one_, incl_set_,
1084  decaytree::Node tree(a.name() + b.name(), act->cross_section(), {&a, &b},
1085  {&a, &b}, {&a, &b}, {});
1086  const CollisionBranchList& processes = act->collision_channels();
1087  for (const auto& process : processes) {
1088  const double xs = process->weight();
1089  if (xs <= 0.0) {
1090  continue;
1091  }
1092  if (!final_state) {
1093  std::stringstream process_description_stream;
1094  process_description_stream << *process;
1095  const std::string& description = process_description_stream.str();
1096  double m_tot = 0.0;
1097  for (const auto& ptype : process->particle_types()) {
1098  m_tot += ptype->mass();
1099  }
1100  outgoing_total_mass[description] = m_tot;
1101  if (!xs_dump[description].empty() &&
1102  std::abs(xs_dump[description].back().first - sqrts) <
1103  really_small) {
1104  xs_dump[description].back().second += xs;
1105  } else {
1106  xs_dump[description].push_back(std::make_pair(sqrts, xs));
1107  }
1108  } else {
1109  std::stringstream process_description_stream;
1110  process_description_stream << *process;
1111  const std::string& description = process_description_stream.str();
1112  ParticleTypePtrList initial_particles = {&a, &b};
1113  ParticleTypePtrList final_particles = process->particle_types();
1114  auto& process_node =
1115  tree.add_action(description, xs, std::move(initial_particles),
1116  std::move(final_particles));
1117  decaytree::add_decays(process_node, sqrts);
1118  }
1119  }
1120  xs_dump["total"].push_back(std::make_pair(sqrts, act->cross_section()));
1121  // Total cross-section should be the first in the list -> negative mass
1122  outgoing_total_mass["total"] = -1.0;
1123  if (final_state) {
1124  // tree.print();
1125  auto final_state_xs = tree.final_state_cross_sections();
1126  deduplicate(final_state_xs);
1127  for (const auto& p : final_state_xs) {
1128  // Don't print empty columns.
1129  //
1130  // FIXME(steinberg): The better fix would be to not have them in the
1131  // first place.
1132  if (p.name_ == "") {
1133  continue;
1134  }
1135  outgoing_total_mass[p.name_] = p.mass_;
1136  xs_dump[p.name_].push_back(std::make_pair(sqrts, p.cross_section_));
1137  }
1138  }
1139  }
1140  // Get rid of cross sections that are zero.
1141  // (This only happens if their is a resonance in the final state that cannot
1142  // decay with our simplified assumptions.)
1143  for (auto it = begin(xs_dump); it != end(xs_dump);) {
1144  // Sum cross section over all energies.
1145  const xs_saver& xs = (*it).second;
1146  double sum = 0;
1147  for (const auto& p : xs) {
1148  sum += p.second;
1149  }
1150  if (sum == 0.) {
1151  it = xs_dump.erase(it);
1152  } else {
1153  ++it;
1154  }
1155  }
1156 
1157  // Nice ordering of channels by summed pole mass of products
1158  std::vector<std::string> all_channels;
1159  for (const auto& channel : xs_dump) {
1160  all_channels.push_back(channel.first);
1161  }
1162  std::sort(all_channels.begin(), all_channels.end(),
1163  [&](const std::string& str_a, const std::string& str_b) {
1164  return outgoing_total_mass[str_a] < outgoing_total_mass[str_b];
1165  });
1166 
1167  // Print header
1168  std::cout << "# Dumping partial " << a.name() << b.name()
1169  << " cross-sections in mb, energies in GeV" << std::endl;
1170  std::cout << " sqrt_s";
1171  // Align everything to 16 unicode characters.
1172  // This should be enough for the longest channel name (7 final-state
1173  // particles).
1174  for (const auto& channel : all_channels) {
1175  std::cout << utf8::fill_left(channel, 16, ' ');
1176  }
1177  std::cout << std::endl;
1178 
1179  // Print out all partial cross-sections in mb
1180  for (int i = 0; i < n_momentum_points; i++) {
1181  double momentum;
1182  if (plab.size() > 0) {
1183  momentum = pCM_from_s(s_from_plab(plab.at(i), m_a, m_b), m_a, m_b);
1184  } else {
1185  momentum = momentum_step * (i + 1);
1186  }
1187  a_data.set_4momentum(m_a, momentum, 0.0, 0.0);
1188  b_data.set_4momentum(m_b, -momentum, 0.0, 0.0);
1189  const double sqrts = (a_data.momentum() + b_data.momentum()).abs();
1190  std::printf("%9.6f", sqrts);
1191  for (const auto& channel : all_channels) {
1192  const xs_saver energy_and_xs = xs_dump[channel];
1193  size_t j = 0;
1194  for (; j < energy_and_xs.size() && energy_and_xs[j].first < sqrts; j++) {
1195  }
1196  double xs = 0.0;
1197  if (j < energy_and_xs.size() &&
1198  std::abs(energy_and_xs[j].first - sqrts) < really_small) {
1199  xs = energy_and_xs[j].second;
1200  }
1201  std::printf("%16.6f", xs); // Same alignment as in the header.
1202  }
1203  std::printf("\n");
1204  }
1205 }
1206 
1207 } // 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:353
smash::decaytree::Node
Node of a decay tree, representing a possible action (2-to-2 or 1-to-2).
Definition: scatteractionsfinder.cc:770
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:869
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:805
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:78
smash::ParticleData::momentum
const FourVector & momentum() const
Get the particle's 4-momentum.
Definition: particledata.h:152
smash::ScatterActionsFinder::string_formation_time_
const double string_formation_time_
Parameter for formation time.
Definition: scatteractionsfinder.h:377
smash::decaytree::Node::final_state_cross_sections
std::vector< FinalStateCrossSection > final_state_cross_sections() const
Definition: scatteractionsfinder.cc:856
smash::ParticleData::pole_mass
double pole_mass() const
Get the particle's pole mass ("on-shell").
Definition: particledata.h:109
smash::ScatterActionsFinder::elastic_parameter_
const double elastic_parameter_
Elastic cross section parameter (in mb).
Definition: scatteractionsfinder.h:334
smash::ScatterActionsFinder::string_process_interface_
std::unique_ptr< StringProcess > string_process_interface_
Class that deals with strings, interfacing Pythia.
Definition: scatteractionsfinder.h:330
smash::decaytree::Node::final_particles_
ParticleTypePtrList final_particles_
Final-state particle types in this action.
Definition: scatteractionsfinder.cc:782
smash::ParticleData
Definition: particledata.h:52
smash::ScatterActionsFinder::additional_el_xs_
const double additional_el_xs_
Additional constant elastic cross section.
Definition: scatteractionsfinder.h:348
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:890
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:336
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:342
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:359
smash::ParticleType::mass
double mass() const
Definition: particletype.h:144
smash::FinalStateCrossSection
Represent a final-state cross section.
Definition: scatteractionsfinder.cc:734
smash::ScatterActionsFinder::check_collision_multi_part
ActionPtr check_collision_multi_part(const ParticleList &plist, double dt, const double gcell_vol) const
Check for multiple i.e.
Definition: scatteractionsfinder.cc:503
smash::ScatterActionsFinder::two_to_one_
const bool two_to_one_
Enable 2->1 processes.
Definition: scatteractionsfinder.h:340
smash::decaytree::Node::children_
std::vector< Node > children_
Possible actions after this action.
Definition: scatteractionsfinder.cc:788
smash::FinalStateCrossSection::FinalStateCrossSection
FinalStateCrossSection(const std::string &name, double cross_section, double mass)
Construct a final-state cross section.
Definition: scatteractionsfinder.cc:752
smash::LFindScatter
static constexpr int LFindScatter
Definition: scatteractionsfinder.cc:26
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:371
smash::decaytree::Node::weight_
double weight_
Weight (cross section or branching ratio).
Definition: scatteractionsfinder.cc:776
smash::ParticleData::id_process
uint32_t id_process() const
Get the id of the last action.
Definition: particledata.h:128
smash::ProcessType::TwoToTwo
2->2 inelastic scattering
smash::FinalStateCrossSection::mass_
double mass_
Total mass of final state particles.
Definition: scatteractionsfinder.cc:742
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:1042
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:236
smash::ParticleData::set_4momentum
void set_4momentum(const FourVector &momentum_vector)
Set the particle's 4-momentum directly.
Definition: particledata.h:158
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:739
smash::decaytree::Node::print
void print() const
Print the decay tree starting with this node.
Definition: scatteractionsfinder.cc:851
smash::all_of
bool all_of(Container &&c, UnaryPredicate &&p)
Convenience wrapper for std::all_of that operates on a complete container.
Definition: algorithms.h:80
smash::deduplicate
static void deduplicate(std::vector< FinalStateCrossSection > &final_state_xs)
Deduplicate the final-state cross sections by summing.
Definition: scatteractionsfinder.cc:1023
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:422
smash::ScatterActionsFinder::incl_multi_set_
const MultiParticleReactionsBitSet incl_multi_set_
List of included multi-particle reactions.
Definition: scatteractionsfinder.h:344
smash::Configuration
Interface to the SMASH configuration files.
Definition: configuration.h:464
Deuteron_3to2
Definition: forwarddeclarations.h:236
smash::ParticleTypePtr
Definition: particletype.h:665
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:77
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:361
CollisionCriterion::Stochastic
Stochastic Criteiron.
CollisionCriterion::Covariant
Covariant Criterion.
smash::ScatterActionsFinder::strings_switch_
const bool strings_switch_
Switch to turn off string excitation.
Definition: scatteractionsfinder.h:355
smash::FourVector::x0
double x0() const
Definition: fourvector.h:303
smash::IsoParticleType
Definition: isoparticletype.h:28
smash::ParticleType::is_stable
bool is_stable() const
Definition: particletype.h:239
smash::ParticleData::position
const FourVector & position() const
Get the particle's position in Minkowski space.
Definition: particledata.h:198
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:296
smash::ScatterActionsFinder::find_actions_in_cell
ActionList find_actions_in_cell(const ParticleList &search_list, double dt, const double gcell_vol, const std::vector< FourVector > &beam_momentum) const override
Search for all the possible collisions within one cell.
Definition: scatteractionsfinder.cc:573
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:961
smash::ScatterActionsFinder::only_warn_for_high_prob_
const bool only_warn_for_high_prob_
Switch to turn off throwing an exception for collision probabilities larger than 1.
Definition: scatteractionsfinder.h:385
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:605
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:941
NDeuteron_to_Ndprime
Definition: forwarddeclarations.h:227
smash::ScatterActionsFinder::isotropic_
const bool isotropic_
Do all collisions isotropically.
Definition: scatteractionsfinder.h:338
smash::ScatterActionsFinder::check_collision_two_part
ActionPtr check_collision_two_part(const ParticleData &data_a, const ParticleData &data_b, double dt, const std::vector< FourVector > &beam_momentum={}, const double gcell_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:371
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:779
smash::ScatterActionsFinder::use_AQM_
const bool use_AQM_
Switch to control whether to use AQM or not.
Definition: scatteractionsfinder.h:357
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
smash::decaytree::Node::name_
std::string name_
Name for printing.
Definition: scatteractionsfinder.cc:773
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:827
smash::ExperimentParameters
Helper structure for Experiment.
Definition: experimentparameters.h:24
smash::ScatterActionsFinder::scale_xs_
const double scale_xs_
Factor by which all (partial) cross sections are scaled.
Definition: scatteractionsfinder.h:346
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:654
PiDeuteron_to_pidprime
Definition: forwarddeclarations.h:226
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:373
CollisionCriterion::Geometric
(Default) geometric criterion.
smash::ScatterActionsFinder::N_proj_
const int N_proj_
Record the number of the nucleons in the projectile.
Definition: scatteractionsfinder.h:375
scatteraction.h
smash::FinalStateCrossSection::name_
std::string name_
Name of the final state.
Definition: scatteractionsfinder.cc:736
stringfunctions.h
scatteractionmulti.h
smash::ScatterActionsFinder::coll_crit_
const CollisionCriterion coll_crit_
Specifies which collision criterion is used.
Definition: scatteractionsfinder.h:332
smash::IsoParticleType::list_all
static const IsoParticleTypeList & list_all()
Returns a list of all IsoParticleTypes.
Definition: isoparticletype.cc:42
smash::decaytree::Node::state_
ParticleTypePtrList state_
Particle types corresponding to the global state after this action.
Definition: scatteractionsfinder.cc:785
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:626
smash::pCM_from_s
T pCM_from_s(const T s, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:66
smash::ScatterActionsFinder::box_length_
const double box_length_
Box length: needed to determine coordinates of collision correctly in case of collision through the w...
Definition: scatteractionsfinder.h:367
decaymodes.h