Version: SMASH-3.4
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:
[legend]
Collaboration diagram for smash::ScatterActionsFinder:
[legend]

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 &) const override
 No scatterings should be found when the event is over. 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 31 of file scatteractionsfinder.cc.

33  : finder_parameters_(config, parameters),
35  box_length_(parameters.box_length),
39  logg[LFindScatter].info(
40  "Constant elastic isotropic cross-section mode:", " using ",
41  finder_parameters_.elastic_parameter, " mb as maximal cross-section.");
42  }
45  throw std::invalid_argument(
46  "Multi-body reactions (like e.g. 3->1 or 3->2) are only possible with "
47  "the stochastic collision criterion. Change your config accordingly.");
48  }
49 
52  1 &&
54  .included_2to2[IncludedReactions::PiDeuteron_to_pidprime] == 1 ||
56  .included_2to2[IncludedReactions::NDeuteron_to_Ndprime] == 1)) {
57  throw std::invalid_argument(
58  "To prevent double counting it is not possible to enable deuteron 3->2 "
59  "reactions\nand reactions involving the d' at the same time\ni.e. to "
60  "include \"Deuteron_3to2\" in `Multi_Particle_Reactions` and\n "
61  "\"PiDeuteron_to_pidprime\" "
62  "or \"NDeuteron_to_Ndprime\" in `Included_2to2` at the same time.\n"
63  "Change your config accordingly.");
64  }
65 
68  1 &&
70  throw std::invalid_argument(
71  "Do not use the d' resonance and enable \"Deuteron_3to2\" "
72  "`Multi_Particle_Reactions` at the same time. Either use the direct "
73  "3-to-2 reactions or the d' together with \"PiDeuteron_to_pidprime\" "
74  "and \"NDeuteron_to_Ndprime\" in `Included_2to2`. Otherwise the "
75  "deuteron 3-to-2 reactions would be double counted.");
76  }
77 
81  1) ||
84  1 &&
86  throw std::invalid_argument(
87  "In order to conserve detailed balance, when \"NNbar_5to2\" is "
88  "included in\n`Multi_Particle_Reactions`, the `NNbarTreatment` has to "
89  "be set to \"two to five\" and vice versa.");
90  }
91 
94  throw std::invalid_argument(
95  "'NNbar' has to be in the list of allowed 2 to 2 processes "
96  "to enable annihilation to go through resonances");
97  }
98 
100  string_process_interface_ = std::make_unique<StringProcess>(config);
101  }
102 }
static const ParticleTypePtr try_find(PdgCode pdgcode)
Returns the ParticleTypePtr for the given pdgcode.
Definition: particletype.cc:89
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.
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.h:245
constexpr int64_t dprime
Deuteron-prime resonance.
static constexpr int LFindScatter
static const Key< double > collTerm_stringParam_formationTime
See user guide description for more information.
Definition: input_keys.h:3453
static const Key< bool > collTerm_isotropic
See user guide description for more information.
Definition: input_keys.h:2786
Here is the call graph for this function:

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 [30] (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 [8] (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();
99  /**
100  * JAM collision times from the closest approach
101  * in the two-particle center-of-mass-framem,
102  * see \iref{Hirano:2012yy} (5.13) and (5.14).
103  * The scatteraction is performed at the mean of these two times.
104  */
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 {
122  /**
123  * UrQMD collision time in computational frame,
124  * see \iref{Bass:1998ca} (3.28):
125  * position of particle 1: \f$r_1\f$ [fm]
126  * position of particle 2: \f$r_2\f$ [fm]
127  * velocity of particle 1: \f$v_1\f$
128  * velocity of particle 1: \f$v_2\f$
129  * \f[t_{coll} = - (r_1 - r_2) . (v_1 - v_2) / (v_1 - v_2)^2\f] [fm]
130  */
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:91
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:41
Here is the call graph for this function:
Here is the caller graph for this function:

◆ 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 411 of file scatteractionsfinder.cc.

413  {
414  std::vector<ActionPtr> actions;
415  for (const ParticleData& p1 : search_list) {
416  for (const ParticleData& p2 : search_list) {
417  // Check for 2 particle scattering
418  if (p1.id() < p2.id()) {
419  ActionPtr act =
420  check_collision_two_part(p1, p2, dt, beam_momentum, gcell_vol);
421  if (act) {
422  actions.push_back(std::move(act));
423  }
424  }
426  // Also, check for 3 particle scatterings with stochastic criterion
427  for (const ParticleData& p3 : search_list) {
432  if (p1.id() < p2.id() && p2.id() < p3.id()) {
433  ActionPtr act =
434  check_collision_multi_part({p1, p2, p3}, dt, gcell_vol);
435  if (act) {
436  actions.push_back(std::move(act));
437  }
438  }
439  }
440  for (const ParticleData& p4 : search_list) {
443  if (p1.id() < p2.id() && p2.id() < p3.id() && p3.id() < p4.id()) {
444  ActionPtr act =
445  check_collision_multi_part({p1, p2, p3, p4}, dt, gcell_vol);
446  if (act) {
447  actions.push_back(std::move(act));
448  }
449  }
450  }
453  search_list.size() >= 5) {
454  for (const ParticleData& p5 : search_list) {
455  if ((p1.id() < p2.id() && p2.id() < p3.id() &&
456  p3.id() < p4.id() && p4.id() < p5.id()) &&
457  (p1.is_pion() && p2.is_pion() && p3.is_pion() &&
458  p4.is_pion() && p5.is_pion())) {
459  // at the moment only pure pion 5-body reactions
460  ActionPtr act = check_collision_multi_part(
461  {p1, p2, p3, p4, p5}, dt, gcell_vol);
462  if (act) {
463  actions.push_back(std::move(act));
464  }
465  }
466  }
467  }
468  }
469  }
470  }
471  }
472  }
473  return actions;
474 }
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
Here is the call graph for this function:

◆ 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 476 of file scatteractionsfinder.cc.

478  {
479  std::vector<ActionPtr> actions;
481  // Only search in cells
482  return actions;
483  }
484  for (const ParticleData& p1 : search_list) {
485  for (const ParticleData& p2 : neighbors_list) {
486  assert(p1.id() != p2.id());
487  // Check if a collision is possible.
488  ActionPtr act = check_collision_two_part(p1, p2, dt, beam_momentum);
489  if (act) {
490  actions.push_back(std::move(act));
491  }
492  }
493  }
494  return actions;
495 }
Here is the call graph for this function:

◆ 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 497 of file scatteractionsfinder.cc.

499  {
500  std::vector<ActionPtr> actions;
502  // Only search in cells
503  return actions;
504  }
505  for (const ParticleData& p2 : surrounding_list) {
506  /* don't look for collisions if the particle from the surrounding list is
507  * also in the search list */
508  auto result = std::find_if(
509  search_list.begin(), search_list.end(),
510  [&p2](const ParticleData& p) { return p.id() == p2.id(); });
511  if (result != search_list.end()) {
512  continue;
513  }
514  for (const ParticleData& p1 : search_list) {
515  // Check if a collision is possible.
516  ActionPtr act = check_collision_two_part(p1, p2, dt, beam_momentum);
517  if (act) {
518  actions.push_back(std::move(act));
519  }
520  }
521  }
522  return actions;
523 }
constexpr int p
Proton.
Here is the call graph for this function:

◆ find_final_actions()

ActionList smash::ScatterActionsFinder::find_final_actions ( const Particles ) const
inlineoverridevirtual

No scatterings should be found when the event is over.

Implements smash::ActionFinderInterface.

Definition at line 195 of file scatteractionsfinder.h.

195 { return {}; }

◆ 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 207 of file scatteractionsfinder.h.

207  {
208  return ParticleType::list_all().size() == 1 &&
211  }
static const ParticleTypeList & list_all()
Definition: particletype.cc:51
const bool two_to_one
Enables resonance production.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ 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 225 of file scatteractionsfinder.h.

225  {
229  testparticles * fm2_mb * M_1_PI;
230  }
constexpr double fm2_mb
mb <-> fm^2 conversion factor.
Definition: constants.h:32
Here is the call graph for this function:
Here is the caller graph for this function:

◆ 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 525 of file scatteractionsfinder.cc.

525  {
526  constexpr double time = 0.0;
527 
528  const size_t N_isotypes = IsoParticleType::list_all().size();
529  const size_t N_pairs = N_isotypes * (N_isotypes - 1) / 2;
530 
531  std::cout << N_isotypes << " iso-particle types." << std::endl;
532  std::cout << "They can make " << N_pairs << " pairs." << std::endl;
533  std::vector<double> momentum_scan_list = {0.1, 0.3, 0.5, 1.0,
534  2.0, 3.0, 5.0, 10.0};
535  for (const IsoParticleType& A_isotype : IsoParticleType::list_all()) {
536  for (const IsoParticleType& B_isotype : IsoParticleType::list_all()) {
537  if (&A_isotype > &B_isotype) {
538  continue;
539  }
540  bool any_nonzero_cs = false;
541  std::vector<std::string> r_list;
542  for (const ParticleTypePtr A_type : A_isotype.get_states()) {
543  for (const ParticleTypePtr B_type : B_isotype.get_states()) {
544  if (A_type > B_type) {
545  continue;
546  }
547  ParticleData A(*A_type), B(*B_type);
548  for (auto mom : momentum_scan_list) {
549  A.set_4momentum(A.pole_mass(), mom, 0.0, 0.0);
550  B.set_4momentum(B.pole_mass(), -mom, 0.0, 0.0);
551  ScatterActionPtr act = std::make_unique<ScatterAction>(
552  A, B, time, isotropic_, string_formation_time_, -1, false,
555  act->set_string_interface(string_process_interface_.get());
556  }
557  act->add_all_scatterings(finder_parameters_);
558  const double total_cs = act->cross_section();
559  if (total_cs <= 0.0) {
560  continue;
561  }
562  any_nonzero_cs = true;
563  for (const auto& channel : act->collision_channels()) {
564  const auto type = channel->get_type();
565  std::string r;
566  if (is_string_process(type)) {
567  r = A_type->name() + B_type->name() + std::string(" → strings");
568  } else {
569  std::string r_type =
570  (type == ProcessType::Elastic) ? std::string(" (el)")
571  : (channel->get_type() == ProcessType::TwoToTwo)
572  ? std::string(" (inel)")
573  : std::string(" (?)");
574  r = A_type->name() + B_type->name() + std::string(" → ") +
575  channel->particle_types()[0]->name() +
576  channel->particle_types()[1]->name() + r_type;
577  }
578  isoclean(r);
579  r_list.push_back(r);
580  }
581  }
582  }
583  }
584  std::sort(r_list.begin(), r_list.end());
585  r_list.erase(std::unique(r_list.begin(), r_list.end()), r_list.end());
586  if (any_nonzero_cs) {
587  for (auto r : r_list) {
588  std::cout << r;
589  if (r_list.back() != r) {
590  std::cout << ", ";
591  }
592  }
593  std::cout << std::endl;
594  }
595  }
596  }
597 }
static const IsoParticleTypeList & list_all()
Returns a list of all IsoParticleTypes.
const SpinInteractionType spin_interaction_type
Switch to control whether to include spin interactions.
@ TwoToTwo
See here for a short description.
@ Elastic
See here for a short description.
void isoclean(std::string &s)
Remove ⁺, ⁻, ⁰ from string.
bool is_string_process(ProcessType p)
Check if a given process type is a string excitation.
Here is the call graph for this function:

◆ 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 908 of file scatteractionsfinder.cc.

910  {
911  std::vector<double> sqrts_values;
912  std::map<std::string, std::vector<double>> xs_dump;
913  std::map<std::string, double> outgoing_total_mass;
914 
915  ParticleData a_data(a), b_data(b);
916  int n_momentum_points = 200;
917  constexpr double momentum_step = 0.02;
918  if (plab.size() > 0) {
919  // Remove duplicates.
920  std::sort(plab.begin(), plab.end());
921  plab.erase(std::unique(plab.begin(), plab.end()), plab.end());
922  // Reset size of momentum points to the number of unique values.
923  n_momentum_points = plab.size();
924  }
925  sqrts_values.reserve(n_momentum_points);
926  const auto store_cross_section_into_map = [&](const std::string& channel,
927  double xs, int i) {
928  /* Store one cross-section value per energy point. Missing channels remain
929  * zero, so all channel vectors have the same indexing as sqrts_values. */
930  auto& xs_values = xs_dump[channel];
931  if (xs_values.empty()) {
932  xs_values.resize(n_momentum_points, 0.0);
933  }
934  /* NOTE: We add the value to the existing one (usually 0.0) in order to
935  * correctly accumulate cross-sections in case multiple channels have the
936  * same name. */
937  xs_values[i] += xs;
938  };
939  for (int i = 0; i < n_momentum_points; i++) {
940  double momentum;
941  if (plab.size() > 0) {
942  momentum = pCM_from_s(s_from_plab(plab.at(i), m_a, m_b), m_a, m_b);
943  } else {
944  momentum = momentum_step * (i + 1);
945  }
946  a_data.set_4momentum(m_a, momentum, 0.0, 0.0);
947  b_data.set_4momentum(m_b, -momentum, 0.0, 0.0);
948  const double sqrts = (a_data.momentum() + b_data.momentum()).abs();
949  sqrts_values.push_back(sqrts);
950  ScatterActionPtr act = std::make_unique<ScatterAction>(
951  a_data, b_data, 0., isotropic_, string_formation_time_, -1, false,
954  act->set_string_interface(string_process_interface_.get());
955  }
956  act->add_all_scatterings(finder_parameters_);
957  decaytree::Node tree(a.name() + b.name(), act->cross_section(), {&a, &b},
958  {&a, &b}, {&a, &b}, {});
959  const CollisionBranchList& processes = act->collision_channels();
960  for (const auto& process : processes) {
961  const double xs = process->weight();
962  if (xs <= 0.0) {
963  continue;
964  }
965  std::stringstream process_description_stream;
966  process_description_stream << *process;
967  const std::string& description = process_description_stream.str();
968  if (!final_state) {
969  double m_tot = 0.0;
970  for (const auto& ptype : process->particle_types()) {
971  m_tot += ptype->mass();
972  }
973  outgoing_total_mass[description] = m_tot;
974  store_cross_section_into_map(description, xs, i);
975  } else {
976  ParticleTypePtrList initial_particles = {&a, &b};
977  ParticleTypePtrList final_particles = process->particle_types();
978  auto& process_node =
979  tree.add_action(description, xs, std::move(initial_particles),
980  std::move(final_particles));
981  decaytree::add_decays(process_node, sqrts);
982  }
983  }
984  store_cross_section_into_map("total", act->cross_section(), i);
985  // Total cross-section should be the first in the list -> negative mass
986  outgoing_total_mass["total"] = -1.0;
987  if (final_state) {
988  // tree.print();
989  auto final_state_xs = tree.final_state_cross_sections();
990  deduplicate(final_state_xs);
991  for (const auto& p : final_state_xs) {
992  // Don't print empty columns.
993  //
994  // FIXME(steinberg): The better fix would be to not have them in the
995  // first place.
996  if (p.name_ == "") {
997  continue;
998  }
999  outgoing_total_mass[p.name_] = p.mass_;
1000  store_cross_section_into_map(p.name_, p.cross_section_, i);
1001  }
1002  }
1003  }
1004  // Get rid of cross sections that are zero.
1005  // This only happens if there is a resonance in the final state that cannot
1006  // decay with our simplified assumptions.
1007  for (auto it = begin(xs_dump); it != end(xs_dump);) {
1008  // Sum cross section over all energies.
1009  const auto& xs = (*it).second;
1010  const double sum = std::accumulate(xs.begin(), xs.end(), 0.0);
1011  if (sum == 0.) {
1012  it = xs_dump.erase(it);
1013  } else {
1014  ++it;
1015  }
1016  }
1017 
1018  // Nice ordering of channels by summed pole mass of products
1019  std::vector<std::string> all_channels;
1020  for (const auto& channel : xs_dump) {
1021  all_channels.push_back(channel.first);
1022  }
1023  std::sort(all_channels.begin(), all_channels.end(),
1024  [&](const std::string& str_a, const std::string& str_b) {
1025  return outgoing_total_mass[str_a] < outgoing_total_mass[str_b];
1026  });
1027 
1028  // Print header
1029  std::cout << "# Dumping partial " << a.name() << b.name()
1030  << " cross-sections in mb, energies in GeV" << std::endl;
1031  std::cout << " sqrt_s";
1032  // Align everything to 24 unicode characters.
1033  // This should be enough for the longest channel name: 7 final-state
1034  // particles, or 2 of the longest named resonances (currently Ds0*(2317)⁺).
1035  for (const auto& channel : all_channels) {
1036  std::cout << utf8::fill_left(channel, 24, ' ');
1037  }
1038  std::cout << std::endl;
1039 
1040  // Print out all partial cross-sections in mb
1041  for (int i = 0; i < n_momentum_points; i++) {
1042  std::printf("%9.6f", sqrts_values[i]);
1043  for (const auto& channel : all_channels) {
1044  std::printf("%24.6f", xs_dump.at(channel)[i]);
1045  }
1046  std::printf("\n");
1047  }
1048 }
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:280
Here is the call graph for this function:

◆ 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 259 of file scatteractionsfinder.h.

259  {
261  return string_process_interface_.get();
262  } else {
263  return NULL;
264  }
265  }

◆ 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 [8] (3.27). 2. A stochastic collision criterion as introduced in Staudenmaier:2021lrg [66].

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 176 of file scatteractionsfinder.cc.

179  {
180  /* If the two particles
181  * 1) belong to one of the two colliding nuclei, and
182  * 2) both of them have never experienced any collisions,
183  * then the collisions between them are banned. */
185  assert(data_a.id() >= 0);
186  assert(data_b.id() >= 0);
187  bool in_same_nucleus = (data_a.belongs_to() == BelongsTo::Projectile &&
188  data_b.belongs_to() == BelongsTo::Projectile) ||
189  (data_a.belongs_to() == BelongsTo::Target &&
190  data_b.belongs_to() == BelongsTo::Target);
191  bool never_interacted_before =
192  data_a.get_history().collisions_per_particle == 0 &&
193  data_b.get_history().collisions_per_particle == 0;
194  if (in_same_nucleus && never_interacted_before) {
195  return nullptr;
196  }
197  }
198 
199  // No grid or search in cell means no collision for stochastic criterion
201  gcell_vol < really_small) {
202  return nullptr;
203  }
204 
205  // Determine time of collision.
206  const double time_until_collision =
207  collision_time(data_a, data_b, dt, beam_momentum);
208 
209  // Check that collision happens in this timestep.
210  if (time_until_collision < 0. || time_until_collision >= dt) {
211  return nullptr;
212  }
213 
214  // Determine which total cross section to use
215  bool incoming_parametrized = (finder_parameters_.total_xs_strategy ==
219  const PdgCode& pdg_a = data_a.type().pdgcode();
220  const PdgCode& pdg_b = data_b.type().pdgcode();
221  incoming_parametrized = parametrization_exists(pdg_a, pdg_b);
222  }
223 
224  // Create ScatterAction object.
225  ScatterActionPtr act = std::make_unique<ScatterAction>(
226  data_a, data_b, time_until_collision, isotropic_, string_formation_time_,
227  box_length_, incoming_parametrized,
229 
231  act->set_stochastic_pos_idx();
232  }
233 
235  act->set_string_interface(string_process_interface_.get());
236  }
237 
238  // Distance squared calculation not needed for stochastic criterion
239  const double distance_squared =
241  ? act->transverse_distance_sqr()
243  ? act->cov_transverse_distance_sqr()
244  : 0.0;
245 
246  // Don't calculate cross section if the particles are very far apart.
247  // Not needed for stochastic criterion because of cell structure.
249  distance_squared >=
251  return nullptr;
252  }
253 
254  if (incoming_parametrized) {
255  act->set_parametrized_total_cross_section(finder_parameters_);
256  } else {
257  // Add various subprocesses.
258  act->add_all_scatterings(finder_parameters_);
259  }
260 
261  double xs = act->cross_section() * fm2_mb /
262  static_cast<double>(finder_parameters_.testparticles);
263 
264  // Take cross section scaling factors into account
265  xs *= data_a.xsec_scaling_factor(time_until_collision);
266  xs *= data_b.xsec_scaling_factor(time_until_collision);
267 
269  const double v_rel = act->relative_velocity();
270  /* Collision probability for 2-particle scattering, see
271  * \iref{Staudenmaier:2021lrg}. */
272  const double prob = xs * v_rel * dt / gcell_vol;
273 
274  logg[LFindScatter].debug(
275  "Stochastic collison criterion parameters (2-particles):\nprob = ",
276  prob, ", xs = ", xs, ", v_rel = ", v_rel, ", dt = ", dt,
277  ", gcell_vol = ", gcell_vol,
278  ", testparticles = ", finder_parameters_.testparticles);
279 
280  if (prob > 1.) {
281  std::stringstream err;
282  err << "Probability larger than 1 for stochastic rates. ( P_22 = " << prob
283  << " )\n"
284  << data_a.type().name() << data_b.type().name() << " with masses "
285  << data_a.momentum().abs() << " and " << data_b.momentum().abs()
286  << " at sqrts[GeV] = " << act->sqrt_s()
287  << " with xs[fm^2]/Ntest = " << xs
288  << "\nConsider using smaller timesteps.";
290  logg[LFindScatter].warn(err.str());
291  } else {
292  throw std::runtime_error(err.str());
293  }
294  }
295 
296  // probability criterion
297  double random_no = random::uniform(0., 1.);
298  if (random_no > prob) {
299  return nullptr;
300  }
301 
304  // just collided with this particle
305  if (data_a.id_process() > 0 && data_a.id_process() == data_b.id_process()) {
306  logg[LFindScatter].debug("Skipping collided particles at time ",
307  data_a.position().x0(), " due to process ",
308  data_a.id_process(), "\n ", data_a, "\n<-> ",
309  data_b);
310 
311  return nullptr;
312  }
313 
314  // Cross section for collision criterion
315  const double cross_section_criterion = xs * M_1_PI;
316 
317  // distance criterion according to cross_section
318  if (distance_squared >= cross_section_criterion) {
319  return nullptr;
320  }
321 
322  logg[LFindScatter].debug("particle distance squared: ", distance_squared,
323  "\n ", data_a, "\n<-> ", data_b);
324  }
325 
326  // Include possible outgoing branches
327  if (incoming_parametrized) {
328  act->add_all_scatterings(finder_parameters_);
329  }
330 
331  return act;
332 }
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.
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.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ 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 [66]. 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 334 of file scatteractionsfinder.cc.

335  {
336  /* If all particles
337  * 1) belong to the two colliding nuclei
338  * 2) are within the same nucleus
339  * 3) have never experienced any collisons,
340  * then the collision between them are banned also for multi-particle
341  * interactions. */
343  bool all_projectile =
344  std::all_of(plist.begin(), plist.end(), [&](const ParticleData& data) {
345  return data.belongs_to() == BelongsTo::Projectile;
346  });
347  bool all_target =
348  std::all_of(plist.begin(), plist.end(), [&](const ParticleData& data) {
349  return data.belongs_to() == BelongsTo::Target;
350  });
351  bool none_collided =
352  std::all_of(plist.begin(), plist.end(), [&](const ParticleData& data) {
353  return data.get_history().collisions_per_particle == 0;
354  });
355  if ((all_projectile || all_target) && none_collided) {
356  return nullptr;
357  }
358  }
359  // No grid or search in cell
360  if (gcell_vol < really_small) {
361  return nullptr;
362  }
363 
364  /* Optimisation for later: Already check here at the beginning
365  * if collision with plist is possible before constructing actions. */
366 
367  // 1. Determine time of collision.
368  const double time_until_collision = dt * random::uniform(0., 1.);
369 
370  // 2. Create ScatterAction object.
371  ScatterActionMultiPtr act =
372  std::make_unique<ScatterActionMulti>(plist, time_until_collision);
373 
374  act->set_stochastic_pos_idx();
375 
376  // 3. Add possible final states (dt and gcell_vol for probability calculation)
377  act->add_possible_reactions(dt, gcell_vol, finder_parameters_.included_multi);
378 
379  /* 4. Return total collision probability
380  * Scales with 1 over the number of testpartciles to the power of the
381  * number of incoming particles - 1 */
382  const double prob =
383  act->get_total_weight() /
384  std::pow(finder_parameters_.testparticles, plist.size() - 1);
385 
386  // 5. Check that probability is smaller than one
387  if (prob > 1.) {
388  std::stringstream err;
389  err << "Probability " << prob << " larger than 1 for stochastic rates for ";
390  for (const ParticleData& data : plist) {
391  err << data.type().name();
392  }
393  err << " at sqrts[GeV] = " << act->sqrt_s()
394  << "\nConsider using smaller timesteps.";
396  logg[LFindScatter].warn(err.str());
397  } else {
398  throw std::runtime_error(err.str());
399  }
400  }
401 
402  // 6. Perform probability decisions
403  double random_no = random::uniform(0., 1.);
404  if (random_no > prob) {
405  return nullptr;
406  }
407 
408  return act;
409 }
bool all_of(Container &&c, UnaryPredicate &&p)
Convenience wrapper for std::all_of that operates on a complete container.
Definition: algorithms.h:80
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ finder_parameters_

ScatterActionsFinderParameters smash::ScatterActionsFinder::finder_parameters_
private

Struct collecting several parameters.

Definition at line 314 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 316 of file scatteractionsfinder.h.

◆ isotropic_

const bool smash::ScatterActionsFinder::isotropic_
private

Do all collisions isotropically.

Definition at line 318 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 324 of file scatteractionsfinder.h.

◆ string_formation_time_

const double smash::ScatterActionsFinder::string_formation_time_
private

Parameter for formation time.

Definition at line 326 of file scatteractionsfinder.h.


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