210 const std::vector<bool>& nucleon_has_interacted,
int N_tot,
int N_proj)
211 : elastic_parameter_(
212 config.take({
"Collision_Term",
"Elastic_Cross_Section"}, -1.)),
214 isotropic_(config.take({
"Collision_Term",
"Isotropic"},
false)),
226 {
"Collision_Term",
"String_Parameters",
"Formation_Time"}, 1.)) {
228 const auto& log = logger<LogArea::FindScatter>();
229 log.info(
"Constant elastic isotropic cross-section mode:",
" using ",
233 auto subconfig = config[
"Collision_Term"][
"String_Parameters"];
236 subconfig.take({
"Gluon_Beta"}, 0.5),
237 subconfig.take({
"Gluon_Pmin"}, 0.001),
238 subconfig.take({
"Quark_Alpha"}, 2.0),
239 subconfig.take({
"Quark_Beta"}, 7.0),
240 subconfig.take({
"Strange_Supp"}, 0.16),
241 subconfig.take({
"Diquark_Supp"}, 0.036),
242 subconfig.take({
"Sigma_Perp"}, 0.42),
243 subconfig.take({
"StringZ_A_Leading"}, 0.2),
244 subconfig.take({
"StringZ_B_Leading"}, 2.0),
245 subconfig.take({
"StringZ_A"}, 2.0), subconfig.take({
"StringZ_B"}, 0.55),
246 subconfig.take({
"String_Sigma_T"}, 0.5),
247 subconfig.take({
"Form_Time_Factor"}, 1.0),
248 subconfig.take({
"Mass_Dependent_Formation_Times"},
false),
249 subconfig.take({
"Prob_proton_to_d_uu"}, 1. / 3.),
250 subconfig.take({
"Separate_Fragment_Baryon"},
true),
251 subconfig.take({
"Popcorn_Rate"}, 0.15));
259 const auto& log = logger<LogArea::FindScatter>();
265 log.debug(
"Skipping collided particles at time ", data_a.
position().
x0(),
266 " due to process ", data_a.
id_process(),
"\n ", data_a,
276 assert(data_a.
id() >= 0);
277 assert(data_b.
id() >= 0);
287 const double time_until_collision =
collision_time(data_a, data_b);
290 if (time_until_collision < 0. || time_until_collision >= dt) {
295 ScatterActionPtr act = make_unique<ScatterAction>(
301 const double distance_squared = act->transverse_distance_sqr();
314 double cross_section_criterion = act->cross_section() *
fm2_mb * M_1_PI /
317 cross_section_criterion *= data_a.xsec_scaling_factor(time_until_collision);
318 cross_section_criterion *= data_b.xsec_scaling_factor(time_until_collision);
321 if (distance_squared >= cross_section_criterion) {
326 log.debug(
"particle distance squared: ", distance_squared,
"\n ", data_a,
332 return std::move(act);
336 const ParticleList& search_list,
double dt)
const {
337 std::vector<ActionPtr> actions;
340 if (p1.id() < p2.id()) {
344 actions.push_back(std::move(act));
353 const ParticleList& search_list,
const ParticleList& neighbors_list,
355 std::vector<ActionPtr> actions;
358 assert(p1.id() != p2.id());
362 actions.push_back(std::move(act));
370 const ParticleList& search_list,
const Particles& surrounding_list,
372 std::vector<ActionPtr> actions;
376 auto result = std::find_if(
377 search_list.begin(), search_list.end(),
379 if (result != search_list.end()) {
386 actions.push_back(std::move(act));
394 constexpr
double time = 0.0;
397 const size_t N_pairs = N_isotypes * (N_isotypes - 1) / 2;
399 std::cout << N_isotypes <<
" iso-particle types." << std::endl;
400 std::cout <<
"They can make " << N_pairs <<
" pairs." << std::endl;
401 std::vector<double> momentum_scan_list = {0.1, 0.3, 0.5, 1.0,
402 2.0, 3.0, 5.0, 10.0};
405 if (&A_isotype > &B_isotype) {
408 bool any_nonzero_cs =
false;
409 std::vector<std::string> r_list;
412 if (A_type > B_type) {
416 for (
auto mom : momentum_scan_list) {
417 A.set_4momentum(A.pole_mass(), mom, 0.0, 0.0);
419 ScatterActionPtr act = make_unique<ScatterAction>(
428 const double total_cs = act->cross_section();
429 if (total_cs <= 0.0) {
432 any_nonzero_cs =
true;
433 for (
const auto& channel : act->collision_channels()) {
434 const auto type = channel->get_type();
438 r = A_type->name() + B_type->name() + std::string(
" → strings");
442 ? std::string(
" (el)")
444 ? std::string(
" (inel)")
445 : std::string(
" (?)");
446 r = A_type->name() + B_type->name() + std::string(
" → ") +
447 channel->particle_types()[0]->name() +
448 channel->particle_types()[1]->name() + r_type;
456 std::sort(r_list.begin(), r_list.end());
457 r_list.erase(std::unique(r_list.begin(), r_list.end()), r_list.end());
458 if (any_nonzero_cs) {
459 for (
auto r : r_list) {
461 if (r_list.back() != r) {
465 std::cout << std::endl;
492 : name_(name), cross_section_(cross_section), mass_(mass) {}
495 namespace decaytree {
543 Node(
const std::string& name,
double weight,
544 ParticleTypePtrList&& initial_particles,
545 ParticleTypePtrList&& final_particles, ParticleTypePtrList&& state,
546 std::vector<Node>&& children)
549 initial_particles_(
std::move(initial_particles)),
550 final_particles_(
std::move(final_particles)),
551 state_(
std::move(state)),
552 children_(
std::move(children)) {}
566 ParticleTypePtrList&& initial_particles,
567 ParticleTypePtrList&& final_particles) {
569 ParticleTypePtrList state(state_);
570 for (
const auto&
p : initial_particles) {
571 state.erase(std::find(state.begin(), state.end(),
p));
573 for (
const auto&
p : final_particles) {
577 std::sort(state.begin(), state.end(),
579 return a->
name() < b->name();
582 Node new_node(name, weight, std::move(initial_particles),
583 std::move(final_particles), std::move(state), {});
584 children_.emplace_back(std::move(new_node));
585 return children_.back();
589 void print()
const { print_helper(0); }
595 std::vector<FinalStateCrossSection> result;
596 final_state_cross_sections_helper(0, result,
"", 1.);
608 for (uint64_t i = 0; i < depth; i++) {
611 std::cout << name_ <<
" " << weight_ << std::endl;
612 for (
const auto& child : children_) {
613 child.print_helper(depth + 1);
629 uint64_t depth, std::vector<FinalStateCrossSection>& result,
630 const std::string& name,
double weight,
631 bool show_intermediate_states =
false)
const {
639 std::string new_name;
642 if (show_intermediate_states) {
644 if (!new_name.empty()) {
652 for (
const auto& s : state_) {
653 new_name += s->name();
656 if (show_intermediate_states) {
660 if (children_.empty()) {
664 for (
const auto& child : children_) {
665 child.final_state_cross_sections_helper(depth + 1, result, new_name,
666 weight, show_intermediate_states);
680 const DecayBranchPtr& decay,
681 ParticleTypePtrList& final_state) {
682 std::stringstream name;
683 name <<
"[" << res_name <<
"->";
684 for (
const auto&
p : decay->particle_types()) {
686 final_state.push_back(
p);
709 uint32_t n_unstable = 0;
710 double sqrts_minus_masses = sqrts;
715 sqrts_minus_masses -= ptype->
mass();
718 n_unstable != 0 ? 1. /
static_cast<double>(n_unstable) : 1.;
722 const double sqrts_decay = sqrts_minus_masses + ptype->
mass();
727 double final_state_mass = 0.;
728 for (
const auto&
p : decay->particle_types()) {
729 final_state_mass +=
p->mass();
731 if (final_state_mass > sqrts_decay) {
735 ParticleTypePtrList parts;
737 auto& new_node = node.
add_action(name, norm * decay->weight(), {ptype},
752 static void deduplicate(std::vector<FinalStateCrossSection>& final_state_xs) {
753 std::sort(final_state_xs.begin(), final_state_xs.end(),
756 auto current = final_state_xs.begin();
757 while (current != final_state_xs.end()) {
758 auto adjacent = std::adjacent_find(
759 current, final_state_xs.end(),
761 return a.
name_ == b.name_;
764 if (adjacent != final_state_xs.end()) {
765 adjacent->cross_section_ += (adjacent + 1)->cross_section_;
766 final_state_xs.erase(adjacent + 1);
773 bool final_state, std::vector<double>& plab)
const {
774 typedef std::vector<std::pair<double, double>> xs_saver;
775 std::map<std::string, xs_saver> xs_dump;
776 std::map<std::string, double> outgoing_total_mass;
779 int n_momentum_points = 200;
780 constexpr
double momentum_step = 0.02;
787 if (plab.size() > 0) {
788 n_momentum_points = plab.size();
790 std::sort(plab.begin(), plab.end());
791 plab.erase(std::unique(plab.begin(), plab.end()), plab.end());
793 for (
int i = 0; i < n_momentum_points; i++) {
795 if (plab.size() > 0) {
798 momentum = momentum_step * (i + 1);
800 a_data.set_4momentum(m_a, momentum, 0.0, 0.0);
802 const double sqrts = (a_data.momentum() + b_data.
momentum()).abs();
803 const ParticleList incoming = {a_data, b_data};
804 ScatterActionPtr act = make_unique<ScatterAction>(
813 {&a, &b}, {&a, &b}, {});
814 const CollisionBranchList& processes = act->collision_channels();
815 for (
const auto& process : processes) {
816 const double xs = process->weight();
821 std::stringstream process_description_stream;
822 process_description_stream << *process;
823 const std::string& description = process_description_stream.str();
825 for (
const auto& ptype : process->particle_types()) {
826 m_tot += ptype->mass();
828 outgoing_total_mass[description] = m_tot;
829 if (!xs_dump[description].empty() &&
830 std::abs(xs_dump[description].back().first - sqrts) <
832 xs_dump[description].back().second += xs;
834 xs_dump[description].push_back(std::make_pair(sqrts, xs));
837 std::stringstream process_description_stream;
838 process_description_stream << *process;
839 const std::string& description = process_description_stream.str();
840 ParticleTypePtrList initial_particles = {&a, &b};
841 ParticleTypePtrList final_particles = process->particle_types();
843 tree.add_action(description, xs, std::move(initial_particles),
844 std::move(final_particles));
848 xs_dump[
"total"].push_back(std::make_pair(sqrts, act->cross_section()));
850 outgoing_total_mass[
"total"] = -1.0;
853 auto final_state_xs = tree.final_state_cross_sections();
855 for (
const auto&
p : final_state_xs) {
863 outgoing_total_mass[
p.name_] =
p.mass_;
864 xs_dump[
p.name_].push_back(std::make_pair(sqrts,
p.cross_section_));
870 std::vector<std::string> all_channels;
871 for (
const auto channel : xs_dump) {
872 all_channels.push_back(channel.first);
874 std::sort(all_channels.begin(), all_channels.end(),
875 [&](
const std::string& str_a,
const std::string& str_b) {
876 return outgoing_total_mass[str_a] < outgoing_total_mass[str_b];
880 std::cout <<
"# Dumping partial " << a.
name() << b.
name()
881 <<
" cross-sections in mb, energies in GeV" << std::endl;
882 std::cout <<
" sqrt_s";
886 for (
const auto channel : all_channels) {
889 std::cout << std::endl;
892 for (
int i = 0; i < n_momentum_points; i++) {
894 if (plab.size() > 0) {
897 momentum = momentum_step * (i + 1);
899 a_data.set_4momentum(m_a, momentum, 0.0, 0.0);
901 const double sqrts = (a_data.momentum() + b_data.
momentum()).abs();
902 std::printf(
"%9.6f", sqrts);
903 for (
const auto channel : all_channels) {
904 const xs_saver energy_and_xs = xs_dump[channel];
906 for (; j < energy_and_xs.size() && energy_and_xs[j].first < sqrts; j++) {
909 if (j < energy_and_xs.size() &&
910 std::abs(energy_and_xs[j].first - sqrts) <
really_small) {
911 xs = energy_and_xs[j].second;
913 std::printf(
"%16.6f", xs);
static void add_decays(Node &node, double sqrts)
Add nodes for all decays possible from the given node and all of its children.
uint32_t id_process() const
Get the id of the last action.
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...
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 FourVector & position() const
Get the particle's position in Minkowski space.
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_.
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.
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.
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.
const bool strings_with_probability_
Decide whether to implement string fragmentation based on a probability.
T pCM_from_s(const T s, const T mass_a, const T mass_b) noexcept
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...
constexpr double fm2_mb
mb <-> fm^2 conversion factor.
2->2 inelastic scattering
std::vector< Node > children_
Possible actions after this action.
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::unique_ptr< StringProcess > string_process_interface_
Class that deals with strings, interfacing Pythia.
const bool strings_switch_
Switch to turn off string excitation.
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 DecayBranchList & decay_mode_list() const
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.
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...
elastic scattering: particles remain the same, only momenta change
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...
double weight_
Weight (cross section or branching ratio).
const std::string & name() const
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 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.
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.
std::vector< FinalStateCrossSection > final_state_cross_sections() const
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...
double pole_mass() const
Get the particle's pole mass ("on-shell").
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.
void print_helper(uint64_t depth) const
Internal helper function for print, to be called recursively to print all nodes.
const int N_tot_
Record the total number of the nucleons in the two colliding nuclei.
A pointer-like interface to global references to ParticleType objects.
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.
void print() const
Print the decay tree starting with this node.
The Particles class abstracts the storage and manipulation of particles.
const DecayModes & decay_modes() const
Node(const std::string &name, double weight, ParticleTypePtrList &&initial_particles, ParticleTypePtrList &&final_particles, ParticleTypePtrList &&state, std::vector< Node > &&children)
int32_t id() const
Get the id of the particle.
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).
const FourVector & momentum() const
Get the particle's 4-momentum.
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.