Version: SMASH-3.4
spheremodus.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2012-2026
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/spheremodus.h"
11 
12 #include <cmath>
13 #include <cstdio>
14 #include <cstdlib>
15 #include <list>
16 #include <map>
17 #include <utility>
18 #include <vector>
19 
20 #include "smash/angles.h"
22 #include "smash/configuration.h"
23 #include "smash/constants.h"
24 #include "smash/cxx17compat.h"
26 #include "smash/fourvector.h"
27 #include "smash/hadgas_eos.h"
28 #include "smash/logging.h"
29 #include "smash/particles.h"
30 #include "smash/quantumsampling.h"
31 #include "smash/random.h"
32 #include "smash/threevector.h"
33 
34 namespace smash {
35 static constexpr int LSphere = LogArea::Sphere::id;
36 
38  const ExperimentParameters &)
39  : radius_(modus_config.take(InputKeys::modi_sphere_radius)),
40  sphere_temperature_(
41  modus_config.take(InputKeys::modi_sphere_temperature)),
42  start_time_(modus_config.take(InputKeys::modi_sphere_startTime)),
43  use_thermal_(
44  modus_config.take(InputKeys::modi_sphere_useThermalMultiplicities)),
45  mub_(modus_config.take(InputKeys::modi_sphere_baryonChemicalPotential)),
46  mus_(modus_config.take(InputKeys::modi_sphere_strangeChemicalPotential)),
47  muq_(modus_config.take(InputKeys::modi_sphere_chargeChemicalPotential)),
48  hf_multiplier_(
49  modus_config.take(InputKeys::modi_sphere_heavyFlavorMultiplier)),
50  account_for_resonance_widths_(
51  modus_config.take(InputKeys::modi_sphere_accountResonanceWidths)),
52  init_multipl_(use_thermal_
53  ? std::map<PdgCode, int>()
54  : modus_config.take(
55  InputKeys::modi_sphere_initialMultiplicities)),
56  init_distr_(modus_config.take(InputKeys::modi_sphere_initialCondition)),
57  radial_velocity_(
58  modus_config.take(InputKeys::modi_sphere_addRadialVelocity)),
59  radial_velocity_exponent_(
60  modus_config.take(InputKeys::modi_sphere_addRadialVelocityExponent)),
61  /* Note that it is crucial not to take other keys from the Jet section
62  * before Jet_PDG, since we want here the take to throw in case the user
63  * had a Jet section without the mandatory Jet_PDG key. If all other keys
64  * are taken first, the section is removed from the config because empty,
65  * and has_section(InputSections::m_s_jet) method would return false.
66  */
67  jet_pdg_(modus_config.has_section(InputSections::m_s_jet)
68  ? make_optional<PdgCode>(
69  modus_config.take(InputKeys::modi_sphere_jet_jetPdg))
70  : std::nullopt),
71  jet_mom_(modus_config.take(InputKeys::modi_sphere_jet_jetMomentum)),
72  jet_pos_(modus_config.take(InputKeys::modi_sphere_jet_jetPosition)),
73  jet_back_(modus_config.take(InputKeys::modi_sphere_jet_backToBack)),
74  jet_back_separation_(
75  jet_back_ ? modus_config.take(
76  InputKeys::modi_sphere_jet_backToBackSeparation)
77  : 0),
78  spin_interaction_type_(
79  modus_config.take(InputKeys::collTerm_spinInteractions)) {
80  if (!jet_back_ &&
82  throw std::invalid_argument(
83  "In order to specify 'Back_To_Back_Separation', 'Back_To_Back' must be "
84  "true.");
85  }
86 }
87 
88 /* console output on startup of sphere specific parameters */
89 std::ostream &operator<<(std::ostream &out, const SphereModus &m) {
90  out << "-- Sphere Modus:\nRadius of the sphere: " << m.radius_ << " fm\n";
91  if (m.use_thermal_) {
92  out << "Thermal multiplicities (T = " << m.sphere_temperature_
93  << " GeV, muB = " << m.mub_ << " GeV, muS = " << m.mus_
94  << " GeV, muQ = " << m.muq_ << " GeV)\n";
95  } else {
96  for (const auto &p : m.init_multipl_) {
97  ParticleTypePtr ptype = &ParticleType::find(p.first);
98  out << ptype->name() << " initial multiplicity " << p.second << '\n';
99  }
100  }
101  switch (m.init_distr_) {
103  out << "Boltzmann momentum distribution with T = "
104  << m.sphere_temperature_ << " GeV.\n";
105  break;
107  out << "Fermi/Bose momentum distribution with T = "
108  << m.sphere_temperature_ << " GeV.\n";
109  break;
111  out << "Sphere Initial Condition is IC_ES";
112  break;
114  out << "Sphere Initial Condition is IC_1M";
115  break;
117  out << "Sphere Initial Condition is IC_2M";
118  break;
120  out << "Sphere Initial Condition is IC_Massive";
121  break;
122  }
123  if (m.jet_pdg_) {
124  ParticleTypePtr ptype = &ParticleType::find(m.jet_pdg_.value());
125  const auto pos = m.jet_pos_;
126  if (m.jet_back_) {
127  ParticleTypePtr anti =
128  ptype->has_antiparticle() ? ptype->get_antiparticle() : ptype;
129  out << "Adding a dijet " << ptype->name() << anti->name()
130  << " centered at (" << pos.x1() << ", " << pos.x2() << ", "
131  << pos.x3() << ") separated by " << m.jet_back_separation_
132  << " fm,\neach with " << m.jet_mom_ << " GeV of initial momentum.\n";
133  } else {
134  out << "Adding a " << ptype->name() << " as a jet at (" << pos.x1()
135  << ", " << pos.x2() << ", " << pos.x3() << ") fm with " << m.jet_mom_
136  << " GeV of initial momentum.\n";
137  }
138  }
139  return out;
140 }
141 
142 /* initial_conditions - sets particle data for @particles */
144  const ExperimentParameters &parameters) {
145  FourVector momentum_total(0, 0, 0, 0);
146  const double T = this->sphere_temperature_;
147  const double V = 4.0 / 3.0 * M_PI * radius_ * radius_ * radius_;
148  /* Create NUMBER OF PARTICLES according to configuration */
149  if (use_thermal_) {
150  if (average_multipl_.empty()) {
151  for (const ParticleType &ptype : ParticleType::list_all()) {
152  const bool is_eos_particle = HadronGasEos::is_eos_particle(ptype);
153  const bool use_heavy_flavor = ptype.pdgcode().is_heavy_flavor() &&
155  if (is_eos_particle || use_heavy_flavor) {
156  const double n = HadronGasEos::partial_density(
158  average_multipl_[ptype.pdgcode()] = n * V * parameters.testparticles;
159  if (ptype.pdgcode().is_heavy_flavor()) {
160  average_multipl_[ptype.pdgcode()] *= hf_multiplier_;
161  }
162  }
163  }
164  }
165  double nb_init = 0.0, ns_init = 0.0, nq_init = 0.0;
166  for (const auto &mult : average_multipl_) {
167  const int thermal_mult_int = random::poisson(mult.second);
168  particles->create(thermal_mult_int, mult.first);
169  nb_init += mult.second * mult.first.baryon_number();
170  ns_init += mult.second * mult.first.strangeness();
171  nq_init += mult.second * mult.first.charge();
172  logg[LSphere].debug(mult.first, " initial multiplicity ",
173  thermal_mult_int);
174  }
175  logg[LSphere].info("Initial hadron gas baryon density ", nb_init);
176  logg[LSphere].info("Initial hadron gas strange density ", ns_init);
177  logg[LSphere].info("Initial hadron gas charge density ", nq_init);
179  logg[LSphere].info("Adding heavy flavor particles with multiplier ",
181  }
182  } else {
183  for (const auto &p : init_multipl_) {
184  particles->create(p.second * parameters.testparticles, p.first);
185  logg[LSphere].debug("Particle ", p.first, " initial multiplicity ",
186  p.second);
187  }
188  }
189  std::unique_ptr<QuantumSampling> quantum_sampling;
191  quantum_sampling = std::make_unique<QuantumSampling>(init_multipl_, V, T);
192  }
193  /* loop over particle data to fill in momentum and position information */
194  for (ParticleData &data : *particles) {
195  Angles phitheta;
196  /* thermal momentum according Maxwell-Boltzmann distribution */
197  double momentum_radial = 0.0, mass = data.pole_mass();
198  /* assign momentum_radial according to requested distribution */
199  switch (init_distr_) {
201  momentum_radial = sample_momenta_IC_ES(T);
202  break;
204  momentum_radial = sample_momenta_1M_IC(T, mass);
205  break;
207  momentum_radial = sample_momenta_2M_IC(T, mass);
208  break;
210  momentum_radial = sample_momenta_non_eq_mass(T, mass);
211  break;
213  default:
215  ? data.type().mass()
216  : HadronGasEos::sample_mass_thermal(data.type(), 1.0 / T);
217  momentum_radial = sample_momenta_from_thermal(T, mass);
218  break;
220  /*
221  * **********************************************************************
222  * Sampling the thermal momentum according Bose/Fermi/Boltzmann
223  * distribution.
224  * We take the pole mass as the mass.
225  * **********************************************************************
226  */
227  mass = data.type().mass();
228  momentum_radial = quantum_sampling->sample(data.pdgcode());
229  break;
230  }
231  phitheta.distribute_isotropically();
232  logg[LSphere].debug(data.type().name(), "(id ", data.id(),
233  ") radial momentum ", momentum_radial, ", direction",
234  phitheta);
235  data.set_4momentum(mass, phitheta.threevec() * momentum_radial);
236  momentum_total += data.momentum();
237  /* uniform sampling in a sphere with radius r */
238  double position_radial;
239  position_radial = std::cbrt(random::canonical()) * radius_;
240  Angles pos_phitheta;
241  pos_phitheta.distribute_isotropically();
242  data.set_4position(
243  FourVector(start_time_, pos_phitheta.threevec() * position_radial));
244  data.set_formation_time(start_time_);
245  if (data.type().pdgcode().is_heavy_flavor()) {
246  data.set_perturbative_weight(1.0 / hf_multiplier_);
247  }
248  }
249 
250  /* Boost in radial direction with an underlying velocity field of the form
251  * u_r = u_0 * (r / R)^n
252  */
253  if (radial_velocity_ > 0.0) {
254  for (ParticleData &data : *particles) {
255  double particle_radius = std::sqrt(data.position().sqr3());
256  auto e_r = data.position().threevec() / particle_radius;
257  auto radial_velocity =
258  -1.0 * radial_velocity_ * e_r *
259  std::pow(particle_radius / radius_, radial_velocity_exponent_);
260  data.set_4momentum(data.momentum().lorentz_boost(radial_velocity));
261  momentum_total += data.momentum();
262  }
263  }
264 
265  /* Make total 3-momentum in sphere 0 and set unpolarized spin vector if spin
266  * interactions are enabled */
267  for (ParticleData &data : *particles) {
268  data.set_4momentum(data.momentum().abs(),
269  data.momentum().threevec() -
270  momentum_total.threevec() / particles->size());
272  data.set_unpolarized_spin_vector();
273  }
274  }
275 
276  /* Add a single highly energetic particle in the center of the sphere (jet) */
277  if (jet_pdg_) {
278  auto &pdg = jet_pdg_.value();
279  auto &jet_particle = particles->create(pdg);
280  auto displacement = ThreeVector(jet_back_separation_ / 2., 0., 0.);
281  jet_particle.set_formation_time(start_time_);
282  jet_particle.set_4position(
283  FourVector(start_time_, jet_pos_ + displacement));
284  jet_particle.set_4momentum(ParticleType::find(pdg).mass(),
285  ThreeVector(jet_mom_, 0., 0.));
286  if (jet_back_) {
287  auto &anti_pdg = pdg.has_antiparticle() ? pdg.get_antiparticle() : pdg;
288  auto &jet_antiparticle = particles->create(anti_pdg);
289  jet_antiparticle.set_formation_time(start_time_);
290  jet_antiparticle.set_4position(
291  FourVector(start_time_, jet_pos_ - displacement));
292  jet_antiparticle.set_4momentum(ParticleType::find(anti_pdg).mass(),
293  ThreeVector(-jet_mom_, 0., 0.));
294  }
296  jet_particle.set_unpolarized_spin_vector();
297  }
298  }
299 
300  /* Recalculate total momentum */
301  momentum_total = FourVector(0, 0, 0, 0);
302  for (ParticleData &data : *particles) {
303  momentum_total += data.momentum();
304  /* IC: debug checks */
305  logg[LSphere].debug() << data;
306  }
307  /* allows to check energy conservation */
308  logg[LSphere].debug() << "Sphere initial total 4-momentum [GeV]: "
309  << momentum_total;
310  return start_time_;
311 }
312 } // namespace smash
Angles provides a common interface for generating directions: i.e., two angles that should be interpr...
Definition: angles.h:59
ThreeVector threevec() const
Definition: angles.h:288
void distribute_isotropically()
Populate the object with a new direction.
Definition: angles.h:199
Interface to the SMASH configuration files.
bool has_value(const Key< T > &key) const
Return whether there is a non-empty value behind the requested key (which is supposed not to refer to...
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:33
ThreeVector threevec() const
Definition: fourvector.h:329
static double partial_density(const ParticleType &ptype, double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
Compute partial density of one hadron sort.
Definition: hadgas_eos.cc:273
static double sample_mass_thermal(const ParticleType &ptype, double beta)
Sample resonance mass in a thermal medium.
Definition: hadgas_eos.cc:388
static bool is_eos_particle(const ParticleType &ptype)
Check if a particle belongs to the EoS.
Definition: hadgas_eos.h:354
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:59
A pointer-like interface to global references to ParticleType objects.
Definition: particletype.h:731
Particle type contains the static properties of a particle species.
Definition: particletype.h:100
ParticleTypePtr get_antiparticle() const
Definition: particletype.h:812
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode.
Definition: particletype.cc:99
const std::string & name() const
Definition: particletype.h:144
static const ParticleTypeList & list_all()
Definition: particletype.cc:51
bool has_antiparticle() const
Definition: particletype.h:162
The Particles class abstracts the storage and manipulation of particles.
Definition: particles.h:33
size_t size() const
Definition: particles.h:87
void create(size_t n, PdgCode pdg)
Add n particles of the same type (pdg) to the list.
Definition: particles.cc:66
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
Definition: pdgcode.h:108
SphereModus: Provides a modus for expanding matter calculations.
Definition: spheremodus.h:49
const bool account_for_resonance_widths_
In case of thermal initialization:
Definition: spheremodus.h:121
const bool use_thermal_
Whether to use a thermal initialization for all particles instead of specific numbers.
Definition: spheremodus.h:94
const double muq_
Charge chemical potential for thermal initialization; only used if use_thermal_ is true.
Definition: spheremodus.h:109
const ThreeVector jet_pos_
Initial position of the jet particle; only used if jet_pdg_ is not nullopt.
Definition: spheremodus.h:162
double sphere_temperature_
Temperature for momentum distribution (in GeV)
Definition: spheremodus.h:87
const double start_time_
Starting time for the Sphere.
Definition: spheremodus.h:89
const double radial_velocity_exponent_
Parameter in the initial flow velocity profile of particles in the sphere, which has the form .
Definition: spheremodus.h:146
const SphereInitialCondition init_distr_
Initialization scheme for momenta in the sphere; used for expanding metric setup.
Definition: spheremodus.h:136
const std::optional< PdgCode > jet_pdg_
Optional PDG code of the particle to use as a jet, i.e.
Definition: spheremodus.h:154
SphereModus(Configuration modus_config, const ExperimentParameters &parameters)
Constructor.
Definition: spheremodus.cc:37
const bool jet_back_
Create the back to back jet with the corresponding antiparticle; only used if jet_pdg_ is not nullopt...
Definition: spheremodus.h:167
const SpinInteractionType spin_interaction_type_
Spin interaction type.
Definition: spheremodus.h:174
const double hf_multiplier_
Multiplicative factor for thermal multiplicity of heavy flavored hadrons; only used if use_thermal_ i...
Definition: spheremodus.h:114
double initial_conditions(Particles *particles, const ExperimentParameters &parameters)
Generates initial state of the particles in the system according to specified parameters: number of p...
Definition: spheremodus.cc:143
std::map< PdgCode, double > average_multipl_
Average multiplicities in case of thermal initialization.
Definition: spheremodus.h:131
const double mub_
Baryon chemical potential for thermal initialization; only used if use_thermal_ is true.
Definition: spheremodus.h:99
const double jet_mom_
Initial momentum of the jet particle; only used if jet_pdg_ is not nullopt.
Definition: spheremodus.h:158
const std::map< PdgCode, int > init_multipl_
Particle multiplicities at initialization; required if use_thermal_ is false.
Definition: spheremodus.h:126
const double jet_back_separation_
Initial separation between the back to back jets; can only be set by the user if jet_back_ is true.
Definition: spheremodus.h:172
const double mus_
Strange chemical potential for thermal initialization; only used if use_thermal_ is true.
Definition: spheremodus.h:104
const double radial_velocity_
Parameter in the initial flow velocity profile of particles in the sphere, which has the form .
Definition: spheremodus.h:141
double radius_
Sphere radius (in fm)
Definition: spheremodus.h:85
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
Collection of useful constants that are known at compile time.
@ ThermalMomentaBoltzmann
A thermalized ensemble is generated, with momenta sampled from a Maxwell-Boltzmann distribution.
@ IC_ES
Off-equilibrium distribution used in massless comparisons of SMASH to the extended universe metric.
@ ThermalMomentaQuantum
A thermalized ensemble is generated, with momenta of baryons(mesons) sampled from a Fermi(Bose) distr...
@ IC_Massive
A generalization of IC_ES for the non-zero mass case; note that there is currently no analytical comp...
@ IC_2M
Off-equilibrium distribution used in massless comparisons of SMASH to the extended universe metric.
@ IC_1M
Off-equilibrium distribution used in massless comparisons of SMASH to the extended universe metric.
@ Off
No spin interactions.
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 Section m_s_jet
Subsection for the jet in sphere modus.
Definition: input_keys.h:202
constexpr int p
Proton.
constexpr int n
Neutron.
int poisson(const T &lam)
Returns a Poisson distributed random number.
Definition: random.h:270
T canonical()
Definition: random.h:122
Definition: action.h:24
static constexpr int LSphere
Definition: spheremodus.cc:35
double sample_momenta_from_thermal(const double temperature, const double mass)
Samples a momentum from the Maxwell-Boltzmann (thermal) distribution in a faster way,...
double sample_momenta_IC_ES(const double temperature)
Sample momenta according to the momentum distribution in Bazow:2016oky .
double sample_momenta_non_eq_mass(const double temperature, const double mass)
Samples a momentum via rejection method from the non-equilibrium distribution.
double sample_momenta_1M_IC(const double temperature, const double mass)
Samples a momentum from the non-equilibrium distribution 1M_IC from Bazow:2016oky .
double sample_momenta_2M_IC(const double temperature, const double mass)
Samples a momentum from the non-equilibrium distribution 2M_IC from Bazow:2016oky .
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:41
Helper structure for Experiment.
int testparticles
Number of test-particles.
A container to keep track of all ever existed input keys.
Definition: input_keys.h:1255
static const Key< double > modi_sphere_jet_backToBackSeparation
See user guide description for more information.
Definition: input_keys.h:5568