195 const std::vector<bool>& nucleon_has_interacted,
int N_tot,
int N_proj)
196 : elastic_parameter_(
197 config.take({
"Collision_Term",
"Elastic_Cross_Section"}, -1.)),
198 testparticles_(parameters.testparticles),
199 isotropic_(config.take({
"Collision_Term",
"Isotropic"},
false)),
200 two_to_one_(parameters.two_to_one),
201 incl_set_(parameters.included_2to2),
202 low_snn_cut_(parameters.low_snn_cut),
203 strings_switch_(parameters.strings_switch),
204 use_AQM_(parameters.use_AQM),
205 strings_with_probability_(parameters.strings_with_probability),
206 nnbar_treatment_(parameters.nnbar_treatment),
207 nucleon_has_interacted_(nucleon_has_interacted),
210 string_formation_time_(config.take(
211 {
"Collision_Term",
"String_Parameters",
"Formation_Time"}, 1.)) {
212 if (is_constant_elastic_isotropic()) {
213 const auto& log = logger<LogArea::FindScatter>();
214 log.info(
"Constant elastic isotropic cross-section mode:",
" using ",
215 elastic_parameter_,
" mb as maximal cross-section.");
217 if (strings_switch_) {
218 auto subconfig = config[
"Collision_Term"][
"String_Parameters"];
219 string_process_interface_ = make_unique<StringProcess>(
220 subconfig.take({
"String_Tension"}, 1.0), string_formation_time_,
221 subconfig.take({
"Gluon_Beta"}, 0.5),
222 subconfig.take({
"Gluon_Pmin"}, 0.001),
223 subconfig.take({
"Quark_Alpha"}, 2.0),
224 subconfig.take({
"Quark_Beta"}, 5.0),
225 subconfig.take({
"Strange_Supp"}, 0.12),
226 subconfig.take({
"Diquark_Supp"}, 0.03),
227 subconfig.take({
"Sigma_Perp"}, 0.42),
228 subconfig.take({
"Leading_Frag_Mean"}, 1.0),
229 subconfig.take({
"Leading_Frag_Width"}, 0.6),
230 subconfig.take({
"StringZ_A"}, 0.68), subconfig.take({
"StringZ_B"}, 0.3),
231 subconfig.take({
"String_Sigma_T"}, 0.5),
232 subconfig.take({
"Form_Time_Factor"}, 1.0),
233 subconfig.take({
"Use_Yoyo_Model"},
true),
234 subconfig.take({
"Prob_proton_to_d_uu"}, 1. / 3.));
242 const auto& log = logger<LogArea::FindScatter>();
248 log.debug(
"Skipping collided particles at time ", data_a.
position().
x0(),
249 " due to process ", data_a.
id_process(),
"\n ", data_a,
259 assert(data_a.
id() >= 0);
260 assert(data_b.
id() >= 0);
270 const double time_until_collision =
collision_time(data_a, data_b);
273 if (time_until_collision < 0. || time_until_collision >= dt) {
278 ScatterActionPtr act = make_unique<ScatterAction>(
284 const double distance_squared = act->transverse_distance_sqr();
297 double cross_section_criterion = act->cross_section() *
fm2_mb * M_1_PI /
300 cross_section_criterion *= data_a.xsec_scaling_factor(time_until_collision);
301 cross_section_criterion *= data_b.xsec_scaling_factor(time_until_collision);
304 if (distance_squared >= cross_section_criterion) {
309 log.debug(
"particle distance squared: ", distance_squared,
"\n ", data_a,
313 return std::move(act);
317 const ParticleList& search_list,
double dt)
const {
318 std::vector<ActionPtr> actions;
321 if (p1.id() < p2.id()) {
325 actions.push_back(std::move(act));
334 const ParticleList& search_list,
const ParticleList& neighbors_list,
336 std::vector<ActionPtr> actions;
339 assert(p1.id() != p2.id());
343 actions.push_back(std::move(act));
351 const ParticleList& search_list,
const Particles& surrounding_list,
353 std::vector<ActionPtr> actions;
357 auto result = std::find_if(
358 search_list.begin(), search_list.end(),
360 if (result != search_list.end()) {
367 actions.push_back(std::move(act));
375 constexpr
double time = 0.0;
378 const size_t N_pairs = N_isotypes * (N_isotypes - 1) / 2;
380 std::cout << N_isotypes <<
" iso-particle types." << std::endl;
381 std::cout <<
"They can make " << N_pairs <<
" pairs." << std::endl;
382 std::vector<double> momentum_scan_list = {0.1, 0.3, 0.5, 1.0,
383 2.0, 3.0, 5.0, 10.0};
386 if (&A_isotype > &B_isotype) {
389 bool any_nonzero_cs =
false;
390 std::vector<std::string> r_list;
393 if (A_type > B_type) {
397 for (
auto mom : momentum_scan_list) {
398 A.set_4momentum(A.pole_mass(), mom, 0.0, 0.0);
400 ScatterActionPtr act = make_unique<ScatterAction>(
409 const double total_cs = act->cross_section();
410 if (total_cs <= 0.0) {
413 any_nonzero_cs =
true;
414 for (
const auto& channel : act->collision_channels()) {
415 const auto type = channel->get_type();
419 r = A_type->name() + B_type->name() + std::string(
" → strings");
423 ? std::string(
" (el)")
425 ? std::string(
" (inel)")
426 : std::string(
" (?)");
427 r = A_type->name() + B_type->name() + std::string(
" → ") +
428 channel->particle_types()[0]->name() +
429 channel->particle_types()[1]->name() + r_type;
437 std::sort(r_list.begin(), r_list.end());
438 r_list.erase(std::unique(r_list.begin(), r_list.end()), r_list.end());
439 if (any_nonzero_cs) {
440 for (
auto r : r_list) {
442 if (r_list.back() != r) {
446 std::cout << std::endl;
476 namespace decaytree {
524 Node(
const std::string& name,
double weight,
525 ParticleTypePtrList&& initial_particles,
526 ParticleTypePtrList&& final_particles, ParticleTypePtrList&& state,
527 std::vector<Node>&& children)
547 ParticleTypePtrList&& initial_particles,
548 ParticleTypePtrList&& final_particles) {
550 ParticleTypePtrList state(
state_);
551 for (
const auto&
p : initial_particles) {
552 state.erase(std::find(state.begin(), state.end(),
p));
554 for (
const auto&
p : final_particles) {
558 std::sort(state.begin(), state.end(),
560 return a->
name() < b->name();
563 Node new_node(name, weight, std::move(initial_particles),
564 std::move(final_particles), std::move(state), {});
565 children_.emplace_back(std::move(new_node));
576 std::vector<FinalStateCrossSection> result;
589 for (uint64_t i = 0; i < depth; i++) {
594 child.print_helper(depth + 1);
610 uint64_t depth, std::vector<FinalStateCrossSection>& result,
611 const std::string& name,
double weight,
612 bool show_intermediate_states =
false)
const {
620 std::string new_name;
623 if (show_intermediate_states) {
625 if (!new_name.empty()) {
633 for (
const auto& s :
state_) {
634 new_name += s->name();
637 if (show_intermediate_states) {
646 child.final_state_cross_sections_helper(depth + 1, result, new_name,
647 weight, show_intermediate_states);
661 const DecayBranchPtr& decay,
662 ParticleTypePtrList& final_state) {
663 std::stringstream name;
664 name <<
"[" << res_name <<
"->";
665 for (
const auto&
p : decay->particle_types()) {
667 final_state.push_back(
p);
690 uint32_t n_unstable = 0;
697 n_unstable != 0 ? 1. /
static_cast<double>(n_unstable) : 1.;
702 ParticleTypePtrList parts;
704 auto& new_node = node.
add_action(name, norm * decay->weight(), {ptype},
719 static void deduplicate(std::vector<FinalStateCrossSection>& final_state_xs) {
720 std::sort(final_state_xs.begin(), final_state_xs.end(),
723 auto current = final_state_xs.begin();
724 while (current != final_state_xs.end()) {
725 auto adjacent = std::adjacent_find(
726 current, final_state_xs.end(),
728 return a.
name_ == b.name_;
731 if (adjacent != final_state_xs.end()) {
732 adjacent->cross_section_ += (adjacent + 1)->cross_section_;
733 final_state_xs.erase(adjacent + 1);
740 double m_a,
double m_b,
741 bool final_state)
const {
742 typedef std::vector<std::pair<double, double>> xs_saver;
743 std::map<std::string, xs_saver> xs_dump;
744 std::map<std::string, double> outgoing_total_mass;
747 constexpr
int n_momentum_points = 200;
748 constexpr
double momentum_step = 0.02;
749 for (
int i = 1; i < n_momentum_points + 1; i++) {
750 const double momentum = momentum_step * i;
751 a_data.set_4momentum(m_a, momentum, 0.0, 0.0);
753 const double sqrts = (a_data.momentum() + b_data.
momentum()).abs();
754 const ParticleList incoming = {a_data, b_data};
755 ScatterActionPtr act = make_unique<ScatterAction>(
764 {&a, &b}, {&a, &b}, {});
765 const CollisionBranchList& processes = act->collision_channels();
766 for (
const auto& process : processes) {
767 const double xs = process->weight();
772 std::stringstream process_description_stream;
773 process_description_stream << *process;
774 const std::string& description = process_description_stream.str();
776 for (
const auto& ptype : process->particle_types()) {
777 m_tot += ptype->mass();
779 outgoing_total_mass[description] = m_tot;
780 if (!xs_dump[description].empty() &&
781 std::abs(xs_dump[description].back().first - sqrts) <
783 xs_dump[description].back().second += xs;
785 xs_dump[description].push_back(std::make_pair(sqrts, xs));
788 std::stringstream process_description_stream;
789 process_description_stream << *process;
790 const std::string& description = process_description_stream.str();
791 ParticleTypePtrList initial_particles = {&a, &b};
792 ParticleTypePtrList final_particles = process->particle_types();
794 tree.add_action(description, xs, std::move(initial_particles),
795 std::move(final_particles));
799 xs_dump[
"total"].push_back(std::make_pair(sqrts, act->cross_section()));
801 outgoing_total_mass[
"total"] = -1.0;
804 auto final_state_xs = tree.final_state_cross_sections();
806 for (
const auto&
p : final_state_xs) {
807 outgoing_total_mass[
p.name_] =
p.mass_;
808 xs_dump[
p.name_].push_back(std::make_pair(sqrts,
p.cross_section_));
814 std::vector<std::string> all_channels;
815 for (
const auto channel : xs_dump) {
816 all_channels.push_back(channel.first);
818 std::sort(all_channels.begin(), all_channels.end(),
819 [&](
const std::string& str_a,
const std::string& str_b) {
820 return outgoing_total_mass[str_a] < outgoing_total_mass[str_b];
824 std::cout <<
"# Dumping partial " << a.
name() << b.
name()
825 <<
" cross-sections in mb, energies in GeV" << std::endl;
826 std::cout <<
" sqrt_s";
830 for (
const auto channel : all_channels) {
833 std::cout << std::endl;
836 for (
int i = 1; i < n_momentum_points; i++) {
837 const double momentum = momentum_step * i;
838 a_data.set_4momentum(m_a, momentum, 0.0, 0.0);
840 const double sqrts = (a_data.momentum() + b_data.
momentum()).abs();
841 printf(
"%9.5f", sqrts);
842 for (
const auto channel : all_channels) {
843 const xs_saver energy_and_xs = xs_dump[channel];
845 for (; j < energy_and_xs.size() && energy_and_xs[j].first < sqrts; j++) {
848 if (j < energy_and_xs.size() &&
849 std::abs(energy_and_xs[j].first - sqrts) <
really_small) {
850 xs = energy_and_xs[j].second;
852 printf(
"%16.6f", xs);
void print_helper(uint64_t depth) const
Internal helper function for print, to be called recursively to print all nodes.
Node(const Node &)=delete
Cannot be copied.
std::string name_
Name of the final state.
static double collision_time(const ParticleData &p1, const ParticleData &p2)
Determine the collision time of the two particles.
double mass_
Total mass of final state particles.
static void deduplicate(std::vector< FinalStateCrossSection > &final_state_xs)
Deduplicate the final-state cross sections by summing.
const int testparticles_
Number of test particles.
constexpr double really_small
Numerical error tolerance.
const ReactionsBitSet incl_set_
List of included 2<->2 reactions.
bool is_string_soft_process(ProcessType p)
Check if a given process type is a soft string excitation.
const bool two_to_one_
Enable 2->1 processes.
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.
const double low_snn_cut_
Elastic collsions between two nucleons with sqrt_s below low_snn_cut_ are excluded.
const double string_formation_time_
Parameter for formation time.
void isoclean(std::string &s)
Remove ⁺, ⁻, ⁰ from string.
Collection of useful constants that are known at compile time.
double pole_mass() const
Get the particle's pole mass ("on-shell").
const bool strings_with_probability_
Decide whether to implement string fragmentation based on a probability.
double max_transverse_distance_sqr(int testparticles) const
The maximal distance over which particles can interact, related to the number of test particles and t...
ActionPtr check_collision(const ParticleData &data_a, const ParticleData &data_b, double dt) const
Check for a single pair of particles (id_a, id_b) if a collision will happen in the next timestep and...
constexpr double fm2_mb
mb <-> fm^2 conversion factor.
2->2 inelastic scattering
std::vector< Node > children_
Possible actions after this action.
const FourVector & momentum() const
Get the particle's 4-momentum.
const std::vector< bool > & nucleon_has_interacted_
Parameter to record whether the nucleon has experienced a collision or not.
Represent a final-state cross section.
Interface to the SMASH configuration files.
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.
std::unique_ptr< StringProcess > string_process_interface_
Class that deals with strings, interfacing Pythia.
const bool strings_switch_
Switch to turn off string excitation.
ParticleTypePtrList initial_particles_
Initial-state particle types in this action.
ActionList find_actions_in_cell(const ParticleList &search_list, double dt) const override
Search for all the possible collisions within one cell.
std::string name_
Name for printing.
elastic scattering: particles remain the same, only momenta change
double weight_
Weight (cross section or branching ratio).
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...
const FourVector & position() const
Get the particle's position in Minkowski space.
Particle type contains the static properties of a particle species.
ScatterActionsFinder(Configuration config, const ExperimentParameters ¶meters, const std::vector< bool > &nucleon_has_interacted, int N_tot, int N_proj)
Constructor of the finder with the given parameters.
void dump_cross_sections(const ParticleType &a, const ParticleType &b, double m_a, double m_b, bool final_state) const
Print out partial cross-sections of all processes that can occur in the collision of a(mass = m_a) an...
void set_4momentum(const FourVector &momentum_vector)
Set the particle's 4-momentum directly.
IsoParticleType is a class to represent isospin multiplets.
const NNbarTreatment nnbar_treatment_
Switch for NNbar reactions.
uint32_t id_process() const
Get the id of the last action.
hard string process involving 2->2 QCD process by PYTHIA.
FinalStateCrossSection(const std::string &name, double cross_section, double mass)
Construct a final-state cross section.
ParticleTypePtrList final_particles_
Final-state particle types in this action.
void dump_reactions() const
Prints out all the 2-> n (n > 1) reactions with non-zero cross-sections between all possible pairs of...
std::vector< FinalStateCrossSection > final_state_cross_sections() const
const DecayModes & decay_modes() const
const bool use_AQM_
Switch to control whether to use AQM or not.
const int N_proj_
Record the number of the nucleons in the projectile.
const bool isotropic_
Do all collisions isotropically.
const int N_tot_
Record the total number of the nucleons in the two colliding nuclei.
void print() const
Print the decay tree starting with this node.
A pointer-like interface to global references to ParticleType objects.
static void add_decays(Node &node)
Add nodes for all decays possible from the given node and all of its children.
Node of a decay tree, representing a possible action (2-to-2 or 1-to-2).
ParticleTypePtrList state_
Particle types corresponding to the global state after this action.
The Particles class abstracts the storage and manipulation of particles.
int id() const
Get the id of the particle.
Node(const std::string &name, double weight, ParticleTypePtrList &&initial_particles, ParticleTypePtrList &&final_particles, ParticleTypePtrList &&state, std::vector< Node > &&children)
double cross_section_
Corresponding cross section in mb.
Node & add_action(const std::string &name, double weight, ParticleTypePtrList &&initial_particles, ParticleTypePtrList &&final_particles)
Add an action to the children of this node.
ActionList find_actions_with_surrounding_particles(const ParticleList &search_list, const Particles &surrounding_list, double dt) const override
Search for all the possible secondary collisions between the outgoing particles and the rest...
Helper structure for Experiment.
ParticleData contains the dynamic information of a certain particle.
const double elastic_parameter_
Elastic cross section parameter (in mb).
static const IsoParticleTypeList & list_all()
Returns a list of all IsoParticleTypes.
ActionList find_actions_with_neighbors(const ParticleList &search_list, const ParticleList &neighbors_list, double dt) const override
Search for all the possible collisions among the neighboring cells.
const DecayBranchList & decay_mode_list() const
const std::string & name() const