Version: SMASH-3.4
particledata.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2026
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/particledata.h"
11 
12 #include <cassert>
13 #include <iomanip>
14 #include <iostream>
15 #include <optional>
16 #include <vector>
17 
18 #include "smash/constants.h"
19 #include "smash/iomanipulators.h"
20 #include "smash/logging.h"
21 #include "smash/numerics.h"
22 
23 namespace smash {
24 
26  const double m_pole = pole_mass();
27  if (m_pole < really_small) {
28  // prevent numerical problems with massless or very light particles
29  return m_pole;
30  } else {
31  return momentum().abs();
32  }
33 }
34 
35 void ParticleData::set_history(int ncoll, uint32_t pid, ProcessType pt,
36  double time_last_coll,
37  const ParticleList &plist) {
40  history_.time_last_collision = time_last_coll;
41  }
42  history_.id_process = pid;
44  switch (pt) {
45  case ProcessType::Decay:
46  case ProcessType::Wall:
47  // only store one parent
48  history_.p1 = plist[0].pdgcode();
49  history_.p2 = 0x0;
50  break;
55  // Parent particles are not updated by the elastic scatterings,
56  // failed string processes, or fluidizations
57  break;
74  // store two parent particles
75  history_.p1 = plist[0].pdgcode();
76  history_.p2 = plist[1].pdgcode();
77  break;
84  case ProcessType::None:
85  // nullify parents
86  history_.p1 = 0x0;
87  history_.p2 = 0x0;
88  break;
89  }
90 }
91 
93  // For massless particles, a rest frame does not exist,
94  // so the spin 4-vector cannot be defined via a rest-frame boost.
95  // In such cases, we assign a vanishing spin vector to ensure
96  // numerical stability and well-defined behavior.
97  // For spin-0 particles, the spin 4-vector is physically zero
98  if (pole_mass() == 0.0 || spin() == 0) {
99  spin_vector_ = FourVector(0., 0., 0., 0.);
100  return;
101  }
102 
103  // Check whether the velocity of a particle is set and not nan
104  const ThreeVector v = velocity();
105  assert(!(std::isnan(v.x1()) || std::isnan(v.x2()) || std::isnan(v.x3())));
106 
107  /**
108  * For finite-spin particles, we assign unpolarized spin vectors by sampling
109  * the spatial components from a normal distribution with mean 0 in the
110  * particle rest frame, ensuring ⟨S⟩ = 0 on average. The time component S⁰ is
111  * set to 0. The resulting spin vector is then Lorentz-boosted to the lab
112  * frame.
113  *
114  * This initialization is not physical spin quantization, but a statistically
115  * unpolarized setup. The standard deviation is arbitrary and chosen small to
116  * avoid unphysical artifacts.
117  */
118  constexpr double mean = 0.0;
119  constexpr double sigma = 0.75;
120 
121  const FourVector rest_frame_spin(0., random::normal(mean, sigma),
122  random::normal(mean, sigma),
123  random::normal(mean, sigma));
124 
125  // Boost the spin vector from rest frame to lab frame
126  spin_vector_ = rest_frame_spin.lorentz_boost(v);
127 }
128 
129 double ParticleData::xsec_scaling_factor(double delta_time) const {
130  // if formation times are NaNs simply return a NaN to avoid floating-point
131  // FE_INVALID errors (that would be raised by unordered comparisons with NaNs)
132  if (std::isnan(formation_time_) || std::isnan(begin_formation_time_)) {
133  return smash_NaN<double>;
134  }
135 
136  double time_of_interest = position_.x0() + delta_time;
137  // cross section scaling factor at the time_of_interest
138  double scaling_factor;
139 
140  if (formation_power_ <= 0.) {
141  // use a step function to form particles
142  if (time_of_interest < formation_time_) {
143  // particles will not be fully formed at time of interest
144  scaling_factor = initial_xsec_scaling_factor_;
145  } else {
146  // particles are fully formed at time of interest
147  scaling_factor = 1.;
148  }
149  } else {
150  // use smooth function to scale cross section (unless particles are already
151  // fully formed at desired time or will start to form later)
152  if (formation_time_ <= time_of_interest) {
153  // particles are fully formed when colliding
154  scaling_factor = 1.;
155  } else if (begin_formation_time_ >= time_of_interest) {
156  // particles will start formimg later
157  scaling_factor = initial_xsec_scaling_factor_;
158  } else {
159  // particles are in the process of formation at the given time
160  scaling_factor =
163  std::pow((time_of_interest - begin_formation_time_) /
166  }
167  }
168  return scaling_factor;
169 }
170 
171 std::ostream &operator<<(std::ostream &out, const ParticleData &p) {
172  out.fill(' ');
173  return out << p.type().name() << " (" << std::setw(5) << p.type().pdgcode()
174  << ")" << std::right << "{id:" << field<6> << p.id()
175  << ", process:" << field<4> << p.id_process()
176  << ", pos [fm]:" << p.position() << ", mom [GeV]:" << p.momentum()
177  << ", formation time [fm]:" << p.formation_time()
178  << ", cross section scaling factor:" << p.xsec_scaling_factor()
179  << "}";
180 }
181 
182 std::ostream &operator<<(std::ostream &out, const ParticleList &particle_list) {
183  auto column = out.tellp();
184  out << '[';
185  for (const auto &p : particle_list) {
186  if (out.tellp() - column >= 201) {
187  out << '\n';
188  column = out.tellp();
189  out << ' ';
190  }
191  out << std::setw(5) << std::setprecision(3) << p.momentum().abs3()
192  << p.type().name();
193  }
194  return out << ']';
195 }
196 
197 std::ostream &operator<<(std::ostream &out,
198  const PrintParticleListDetailed &particle_list) {
199  bool first = true;
200  out << '[';
201  for (const auto &p : particle_list.list) {
202  if (first) {
203  first = false;
204  } else {
205  out << "\n ";
206  }
207  out << p;
208  }
209  return out << ']';
210 }
211 
212 double ParticleData::formation_power_ = 0.0;
213 
215  PdgCode pdgcode, double mass, const FourVector &four_position,
216  const FourVector &four_momentum, int log_area, bool &mass_warning,
217  bool &on_shell_warning) {
218  // Check input position and momentum for nan values
219  if (is_any_nan(four_position) || is_any_nan(four_momentum)) {
220  logg[log_area].fatal() << "Input particle has at least one nan value in "
221  "position and/or momentum four vector.";
222  throw std::invalid_argument(
223  "Invalid input (nan) for particle position or momentum.");
224  }
225 
226  // Some preliminary tool to avoid duplication later
227  static const auto emph = einhard::Yellow_t_::ANSI();
228  static const auto restore_default = einhard::NoColor_t_::ANSI();
229  auto prepare_needed_warnings = [&mass_warning, &on_shell_warning, &mass,
230  &four_momentum](const ParticleData &p) {
231  std::array<std::optional<std::string>, 2> warnings{};
232  if (mass_warning) {
233  warnings[0] = "Provided mass of stable particle " + p.type().name() +
234  " = " + std::to_string(mass) +
235  " [GeV] is inconsistent with value = " +
236  std::to_string(p.pole_mass()) + " [GeV] from " +
237  "particles file.\nForcing E = sqrt(p^2 + m^2)" +
238  ", where m is the mass contained in the particles file." +
239  "\nFurther warnings about discrepancies between the " +
240  "input mass and the mass contained in the particles file" +
241  " will be suppressed.\n" + emph + "Please make sure" +
242  " that changing input particle properties is an " +
243  "acceptable behavior." + restore_default;
244  }
245  if (on_shell_warning) {
246  std::stringstream ss{};
247  ss << four_momentum;
248  warnings[1] =
249  "Provided 4-momentum " + ss.str() + " [GeV] and mass " +
250  std::to_string(mass) + " [GeV] do not satisfy E^2 - p^2 = m^2.\n" +
251  "This may originate from the lack of numerical" +
252  " precision in the input. Setting E to sqrt(p^2 + " +
253  "m^2).\nFurther warnings about E != sqrt(p^2 + m^2) will" +
254  " be suppressed.\n" + emph + "Please make sure that setting " +
255  "particles back on the mass shell is an acceptable behavior." +
256  restore_default;
257  }
258  return warnings;
259  };
260  auto warn_if_needed = [&log_area](bool &flag,
261  const std::optional<std::string> &message) {
262  if (flag) {
263  logg[log_area].warn(message.value());
264  flag = false;
265  }
266  };
267  auto is_particle_stable_and_with_invalid_mass =
268  [&mass](const ParticleData &p) {
269  return p.type().is_stable() &&
270  std::abs(mass - p.pole_mass()) > really_small;
271  };
272  auto is_particle_off_its_mass_shell = [&mass](const ParticleData &p) {
273  return std::abs(p.momentum().sqr() - mass * mass) > really_small;
274  };
275 
276  // Actual implementation
277  ParticleData smash_particle{ParticleType::find(pdgcode)};
278  const auto warnings = prepare_needed_warnings(smash_particle);
279  if (is_particle_stable_and_with_invalid_mass(smash_particle)) {
280  warn_if_needed(mass_warning, warnings[0]);
281  smash_particle.set_4momentum(smash_particle.pole_mass(),
282  four_momentum.threevec());
283  } else {
284  smash_particle.set_4momentum(four_momentum);
285  if (is_particle_off_its_mass_shell(smash_particle)) {
286  warn_if_needed(on_shell_warning, warnings[1]);
287  smash_particle.set_4momentum(mass, four_momentum.threevec());
288  }
289  }
290 
291  // Set spatial coordinates, they will later be backpropagated if needed
292  smash_particle.set_4position(four_position);
293  smash_particle.set_formation_time(four_position.x0());
294  smash_particle.set_cross_section_scaling_factor(1.0);
295 
296  return smash_particle;
297 }
298 
300  const ParticleData &p2,
301  double time) {
302  if (p1.pdgcode() != p2.pdgcode()) {
303  return false;
304  } else {
305  if (p1.momentum() != p2.momentum()) {
306  return false;
307  }
308  auto get_propagated_position = [&time](const ParticleData &p) {
309  const double t = p.position().x0();
310  const FourVector u(1.0, p.velocity());
311  return p.position() + u * (time - t);
312  };
313  return get_propagated_position(p1) == get_propagated_position(p2);
314  }
315 }
316 
317 } // namespace smash
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:33
double abs() const
calculate the lorentz invariant absolute value
Definition: fourvector.h:464
FourVector lorentz_boost(const ThreeVector &v) const
Returns the FourVector boosted with velocity v.
Definition: fourvector.cc:17
ThreeVector threevec() const
Definition: fourvector.h:329
double x0() const
Definition: fourvector.h:313
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:59
double formation_time_
Formation time at which the particle is fully formed given as an absolute value in the computational ...
Definition: particledata.h:556
PdgCode pdgcode() const
Get the pdgcode of the particle.
Definition: particledata.h:88
void set_history(HistoryData &&history)
Set history_ from rvalue reference.
Definition: particledata.h:151
double begin_formation_time_
time when the cross section scaling factor starts to increase to 1
Definition: particledata.h:558
double xsec_scaling_factor(double delta_time=0.) const
Return the cross section scaling factor at a given time.
static double formation_power_
Power with which the cross section scaling factor grows in time.
Definition: particledata.h:471
const FourVector & momentum() const
Get the particle's 4-momentum.
Definition: particledata.h:171
ThreeVector velocity() const
Get the velocity 3-vector.
Definition: particledata.h:321
double initial_xsec_scaling_factor_
Initial cross section scaling factor.
Definition: particledata.h:563
FourVector spin_vector_
Pauli-Lubanski vector (mean spin 4-vector) of the particle.
Definition: particledata.h:551
double effective_mass() const
Get the particle's effective mass.
Definition: particledata.cc:25
FourVector position_
position in space: x0, x1, x2, x3 as t, x, y, z
Definition: particledata.h:545
double pole_mass() const
Get the particle's pole mass ("on-shell").
Definition: particledata.h:119
int spin() const
Get the (maximum positive) spin s of a particle in multiples of 1/2.
Definition: particledata.h:360
HistoryData history_
history information
Definition: particledata.h:567
void set_unpolarized_spin_vector()
Set the 4 components of the spin vector such that the particle is unpolarized.
Definition: particledata.cc:92
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode.
Definition: particletype.cc:99
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
Definition: pdgcode.h:108
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
double x3() const
Definition: threevector.h:194
double x2() const
Definition: threevector.h:190
double x1() const
Definition: threevector.h:186
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.
Definition: action.h:546
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > & logg
An array that stores all pre-configured Logger objects.
Definition: logging.h:245
constexpr int p
Proton.
double normal(const T &mean, const T &sigma)
Returns a random number drawn from a normal distribution.
Definition: random.h:294
Definition: action.h:24
ProcessType
ProcessTypes are used to identify the type of the process.
Definition: processbranch.h:39
@ FluidizationNoRemoval
See here for a short description.
@ FailedString
See here for a short description.
@ TwoToOne
See here for a short description.
@ StringHardSingleDiffractiveAX
See here for a short description.
@ MultiParticleThreeToTwo
See here for a short description.
@ BremsstrahlungPhoton
See here for a short description.
@ StringSoftDoubleDiffractive
See here for a short description.
@ Fluidization
See here for a short description.
@ BremsstrahlungDilepton
See here for a short description.
@ Thermalization
See here for a short description.
@ Freeforall
See here for a short description.
@ Decay
See here for a short description.
@ TwoToFive
See here for a short description.
@ None
See here for a short description.
@ StringSoftSingleDiffractiveXB
See here for a short description.
@ TwoToTwo
See here for a short description.
@ Wall
See here for a short description.
@ Elastic
See here for a short description.
@ TwoToFour
See here for a short description.
@ StringHardNonDiffractive
See here for a short description.
@ StringSoftAnnihilation
See here for a short description.
@ MultiParticleThreeMesonsToOne
See here for a short description.
@ StringSoftNonDiffractive
See here for a short description.
@ MultiParticleFourToTwo
See here for a short description.
@ StringSoftSingleDiffractiveAX
See here for a short description.
@ StringHardSingleDiffractiveXB
See here for a short description.
@ StringHardDoubleDiffractive
See here for a short description.
@ TwoToThree
See here for a short description.
@ MultiParticleFiveToTwo
See here for a short description.
bool are_particles_identical_at_given_time(const ParticleData &p1, const ParticleData &p2, double time)
Utility function to compare two ParticleData instances with respect to their PDG code,...
std::string to_string(ThermodynamicQuantity quantity)
Convert a ThermodynamicQuantity enum value to its corresponding string.
Definition: stringify.cc:26
bool is_any_nan(const T &collection)
Returns whether any element in a collection is NaN.
Definition: numerics.h:121
ParticleData create_valid_smash_particle_matching_provided_quantities(PdgCode pdgcode, double mass, const FourVector &four_position, const FourVector &four_momentum, int log_area, bool &mass_warning, bool &on_shell_warning)
This function creates a SMASH particle validating the provided information.
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:41
Generic numerical functions.
double time_last_collision
Time of the last action (excluding walls), time of kinetic freeze_out for HBT analysis this time shou...
Definition: particledata.h:44
int32_t id_process
id of the last action
Definition: particledata.h:35
PdgCode p2
PdgCode of the second parent particles.
Definition: particledata.h:48
PdgCode p1
PdgCode of the first parent particles.
Definition: particledata.h:46
int32_t collisions_per_particle
Collision counter per particle, zero only for initially present particles.
Definition: particledata.h:33
ProcessType process_type
type of the last action
Definition: particledata.h:37
const ParticleList & list
Particle list.
Definition: particledata.h:592