Version: SMASH-3.1
experiment.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2013-2023
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/experiment.h"
11 
12 #include <cstdint>
13 
14 #include "smash/boxmodus.h"
15 #include "smash/collidermodus.h"
16 #include "smash/listmodus.h"
17 #include "smash/spheremodus.h"
18 
19 namespace smash {
20 
21 /* ExperimentBase carries everything that is needed for the evolution */
22 ExperimentPtr ExperimentBase::create(Configuration &config,
23  const std::filesystem::path &output_path) {
24  if (!std::filesystem::exists(output_path)) {
25  throw NonExistingOutputPathRequest("The requested output path (" +
26  output_path.string() +
27  ") does not exist.");
28  }
30 
31  const std::string modus_chooser = config.read({"General", "Modus"});
32  logg[LExperiment].debug() << "Modus for this calculation: " << modus_chooser;
33 
34  if (modus_chooser == "Box") {
35  return std::make_unique<Experiment<BoxModus>>(config, output_path);
36  } else if (modus_chooser == "List") {
37  return std::make_unique<Experiment<ListModus>>(config, output_path);
38  } else if (modus_chooser == "ListBox") {
39  return std::make_unique<Experiment<ListBoxModus>>(config, output_path);
40  } else if (modus_chooser == "Collider") {
41  return std::make_unique<Experiment<ColliderModus>>(config, output_path);
42  } else if (modus_chooser == "Sphere") {
43  return std::make_unique<Experiment<SphereModus>>(config, output_path);
44  } else {
45  throw InvalidModusRequest("Invalid Modus (" + modus_chooser +
46  ") requested from ExperimentBase::create.");
47  }
48 }
49 
134 
135  const int ntest = config.take({"General", "Testparticles"}, 1);
136  if (ntest <= 0) {
137  throw std::invalid_argument("Testparticle number should be positive!");
138  }
139 
140  // sets whether to consider only participants in thermodynamic outputs or not
141  const bool only_participants =
142  config.take({"Output", "Thermodynamics", "Only_Participants"}, false);
143 
144  if (only_participants && config.has_value({"Potentials"})) {
145  throw std::invalid_argument(
146  "Only_Participants option cannot be "
147  "set to True when using Potentials.");
148  }
149 
150  const std::string modus_chooser = config.take({"General", "Modus"});
151  // remove config maps of unused Modi
152  config.remove_all_entries_in_section_but_one(modus_chooser, {"Modi"});
153 
154  double box_length = -1.0;
155  if (config.has_value({"Modi", "Box", "Length"})) {
156  box_length = config.read({"Modi", "Box", "Length"});
157  }
158 
159  if (config.has_value({"Modi", "ListBox", "Length"})) {
160  box_length = config.read({"Modi", "ListBox", "Length"});
161  }
162 
163  /* If this Delta_Time option is absent (this can be for timestepless mode)
164  * just assign 1.0 fm, reasonable value will be set at event initialization
165  */
166  const double dt = config.take({"General", "Delta_Time"}, 1.);
167  if (dt <= 0.) {
168  throw std::invalid_argument("Delta_Time cannot be zero or negative.");
169  }
170 
171  const double t_end = config.read({"General", "End_Time"});
172  if (t_end <= 0.) {
173  throw std::invalid_argument("End_Time cannot be zero or negative.");
174  }
175 
176  // Enforce a small time step, if the box modus is used
177  if (box_length > 0.0 && dt > box_length / 10.0) {
178  throw std::invalid_argument(
179  "Please decrease the timestep size. "
180  "A value of (dt <= l_box / 10) is necessary in the box modus.");
181  }
182 
183  // define output clock
184  std::unique_ptr<Clock> output_clock = nullptr;
185  if (config.has_value({"Output", "Output_Times"})) {
186  if (config.has_value({"Output", "Output_Interval"})) {
187  throw std::invalid_argument(
188  "Please specify either Output_Interval or Output_Times");
189  }
190  std::vector<double> output_times = config.take({"Output", "Output_Times"});
191  // Add an output time larger than the end time so that the next time is
192  // always defined during the time evolution
193  output_times.push_back(t_end + 1.);
194  output_clock = std::make_unique<CustomClock>(output_times);
195  } else {
196  const double output_dt = config.take({"Output", "Output_Interval"}, t_end);
197  if (output_dt <= 0.) {
198  throw std::invalid_argument(
199  "Output_Interval cannot be zero or negative.");
200  }
201  output_clock = std::make_unique<UniformClock>(0.0, output_dt, t_end);
202  }
203 
204  // Add proper error messages if photons are not configured properly.
205  // 1) Missing Photon config section.
206  if (config.has_value({"Output", "Photons"}) &&
207  (!config.has_value({"Collision_Term", "Photons"}))) {
208  throw std::invalid_argument(
209  "Photon output is enabled although photon production is disabled. "
210  "Photon production can be configured in the \"Photon\" subsection "
211  "of the \"Collision_Term\".");
212  }
213 
214  // 2) Missing Photon output section.
215  bool missing_output_2to2 = false;
216  bool missing_output_brems = false;
217  if (!(config.has_value({"Output", "Photons"}))) {
218  if (config.has_value({"Collision_Term", "Photons", "2to2_Scatterings"})) {
219  missing_output_2to2 =
220  config.read({"Collision_Term", "Photons", "2to2_Scatterings"});
221  }
222  if (config.has_value({"Collision_Term", "Photons", "Bremsstrahlung"})) {
223  missing_output_brems =
224  config.read({"Collision_Term", "Photons", "Bremsstrahlung"});
225  }
226 
227  if (missing_output_2to2 || missing_output_brems) {
228  throw std::invalid_argument(
229  "Photon output is disabled although photon production is enabled. "
230  "Please enable the photon output.");
231  }
232  }
233 
234  // Add proper error messages if dileptons are not configured properly.
235  // 1) Missing Dilepton config section.
236  if (config.has_value({"Output", "Dileptons"}) &&
237  (!config.has_value({"Collision_Term", "Dileptons"}))) {
238  throw std::invalid_argument(
239  "Dilepton output is enabled although dilepton production is disabled. "
240  "Dilepton production can be configured in the \"Dileptons\" subsection "
241  "of the \"Collision_Term\".");
242  }
243 
244  // 2) Missing Dilepton output section.
245  bool missing_output_decays = false;
246  if (!(config.has_value({"Output", "Dileptons"}))) {
247  if (config.has_value({"Collision_Term", "Dileptons", "Decays"})) {
248  missing_output_decays =
249  config.read({"Collision_Term", "Dileptons", "Decays"});
250  }
251 
252  if (missing_output_decays) {
253  throw std::invalid_argument(
254  "Dilepton output is disabled although dilepton production is "
255  "enabled. "
256  "Please enable the dilepton output.");
257  }
258  }
259  /* Elastic collisions between the nucleons with the square root s
260  * below low_snn_cut are excluded. */
261  const double low_snn_cut =
262  config.take({"Collision_Term", "Elastic_NN_Cutoff_Sqrts"}, 1.98);
263  const auto proton = ParticleType::try_find(pdg::p);
264  const auto pion = ParticleType::try_find(pdg::pi_z);
265  if (proton && pion &&
266  low_snn_cut > proton->mass() + proton->mass() + pion->mass()) {
267  logg[LExperiment].warn("The cut-off should be below the threshold energy",
268  " of the process: NN to NNpi");
269  }
270  const bool potential_affect_threshold =
271  config.take({"Lattice", "Potentials_Affect_Thresholds"}, false);
272  const double scale_xs =
273  config.take({"Collision_Term", "Cross_Section_Scaling"}, 1.0);
274 
275  const auto criterion = config.take({"Collision_Term", "Collision_Criterion"},
277 
278  if (config.has_value({"Collision_Term", "Fixed_Min_Cell_Length"}) &&
279  criterion != CollisionCriterion::Stochastic) {
280  throw std::invalid_argument(
281  "Only use a fixed minimal cell length with the stochastic collision "
282  "criterion.");
283  }
284  if (config.has_value({"Collision_Term", "Maximum_Cross_Section"}) &&
285  criterion == CollisionCriterion::Stochastic) {
286  throw std::invalid_argument(
287  "Only use maximum cross section with the "
288  "geometric collision criterion. Use Fixed_Min_Cell_Length to change "
289  "the grid "
290  "size for the stochastic criterion.");
291  }
292 
301  const double maximum_cross_section_default =
302  ParticleType::exists("d'") ? 2000.0 : 200.0;
303 
304  double maximum_cross_section =
305  config.take({"Collision_Term", "Maximum_Cross_Section"},
306  maximum_cross_section_default);
307  maximum_cross_section *= scale_xs;
308  return {
309  std::make_unique<UniformClock>(0.0, dt, t_end),
310  std::move(output_clock),
311  config.take({"General", "Ensembles"}, 1),
312  ntest,
313  config.take({"General", "Derivatives_Mode"},
315  config.has_value({"Potentials", "VDF"})
318  config.take({"General", "Field_Derivatives_Mode"},
320  config.take({"General", "Smearing_Mode"},
322  config.take({"General", "Gaussian_Sigma"}, 1.),
323  config.take({"General", "Gauss_Cutoff_In_Sigma"}, 4.),
324  config.take({"General", "Discrete_Weight"}, 1. / 3.0),
325  config.take({"General", "Triangular_Range"}, 2.0),
326  criterion,
327  config.take({"Collision_Term", "Two_to_One"}, true),
328  config.take({"Collision_Term", "Included_2to2"}, ReactionsBitSet().set()),
329  config.take({"Collision_Term", "Multi_Particle_Reactions"},
330  MultiParticleReactionsBitSet().reset()),
331  config.take({"Collision_Term", "Strings"}, modus_chooser != "Box"),
332  config.take({"Collision_Term", "Resonance_Lifetime_Modifier"}, 1.),
333  config.take({"Collision_Term", "NNbar_Treatment"},
335  low_snn_cut,
336  potential_affect_threshold,
337  box_length,
338  maximum_cross_section,
339  config.take({"Collision_Term", "Fixed_Min_Cell_Length"}, 2.5),
340  scale_xs,
341  only_participants,
342  config.take({"Collision_Term", "Include_Weak_And_EM_Decays_At_The_End"},
343  false),
344  config.take({"Collision_Term", "Decay_Initial_Particles"},
345  InputKeys::collTerm_decayInitial.default_value()),
346  std::nullopt};
347 }
348 
349 std::string format_measurements(const std::vector<Particles> &ensembles,
350  uint64_t scatterings_this_interval,
351  const QuantumNumbers &conserved_initial,
352  SystemTimePoint time_start, double time,
353  double E_mean_field,
354  double E_mean_field_initial) {
355  const SystemTimeSpan elapsed_seconds = SystemClock::now() - time_start;
356 
357  const QuantumNumbers current_values(ensembles);
358  const QuantumNumbers difference = current_values - conserved_initial;
359  int total_particles = 0;
360  for (const Particles &particles : ensembles) {
361  total_particles += particles.size();
362  }
363 
364  // Make sure there are no FPEs in case of IC output, were there will
365  // eventually be no more particles in the system
366  const double current_energy = current_values.momentum().x0();
367  const double energy_per_part =
368  (total_particles > 0) ? (current_energy + E_mean_field) / total_particles
369  : 0.0;
370 
371  std::ostringstream ss;
372  // clang-format off
373  ss << field<7, 3> << time
374  // total kinetic energy in the system
375  << field<11, 3> << current_energy
376  // total mean field energy in the system
377  << field<11, 3> << E_mean_field
378  // total energy in the system
379  << field<12, 3> << current_energy + E_mean_field
380  // total energy per particle in the system
381  << field<12, 6> << energy_per_part;
382  // change in total energy per particle (unless IC output is enabled)
383  if (total_particles == 0) {
384  ss << field<13, 6> << "N/A";
385  } else {
386  ss << field<13, 6> << (difference.momentum().x0()
387  + E_mean_field - E_mean_field_initial)
388  / total_particles;
389  }
390  ss << field<14, 3> << scatterings_this_interval
391  << field<10, 3> << total_particles
392  << field<9, 3> << elapsed_seconds;
393  // clang-format on
394  return ss.str();
395 }
396 
398  const Potentials &potentials,
400  RectangularLattice<std::pair<ThreeVector, ThreeVector>> *em_lattice,
401  const ExperimentParameters &parameters) {
402  // basic parameters and variables
403  const double V_cell = (jmuB_lat.cell_sizes())[0] *
404  (jmuB_lat.cell_sizes())[1] * (jmuB_lat.cell_sizes())[2];
405 
406  double E_mean_field = 0.0;
407  double density_mean = 0.0;
408  double density_variance = 0.0;
409 
410  /*
411  * We anticipate having other options, like the vector DFT potentials, in the
412  * future, hence we include checking which potentials are used.
413  */
414  if (potentials.use_skyrme()) {
415  /*
416  * Calculating the symmetry energy contribution to the total mean field
417  * energy in the system is not implemented at this time.
418  */
419  if (potentials.use_symmetry() &&
420  parameters.outputclock->current_time() == 0.0) {
421  logg[LExperiment].warn()
422  << "Note:"
423  << "\nSymmetry energy is not included in the mean field calculation."
424  << "\n\n";
425  }
426 
427  /*
428  * Skyrme potential parameters:
429  * C1GeV are the Skyrme coefficients converted to GeV,
430  * b1 are the powers of the baryon number density entering the expression
431  * for the energy density of the system. Note that these exponents are
432  * larger by 1 than those for the energy of a particle (which are used in
433  * Potentials class). The formula for a total mean field energy due to a
434  * Skyrme potential is E_MF = \sum_i (C_i/b_i) ( n_B^b_i )/( n_0^(b_i - 1) )
435  * where nB is the local rest frame baryon number density and n_0 is the
436  * saturation density. Then the single particle potential follows from
437  * V = d E_MF / d n_B .
438  */
439  double C1GeV = (potentials.skyrme_a()) / 1000.0;
440  double C2GeV = (potentials.skyrme_b()) / 1000.0;
441  double b1 = 2.0;
442  double b2 = (potentials.skyrme_tau()) + 1.0;
443 
444  /*
445  * Note: calculating the mean field only works if lattice is used.
446  * We iterate over the nodes of the baryon density lattice to sum their
447  * contributions to the total mean field.
448  */
449  int number_of_nodes = 0;
450  double lattice_mean_field_total = 0.0;
451 
452  for (auto &node : jmuB_lat) {
453  number_of_nodes++;
454  // the rest frame density
455  double rhoB = node.rho();
456  // the computational frame density
457  const double j0B = node.jmu_net().x0();
458 
459  const double abs_rhoB = std::abs(rhoB);
460  if (abs_rhoB < very_small_double) {
461  continue;
462  }
463  density_mean += j0B;
464  density_variance += j0B * j0B;
465 
466  /*
467  * The mean-field energy for the Skyrme potential. Note: this expression
468  * is only exact in the rest frame, and is expected to significantly
469  * deviate from the correct value for systems that are considerably
470  * relativistic. Note: symmetry energy is not taken into the account.
471  *
472  * TODO: Add symmetry energy.
473  */
474  double mean_field_contribution_1 = (C1GeV / b1) * std::pow(abs_rhoB, b1) /
475  std::pow(nuclear_density, b1 - 1);
476  double mean_field_contribution_2 = (C2GeV / b2) * std::pow(abs_rhoB, b2) /
477  std::pow(nuclear_density, b2 - 1);
478 
479  lattice_mean_field_total +=
480  V_cell * (mean_field_contribution_1 + mean_field_contribution_2);
481  }
482 
483  // logging statistical properties of the density calculation
484  density_mean = density_mean / number_of_nodes;
485  density_variance = density_variance / number_of_nodes;
486  double density_scaled_variance =
487  std::sqrt(density_variance - density_mean * density_mean) /
488  density_mean;
489  logg[LExperiment].debug() << "\t\t\t\t\t";
490  logg[LExperiment].debug()
491  << "\n\t\t\t\t\t density mean = " << density_mean;
492  logg[LExperiment].debug()
493  << "\n\t\t\t\t\t density scaled variance = " << density_scaled_variance;
494  logg[LExperiment].debug()
495  << "\n\t\t\t\t\t total mean_field = "
496  << lattice_mean_field_total * parameters.testparticles *
497  parameters.n_ensembles
498  << "\n";
499 
500  E_mean_field = lattice_mean_field_total;
501  } // if (potentials.use_skyrme())
502 
503  if (potentials.use_vdf()) {
504  /*
505  * Safety check:
506  * Calculating the symmetry energy contribution to the total mean field
507  * energy in the system is not implemented at this time.
508  */
509  if (potentials.use_symmetry() &&
510  parameters.outputclock->current_time() == 0.0) {
511  logg[LExperiment].error()
512  << "\nSymmetry energy is not included in the VDF mean-field "
513  "calculation"
514  << "\nas VDF potentials haven't been fitted with symmetry energy."
515  << "\n\n";
516  }
517 
518  /*
519  * The total mean-field energy density due to a VDF potential is
520  * E_MF = \sum_i C_i rho^(b_i - 2) *
521  * * [j_0^2 - rho^2 * (b_i - 1)/b_i] / rho_0^(b_i - 1)
522  * where j_0 is the local computational frame baryon density, rho is the
523  * local rest frame baryon density, and rho_0 is the saturation density.
524  */
525 
526  // saturation density of nuclear matter specified in the VDF parameters
527  double rhoB_0 = potentials.saturation_density();
528 
529  /*
530  * Note: calculating the mean field only works if lattice is used.
531  * We iterate over the nodes of the baryon density lattice to sum their
532  * contributions to the total mean field.
533  */
534  int number_of_nodes = 0;
535  double lattice_mean_field_total = 0.0;
536 
537  for (auto &node : jmuB_lat) {
538  number_of_nodes++;
539  // the rest frame density
540  double rhoB = node.rho();
541  // the computational frame density
542  const double j0B = node.jmu_net().x0();
543  double abs_rhoB = std::abs(rhoB);
544  density_mean += j0B;
545  density_variance += j0B * j0B;
546 
547  /*
548  * The mean-field energy for the VDF potential. This expression is correct
549  * in any frame, and in the rest frame conforms to the Skyrme mean-field
550  * energy (if same coefficients and powers are used).
551  */
552  // in order to prevent dividing by zero in case any b_i < 2.0
553  if (abs_rhoB < very_small_double) {
554  abs_rhoB = very_small_double;
555  }
556  double mean_field_contribution = 0.0;
557  for (int i = 0; i < potentials.number_of_terms(); i++) {
558  mean_field_contribution +=
559  potentials.coeffs()[i] *
560  std::pow(abs_rhoB, potentials.powers()[i] - 2.0) *
561  (j0B * j0B -
562  ((potentials.powers()[i] - 1.0) / potentials.powers()[i]) *
563  abs_rhoB * abs_rhoB) /
564  std::pow(rhoB_0, potentials.powers()[i] - 1.0);
565  }
566  lattice_mean_field_total += V_cell * mean_field_contribution;
567  }
568 
569  // logging statistical properties of the density calculation
570  density_mean = density_mean / number_of_nodes;
571  density_variance = density_variance / number_of_nodes;
572  double density_scaled_variance =
573  std::sqrt(density_variance - density_mean * density_mean) /
574  density_mean;
575  logg[LExperiment].debug() << "\t\t\t\t\t";
576  logg[LExperiment].debug()
577  << "\n\t\t\t\t\t density mean = " << density_mean;
578  logg[LExperiment].debug()
579  << "\n\t\t\t\t\t density scaled variance = " << density_scaled_variance;
580  logg[LExperiment].debug()
581  << "\n\t\t\t\t\t total mean_field = "
582  << lattice_mean_field_total * parameters.testparticles *
583  parameters.n_ensembles
584  << "\n";
585 
586  E_mean_field = lattice_mean_field_total;
587  }
588 
589  double electromagnetic_potential = 0.0;
590  if (potentials.use_coulomb() && em_lattice) {
591  // Use cell volume of electromagnetic fields lattice even though it should
592  // be the same as for net-baryon density
593  double V_cell_em = em_lattice->cell_sizes()[0] *
594  em_lattice->cell_sizes()[1] *
595  em_lattice->cell_sizes()[2];
596  for (auto &fields : *em_lattice) {
597  // Energy is 0.5 * int E^2 + B^2 dV
598  electromagnetic_potential +=
599  hbarc * 0.5 * V_cell_em * (fields.first.sqr() + fields.second.sqr());
600  }
601  }
602  logg[LExperiment].debug() << "Total energy in electromagnetic field = "
603  << electromagnetic_potential;
604  E_mean_field += electromagnetic_potential;
605  /*
606  * E_mean_field is multiplied by the number of testparticles per particle and
607  * the number of parallel ensembles because the total kinetic energy tracked
608  * is that of all particles in the simulation, including test-particles and/or
609  * ensembles, and so this way is more consistent.
610  */
611  E_mean_field =
612  E_mean_field * parameters.testparticles * parameters.n_ensembles;
613 
614  return E_mean_field;
615 }
616 
617 EventInfo fill_event_info(const std::vector<Particles> &ensembles,
618  double E_mean_field, double modus_impact_parameter,
619  const ExperimentParameters &parameters,
620  bool projectile_target_interact,
621  bool kinematic_cut_for_SMASH_IC) {
622  const QuantumNumbers current_values(ensembles);
623  const double E_kinetic_total = current_values.momentum().x0();
624  const double E_total = E_kinetic_total + E_mean_field;
625 
626  EventInfo event_info{modus_impact_parameter,
627  parameters.box_length,
628  parameters.outputclock->current_time(),
629  E_kinetic_total,
630  E_mean_field,
631  E_total,
632  parameters.testparticles,
633  parameters.n_ensembles,
634  !projectile_target_interact,
635  kinematic_cut_for_SMASH_IC};
636  return event_info;
637 }
638 
639 void validate_and_adjust_particle_list(ParticleList &particle_list) {
640  static bool warn_mass_discrepancy = true;
641  static bool warn_off_shell_particle = true;
642  for (auto it = particle_list.begin(); it != particle_list.end();) {
643  auto &particle = *it;
644  auto pdgcode = particle.pdgcode();
645  try {
646  // Convert Kaon-L or Kaon-S into K0 or Anti-K0 used in SMASH
647  if (pdgcode == 0x310 || pdgcode == 0x130) {
648  pdgcode = (random::uniform_int(0, 1) == 0) ? pdg::K_z : pdg::Kbar_z;
649  }
650  /* ATTENTION: It would be wrong to directly assign here the return value
651  * to 'particle', because this would potentially also change its id and
652  * process number, which in turn, might lead to actions to be discarded.
653  * Here, only the particle momentum has to be adjusted and this is done
654  * creating a new particle and using its momentum to set 'particle' one.
655  * The position and momentum of the particle are checked for nan values.
656  */
657  auto valid_smash_particle =
659  pdgcode, particle.effective_mass(), particle.position(),
660  particle.momentum(), LExperiment, warn_mass_discrepancy,
661  warn_off_shell_particle);
662  particle.set_4position(valid_smash_particle.position());
663  particle.set_4momentum(valid_smash_particle.momentum());
664  particle.set_cross_section_scaling_factor(
665  valid_smash_particle.xsec_scaling_factor());
666  it++;
668  logg[LExperiment].warn()
669  << "SMASH does not recognize pdg code " << pdgcode
670  << " obtained from hadron list. This particle will be ignored.\n";
671  it = particle_list.erase(it);
672  }
673  }
674 }
675 
676 } // namespace smash
Interface to the SMASH configuration files.
bool has_value(std::initializer_list< const char * > keys) const
Return whether there is a non-empty value behind the requested keys.
void remove_all_entries_in_section_but_one(const std::string &key, std::initializer_list< const char * > section={})
Remove all entries in the given section except for key.
Value take(std::initializer_list< const char * > keys)
The default interface for SMASH to read configuration values.
Value read(std::initializer_list< const char * > keys) const
Additional interface for SMASH to read configuration values without removing them.
static std::unique_ptr< ExperimentBase > create(Configuration &config, const std::filesystem::path &output_path)
Factory method that creates and initializes a new Experiment<Modus>.
Definition: experiment.cc:22
double x0() const
Definition: fourvector.h:313
static const ParticleTypePtr try_find(PdgCode pdgcode)
Returns the ParticleTypePtr for the given pdgcode.
Definition: particletype.cc:89
static bool exists(PdgCode pdgcode)
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
const std::vector< double > & powers() const
Definition: potentials.h:459
virtual bool use_symmetry() const
Definition: potentials.h:435
const std::vector< double > & coeffs() const
Definition: potentials.h:457
virtual bool use_skyrme() const
Definition: potentials.h:433
virtual bool use_coulomb() const
Definition: potentials.h:437
double skyrme_a() const
Definition: potentials.h:444
double skyrme_tau() const
Definition: potentials.h:448
int number_of_terms() const
Definition: potentials.h:461
double skyrme_b() const
Definition: potentials.h:446
virtual bool use_vdf() const
Definition: potentials.h:453
double saturation_density() const
Definition: potentials.h:455
A container for storing conserved values.
FourVector momentum() const
A container class to hold all the arrays on the lattice and access them.
Definition: lattice.h:47
const std::array< double, 3 > & cell_sizes() const
Definition: lattice.h:160
std::bitset< 10 > ReactionsBitSet
Container for the 2 to 2 reactions in the code.
@ Strings
Use string fragmentation.
std::bitset< 4 > MultiParticleReactionsBitSet
Container for the n to m reactions in the code.
@ Stochastic
Stochastic Criteiron.
@ Covariant
Covariant Criterion.
#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
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
constexpr int K_z
K⁰.
constexpr int p
Proton.
constexpr int pi_z
π⁰.
constexpr int Kbar_z
K̄⁰.
T uniform_int(T min, T max)
Definition: random.h:100
Definition: action.h:24
EventInfo fill_event_info(const std::vector< Particles > &ensembles, double E_mean_field, double modus_impact_parameter, const ExperimentParameters &parameters, bool projectile_target_interact, bool kinematic_cut_for_SMASH_IC)
Generate the EventInfo object which is passed to outputs_.
Definition: experiment.cc:617
SystemClock::duration SystemTimeSpan
The time duration type (alias) used for measuring run times.
Definition: chrono.h:28
std::string format_measurements(const std::vector< Particles > &ensembles, uint64_t scatterings_this_interval, const QuantumNumbers &conserved_initial, SystemTimePoint time_start, double time, double E_mean_field, double E_mean_field_initial)
Generate a string which will be printed to the screen when SMASH is running.
Definition: experiment.cc:349
ExperimentParameters create_experiment_parameters(Configuration &config)
Gathers all general Experiment parameters.
Definition: experiment.cc:132
constexpr double very_small_double
A very small double, used to avoid division by zero.
Definition: constants.h:40
double calculate_mean_field_energy(const Potentials &potentials, RectangularLattice< smash::DensityOnLattice > &jmu_B_lat, RectangularLattice< std::pair< ThreeVector, ThreeVector >> *em_lattice, const ExperimentParameters &parameters)
Calculate the total mean field energy of the system; this will be printed to the screen when SMASH is...
Definition: experiment.cc:397
static constexpr int LExperiment
void validate_and_adjust_particle_list(ParticleList &particle_list)
Validate a particle list adjusting each particle to be a valid SMASH particle.
Definition: experiment.cc:639
constexpr double nuclear_density
Ground state density of symmetric nuclear matter [fm^-3].
Definition: constants.h:48
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 hbarc
GeV <-> fm conversion factor.
Definition: constants.h:25
std::chrono::time_point< std::chrono::system_clock > SystemTimePoint
Type (alias) that is used to store the current time.
Definition: chrono.h:22
Structure to contain custom data for output.
Exception class that is thrown if an invalid modus is requested from the Experiment factory.
Definition: experiment.h:144
Exception class that is thrown if the requested output path in the Experiment factory is not existing...
Definition: experiment.h:153
Helper structure for Experiment.
double box_length
Length of the box in fm in case of box modus, otherwise -1.
int n_ensembles
Number of parallel ensembles.
std::unique_ptr< Clock > outputclock
Output clock to keep track of the next output time.
int testparticles
Number of test-particles.