Version: SMASH-3.3
propagation.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2015-2023,2025
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/propagation.h"
11 
12 #include "smash/boxmodus.h"
13 #include "smash/collidermodus.h"
14 #include "smash/listmodus.h"
15 #include "smash/logging.h"
16 #include "smash/spheremodus.h"
17 
18 namespace smash {
19 static constexpr int LPropagation = LogArea::Propagation::id;
20 
21 double calc_hubble(double time, const ExpansionProperties &metric) {
22  double h; // Hubble parameter
23 
24  switch (metric.mode_) {
26  h = 0.;
27  break;
29  h = metric.b_ / (2 * (metric.b_ * time + 1));
30  break;
32  h = 2 * metric.b_ / (3 * (metric.b_ * time + 1));
33  break;
35  h = metric.b_ * time;
36  break;
37  default:
38  h = 0.;
39  }
40 
41  return h;
42 }
43 
44 double propagate_straight_line(Particles *particles, double to_time,
45  const std::vector<FourVector> &beam_momentum) {
46  bool negative_dt_error = false;
47  double dt = 0.0;
48  for (ParticleData &data : *particles) {
49  const double t0 = data.position().x0();
50  dt = to_time - t0;
51  if (dt < 0.0 && !negative_dt_error) {
52  // Print error message once, not for every particle
53  negative_dt_error = true;
54  logg[LPropagation].error("propagate_straight_line - negative dt = ", dt);
55  }
56  assert(dt >= 0.0);
57  /* "Frozen Fermi motion": Fermi momenta are only used for collisions,
58  * but not for propagation. This is done to avoid nucleus flying apart
59  * even if potentials are off. Initial nucleons before the first collision
60  * are propagated only according to beam momentum.
61  * Initial nucleons are distinguished by data.id() < the size of
62  * beam_momentum, which is by default zero except for the collider modus
63  * with the fermi motion == frozen.
64  * todo(m. mayer): improve this condition (see comment #11 issue #4213)*/
65  assert(data.id() >= 0);
66  const bool avoid_fermi_motion =
67  (static_cast<uint64_t>(data.id()) <
68  static_cast<uint64_t>(beam_momentum.size())) &&
69  (data.get_history().collisions_per_particle == 0);
70  ThreeVector v;
71  if (avoid_fermi_motion) {
72  const FourVector vbeam = beam_momentum[data.id()];
73  v = vbeam.velocity();
74  } else {
75  v = data.velocity();
76  }
77  const FourVector distance = FourVector(0.0, v * dt);
78  logg[LPropagation].debug("Particle ", data, " motion: ", distance);
79  FourVector position = data.position() + distance;
80  position.set_x0(to_time);
81  data.set_4position(position);
82  }
83  return dt;
84 }
85 
86 void backpropagate_straight_line(Particles *particles, double to_time) {
87  bool positive_dt_error = false;
88  for (ParticleData &data : *particles) {
89  const double t = data.position().x0();
90  if (t < to_time && !positive_dt_error) {
91  // Print error message once, not for every particle
92  positive_dt_error = true;
93  logg[LPropagation].error(
94  to_time,
95  " in backpropagate_straight_line is after the earliest particle.");
96  }
97  assert(t >= to_time);
98  const double dt = to_time - t;
99  const ThreeVector r = data.position().threevec() + dt * data.velocity();
100  data.set_4position(FourVector(to_time, r));
101  data.set_formation_time(t);
102  data.set_cross_section_scaling_factor(0.0);
103  }
104 }
105 
106 void expand_space_time(Particles *particles,
107  const ExperimentParameters &parameters,
108  const ExpansionProperties &metric) {
109  const double dt = parameters.labclock->timestep_duration();
110  for (ParticleData &data : *particles) {
111  // Momentum and position modification to ensure appropriate expansion
112  const double h = calc_hubble(parameters.labclock->current_time(), metric);
113  FourVector delta_mom = FourVector(0.0, h * data.momentum().threevec() * dt);
114  FourVector expan_dist =
115  FourVector(0.0, h * data.position().threevec() * dt);
116 
117  logg[LPropagation].debug("Particle ", data,
118  " expansion motion: ", expan_dist);
119  // New position and momentum
120  FourVector position = data.position() + expan_dist;
121  FourVector momentum = data.momentum() - delta_mom;
122 
123  // set the new momentum and position variables
124  data.set_4position(position);
125  data.set_4momentum(momentum);
126  // force the on shell condition to ensure correct energy
127  data.set_4momentum(data.pole_mass(), data.momentum().threevec());
128  }
129 }
130 
132  std::vector<Particles> &ensembles, double dt, const Potentials &pot,
133  RectangularLattice<std::pair<ThreeVector, ThreeVector>> *FB_lat,
134  RectangularLattice<std::pair<ThreeVector, ThreeVector>> *FI3_lat,
135  RectangularLattice<std::pair<ThreeVector, ThreeVector>> *EM_lat,
136  DensityLattice *jB_lat) {
137  // Copy particles from ALL ensembles to a single list before propagation
138  // and calculate potentials from this list
139  ParticleList plist;
140  for (Particles &particles : ensembles) {
141  const ParticleList tmp = particles.copy_to_vector();
142  plist.insert(plist.end(), tmp.begin(), tmp.end());
143  }
144 
145  bool possibly_use_lattice =
146  (pot.use_skyrme() ? (FB_lat != nullptr) : true) &&
147  (pot.use_vdf() ? (FB_lat != nullptr) : true) &&
148  (pot.use_symmetry() ? (FI3_lat != nullptr) : true);
149  std::pair<ThreeVector, ThreeVector> FB, FI3, EM_fields;
150  double min_time_scale = std::numeric_limits<double>::infinity();
151 
152  for (Particles &particles : ensembles) {
153  for (ParticleData &data : particles) {
154  // Only baryons and nuclei will be affected by the potentials
155  if (!(data.is_baryon() || data.is_nucleus())) {
156  continue;
157  }
158  const auto scale = pot.force_scale(data.type());
159  const ThreeVector r = data.position().threevec();
160  /* Lattices can be used for calculation if 1-2 are fulfilled:
161  * 1) Required lattices are not nullptr - possibly_use_lattice
162  * 2) r is not out of required lattices */
163  const bool use_lattice =
164  possibly_use_lattice &&
165  (pot.use_skyrme() ? FB_lat->value_at(r, FB) : true) &&
166  (pot.use_vdf() ? FB_lat->value_at(r, FB) : true) &&
167  (pot.use_symmetry() ? FI3_lat->value_at(r, FI3) : true);
168  if (!use_lattice && !pot.use_potentials_outside_lattice()) {
169  continue;
170  }
171  if (!pot.use_skyrme() && !pot.use_vdf()) {
172  FB = std::make_pair(ThreeVector(0., 0., 0.), ThreeVector(0., 0., 0.));
173  }
174  if (!pot.use_symmetry()) {
175  FI3 = std::make_pair(ThreeVector(0., 0., 0.), ThreeVector(0., 0., 0.));
176  }
177  if (!use_lattice) {
178  const auto tmp = pot.all_forces(r, plist);
179  FB = std::make_pair(std::get<0>(tmp), std::get<1>(tmp));
180  FI3 = std::make_pair(std::get<2>(tmp), std::get<3>(tmp));
181  }
182  ThreeVector force = std::invoke([&]() {
183  if (pot.use_momentum_dependence()) {
184  const ThreeVector energy_grad = pot.single_particle_energy_gradient(
185  jB_lat, data.position().threevec(), data.momentum().threevec(),
186  data.effective_mass(), plist);
187  return -energy_grad * scale.first +
188  scale.second * data.type().isospin3_rel() *
189  (FI3.first +
190  data.momentum().velocity().cross_product(FI3.second));
191  } else {
192  return scale.first *
193  (FB.first +
194  data.momentum().velocity().cross_product(FB.second)) +
195  scale.second * data.type().isospin3_rel() *
196  (FI3.first +
197  data.momentum().velocity().cross_product(FI3.second));
198  }
199  });
200  // Potentially add Lorentz force
201  if (pot.use_coulomb() && EM_lat->value_at(r, EM_fields)) {
202  // factor hbar*c to convert fields from 1/fm^2 to GeV/fm
203  force += hbarc * data.type().charge() * elementary_charge *
204  (EM_fields.first +
205  data.momentum().velocity().cross_product(EM_fields.second));
206  }
207  logg[LPropagation].debug("Update momenta: F [GeV/fm] = ", force);
208  data.set_4momentum(data.effective_mass(),
209  data.momentum().threevec() + force * dt);
210 
211  // calculate the time scale of the change in momentum
212  const double Force_abs = force.abs();
213  if (Force_abs < really_small) {
214  continue;
215  }
216  const double time_scale = data.momentum().x0() / Force_abs;
217  if (time_scale < min_time_scale) {
218  min_time_scale = time_scale;
219  }
220  }
221  }
222  // warn if the time step is too big
223  constexpr double safety_factor = 0.1;
224  if (dt > safety_factor * min_time_scale) {
225  logg[LPropagation].warn()
226  << "The time step size is too large for an accurate propagation "
227  << "with potentials. Maximum safe value: "
228  << safety_factor * min_time_scale << " fm.\n"
229  << "In case of Triangular or Discrete smearing you may additionally "
230  << "need to increase the number of ensembles or testparticles.";
231  }
232 }
233 
234 } // namespace smash
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:33
ThreeVector velocity() const
Get the velocity (3-vector divided by zero component).
Definition: fourvector.h:333
void set_x0(double t)
Definition: fourvector.h:315
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:59
The Particles class abstracts the storage and manipulation of particles.
Definition: particles.h:33
A class that stores parameters of potentials, calculates potentials and their gradients.
Definition: potentials.h:36
virtual bool use_symmetry() const
Definition: potentials.h:480
virtual bool use_skyrme() const
Definition: potentials.h:478
bool use_potentials_outside_lattice() const
Definition: potentials.h:515
virtual bool use_coulomb() const
Definition: potentials.h:482
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
virtual std::tuple< ThreeVector, ThreeVector, ThreeVector, ThreeVector > all_forces(const ThreeVector &r, const ParticleList &plist) const
Evaluates the electric and magnetic components of the forces at point r.
Definition: potentials.cc:274
virtual bool use_vdf() const
Definition: potentials.h:498
virtual bool use_momentum_dependence() const
Definition: potentials.h:484
A container class to hold all the arrays on the lattice and access them.
Definition: lattice.h:49
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
double abs() const
Definition: threevector.h:277
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:40
Definition: action.h:24
void update_momenta(std::vector< Particles > &particles, double dt, const Potentials &pot, RectangularLattice< std::pair< ThreeVector, ThreeVector >> *FB_lat, RectangularLattice< std::pair< ThreeVector, ThreeVector >> *FI3_lat, RectangularLattice< std::pair< ThreeVector, ThreeVector >> *EM_lat, DensityLattice *jB_lat)
Updates the momenta of all particles at the current time step according to the equations of motion:
Definition: propagation.cc:131
void expand_space_time(Particles *particles, const ExperimentParameters &parameters, const ExpansionProperties &metric)
Modifies positions and momentum of all particles to account for space-time deformation.
Definition: propagation.cc:106
double propagate_straight_line(Particles *particles, double to_time, const std::vector< FourVector > &beam_momentum)
Propagates the positions of all particles on a straight line to a given moment.
Definition: propagation.cc:44
constexpr double hbarc
GeV <-> fm conversion factor.
Definition: constants.h:29
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:41
void backpropagate_straight_line(Particles *particles, double to_time)
Definition: propagation.cc:86
double calc_hubble(double time, const ExpansionProperties &metric)
Calculate the Hubble parameter , which describes how large the expansion flow is.
Definition: propagation.cc:21
static constexpr int LPropagation
Definition: propagation.cc:19
const double elementary_charge
Elementary electric charge in natural units, approximately 0.3.
Definition: constants.h:102
Struct containing the type of the metric and the expansion parameter of the metric.
Definition: propagation.h:26
double b_
Expansion parameter in the metric (faster expansion for larger values)
Definition: propagation.h:30
ExpansionMode mode_
Type of metric used.
Definition: propagation.h:28
Helper structure for Experiment.
std::unique_ptr< Clock > labclock
System clock (for simulation time keeping in the computational frame)