33 : finder_parameters_(config, parameters),
34 isotropic_(config.take(
InputKeys::collTerm_isotropic)),
35 box_length_(parameters.box_length),
36 string_formation_time_(
37 config.read(
InputKeys::collTerm_stringParam_formationTime)) {
40 "Constant elastic isotropic cross-section mode:",
" using ",
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.");
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.");
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.");
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.");
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");
116 : elastic_parameter(config.take(
InputKeys::collTerm_elasticCrossSection)),
117 low_snn_cut(parameters.low_snn_cut),
118 scale_xs(parameters.scale_xs),
120 config.take(
InputKeys::collTerm_additionalElasticCrossSection)),
121 maximum_cross_section(parameters.maximum_cross_section),
122 coll_crit(parameters.coll_crit),
123 nnbar_treatment(parameters.nnbar_treatment),
124 included_2to2(parameters.included_2to2),
125 charm_rescattering(parameters.charm_rescattering),
126 included_multi(parameters.included_multi),
127 testparticles(parameters.testparticles),
128 two_to_one(parameters.two_to_one),
129 allow_collisions_within_nucleus(
130 config.take(
InputKeys::modi_collider_collisionWithinNucleus)),
131 spin_interaction_type(parameters.spin_interaction_type),
132 strings_switch(parameters.strings_switch),
133 use_AQM(config.take(
InputKeys::collTerm_useAQM)),
134 strings_with_probability(
135 config.take(
InputKeys::collTerm_stringsWithProbability)),
136 only_warn_for_high_prob(
137 config.take(
InputKeys::collTerm_onlyWarnForHighProbability)),
139 total_xs_strategy(config.take(
InputKeys::collTerm_totXsStrategy)),
140 pseudoresonance_method(config.take(
InputKeys::collTerm_pseudoresonance)),
141 hard_string_transition_mode(
142 config.take(
InputKeys::collTerm_hardStringTransition_mode)),
143 hard_string_transition_energy_range(
144 config.take(
InputKeys::collTerm_hardStringTransition_energyRange)),
145 AQM_charm_suppression(
146 config.take(
InputKeys::collTerm_HF_AQMcSuppression)),
147 AQM_bottom_suppression(
148 config.take(
InputKeys::collTerm_HF_AQMbSuppression)) {
151 "Evaluating total cross sections from partial processes.");
154 throw std::invalid_argument(
155 "The BottomUp strategy for total cross section evaluation is needed to "
156 "have only elastic interactions, please change the configuration "
160 "Evaluating total cross sections from parametrizations.");
163 "Evaluating total cross sections from parametrizations only for "
164 "measured processes.");
169 "It is not possible to completely disable AQM when "
170 "Total_Cross_Section_Strategy is set to \"TopDown\" or "
171 "\"TopDownMeasured\".\n"
172 "AQM will be used for total parametrizations of cross sections.");
178 const std::vector<FourVector>& beam_momentum,
179 const double gcell_vol)
const {
185 assert(data_a.
id() >= 0);
186 assert(data_b.
id() >= 0);
191 bool never_interacted_before =
194 if (in_same_nucleus && never_interacted_before) {
206 const double time_until_collision =
210 if (time_until_collision < 0. || time_until_collision >= dt) {
225 ScatterActionPtr act = std::make_unique<ScatterAction>(
231 act->set_stochastic_pos_idx();
239 const double distance_squared =
241 ? act->transverse_distance_sqr()
243 ? act->cov_transverse_distance_sqr()
254 if (incoming_parametrized) {
261 double xs = act->cross_section() *
fm2_mb /
269 const double v_rel = act->relative_velocity();
272 const double prob = xs * v_rel * dt / gcell_vol;
275 "Stochastic collison criterion parameters (2-particles):\nprob = ",
276 prob,
", xs = ", xs,
", v_rel = ", v_rel,
", dt = ", dt,
277 ", gcell_vol = ", gcell_vol,
281 std::stringstream err;
282 err <<
"Probability larger than 1 for stochastic rates. ( P_22 = " << prob
286 <<
" at sqrts[GeV] = " << act->sqrt_s()
287 <<
" with xs[fm^2]/Ntest = " << xs
288 <<
"\nConsider using smaller timesteps.";
292 throw std::runtime_error(err.str());
298 if (random_no > prob) {
315 const double cross_section_criterion = xs * M_1_PI;
318 if (distance_squared >= cross_section_criterion) {
323 "\n ", data_a,
"\n<-> ", data_b);
327 if (incoming_parametrized) {
335 const ParticleList& plist,
double dt,
const double gcell_vol)
const {
343 bool all_projectile =
345 return data.belongs_to() == BelongsTo::Projectile;
349 return data.belongs_to() == BelongsTo::Target;
353 return data.get_history().collisions_per_particle == 0;
355 if ((all_projectile || all_target) && none_collided) {
371 ScatterActionMultiPtr act =
372 std::make_unique<ScatterActionMulti>(plist, time_until_collision);
374 act->set_stochastic_pos_idx();
383 act->get_total_weight() /
388 std::stringstream err;
389 err <<
"Probability " << prob <<
" larger than 1 for stochastic rates for ";
391 err << data.type().name();
393 err <<
" at sqrts[GeV] = " << act->sqrt_s()
394 <<
"\nConsider using smaller timesteps.";
398 throw std::runtime_error(err.str());
404 if (random_no > prob) {
412 const ParticleList& search_list,
double dt,
const double gcell_vol,
413 const std::vector<FourVector>& beam_momentum)
const {
414 std::vector<ActionPtr> actions;
418 if (p1.id() < p2.id()) {
422 actions.push_back(std::move(act));
432 if (p1.id() < p2.id() && p2.id() < p3.id()) {
436 actions.push_back(std::move(act));
443 if (p1.id() < p2.id() && p2.id() < p3.id() && p3.id() < p4.id()) {
447 actions.push_back(std::move(act));
453 search_list.size() >= 5) {
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())) {
461 {p1, p2, p3, p4, p5}, dt, gcell_vol);
463 actions.push_back(std::move(act));
477 const ParticleList& search_list,
const ParticleList& neighbors_list,
478 double dt,
const std::vector<FourVector>& beam_momentum)
const {
479 std::vector<ActionPtr> actions;
486 assert(p1.id() != p2.id());
490 actions.push_back(std::move(act));
498 const ParticleList& search_list,
const Particles& surrounding_list,
499 double dt,
const std::vector<FourVector>& beam_momentum)
const {
500 std::vector<ActionPtr> actions;
508 auto result = std::find_if(
509 search_list.begin(), search_list.end(),
511 if (result != search_list.end()) {
518 actions.push_back(std::move(act));
526 constexpr
double time = 0.0;
529 const size_t N_pairs = N_isotypes * (N_isotypes - 1) / 2;
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};
537 if (&A_isotype > &B_isotype) {
540 bool any_nonzero_cs =
false;
541 std::vector<std::string> r_list;
544 if (A_type > B_type) {
548 for (
auto mom : momentum_scan_list) {
549 A.set_4momentum(A.pole_mass(), mom, 0.0, 0.0);
551 ScatterActionPtr act = std::make_unique<ScatterAction>(
558 const double total_cs = act->cross_section();
559 if (total_cs <= 0.0) {
562 any_nonzero_cs =
true;
563 for (
const auto& channel : act->collision_channels()) {
564 const auto type = channel->get_type();
567 r = A_type->name() + B_type->name() + std::string(
" → strings");
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;
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) {
589 if (r_list.back() != r) {
593 std::cout << std::endl;
623 namespace decaytree {
671 Node(
const std::string& name,
double weight,
672 ParticleTypePtrList&& initial_particles,
673 ParticleTypePtrList&& final_particles, ParticleTypePtrList&& state,
674 std::vector<Node>&& children)
694 ParticleTypePtrList&& initial_particles,
695 ParticleTypePtrList&& final_particles) {
697 ParticleTypePtrList state(
state_);
698 for (
const auto&
p : initial_particles) {
699 state.erase(std::find(state.begin(), state.end(),
p));
701 for (
const auto&
p : final_particles) {
705 std::sort(state.begin(), state.end(),
707 return a->name() < b->name();
710 Node new_node(name, weight, std::move(initial_particles),
711 std::move(final_particles), std::move(state), {});
712 children_.emplace_back(std::move(new_node));
723 std::vector<FinalStateCrossSection> result;
736 for (uint64_t i = 0; i < depth; i++) {
741 child.print_helper(depth + 1);
757 uint64_t depth, std::vector<FinalStateCrossSection>& result,
758 const std::string& name,
double weight,
759 bool show_intermediate_states =
false)
const {
767 std::string new_name;
770 if (show_intermediate_states) {
772 if (!new_name.empty()) {
780 for (
const auto& s :
state_) {
781 new_name += s->name();
784 if (show_intermediate_states) {
793 child.final_state_cross_sections_helper(depth + 1, result, new_name,
794 weight, show_intermediate_states);
808 const DecayBranchPtr& decay,
809 ParticleTypePtrList& final_state) {
810 std::stringstream name;
811 name <<
"[" << res_name <<
"->";
812 for (
const auto&
p : decay->particle_types()) {
814 final_state.push_back(
p);
838 uint32_t n_unstable = 0;
839 double sqrts_minus_masses = sqrts;
844 sqrts_minus_masses -= ptype->
mass();
847 n_unstable != 0 ? 1. /
static_cast<double>(n_unstable) : 1.;
851 const double sqrts_decay = sqrts_minus_masses + ptype->
mass();
852 bool can_decay =
false;
857 double final_state_mass = 0.;
858 for (
const auto&
p : decay->particle_types()) {
859 final_state_mass +=
p->mass();
861 if (final_state_mass > sqrts_decay) {
866 ParticleTypePtrList parts;
868 auto& new_node = node.
add_action(name, norm * decay->weight(), {ptype},
889 static void deduplicate(std::vector<FinalStateCrossSection>& final_state_xs) {
890 std::sort(final_state_xs.begin(), final_state_xs.end(),
893 auto current = final_state_xs.begin();
894 while (current != final_state_xs.end()) {
895 auto adjacent = std::adjacent_find(
896 current, final_state_xs.end(),
898 return a.name_ == b.name_;
901 if (adjacent != final_state_xs.end()) {
902 adjacent->cross_section_ += (adjacent + 1)->cross_section_;
903 final_state_xs.erase(adjacent + 1);
910 bool final_state, std::vector<double>& plab)
const {
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;
916 int n_momentum_points = 200;
917 constexpr
double momentum_step = 0.02;
918 if (plab.size() > 0) {
920 std::sort(plab.begin(), plab.end());
921 plab.erase(std::unique(plab.begin(), plab.end()), plab.end());
923 n_momentum_points = plab.size();
925 sqrts_values.reserve(n_momentum_points);
926 const auto store_cross_section_into_map = [&](
const std::string& channel,
930 auto& xs_values = xs_dump[channel];
931 if (xs_values.empty()) {
932 xs_values.resize(n_momentum_points, 0.0);
939 for (
int i = 0; i < n_momentum_points; i++) {
941 if (plab.size() > 0) {
944 momentum = momentum_step * (i + 1);
946 a_data.set_4momentum(m_a, 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>(
958 {&a, &b}, {&a, &b}, {});
959 const CollisionBranchList& processes = act->collision_channels();
960 for (
const auto& process : processes) {
961 const double xs = process->weight();
965 std::stringstream process_description_stream;
966 process_description_stream << *process;
967 const std::string& description = process_description_stream.str();
970 for (
const auto& ptype : process->particle_types()) {
971 m_tot += ptype->mass();
973 outgoing_total_mass[description] = m_tot;
974 store_cross_section_into_map(description, xs, i);
976 ParticleTypePtrList initial_particles = {&a, &b};
977 ParticleTypePtrList final_particles = process->particle_types();
979 tree.
add_action(description, xs, std::move(initial_particles),
980 std::move(final_particles));
984 store_cross_section_into_map(
"total", act->cross_section(), i);
986 outgoing_total_mass[
"total"] = -1.0;
991 for (
const auto&
p : final_state_xs) {
999 outgoing_total_mass[
p.name_] =
p.mass_;
1000 store_cross_section_into_map(
p.name_,
p.cross_section_, i);
1007 for (
auto it = begin(xs_dump); it != end(xs_dump);) {
1009 const auto& xs = (*it).second;
1010 const double sum = std::accumulate(xs.begin(), xs.end(), 0.0);
1012 it = xs_dump.erase(it);
1019 std::vector<std::string> all_channels;
1020 for (
const auto& channel : xs_dump) {
1021 all_channels.push_back(channel.first);
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];
1029 std::cout <<
"# Dumping partial " << a.
name() << b.
name()
1030 <<
" cross-sections in mb, energies in GeV" << std::endl;
1031 std::cout <<
" sqrt_s";
1035 for (
const auto& channel : all_channels) {
1038 std::cout << std::endl;
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]);
Interface to the SMASH configuration files.
T take(const Key< T > &key)
The default interface for SMASH to read configuration values.
const DecayBranchList & decay_mode_list() const
double abs() const
calculate the lorentz invariant absolute value
IsoParticleType is a class to represent isospin multiplets.
static const IsoParticleTypeList & list_all()
Returns a list of all IsoParticleTypes.
ParticleData contains the dynamic information of a certain particle.
void set_4momentum(const FourVector &momentum_vector)
Set the particle's 4-momentum directly.
const ParticleType & type() const
Get the type of the particle.
double xsec_scaling_factor(double delta_time=0.) const
Return the cross section scaling factor at a given time.
uint32_t id_process() const
Get the id of the last action.
const FourVector & momentum() const
Get the particle's 4-momentum.
BelongsTo belongs_to() const
Getter for belongs_to label.
int32_t id() const
Get the id of the particle.
HistoryData get_history() const
Get history information.
double pole_mass() const
Get the particle's pole mass ("on-shell").
const FourVector & position() const
Get the particle's position in Minkowski space.
A pointer-like interface to global references to ParticleType objects.
Particle type contains the static properties of a particle species.
const DecayModes & decay_modes() const
static const ParticleTypePtr try_find(PdgCode pdgcode)
Returns the ParticleTypePtr for the given pdgcode.
const std::string & name() const
The Particles class abstracts the storage and manipulation of particles.
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
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.
ScatterActionsFinderParameters(Configuration &config, const ExperimentParameters ¶meters)
Class constructor.
const ReactionsBitSet included_2to2
List of included 2<->2 reactions.
const bool use_AQM
Switch to control whether to use AQM or not.
const double elastic_parameter
Elastic cross section parameter (in mb).
const bool strings_switch
Indicates whether string fragmentation is switched on.
const TotalCrossSectionStrategy total_xs_strategy
Method used to evaluate total cross sections for collision finding.
const MultiParticleReactionsBitSet included_multi
List of included multi-particle reactions.
const bool allow_collisions_within_nucleus
If particles within the same nucleus are allowed to collide for their first time.
const NNbarTreatment nnbar_treatment
Switch for NNbar reactions.
const CollisionCriterion coll_crit
Specifies which collision criterion is used.
const SpinInteractionType spin_interaction_type
Switch to control whether to include spin interactions.
ScatterActionsFinder(Configuration &config, const ExperimentParameters ¶meters)
Constructor of the finder with the given parameters.
ScatterActionsFinderParameters finder_parameters_
Struct collecting several parameters.
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.
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...
const bool isotropic_
Do all collisions isotropically.
double max_transverse_distance_sqr(int testparticles) const
The maximal distance over which particles can interact in case of the geometric criterion,...
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...
const double string_formation_time_
Parameter for formation time.
std::unique_ptr< StringProcess > string_process_interface_
Class that deals with strings, interfacing Pythia.
void dump_reactions() const
Prints out all the 2-> n (n > 1) reactions with non-zero cross-sections between all possible pairs of...
bool is_constant_elastic_isotropic() const
If there is only one particle sort, no decays (only elastic scatterings are possible),...
ActionPtr check_collision_multi_part(const ParticleList &plist, double dt, const double gcell_vol) const
Check for multiple i.e.
const double box_length_
Box length: needed to determine coordinates of collision correctly in case of collision through the w...
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.
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.
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.
Collection of useful constants that are known at compile time.
@ TwoToFive
Directly create 5 pions, use with multi-particle reactions.
@ Resonances
Use intermediate Resonances.
@ 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.
@ BottomUp
Sum the existing partial contributions.
@ Stochastic
Stochastic Criteiron.
@ Geometric
Geometric criterion.
@ Covariant
Covariant Criterion.
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > & logg
An array that stores all pre-configured Logger objects.
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.
static void add_decays(Node &node, double sqrts)
Add nodes for all decays possible from the given node and all of its children.
constexpr int64_t dprime
Deuteron-prime resonance.
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.
bool parametrization_exists(const PdgCode &pdg_a, const PdgCode &pdg_b)
Checks if supplied codes have existing parametrizations of total cross sections.
static void deduplicate(std::vector< FinalStateCrossSection > &final_state_xs)
Deduplicate the final-state cross sections by summing.
@ TwoToTwo
See here for a short description.
@ Elastic
See here for a short description.
bool all_of(Container &&c, UnaryPredicate &&p)
Convenience wrapper for std::all_of that operates on a complete container.
static StringTransitionParameters create_string_transition_parameters(Configuration &config)
T pCM_from_s(const T s, const T mass_a, const T mass_b) noexcept
constexpr double really_small
Numerical error tolerance.
void isoclean(std::string &s)
Remove ⁺, ⁻, ⁰ from string.
static constexpr int LFindScatter
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...
bool is_string_process(ProcessType p)
Check if a given process type is a string excitation.
constexpr double fm2_mb
mb <-> fm^2 conversion factor.
Helper structure for Experiment.
const ReactionsBitSet included_2to2
This indicates which two to two reactions are switched off.
Represent a final-state cross section.
FinalStateCrossSection(const std::string &name, double cross_section, double mass)
Construct a final-state cross section.
std::string name_
Name of the final state.
double cross_section_
Corresponding cross section in mb.
double mass_
Total mass of final state particles.
int32_t collisions_per_particle
Collision counter per particle, zero only for initially present particles.
Constants related to transition between low and high collision energies.
Node of a decay tree, representing a possible action (2-to-2 or 1-to-2).
std::vector< Node > children_
Possible actions after this action.
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...
ParticleTypePtrList final_particles_
Final-state particle types in this action.
std::vector< FinalStateCrossSection > final_state_cross_sections() const
Node & add_action(const std::string &name, double weight, ParticleTypePtrList &&initial_particles, ParticleTypePtrList &&final_particles)
Add an action to the children of this node.
ParticleTypePtrList initial_particles_
Initial-state particle types in this action.
void print() const
Print the decay tree starting with this node.
void print_helper(uint64_t depth) const
Internal helper function for print, to be called recursively to print all nodes.
double weight_
Weight (cross section or branching ratio).
Node(const Node &)=delete
Cannot be copied.
Node(const std::string &name, double weight, ParticleTypePtrList &&initial_particles, ParticleTypePtrList &&final_particles, ParticleTypePtrList &&state, std::vector< Node > &&children)
Node(Node &&)=default
Move constructor.
ParticleTypePtrList state_
Particle types corresponding to the global state after this action.
std::string name_
Name for printing.