Version: SMASH-3.3
smash::Action Class Referenceabstract

#include <action.h>

Action is the base class for a generic process that takes a number of incoming particles and transforms them into any number of outgoing particles.

Currently such an action can be either a decay, a two-body collision, a wallcrossing or a thermalization. (see derived classes).

Definition at line 35 of file action.h.

Inheritance diagram for smash::Action:
smash::DecayAction smash::FluidizationAction smash::FreeforallAction smash::ScatterAction smash::ScatterActionMulti smash::ThermalizationAction smash::WallcrossingAction smash::DecayActionDilepton smash::BremsstrahlungAction smash::ScatterActionPhoton

Classes

class  InvalidResonanceFormation
 Thrown for example when ScatterAction is called to perform with a wrong number of final-state particles or when the energy is too low to produce the resonance. More...
 
class  StochasticBelowEnergyThreshold
 Exception for a temporary bugfix for when multiparticle interactions do not have the necessary energy to create the final state. More...
 

Public Member Functions

 Action (const ParticleList &in_part, double time)
 Construct an action object with incoming particles and relative time. More...
 
 Action (const ParticleData &in_part, const ParticleData &out_part, double time, ProcessType type)
 Construct an action object with the incoming particles, relative time, and the already known outgoing particles and type of the process. More...
 
 Action (const ParticleList &in_part, const ParticleList &out_part, double absolute_execution_time, ProcessType type)
 Construct an action object with the incoming particles, absolute time, and the already known outgoing particles and type of the process. More...
 
 Action (const Action &)=delete
 Copying is disabled. Use pointers or create a new Action. More...
 
virtual ~Action ()
 Virtual Destructor. More...
 
bool operator< (const Action &rhs) const
 Determine whether one action takes place before another in time. More...
 
virtual double get_total_weight () const =0
 Return the total weight value, which is mainly used for the weight output entry. More...
 
virtual double get_partial_weight () const =0
 Return the specific weight for the chosen outgoing channel, which is mainly used for the partial weight output entry. More...
 
virtual ProcessType get_type () const
 Get the process type. More...
 
template<typename Branch >
void add_process (ProcessBranchPtr< Branch > &p, ProcessBranchList< Branch > &subprocesses, double &total_weight)
 Add a new subprocess. More...
 
template<typename Branch >
void add_processes (ProcessBranchList< Branch > pv, ProcessBranchList< Branch > &subprocesses, double &total_weight)
 Add several new subprocesses at once. More...
 
virtual void generate_final_state ()=0
 Generate the final state for this action. More...
 
virtual double perform (Particles *particles, uint32_t id_process)
 Actually perform the action, e.g. More...
 
bool is_valid (const Particles &particles) const
 Check whether the action still applies. More...
 
bool is_pauli_blocked (const std::vector< Particles > &ensembles, const PauliBlocker &p_bl) const
 Check if the action is Pauli-blocked. More...
 
const ParticleList & incoming_particles () const
 Get the list of particles that go into the action. More...
 
void update_incoming (const Particles &particles)
 Update the incoming particles that are stored in this action to the state they have in the global particle list. More...
 
const ParticleList & outgoing_particles () const
 Get the list of particles that resulted from the action. More...
 
double time_of_execution () const
 Get the time at which the action is supposed to be performed. More...
 
virtual double check_conservation (const uint32_t id_process) const
 Check various conservation laws. More...
 
double sqrt_s () const
 Determine the total energy in the center-of-mass frame [GeV]. More...
 
FourVector total_momentum_of_outgoing_particles () const
 Calculate the total kinetic momentum of the outgoing particles. More...
 
FourVector get_interaction_point () const
 Get the interaction point. More...
 
std::pair< FourVector, FourVectorget_potential_at_interaction_point () const
 Get the skyrme and asymmetry potential at the interaction point. More...
 
void set_stochastic_pos_idx ()
 Setter function that stores a random incoming particle index latter used to determine the interaction point. More...
 
void assign_unpolarized_spin_vector_to_outgoing_particles ()
 Assign an unpolarized spin vector to all outgoing particles. More...
 

Static Public Member Functions

static double lambda_tilde (double a, double b, double c)
 Little helper function that calculates the lambda function (sometimes written with a tilde to better distinguish it) that appears e.g. More...
 
static void sample_manybody_phasespace_impl (double sqrts, const std::vector< double > &m, std::vector< FourVector > &sampled_momenta)
 Implementation of the full n-body phase-space sampling (masses, momenta, angles) in the center-of-mass frame for the final state particles. More...
 

Protected Member Functions

FourVector total_momentum () const
 Sum of 4-momenta of incoming particles. More...
 
template<typename Branch >
const Branch * choose_channel (const ProcessBranchList< Branch > &subprocesses, double total_weight)
 Decide for a particular final-state channel via Monte-Carlo and return it as a ProcessBranch. More...
 
virtual std::pair< double, double > sample_masses (double kinetic_energy_cm) const
 Sample final-state masses in general X->2 processes (thus also fixing the absolute c.o.m. More...
 
virtual void sample_angles (std::pair< double, double > masses, double kinetic_energy_cm)
 Sample final-state momenta in general X->2 processes (here: using an isotropical angular distribution). More...
 
virtual void sample_2body_phasespace ()
 Sample the full 2-body phase-space (masses, momenta, angles) in the center-of-mass frame for the final state particles. More...
 
virtual void sample_manybody_phasespace ()
 Sample the full n-body phase-space (masses, momenta, angles) in the center-of-mass frame for the final state particles. More...
 
void assign_formation_time_to_outgoing_particles ()
 Assign the formation time to the outgoing particles. More...
 
virtual void format_debug_output (std::ostream &out) const =0
 Writes information about this action to the out stream. More...
 

Protected Attributes

ParticleList incoming_particles_
 List with data of incoming particles. More...
 
ParticleList outgoing_particles_
 Initially this stores only the PDG codes of final-state particles. More...
 
const double time_of_execution_
 Time at which the action is supposed to be performed (absolute time in the lab frame in fm). More...
 
ProcessType process_type_
 type of process More...
 
double box_length_ = -1.0
 Box length: needed to determine coordinates of collision correctly in case of collision through the wall. More...
 
int stochastic_position_idx_ = -1
 This stores a randomly-chosen index to an incoming particle. More...
 

Private Member Functions

const ParticleTypetype_of_pout (const ParticleData &p_out) const
 Get the type of a given particle. More...
 
const ParticleTypetype_of_pout (const ParticleTypePtr &p_out) const
 Get the particle type for given pointer to a particle type. More...
 

Friends

std::ostream & operator<< (std::ostream &out, const Action &action)
 Dispatches formatting to the virtual Action::format_debug_output function. More...
 

Constructor & Destructor Documentation

◆ Action() [1/4]

smash::Action::Action ( const ParticleList &  in_part,
double  time 
)
inline

Construct an action object with incoming particles and relative time.

Parameters
[in]in_partlist of incoming particles
[in]timetime at which the action is supposed to take place (relative to the current time of the incoming particles)

Definition at line 44 of file action.h.

45  : incoming_particles_(in_part),
46  time_of_execution_(time + in_part[0].position().x0()) {}
const double time_of_execution_
Time at which the action is supposed to be performed (absolute time in the lab frame in fm).
Definition: action.h:378
ParticleList incoming_particles_
List with data of incoming particles.
Definition: action.h:364

◆ Action() [2/4]

smash::Action::Action ( const ParticleData in_part,
const ParticleData out_part,
double  time,
ProcessType  type 
)
inline

Construct an action object with the incoming particles, relative time, and the already known outgoing particles and type of the process.

Parameters
[in]in_partlist of incoming particles
[in]out_partlist of outgoing particles
[in]timetime at which the action is supposed to take place (relative to the current time of the incoming particles)
[in]typetype of the interaction

Definition at line 58 of file action.h.

60  : incoming_particles_({in_part}),
61  outgoing_particles_({out_part}),
62  time_of_execution_(time + in_part.position().x0()),
63  process_type_(type) {}
ParticleList outgoing_particles_
Initially this stores only the PDG codes of final-state particles.
Definition: action.h:372
ProcessType process_type_
type of process
Definition: action.h:381

◆ Action() [3/4]

smash::Action::Action ( const ParticleList &  in_part,
const ParticleList &  out_part,
double  absolute_execution_time,
ProcessType  type 
)
inline

Construct an action object with the incoming particles, absolute time, and the already known outgoing particles and type of the process.

Parameters
[in]in_partlist of incoming particles
[in]out_partlist of outgoing particles
[in]absolute_execution_timeabsolute time at which the action is supposed to take place
[in]typetype of the interaction

Definition at line 75 of file action.h.

77  : incoming_particles_(std::move(in_part)),
78  outgoing_particles_(std::move(out_part)),
79  time_of_execution_(absolute_execution_time),
80  process_type_(type) {}

◆ Action() [4/4]

smash::Action::Action ( const Action )
delete

Copying is disabled. Use pointers or create a new Action.

◆ ~Action()

smash::Action::~Action ( )
virtualdefault

Virtual Destructor.

Destructor.

The declaration of the destructor is necessary to make it virtual.

Member Function Documentation

◆ operator<()

bool smash::Action::operator< ( const Action rhs) const
inline

Determine whether one action takes place before another in time.

Returns
if the first argument action takes place before the other

Definition at line 96 of file action.h.

96  {
97  return time_of_execution_ < rhs.time_of_execution_;
98  }

◆ get_total_weight()

virtual double smash::Action::get_total_weight ( ) const
pure virtual

Return the total weight value, which is mainly used for the weight output entry.

It has different meanings depending of the type of action. It is the total cross section in case of a ScatterAction, the total decay width in case of a DecayAction and the shining weight in case of a DecayActionDilepton.

Prefer to use a more specific function. If there is no weight for the action type, 0 should be returned.

Returns
total cross section, decay width or shining weight

Implemented in smash::WallcrossingAction, smash::ThermalizationAction, smash::ScatterActionPhoton, smash::ScatterActionMulti, smash::ScatterAction, smash::FreeforallAction, smash::FluidizationAction, smash::DecayActionDilepton, smash::DecayAction, and smash::BremsstrahlungAction.

◆ get_partial_weight()

virtual double smash::Action::get_partial_weight ( ) const
pure virtual

Return the specific weight for the chosen outgoing channel, which is mainly used for the partial weight output entry.

For scatterings it will be the partial cross section, for decays (including dilepton decays) the partial decay width.

If there is no weight for the action type, 0 should be returned.

Returns
specific weight for the chosen output channel.

Implemented in smash::WallcrossingAction, smash::ThermalizationAction, smash::ScatterActionMulti, smash::ScatterAction, smash::FreeforallAction, smash::FluidizationAction, and smash::DecayAction.

◆ get_type()

virtual ProcessType smash::Action::get_type ( ) const
inlinevirtual

Get the process type.

Returns
type of the process

Definition at line 131 of file action.h.

131 { return process_type_; }

◆ add_process()

template<typename Branch >
void smash::Action::add_process ( ProcessBranchPtr< Branch > &  p,
ProcessBranchList< Branch > &  subprocesses,
double &  total_weight 
)
inline

Add a new subprocess.

Parameters
[in]pprocess to be added
[out]subprocessesprocesses, where p is added to
[out]total_weightsummed weights of all the subprocesses

Definition at line 141 of file action.h.

143  {
144  if (p->weight() > 0) {
145  total_weight += p->weight();
146  subprocesses.emplace_back(std::move(p));
147  }
148  }
constexpr int p
Proton.

◆ add_processes()

template<typename Branch >
void smash::Action::add_processes ( ProcessBranchList< Branch >  pv,
ProcessBranchList< Branch > &  subprocesses,
double &  total_weight 
)
inline

Add several new subprocesses at once.

Parameters
[in]pvprocesses list to be added
[out]subprocessesprocesses, where pv are added to
[out]total_weightsummed weights of all the subprocesses

Definition at line 158 of file action.h.

160  {
161  subprocesses.reserve(subprocesses.size() + pv.size());
162  for (auto &proc : pv) {
163  if (proc->weight() > 0) {
164  total_weight += proc->weight();
165  subprocesses.emplace_back(std::move(proc));
166  }
167  }
168  }

◆ generate_final_state()

virtual void smash::Action::generate_final_state ( )
pure virtual

Generate the final state for this action.

This function selects a subprocess by Monte-Carlo decision and sets up the final-state particles in phase space.

Implemented in smash::WallcrossingAction, smash::ThermalizationAction, smash::ScatterActionPhoton, smash::ScatterActionMulti, smash::ScatterAction, smash::FreeforallAction, smash::FluidizationAction, smash::DecayAction, and smash::BremsstrahlungAction.

◆ perform()

double smash::Action::perform ( Particles particles,
uint32_t  id_process 
)
virtual

Actually perform the action, e.g.

carry out a decay or scattering by updating the particle list.

This function removes the initial-state particles from the particle list and then inserts the final-state particles. It does not do any sanity checks, but assumes that is_valid has been called to determine if the action is still valid.

Parameters
[in]id_processunique id of the performed process
[out]particlesparticle list that is updated
Returns
the amount of energy violated in Pythia processes (if any)

Note that you are required to increase id_process before the next call, such that you get unique numbers.

Definition at line 128 of file action.cc.

128  {
129  assert(id_process != 0);
130  double energy_violation = 0.;
131  for (ParticleData &p : outgoing_particles_) {
132  /* Store the history info. Wall crossing and fluidization don't change the
133  * last collision a particle went through. */
134  if ((process_type_ != ProcessType::Wall) &&
136  p.set_history(p.get_history().collisions_per_particle + 1, id_process,
138  }
139  }
140 
141  /* For elastic collisions and box wall crossings it is not necessary to remove
142  * particles from the list and insert new ones, it is enough to update their
143  * properties. */
144  const bool replace = (process_type_ != ProcessType::Elastic) &&
147  particles->update(incoming_particles_, outgoing_particles_, replace);
148 
149  logg[LAction].debug("Particle map now has ", particles->size(), " elements.");
150 
151  /* Check the conservation laws if the modifications of the total kinetic
152  * energy of the outgoing particles by the mean field potentials are not
153  * taken into account. */
154  if (UB_lat_pointer == nullptr && UI3_lat_pointer == nullptr) {
155  energy_violation = check_conservation(id_process);
156  }
157  return energy_violation;
158 }
virtual double check_conservation(const uint32_t id_process) const
Check various conservation laws.
Definition: action.cc:484
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:40
static constexpr int LAction
Definition: action.h:25
@ FluidizationNoRemoval
See here for a short description.
@ Wall
See here for a short description.
@ Elastic
See here for a short description.
RectangularLattice< FourVector > * UB_lat_pointer
Pointer to the skyrme potential on the lattice.
RectangularLattice< FourVector > * UI3_lat_pointer
Pointer to the symmmetry potential on the lattice.

◆ is_valid()

bool smash::Action::is_valid ( const Particles particles) const

Check whether the action still applies.

It can happen that a different action removed the incoming_particles from the set of existing particles in the experiment, or that the particle has scattered elastically in the meantime. In this case the Action doesn't apply anymore and should be discarded.

Parameters
[in]particlescurrent particle list
Returns
true, if action still applies; false otherwise

Definition at line 29 of file action.cc.

29  {
30  return std::all_of(
32  [&particles](const ParticleData &p) { return particles.is_valid(p); });
33 }
bool all_of(Container &&c, UnaryPredicate &&p)
Convenience wrapper for std::all_of that operates on a complete container.
Definition: algorithms.h:80

◆ is_pauli_blocked()

bool smash::Action::is_pauli_blocked ( const std::vector< Particles > &  ensembles,
const PauliBlocker p_bl 
) const

Check if the action is Pauli-blocked.

If there are baryons in the final state then blocking probability is \( 1 - \Pi (1-f_i) \), where the product is taken by all fermions in the final state and \( f_i \) denotes the phase-space density at the position of i-th final-state fermion.

Parameters
[in]ensemblescurrent particle list, all ensembles
[in]p_blPauliBlocker that stores the configurations concerning Pauli-blocking.
Returns
true, if the action is Pauli-blocked, false otherwise

Definition at line 35 of file action.cc.

36  {
37  // Wall-crossing actions should never be blocked: currently
38  // if the action is blocked, a particle continues to propagate in a straight
39  // line. This would simply bring it out of the box.
41  return false;
42  }
43  for (const auto &p : outgoing_particles_) {
44  if (p.is_baryon()) {
45  const auto f =
46  p_bl.phasespace_dens(p.position().threevec(), p.momentum().threevec(),
47  ensembles, p.pdgcode(), incoming_particles_);
48  if (f > random::uniform(0., 1.)) {
49  logg[LPauliBlocking].debug("Action ", *this,
50  " is pauli-blocked with f = ", f);
51  return true;
52  }
53  }
54  }
55  return false;
56 }
T uniform(T min, T max)
Definition: random.h:88
static constexpr int LPauliBlocking
Definition: action.cc:27

◆ incoming_particles()

const ParticleList & smash::Action::incoming_particles ( ) const

Get the list of particles that go into the action.

Returns
a list of incoming particles

Definition at line 58 of file action.cc.

58  {
59  return incoming_particles_;
60 }

◆ update_incoming()

void smash::Action::update_incoming ( const Particles particles)

Update the incoming particles that are stored in this action to the state they have in the global particle list.

Parameters
[in]particlescurrent particle list

Definition at line 62 of file action.cc.

62  {
63  for (auto &p : incoming_particles_) {
64  p = particles.lookup(p);
65  }
66 }

◆ outgoing_particles()

const ParticleList& smash::Action::outgoing_particles ( ) const
inline

Get the list of particles that resulted from the action.

Returns
list of outgoing particles

Definition at line 247 of file action.h.

247 { return outgoing_particles_; }

◆ time_of_execution()

double smash::Action::time_of_execution ( ) const
inline

Get the time at which the action is supposed to be performed.

Returns
absolute time in the calculation frame in fm

Definition at line 254 of file action.h.

254 { return time_of_execution_; }

◆ check_conservation()

double smash::Action::check_conservation ( const uint32_t  id_process) const
virtual

Check various conservation laws.

Parameters
[in]id_processprocess id only used for debugging output
Returns
the amount of energy conservation violated by Pythia processes (if any)

Reimplemented in smash::FluidizationAction.

Definition at line 484 of file action.cc.

484  {
485  QuantumNumbers before(incoming_particles_);
486  QuantumNumbers after(outgoing_particles_);
487  double energy_violation = 0.;
488  if (before != after) {
489  std::stringstream particle_names;
490  for (const auto &p : incoming_particles_) {
491  particle_names << p.type().name();
492  }
493  particle_names << " vs. ";
494  for (const auto &p : outgoing_particles_) {
495  particle_names << p.type().name();
496  }
497  particle_names << "\n";
498  std::string err_msg = before.report_deviations(after);
499  /* Pythia does not conserve energy and momentum at high energy, so we just
500  * print the warning and continue. */
503  logg[LAction].warn() << "Conservation law violations due to Pythia\n"
504  << particle_names.str() << err_msg;
505  energy_violation = after.momentum()[0] - before.momentum()[0];
506  return energy_violation;
507  }
508  /* We allow decay of particles stable under the strong interaction to decay
509  * at the end, so just warn about such a "weak" process violating
510  * conservation laws */
512  incoming_particles_[0].type().is_stable()) {
513  logg[LAction].warn()
514  << "Conservation law violations of strong interaction in weak or "
515  "e.m. decay\n"
516  << particle_names.str() << err_msg;
517  return energy_violation;
518  }
519  /* If particles are added or removed, it is not surprising that conservation
520  * laws are potentially violated. Do not warn the user but print some
521  * information for debug */
523  logg[LAction].debug()
524  << "Conservation law violation, but we want it (Freeforall Action).\n"
525  << particle_names.str() << err_msg;
526  return energy_violation;
527  }
528  logg[LAction].error() << "Conservation law violations detected\n"
529  << particle_names.str() << err_msg;
530  if (id_process == ID_PROCESS_PHOTON) {
531  throw std::runtime_error("Conservation laws violated in photon process");
532  } else {
533  throw std::runtime_error("Conservation laws violated in process " +
534  std::to_string(id_process));
535  }
536  }
537  return energy_violation;
538 }
constexpr std::uint32_t ID_PROCESS_PHOTON
Process ID for any photon process.
Definition: constants.h:122
@ Freeforall
See here for a short description.
@ Decay
See here for a short description.
@ StringHard
See here for a short description.
std::string to_string(ThermodynamicQuantity quantity)
Convert a ThermodynamicQuantity enum value to its corresponding string.
Definition: stringify.cc:26
bool is_string_soft_process(ProcessType p)
Check if a given process type is a soft string excitation.

◆ sqrt_s()

double smash::Action::sqrt_s ( ) const
inline

Determine the total energy in the center-of-mass frame [GeV].

Returns
\( \sqrt{s}\) of incoming particles

Definition at line 271 of file action.h.

271 { return total_momentum().abs(); }
FourVector total_momentum() const
Sum of 4-momenta of incoming particles.
Definition: action.h:398
double abs() const
calculate the lorentz invariant absolute value
Definition: fourvector.h:464

◆ total_momentum_of_outgoing_particles()

FourVector smash::Action::total_momentum_of_outgoing_particles ( ) const

Calculate the total kinetic momentum of the outgoing particles.

Use this to determine the momemtum and boost of the outgoing particles by calcluating the total momentum of the incoming particles and correcting it for the effect of potentials. This function is used when the species of the outgoing particles are already determined.

Returns
total kinetic momentum of the outgoing particles [GeV]

Definition at line 160 of file action.cc.

160  {
161  const auto potentials = get_potential_at_interaction_point();
162  /* scale_B returns the difference of the total force scales of the skyrme
163  * potential between the initial and final states. */
164  double scale_B = 0.0;
165  /* scale_I3 returns the difference of the total force scales of the symmetry
166  * potential between the initial and final states. */
167  double scale_I3 = 0.0;
168  for (const auto &p_in : incoming_particles_) {
169  // Get the force scale of the incoming particle.
170  const auto scale =
171  ((pot_pointer != nullptr) ? pot_pointer->force_scale(p_in.type())
172  : std::make_pair(0.0, 0));
173  scale_B += scale.first;
174  scale_I3 += scale.second * p_in.type().isospin3_rel();
175  }
176  for (const auto &p_out : outgoing_particles_) {
177  // Get the force scale of the outgoing particle.
178  const auto scale = ((pot_pointer != nullptr)
180  : std::make_pair(0.0, 0));
181  scale_B -= scale.first;
182  scale_I3 -= scale.second * type_of_pout(p_out).isospin3_rel();
183  }
184  /* Rescale to get the potential difference between the
185  * initial and final state, and thus get the total momentum
186  * of the outgoing particles*/
187  return total_momentum() + potentials.first * scale_B +
188  potentials.second * scale_I3;
189 }
std::pair< FourVector, FourVector > get_potential_at_interaction_point() const
Get the skyrme and asymmetry potential at the interaction point.
Definition: action.cc:112
const ParticleType & type_of_pout(const ParticleData &p_out) const
Get the type of a given particle.
Definition: action.h:517
double isospin3_rel() const
Definition: particletype.h:180
static std::pair< double, int > force_scale(const ParticleType &data)
Evaluates the scaling factor of the forces acting on the particles.
Definition: potentials.cc:158
Potentials * pot_pointer
Pointer to a Potential class.

◆ get_interaction_point()

FourVector smash::Action::get_interaction_point ( ) const

Get the interaction point.

Returns
four vector of interaction point

Definition at line 68 of file action.cc.

68  {
69  // Estimate for the interaction point in the calculational frame
70  ThreeVector interaction_point = ThreeVector(0., 0., 0.);
71  std::vector<ThreeVector> propagated_positions;
72  for (const auto &part : incoming_particles_) {
73  ThreeVector propagated_position =
74  part.position().threevec() +
75  part.velocity() * (time_of_execution_ - part.position().x0());
76  propagated_positions.push_back(propagated_position);
77  interaction_point += propagated_position;
78  }
79  interaction_point /= incoming_particles_.size();
80  /*
81  * In case of periodic boundaries interaction point is not necessarily
82  * (x1 + x2)/2. Consider only one dimension, e.g. x, the rest are analogous.
83  * Instead of x, there can be x + k * L, where k is any integer and L
84  * is period.Interaction point is either. Therefore, interaction point is
85  * (x1 + k * L + x2 + m * L) / 2 = (x1 + x2) / 2 + n * L / 2. We need
86  * this interaction point to be with [0, L], so n can be {-1, 0, 1}.
87  * Which n to choose? Our guiding principle is that n should be such that
88  * interaction point is closest to interacting particles.
89  */
90  if (box_length_ > 0 && stochastic_position_idx_ < 0) {
91  assert(incoming_particles_.size() == 2);
92  const ThreeVector r = propagated_positions[0] - propagated_positions[1];
93  for (int i = 0; i < 3; i++) {
94  const double d = std::abs(r[i]);
95  if (d > 0.5 * box_length_) {
96  if (interaction_point[i] >= 0.5 * box_length_) {
97  interaction_point[i] -= 0.5 * box_length_;
98  } else {
99  interaction_point[i] += 0.5 * box_length_;
100  }
101  }
102  }
103  }
104  /* In case of scatterings via the stochastic criterion, use postion of random
105  * incoming particle to prevent density hotspots in grid cell centers. */
106  if (stochastic_position_idx_ >= 0) {
108  }
109  return FourVector(time_of_execution_, interaction_point);
110 }
int stochastic_position_idx_
This stores a randomly-chosen index to an incoming particle.
Definition: action.h:395
double box_length_
Box length: needed to determine coordinates of collision correctly in case of collision through the w...
Definition: action.h:388

◆ get_potential_at_interaction_point()

std::pair< FourVector, FourVector > smash::Action::get_potential_at_interaction_point ( ) const

Get the skyrme and asymmetry potential at the interaction point.

Returns
skyrme and asymmetry potential [GeV]

Definition at line 112 of file action.cc.

113  {
114  const ThreeVector r = get_interaction_point().threevec();
115  FourVector UB = FourVector();
116  FourVector UI3 = FourVector();
117  /* Check:
118  * Lattice is turned on. */
119  if (UB_lat_pointer != nullptr) {
120  UB_lat_pointer->value_at(r, UB);
121  }
122  if (UI3_lat_pointer != nullptr) {
123  UI3_lat_pointer->value_at(r, UI3);
124  }
125  return std::make_pair(UB, UI3);
126 }
FourVector get_interaction_point() const
Get the interaction point.
Definition: action.cc:68
ThreeVector threevec() const
Definition: fourvector.h:329

◆ set_stochastic_pos_idx()

void smash::Action::set_stochastic_pos_idx ( )
inline

Setter function that stores a random incoming particle index latter used to determine the interaction point.

Definition at line 303 of file action.h.

303  {
304  const int max_inc_idx = incoming_particles_.size() - 1;
306  }
T uniform_int(T min, T max)
Definition: random.h:100

◆ lambda_tilde()

static double smash::Action::lambda_tilde ( double  a,
double  b,
double  c 
)
inlinestatic

Little helper function that calculates the lambda function (sometimes written with a tilde to better distinguish it) that appears e.g.

in the relative velocity or 3-to-2 probability calculation, where it is used with a=s, b=m1^2 and c=m2^2. Defintion found e.g. in Seifert:2017oyb [55], eq. (5).

Definition at line 315 of file action.h.

315  {
316  const double res = (a - b - c) * (a - b - c) - 4. * b * c;
317  if (res < 0.0) {
318  // floating point precision problem
319  return 0.0;
320  }
321  return res;
322  }

◆ sample_manybody_phasespace_impl()

void smash::Action::sample_manybody_phasespace_impl ( double  sqrts,
const std::vector< double > &  m,
std::vector< FourVector > &  sampled_momenta 
)
static

Implementation of the full n-body phase-space sampling (masses, momenta, angles) in the center-of-mass frame for the final state particles.

Function is static for convenient testing.

Using the M-method from CERN-68-15 report, paragraph 9.6 1) Generate invariant masses M12, M123, M1234, etc from distribution dM12 x dM123 x dM1234 x ... This is not trivial because of the integration limits. Here the idea is to change variables to T12 = M12 - (m1 + m2), T123 = M123 - (m1 + m2 + m3), etc. Then we need to generate uniform T such that 0 <= T12 <= T123 <= T1234 <= ... <= sqrts - sum (m_i). For the latter there is a trick: generate values uniformly in [0, sqrts - sum (m_i)] and then sort the values. 2) accept or reject this combination of invariant masses with weight proportional to R2(sqrt, M_{n-1}, m_n) x R2(M_{n-1}, M_{n-2}, m_{n-1}) x ... x R2(M2, m1, m2) x (prod M_i). Maximum weight is estmated heuristically, here I'm using an idea by Scott Pratt that maximum is close to T12 = T123 = T1234 = ... = (sqrts - sum (m_i)) / (n - 1)

Definition at line 316 of file action.cc.

318  {
335  const size_t n = m.size();
336  assert(n > 1);
337  sampled_momenta.resize(n);
338 
339  // Arrange a convenient vector of m1, m1 + m2, m1 + m2 + m3, ...
340  std::vector<double> msum(n);
341  std::partial_sum(m.begin(), m.end(), msum.begin());
342  const double msum_all = msum[n - 1];
343  int rejection_counter = -1;
344  if (sqrts <= msum_all) {
345  logg[LAction].error()
346  << "An interaction requiring " << sqrts
347  << "GeV was attempted below the minimum energy threshold" << msum_all
348  << " GeV, but was ignored.\nThis is a known internal error which does "
349  "not significantly affect physical results, and will be fixed in a "
350  "near-future release.";
351  throw StochasticBelowEnergyThreshold("Ignoring this action.");
352  }
353 
354  double w, r01;
355  std::vector<double> Minv(n);
356 
357  double weight_sqr_max = 1;
358  const double Ekin_share = (sqrts - msum_all) / (n - 1);
359  for (size_t i = 1; i < n; i++) {
360  // This maximum estimate idea is due Scott Pratt: maximum should be
361  // roughly at equal kinetic energies
362  weight_sqr_max *= pCM_sqr(i * Ekin_share + msum[i],
363  (i - 1) * Ekin_share + msum[i - 1], m[i]);
364  }
365  // Maximum estimate is rough and can be wrong. We multiply it by additional
366  // factor to be on the safer side.
367  const double safety_factor = 1.1 + (n - 2) * 0.2;
368  weight_sqr_max *= (safety_factor * safety_factor);
369  bool first_warning = true;
370 
371  do {
372  // Generate invariant masses of 1, 12, 123, 1243, etc.
373  // Minv = {m1, M12, M123, ..., M123n-1, sqrts}
374  Minv[0] = 0.0;
375  Minv[n - 1] = sqrts - msum_all;
376  for (size_t i = 1; i < n - 1; i++) {
377  Minv[i] = random::uniform(0.0, sqrts - msum_all);
378  }
379  std::sort(Minv.begin(), Minv.end());
380  for (size_t i = 0; i < n; i++) {
381  Minv[i] += msum[i];
382  }
383 
384  double weight_sqr = 1;
385  for (size_t i = 1; i < n; i++) {
386  weight_sqr *= pCM_sqr(Minv[i], Minv[i - 1], m[i]);
387  }
388 
389  rejection_counter++;
390  r01 = random::canonical();
391  w = weight_sqr / weight_sqr_max;
392  if (w > 1.0) {
393  logg[LAction].warn()
394  << "sample_manybody_phasespace_impl: alarm, weight > 1, w^2 = " << w
395  << ". Increase safety factor." << std::endl;
396  }
397  if (rejection_counter > 20 && first_warning) {
398  logg[LAction].warn() << "sample_manybody_phasespace_impl: "
399  << "likely hanging, way too many rejections,"
400  << " n = " << n << ", sqrts = " << sqrts
401  << ", msum = " << msum_all;
402  first_warning = false;
403  }
404  } while (w < r01 * r01);
405 
406  // Boost particles to the right frame
407  std::vector<ThreeVector> beta(n);
408  for (size_t i = n - 1; i > 0; i--) {
409  const double pcm = pCM(Minv[i], Minv[i - 1], m[i]);
410  Angles phitheta;
411  phitheta.distribute_isotropically();
412  const ThreeVector isotropic_unitvector = phitheta.threevec();
413  sampled_momenta[i] = FourVector(std::sqrt(m[i] * m[i] + pcm * pcm),
414  pcm * isotropic_unitvector);
415  if (i >= 2) {
416  beta[i - 2] = pcm * isotropic_unitvector /
417  std::sqrt(pcm * pcm + Minv[i - 1] * Minv[i - 1]);
418  }
419  if (i == 1) {
420  sampled_momenta[0] = FourVector(std::sqrt(m[0] * m[0] + pcm * pcm),
421  -pcm * isotropic_unitvector);
422  }
423  }
424 
425  for (size_t i = 0; i < n - 2; i++) {
426  // After each boost except the last one the sum of 3-momenta should be 0
427  FourVector ptot = FourVector(0.0, 0.0, 0.0, 0.0);
428  for (size_t j = 0; j <= i + 1; j++) {
429  ptot += sampled_momenta[j];
430  }
431  logg[LAction].debug() << "Total momentum of 0.." << i + 1 << " = "
432  << ptot.threevec() << " and should be (0, 0, 0). "
433  << std::endl;
434 
435  // Boost the first i+1 particles to the next CM frame
436  for (size_t j = 0; j <= i + 1; j++) {
437  sampled_momenta[j] = sampled_momenta[j].lorentz_boost(beta[i]);
438  }
439  }
440 
441  FourVector ptot_all = FourVector(0.0, 0.0, 0.0, 0.0);
442  for (size_t j = 0; j < n; j++) {
443  ptot_all += sampled_momenta[j];
444  }
445  logg[LAction].debug() << "Total 4-momentum = " << ptot_all << ", should be ("
446  << sqrts << ", 0, 0, 0)" << std::endl;
447 }
constexpr int n
Neutron.
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of is .
Definition: random.h:329
T canonical()
Definition: random.h:113
T pCM(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:79
T pCM_sqr(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:91

◆ assign_unpolarized_spin_vector_to_outgoing_particles()

void smash::Action::assign_unpolarized_spin_vector_to_outgoing_particles ( )

Assign an unpolarized spin vector to all outgoing particles.

Attention
Make sure to assign the spin vectors after the boosted 4-momentum of the outgoing particles has been set, as the function includes a boost to the lab frame.

Definition at line 478 of file action.cc.

478  {
479  for (ParticleData &p : outgoing_particles_) {
480  p.set_unpolarized_spin_vector();
481  }
482 }

◆ total_momentum()

FourVector smash::Action::total_momentum ( ) const
inlineprotected

Sum of 4-momenta of incoming particles.

Definition at line 398 of file action.h.

398  {
399  FourVector mom(0.0, 0.0, 0.0, 0.0);
400  for (const auto &p : incoming_particles_) {
401  mom += p.momentum();
402  }
403  return mom;
404  }

◆ choose_channel()

template<typename Branch >
const Branch* smash::Action::choose_channel ( const ProcessBranchList< Branch > &  subprocesses,
double  total_weight 
)
inlineprotected

Decide for a particular final-state channel via Monte-Carlo and return it as a ProcessBranch.

Template Parameters
BranchType of processbranch
Parameters
[in]subprocesseslist of possible processes
[in]total_weightsummed weight of all processes
Returns
ProcessBranch that is sampled

Definition at line 416 of file action.h.

417  {
418  double random_weight = random::uniform(0., total_weight);
419  double weight_sum = 0.;
420  /* Loop through all subprocesses and select one by Monte Carlo, based on
421  * their weights. */
422  for (const auto &proc : subprocesses) {
423  weight_sum += proc->weight();
424  if (random_weight <= weight_sum) {
425  /* Return the full process information. */
426  return proc.get();
427  }
428  }
429  /* Should never get here. */
431  "Problem in choose_channel: ", subprocesses.size(), " ",
432  weight_sum, " ", total_weight, " ", random_weight, "\n",
433  *this);
434  std::abort();
435  }
#define SMASH_SOURCE_LOCATION
Hackery that is required to output the location in the source code where the log statement occurs.
Definition: logging.h:153

◆ sample_masses()

std::pair< double, double > smash::Action::sample_masses ( double  kinetic_energy_cm) const
protectedvirtual

Sample final-state masses in general X->2 processes (thus also fixing the absolute c.o.m.

momentum).

Parameters
[in]kinetic_energy_cmtotal kinetic energy of the outgoing particles in their center of mass frame [GeV]
Exceptions
InvalidResonanceFormation
Returns
masses of final state particles

Reimplemented in smash::DecayAction.

Definition at line 253 of file action.cc.

254  {
255  const ParticleType &t_a = outgoing_particles_[0].type();
256  const ParticleType &t_b = outgoing_particles_[1].type();
257  // start with pole masses
258  std::pair<double, double> masses = {t_a.mass(), t_b.mass()};
259 
260  if (kinetic_energy_cm < t_a.min_mass_kinematic() + t_b.min_mass_kinematic()) {
261  const std::string reaction = incoming_particles_[0].type().name() +
262  incoming_particles_[1].type().name() + "→" +
263  t_a.name() + t_b.name();
264  throw InvalidResonanceFormation(
265  reaction + ": not enough energy, " + std::to_string(kinetic_energy_cm) +
266  " < " + std::to_string(t_a.min_mass_kinematic()) + " + " +
267  std::to_string(t_b.min_mass_kinematic()));
268  }
269 
270  /* If one of the particles is a resonance, sample its mass. */
271  if (!t_a.is_stable() && t_b.is_stable()) {
272  masses.first = t_a.sample_resonance_mass(t_b.mass(), kinetic_energy_cm);
273  } else if (!t_b.is_stable() && t_a.is_stable()) {
274  masses.second = t_b.sample_resonance_mass(t_a.mass(), kinetic_energy_cm);
275  } else if (!t_a.is_stable() && !t_b.is_stable()) {
276  // two resonances in final state
277  masses = t_a.sample_resonance_masses(t_b, kinetic_energy_cm);
278  }
279  return masses;
280 }

◆ sample_angles()

void smash::Action::sample_angles ( std::pair< double, double >  masses,
double  kinetic_energy_cm 
)
protectedvirtual

Sample final-state momenta in general X->2 processes (here: using an isotropical angular distribution).

Parameters
[in]kinetic_energy_cmtotal kinetic energy of the outgoing particles in their center of mass frame [GeV]
[in]massesmasses of each of the final state particles

Reimplemented in smash::ScatterAction.

Definition at line 282 of file action.cc.

283  {
284  ParticleData *p_a = &outgoing_particles_[0];
285  ParticleData *p_b = &outgoing_particles_[1];
286 
287  const double pcm = pCM(kinetic_energy_cm, masses.first, masses.second);
288  if (!(pcm > 0.0)) {
289  logg[LAction].warn("Particle: ", p_a->pdgcode(), " radial momentum: ", pcm);
290  logg[LAction].warn("Ektot: ", kinetic_energy_cm, " m_a: ", masses.first,
291  " m_b: ", masses.second);
292  }
293  /* Here we assume an isotropic angular distribution. */
294  Angles phitheta;
295  phitheta.distribute_isotropically();
296 
297  p_a->set_4momentum(masses.first, phitheta.threevec() * pcm);
298  p_b->set_4momentum(masses.second, -phitheta.threevec() * pcm);
299  /* Debug message is printed before boost, so that p_a and p_b are
300  * the momenta in the center of mass frame and thus opposite to
301  * each other.*/
302  logg[LAction].debug("p_a: ", *p_a, "\np_b: ", *p_b);
303 }

◆ sample_2body_phasespace()

void smash::Action::sample_2body_phasespace ( )
protectedvirtual

Sample the full 2-body phase-space (masses, momenta, angles) in the center-of-mass frame for the final state particles.

Reimplemented in smash::DecayAction.

Definition at line 305 of file action.cc.

305  {
306  /* This function only operates on 2-particle final states. */
307  assert(outgoing_particles_.size() == 2);
308  const FourVector p_tot = total_momentum_of_outgoing_particles();
309  const double cm_kin_energy = p_tot.abs();
310  // first sample the masses
311  const std::pair<double, double> masses = sample_masses(cm_kin_energy);
312  // after the masses are fixed (and thus also pcm), sample the angles
313  sample_angles(masses, cm_kin_energy);
314 }
FourVector total_momentum_of_outgoing_particles() const
Calculate the total kinetic momentum of the outgoing particles.
Definition: action.cc:160
virtual void sample_angles(std::pair< double, double > masses, double kinetic_energy_cm)
Sample final-state momenta in general X->2 processes (here: using an isotropical angular distribution...
Definition: action.cc:282
virtual std::pair< double, double > sample_masses(double kinetic_energy_cm) const
Sample final-state masses in general X->2 processes (thus also fixing the absolute c....
Definition: action.cc:253

◆ sample_manybody_phasespace()

void smash::Action::sample_manybody_phasespace ( )
protectedvirtual

Sample the full n-body phase-space (masses, momenta, angles) in the center-of-mass frame for the final state particles.

Exceptions
std::invalid_argumentif one outgoing particle is a resonance

Reimplemented in smash::DecayActionDilepton.

Definition at line 449 of file action.cc.

449  {
450  const size_t n = outgoing_particles_.size();
451  if (n < 3) {
452  throw std::invalid_argument(
453  "sample_manybody_phasespace: number of outgoing particles should be 3 "
454  "or more");
455  }
456  bool all_stable = true;
457  for (size_t i = 0; i < n; i++) {
458  all_stable = all_stable && outgoing_particles_[i].type().is_stable();
459  }
460  if (!all_stable) {
461  throw std::invalid_argument(
462  "sample_manybody_phasespace: Found resonance in to be sampled outgoing "
463  "particles, but assumes stable particles.");
464  }
465 
466  std::vector<double> m(n);
467  for (size_t i = 0; i < n; i++) {
468  m[i] = outgoing_particles_[i].type().mass();
469  }
470  std::vector<FourVector> p(n);
471 
473  for (size_t i = 0; i < n; i++) {
474  outgoing_particles_[i].set_4momentum(p[i]);
475  }
476 }
double sqrt_s() const
Determine the total energy in the center-of-mass frame [GeV].
Definition: action.h:271
static void sample_manybody_phasespace_impl(double sqrts, const std::vector< double > &m, std::vector< FourVector > &sampled_momenta)
Implementation of the full n-body phase-space sampling (masses, momenta, angles) in the center-of-mas...
Definition: action.cc:316

◆ assign_formation_time_to_outgoing_particles()

void smash::Action::assign_formation_time_to_outgoing_particles ( )
protected

Assign the formation time to the outgoing particles.

The formation time is set to the largest formation time of the incoming particles, if it is larger than the execution time. The newly produced particles are supposed to continue forming exactly like the latest forming ingoing particle. Therefore the details on the formation are adopted. The initial cross section scaling factor of the incoming particles is considered to also be the scaling factor of the newly produced outgoing particles. If the formation time is smaller than the exectution time, the execution time is taken to be the formation time.

Note: Make sure to assign the formation times before boosting the outgoing particles to the computational frame.

Definition at line 191 of file action.cc.

191  {
192  /* Find incoming particle with largest formation time i.e. the last formed
193  * incoming particle. If all particles form at the same time, take the one
194  * with the lowest cross section scaling factor */
195  ParticleList::iterator last_formed_in_part;
196  bool all_incoming_same_formation_time =
198  [&](const ParticleData &data_comp) {
199  return std::abs(incoming_particles_[0].formation_time() -
200  data_comp.formation_time()) < really_small;
201  });
202  if (all_incoming_same_formation_time) {
203  last_formed_in_part =
204  std::min_element(incoming_particles_.begin(), incoming_particles_.end(),
205  [](const ParticleData &a, const ParticleData &b) {
206  return a.initial_xsec_scaling_factor() <
207  b.initial_xsec_scaling_factor();
208  });
209  } else {
210  last_formed_in_part =
211  std::max_element(incoming_particles_.begin(), incoming_particles_.end(),
212  [](const ParticleData &a, const ParticleData &b) {
213  return a.formation_time() < b.formation_time();
214  });
215  }
216 
217  const double form_time_begin = last_formed_in_part->begin_formation_time();
218  const double sc = last_formed_in_part->initial_xsec_scaling_factor();
219 
220  if (last_formed_in_part->formation_time() > time_of_execution_) {
221  for (ParticleData &new_particle : outgoing_particles_) {
222  if (new_particle.initial_xsec_scaling_factor() < 1.0) {
223  /* The new cross section scaling factor will be the product of the
224  * cross section scaling factor of the ingoing particles and of the
225  * outgoing ones (since the outgoing ones are also string fragments
226  * and thus take time to form). */
227  double sc_out = new_particle.initial_xsec_scaling_factor();
228  new_particle.set_cross_section_scaling_factor(sc * sc_out);
229  if (last_formed_in_part->formation_time() >
230  new_particle.formation_time()) {
231  /* If the unformed incoming particles' formation time is larger than
232  * the current outgoing particle's formation time, then the latter
233  * is overwritten by the former*/
234  new_particle.set_slow_formation_times(
235  time_of_execution_, last_formed_in_part->formation_time());
236  }
237  } else {
238  // not a string product
239  new_particle.set_slow_formation_times(
240  form_time_begin, last_formed_in_part->formation_time());
241  new_particle.set_cross_section_scaling_factor(sc);
242  }
243  }
244  } else {
245  for (ParticleData &new_particle : outgoing_particles_) {
246  if (new_particle.initial_xsec_scaling_factor() == 1.0) {
247  new_particle.set_formation_time(time_of_execution_);
248  }
249  }
250  }
251 }

◆ type_of_pout() [1/2]

const ParticleType& smash::Action::type_of_pout ( const ParticleData p_out) const
inlineprivate

Get the type of a given particle.

Parameters
[in]p_outparticle of which the type will be returned
Returns
type of given particle

Definition at line 517 of file action.h.

517  {
518  return p_out.type();
519  }

◆ type_of_pout() [2/2]

const ParticleType& smash::Action::type_of_pout ( const ParticleTypePtr p_out) const
inlineprivate

Get the particle type for given pointer to a particle type.

Helper function for total_momentum_of_outgoing_particles

Parameters
[in]p_outpointer to a particle type
Returns
particle type

Definition at line 528 of file action.h.

528  {
529  return *p_out;
530  }

Member Data Documentation

◆ incoming_particles_

ParticleList smash::Action::incoming_particles_
protected

List with data of incoming particles.

Definition at line 364 of file action.h.

◆ outgoing_particles_

ParticleList smash::Action::outgoing_particles_
protected

Initially this stores only the PDG codes of final-state particles.

After perform was called it contains the complete particle data of the outgoing particles.

Definition at line 372 of file action.h.

◆ time_of_execution_

const double smash::Action::time_of_execution_
protected

Time at which the action is supposed to be performed (absolute time in the lab frame in fm).

Definition at line 378 of file action.h.

◆ process_type_

ProcessType smash::Action::process_type_
protected

type of process

Definition at line 381 of file action.h.

◆ box_length_

double smash::Action::box_length_ = -1.0
protected

Box length: needed to determine coordinates of collision correctly in case of collision through the wall.

Ignored if negative.

Definition at line 388 of file action.h.

◆ stochastic_position_idx_

int smash::Action::stochastic_position_idx_ = -1
protected

This stores a randomly-chosen index to an incoming particle.

If non-negative, the the interaction point equals the postion of the chosen particle (index). This is done for the stochastic criterion.

Definition at line 395 of file action.h.


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