Version: SMASH-3.1
smash::ScatterActionsFinder Class Reference

#include <scatteractionsfinder.h>

A simple scatter finder: Just loops through all particles and checks each pair for a collision.

It supports two collision criteria: a geometric and stochastic criterion.

Definition at line 31 of file scatteractionsfinder.h.

Inheritance diagram for smash::ScatterActionsFinder:
smash::ActionFinderInterface

Public Member Functions

 ScatterActionsFinder (Configuration &config, const ExperimentParameters &parameters)
 Constructor of the finder with the given parameters. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
ActionList find_final_actions (const Particles &, bool=false) const override
 Find some final collisions at the end of the simulation. More...
 
bool is_constant_elastic_isotropic () const
 If there is only one particle sort, no decays (only elastic scatterings are possible), scatterings are isotropic and cross-section fixed to elastic_parameter_ independently on momenta, then maximal cross-section is elastic_parameter_. More...
 
double max_transverse_distance_sqr (int testparticles) const
 The maximal distance over which particles can interact in case of the geometric criterion, related to the number of test particles and the maximal cross section. More...
 
void dump_reactions () const
 Prints out all the 2-> n (n > 1) reactions with non-zero cross-sections between all possible pairs of particle types. More...
 
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) and b(mass = m_b). More...
 
StringProcessget_process_string_ptr ()
 
- Public Member Functions inherited from smash::ActionFinderInterface
virtual ~ActionFinderInterface ()=default
 

Private Member Functions

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 create a corresponding Action object in that case. More...
 
ActionPtr check_collision_multi_part (const ParticleList &plist, double dt, const double gcell_vol) const
 Check for multiple i.e. More...
 

Private Attributes

ScatterActionsFinderParameters finder_parameters_
 Struct collecting several parameters. More...
 
std::unique_ptr< StringProcessstring_process_interface_
 Class that deals with strings, interfacing Pythia. More...
 
const bool isotropic_
 Do all collisions isotropically. More...
 
const double box_length_
 Box length: needed to determine coordinates of collision correctly in case of collision through the wall. More...
 
const double string_formation_time_
 Parameter for formation time. More...
 

Constructor & Destructor Documentation

◆ ScatterActionsFinder()

smash::ScatterActionsFinder::ScatterActionsFinder ( Configuration config,
const ExperimentParameters parameters 
)

Constructor of the finder with the given parameters.

Parameters
[in,out]configConfiguration of smash from which we take: 1) A global elastic cross section [mb]. It will be used regardless of the species of the colliding particles. It won't be used if the value is negative. 2) An option determining whether all the scatterings are isotropic 3) Parameters of the string process
[in]parametersStruct of parameters determining whether to exclude some certain types of scatterings and switching among the methods to treat with the NNbar collisions.

Definition at line 34 of file scatteractionsfinder.cc.

36  : finder_parameters_(create_finder_parameters(config, parameters)),
37  isotropic_(config.take({"Collision_Term", "Isotropic"}, false)),
38  box_length_(parameters.box_length),
39  string_formation_time_(config.take(
40  {"Collision_Term", "String_Parameters", "Formation_Time"}, 1.)) {
42  logg[LFindScatter].info(
43  "Constant elastic isotropic cross-section mode:", " using ",
44  finder_parameters_.elastic_parameter, " mb as maximal cross-section.");
45  }
48  throw std::invalid_argument(
49  "Multi-body reactions (like e.g. 3->1 or 3->2) are only possible with "
50  "the stochastic "
51  "collision "
52  "criterion. Change your config accordingly.");
53  }
54 
57  1 &&
59  .included_2to2[IncludedReactions::PiDeuteron_to_pidprime] == 1 ||
61  .included_2to2[IncludedReactions::NDeuteron_to_Ndprime] == 1)) {
62  throw std::invalid_argument(
63  "To prevent double counting it is not possible to enable deuteron 3->2 "
64  "reactions\nand reactions involving the d' at the same time\ni.e. to "
65  "include \"Deuteron_3to2\" in `Multi_Particle_Reactions` and\n "
66  "\"PiDeuteron_to_pidprime\" "
67  "or \"NDeuteron_to_Ndprime\" in `Included_2to2` at the same time.\n"
68  "Change your config accordingly.");
69  }
70 
73  1 &&
75  throw std::invalid_argument(
76  "Do not use the d' resonance and enable \"Deuteron_3to2\" "
77  "`Multi_Particle_Reactions` at the same time. Either use the direct "
78  "3-to-2 reactions or the d' together with \"PiDeuteron_to_pidprime\" "
79  "and \"NDeuteron_to_Ndprime\" in `Included_2to2`. Otherwise the "
80  "deuteron 3-to-2 reactions would be double counted.");
81  }
82 
86  1) ||
89  1 &&
91  throw std::invalid_argument(
92  "In order to conserve detailed balance, when \"NNbar_5to2\" is "
93  "included in\n`Multi_Particle_Reactions`, the `NNbarTreatment` has to "
94  "be set to \"two to five\" and vice versa.");
95  }
96 
99  throw std::invalid_argument(
100  "'NNbar' has to be in the list of allowed 2 to 2 processes "
101  "to enable annihilation to go through resonances");
102  }
103 
105  auto subconfig = config.extract_sub_configuration(
106  {"Collision_Term", "String_Parameters"}, Configuration::GetEmpty::Yes);
107  string_process_interface_ = std::make_unique<StringProcess>(
108  subconfig.take({"String_Tension"}, 1.0), string_formation_time_,
109  subconfig.take({"Gluon_Beta"}, 0.5),
110  subconfig.take({"Gluon_Pmin"}, 0.001),
111  subconfig.take({"Quark_Alpha"}, 2.0),
112  subconfig.take({"Quark_Beta"}, 7.0),
113  subconfig.take({"Strange_Supp"}, 0.16),
114  subconfig.take({"Diquark_Supp"}, 0.036),
115  subconfig.take({"Sigma_Perp"}, 0.42),
116  subconfig.take({"StringZ_A_Leading"}, 0.2),
117  subconfig.take({"StringZ_B_Leading"}, 2.0),
118  subconfig.take({"StringZ_A"}, 2.0), subconfig.take({"StringZ_B"}, 0.55),
119  subconfig.take({"String_Sigma_T"}, 0.5),
120  subconfig.take({"Form_Time_Factor"}, 1.0),
121  subconfig.take({"Mass_Dependent_Formation_Times"}, false),
122  subconfig.take({"Prob_proton_to_d_uu"}, 1. / 3.),
123  subconfig.take({"Separate_Fragment_Baryon"}, true),
124  subconfig.take({"Popcorn_Rate"}, 0.15),
125  subconfig.take({"Use_Monash_Tune"},
126  parameters.use_monash_tune_default.value()));
127  }
128 }
static const ParticleTypePtr try_find(PdgCode pdgcode)
Returns the ParticleTypePtr for the given pdgcode.
Definition: particletype.cc:89
ScatterActionsFinderParameters finder_parameters_
Struct collecting several parameters.
const bool isotropic_
Do all collisions isotropically.
const double string_formation_time_
Parameter for formation time.
std::unique_ptr< StringProcess > string_process_interface_
Class that deals with strings, interfacing Pythia.
bool is_constant_elastic_isotropic() const
If there is only one particle sort, no decays (only elastic scatterings are possible),...
const double box_length_
Box length: needed to determine coordinates of collision correctly in case of collision through the w...
@ TwoToFive
Directly create 5 pions, use with multi-particle reactions.
@ Resonances
Use intermediate Resonances.
@ NNbar_5to2
@ Deuteron_3to2
@ Stochastic
Stochastic Criteiron.
@ PiDeuteron_to_pidprime
@ NDeuteron_to_Ndprime
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 int64_t dprime
Deuteron-prime resonance.
ScatterActionsFinderParameters create_finder_parameters(Configuration &config, const ExperimentParameters &parameters)
Gather all relevant parameters for a ScatterActionsFinder either getting them from an ExperimentParam...
static constexpr int LFindScatter
const ReactionsBitSet included_2to2
List of included 2<->2 reactions.
const double elastic_parameter
Elastic cross section parameter (in mb).
const bool strings_switch
Indicates whether string fragmentation is switched on.
const MultiParticleReactionsBitSet included_multi
List of included multi-particle reactions.
const NNbarTreatment nnbar_treatment
Switch for NNbar reactions.
const CollisionCriterion coll_crit
Specifies which collision criterion is used.

Member Function Documentation

◆ collision_time()

double smash::ScatterActionsFinder::collision_time ( const ParticleData p1,
const ParticleData p2,
double  dt,
const std::vector< FourVector > &  beam_momentum 
) const
inline

Determine the collision time of the two particles.

Time of the closest approach is taken as collision time, if the geometric collision criterion is used. For stochastic criterion the time is distributed uniformly within the timestep.

Parameters
[in]p1First incoming particle
[in]p2Second incoming particle
[in]dtThe maximum time interval at the current time step [fm]
[in]beam_momentum[GeV] List of beam momenta for each particle; only necessary for frozen Fermi motion
Returns
How long does it take for the two incoming particles to propagate before scattering [fm]. It's set equal to -1 if the two particles are not moving relative to each other.

JAM collision times from the closest approach in the two-particle center-of-mass-framem, see Hirano:2012yy [26] (5.13) and (5.14). The scatteraction is performed at the mean of these two times.

UrQMD collision time in computational frame, see Bass:1998ca [5] (3.28): position of particle 1: \(r_1\) [fm] position of particle 2: \(r_2\) [fm] velocity of particle 1: \(v_1\) velocity of particle 1: \(v_2\)

\[t_{coll} = - (r_1 - r_2) . (v_1 - v_2) / (v_1 - v_2)^2\]

[fm]

Definition at line 66 of file scatteractionsfinder.h.

68  {
70  return dt * random::uniform(0., 1.);
71  } else {
72  /*
73  * For frozen Fermi motion:
74  * If particles have not yet interacted and are the initial nucleons,
75  * perform action finding with beam momentum instead of Fermi motion
76  * corrected momentum. That is because the particles are propagated with
77  * the beam momentum until they interact.
78  */
79  if (p1.id() < 0 || p2.id() < 0) {
80  throw std::runtime_error("Invalid particle ID for Fermi motion");
81  }
82  const bool p1_has_no_prior_interactions =
83  (static_cast<uint64_t>(p1.id()) < // particle from
84  static_cast<uint64_t>(beam_momentum.size())) && // initial nucleus
85  (p1.get_history().collisions_per_particle == 0);
86 
87  const bool p2_has_no_prior_interactions =
88  (static_cast<uint64_t>(p2.id()) < // particle from
89  static_cast<uint64_t>(beam_momentum.size())) && // initial nucleus
90  (p2.get_history().collisions_per_particle == 0);
91 
92  const FourVector p1_mom = (p1_has_no_prior_interactions)
93  ? beam_momentum[p1.id()]
94  : p1.momentum();
95  const FourVector p2_mom = (p2_has_no_prior_interactions)
96  ? beam_momentum[p2.id()]
97  : p2.momentum();
105  const FourVector delta_x = p1.position() - p2.position();
106  const double p1_sqr = p1_mom.sqr();
107  const double p2_sqr = p2_mom.sqr();
108  const double p1_dot_x = p1_mom.Dot(delta_x);
109  const double p2_dot_x = p2_mom.Dot(delta_x);
110  const double p1_dot_p2 = p1_mom.Dot(p2_mom);
111  const double denominator = std::pow(p1_dot_p2, 2) - p1_sqr * p2_sqr;
112  if (unlikely(std::abs(denominator) < really_small * really_small)) {
113  return -1.0;
114  }
115 
116  const double time_1 = (p2_sqr * p1_dot_x - p1_dot_p2 * p2_dot_x) *
117  p1_mom.x0() / denominator;
118  const double time_2 = -(p1_sqr * p2_dot_x - p1_dot_p2 * p1_dot_x) *
119  p2_mom.x0() / denominator;
120  return (time_1 + time_2) / 2;
121  } else {
131  const ThreeVector dv_times_e1e2 =
132  p1_mom.threevec() * p2_mom.x0() - p2_mom.threevec() * p1_mom.x0();
133  const double dv_times_e1e2_sqr = dv_times_e1e2.sqr();
134  if (dv_times_e1e2_sqr < really_small) {
135  return -1.0;
136  }
137  const ThreeVector dr =
138  p1.position().threevec() - p2.position().threevec();
139  return -(dr * dv_times_e1e2) *
140  (p1_mom.x0() * p2_mom.x0() / dv_times_e1e2_sqr);
141  }
142  }
143  }
@ Covariant
Covariant Criterion.
#define unlikely(x)
Tell the branch predictor that this expression is likely false.
Definition: macros.h:16
T uniform(T min, T max)
Definition: random.h:88
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:37

◆ find_actions_in_cell()

ActionList smash::ScatterActionsFinder::find_actions_in_cell ( const ParticleList &  search_list,
double  dt,
const double  gcell_vol,
const std::vector< FourVector > &  beam_momentum 
) const
overridevirtual

Search for all the possible collisions within one cell.

This function is only used for counting the primary collisions at the beginning of each time step. (Although it's also called afterwards for searching the secondary collisions among the outgoing particles, no new actions will be found since the scattered pairs cannot scatter again.)

Parameters
[in]search_listA list of particles within one cell
[in]dtThe maximum time interval at the current time step [fm]
[in]gcell_volVolume of searched grid cell [fm^3]
[in]beam_momentum[GeV] List of beam momenta for each particle; only necessary for frozen Fermi motion
Returns
A list of possible scatter actions

Implements smash::ActionFinderInterface.

Definition at line 445 of file scatteractionsfinder.cc.

447  {
448  std::vector<ActionPtr> actions;
449  for (const ParticleData& p1 : search_list) {
450  for (const ParticleData& p2 : search_list) {
451  // Check for 2 particle scattering
452  if (p1.id() < p2.id()) {
453  ActionPtr act =
454  check_collision_two_part(p1, p2, dt, beam_momentum, gcell_vol);
455  if (act) {
456  actions.push_back(std::move(act));
457  }
458  }
460  // Also, check for 3 particle scatterings with stochastic criterion
461  for (const ParticleData& p3 : search_list) {
466  if (p1.id() < p2.id() && p2.id() < p3.id()) {
467  ActionPtr act =
468  check_collision_multi_part({p1, p2, p3}, dt, gcell_vol);
469  if (act) {
470  actions.push_back(std::move(act));
471  }
472  }
473  }
474  for (const ParticleData& p4 : search_list) {
477  if (p1.id() < p2.id() && p2.id() < p3.id() && p3.id() < p4.id()) {
478  ActionPtr act =
479  check_collision_multi_part({p1, p2, p3, p4}, dt, gcell_vol);
480  if (act) {
481  actions.push_back(std::move(act));
482  }
483  }
484  }
487  search_list.size() >= 5) {
488  for (const ParticleData& p5 : search_list) {
489  if ((p1.id() < p2.id() && p2.id() < p3.id() &&
490  p3.id() < p4.id() && p4.id() < p5.id()) &&
491  (p1.is_pion() && p2.is_pion() && p3.is_pion() &&
492  p4.is_pion() && p5.is_pion())) {
493  // at the moment only pure pion 5-body reactions
494  ActionPtr act = check_collision_multi_part(
495  {p1, p2, p3, p4, p5}, dt, gcell_vol);
496  if (act) {
497  actions.push_back(std::move(act));
498  }
499  }
500  }
501  }
502  }
503  }
504  }
505  }
506  }
507  return actions;
508 }
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...
ActionPtr check_collision_multi_part(const ParticleList &plist, double dt, const double gcell_vol) const
Check for multiple i.e.
@ A3_Nuclei_4to2
@ Meson_3to1

◆ find_actions_with_neighbors()

ActionList smash::ScatterActionsFinder::find_actions_with_neighbors ( const ParticleList &  search_list,
const ParticleList &  neighbors_list,
double  dt,
const std::vector< FourVector > &  beam_momentum 
) const
overridevirtual

Search for all the possible collisions among the neighboring cells.

This function is only used for counting the primary collisions at the beginning of each time step.

Parameters
[in]search_listA list of particles within the current cell
[in]neighbors_listA list of particles within the neighboring cell
[in]dtThe maximum time interval at the current time step [fm]
[in]beam_momentum[GeV] List of beam momenta for each particle; only necessary for frozen Fermi motion
Returns
A list of possible scatter actions

Implements smash::ActionFinderInterface.

Definition at line 510 of file scatteractionsfinder.cc.

512  {
513  std::vector<ActionPtr> actions;
515  // Only search in cells
516  return actions;
517  }
518  for (const ParticleData& p1 : search_list) {
519  for (const ParticleData& p2 : neighbors_list) {
520  assert(p1.id() != p2.id());
521  // Check if a collision is possible.
522  ActionPtr act = check_collision_two_part(p1, p2, dt, beam_momentum);
523  if (act) {
524  actions.push_back(std::move(act));
525  }
526  }
527  }
528  return actions;
529 }

◆ find_actions_with_surrounding_particles()

ActionList smash::ScatterActionsFinder::find_actions_with_surrounding_particles ( const ParticleList &  search_list,
const Particles surrounding_list,
double  dt,
const std::vector< FourVector > &  beam_momentum 
) const
overridevirtual

Search for all the possible secondary collisions between the outgoing particles and the rest.

Parameters
[in]search_listA list of particles within the current cell
[in]surrounding_listThe whole particle list
[in]dtThe maximum time interval at the current time step [fm]
[in]beam_momentum[GeV] List of beam momenta for each particle; only necessary for frozen Fermi motion
Returns
A list of possible scatter actions

Implements smash::ActionFinderInterface.

Definition at line 531 of file scatteractionsfinder.cc.

533  {
534  std::vector<ActionPtr> actions;
536  // Only search in cells
537  return actions;
538  }
539  for (const ParticleData& p2 : surrounding_list) {
540  /* don't look for collisions if the particle from the surrounding list is
541  * also in the search list */
542  auto result = std::find_if(
543  search_list.begin(), search_list.end(),
544  [&p2](const ParticleData& p) { return p.id() == p2.id(); });
545  if (result != search_list.end()) {
546  continue;
547  }
548  for (const ParticleData& p1 : search_list) {
549  // Check if a collision is possible.
550  ActionPtr act = check_collision_two_part(p1, p2, dt, beam_momentum);
551  if (act) {
552  actions.push_back(std::move(act));
553  }
554  }
555  }
556  return actions;
557 }
constexpr int p
Proton.

◆ find_final_actions()

ActionList smash::ScatterActionsFinder::find_final_actions ( const Particles ,
bool  = false 
) const
inlineoverridevirtual

Find some final collisions at the end of the simulation.

Todo:
Seems to do nothing.

Implements smash::ActionFinderInterface.

Definition at line 198 of file scatteractionsfinder.h.

199  {
200  return ActionList();
201  }

◆ is_constant_elastic_isotropic()

bool smash::ScatterActionsFinder::is_constant_elastic_isotropic ( ) const
inline

If there is only one particle sort, no decays (only elastic scatterings are possible), scatterings are isotropic and cross-section fixed to elastic_parameter_ independently on momenta, then maximal cross-section is elastic_parameter_.

This knowledge can be used for improving performance.

Returns
A boolean indicating whether all the scatterings are elastic and isotropic

Definition at line 213 of file scatteractionsfinder.h.

213  {
214  return ParticleType::list_all().size() == 1 &&
217  }
static const ParticleTypeList & list_all()
Definition: particletype.cc:51
const bool two_to_one
Enables resonance production.

◆ max_transverse_distance_sqr()

double smash::ScatterActionsFinder::max_transverse_distance_sqr ( int  testparticles) const
inline

The maximal distance over which particles can interact in case of the geometric criterion, related to the number of test particles and the maximal cross section.

Parameters
[in]testparticlesNumber of test particles.
Returns
Maximal transverse distance squared. [fm \(^{2}\)] Particle pairs whose transverse distance is larger than this are not checked for collisions in case of the default geometric collision criterion.

Definition at line 231 of file scatteractionsfinder.h.

231  {
235  testparticles * fm2_mb * M_1_PI;
236  }
constexpr double fm2_mb
mb <-> fm^2 conversion factor.
Definition: constants.h:28

◆ dump_reactions()

void smash::ScatterActionsFinder::dump_reactions ( ) const

Prints out all the 2-> n (n > 1) reactions with non-zero cross-sections between all possible pairs of particle types.

Definition at line 559 of file scatteractionsfinder.cc.

559  {
560  constexpr double time = 0.0;
561 
562  const size_t N_isotypes = IsoParticleType::list_all().size();
563  const size_t N_pairs = N_isotypes * (N_isotypes - 1) / 2;
564 
565  std::cout << N_isotypes << " iso-particle types." << std::endl;
566  std::cout << "They can make " << N_pairs << " pairs." << std::endl;
567  std::vector<double> momentum_scan_list = {0.1, 0.3, 0.5, 1.0,
568  2.0, 3.0, 5.0, 10.0};
569  for (const IsoParticleType& A_isotype : IsoParticleType::list_all()) {
570  for (const IsoParticleType& B_isotype : IsoParticleType::list_all()) {
571  if (&A_isotype > &B_isotype) {
572  continue;
573  }
574  bool any_nonzero_cs = false;
575  std::vector<std::string> r_list;
576  for (const ParticleTypePtr A_type : A_isotype.get_states()) {
577  for (const ParticleTypePtr B_type : B_isotype.get_states()) {
578  if (A_type > B_type) {
579  continue;
580  }
581  ParticleData A(*A_type), B(*B_type);
582  for (auto mom : momentum_scan_list) {
583  A.set_4momentum(A.pole_mass(), mom, 0.0, 0.0);
584  B.set_4momentum(B.pole_mass(), -mom, 0.0, 0.0);
585  ScatterActionPtr act = std::make_unique<ScatterAction>(
586  A, B, time, isotropic_, string_formation_time_, -1, false);
588  act->set_string_interface(string_process_interface_.get());
589  }
590  act->add_all_scatterings(finder_parameters_);
591  const double total_cs = act->cross_section();
592  if (total_cs <= 0.0) {
593  continue;
594  }
595  any_nonzero_cs = true;
596  for (const auto& channel : act->collision_channels()) {
597  const auto type = channel->get_type();
598  std::string r;
599  if (is_string_soft_process(type) ||
600  type == ProcessType::StringHard) {
601  r = A_type->name() + B_type->name() + std::string(" → strings");
602  } else {
603  std::string r_type =
604  (type == ProcessType::Elastic) ? std::string(" (el)")
605  : (channel->get_type() == ProcessType::TwoToTwo)
606  ? std::string(" (inel)")
607  : std::string(" (?)");
608  r = A_type->name() + B_type->name() + std::string(" → ") +
609  channel->particle_types()[0]->name() +
610  channel->particle_types()[1]->name() + r_type;
611  }
612  isoclean(r);
613  r_list.push_back(r);
614  }
615  }
616  }
617  }
618  std::sort(r_list.begin(), r_list.end());
619  r_list.erase(std::unique(r_list.begin(), r_list.end()), r_list.end());
620  if (any_nonzero_cs) {
621  for (auto r : r_list) {
622  std::cout << r;
623  if (r_list.back() != r) {
624  std::cout << ", ";
625  }
626  }
627  std::cout << std::endl;
628  }
629  }
630  }
631 }
static const IsoParticleTypeList & list_all()
Returns a list of all IsoParticleTypes.
@ TwoToTwo
See here for a short description.
@ Elastic
See here for a short description.
@ StringHard
See here for a short description.
void isoclean(std::string &s)
Remove ⁺, ⁻, ⁰ from string.
bool is_string_soft_process(ProcessType p)
Check if a given process type is a soft string excitation.

◆ dump_cross_sections()

void smash::ScatterActionsFinder::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) and b(mass = m_b).

Parameters
[in]aThe specie of the first incoming particle.
[in]bThe specie of the second incoming particle.
[in]m_aMass of species a [GeV].
[in]m_bMass of species b [GeV].
[in]final_stateWhether the final state cross sections should be printed.
[in]plabOptional momenta in lab frame to be evaluated [GeV]. Ignored if empty.

Definition at line 942 of file scatteractionsfinder.cc.

944  {
945  typedef std::vector<std::pair<double, double>> xs_saver;
946  std::map<std::string, xs_saver> xs_dump;
947  std::map<std::string, double> outgoing_total_mass;
948 
949  ParticleData a_data(a), b_data(b);
950  int n_momentum_points = 200;
951  constexpr double momentum_step = 0.02;
952  if (plab.size() > 0) {
953  n_momentum_points = plab.size();
954  // Remove duplicates.
955  std::sort(plab.begin(), plab.end());
956  plab.erase(std::unique(plab.begin(), plab.end()), plab.end());
957  }
958  for (int i = 0; i < n_momentum_points; i++) {
959  double momentum;
960  if (plab.size() > 0) {
961  momentum = pCM_from_s(s_from_plab(plab.at(i), m_a, m_b), m_a, m_b);
962  } else {
963  momentum = momentum_step * (i + 1);
964  }
965  a_data.set_4momentum(m_a, momentum, 0.0, 0.0);
966  b_data.set_4momentum(m_b, -momentum, 0.0, 0.0);
967  const double sqrts = (a_data.momentum() + b_data.momentum()).abs();
968  const ParticleList incoming = {a_data, b_data};
969  ScatterActionPtr act = std::make_unique<ScatterAction>(
970  a_data, b_data, 0., isotropic_, string_formation_time_, -1, false);
972  act->set_string_interface(string_process_interface_.get());
973  }
974  act->add_all_scatterings(finder_parameters_);
975  decaytree::Node tree(a.name() + b.name(), act->cross_section(), {&a, &b},
976  {&a, &b}, {&a, &b}, {});
977  const CollisionBranchList& processes = act->collision_channels();
978  for (const auto& process : processes) {
979  const double xs = process->weight();
980  if (xs <= 0.0) {
981  continue;
982  }
983  if (!final_state) {
984  std::stringstream process_description_stream;
985  process_description_stream << *process;
986  const std::string& description = process_description_stream.str();
987  double m_tot = 0.0;
988  for (const auto& ptype : process->particle_types()) {
989  m_tot += ptype->mass();
990  }
991  outgoing_total_mass[description] = m_tot;
992  if (!xs_dump[description].empty() &&
993  std::abs(xs_dump[description].back().first - sqrts) <
994  really_small) {
995  xs_dump[description].back().second += xs;
996  } else {
997  xs_dump[description].push_back(std::make_pair(sqrts, xs));
998  }
999  } else {
1000  std::stringstream process_description_stream;
1001  process_description_stream << *process;
1002  const std::string& description = process_description_stream.str();
1003  ParticleTypePtrList initial_particles = {&a, &b};
1004  ParticleTypePtrList final_particles = process->particle_types();
1005  auto& process_node =
1006  tree.add_action(description, xs, std::move(initial_particles),
1007  std::move(final_particles));
1008  decaytree::add_decays(process_node, sqrts);
1009  }
1010  }
1011  xs_dump["total"].push_back(std::make_pair(sqrts, act->cross_section()));
1012  // Total cross-section should be the first in the list -> negative mass
1013  outgoing_total_mass["total"] = -1.0;
1014  if (final_state) {
1015  // tree.print();
1016  auto final_state_xs = tree.final_state_cross_sections();
1017  deduplicate(final_state_xs);
1018  for (const auto& p : final_state_xs) {
1019  // Don't print empty columns.
1020  //
1021  // FIXME(steinberg): The better fix would be to not have them in the
1022  // first place.
1023  if (p.name_ == "") {
1024  continue;
1025  }
1026  outgoing_total_mass[p.name_] = p.mass_;
1027  xs_dump[p.name_].push_back(std::make_pair(sqrts, p.cross_section_));
1028  }
1029  }
1030  }
1031  // Get rid of cross sections that are zero.
1032  // (This only happens if their is a resonance in the final state that cannot
1033  // decay with our simplified assumptions.)
1034  for (auto it = begin(xs_dump); it != end(xs_dump);) {
1035  // Sum cross section over all energies.
1036  const xs_saver& xs = (*it).second;
1037  double sum = 0;
1038  for (const auto& p : xs) {
1039  sum += p.second;
1040  }
1041  if (sum == 0.) {
1042  it = xs_dump.erase(it);
1043  } else {
1044  ++it;
1045  }
1046  }
1047 
1048  // Nice ordering of channels by summed pole mass of products
1049  std::vector<std::string> all_channels;
1050  for (const auto& channel : xs_dump) {
1051  all_channels.push_back(channel.first);
1052  }
1053  std::sort(all_channels.begin(), all_channels.end(),
1054  [&](const std::string& str_a, const std::string& str_b) {
1055  return outgoing_total_mass[str_a] < outgoing_total_mass[str_b];
1056  });
1057 
1058  // Print header
1059  std::cout << "# Dumping partial " << a.name() << b.name()
1060  << " cross-sections in mb, energies in GeV" << std::endl;
1061  std::cout << " sqrt_s";
1062  // Align everything to 16 unicode characters.
1063  // This should be enough for the longest channel name (7 final-state
1064  // particles).
1065  for (const auto& channel : all_channels) {
1066  std::cout << utf8::fill_left(channel, 16, ' ');
1067  }
1068  std::cout << std::endl;
1069 
1070  // Print out all partial cross-sections in mb
1071  for (int i = 0; i < n_momentum_points; i++) {
1072  double momentum;
1073  if (plab.size() > 0) {
1074  momentum = pCM_from_s(s_from_plab(plab.at(i), m_a, m_b), m_a, m_b);
1075  } else {
1076  momentum = momentum_step * (i + 1);
1077  }
1078  a_data.set_4momentum(m_a, momentum, 0.0, 0.0);
1079  b_data.set_4momentum(m_b, -momentum, 0.0, 0.0);
1080  const double sqrts = (a_data.momentum() + b_data.momentum()).abs();
1081  std::printf("%9.6f", sqrts);
1082  for (const auto& channel : all_channels) {
1083  const xs_saver energy_and_xs = xs_dump[channel];
1084  size_t j = 0;
1085  for (; j < energy_and_xs.size() && energy_and_xs[j].first < sqrts; j++) {
1086  }
1087  double xs = 0.0;
1088  if (j < energy_and_xs.size() &&
1089  std::abs(energy_and_xs[j].first - sqrts) < really_small) {
1090  xs = energy_and_xs[j].second;
1091  }
1092  std::printf("%16.6f", xs); // Same alignment as in the header.
1093  }
1094  std::printf("\n");
1095  }
1096 }
static void add_decays(Node &node, double sqrts)
Add nodes for all decays possible from the given node and all of its children.
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.
static void deduplicate(std::vector< FinalStateCrossSection > &final_state_xs)
Deduplicate the final-state cross sections by summing.
T pCM_from_s(const T s, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:66
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:265

◆ get_process_string_ptr()

StringProcess* smash::ScatterActionsFinder::get_process_string_ptr ( )
inline
Returns
Pointer to the string process class object. If string is turned off, the null pointer is returned.

Definition at line 265 of file scatteractionsfinder.h.

265  {
267  return string_process_interface_.get();
268  } else {
269  return NULL;
270  }
271  }

◆ check_collision_two_part()

ActionPtr smash::ScatterActionsFinder::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
private

Check for a single pair of particles (id_a, id_b) if a collision will happen in the next timestep and create a corresponding Action object in that case.

Two criteria for the collision decision are supported: 1. The default geometric criterion from UrQMD Bass:1998ca [5] (3.27). 2. A stochastic collision criterion as introduced in Staudenmaier:2021lrg [56].

Parameters
[in]data_aFirst incoming particle
[in]data_bSecond incoming particle
[in]dtMaximum time interval within which a collision can happen
[in]beam_momentum[GeV] List of beam momenta for each particle; only necessary for frozen Fermi motion
[in]gcell_vol(optional) volume of grid cell in which the collision is checked
Returns
A null pointer if no collision happens or an action which contains the information of the outgoing particles.

Note: gcell_vol is optional, since only find_actions_in_cell has (and needs) this information for the stochastic collision criterion.

Definition at line 211 of file scatteractionsfinder.cc.

214  {
215  /* If the two particles
216  * 1) belong to one of the two colliding nuclei, and
217  * 2) both of them have never experienced any collisions,
218  * then the collisions between them are banned. */
220  assert(data_a.id() >= 0);
221  assert(data_b.id() >= 0);
222  bool in_same_nucleus = (data_a.belongs_to() == BelongsTo::Projectile &&
223  data_b.belongs_to() == BelongsTo::Projectile) ||
224  (data_a.belongs_to() == BelongsTo::Target &&
225  data_b.belongs_to() == BelongsTo::Target);
226  bool never_interacted_before =
227  data_a.get_history().collisions_per_particle == 0 &&
228  data_b.get_history().collisions_per_particle == 0;
229  if (in_same_nucleus && never_interacted_before) {
230  return nullptr;
231  }
232  }
233 
234  // No grid or search in cell means no collision for stochastic criterion
236  gcell_vol < really_small) {
237  return nullptr;
238  }
239 
240  // Determine time of collision.
241  const double time_until_collision =
242  collision_time(data_a, data_b, dt, beam_momentum);
243 
244  // Check that collision happens in this timestep.
245  if (time_until_collision < 0. || time_until_collision >= dt) {
246  return nullptr;
247  }
248 
249  // Determine which total cross section to use
250  bool incoming_parametrized = (finder_parameters_.total_xs_strategy ==
254  const PdgCode& pdg_a = data_a.type().pdgcode();
255  const PdgCode& pdg_b = data_b.type().pdgcode();
256  incoming_parametrized = parametrization_exists(pdg_a, pdg_b);
257  }
258 
259  // Create ScatterAction object.
260  ScatterActionPtr act = std::make_unique<ScatterAction>(
261  data_a, data_b, time_until_collision, isotropic_, string_formation_time_,
262  box_length_, incoming_parametrized);
263 
265  act->set_stochastic_pos_idx();
266  }
267 
269  act->set_string_interface(string_process_interface_.get());
270  }
271 
272  // Distance squared calculation not needed for stochastic criterion
273  const double distance_squared =
275  ? act->transverse_distance_sqr()
277  ? act->cov_transverse_distance_sqr()
278  : 0.0;
279 
280  // Don't calculate cross section if the particles are very far apart.
281  // Not needed for stochastic criterion because of cell structure.
283  distance_squared >=
285  return nullptr;
286  }
287 
288  if (incoming_parametrized) {
289  act->set_parametrized_total_cross_section(finder_parameters_);
290  } else {
291  // Add various subprocesses.
292  act->add_all_scatterings(finder_parameters_);
293  }
294 
295  double xs = act->cross_section() * fm2_mb /
296  static_cast<double>(finder_parameters_.testparticles);
297 
298  // Take cross section scaling factors into account
299  xs *= data_a.xsec_scaling_factor(time_until_collision);
300  xs *= data_b.xsec_scaling_factor(time_until_collision);
301 
303  const double v_rel = act->relative_velocity();
304  /* Collision probability for 2-particle scattering, see
305  * \iref{Staudenmaier:2021lrg}. */
306  const double prob = xs * v_rel * dt / gcell_vol;
307 
308  logg[LFindScatter].debug(
309  "Stochastic collison criterion parameters (2-particles):\nprob = ",
310  prob, ", xs = ", xs, ", v_rel = ", v_rel, ", dt = ", dt,
311  ", gcell_vol = ", gcell_vol,
312  ", testparticles = ", finder_parameters_.testparticles);
313 
314  if (prob > 1.) {
315  std::stringstream err;
316  err << "Probability larger than 1 for stochastic rates. ( P_22 = " << prob
317  << " )\n"
318  << data_a.type().name() << data_b.type().name() << " with masses "
319  << data_a.momentum().abs() << " and " << data_b.momentum().abs()
320  << " at sqrts[GeV] = " << act->sqrt_s()
321  << " with xs[fm^2]/Ntest = " << xs
322  << "\nConsider using smaller timesteps.";
324  logg[LFindScatter].warn(err.str());
325  } else {
326  throw std::runtime_error(err.str());
327  }
328  }
329 
330  // probability criterion
331  double random_no = random::uniform(0., 1.);
332  if (random_no > prob) {
333  return nullptr;
334  }
335 
338  // just collided with this particle
339  if (data_a.id_process() > 0 && data_a.id_process() == data_b.id_process()) {
340  logg[LFindScatter].debug("Skipping collided particles at time ",
341  data_a.position().x0(), " due to process ",
342  data_a.id_process(), "\n ", data_a, "\n<-> ",
343  data_b);
344 
345  return nullptr;
346  }
347 
348  // Cross section for collision criterion
349  const double cross_section_criterion = xs * M_1_PI;
350 
351  // distance criterion according to cross_section
352  if (distance_squared >= cross_section_criterion) {
353  return nullptr;
354  }
355 
356  logg[LFindScatter].debug("particle distance squared: ", distance_squared,
357  "\n ", data_a, "\n<-> ", data_b);
358  }
359 
360  // Include possible outgoing branches
361  if (incoming_parametrized) {
362  act->add_all_scatterings(finder_parameters_);
363  }
364 
365  return act;
366 }
double max_transverse_distance_sqr(int testparticles) const
The maximal distance over which particles can interact in case of the geometric criterion,...
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.
@ TopDownMeasured
Mix the two above, using the parametrizations only for measured processes, and summing up partials fo...
@ TopDown
Use parametrizations based on existing data, rescaling with AQM for unmeasured processes.
@ Geometric
Geometric criterion.
bool parametrization_exists(const PdgCode &pdg_a, const PdgCode &pdg_b)
Checks if supplied codes have existing parametrizations of total cross sections.
const bool only_warn_for_high_prob
Switch to turn off throwing an exception for collision probabilities larger than 1.
const int testparticles
Number of test particles.
const TotalCrossSectionStrategy total_xs_strategy
Method used to evaluate total cross sections for collision finding.
const bool allow_collisions_within_nucleus
If particles within the same nucleus are allowed to collide for their first time.

◆ check_collision_multi_part()

ActionPtr smash::ScatterActionsFinder::check_collision_multi_part ( const ParticleList &  plist,
double  dt,
const double  gcell_vol 
) const
private

Check for multiple i.e.

more than 2 particles if a collision will happen in the next timestep and create a corresponding Action object in that case.

This is only possible for the stochastic collision criterion, which is introduced in Staudenmaier:2021lrg [56]. Following the same general idea as for the 2-particle scatterings, probabilities for multi-particle scatterings can be derived.

Parameters
[in]plistList of incoming particles
[in]dtMaximum time interval within which a collision can happen
[in]gcell_volvolume of grid cell in which the collision is checked
Returns
A null pointer if no collision happens or an action which contains the information of the outgoing particles.

Definition at line 368 of file scatteractionsfinder.cc.

369  {
370  /* If all particles
371  * 1) belong to the two colliding nuclei
372  * 2) are within the same nucleus
373  * 3) have never experienced any collisons,
374  * then the collision between them are banned also for multi-particle
375  * interactions. */
377  bool all_projectile =
378  std::all_of(plist.begin(), plist.end(), [&](const ParticleData& data) {
379  return data.belongs_to() == BelongsTo::Projectile;
380  });
381  bool all_target =
382  std::all_of(plist.begin(), plist.end(), [&](const ParticleData& data) {
383  return data.belongs_to() == BelongsTo::Target;
384  });
385  bool none_collided =
386  std::all_of(plist.begin(), plist.end(), [&](const ParticleData& data) {
387  return data.get_history().collisions_per_particle == 0;
388  });
389  if ((all_projectile || all_target) && none_collided) {
390  return nullptr;
391  }
392  }
393  // No grid or search in cell
394  if (gcell_vol < really_small) {
395  return nullptr;
396  }
397 
398  /* Optimisation for later: Already check here at the beginning
399  * if collision with plist is possible before constructing actions. */
400 
401  // 1. Determine time of collision.
402  const double time_until_collision = dt * random::uniform(0., 1.);
403 
404  // 2. Create ScatterAction object.
405  ScatterActionMultiPtr act =
406  std::make_unique<ScatterActionMulti>(plist, time_until_collision);
407 
408  act->set_stochastic_pos_idx();
409 
410  // 3. Add possible final states (dt and gcell_vol for probability calculation)
411  act->add_possible_reactions(dt, gcell_vol, finder_parameters_.included_multi);
412 
413  /* 4. Return total collision probability
414  * Scales with 1 over the number of testpartciles to the power of the
415  * number of incoming particles - 1 */
416  const double prob =
417  act->get_total_weight() /
418  std::pow(finder_parameters_.testparticles, plist.size() - 1);
419 
420  // 5. Check that probability is smaller than one
421  if (prob > 1.) {
422  std::stringstream err;
423  err << "Probability " << prob << " larger than 1 for stochastic rates for ";
424  for (const ParticleData& data : plist) {
425  err << data.type().name();
426  }
427  err << " at sqrts[GeV] = " << act->sqrt_s()
428  << "\nConsider using smaller timesteps.";
430  logg[LFindScatter].warn(err.str());
431  } else {
432  throw std::runtime_error(err.str());
433  }
434  }
435 
436  // 6. Perform probability decisions
437  double random_no = random::uniform(0., 1.);
438  if (random_no > prob) {
439  return nullptr;
440  }
441 
442  return act;
443 }
bool all_of(Container &&c, UnaryPredicate &&p)
Convenience wrapper for std::all_of that operates on a complete container.
Definition: algorithms.h:80

Member Data Documentation

◆ finder_parameters_

ScatterActionsFinderParameters smash::ScatterActionsFinder::finder_parameters_
private

Struct collecting several parameters.

Definition at line 320 of file scatteractionsfinder.h.

◆ string_process_interface_

std::unique_ptr<StringProcess> smash::ScatterActionsFinder::string_process_interface_
private

Class that deals with strings, interfacing Pythia.

Definition at line 322 of file scatteractionsfinder.h.

◆ isotropic_

const bool smash::ScatterActionsFinder::isotropic_
private

Do all collisions isotropically.

Definition at line 324 of file scatteractionsfinder.h.

◆ box_length_

const double smash::ScatterActionsFinder::box_length_
private

Box length: needed to determine coordinates of collision correctly in case of collision through the wall.

Ignored if negative.

Definition at line 330 of file scatteractionsfinder.h.

◆ string_formation_time_

const double smash::ScatterActionsFinder::string_formation_time_
private

Parameter for formation time.

Definition at line 332 of file scatteractionsfinder.h.


The documentation for this class was generated from the following files: