Version: SMASH-1.6
experiment.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2019
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 
218  Particles *particles() { return &particles_; }
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 
272  void run_time_evolution_timestepless(Actions &actions);
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 {
294  return parameters_.outputclock.next_time();
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 
364  int n_fractional_photons_ = 100;
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 
382  DensityType dens_type_lattice_printout_ = DensityType::None;
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 
491  DensityType dens_type_ = DensityType::None;
492 
497  uint64_t interactions_total_ = 0;
498 
503  uint64_t previous_interactions_total_ = 0;
504 
509  uint64_t wall_actions_total_ = 0;
510 
515  uint64_t previous_wall_actions_total_ = 0;
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  }
765  ParticleData::formation_power_ =
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"];
1024  dens_type_ = config.take({"Output", "Density_Type"}, DensityType::None);
1025  log.debug() << "Density type printed to headers: " << dens_type_;
1026 
1027  const OutputParameters output_parameters(std::move(output_conf));
1028 
1029  std::vector<std::string> output_contents = output_conf.list_upmost_nodes();
1030  for (const auto &content : output_contents) {
1031  auto this_output_conf = output_conf[content.c_str()];
1032  std::vector<std::string> formats = this_output_conf.take({"Format"});
1033  for (const auto &format : formats) {
1034  create_output(format, content, output_path, output_parameters);
1035  }
1036  }
1037 
1038  /* We can take away the Fermi motion flag, because the collider modus is
1039  * already initialized. We only need it when potentials are enabled, but we
1040  * always have to take it, otherwise SMASH will complain about unused
1041  * options. We have to provide a default value for modi other than Collider.
1042  */
1043  const FermiMotion motion =
1044  config.take({"Modi", "Collider", "Fermi_Motion"}, FermiMotion::Off);
1045  if (config.has_value({"Potentials"})) {
1046  if (time_step_mode_ == TimeStepMode::None) {
1047  log.error() << "Potentials only work with time steps!";
1048  throw std::invalid_argument("Can't use potentials without time steps!");
1049  }
1050  if (motion == FermiMotion::Frozen) {
1051  log.error() << "Potentials don't work with frozen Fermi momenta! "
1052  "Use normal Fermi motion instead.";
1053  throw std::invalid_argument(
1054  "Can't use potentials "
1055  "with frozen Fermi momenta!");
1056  }
1057  log.info() << "Potentials are ON. Timestep is "
1058  << parameters_.labclock.timestep_duration();
1059  // potentials need testparticles and gaussian sigma from parameters_
1060  potentials_ = make_unique<Potentials>(config["Potentials"], parameters_);
1061  }
1062 
1117  // Create lattices
1118  if (config.has_value({"Lattice"})) {
1119  // Take lattice properties from config to assign them to all lattices
1120  const std::array<double, 3> l = config.take({"Lattice", "Sizes"});
1121  const std::array<int, 3> n = config.take({"Lattice", "Cell_Number"});
1122  const std::array<double, 3> origin = config.take({"Lattice", "Origin"});
1123  const bool periodic = config.take({"Lattice", "Periodic"});
1124 
1125  if (printout_lattice_td_) {
1126  dens_type_lattice_printout_ = output_parameters.td_dens_type;
1127  printout_tmn_ = output_parameters.td_tmn;
1128  printout_tmn_landau_ = output_parameters.td_tmn_landau;
1129  printout_v_landau_ = output_parameters.td_v_landau;
1130  }
1131  if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
1132  Tmn_ = make_unique<RectangularLattice<EnergyMomentumTensor>>(
1133  l, n, origin, periodic, LatticeUpdate::AtOutput);
1134  }
1135  /* Create baryon and isospin density lattices regardless of config
1136  if potentials are on. This is because they allow to compute
1137  potentials faster */
1138  if (potentials_) {
1139  if (potentials_->use_skyrme()) {
1140  jmu_B_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1141  LatticeUpdate::EveryTimestep);
1142  UB_lat_ = make_unique<RectangularLattice<FourVector>>(
1143  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1144  FB_lat_ = make_unique<
1146  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1147  }
1148  if (potentials_->use_symmetry()) {
1149  jmu_I3_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1150  LatticeUpdate::EveryTimestep);
1151  UI3_lat_ = make_unique<RectangularLattice<FourVector>>(
1152  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1153  FI3_lat_ = make_unique<
1155  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1156  }
1157  } else {
1158  if (dens_type_lattice_printout_ == DensityType::Baryon) {
1159  jmu_B_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1160  LatticeUpdate::AtOutput);
1161  }
1162  if (dens_type_lattice_printout_ == DensityType::BaryonicIsospin) {
1163  jmu_I3_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1164  LatticeUpdate::AtOutput);
1165  }
1166  }
1167  if (dens_type_lattice_printout_ != DensityType::None &&
1168  dens_type_lattice_printout_ != DensityType::BaryonicIsospin &&
1169  dens_type_lattice_printout_ != DensityType::Baryon) {
1170  jmu_custom_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1171  LatticeUpdate::AtOutput);
1172  }
1173  } else if (printout_lattice_td_) {
1174  log.error(
1175  "If you want Thermodynamic VTK output, configure a lattice for it.");
1176  }
1177 
1178  // Store pointers to potential and lattice accessible for Action
1179  if (parameters_.potential_affect_threshold) {
1180  UB_lat_pointer = UB_lat_.get();
1181  UI3_lat_pointer = UI3_lat_.get();
1182  pot_pointer = potentials_.get();
1183  }
1184 
1185  // Create forced thermalizer
1186  if (config.has_value({"Forced_Thermalization"})) {
1187  Configuration &&th_conf = config["Forced_Thermalization"];
1188  thermalizer_ = modus_.create_grandcan_thermalizer(th_conf);
1189  }
1190 
1191  /* Take the seed setting only after the configuration was stored to a file
1192  * in smash.cc */
1193  seed_ = config.take({"General", "Randomseed"});
1194 }
1195 
1197 const std::string hline(67, '-');
1198 
1199 template <typename Modus>
1201  const auto &log = logger<LogArea::Experiment>();
1202 
1203  random::set_seed(seed_);
1204  log.info() << "random number seed: " << seed_;
1205  /* Set seed for the next event. It has to be positive, so it can be entered
1206  * in the config.
1207  *
1208  * We have to be careful about the minimal integer, whose absolute value
1209  * cannot be represented. */
1210  int64_t r = random::advance();
1211  while (r == INT64_MIN) {
1212  r = random::advance();
1213  }
1214  seed_ = std::abs(r);
1215  /* Set the random seed used in PYTHIA hadronization
1216  * to be same with the SMASH one.
1217  * In this way we ensure that the results are reproducible
1218  * for every event if one knows SMASH random seed. */
1219  if (process_string_ptr_ != NULL) {
1220  process_string_ptr_->init_pythia_hadron_rndm();
1221  }
1222 
1223  particles_.reset();
1224 
1225  // Sample particles according to the initial conditions
1226  double start_time = modus_.initial_conditions(&particles_, parameters_);
1227  /* For box modus make sure that particles are in the box. In principle, after
1228  * a correct initialization they should be, so this is just playing it safe.
1229  */
1230  modus_.impose_boundary_conditions(&particles_, outputs_);
1231  // Reset the simulation clock
1232  double timestep = delta_time_startup_;
1233 
1234  switch (time_step_mode_) {
1235  case TimeStepMode::Fixed:
1236  break;
1237  case TimeStepMode::None:
1238  timestep = end_time_ - start_time;
1239  // Take care of the box modus + timestepless propagation
1240  const double max_dt = modus_.max_timestep(max_transverse_distance_sqr_);
1241  if (max_dt > 0. && max_dt < timestep) {
1242  timestep = max_dt;
1243  }
1244  break;
1245  }
1246  Clock clock_for_this_event(start_time, timestep);
1247  parameters_.labclock = std::move(clock_for_this_event);
1248 
1249  // Reset the output clock
1250  const double dt_output = parameters_.outputclock.timestep_duration();
1251  const double zeroth_output_time =
1252  std::floor(start_time / dt_output) * dt_output;
1253  Clock output_clock(zeroth_output_time, dt_output);
1254  parameters_.outputclock = std::move(output_clock);
1255 
1256  log.debug("Lab clock: t_start = ", parameters_.labclock.current_time(),
1257  ", dt = ", parameters_.labclock.timestep_duration());
1258  log.debug("Output clock: t_start = ", parameters_.outputclock.current_time(),
1259  ", dt = ", parameters_.outputclock.timestep_duration());
1260 
1261  /* Save the initial conserved quantum numbers and total momentum in
1262  * the system for conservation checks */
1263  conserved_initial_ = QuantumNumbers(particles_);
1264  wall_actions_total_ = 0;
1265  previous_wall_actions_total_ = 0;
1266  interactions_total_ = 0;
1267  previous_interactions_total_ = 0;
1268  total_pauli_blocked_ = 0;
1269  // Print output headers
1270  log.info() << hline;
1271  log.info() << "Time [fm] Ediff [GeV] Scatt.|Decays "
1272  "Particles Timing";
1273  log.info() << hline;
1274 }
1275 
1276 template <typename Modus>
1277 template <typename Container>
1279  Action &action, const Container &particles_before_actions) {
1280  const auto &log = logger<LogArea::Experiment>();
1281  // Make sure to skip invalid and Pauli-blocked actions.
1282  if (!action.is_valid(particles_)) {
1283  log.debug(~einhard::DRed(), "✘ ", action, " (discarded: invalid)");
1284  return false;
1285  }
1286  action.generate_final_state();
1287  log.debug("Process Type is: ", action.get_type());
1288  if (pauli_blocker_ && action.is_pauli_blocked(particles_, *pauli_blocker_)) {
1289  total_pauli_blocked_++;
1290  return false;
1291  }
1292  if (modus_.is_collider()) {
1293  /* Mark incoming nucleons as interacted - now they are permitted
1294  * to collide with nucleons from their native nucleus */
1295  for (const auto &incoming : action.incoming_particles()) {
1296  assert(incoming.id() >= 0);
1297  if (incoming.id() < modus_.total_N_number()) {
1298  nucleon_has_interacted_[incoming.id()] = true;
1299  }
1300  }
1301  }
1302  /* Make sure to pick a non-zero integer, because 0 is reserved for "no
1303  * interaction yet". */
1304  const auto id_process = static_cast<uint32_t>(interactions_total_ + 1);
1305  action.perform(&particles_, id_process);
1306  interactions_total_++;
1307  if (action.get_type() == ProcessType::Wall) {
1308  wall_actions_total_++;
1309  }
1310  // Calculate Eckart rest frame density at the interaction point
1311  double rho = 0.0;
1312  if (dens_type_ != DensityType::None) {
1313  const FourVector r_interaction = action.get_interaction_point();
1314  constexpr bool compute_grad = false;
1315  const bool smearing = true;
1316  rho = std::get<0>(current_eckart(r_interaction.threevec(),
1317  particles_before_actions, density_param_,
1318  dens_type_, compute_grad, smearing));
1319  }
1335  for (const auto &output : outputs_) {
1336  if (!output->is_dilepton_output() && !output->is_photon_output()) {
1337  output->at_interaction(action, rho);
1338  }
1339  }
1340 
1341  // At every collision photons can be produced.
1342  // Note: We rely here on the lazy evaluation of the arguments to if.
1343  // It may happen that in a wall-crossing-action sqrt_s raises an exception.
1344  // Therefore we first have to check if the incoming particles can undergo
1345  // an em-interaction.
1346  if (photons_switch_ &&
1347  ScatterActionPhoton::is_photon_reaction(action.incoming_particles()) &&
1348  ScatterActionPhoton::is_kinematically_possible(
1349  action.sqrt_s(), action.incoming_particles())) {
1350  /* Time in the action constructor is relative to
1351  * current time of incoming */
1352  constexpr double action_time = 0.;
1353  ScatterActionPhoton photon_act(action.incoming_particles(), action_time,
1354  n_fractional_photons_,
1355  action.get_total_weight());
1356 
1367  photon_act.add_dummy_hadronic_process(action.get_total_weight());
1368 
1369  // Now add the actual photon reaction channel.
1370  photon_act.add_single_process();
1371 
1372  photon_act.perform_photons(outputs_);
1373  }
1374  log.debug(~einhard::Green(), "✔ ", action);
1375  return true;
1376 }
1377 
1398 std::string format_measurements(const Particles &particles,
1399  uint64_t scatterings_this_interval,
1400  const QuantumNumbers &conserved_initial,
1401  SystemTimePoint time_start, double time);
1402 
1403 template <typename Modus>
1405  Actions actions;
1406 
1407  const auto &log = logger<LogArea::Experiment>();
1408 
1409  log.info() << format_measurements(particles_, 0u, conserved_initial_,
1410  time_start_,
1411  parameters_.labclock.current_time());
1412 
1413  while (parameters_.labclock.current_time() < end_time_) {
1414  const double t = parameters_.labclock.current_time();
1415  const double dt =
1416  std::min(parameters_.labclock.timestep_duration(), end_time_ - t);
1417  log.debug("Timestepless propagation for next ", dt, " fm/c.");
1418 
1419  // Perform forced thermalization if required
1420  if (thermalizer_ &&
1421  thermalizer_->is_time_to_thermalize(parameters_.labclock)) {
1422  const bool ignore_cells_under_treshold = true;
1423  thermalizer_->update_thermalizer_lattice(particles_, density_param_,
1424  ignore_cells_under_treshold);
1425  const double current_t = parameters_.labclock.current_time();
1426  thermalizer_->thermalize(particles_, current_t,
1427  parameters_.testparticles);
1428  ThermalizationAction th_act(*thermalizer_, current_t);
1429  if (th_act.any_particles_thermalized()) {
1430  perform_action(th_act, particles_);
1431  }
1432  }
1433 
1434  /* (1.a) Create grid. */
1435  double min_cell_length = compute_min_cell_length(dt);
1436  log.debug("Creating grid with minimal cell length ", min_cell_length);
1437  const auto &grid = use_grid_
1438  ? modus_.create_grid(particles_, min_cell_length, dt)
1439  : modus_.create_grid(particles_, min_cell_length, dt,
1440  CellSizeStrategy::Largest);
1441 
1442  /* (1.b) Iterate over cells and find actions. */
1443  grid.iterate_cells(
1444  [&](const ParticleList &search_list) {
1445  for (const auto &finder : action_finders_) {
1446  actions.insert(finder->find_actions_in_cell(search_list, dt));
1447  }
1448  },
1449  [&](const ParticleList &search_list,
1450  const ParticleList &neighbors_list) {
1451  for (const auto &finder : action_finders_) {
1452  actions.insert(finder->find_actions_with_neighbors(
1453  search_list, neighbors_list, dt));
1454  }
1455  });
1456 
1457  /* \todo (optimizations) Adapt timestep size here */
1458 
1459  /* (2) Propagation from action to action until the end of timestep */
1460  run_time_evolution_timestepless(actions);
1461 
1462  /* (3) Update potentials (if computed on the lattice) and
1463  * compute new momenta according to equations of motion */
1464  if (potentials_) {
1465  update_potentials();
1466  update_momenta(&particles_, parameters_.labclock.timestep_duration(),
1467  *potentials_, FB_lat_.get(), FI3_lat_.get());
1468  }
1469 
1470  /* (4) Expand universe if non-minkowskian metric; updates
1471  * positions and momenta according to the selected expansion */
1472  if (metric_.mode_ != ExpansionMode::NoExpansion) {
1473  expand_space_time(&particles_, parameters_, metric_);
1474  }
1475 
1476  ++parameters_.labclock;
1477 
1478  /* (5) Check conservation laws.
1479  *
1480  * Check conservation of conserved quantities if potentials and string
1481  * fragmentation are off. If potentials are on then momentum is conserved
1482  * only in average. If string fragmentation is on, then energy and
1483  * momentum are only very roughly conserved in high-energy collisions. */
1484  if (!potentials_ && !parameters_.strings_switch &&
1485  metric_.mode_ == ExpansionMode::NoExpansion) {
1486  std::string err_msg = conserved_initial_.report_deviations(particles_);
1487  if (!err_msg.empty()) {
1488  log.error() << err_msg;
1489  throw std::runtime_error("Violation of conserved quantities!");
1490  }
1491  }
1492  }
1493 
1494  if (pauli_blocker_) {
1495  log.info("Interactions: Pauli-blocked/performed = ", total_pauli_blocked_,
1496  "/", interactions_total_ - wall_actions_total_);
1497  }
1498 }
1499 
1500 template <typename Modus>
1502  const double dt =
1503  propagate_straight_line(&particles_, to_time, beam_momentum_);
1504  if (dilepton_finder_ != nullptr) {
1505  for (const auto &output : outputs_) {
1506  dilepton_finder_->shine(particles_, output.get(), dt);
1507  }
1508  }
1509 }
1510 
1518 inline void check_interactions_total(uint64_t interactions_total) {
1519  constexpr uint64_t max_uint32 = std::numeric_limits<uint32_t>::max();
1520  if (interactions_total >= max_uint32) {
1521  throw std::runtime_error("Integer overflow in total interaction number!");
1522  }
1523 }
1524 
1525 template <typename Modus>
1527  const auto &log = logger<LogArea::Experiment>();
1528 
1529  const double start_time = parameters_.labclock.current_time();
1530  const double end_time = std::min(parameters_.labclock.next_time(), end_time_);
1531  double time_left = end_time - start_time;
1532  log.debug("Timestepless propagation: ", "Actions size = ", actions.size(),
1533  ", start time = ", start_time, ", end time = ", end_time);
1534 
1535  // iterate over all actions
1536  while (!actions.is_empty()) {
1537  // get next action
1538  ActionPtr act = actions.pop();
1539  if (!act->is_valid(particles_)) {
1540  log.debug(~einhard::DRed(), "✘ ", act, " (discarded: invalid)");
1541  continue;
1542  }
1543  if (act->time_of_execution() > end_time) {
1544  log.error(act, " scheduled later than end time: t_action[fm/c] = ",
1545  act->time_of_execution(), ", t_end[fm/c] = ", end_time);
1546  }
1547  log.debug(~einhard::Green(), "✔ ", act);
1548 
1549  while (next_output_time() <= act->time_of_execution()) {
1550  log.debug("Propagating until output time: ", next_output_time());
1551  propagate_and_shine(next_output_time());
1552  ++parameters_.outputclock;
1553  intermediate_output();
1554  }
1555 
1556  /* (1) Propagate to the next action. */
1557  log.debug("Propagating until next action ", act,
1558  ", action time = ", act->time_of_execution());
1559  propagate_and_shine(act->time_of_execution());
1560 
1561  /* (2) Perform action.
1562  *
1563  * Update the positions of the incoming particles, because the information
1564  * in the action object will be outdated as the particles have been
1565  * propagated since the construction of the action. */
1566  act->update_incoming(particles_);
1567 
1568  const bool performed = perform_action(*act, particles_);
1569 
1570  /* No need to update actions for outgoing particles
1571  * if the action is not performed. */
1572  if (!performed) {
1573  continue;
1574  }
1575 
1576  /* (3) Update actions for newly-produced particles. */
1577 
1578  time_left = end_time - act->time_of_execution();
1579  const ParticleList &outgoing_particles = act->outgoing_particles();
1580  for (const auto &finder : action_finders_) {
1581  // Outgoing particles can still decay, cross walls...
1582  actions.insert(
1583  finder->find_actions_in_cell(outgoing_particles, time_left));
1584  // ... and collide with other particles.
1585  actions.insert(finder->find_actions_with_surrounding_particles(
1586  outgoing_particles, particles_, time_left));
1587  }
1588 
1589  check_interactions_total(interactions_total_);
1590  }
1591 
1592  while (next_output_time() <= end_time) {
1593  log.debug("Propagating until output time: ", next_output_time());
1594  propagate_and_shine(next_output_time());
1595  ++parameters_.outputclock;
1596  // Avoid duplicating printout at event end time
1597  if (parameters_.outputclock.current_time() < end_time_) {
1598  intermediate_output();
1599  }
1600  }
1601 
1602  log.debug("Propagating to time ", end_time);
1603  propagate_and_shine(end_time);
1604 }
1605 
1606 template <typename Modus>
1608  const auto &log = logger<LogArea::Experiment>();
1609  const uint64_t wall_actions_this_interval =
1610  wall_actions_total_ - previous_wall_actions_total_;
1611  previous_wall_actions_total_ = wall_actions_total_;
1612  const uint64_t interactions_this_interval = interactions_total_ -
1613  previous_interactions_total_ -
1614  wall_actions_this_interval;
1615  previous_interactions_total_ = interactions_total_;
1616  log.info() << format_measurements(particles_, interactions_this_interval,
1617  conserved_initial_, time_start_,
1618  parameters_.outputclock.current_time());
1619  const LatticeUpdate lat_upd = LatticeUpdate::AtOutput;
1620  // save evolution data
1621  for (const auto &output : outputs_) {
1622  if (output->is_dilepton_output() || output->is_photon_output()) {
1623  continue;
1624  }
1625  output->at_intermediate_time(particles_, parameters_.outputclock,
1626  density_param_);
1627 
1628  // Thermodynamic output on the lattice versus time
1629  switch (dens_type_lattice_printout_) {
1630  case DensityType::Baryon:
1631  update_lattice(jmu_B_lat_.get(), lat_upd, DensityType::Baryon,
1632  density_param_, particles_, false);
1633  output->thermodynamics_output(ThermodynamicQuantity::EckartDensity,
1634  DensityType::Baryon, *jmu_B_lat_);
1635  break;
1636  case DensityType::BaryonicIsospin:
1637  update_lattice(jmu_I3_lat_.get(), lat_upd, DensityType::BaryonicIsospin,
1638  density_param_, particles_, false);
1639  output->thermodynamics_output(ThermodynamicQuantity::EckartDensity,
1640  DensityType::BaryonicIsospin,
1641  *jmu_I3_lat_);
1642  break;
1643  case DensityType::None:
1644  break;
1645  default:
1646  update_lattice(jmu_custom_lat_.get(), lat_upd,
1647  dens_type_lattice_printout_, density_param_, particles_,
1648  false);
1649  output->thermodynamics_output(ThermodynamicQuantity::EckartDensity,
1650  dens_type_lattice_printout_,
1651  *jmu_custom_lat_);
1652  }
1653  if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
1654  update_lattice(Tmn_.get(), lat_upd, dens_type_lattice_printout_,
1655  density_param_, particles_);
1656  if (printout_tmn_) {
1657  output->thermodynamics_output(ThermodynamicQuantity::Tmn,
1658  dens_type_lattice_printout_, *Tmn_);
1659  }
1660  if (printout_tmn_landau_) {
1661  output->thermodynamics_output(ThermodynamicQuantity::TmnLandau,
1662  dens_type_lattice_printout_, *Tmn_);
1663  }
1664  if (printout_v_landau_) {
1665  output->thermodynamics_output(ThermodynamicQuantity::LandauVelocity,
1666  dens_type_lattice_printout_, *Tmn_);
1667  }
1668  }
1669 
1670  if (thermalizer_) {
1671  output->thermodynamics_output(*thermalizer_);
1672  }
1673  }
1674 }
1675 
1676 template <typename Modus>
1678  if (potentials_) {
1679  if (potentials_->use_skyrme() && jmu_B_lat_ != nullptr) {
1680  update_lattice(jmu_B_lat_.get(), LatticeUpdate::EveryTimestep,
1681  DensityType::Baryon, density_param_, particles_, true);
1682  const size_t UBlattice_size = UB_lat_->size();
1683  for (size_t i = 0; i < UBlattice_size; i++) {
1684  auto jB = (*jmu_B_lat_)[i];
1685  const FourVector flow_four_velocity =
1686  std::abs(jB.density()) > really_small ? jB.jmu_net() / jB.density()
1687  : FourVector();
1688  (*UB_lat_)[i] =
1689  flow_four_velocity * potentials_->skyrme_pot(jB.density());
1690  (*FB_lat_)[i] = potentials_->skyrme_force(jB.density(), jB.grad_rho(),
1691  jB.dj_dt(), jB.rot_j());
1692  }
1693  }
1694  if (potentials_->use_symmetry() && jmu_I3_lat_ != nullptr) {
1695  update_lattice(jmu_I3_lat_.get(), LatticeUpdate::EveryTimestep,
1696  DensityType::BaryonicIsospin, density_param_, particles_,
1697  true);
1698  const size_t UI3lattice_size = UI3_lat_->size();
1699  for (size_t i = 0; i < UI3lattice_size; i++) {
1700  auto jI3 = (*jmu_I3_lat_)[i];
1701  const FourVector flow_four_velocity =
1702  std::abs(jI3.density()) > really_small
1703  ? jI3.jmu_net() / jI3.density()
1704  : FourVector();
1705  (*UI3_lat_)[i] =
1706  flow_four_velocity * potentials_->symmetry_pot(jI3.density());
1707  (*FI3_lat_)[i] = potentials_->symmetry_force(jI3.grad_rho(),
1708  jI3.dj_dt(), jI3.rot_j());
1709  }
1710  }
1711  }
1712 }
1713 
1714 template <typename Modus>
1716  /* At end of time evolution: Force all resonances to decay. In order to handle
1717  * decay chains, we need to loop until no further actions occur. */
1718  uint64_t interactions_old;
1719  const auto particles_before_actions = particles_.copy_to_vector();
1720  do {
1721  Actions actions;
1722 
1723  interactions_old = interactions_total_;
1724 
1725  // Dileptons: shining of remaining resonances
1726  if (dilepton_finder_ != nullptr) {
1727  for (const auto &output : outputs_) {
1728  dilepton_finder_->shine_final(particles_, output.get(), true);
1729  }
1730  }
1731  // Find actions.
1732  for (const auto &finder : action_finders_) {
1733  actions.insert(finder->find_final_actions(particles_));
1734  }
1735  // Perform actions.
1736  while (!actions.is_empty()) {
1737  perform_action(*actions.pop(), particles_before_actions);
1738  }
1739  // loop until no more decays occur
1740  } while (interactions_total_ > interactions_old);
1741 
1742  // Dileptons: shining of stable particles at the end
1743  if (dilepton_finder_ != nullptr) {
1744  for (const auto &output : outputs_) {
1745  dilepton_finder_->shine_final(particles_, output.get(), false);
1746  }
1747  }
1748 }
1749 
1750 template <typename Modus>
1751 void Experiment<Modus>::final_output(const int evt_num) {
1752  const auto &log = logger<LogArea::Experiment>();
1753  /* make sure the experiment actually ran (note: we should compare this
1754  * to the start time, but we don't know that. Therefore, we check that
1755  * the time is positive, which should heuristically be the same). */
1756  if (likely(parameters_.labclock > 0)) {
1757  const uint64_t wall_actions_this_interval =
1758  wall_actions_total_ - previous_wall_actions_total_;
1759  const uint64_t interactions_this_interval = interactions_total_ -
1760  previous_interactions_total_ -
1761  wall_actions_this_interval;
1762  log.info() << format_measurements(particles_, interactions_this_interval,
1763  conserved_initial_, time_start_,
1764  parameters_.outputclock.current_time());
1765  log.info() << hline;
1766  log.info() << "Time real: " << SystemClock::now() - time_start_;
1767  log.info() << "Final interaction number: "
1768  << interactions_total_ - wall_actions_total_;
1769  // Check if there are unformed particles
1770  int unformed_particles_count = 0;
1771  for (const auto &particle : particles_) {
1772  if (particle.formation_time() > end_time_) {
1773  unformed_particles_count++;
1774  }
1775  }
1776  if (unformed_particles_count > 0) {
1777  log.warn("End time might be too small. ", unformed_particles_count,
1778  " unformed particles were found at the end of the evolution.");
1779  }
1780  }
1781 
1782  for (const auto &output : outputs_) {
1783  output->at_eventend(particles_, evt_num, modus_.impact_parameter());
1784  }
1785 }
1786 
1787 template <typename Modus>
1789  const auto &mainlog = logger<LogArea::Main>();
1790  for (int j = 0; j < nevents_; j++) {
1791  mainlog.info() << "Event " << j;
1792 
1793  // Sample initial particles, start clock, some printout and book-keeping
1794  initialize_new_event();
1795  /* In the ColliderModus, if the first collisions within the same nucleus are
1796  * forbidden, 'nucleon_has_interacted_', which records whether a nucleon has
1797  * collided with another nucleon, is initialized equal to false. If allowed,
1798  * 'nucleon_has_interacted' is initialized equal to true, which means these
1799  * incoming particles have experienced some fake scatterings, they can
1800  * therefore collide with each other later on since these collisions are not
1801  * "first" to them. */
1802  if (modus_.is_collider()) {
1803  if (!modus_.cll_in_nucleus()) {
1804  nucleon_has_interacted_.assign(modus_.total_N_number(), false);
1805  } else {
1806  nucleon_has_interacted_.assign(modus_.total_N_number(), true);
1807  }
1808  }
1809  /* In the ColliderModus, if Fermi motion is frozen, assign the beam momenta
1810  * to the nucleons in both the projectile and the target. */
1811  if (modus_.is_collider() && modus_.fermi_motion() == FermiMotion::Frozen) {
1812  for (int i = 0; i < modus_.total_N_number(); i++) {
1813  const auto mass_beam = particles_.copy_to_vector()[i].effective_mass();
1814  const auto v_beam = i < modus_.proj_N_number()
1815  ? modus_.velocity_projectile()
1816  : modus_.velocity_target();
1817  const auto gamma = 1.0 / std::sqrt(1.0 - v_beam * v_beam);
1818  beam_momentum_.emplace_back(FourVector(gamma * mass_beam, 0.0, 0.0,
1819  gamma * v_beam * mass_beam));
1820  }
1821  }
1822 
1823  // Output at event start
1824  for (const auto &output : outputs_) {
1825  output->at_eventstart(particles_, j);
1826  }
1827 
1828  run_time_evolution();
1829 
1830  if (force_decays_) {
1831  do_final_decays();
1832  }
1833 
1834  // Output at event end
1835  final_output(j);
1836  }
1837 }
1838 
1839 } // namespace smash
1840 
1841 #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
A class to pre-calculate and store parameters relevant for density calculation.
Definition: density.h:106
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:1518
virtual void generate_final_state()=0
Generate the final state for this action.
double sqrt_s() const
Determine the total energy in the center-of-mass frame [GeV].
Definition: action.h:265
std::unique_ptr< RectangularLattice< EnergyMomentumTensor > > Tmn_
Lattices of energy-momentum tensors for printout.
Definition: experiment.h:405
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
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< 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
DensityType td_dens_type
Type (e.g., baryon/pion/hadron) of thermodynamic quantity.
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
RectangularLattice< FourVector > * UI3_lat_pointer
Pointer to the symmmetry potential on the lattice.
#define likely(x)
Tell the branch predictor that this expression is likely true.
Definition: macros.h:14
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:400
STL namespace.
ThreeVector threevec() const
Definition: fourvector.h:306
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:71
LatticeUpdate
Enumerator option for lattice updates.
Definition: lattice.h:35
Interface to the SMASH configuration files.
double next_output_time() const
Shortcut for next output time.
Definition: experiment.h:293
bool is_pauli_blocked(const Particles &particles, const PauliBlocker &p_bl) const
Check if the action is Pauli-blocked.
Definition: action.cc:35
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:281
virtual ProcessType get_type() const
Get the process type.
Definition: action.h:130
bool has_value(std::initializer_list< const char * > keys) const
Returns whether there is a non-empty value behind the requested keys.
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
bool td_tmn_landau
Print out energy-momentum tensor in Landau rest frame (of type td_dens_type) or not?
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
QuantumNumbers conserved_initial_
The conserved quantities of the system.
Definition: experiment.h:485
ThermalizationAction implements forced thermalization as an Action class.
ExperimentParameters parameters_
Struct of several member variables.
Definition: experiment.h:302
bool any_particles_thermalized() const
This method checks, if there are particles in the region to be thermalized.
const bool use_grid_
This indicates whether to use the grid.
Definition: experiment.h:461
A container class to hold all the arrays on the lattice and access them.
Definition: lattice.h:46
Particles particles_
Complete particle list.
Definition: experiment.h:314
const std::string hline(67, '-')
String representing a horizontal line.
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
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:735
const double end_time_
simulation time at which the evolution is stopped.
Definition: experiment.h:445
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:78
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:330
#define source_location
Hackery that is required to output the location in the source code where the log statement occurs...
Definition: logging.h:246
Value take(std::initializer_list< const char * > keys)
The default interface for SMASH to read configuration values.
Don&#39;t use time steps; propagate from action to action.
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
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
const double delta_time_startup_
The clock&#39;s timestep size at start up.
Definition: experiment.h:452
A container for storing conserved values.
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
Helper structure for Experiment to hold output options and parameters.
const bool dileptons_switch_
This indicates whether dileptons are switched on.
Definition: experiment.h:467
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
void add_dummy_hadronic_process(double reaction_cross_section)
Adds one hadronic process with a given cross-section.
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
bool is_empty() const
Definition: actions.h:52
virtual double get_total_weight() const =0
Return the total weight value, which is mainly used for the weight output entry.
ScatterActionPhoton is a special action which takes two incoming particles and performs a perturbativ...
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
Use fermi motion without potentials.
bool is_valid(const Particles &particles) const
Check whether the action still applies.
Definition: action.cc:29
FourVector get_interaction_point() const
Get the interaction point.
Definition: action.cc:68
Use fixed time step.
std::tuple< double, FourVector, ThreeVector, ThreeVector, ThreeVector > current_eckart(const ThreeVector &r, const ParticleList &plist, const DensityParameters &par, DensityType dens_type, bool compute_gradient, bool smearing)
Calculates Eckart rest frame density and 4-current of a given density type and optionally the gradien...
Definition: density.cc:149
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
Modus modus_
Instance of the Modus template parameter.
Definition: experiment.h:311
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
bool td_tmn
Print out energy-momentum tensor of type td_dens_type or not?
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
DensityParameters density_param_
Structure to precalculate and hold parameters for density computations.
Definition: experiment.h:305
A stream modifier that allows to colorize the log output.
Definition: einhard.hpp:142
const ParticleList & incoming_particles() const
Get the list of particles that go into the action.
Definition: action.cc:58
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
bool td_v_landau
Print out Landau velocity of type td_dens_type or not?
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
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
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
ActionList::size_type size() const
Definition: actions.h:95
Helper structure for Experiment.
Definition: action.h:24
virtual void perform(Particles *particles, uint32_t id_process)
Actually perform the action, e.g.
Definition: action.cc:94