310 : coll_crit_(parameters.coll_crit),
312 config.take({
"Collision_Term",
"Elastic_Cross_Section"}, -1.)),
313 testparticles_(parameters.testparticles),
314 isotropic_(config.take({
"Collision_Term",
"Isotropic"},
false)),
315 two_to_one_(parameters.two_to_one),
316 incl_set_(parameters.included_2to2),
317 incl_multi_set_(parameters.included_multi),
318 scale_xs_(parameters.scale_xs),
319 additional_el_xs_(parameters.additional_el_xs),
320 low_snn_cut_(parameters.low_snn_cut),
321 strings_switch_(parameters.strings_switch),
322 use_AQM_(parameters.use_AQM),
323 strings_with_probability_(parameters.strings_with_probability),
324 nnbar_treatment_(parameters.nnbar_treatment),
325 box_length_(parameters.box_length),
326 string_formation_time_(config.take(
327 {
"Collision_Term",
"String_Parameters",
"Formation_Time"}, 1.)),
328 maximum_cross_section_(parameters.maximum_cross_section),
329 allow_first_collisions_within_nucleus_(
330 parameters.allow_collisions_within_nucleus),
331 only_warn_for_high_prob_(config.take(
332 {
"Collision_Term",
"Only_Warn_For_High_Probability"},
false)) {
333 if (is_constant_elastic_isotropic()) {
335 "Constant elastic isotropic cross-section mode:",
" using ",
336 elastic_parameter_,
" mb as maximal cross-section.");
339 throw std::invalid_argument(
340 "Multi-body reactions (like e.g. 3->1 or 3->2) are only possible with "
343 "criterion. Change your config accordingly.");
349 throw std::invalid_argument(
350 "To prevent double counting it is not possible to enable deuteron 3->2 "
351 "reactions\nand reactions involving the d' at the same time\ni.e. to "
352 "include \"Deuteron_3to2\" in `Multi_Particle_Reactions` and\n "
353 "\"PiDeuteron_to_pidprime\" "
354 "or \"NDeuteron_to_Ndprime\" in `Included_2to2` at the same time.\n"
355 "Change your config accordingly.");
360 throw std::invalid_argument(
361 "Do not use the d' resonance and enable \"Deuteron_3to2\" "
362 "`Multi_Particle_Reactions` at the same time. Either use the direct "
363 "3-to-2 reactions or the d' together with \"PiDeuteron_to_pidprime\" "
364 "and \"NDeuteron_to_Ndprime\" in `Included_2to2`. Otherwise the "
365 "deuteron 3-to-2 reactions would be double counted.");
372 throw std::invalid_argument(
373 "In order to conserve detailed balance, when \"NNbar_5to2\" is "
374 "included in\n`Multi_Particle_Reactions`, the `NNbarTreatment` has to "
375 "be set to \"two to five\" and vice versa.");
380 throw std::invalid_argument(
381 "'NNbar' has to be in the list of allowed 2 to 2 processes "
382 "to enable annihilation to go through resonances");
385 if (strings_switch_) {
386 auto subconfig = config[
"Collision_Term"][
"String_Parameters"];
387 string_process_interface_ = make_unique<StringProcess>(
388 subconfig.take({
"String_Tension"}, 1.0), string_formation_time_,
389 subconfig.take({
"Gluon_Beta"}, 0.5),
390 subconfig.take({
"Gluon_Pmin"}, 0.001),
391 subconfig.take({
"Quark_Alpha"}, 2.0),
392 subconfig.take({
"Quark_Beta"}, 7.0),
393 subconfig.take({
"Strange_Supp"}, 0.16),
394 subconfig.take({
"Diquark_Supp"}, 0.036),
395 subconfig.take({
"Sigma_Perp"}, 0.42),
396 subconfig.take({
"StringZ_A_Leading"}, 0.2),
397 subconfig.take({
"StringZ_B_Leading"}, 2.0),
398 subconfig.take({
"StringZ_A"}, 2.0), subconfig.take({
"StringZ_B"}, 0.55),
399 subconfig.take({
"String_Sigma_T"}, 0.5),
400 subconfig.take({
"Form_Time_Factor"}, 1.0),
401 subconfig.take({
"Mass_Dependent_Formation_Times"},
false),
402 subconfig.take({
"Prob_proton_to_d_uu"}, 1. / 3.),
403 subconfig.take({
"Separate_Fragment_Baryon"},
true),
404 subconfig.take({
"Popcorn_Rate"}, 0.15));
410 const std::vector<FourVector>& beam_momentum,
411 const double gcell_vol)
const {
417 assert(data_a.
id() >= 0);
418 assert(data_b.
id() >= 0);
423 bool never_interacted_before =
426 if (in_same_nucleus && never_interacted_before) {
438 const double time_until_collision =
442 if (time_until_collision < 0. || time_until_collision >= dt) {
447 ScatterActionPtr act = make_unique<ScatterAction>(
452 act->set_stochastic_pos_idx();
460 const double distance_squared =
462 ? act->transverse_distance_sqr()
464 ? act->cov_transverse_distance_sqr()
488 const double v_rel = act->relative_velocity();
491 const double prob = xs * v_rel * dt / gcell_vol;
494 "Stochastic collison criterion parameters (2-particles):\nprob = ",
495 prob,
", xs = ", xs,
", v_rel = ", v_rel,
", dt = ", dt,
496 ", gcell_vol = ", gcell_vol,
", testparticles = ",
testparticles_);
499 std::stringstream err;
500 err <<
"Probability larger than 1 for stochastic rates. ( P_22 = " << prob
501 <<
" )\nConsider using smaller timesteps.";
505 throw std::runtime_error(err.str());
511 if (random_no > prob) {
528 const double cross_section_criterion = xs * M_1_PI;
531 if (distance_squared >= cross_section_criterion) {
536 "\n ", data_a,
"\n<-> ", data_b);
541 return std::move(act);
545 const ParticleList& plist,
double dt,
const double gcell_vol)
const {
553 bool all_projectile =
555 return data.belongs_to() == BelongsTo::Projectile;
559 return data.belongs_to() == BelongsTo::Target;
563 return data.get_history().collisions_per_particle == 0;
565 if ((all_projectile || all_target) && none_collided) {
581 ScatterActionMultiPtr act =
582 make_unique<ScatterActionMulti>(plist, time_until_collision);
584 act->set_stochastic_pos_idx();
593 act->get_total_weight() / std::pow(
testparticles_, plist.size() - 1);
597 std::stringstream err;
598 err <<
"Probability larger than 1 for stochastic rates. ( P_nm = " << prob
599 <<
" )\nConsider using smaller timesteps.";
603 throw std::runtime_error(err.str());
609 if (random_no > prob) {
613 return std::move(act);
617 const ParticleList& search_list,
double dt,
const double gcell_vol,
618 const std::vector<FourVector>& beam_momentum)
const {
619 std::vector<ActionPtr> actions;
623 if (p1.id() < p2.id()) {
627 actions.push_back(std::move(act));
637 if (p1.id() < p2.id() && p2.id() < p3.id()) {
641 actions.push_back(std::move(act));
648 if (p1.id() < p2.id() && p2.id() < p3.id() && p3.id() < p4.id()) {
652 actions.push_back(std::move(act));
658 search_list.size() >= 5) {
660 if ((p1.id() < p2.id() && p2.id() < p3.id() &&
661 p3.id() < p4.id() && p4.id() < p5.id()) &&
662 (p1.is_pion() && p2.is_pion() && p3.is_pion() &&
663 p4.is_pion() && p5.is_pion())) {
666 {p1, p2, p3, p4, p5}, dt, gcell_vol);
668 actions.push_back(std::move(act));
682 const ParticleList& search_list,
const ParticleList& neighbors_list,
683 double dt,
const std::vector<FourVector>& beam_momentum)
const {
684 std::vector<ActionPtr> actions;
691 assert(p1.id() != p2.id());
695 actions.push_back(std::move(act));
703 const ParticleList& search_list,
const Particles& surrounding_list,
704 double dt,
const std::vector<FourVector>& beam_momentum)
const {
705 std::vector<ActionPtr> actions;
713 auto result = std::find_if(
714 search_list.begin(), search_list.end(),
716 if (result != search_list.end()) {
723 actions.push_back(std::move(act));
731 constexpr
double time = 0.0;
734 const size_t N_pairs = N_isotypes * (N_isotypes - 1) / 2;
736 std::cout << N_isotypes <<
" iso-particle types." << std::endl;
737 std::cout <<
"They can make " << N_pairs <<
" pairs." << std::endl;
738 std::vector<double> momentum_scan_list = {0.1, 0.3, 0.5, 1.0,
739 2.0, 3.0, 5.0, 10.0};
742 if (&A_isotype > &B_isotype) {
745 bool any_nonzero_cs =
false;
746 std::vector<std::string> r_list;
749 if (A_type > B_type) {
753 for (
auto mom : momentum_scan_list) {
754 A.set_4momentum(A.pole_mass(), mom, 0.0, 0.0);
756 ScatterActionPtr act = make_unique<ScatterAction>(
761 act->add_all_scatterings(
766 const double total_cs = act->cross_section();
767 if (total_cs <= 0.0) {
770 any_nonzero_cs =
true;
771 for (
const auto& channel : act->collision_channels()) {
772 const auto type = channel->get_type();
776 r = A_type->name() + B_type->name() + std::string(
" → strings");
780 ? std::string(
" (el)")
782 ? std::string(
" (inel)")
783 : std::string(
" (?)");
784 r = A_type->name() + B_type->name() + std::string(
" → ") +
785 channel->particle_types()[0]->name() +
786 channel->particle_types()[1]->name() + r_type;
794 std::sort(r_list.begin(), r_list.end());
795 r_list.erase(std::unique(r_list.begin(), r_list.end()), r_list.end());
796 if (any_nonzero_cs) {
797 for (
auto r : r_list) {
799 if (r_list.back() != r) {
803 std::cout << std::endl;
833 namespace decaytree {
881 Node(
const std::string& name,
double weight,
882 ParticleTypePtrList&& initial_particles,
883 ParticleTypePtrList&& final_particles, ParticleTypePtrList&& state,
884 std::vector<Node>&& children)
904 ParticleTypePtrList&& initial_particles,
905 ParticleTypePtrList&& final_particles) {
907 ParticleTypePtrList state(
state_);
908 for (
const auto&
p : initial_particles) {
909 state.erase(std::find(state.begin(), state.end(),
p));
911 for (
const auto&
p : final_particles) {
915 std::sort(state.begin(), state.end(),
917 return a->name() < b->name();
920 Node new_node(name, weight, std::move(initial_particles),
921 std::move(final_particles), std::move(state), {});
922 children_.emplace_back(std::move(new_node));
933 std::vector<FinalStateCrossSection> result;
946 for (uint64_t i = 0; i < depth; i++) {
951 child.print_helper(depth + 1);
967 uint64_t depth, std::vector<FinalStateCrossSection>& result,
968 const std::string& name,
double weight,
969 bool show_intermediate_states =
false)
const {
977 std::string new_name;
980 if (show_intermediate_states) {
982 if (!new_name.empty()) {
990 for (
const auto& s :
state_) {
991 new_name += s->name();
994 if (show_intermediate_states) {
1003 child.final_state_cross_sections_helper(depth + 1, result, new_name,
1004 weight, show_intermediate_states);
1018 const DecayBranchPtr& decay,
1019 ParticleTypePtrList& final_state) {
1020 std::stringstream name;
1021 name <<
"[" << res_name <<
"->";
1022 for (
const auto&
p : decay->particle_types()) {
1024 final_state.push_back(
p);
1048 uint32_t n_unstable = 0;
1049 double sqrts_minus_masses = sqrts;
1054 sqrts_minus_masses -= ptype->
mass();
1057 n_unstable != 0 ? 1. /
static_cast<double>(n_unstable) : 1.;
1061 const double sqrts_decay = sqrts_minus_masses + ptype->
mass();
1062 bool can_decay =
false;
1067 double final_state_mass = 0.;
1068 for (
const auto&
p : decay->particle_types()) {
1069 final_state_mass +=
p->mass();
1071 if (final_state_mass > sqrts_decay) {
1076 ParticleTypePtrList parts;
1078 auto& new_node = node.
add_action(name, norm * decay->weight(), {ptype},
1099 static void deduplicate(std::vector<FinalStateCrossSection>& final_state_xs) {
1100 std::sort(final_state_xs.begin(), final_state_xs.end(),
1103 auto current = final_state_xs.begin();
1104 while (current != final_state_xs.end()) {
1105 auto adjacent = std::adjacent_find(
1106 current, final_state_xs.end(),
1108 return a.name_ == b.name_;
1111 if (adjacent != final_state_xs.end()) {
1112 adjacent->cross_section_ += (adjacent + 1)->cross_section_;
1113 final_state_xs.erase(adjacent + 1);
1120 bool final_state, std::vector<double>& plab)
const {
1121 typedef std::vector<std::pair<double, double>> xs_saver;
1122 std::map<std::string, xs_saver> xs_dump;
1123 std::map<std::string, double> outgoing_total_mass;
1126 int n_momentum_points = 200;
1127 constexpr
double momentum_step = 0.02;
1134 if (plab.size() > 0) {
1135 n_momentum_points = plab.size();
1137 std::sort(plab.begin(), plab.end());
1138 plab.erase(std::unique(plab.begin(), plab.end()), plab.end());
1140 for (
int i = 0; i < n_momentum_points; i++) {
1142 if (plab.size() > 0) {
1145 momentum = momentum_step * (i + 1);
1147 a_data.set_4momentum(m_a, momentum, 0.0, 0.0);
1149 const double sqrts = (a_data.momentum() + b_data.
momentum()).abs();
1150 const ParticleList incoming = {a_data, b_data};
1151 ScatterActionPtr act = make_unique<ScatterAction>(
1161 {&a, &b}, {&a, &b}, {});
1162 const CollisionBranchList& processes = act->collision_channels();
1163 for (
const auto& process : processes) {
1164 const double xs = process->weight();
1169 std::stringstream process_description_stream;
1170 process_description_stream << *process;
1171 const std::string& description = process_description_stream.str();
1173 for (
const auto& ptype : process->particle_types()) {
1174 m_tot += ptype->mass();
1176 outgoing_total_mass[description] = m_tot;
1177 if (!xs_dump[description].empty() &&
1178 std::abs(xs_dump[description].back().first - sqrts) <
1180 xs_dump[description].back().second += xs;
1182 xs_dump[description].push_back(std::make_pair(sqrts, xs));
1185 std::stringstream process_description_stream;
1186 process_description_stream << *process;
1187 const std::string& description = process_description_stream.str();
1188 ParticleTypePtrList initial_particles = {&a, &b};
1189 ParticleTypePtrList final_particles = process->particle_types();
1190 auto& process_node =
1191 tree.
add_action(description, xs, std::move(initial_particles),
1192 std::move(final_particles));
1196 xs_dump[
"total"].push_back(std::make_pair(sqrts, act->cross_section()));
1198 outgoing_total_mass[
"total"] = -1.0;
1203 for (
const auto&
p : final_state_xs) {
1208 if (
p.name_ ==
"") {
1211 outgoing_total_mass[
p.name_] =
p.mass_;
1212 xs_dump[
p.name_].push_back(std::make_pair(sqrts,
p.cross_section_));
1219 for (
auto it = begin(xs_dump); it != end(xs_dump);) {
1221 const xs_saver& xs = (*it).second;
1223 for (
const auto&
p : xs) {
1227 it = xs_dump.erase(it);
1234 std::vector<std::string> all_channels;
1235 for (
const auto& channel : xs_dump) {
1236 all_channels.push_back(channel.first);
1238 std::sort(all_channels.begin(), all_channels.end(),
1239 [&](
const std::string& str_a,
const std::string& str_b) {
1240 return outgoing_total_mass[str_a] < outgoing_total_mass[str_b];
1244 std::cout <<
"# Dumping partial " << a.
name() << b.
name()
1245 <<
" cross-sections in mb, energies in GeV" << std::endl;
1246 std::cout <<
" sqrt_s";
1250 for (
const auto& channel : all_channels) {
1253 std::cout << std::endl;
1256 for (
int i = 0; i < n_momentum_points; i++) {
1258 if (plab.size() > 0) {
1261 momentum = momentum_step * (i + 1);
1263 a_data.set_4momentum(m_a, momentum, 0.0, 0.0);
1265 const double sqrts = (a_data.momentum() + b_data.
momentum()).abs();
1266 std::printf(
"%9.6f", sqrts);
1267 for (
const auto& channel : all_channels) {
1268 const xs_saver energy_and_xs = xs_dump[channel];
1270 for (; j < energy_and_xs.size() && energy_and_xs[j].first < sqrts; j++) {
1273 if (j < energy_and_xs.size() &&
1274 std::abs(energy_and_xs[j].first - sqrts) <
really_small) {
1275 xs = energy_and_xs[j].second;
1277 std::printf(
"%16.6f", xs);
Interface to the SMASH configuration files.
const DecayBranchList & decay_mode_list() const
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.
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.
const int testparticles_
Number of test particles.
const MultiParticleReactionsBitSet incl_multi_set_
List of included multi-particle reactions.
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.
const double elastic_parameter_
Elastic cross section parameter (in mb).
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 strings_switch_
Switch to turn off string excitation.
const double additional_el_xs_
Additional constant elastic cross section.
const double scale_xs_
Factor by which all (partial) cross sections are scaled.
const bool allow_first_collisions_within_nucleus_
If particles within nucleus are allowed to collide for their first time.
const NNbarTreatment nnbar_treatment_
Switch for NNbar reactions.
const double low_snn_cut_
Elastic collsions between two nucleons with sqrt_s below low_snn_cut_ are excluded.
const bool use_AQM_
Switch to control whether to use AQM or not.
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,...
const bool only_warn_for_high_prob_
Switch to turn off throwing an exception for collision probabilities larger than 1.
const CollisionCriterion coll_crit_
Specifies which collision criterion is used.
ScatterActionsFinder(Configuration config, const ExperimentParameters ¶meters)
Constructor of the finder with the given parameters.
const ReactionsBitSet incl_set_
List of included 2<->2 reactions.
const bool two_to_one_
Enable 2->1 processes.
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...
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.
const bool strings_with_probability_
Decide whether to implement string fragmentation based on a probability.
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.
@ Stochastic
Stochastic Criteiron.
@ Geometric
(Default) 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.
const PdgCode dprime(PdgCode::from_decimal(1000010021))
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.
static void deduplicate(std::vector< FinalStateCrossSection > &final_state_xs)
Deduplicate the final-state cross sections by summing.
@ TwoToTwo
2->2 inelastic scattering
@ Elastic
elastic scattering: particles remain the same, only momenta change
@ StringHard
hard string process involving 2->2 QCD process by PYTHIA.
bool all_of(Container &&c, UnaryPredicate &&p)
Convenience wrapper for std::all_of that operates on a complete container.
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
bool is_string_soft_process(ProcessType p)
Check if a given process type is a soft string excitation.
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...
constexpr double fm2_mb
mb <-> fm^2 conversion factor.
Helper structure for Experiment.
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.
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.