Version: SMASH-1.5
experiment.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2018
3  * SMASH Team
4  *
5  * GNU General Public License (GPLv3 or later)
6  */
7 #ifndef SRC_INCLUDE_EXPERIMENT_H_
8 #define SRC_INCLUDE_EXPERIMENT_H_
9 
10 #include <limits>
11 #include <memory>
12 #include <string>
13 #include <vector>
14 
15 #include "actionfinderfactory.h"
16 #include "actions.h"
17 #include "chrono.h"
18 #include "decayactionsfinder.h"
20 #include "energymomentumtensor.h"
21 #include "fourvector.h"
22 #include "grandcan_thermalizer.h"
23 #include "grid.h"
24 #include "outputparameters.h"
25 #include "pauliblocking.h"
26 #include "potential_globals.h"
27 #include "potentials.h"
28 #include "processstring.h"
29 #include "propagation.h"
30 #include "quantumnumbers.h"
31 #include "scatteractionphoton.h"
32 #include "scatteractionsfinder.h"
33 #include "thermalizationaction.h"
34 // Output
35 #include "binaryoutput.h"
36 #include "oscaroutput.h"
37 #include "thermodynamicoutput.h"
38 #ifdef SMASH_USE_ROOT
39 #include "rootoutput.h"
40 #endif
41 #include "vtkoutput.h"
42 #include "wallcrossingaction.h"
43 
44 namespace std {
55 template <typename T, typename Ratio>
56 static ostream &operator<<(ostream &out,
57  const chrono::duration<T, Ratio> &seconds) {
58  using Seconds = chrono::duration<double>;
59  using Minutes = chrono::duration<double, std::ratio<60>>;
60  using Hours = chrono::duration<double, std::ratio<60 * 60>>;
61  constexpr Minutes threshold_for_minutes{10};
62  constexpr Hours threshold_for_hours{3};
63  if (seconds < threshold_for_minutes) {
64  return out << Seconds(seconds).count() << " [s]";
65  }
66  if (seconds < threshold_for_hours) {
67  return out << Minutes(seconds).count() << " [min]";
68  }
69  return out << Hours(seconds).count() << " [h]";
70 }
71 } // namespace std
72 
73 namespace smash {
74 
83  public:
84  ExperimentBase() = default;
89  virtual ~ExperimentBase() = default;
90 
111  static std::unique_ptr<ExperimentBase> create(Configuration config,
112  const bf::path &output_path);
113 
120  virtual void run() = 0;
121 
127  struct InvalidModusRequest : public std::invalid_argument {
128  using std::invalid_argument::invalid_argument;
129  };
130 };
131 
132 template <typename Modus>
134 template <typename Modus>
135 std::ostream &operator<<(std::ostream &out, const Experiment<Modus> &e);
136 
161 template <typename Modus>
162 class Experiment : public ExperimentBase {
163  friend class ExperimentBase;
164 
165  public:
172  void run() override;
173 
187  explicit Experiment(Configuration config, const bf::path &output_path);
188 
194  void initialize_new_event();
195 
202  void run_time_evolution();
203 
205  void do_final_decays();
206 
212  void final_output(const int evt_num);
213 
219 
224  Modus *modus() { return &modus_; }
225 
226  private:
238  template <typename Container>
239  bool perform_action(Action &action,
240  const Container &particles_before_actions);
249  void create_output(const std::string &format, const std::string &content,
250  const bf::path &output_path, const OutputParameters &par);
251 
258  void propagate_and_shine(double to_time);
259 
273 
275  void intermediate_output();
276 
278  void update_potentials();
279 
288  double compute_min_cell_length(double dt) const {
289  return std::sqrt(4 * dt * dt + max_transverse_distance_sqr_);
290  }
291 
293  double next_output_time() const {
295  }
296 
303 
306 
311  Modus modus_;
312 
315 
320  std::unique_ptr<Potentials> potentials_;
321 
326  std::unique_ptr<PauliBlocker> pauli_blocker_;
327 
332  OutputsList outputs_;
333 
335  OutputPtr dilepton_output_;
336 
338  OutputPtr photon_output_;
339 
345  std::vector<bool> nucleon_has_interacted_ = {};
346 
352  std::vector<FourVector> beam_momentum_ = {};
353 
355  std::vector<std::unique_ptr<ActionFinderInterface>> action_finders_;
356 
358  std::unique_ptr<DecayActionsFinderDilepton> dilepton_finder_;
359 
361  std::unique_ptr<ActionFinderInterface> photon_finder_;
362 
365 
367  std::unique_ptr<DensityLattice> jmu_B_lat_;
368 
370  std::unique_ptr<DensityLattice> jmu_I3_lat_;
371 
379  std::unique_ptr<DensityLattice> jmu_custom_lat_;
380 
383 
388  std::unique_ptr<RectangularLattice<FourVector>> UB_lat_ = nullptr;
389 
394  std::unique_ptr<RectangularLattice<FourVector>> UI3_lat_ = nullptr;
395 
397  std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
399 
401  std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
403 
405  std::unique_ptr<RectangularLattice<EnergyMomentumTensor>> Tmn_;
406 
408  bool printout_tmn_ = false;
409 
411  bool printout_tmn_landau_ = false;
412 
414  bool printout_v_landau_ = false;
415 
417  bool printout_lattice_td_ = false;
418 
420  std::unique_ptr<GrandCanThermalizer> thermalizer_;
421 
427 
442  const int nevents_;
443 
445  const double end_time_;
446 
452  const double delta_time_startup_;
453 
458  const bool force_decays_;
459 
461  const bool use_grid_;
462 
465 
467  const bool dileptons_switch_;
468 
470  const bool photons_switch_;
471 
474 
476  double max_transverse_distance_sqr_ = std::numeric_limits<double>::max();
477 
486 
488  SystemTimePoint time_start_ = SystemClock::now();
489 
492 
497  uint64_t interactions_total_ = 0;
498 
504 
509  uint64_t wall_actions_total_ = 0;
510 
516 
521  uint64_t total_pauli_blocked_ = 0;
522 
524  int64_t seed_ = -1;
525 
531  friend std::ostream &operator<<<>(std::ostream &out, const Experiment &e);
532 };
533 
535 template <typename Modus>
536 std::ostream &operator<<(std::ostream &out, const Experiment<Modus> &e) {
537  out << "End time: " << e.end_time_ << " fm/c\n";
538  out << e.modus_;
539  return out;
540 }
541 
542 template <typename Modus>
543 void Experiment<Modus>::create_output(const std::string &format,
544  const std::string &content,
545  const bf::path &output_path,
546  const OutputParameters &out_par) {
547  const auto &log = logger<LogArea::Experiment>();
548  log.info() << "Adding output " << content << " of format " << format
549  << std::endl;
550 
551  if (format == "VTK" && content == "Particles") {
552  outputs_.emplace_back(
553  make_unique<VtkOutput>(output_path, content, out_par));
554  } else if (format == "Root") {
555 #ifdef SMASH_USE_ROOT
556  outputs_.emplace_back(
557  make_unique<RootOutput>(output_path, content, out_par));
558 #else
559  log.error("Root output requested, but Root support not compiled in");
560 #endif
561  } else if (format == "Binary") {
562  if (content == "Collisions" || content == "Dileptons" ||
563  content == "Photons") {
564  outputs_.emplace_back(
565  make_unique<BinaryOutputCollisions>(output_path, content, out_par));
566  } else if (content == "Particles") {
567  outputs_.emplace_back(
568  make_unique<BinaryOutputParticles>(output_path, content, out_par));
569  }
570  } else if (format == "Oscar1999" || format == "Oscar2013") {
571  outputs_.emplace_back(
572  create_oscar_output(format, content, output_path, out_par));
573  } else if (content == "Thermodynamics" && format == "ASCII") {
574  outputs_.emplace_back(
575  make_unique<ThermodynamicOutput>(output_path, content, out_par));
576  } else if (content == "Thermodynamics" && format == "VTK") {
577  printout_lattice_td_ = true;
578  outputs_.emplace_back(
579  make_unique<VtkOutput>(output_path, content, out_par));
580  } else {
581  log.error() << "Unknown combination of format (" << format
582  << ") and content (" << content << "). Fix the config.";
583  }
584 }
585 
594 
708 template <typename Modus>
709 Experiment<Modus>::Experiment(Configuration config, const bf::path &output_path)
710  : parameters_(create_experiment_parameters(config)),
711  density_param_(DensityParameters(parameters_)),
712  modus_(config["Modi"], parameters_),
713  particles_(),
714  nevents_(config.take({"General", "Nevents"})),
715  end_time_(config.take({"General", "End_Time"})),
716  delta_time_startup_(parameters_.labclock.timestep_duration()),
717  force_decays_(
718  config.take({"Collision_Term", "Force_Decays_At_End"}, true)),
719  use_grid_(config.take({"General", "Use_Grid"}, true)),
720  metric_(
721  config.take({"General", "Metric_Type"}, ExpansionMode::NoExpansion),
722  config.take({"General", "Expansion_Rate"}, 0.1)),
723  dileptons_switch_(config.has_value({"Output", "Dileptons"})),
724  photons_switch_(config.has_value({"Output", "Photons"})),
725  time_step_mode_(
726  config.take({"General", "Time_Step_Mode"}, TimeStepMode::Fixed)) {
727  const auto &log = logger<LogArea::Experiment>();
728  log.info() << *this;
729 
730  // create finders
731  if (dileptons_switch_) {
732  dilepton_finder_ = make_unique<DecayActionsFinderDilepton>();
733  }
734  if (parameters_.photons_switch) {
735  n_fractional_photons_ = config.take({"Output", "Photons", "Fractions"});
736  }
737  if (parameters_.two_to_one) {
738  action_finders_.emplace_back(make_unique<DecayActionsFinder>());
739  }
740  bool no_coll = config.take({"Collision_Term", "No_Collisions"}, false);
741  if ((parameters_.two_to_one || parameters_.included_2to2.any() ||
742  parameters_.strings_switch) &&
743  !no_coll) {
744  auto scat_finder = make_unique<ScatterActionsFinder>(
745  config, parameters_, nucleon_has_interacted_, modus_.total_N_number(),
746  modus_.proj_N_number());
747  max_transverse_distance_sqr_ =
748  scat_finder->max_transverse_distance_sqr(parameters_.testparticles);
749  process_string_ptr_ = scat_finder->get_process_string_ptr();
750  action_finders_.emplace_back(std::move(scat_finder));
751  } else {
752  max_transverse_distance_sqr_ = maximum_cross_section / M_PI * fm2_mb;
753  process_string_ptr_ = NULL;
754  }
755  const double modus_l = modus_.length();
756  if (modus_l > 0.) {
757  action_finders_.emplace_back(make_unique<WallCrossActionsFinder>(modus_l));
758  }
759 
760  if (config.has_value({"Collision_Term", "Pauli_Blocking"})) {
761  log.info() << "Pauli blocking is ON.";
762  pauli_blocker_ = make_unique<PauliBlocker>(
763  config["Collision_Term"]["Pauli_Blocking"], parameters_);
764  }
766  config.take({"Collision_Term", "Power_Particle_Formation"}, 1.);
767 
801  // create outputs
802  log.trace(source_location, " create OutputInterface objects");
803 
804  auto output_conf = config["Output"];
1023  dens_type_ = config.take({"Output", "Density_Type"}, DensityType::None);
1024  log.debug() << "Density type printed to headers: " << dens_type_;
1025 
1026  const OutputParameters output_parameters(std::move(output_conf));
1027 
1028  std::vector<std::string> output_contents = output_conf.list_upmost_nodes();
1029  for (const auto &content : output_contents) {
1030  auto this_output_conf = output_conf[content.c_str()];
1031  std::vector<std::string> formats = this_output_conf.take({"Format"});
1032  for (const auto &format : formats) {
1033  create_output(format, content, output_path, output_parameters);
1034  }
1035  }
1036 
1037  /* We can take away the Fermi motion flag, because the collider modus is
1038  * already initialized. We only need it when potentials are enabled, but we
1039  * always have to take it, otherwise SMASH will complain about unused
1040  * options. We have to provide a default value for modi other than Collider.
1041  */
1042  const FermiMotion motion =
1043  config.take({"Modi", "Collider", "Fermi_Motion"}, FermiMotion::Off);
1044  if (config.has_value({"Potentials"})) {
1045  if (time_step_mode_ == TimeStepMode::None) {
1046  log.error() << "Potentials only work with time steps!";
1047  throw std::invalid_argument("Can't use potentials without time steps!");
1048  }
1049  if (motion == FermiMotion::Frozen) {
1050  log.error() << "Potentials don't work with frozen Fermi momenta! "
1051  "Use normal Fermi motion instead.";
1052  throw std::invalid_argument(
1053  "Can't use potentials "
1054  "with frozen Fermi momenta!");
1055  }
1056  log.info() << "Potentials are ON. Timestep is "
1057  << parameters_.labclock.timestep_duration();
1058  // potentials need testparticles and gaussian sigma from parameters_
1059  potentials_ = make_unique<Potentials>(config["Potentials"], parameters_);
1060  }
1061 
1116  // Create lattices
1117  if (config.has_value({"Lattice"})) {
1118  // Take lattice properties from config to assign them to all lattices
1119  const std::array<double, 3> l = config.take({"Lattice", "Sizes"});
1120  const std::array<int, 3> n = config.take({"Lattice", "Cell_Number"});
1121  const std::array<double, 3> origin = config.take({"Lattice", "Origin"});
1122  const bool periodic = config.take({"Lattice", "Periodic"});
1123 
1124  if (printout_lattice_td_) {
1125  dens_type_lattice_printout_ = output_parameters.td_dens_type;
1126  printout_tmn_ = output_parameters.td_tmn;
1127  printout_tmn_landau_ = output_parameters.td_tmn_landau;
1128  printout_v_landau_ = output_parameters.td_v_landau;
1129  }
1130  if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
1131  Tmn_ = make_unique<RectangularLattice<EnergyMomentumTensor>>(
1132  l, n, origin, periodic, LatticeUpdate::AtOutput);
1133  }
1134  /* Create baryon and isospin density lattices regardless of config
1135  if potentials are on. This is because they allow to compute
1136  potentials faster */
1137  if (potentials_) {
1138  if (potentials_->use_skyrme()) {
1139  jmu_B_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1141  UB_lat_ = make_unique<RectangularLattice<FourVector>>(
1142  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1143  FB_lat_ = make_unique<
1144  RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1145  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1146  }
1147  if (potentials_->use_symmetry()) {
1148  jmu_I3_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1150  UI3_lat_ = make_unique<RectangularLattice<FourVector>>(
1151  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1152  FI3_lat_ = make_unique<
1153  RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1154  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1155  }
1156  } else {
1157  if (dens_type_lattice_printout_ == DensityType::Baryon) {
1158  jmu_B_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1160  }
1161  if (dens_type_lattice_printout_ == DensityType::BaryonicIsospin) {
1162  jmu_I3_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1164  }
1165  }
1166  if (dens_type_lattice_printout_ != DensityType::None &&
1167  dens_type_lattice_printout_ != DensityType::BaryonicIsospin &&
1168  dens_type_lattice_printout_ != DensityType::Baryon) {
1169  jmu_custom_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1171  }
1172  } else if (printout_lattice_td_) {
1173  log.error(
1174  "If you want Thermodynamic VTK output, configure a lattice for it.");
1175  }
1176 
1177  // Store pointers to potential and lattice accessible for Action
1178  if (parameters_.potential_affect_threshold) {
1179  UB_lat_pointer = UB_lat_.get();
1180  UI3_lat_pointer = UI3_lat_.get();
1181  pot_pointer = potentials_.get();
1182  }
1183 
1184  // Create forced thermalizer
1185  if (config.has_value({"Forced_Thermalization"})) {
1186  Configuration &&th_conf = config["Forced_Thermalization"];
1187  thermalizer_ = modus_.create_grandcan_thermalizer(th_conf);
1188  }
1189 
1190  /* Take the seed setting only after the configuration was stored to a file
1191  * in smash.cc */
1192  seed_ = config.take({"General", "Randomseed"});
1193 }
1194 
1196 const std::string hline(67, '-');
1197 
1198 template <typename Modus>
1200  const auto &log = logger<LogArea::Experiment>();
1201 
1202  random::set_seed(seed_);
1203  log.info() << "random number seed: " << seed_;
1204  /* Set seed for the next event. It has to be positive, so it can be entered
1205  * in the config.
1206  *
1207  * We have to be careful about the minimal integer, whose absolute value
1208  * cannot be represented. */
1209  int64_t r = random::advance();
1210  while (r == INT64_MIN) {
1211  r = random::advance();
1212  }
1213  seed_ = std::abs(r);
1214  /* Set the random seed used in PYTHIA hadronization
1215  * to be same with the SMASH one.
1216  * In this way we ensure that the results are reproducible
1217  * for every event if one knows SMASH random seed. */
1218  if (process_string_ptr_ != NULL) {
1219  process_string_ptr_->init_pythia_hadron_rndm();
1220  }
1221 
1222  particles_.reset();
1223 
1224  // Sample particles according to the initial conditions
1225  double start_time = modus_.initial_conditions(&particles_, parameters_);
1226  /* For box modus make sure that particles are in the box. In principle, after
1227  * a correct initialization they should be, so this is just playing it safe.
1228  */
1229  modus_.impose_boundary_conditions(&particles_, outputs_);
1230  // Reset the simulation clock
1231  double timestep = delta_time_startup_;
1232 
1233  switch (time_step_mode_) {
1234  case TimeStepMode::Fixed:
1235  break;
1236  case TimeStepMode::None:
1237  timestep = end_time_ - start_time;
1238  // Take care of the box modus + timestepless propagation
1239  const double max_dt = modus_.max_timestep(max_transverse_distance_sqr_);
1240  if (max_dt > 0. && max_dt < timestep) {
1241  timestep = max_dt;
1242  }
1243  break;
1244  }
1245  Clock clock_for_this_event(start_time, timestep);
1246  parameters_.labclock = std::move(clock_for_this_event);
1247 
1248  // Reset the output clock
1249  const double dt_output = parameters_.outputclock.timestep_duration();
1250  const double zeroth_output_time =
1251  std::floor(start_time / dt_output) * dt_output;
1252  Clock output_clock(zeroth_output_time, dt_output);
1253  parameters_.outputclock = std::move(output_clock);
1254 
1255  log.debug("Lab clock: t_start = ", parameters_.labclock.current_time(),
1256  ", dt = ", parameters_.labclock.timestep_duration());
1257  log.debug("Output clock: t_start = ", parameters_.outputclock.current_time(),
1258  ", dt = ", parameters_.outputclock.timestep_duration());
1259 
1260  /* Save the initial conserved quantum numbers and total momentum in
1261  * the system for conservation checks */
1262  conserved_initial_ = QuantumNumbers(particles_);
1263  wall_actions_total_ = 0;
1264  previous_wall_actions_total_ = 0;
1265  interactions_total_ = 0;
1266  previous_interactions_total_ = 0;
1267  total_pauli_blocked_ = 0;
1268  // Print output headers
1269  log.info() << hline;
1270  log.info() << "Time [fm] Ediff [GeV] Scatt.|Decays "
1271  "Particles Timing ";
1272  log.info() << hline;
1273 }
1274 
1275 template <typename Modus>
1276 template <typename Container>
1278  Action &action, const Container &particles_before_actions) {
1279  const auto &log = logger<LogArea::Experiment>();
1280  // Make sure to skip invalid and Pauli-blocked actions.
1281  if (!action.is_valid(particles_)) {
1282  log.debug(~einhard::DRed(), "✘ ", action, " (discarded: invalid)");
1283  return false;
1284  }
1285  action.generate_final_state();
1286  log.debug("Process Type is: ", action.get_type());
1287  if (pauli_blocker_ && action.is_pauli_blocked(particles_, *pauli_blocker_)) {
1288  total_pauli_blocked_++;
1289  return false;
1290  }
1291  if (modus_.is_collider()) {
1292  /* Mark incoming nucleons as interacted - now they are permitted
1293  * to collide with nucleons from their native nucleus */
1294  for (const auto &incoming : action.incoming_particles()) {
1295  assert(incoming.id() >= 0);
1296  if (incoming.id() < modus_.total_N_number()) {
1297  nucleon_has_interacted_[incoming.id()] = true;
1298  }
1299  }
1300  }
1301  /* Make sure to pick a non-zero integer, because 0 is reserved for "no
1302  * interaction yet". */
1303  const auto id_process = static_cast<uint32_t>(interactions_total_ + 1);
1304  action.perform(&particles_, id_process);
1305  interactions_total_++;
1306  if (action.get_type() == ProcessType::Wall) {
1307  wall_actions_total_++;
1308  }
1309  // Calculate Eckart rest frame density at the interaction point
1310  double rho = 0.0;
1311  if (dens_type_ != DensityType::None) {
1312  const FourVector r_interaction = action.get_interaction_point();
1313  constexpr bool compute_grad = false;
1314  rho = std::get<0>(rho_eckart(r_interaction.threevec(),
1315  particles_before_actions, density_param_,
1316  dens_type_, compute_grad));
1317  }
1333  for (const auto &output : outputs_) {
1334  if (!output->is_dilepton_output() && !output->is_photon_output()) {
1335  output->at_interaction(action, rho);
1336  }
1337  }
1338 
1339  // At every collision photons can be produced.
1340  // Note: We rely here on the lazy evaluation of the arguments to if.
1341  // It may happen that in a wall-crossing-action sqrt_s raises an exception.
1342  // Therefore we first have to check if the incoming particles can undergo
1343  // an em-interaction.
1344  if (photons_switch_ &&
1347  action.sqrt_s(), action.incoming_particles())) {
1348  /* Time in the action constructor is relative to
1349  * current time of incoming */
1350  constexpr double action_time = 0.;
1351  ScatterActionPhoton photon_act(action.incoming_particles(), action_time,
1352  n_fractional_photons_,
1353  action.get_total_weight());
1354 
1365  photon_act.add_dummy_hadronic_process(action.get_total_weight());
1366 
1367  // Now add the actual photon reaction channel.
1368  photon_act.add_single_process();
1369 
1370  photon_act.perform_photons(outputs_);
1371  }
1372  log.debug(~einhard::Green(), "✔ ", action);
1373  return true;
1374 }
1375 
1396 std::string format_measurements(const Particles &particles,
1397  uint64_t scatterings_this_interval,
1398  const QuantumNumbers &conserved_initial,
1399  SystemTimePoint time_start, double time);
1400 
1401 template <typename Modus>
1403  Actions actions;
1404 
1405  const auto &log = logger<LogArea::Experiment>();
1406 
1407  log.info() << format_measurements(particles_, 0u, conserved_initial_,
1408  time_start_,
1409  parameters_.labclock.current_time());
1410 
1411  while (parameters_.labclock.current_time() < end_time_) {
1412  const double t = parameters_.labclock.current_time();
1413  const double dt =
1414  std::min(parameters_.labclock.timestep_duration(), end_time_ - t);
1415  log.debug("Timestepless propagation for next ", dt, " fm/c.");
1416 
1417  // Perform forced thermalization if required
1418  if (thermalizer_ &&
1419  thermalizer_->is_time_to_thermalize(parameters_.labclock)) {
1420  const bool ignore_cells_under_treshold = true;
1421  thermalizer_->update_thermalizer_lattice(particles_, density_param_,
1422  ignore_cells_under_treshold);
1423  const double current_t = parameters_.labclock.current_time();
1424  thermalizer_->thermalize(particles_, current_t,
1425  parameters_.testparticles);
1426  ThermalizationAction th_act(*thermalizer_, current_t);
1427  if (th_act.any_particles_thermalized()) {
1428  perform_action(th_act, particles_);
1429  }
1430  }
1431 
1432  /* (1.a) Create grid. */
1433  double min_cell_length = compute_min_cell_length(dt);
1434  log.debug("Creating grid with minimal cell length ", min_cell_length);
1435  const auto &grid = use_grid_
1436  ? modus_.create_grid(particles_, min_cell_length)
1437  : modus_.create_grid(particles_, min_cell_length,
1439 
1440  /* (1.b) Iterate over cells and find actions. */
1441  grid.iterate_cells(
1442  [&](const ParticleList &search_list) {
1443  for (const auto &finder : action_finders_) {
1444  actions.insert(finder->find_actions_in_cell(search_list, dt));
1445  }
1446  },
1447  [&](const ParticleList &search_list,
1448  const ParticleList &neighbors_list) {
1449  for (const auto &finder : action_finders_) {
1450  actions.insert(finder->find_actions_with_neighbors(
1451  search_list, neighbors_list, dt));
1452  }
1453  });
1454 
1455  /* \todo (optimizations) Adapt timestep size here */
1456 
1457  /* (2) Propagation from action to action until the end of timestep */
1458  run_time_evolution_timestepless(actions);
1459 
1460  /* (3) Update potentials (if computed on the lattice) and
1461  * compute new momenta according to equations of motion */
1462  if (potentials_) {
1463  update_potentials();
1464  update_momenta(&particles_, parameters_.labclock.timestep_duration(),
1465  *potentials_, FB_lat_.get(), FI3_lat_.get());
1466  }
1467 
1468  /* (4) Expand universe if non-minkowskian metric; updates
1469  * positions and momenta according to the selected expansion */
1470  if (metric_.mode_ != ExpansionMode::NoExpansion) {
1471  expand_space_time(&particles_, parameters_, metric_);
1472  }
1473 
1474  ++parameters_.labclock;
1475 
1476  /* (5) Check conservation laws.
1477  *
1478  * Check conservation of conserved quantities if potentials and string
1479  * fragmentation are off. If potentials are on then momentum is conserved
1480  * only in average. If string fragmentation is on, then energy and
1481  * momentum are only very roughly conserved in high-energy collisions. */
1482  if (!potentials_ && !parameters_.strings_switch &&
1483  metric_.mode_ == ExpansionMode::NoExpansion) {
1484  std::string err_msg = conserved_initial_.report_deviations(particles_);
1485  if (!err_msg.empty()) {
1486  log.error() << err_msg;
1487  throw std::runtime_error("Violation of conserved quantities!");
1488  }
1489  }
1490  }
1491 
1492  if (pauli_blocker_) {
1493  log.info("Interactions: Pauli-blocked/performed = ", total_pauli_blocked_,
1494  "/", interactions_total_ - wall_actions_total_);
1495  }
1496 }
1497 
1498 template <typename Modus>
1500  const double dt =
1501  propagate_straight_line(&particles_, to_time, beam_momentum_);
1502  if (dilepton_finder_ != nullptr) {
1503  for (const auto &output : outputs_) {
1504  dilepton_finder_->shine(particles_, output.get(), dt);
1505  }
1506  }
1507 }
1508 
1516 inline void check_interactions_total(uint64_t interactions_total) {
1517  constexpr uint64_t max_uint32 = std::numeric_limits<uint32_t>::max();
1518  if (interactions_total >= max_uint32) {
1519  throw std::runtime_error("Integer overflow in total interaction number!");
1520  }
1521 }
1522 
1523 template <typename Modus>
1525  const auto &log = logger<LogArea::Experiment>();
1526 
1527  const double start_time = parameters_.labclock.current_time();
1528  const double end_time = std::min(parameters_.labclock.next_time(), end_time_);
1529  double time_left = end_time - start_time;
1530  log.debug("Timestepless propagation: ", "Actions size = ", actions.size(),
1531  ", start time = ", start_time, ", end time = ", end_time);
1532 
1533  // iterate over all actions
1534  while (!actions.is_empty()) {
1535  // get next action
1536  ActionPtr act = actions.pop();
1537  if (!act->is_valid(particles_)) {
1538  log.debug(~einhard::DRed(), "✘ ", act, " (discarded: invalid)");
1539  continue;
1540  }
1541  if (act->time_of_execution() > end_time) {
1542  log.error(act, " scheduled later than end time: t_action[fm/c] = ",
1543  act->time_of_execution(), ", t_end[fm/c] = ", end_time);
1544  }
1545  log.debug(~einhard::Green(), "✔ ", act);
1546 
1547  while (next_output_time() <= act->time_of_execution()) {
1548  log.debug("Propagating until output time: ", next_output_time());
1549  propagate_and_shine(next_output_time());
1550  ++parameters_.outputclock;
1551  intermediate_output();
1552  }
1553 
1554  /* (1) Propagate to the next action. */
1555  log.debug("Propagating until next action ", act,
1556  ", action time = ", act->time_of_execution());
1557  propagate_and_shine(act->time_of_execution());
1558 
1559  /* (2) Perform action.
1560  *
1561  * Update the positions of the incoming particles, because the information
1562  * in the action object will be outdated as the particles have been
1563  * propagated since the construction of the action. */
1564  act->update_incoming(particles_);
1565 
1566  const bool performed = perform_action(*act, particles_);
1567 
1568  /* No need to update actions for outgoing particles
1569  * if the action is not performed. */
1570  if (!performed) {
1571  continue;
1572  }
1573 
1574  /* (3) Update actions for newly-produced particles. */
1575 
1576  time_left = end_time - act->time_of_execution();
1577  const ParticleList &outgoing_particles = act->outgoing_particles();
1578  for (const auto &finder : action_finders_) {
1579  // Outgoing particles can still decay, cross walls...
1580  actions.insert(
1581  finder->find_actions_in_cell(outgoing_particles, time_left));
1582  // ... and collide with other particles.
1583  actions.insert(finder->find_actions_with_surrounding_particles(
1584  outgoing_particles, particles_, time_left));
1585  }
1586 
1587  check_interactions_total(interactions_total_);
1588  }
1589 
1590  while (next_output_time() <= end_time) {
1591  log.debug("Propagating until output time: ", next_output_time());
1592  propagate_and_shine(next_output_time());
1593  ++parameters_.outputclock;
1594  // Avoid duplicating printout at event end time
1595  if (parameters_.outputclock.current_time() < end_time_) {
1596  intermediate_output();
1597  }
1598  }
1599 
1600  log.debug("Propagating to time ", end_time);
1601  propagate_and_shine(end_time);
1602 }
1603 
1604 template <typename Modus>
1606  const auto &log = logger<LogArea::Experiment>();
1607  const uint64_t wall_actions_this_interval =
1608  wall_actions_total_ - previous_wall_actions_total_;
1609  previous_wall_actions_total_ = wall_actions_total_;
1610  const uint64_t interactions_this_interval = interactions_total_ -
1611  previous_interactions_total_ -
1612  wall_actions_this_interval;
1613  previous_interactions_total_ = interactions_total_;
1614  log.info() << format_measurements(particles_, interactions_this_interval,
1615  conserved_initial_, time_start_,
1616  parameters_.outputclock.current_time());
1617  const LatticeUpdate lat_upd = LatticeUpdate::AtOutput;
1618  // save evolution data
1619  for (const auto &output : outputs_) {
1620  if (output->is_dilepton_output() || output->is_photon_output()) {
1621  continue;
1622  }
1623  output->at_intermediate_time(particles_, parameters_.outputclock,
1624  density_param_);
1625 
1626  // Thermodynamic output on the lattice versus time
1627  switch (dens_type_lattice_printout_) {
1628  case DensityType::Baryon:
1629  update_lattice(jmu_B_lat_.get(), lat_upd, DensityType::Baryon,
1630  density_param_, particles_, false);
1631  output->thermodynamics_output(ThermodynamicQuantity::EckartDensity,
1632  DensityType::Baryon, *jmu_B_lat_);
1633  break;
1635  update_lattice(jmu_I3_lat_.get(), lat_upd, DensityType::BaryonicIsospin,
1636  density_param_, particles_, false);
1637  output->thermodynamics_output(ThermodynamicQuantity::EckartDensity,
1639  *jmu_I3_lat_);
1640  break;
1641  case DensityType::None:
1642  break;
1643  default:
1644  update_lattice(jmu_custom_lat_.get(), lat_upd,
1645  dens_type_lattice_printout_, density_param_, particles_,
1646  false);
1647  output->thermodynamics_output(ThermodynamicQuantity::EckartDensity,
1648  dens_type_lattice_printout_,
1649  *jmu_custom_lat_);
1650  }
1651  if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
1652  update_lattice(Tmn_.get(), lat_upd, dens_type_lattice_printout_,
1653  density_param_, particles_);
1654  if (printout_tmn_) {
1655  output->thermodynamics_output(ThermodynamicQuantity::Tmn,
1656  dens_type_lattice_printout_, *Tmn_);
1657  }
1658  if (printout_tmn_landau_) {
1659  output->thermodynamics_output(ThermodynamicQuantity::TmnLandau,
1660  dens_type_lattice_printout_, *Tmn_);
1661  }
1662  if (printout_v_landau_) {
1663  output->thermodynamics_output(ThermodynamicQuantity::LandauVelocity,
1664  dens_type_lattice_printout_, *Tmn_);
1665  }
1666  }
1667 
1668  if (thermalizer_) {
1669  output->thermodynamics_output(*thermalizer_);
1670  }
1671  }
1672 }
1673 
1674 template <typename Modus>
1676  if (potentials_) {
1677  if (potentials_->use_skyrme() && jmu_B_lat_ != nullptr) {
1678  update_lattice(jmu_B_lat_.get(), LatticeUpdate::EveryTimestep,
1679  DensityType::Baryon, density_param_, particles_, true);
1680  const size_t UBlattice_size = UB_lat_->size();
1681  for (size_t i = 0; i < UBlattice_size; i++) {
1682  auto jB = (*jmu_B_lat_)[i];
1683  const FourVector flow_four_velocity = abs(jB.density()) > really_small
1684  ? jB.jmu_net() / jB.density()
1685  : FourVector();
1686  (*UB_lat_)[i] =
1687  flow_four_velocity * potentials_->skyrme_pot(jB.density());
1688  (*FB_lat_)[i] = potentials_->skyrme_force(jB.density(), jB.grad_rho(),
1689  jB.dj_dt(), jB.rot_j());
1690  }
1691  }
1692  if (potentials_->use_symmetry() && jmu_I3_lat_ != nullptr) {
1693  update_lattice(jmu_I3_lat_.get(), LatticeUpdate::EveryTimestep,
1694  DensityType::BaryonicIsospin, density_param_, particles_,
1695  true);
1696  const size_t UI3lattice_size = UI3_lat_->size();
1697  for (size_t i = 0; i < UI3lattice_size; i++) {
1698  auto jI3 = (*jmu_I3_lat_)[i];
1699  const FourVector flow_four_velocity =
1700  abs(jI3.density()) > really_small ? jI3.jmu_net() / jI3.density()
1701  : FourVector();
1702  (*UI3_lat_)[i] =
1703  flow_four_velocity * potentials_->symmetry_pot(jI3.density());
1704  (*FI3_lat_)[i] = potentials_->symmetry_force(jI3.grad_rho(),
1705  jI3.dj_dt(), jI3.rot_j());
1706  }
1707  }
1708  }
1709 }
1710 
1711 template <typename Modus>
1713  /* At end of time evolution: Force all resonances to decay. In order to handle
1714  * decay chains, we need to loop until no further actions occur. */
1715  uint64_t interactions_old;
1716  const auto particles_before_actions = particles_.copy_to_vector();
1717  do {
1718  Actions actions;
1719 
1720  interactions_old = interactions_total_;
1721 
1722  // Dileptons: shining of remaining resonances
1723  if (dilepton_finder_ != nullptr) {
1724  for (const auto &output : outputs_) {
1725  dilepton_finder_->shine_final(particles_, output.get(), true);
1726  }
1727  }
1728  // Find actions.
1729  for (const auto &finder : action_finders_) {
1730  actions.insert(finder->find_final_actions(particles_));
1731  }
1732  // Perform actions.
1733  while (!actions.is_empty()) {
1734  perform_action(*actions.pop(), particles_before_actions);
1735  }
1736  // loop until no more decays occur
1737  } while (interactions_total_ > interactions_old);
1738 
1739  // Dileptons: shining of stable particles at the end
1740  if (dilepton_finder_ != nullptr) {
1741  for (const auto &output : outputs_) {
1742  dilepton_finder_->shine_final(particles_, output.get(), false);
1743  }
1744  }
1745 }
1746 
1747 template <typename Modus>
1748 void Experiment<Modus>::final_output(const int evt_num) {
1749  const auto &log = logger<LogArea::Experiment>();
1750  /* make sure the experiment actually ran (note: we should compare this
1751  * to the start time, but we don't know that. Therefore, we check that
1752  * the time is positive, which should heuristically be the same). */
1753  if (likely(parameters_.labclock > 0)) {
1754  const uint64_t wall_actions_this_interval =
1755  wall_actions_total_ - previous_wall_actions_total_;
1756  const uint64_t interactions_this_interval = interactions_total_ -
1757  previous_interactions_total_ -
1758  wall_actions_this_interval;
1759  log.info() << format_measurements(particles_, interactions_this_interval,
1760  conserved_initial_, time_start_,
1761  parameters_.outputclock.current_time());
1762  log.info() << hline;
1763  log.info() << "Time real: " << SystemClock::now() - time_start_;
1764  log.info() << "Final interaction number: "
1765  << interactions_total_ - wall_actions_total_;
1766  // Check if there are unformed particles
1767  int unformed_particles_count = 0;
1768  for (const auto &particle : particles_) {
1769  if (particle.formation_time() > end_time_) {
1770  unformed_particles_count++;
1771  }
1772  }
1773  if (unformed_particles_count > 0) {
1774  log.warn("End time might be too small. ", unformed_particles_count,
1775  " unformed particles were found at the end of the evolution.");
1776  }
1777  }
1778 
1779  for (const auto &output : outputs_) {
1780  output->at_eventend(particles_, evt_num, modus_.impact_parameter());
1781  }
1782 }
1783 
1784 template <typename Modus>
1786  const auto &mainlog = logger<LogArea::Main>();
1787  for (int j = 0; j < nevents_; j++) {
1788  mainlog.info() << "Event " << j;
1789 
1790  // Sample initial particles, start clock, some printout and book-keeping
1791  initialize_new_event();
1792  /* In the ColliderModus, if the first collisions within the same nucleus are
1793  * forbidden, 'nucleon_has_interacted_', which records whether a nucleon has
1794  * collided with another nucleon, is initialized equal to false. If allowed,
1795  * 'nucleon_has_interacted' is initialized equal to true, which means these
1796  * incoming particles have experienced some fake scatterings, they can
1797  * therefore collide with each other later on since these collisions are not
1798  * "first" to them. */
1799  if (modus_.is_collider()) {
1800  if (!modus_.cll_in_nucleus()) {
1801  nucleon_has_interacted_.assign(modus_.total_N_number(), false);
1802  } else {
1803  nucleon_has_interacted_.assign(modus_.total_N_number(), true);
1804  }
1805  }
1806  /* In the ColliderModus, if Fermi motion is frozen, assign the beam momenta
1807  * to the nucleons in both the projectile and the target. */
1808  if (modus_.is_collider() && modus_.fermi_motion() == FermiMotion::Frozen) {
1809  for (int i = 0; i < modus_.total_N_number(); i++) {
1810  const auto mass_beam = particles_.copy_to_vector()[i].effective_mass();
1811  const auto v_beam = i < modus_.proj_N_number()
1812  ? modus_.velocity_projectile()
1813  : modus_.velocity_target();
1814  const auto gamma = 1.0 / std::sqrt(1.0 - v_beam * v_beam);
1815  beam_momentum_.emplace_back(FourVector(gamma * mass_beam, 0.0, 0.0,
1816  gamma * v_beam * mass_beam));
1817  }
1818  }
1819 
1820  // Output at event start
1821  for (const auto &output : outputs_) {
1822  output->at_eventstart(particles_, j);
1823  }
1824 
1825  run_time_evolution();
1826 
1827  if (force_decays_) {
1828  do_final_decays();
1829  }
1830 
1831  // Output at event end
1832  final_output(j);
1833  }
1834 }
1835 
1836 } // namespace smash
1837 
1838 #endif // SRC_INCLUDE_EXPERIMENT_H_
FormattingHelper< T > format(const T &value, const char *unit, int width=-1, int precision=-1)
Acts as a stream modifier for std::ostream to output an object with an optional suffix string and wit...
Definition: logging.h:310
The main class, where the simulation of an experiment is executed.
Definition: experiment.h:133
Experiment(Configuration config, const bf::path &output_path)
Create a new Experiment.
A class to pre-calculate and store parameters relevant for density calculation.
Definition: density.h:103
OutputPtr photon_output_
The Photon output.
Definition: experiment.h:338
Potentials * pot_pointer
Pointer to a Potential class.
FermiMotion
Option to use Fermi Motion.
void check_interactions_total(uint64_t interactions_total)
Make sure interactions_total can be represented as a 32-bit integer.
Definition: experiment.h:1516
virtual void run()=0
Runs the experiment.
static std::unique_ptr< ExperimentBase > create(Configuration config, const bf::path &output_path)
Factory method that creates and initializes a new Experiment<Modus>.
virtual void generate_final_state()=0
Generate the final state for this action.
int64_t seed_
random seed for the next event.
Definition: experiment.h:524
std::unique_ptr< RectangularLattice< EnergyMomentumTensor > > Tmn_
Lattices of energy-momentum tensors for printout.
Definition: experiment.h:405
double next_output_time() const
Shortcut for next output time.
Definition: experiment.h:293
FourVector get_interaction_point() const
Get the interaction point.
Definition: action.cc:68
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:34
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:43
void run_time_evolution()
Runs the time evolution of an event with fixed-sized time steps or without timesteps, from action to actions.
Definition: experiment.h:1402
The Actions class abstracts the storage and manipulation of actions.
Definition: actions.h:29
std::unique_ptr< DensityLattice > jmu_custom_lat_
Custom density on the lattices.
Definition: experiment.h:379
String excitation processes used in SMASH.
Definition: processstring.h:46
std::unique_ptr< RectangularLattice< std::pair< ThreeVector, ThreeVector > > > FB_lat_
Lattices for the electric and magnetic components of the Skyrme force.
Definition: experiment.h:398
uint64_t total_pauli_blocked_
Total number of Pauli-blockings for current timestep.
Definition: experiment.h:521
RectangularLattice< FourVector > * UI3_lat_pointer
Pointer to the symmmetry potential on the lattice.
void final_output(const int evt_num)
Output at the end of an event.
Definition: experiment.h:1748
#define likely(x)
Tell the branch predictor that this expression is likely true.
Definition: macros.h:14
std::unique_ptr< RectangularLattice< FourVector > > UB_lat_
Lattices for Skyrme potentials (evaluated in the local rest frame) times the baryon flow 4-velocity...
Definition: experiment.h:388
void update_momenta(Particles *particles, double dt, const Potentials &pot, RectangularLattice< std::pair< ThreeVector, ThreeVector >> *FB_lat, RectangularLattice< std::pair< ThreeVector, ThreeVector >> *FI3_lat)
Updates the momenta of all particles at the current time step according to the equations of motion: ...
Definition: propagation.cc:111
void insert(ActionList &&new_acts)
Insert a list of actions into this object.
Definition: actions.h:76
std::unique_ptr< DecayActionsFinderDilepton > dilepton_finder_
The Dilepton Action Finder.
Definition: experiment.h:358
void update_lattice(RectangularLattice< T > *lat, const LatticeUpdate update, const DensityType dens_type, const DensityParameters &par, const Particles &particles, const bool compute_gradient=false)
Updates the contents on the lattice.
Definition: density.h:386
std::tuple< double, ThreeVector, ThreeVector, ThreeVector > rho_eckart(const ThreeVector &r, const ParticleList &plist, const DensityParameters &par, DensityType dens_type, bool compute_gradient)
Calculates Eckart rest frame density and optionally the gradient of the density in an arbitary frame...
Definition: density.cc:133
STL namespace.
bool is_valid(const Particles &particles) const
Check whether the action still applies.
Definition: action.cc:29
const TimeStepMode time_step_mode_
This indicates whether to use time steps.
Definition: experiment.h:473
constexpr double fm2_mb
mb <-> fm^2 conversion factor.
Definition: constants.h:28
void set_seed(T &&seed)
Sets the seed of the random number engine.
Definition: random.h:68
LatticeUpdate
Enumerator option for lattice updates.
Definition: lattice.h:35
uint64_t wall_actions_total_
Total number of wall-crossings for current timestep.
Definition: experiment.h:509
double compute_min_cell_length(double dt) const
Calculate the minimal size for the grid cells such that the ScatterActionsFinder will find all collis...
Definition: experiment.h:288
Interface to the SMASH configuration files.
void do_final_decays()
Performs the final decays of an event.
Definition: experiment.h:1712
constexpr double maximum_cross_section
The maximal cross section (in mb) for which it is guaranteed that all collisions with this cross sect...
Definition: constants.h:108
Non-template interface to Experiment<Modus>.
Definition: experiment.h:82
ExperimentParameters create_experiment_parameters(Configuration config)
Gathers all general Experiment parameters.
Definition: experiment.cc:269
std::unique_ptr< GrandCanThermalizer > thermalizer_
Instance of class used for forced thermalization.
Definition: experiment.h:420
const bool force_decays_
This indicates whether we force all resonances to decay in the last timestep.
Definition: experiment.h:458
StringProcess * process_string_ptr_
Pointer to the string process class object, which is used to set the random seed for PYTHIA objects i...
Definition: experiment.h:426
int n_fractional_photons_
Number of fractional photons produced per single reaction.
Definition: experiment.h:364
QuantumNumbers conserved_initial_
The conserved quantities of the system.
Definition: experiment.h:485
void propagate_and_shine(double to_time)
Propagate all particles until time to_time without any interactions and shine dileptons.
Definition: experiment.h:1499
ThermalizationAction implements forced thermalization as an Action class.
ExperimentParameters parameters_
Struct of several member variables.
Definition: experiment.h:302
void update_potentials()
Recompute potentials on lattices if necessary.
Definition: experiment.h:1675
const bool use_grid_
This indicates whether to use the grid.
Definition: experiment.h:461
bool printout_tmn_landau_
Whether to print the energy-momentum tensor in Landau frame.
Definition: experiment.h:411
Particles particles_
Complete particle list.
Definition: experiment.h:314
const std::string hline(67, '-')
String representing a horizontal line.
static bool is_kinematically_possible(const double s_sqrt, const ParticleList &in)
Check if CM-energy is sufficient to produce hadron in final state.
bool printout_lattice_td_
Whether to print the thermodynamics quantities evaluated on the lattices.
Definition: experiment.h:417
RectangularLattice< FourVector > * UB_lat_pointer
Pointer to the skyrme potential on the lattice.
std::unique_ptr< DensityLattice > jmu_I3_lat_
Isospin projection density on the lattices.
Definition: experiment.h:370
DensityType dens_type_
Type of density to be written to collision headers.
Definition: experiment.h:491
bool perform_action(Action &action, const Container &particles_before_actions)
Perform the given action.
void initialize_new_event()
This is called in the beginning of each event.
Definition: experiment.h:1199
OutputPtr dilepton_output_
The Dilepton output.
Definition: experiment.h:335
Collection of useful type aliases to measure and output the (real) runtime.
std::unique_ptr< OutputInterface > create_oscar_output(const std::string &format, const std::string &content, const bf::path &path, const OutputParameters &out_par)
Definition: oscaroutput.cc:732
const double end_time_
simulation time at which the evolution is stopped.
Definition: experiment.h:445
std::unique_ptr< RectangularLattice< FourVector > > UI3_lat_
Lattices for symmetry potentials (evaluated in the local rest frame) times the isospin flow 4-velocit...
Definition: experiment.h:394
uint64_t previous_wall_actions_total_
Total number of wall-crossings for previous timestep.
Definition: experiment.h:515
double max_transverse_distance_sqr_
Maximal distance at which particles can interact, squared.
Definition: experiment.h:476
std::vector< bool > nucleon_has_interacted_
nucleon_has_interacted_ labels whether the particles in the nuclei have experienced any collisions or...
Definition: experiment.h:345
uint64_t interactions_total_
Total number of interactions for current timestep.
Definition: experiment.h:497
TimeStepMode
The time step mode.
std::unique_ptr< RectangularLattice< std::pair< ThreeVector, ThreeVector > > > FI3_lat_
Lattices for the electric and magnetic component of the symmetry force.
Definition: experiment.h:402
Engine::result_type advance()
Advance the engine&#39;s state and return the generated value.
Definition: random.h:75
std::string format_measurements(const Particles &particles, uint64_t scatterings_this_interval, const QuantumNumbers &conserved_initial, SystemTimePoint time_start, double time)
Generate the tabulated string which will be printed to the screen when SMASH is running.
Definition: experiment.cc:318
#define source_location
Hackery that is required to output the location in the source code where the log statement occurs...
Definition: logging.h:246
const ExpansionProperties metric_
This struct contains information on the metric to be used.
Definition: experiment.h:464
Exception class that is thrown if an invalid modus is requested from the Experiment factory...
Definition: experiment.h:127
SystemTimePoint time_start_
system starting time of the simulation
Definition: experiment.h:488
virtual ~ExperimentBase()=default
The virtual destructor avoids undefined behavior when destroying derived objects. ...
const ParticleList & incoming_particles() const
Get the list of particles that go into the action.
Definition: action.cc:58
const double delta_time_startup_
The clock&#39;s timestep size at start up.
Definition: experiment.h:452
Clock outputclock
Output clock to keep track of the next output time.
A container for storing conserved values.
void run() override
Runs the experiment.
Definition: experiment.h:1785
uint64_t previous_interactions_total_
Total number of interactions for previous timestep.
Definition: experiment.h:503
Don&#39;t use fermi motion.
ActionPtr pop()
Return the first action in the list and removes it from the list.
Definition: actions.h:59
box wall crossing
Helper structure for Experiment to hold output options and parameters.
void run_time_evolution_timestepless(Actions &actions)
Performs all the propagations and actions during a certain time interval neglecting the influence of ...
Definition: experiment.h:1524
static double formation_power_
Power with which the cross section scaling factor grows in time.
Definition: particledata.h:365
const bool dileptons_switch_
This indicates whether dileptons are switched on.
Definition: experiment.h:467
virtual ProcessType get_type() const
Get the process type.
Definition: action.h:130
std::unique_ptr< ActionFinderInterface > photon_finder_
The (Scatter) Actions Finder for Direct Photons.
Definition: experiment.h:361
std::unique_ptr< Potentials > potentials_
An instance of potentials class, that stores parameters of potentials, calculates them and their grad...
Definition: experiment.h:320
bool any_particles_thermalized() const
This method checks, if there are particles in the region to be thermalized.
Clock tracks the time in the simulation.
Definition: clock.h:75
Action is the base class for a generic process that takes a number of incoming particles and transfor...
Definition: action.h:34
virtual double get_total_weight() const =0
Return the total weight value, which is mainly used for the weight output entry.
const bool photons_switch_
This indicates whether photons are switched on.
Definition: experiment.h:470
std::ostream & operator<<(std::ostream &out, const Experiment< Modus > &e)
Creates a verbose textual description of the setup of the Experiment.
Definition: experiment.h:536
std::unique_ptr< T > make_unique(Args &&... args)
Definition for make_unique Is in C++14&#39;s standard library; necessary for older compilers.
Definition: cxx14compat.h:25
Use fermi motion without potentials.
void intermediate_output()
Intermediate output during an event.
Definition: experiment.h:1605
Use fixed time step.
std::chrono::time_point< std::chrono::system_clock > SystemTimePoint
Type (alias) that is used to store the current time.
Definition: chrono.h:22
OutputsList outputs_
A list of output formaters.
Definition: experiment.h:332
bool is_empty() const
Definition: actions.h:52
Modus modus_
Instance of the Modus template parameter.
Definition: experiment.h:311
void create_output(const std::string &format, const std::string &content, const bf::path &output_path, const OutputParameters &par)
Create a list of output files.
Definition: experiment.h:543
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:86
Particles * particles()
Provides external access to SMASH particles.
Definition: experiment.h:218
std::vector< std::unique_ptr< ActionFinderInterface > > action_finders_
The Action finder objects.
Definition: experiment.h:355
bool printout_v_landau_
Whether to print the 4-velocity in Landau fram.
Definition: experiment.h:414
DensityParameters density_param_
Structure to precalculate and hold parameters for density computations.
Definition: experiment.h:305
double next_time() const
Definition: clock.h:120
A stream modifier that allows to colorize the log output.
Definition: einhard.hpp:142
Modus * modus()
Provides external access to SMASH calculation modus.
Definition: experiment.h:224
The Particles class abstracts the storage and manipulation of particles.
Definition: particles.h:33
DensityType dens_type_lattice_printout_
Type of density for lattice printout.
Definition: experiment.h:382
constexpr int n
Neutron.
DensityType
Allows to choose which kind of density to calculate.
Definition: density.h:34
const int nevents_
Number of events.
Definition: experiment.h:442
bool is_pauli_blocked(const Particles &particles, const PauliBlocker &p_bl) const
Check if the action is Pauli-blocked.
Definition: action.cc:35
static bool is_photon_reaction(const ParticleList &in)
Check if particles can undergo an implemented photon process.
Make cells as large as possible.
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:32
std::unique_ptr< PauliBlocker > pauli_blocker_
An instance of PauliBlocker class that stores parameters needed for Pauli blocking calculations and c...
Definition: experiment.h:326
ActionList::size_type size() const
Definition: actions.h:95
Struct containing the type of the metric and the expansion parameter of the metric.
Definition: propagation.h:25
std::unique_ptr< DensityLattice > jmu_B_lat_
Baryon density on the lattices.
Definition: experiment.h:367
Helper structure for Experiment.
bool printout_tmn_
Whether to print the energy-momentum tensor.
Definition: experiment.h:408
std::vector< FourVector > beam_momentum_
The initial nucleons in the ColliderModus propagate with beam_momentum_, if Fermi motion is frozen...
Definition: experiment.h:352
Definition: action.h:24
virtual void perform(Particles *particles, uint32_t id_process)
Actually perform the action, e.g.
Definition: action.cc:94
double sqrt_s() const
Determine the total energy in the center-of-mass frame [GeV].
Definition: action.h:265