35 [&particles](
const ParticleData &
p) { return particles.is_valid(p); });
53 " is pauli-blocked with f = ", f);
74 std::vector<ThreeVector> propagated_positions;
77 part.position().threevec() +
79 propagated_positions.push_back(propagated_position);
80 interaction_point += propagated_position;
95 const ThreeVector r = propagated_positions[0] - propagated_positions[1];
96 for (
int i = 0; i < 3; i++) {
97 const double d = std::abs(r[i]);
128 return std::make_pair(UB, UI3);
132 assert(id_process != 0);
133 double energy_violation = 0.;
139 p.set_history(
p.get_history().collisions_per_particle + 1, id_process,
152 logg[
LAction].debug(
"Particle map now has ", particles->
size(),
" elements.");
160 return energy_violation;
167 double scale_B = 0.0;
170 double scale_I3 = 0.0;
175 : std::make_pair(0.0, 0));
176 scale_B += scale.first;
177 scale_I3 += scale.second * p_in.type().isospin3_rel();
183 : std::make_pair(0.0, 0));
184 scale_B -= scale.first;
198 ParticleList::iterator last_formed_in_part;
199 bool all_incoming_same_formation_time =
202 return std::abs(incoming_particles_[0].formation_time() -
203 data_comp.formation_time()) < really_small;
205 if (all_incoming_same_formation_time) {
206 last_formed_in_part =
209 return a.initial_xsec_scaling_factor() <
210 b.initial_xsec_scaling_factor();
213 last_formed_in_part =
216 return a.formation_time() < b.formation_time();
220 const double form_time_begin = last_formed_in_part->begin_formation_time();
221 const double sc = last_formed_in_part->initial_xsec_scaling_factor();
225 if (new_particle.initial_xsec_scaling_factor() < 1.0) {
230 double sc_out = new_particle.initial_xsec_scaling_factor();
231 new_particle.set_cross_section_scaling_factor(sc * sc_out);
232 if (last_formed_in_part->formation_time() >
233 new_particle.formation_time()) {
237 new_particle.set_slow_formation_times(
242 new_particle.set_slow_formation_times(
243 form_time_begin, last_formed_in_part->formation_time());
244 new_particle.set_cross_section_scaling_factor(sc);
249 if (new_particle.initial_xsec_scaling_factor() == 1.0) {
257 const double kinetic_energy_cm)
const {
261 std::pair<double, double> masses = {t_a.
mass(), t_b.
mass()};
268 reaction +
": not enough energy, " +
std::to_string(kinetic_energy_cm) +
286 const double kinetic_energy_cm) {
290 const double pcm =
pCM(kinetic_energy_cm, masses.first, masses.second);
293 logg[
LAction].warn(
"Ektot: ", kinetic_energy_cm,
" m_a: ", masses.first,
294 " m_b: ", masses.second);
305 logg[
LAction].debug(
"p_a: ", *p_a,
"\np_b: ", *p_b);
312 const double cm_kin_energy = p_tot.
abs();
314 const std::pair<double, double> masses =
sample_masses(cm_kin_energy);
322 throw std::invalid_argument(
323 "sample_manybody_phasespace: number of outgoing particles should be 3 "
327 ParticleTypePtrList types(
n);
328 for (
size_t i = 0; i <
n; i++) {
331 std::vector<FourVector>
p(
n);
334 for (
size_t i = 0; i <
n; i++) {
341 p.set_unpolarized_spin_vector();
348 double energy_violation = 0.;
349 if (before != after) {
350 std::stringstream particle_names;
352 particle_names <<
p.type().name();
354 particle_names <<
" vs. ";
356 particle_names <<
p.type().name();
358 particle_names <<
"\n";
363 logg[
LAction].warn() <<
"Conservation law violations due to Pythia\n"
364 << particle_names.str() << err_msg;
366 return energy_violation;
374 <<
"Conservation law violations of strong interaction in weak or "
376 << particle_names.str() << err_msg;
377 return energy_violation;
384 <<
"Conservation law violation, but we want it (Freeforall Action).\n"
385 << particle_names.str() << err_msg;
386 return energy_violation;
388 logg[
LAction].error() <<
"Conservation law violations detected\n"
389 << particle_names.str() << err_msg;
391 throw std::runtime_error(
"Conservation laws violated in photon process");
393 throw std::runtime_error(
"Conservation laws violated in process " +
397 return energy_violation;
400 std::ostream &
operator<<(std::ostream &out,
const ActionList &actions) {
401 out <<
"ActionList {\n";
402 for (
const auto &a : actions) {
403 out <<
"- " << a <<
'\n';
411 const ParticleTypePtrList &types,
412 std::vector<FourVector> &sampled_momenta) {
413 const size_t n = types.size();
415 sampled_momenta.resize(
n);
416 std::vector<double> masses{}, masses_sum(
n), Minv(
n);
419 double safety_factor = 1.1 + (
n - 2) * 0.2;
420 int rejection_counter = 0;
421 constexpr
int rejection_limit = 200;
422 double available_energy =
423 sqrts - std::accumulate(types.begin(), types.end(), 0.0,
425 return sum + type->min_mass_spectral();
427 double acceptance = 1;
431 safety_factor *= std::sqrt(acceptance);
434 double weight_sqr_max = safety_factor * safety_factor;
437 for (
const auto &type : types) {
439 masses.push_back(type->
mass());
443 const double max_ratio = std::max(
446 weight_sqr_max *= max_ratio * max_ratio;
450 std::partial_sum(masses.begin(), masses.end(),
451 std::back_inserter(masses_sum));
452 const double masses_sum_all = masses_sum[
n - 1];
453 const double Ekin_share = (sqrts - masses_sum_all) / (
n - 1);
454 for (
size_t i = 1; i <
n; i++) {
458 pCM_sqr(i * Ekin_share + masses_sum[i],
459 (i - 1) * Ekin_share + masses_sum[i - 1], masses[i]);
464 Minv[
n - 1] = sqrts - masses_sum_all;
465 for (
size_t i = 1; i <
n - 1; i++) {
468 std::sort(Minv.begin(), Minv.end());
469 for (
size_t i = 0; i <
n; i++) {
470 Minv[i] += masses_sum[i];
473 double weight_sqr = 1;
474 for (
size_t i = 0; i <
n; i++) {
476 types[i]->is_stable()
478 : types[i]->ratio_spectral_full_to_breit_wigner(masses[i]);
479 weight_sqr *= ratio * ratio;
481 for (
size_t i = 1; i <
n; i++) {
482 weight_sqr *=
pCM_sqr(Minv[i], Minv[i - 1], masses[i]);
484 acceptance = weight_sqr / weight_sqr_max;
487 }
while (acceptance < random_01 * random_01 &&
488 rejection_counter < rejection_limit);
489 if (acceptance > 1) {
491 <<
"sample_manybody_phasespace_impl: alarm, weight > 1, w^2 = "
492 << acceptance <<
". Increasing safety factor.";
494 }
while (acceptance > 1 && rejection_counter < rejection_limit);
497 std::vector<ThreeVector>
beta(
n);
498 for (
size_t i =
n - 1; i > 0; i--) {
499 const double pcm =
pCM(Minv[i], Minv[i - 1], masses[i]);
504 FourVector(std::sqrt(masses[i] * masses[i] + pcm * pcm),
505 pcm * isotropic_unitvector);
507 beta[i - 2] = pcm * isotropic_unitvector /
508 std::sqrt(pcm * pcm + Minv[i - 1] * Minv[i - 1]);
512 FourVector(std::sqrt(masses[0] * masses[0] + pcm * pcm),
513 -pcm * isotropic_unitvector);
517 for (
size_t i = 0; i <
n - 2; i++) {
520 for (
size_t j = 0; j <= i + 1; j++) {
521 ptot += sampled_momenta[j];
523 logg[
LAction].debug() <<
"Total momentum of 0.." << i + 1 <<
" = "
524 << ptot.
threevec() <<
" and should be (0, 0, 0).";
527 for (
size_t j = 0; j <= i + 1; j++) {
528 sampled_momenta[j] = sampled_momenta[j].lorentz_boost(
beta[i]);
533 for (
size_t j = 0; j <
n; j++) {
534 ptot_all += sampled_momenta[j];
536 logg[
LAction].debug() <<
"Total 4-momentum = " << ptot_all <<
", should be ("
537 << sqrts <<
", 0, 0, 0)";
538 if (rejection_counter >= rejection_limit) {
540 <<
"Failed to sample kinematically correct 4-momenta of "
541 << std::accumulate(types.begin(), types.end(), std::string{},
543 return a + b->name();
545 <<
" with energy " << sqrts
546 <<
" GeV.\n Using MCMC fallback, which conserves energy and momentum "
547 "but may deviate slightly from the correct spectral distribution.";
553 std::vector<FourVector> &sampled_momenta) {
554 constexpr
int monte_carlo_iterations = 200;
556 const int n = types.size();
559 assert(sampled_momenta.size() ==
static_cast<size_t>(
n));
561 const bool all_zero =
562 std::all_of(sampled_momenta.begin(), sampled_momenta.end(),
563 [](
const FourVector &
p) { return p[0] < really_small; });
565 throw std::runtime_error(
566 "All initial momenta for the MCMC algorithm manybody phase space "
567 "sampling are zero, which should not happen.");
570 for (
int i = 0; i < monte_carlo_iterations; i++) {
576 }
while (idx2 == idx1);
577 }
while (types[idx1]->is_stable() && types[idx2]->is_stable());
580 const FourVector p_sum = sampled_momenta[idx1] + sampled_momenta[idx2];
582 const double sqrts_12 = p_sum.
abs();
585 m1 = types[idx1]->sample_full_spectral_function(sqrts_12);
586 m2 = types[idx2]->sample_full_spectral_function(sqrts_12);
587 }
while (sqrts_12 < m1 + m2);
588 const double pcm =
pCM(sqrts_12, m1, m2);
597 if (!types[idx1]->is_stable()) {
598 acc *= types[idx1]->ratio_spectral_full_to_breit_wigner(m1) /
599 types[idx1]->ratio_spectral_full_to_breit_wigner(
600 sampled_momenta[idx1].abs());
602 if (!types[idx2]->is_stable()) {
603 acc *= types[idx2]->ratio_spectral_full_to_breit_wigner(m2) /
604 types[idx2]->ratio_spectral_full_to_breit_wigner(
605 sampled_momenta[idx2].abs());
610 sampled_momenta[idx1] =
613 sampled_momenta[idx2] =
virtual void sample_2body_phasespace()
Sample the full 2-body phase-space (masses, momenta, angles) in the center-of-mass frame for the fina...
FourVector total_momentum_of_outgoing_particles() const
Calculate the total kinetic momentum of the outgoing particles.
void assign_formation_time_to_outgoing_particles()
Assign the formation time to the outgoing particles.
virtual ~Action()
Virtual Destructor.
int stochastic_position_idx_
This stores a randomly-chosen index to an incoming particle.
std::pair< FourVector, FourVector > get_potential_at_interaction_point() const
Get the skyrme and asymmetry potential at the interaction point.
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...
ParticleList outgoing_particles_
Initially this stores only the PDG codes of final-state particles.
const ParticleType & type_of_pout(const ParticleData &p_out) const
Get the type of a given particle.
FourVector total_momentum() const
Sum of 4-momenta of incoming particles.
virtual void sample_manybody_phasespace()
Sample the full n-body phase-space (masses, momenta, angles) in the center-of-mass frame for the fina...
const double time_of_execution_
Time at which the action is supposed to be performed (absolute time in the lab frame in fm).
virtual double perform(Particles *particles, uint32_t id_process)
Actually perform the action, e.g.
void update_incoming(const Particles &particles)
Update the incoming particles that are stored in this action to the state they have in the global par...
void assign_unpolarized_spin_vector_to_outgoing_particles()
Assign an unpolarized spin vector to all outgoing particles.
virtual double check_conservation(const uint32_t id_process) const
Check various conservation laws.
const ParticleList & incoming_particles() const
Get the list of particles that go into the action.
double sqrt_s() const
Determine the total energy in the center-of-mass frame [GeV].
double box_length_
Box length: needed to determine coordinates of collision correctly in case of collision through the w...
ParticleList incoming_particles_
List with data of incoming particles.
FourVector get_interaction_point() const
Get the interaction point.
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....
ProcessType process_type_
type of process
bool is_valid(const Particles &particles) const
Check whether the action still applies.
bool is_pauli_blocked(const std::vector< Particles > &ensembles, const PauliBlocker &p_bl) const
Check if the action is Pauli-blocked.
Angles provides a common interface for generating directions: i.e., two angles that should be interpr...
ThreeVector threevec() const
void distribute_isotropically()
Populate the object with a new direction.
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
double abs() const
calculate the lorentz invariant absolute value
FourVector lorentz_boost(const ThreeVector &v) const
Returns the FourVector boosted with velocity v.
ThreeVector threevec() const
ThreeVector velocity() const
Get the velocity (3-vector divided by zero component).
ParticleData contains the dynamic information of a certain particle.
PdgCode pdgcode() const
Get the pdgcode of the particle.
void set_4momentum(const FourVector &momentum_vector)
Set the particle's 4-momentum directly.
A pointer-like interface to global references to ParticleType objects.
Particle type contains the static properties of a particle species.
double sample_resonance_mass(const double mass_stable, const double cms_energy, int L=0) const
Resonance mass sampling for 2-particle final state with one resonance (type given by 'this') and one ...
double min_mass_kinematic() const
The minimum mass of the resonance that is kinematically allowed.
const std::string & name() const
double max_ratio_spectral_full_to_breit_wigner() const
Getter used in the resonance mass sampling functions.
double isospin3_rel() const
double ratio_spectral_full_to_breit_wigner(double m) const
Calculate the ratio between the full spectral function and simple one.
double sample_breit_wigner_spectral_function(double energy=mass_limit_) const
Sample mass from the simple spectral function (Breit-Wigner/Cauchy distribution).
The Particles class abstracts the storage and manipulation of particles.
void update(const ParticleList &old_state, ParticleList &new_state, bool do_replace)
Updates the Particles object, replacing the particles in old_state with the particles in new_state.
const ParticleData & lookup(const ParticleData &old_state) const
Returns the particle that is currently stored in this object given an old copy of that particle.
A class that stores parameters needed for Pauli blocking, tabulates necessary integrals and computes ...
double phasespace_dens(const ThreeVector &r, const ThreeVector &p, const std::vector< Particles > &ensembles, const PdgCode pdg, const ParticleList &disregard) const
Calculate phase-space density of a particle species at the point (r,p).
static std::pair< double, int > force_scale(const ParticleType &data)
Evaluates the scaling factor of the forces acting on the particles.
A container for storing conserved values.
FourVector momentum() const
std::string report_deviations(const std::vector< Particles > &ensembles) const
Checks if the current particle list has still the same values and reports about differences.
The ThreeVector class represents a physical three-vector with the components .
Collection of useful constants that are known at compile time.
std::ostream & operator<<(std::ostream &out, const ActionPtr &action)
Convenience: dereferences the ActionPtr to Action.
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > & logg
An array that stores all pre-configured Logger objects.
void sample_manybody_phasespace_impl(double sqrts, const ParticleTypePtrList &types, std::vector< FourVector > &sampled_momenta)
Implementation of the full n-body phase-space sampling (masses, momenta, angles) in the center-of-mas...
void sample_manybody_phasespace_MCMC(const ParticleTypePtrList &types, std::vector< FourVector > &sampled_momenta)
Metropolis–Hastings sampling of the many body phase space, starting from an initial guess in sampled_...
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of is .
T uniform_int(T min, T max)
static constexpr int LPauliBlocking
T pCM(const T sqrts, const T mass_a, const T mass_b) noexcept
T pCM_sqr(const T sqrts, const T mass_a, const T mass_b) noexcept
constexpr std::uint32_t ID_PROCESS_PHOTON
Process ID for any photon process.
static constexpr int LAction
@ FluidizationNoRemoval
See here for a short description.
@ Freeforall
See here for a short description.
@ Decay
See here for a short description.
@ Wall
See here for a short description.
@ Elastic
See here for a short description.
bool all_of(Container &&c, UnaryPredicate &&p)
Convenience wrapper for std::all_of that operates on a complete container.
std::string to_string(ThermodynamicQuantity quantity)
Convert a ThermodynamicQuantity enum value to its corresponding string.
Potentials * pot_pointer
Pointer to a Potential class.
RectangularLattice< FourVector > * UB_lat_pointer
Pointer to the skyrme potential on the lattice.
std::pair< double, double > sample_two_resonance_masses(const ParticleType &t1, const ParticleType &t2, const double cms_energy, int L=0)
Resonance mass sampling for 2-particle final state with two resonances.
bool is_string_process(ProcessType p)
Check if a given process type is a string excitation.
RectangularLattice< FourVector > * UI3_lat_pointer
Pointer to the symmmetry potential on the lattice.