Version: SMASH-1.7
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"
25 #include "outputparameters.h"
26 #include "pauliblocking.h"
27 #include "potential_globals.h"
28 #include "potentials.h"
29 #include "processstring.h"
30 #include "propagation.h"
31 #include "quantumnumbers.h"
32 #include "scatteractionphoton.h"
33 #include "scatteractionsfinder.h"
34 #include "thermalizationaction.h"
35 // Output
36 #include "binaryoutput.h"
37 #include "icoutput.h"
38 #include "oscaroutput.h"
39 #include "thermodynamicoutput.h"
40 #ifdef SMASH_USE_ROOT
41 #include "rootoutput.h"
42 #endif
43 #include "vtkoutput.h"
44 #include "wallcrossingaction.h"
45 
46 namespace std {
57 template <typename T, typename Ratio>
58 static ostream &operator<<(ostream &out,
59  const chrono::duration<T, Ratio> &seconds) {
60  using Seconds = chrono::duration<double>;
61  using Minutes = chrono::duration<double, std::ratio<60>>;
62  using Hours = chrono::duration<double, std::ratio<60 * 60>>;
63  constexpr Minutes threshold_for_minutes{10};
64  constexpr Hours threshold_for_hours{3};
65  if (seconds < threshold_for_minutes) {
66  return out << Seconds(seconds).count() << " [s]";
67  }
68  if (seconds < threshold_for_hours) {
69  return out << Minutes(seconds).count() << " [min]";
70  }
71  return out << Hours(seconds).count() << " [h]";
72 }
73 } // namespace std
74 
75 namespace smash {
76 
85  public:
86  ExperimentBase() = default;
91  virtual ~ExperimentBase() = default;
92 
113  static std::unique_ptr<ExperimentBase> create(Configuration config,
114  const bf::path &output_path);
115 
122  virtual void run() = 0;
123 
129  struct InvalidModusRequest : public std::invalid_argument {
130  using std::invalid_argument::invalid_argument;
131  };
132 };
133 
134 template <typename Modus>
136 template <typename Modus>
137 std::ostream &operator<<(std::ostream &out, const Experiment<Modus> &e);
138 
163 template <typename Modus>
164 class Experiment : public ExperimentBase {
165  friend class ExperimentBase;
166 
167  public:
174  void run() override;
175 
189  explicit Experiment(Configuration config, const bf::path &output_path);
190 
196  void initialize_new_event();
197 
204  void run_time_evolution();
205 
207  void do_final_decays();
208 
214  void final_output(const int evt_num);
215 
220  Particles *particles() { return &particles_; }
221 
226  Modus *modus() { return &modus_; }
227 
228  private:
240  template <typename Container>
241  bool perform_action(Action &action,
242  const Container &particles_before_actions);
251  void create_output(const std::string &format, const std::string &content,
252  const bf::path &output_path, const OutputParameters &par);
253 
260  void propagate_and_shine(double to_time);
261 
274  void run_time_evolution_timestepless(Actions &actions);
275 
277  void intermediate_output();
278 
280  void update_potentials();
281 
290  double compute_min_cell_length(double dt) const {
291  return std::sqrt(4 * dt * dt + max_transverse_distance_sqr_);
292  }
293 
295  double next_output_time() const {
296  return parameters_.outputclock->next_time();
297  }
298 
305 
308 
313  Modus modus_;
314 
317 
322  std::unique_ptr<Potentials> potentials_;
323 
328  std::unique_ptr<PauliBlocker> pauli_blocker_;
329 
334  OutputsList outputs_;
335 
337  OutputPtr dilepton_output_;
338 
340  OutputPtr photon_output_;
341 
347  std::vector<bool> nucleon_has_interacted_ = {};
351  bool projectile_target_interact_ = false;
352 
358  std::vector<FourVector> beam_momentum_ = {};
359 
361  std::vector<std::unique_ptr<ActionFinderInterface>> action_finders_;
362 
364  std::unique_ptr<DecayActionsFinderDilepton> dilepton_finder_;
365 
367  std::unique_ptr<ActionFinderInterface> photon_finder_;
368 
370  int n_fractional_photons_ = 100;
371 
373  std::unique_ptr<DensityLattice> jmu_B_lat_;
374 
376  std::unique_ptr<DensityLattice> jmu_I3_lat_;
377 
385  std::unique_ptr<DensityLattice> jmu_custom_lat_;
386 
388  DensityType dens_type_lattice_printout_ = DensityType::None;
389 
394  std::unique_ptr<RectangularLattice<FourVector>> UB_lat_ = nullptr;
395 
400  std::unique_ptr<RectangularLattice<FourVector>> UI3_lat_ = nullptr;
401 
403  std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
405 
407  std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
409 
411  std::unique_ptr<RectangularLattice<EnergyMomentumTensor>> Tmn_;
412 
414  bool printout_tmn_ = false;
415 
417  bool printout_tmn_landau_ = false;
418 
420  bool printout_v_landau_ = false;
421 
423  bool printout_lattice_td_ = false;
424 
426  std::unique_ptr<GrandCanThermalizer> thermalizer_;
427 
433 
448  const int nevents_;
449 
451  const double end_time_;
452 
458  const double delta_time_startup_;
459 
464  const bool force_decays_;
465 
467  const bool use_grid_;
468 
471 
473  const bool dileptons_switch_;
474 
476  const bool photons_switch_;
477 
479  const bool IC_output_switch_;
480 
483 
485  double max_transverse_distance_sqr_ = std::numeric_limits<double>::max();
486 
495 
497  SystemTimePoint time_start_ = SystemClock::now();
498 
500  DensityType dens_type_ = DensityType::None;
501 
506  uint64_t interactions_total_ = 0;
507 
512  uint64_t previous_interactions_total_ = 0;
513 
518  uint64_t wall_actions_total_ = 0;
519 
524  uint64_t previous_wall_actions_total_ = 0;
525 
530  uint64_t total_pauli_blocked_ = 0;
531 
536  uint64_t total_hypersurface_crossing_actions_ = 0;
537 
542  double total_energy_removed_ = 0.0;
543 
545  int64_t seed_ = -1;
546 
552  friend std::ostream &operator<<<>(std::ostream &out, const Experiment &e);
553 };
554 
556 template <typename Modus>
557 std::ostream &operator<<(std::ostream &out, const Experiment<Modus> &e) {
558  out << "End time: " << e.end_time_ << " fm/c\n";
559  out << e.modus_;
560  return out;
561 }
562 
563 template <typename Modus>
564 void Experiment<Modus>::create_output(const std::string &format,
565  const std::string &content,
566  const bf::path &output_path,
567  const OutputParameters &out_par) {
568  const auto &log = logger<LogArea::Experiment>();
569  log.info() << "Adding output " << content << " of format " << format
570  << std::endl;
571 
572  if (format == "VTK" && content == "Particles") {
573  outputs_.emplace_back(
574  make_unique<VtkOutput>(output_path, content, out_par));
575  } else if (format == "Root") {
576 #ifdef SMASH_USE_ROOT
577  if (content == "Initial_Conditions") {
578  outputs_.emplace_back(
579  make_unique<RootOutput>(output_path, "SMASH_IC", out_par));
580  } else {
581  outputs_.emplace_back(
582  make_unique<RootOutput>(output_path, content, out_par));
583  }
584 #else
585  log.error("Root output requested, but Root support not compiled in");
586 #endif
587  } else if (format == "Binary") {
588  if (content == "Collisions" || content == "Dileptons" ||
589  content == "Photons") {
590  outputs_.emplace_back(
591  make_unique<BinaryOutputCollisions>(output_path, content, out_par));
592  } else if (content == "Particles") {
593  outputs_.emplace_back(
594  make_unique<BinaryOutputParticles>(output_path, content, out_par));
595  } else if (content == "Initial_Conditions") {
596  outputs_.emplace_back(make_unique<BinaryOutputInitialConditions>(
597  output_path, content, out_par));
598  }
599  } else if (format == "Oscar1999" || format == "Oscar2013") {
600  outputs_.emplace_back(
601  create_oscar_output(format, content, output_path, out_par));
602  } else if (content == "Thermodynamics" && format == "ASCII") {
603  outputs_.emplace_back(
604  make_unique<ThermodynamicOutput>(output_path, content, out_par));
605  } else if (content == "Thermodynamics" && format == "VTK") {
606  printout_lattice_td_ = true;
607  outputs_.emplace_back(
608  make_unique<VtkOutput>(output_path, content, out_par));
609  } else if (content == "Initial_Conditions" && format == "ASCII") {
610  outputs_.emplace_back(
611  make_unique<ICOutput>(output_path, "SMASH_IC", out_par));
612  } else {
613  log.error() << "Unknown combination of format (" << format
614  << ") and content (" << content << "). Fix the config.";
615  }
616 }
617 
626 
755 template <typename Modus>
756 Experiment<Modus>::Experiment(Configuration config, const bf::path &output_path)
757  : parameters_(create_experiment_parameters(config)),
758  density_param_(DensityParameters(parameters_)),
759  modus_(config["Modi"], parameters_),
760  particles_(),
761  nevents_(config.take({"General", "Nevents"})),
762  end_time_(config.take({"General", "End_Time"})),
763  delta_time_startup_(parameters_.labclock->timestep_duration()),
764  force_decays_(
765  config.take({"Collision_Term", "Force_Decays_At_End"}, true)),
766  use_grid_(config.take({"General", "Use_Grid"}, true)),
767  metric_(
768  config.take({"General", "Metric_Type"}, ExpansionMode::NoExpansion),
769  config.take({"General", "Expansion_Rate"}, 0.1)),
770  dileptons_switch_(config.has_value({"Output", "Dileptons"})),
771  photons_switch_(config.has_value({"Output", "Photons"})),
772  IC_output_switch_(config.has_value({"Output", "Initial_Conditions"})),
773  time_step_mode_(
774  config.take({"General", "Time_Step_Mode"}, TimeStepMode::Fixed)) {
775  const auto &log = logger<LogArea::Experiment>();
776  log.info() << *this;
777 
778  // create finders
779  if (dileptons_switch_) {
780  dilepton_finder_ = make_unique<DecayActionsFinderDilepton>();
781  }
782  if (parameters_.photons_switch) {
783  n_fractional_photons_ = config.take({"Output", "Photons", "Fractions"});
784  }
785  if (parameters_.two_to_one) {
786  action_finders_.emplace_back(make_unique<DecayActionsFinder>());
787  }
788  bool no_coll = config.take({"Collision_Term", "No_Collisions"}, false);
789  if ((parameters_.two_to_one || parameters_.included_2to2.any() ||
790  parameters_.strings_switch) &&
791  !no_coll) {
792  auto scat_finder = make_unique<ScatterActionsFinder>(
793  config, parameters_, nucleon_has_interacted_, modus_.total_N_number(),
794  modus_.proj_N_number());
795  max_transverse_distance_sqr_ =
796  scat_finder->max_transverse_distance_sqr(parameters_.testparticles);
797  process_string_ptr_ = scat_finder->get_process_string_ptr();
798  action_finders_.emplace_back(std::move(scat_finder));
799  } else {
800  max_transverse_distance_sqr_ = maximum_cross_section / M_PI * fm2_mb;
801  process_string_ptr_ = NULL;
802  }
803  const double modus_l = modus_.length();
804  if (modus_l > 0.) {
805  action_finders_.emplace_back(make_unique<WallCrossActionsFinder>(modus_l));
806  }
807  if (IC_output_switch_) {
808  if (!modus_.is_collider()) {
809  throw std::runtime_error(
810  "Initial conditions can only be extracted in collider modus.");
811  }
812  double proper_time;
813  if (config.has_value({"Output", "Initial_Conditions", "Proper_Time"})) {
814  // Read in proper time from config
815  proper_time =
816  config.take({"Output", "Initial_Conditions", "Proper_Time"});
817  } else {
818  // Default proper time is the passing time of the two nuclei
819  proper_time = modus_.nuclei_passing_time();
820  }
821  action_finders_.emplace_back(
822  make_unique<HyperSurfaceCrossActionsFinder>(proper_time));
823  }
824 
825  if (config.has_value({"Collision_Term", "Pauli_Blocking"})) {
826  log.info() << "Pauli blocking is ON.";
827  pauli_blocker_ = make_unique<PauliBlocker>(
828  config["Collision_Term"]["Pauli_Blocking"], parameters_);
829  }
830  ParticleData::formation_power_ =
831  config.take({"Collision_Term", "Power_Particle_Formation"}, 1.);
832 
866  // create outputs
867  log.trace(source_location, " create OutputInterface objects");
868 
869  auto output_conf = config["Output"];
1147  dens_type_ = config.take({"Output", "Density_Type"}, DensityType::None);
1148  log.debug() << "Density type printed to headers: " << dens_type_;
1149 
1150  const OutputParameters output_parameters(std::move(output_conf));
1151 
1152  std::vector<std::string> output_contents = output_conf.list_upmost_nodes();
1153  for (const auto &content : output_contents) {
1154  auto this_output_conf = output_conf[content.c_str()];
1155  const std::vector<std::string> formats = this_output_conf.take({"Format"});
1156  if (output_path == "") {
1157  continue;
1158  }
1159  for (const auto &format : formats) {
1160  create_output(format, content, output_path, output_parameters);
1161  }
1162  }
1163 
1164  /* We can take away the Fermi motion flag, because the collider modus is
1165  * already initialized. We only need it when potentials are enabled, but we
1166  * always have to take it, otherwise SMASH will complain about unused
1167  * options. We have to provide a default value for modi other than Collider.
1168  */
1169  const FermiMotion motion =
1170  config.take({"Modi", "Collider", "Fermi_Motion"}, FermiMotion::Off);
1171  if (config.has_value({"Potentials"})) {
1172  if (time_step_mode_ == TimeStepMode::None) {
1173  log.error() << "Potentials only work with time steps!";
1174  throw std::invalid_argument("Can't use potentials without time steps!");
1175  }
1176  if (motion == FermiMotion::Frozen) {
1177  log.error() << "Potentials don't work with frozen Fermi momenta! "
1178  "Use normal Fermi motion instead.";
1179  throw std::invalid_argument(
1180  "Can't use potentials "
1181  "with frozen Fermi momenta!");
1182  }
1183  log.info() << "Potentials are ON. Timestep is "
1184  << parameters_.labclock->timestep_duration();
1185  // potentials need testparticles and gaussian sigma from parameters_
1186  potentials_ = make_unique<Potentials>(config["Potentials"], parameters_);
1187  }
1188 
1243  // Create lattices
1244  if (config.has_value({"Lattice"})) {
1245  // Take lattice properties from config to assign them to all lattices
1246  const std::array<double, 3> l = config.take({"Lattice", "Sizes"});
1247  const std::array<int, 3> n = config.take({"Lattice", "Cell_Number"});
1248  const std::array<double, 3> origin = config.take({"Lattice", "Origin"});
1249  const bool periodic = config.take({"Lattice", "Periodic"});
1250 
1251  if (printout_lattice_td_) {
1252  dens_type_lattice_printout_ = output_parameters.td_dens_type;
1253  printout_tmn_ = output_parameters.td_tmn;
1254  printout_tmn_landau_ = output_parameters.td_tmn_landau;
1255  printout_v_landau_ = output_parameters.td_v_landau;
1256  }
1257  if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
1258  Tmn_ = make_unique<RectangularLattice<EnergyMomentumTensor>>(
1259  l, n, origin, periodic, LatticeUpdate::AtOutput);
1260  }
1261  /* Create baryon and isospin density lattices regardless of config
1262  if potentials are on. This is because they allow to compute
1263  potentials faster */
1264  if (potentials_) {
1265  if (potentials_->use_skyrme()) {
1266  jmu_B_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1267  LatticeUpdate::EveryTimestep);
1268  UB_lat_ = make_unique<RectangularLattice<FourVector>>(
1269  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1270  FB_lat_ = make_unique<
1272  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1273  }
1274  if (potentials_->use_symmetry()) {
1275  jmu_I3_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1276  LatticeUpdate::EveryTimestep);
1277  UI3_lat_ = make_unique<RectangularLattice<FourVector>>(
1278  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1279  FI3_lat_ = make_unique<
1281  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1282  }
1283  } else {
1284  if (dens_type_lattice_printout_ == DensityType::Baryon) {
1285  jmu_B_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1286  LatticeUpdate::AtOutput);
1287  }
1288  if (dens_type_lattice_printout_ == DensityType::BaryonicIsospin) {
1289  jmu_I3_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1290  LatticeUpdate::AtOutput);
1291  }
1292  }
1293  if (dens_type_lattice_printout_ != DensityType::None &&
1294  dens_type_lattice_printout_ != DensityType::BaryonicIsospin &&
1295  dens_type_lattice_printout_ != DensityType::Baryon) {
1296  jmu_custom_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1297  LatticeUpdate::AtOutput);
1298  }
1299  } else if (printout_lattice_td_) {
1300  log.error(
1301  "If you want Thermodynamic VTK output, configure a lattice for it.");
1302  }
1303 
1304  // Store pointers to potential and lattice accessible for Action
1305  if (parameters_.potential_affect_threshold) {
1306  UB_lat_pointer = UB_lat_.get();
1307  UI3_lat_pointer = UI3_lat_.get();
1308  pot_pointer = potentials_.get();
1309  }
1310 
1311  // Create forced thermalizer
1312  if (config.has_value({"Forced_Thermalization"})) {
1313  Configuration &&th_conf = config["Forced_Thermalization"];
1314  thermalizer_ = modus_.create_grandcan_thermalizer(th_conf);
1315  }
1316 
1317  /* Take the seed setting only after the configuration was stored to a file
1318  * in smash.cc */
1319  seed_ = config.take({"General", "Randomseed"});
1320 }
1321 
1323 const std::string hline(67, '-');
1324 
1325 template <typename Modus>
1327  const auto &log = logger<LogArea::Experiment>();
1328 
1329  random::set_seed(seed_);
1330  log.info() << "random number seed: " << seed_;
1331  /* Set seed for the next event. It has to be positive, so it can be entered
1332  * in the config.
1333  *
1334  * We have to be careful about the minimal integer, whose absolute value
1335  * cannot be represented. */
1336  int64_t r = random::advance();
1337  while (r == INT64_MIN) {
1338  r = random::advance();
1339  }
1340  seed_ = std::abs(r);
1341  /* Set the random seed used in PYTHIA hadronization
1342  * to be same with the SMASH one.
1343  * In this way we ensure that the results are reproducible
1344  * for every event if one knows SMASH random seed. */
1345  if (process_string_ptr_ != NULL) {
1346  process_string_ptr_->init_pythia_hadron_rndm();
1347  }
1348 
1349  particles_.reset();
1350 
1351  // Sample particles according to the initial conditions
1352  double start_time = modus_.initial_conditions(&particles_, parameters_);
1353  /* For box modus make sure that particles are in the box. In principle, after
1354  * a correct initialization they should be, so this is just playing it safe.
1355  */
1356  modus_.impose_boundary_conditions(&particles_, outputs_);
1357  // Reset the simulation clock
1358  double timestep = delta_time_startup_;
1359 
1360  switch (time_step_mode_) {
1361  case TimeStepMode::Fixed:
1362  break;
1363  case TimeStepMode::None:
1364  timestep = end_time_ - start_time;
1365  // Take care of the box modus + timestepless propagation
1366  const double max_dt = modus_.max_timestep(max_transverse_distance_sqr_);
1367  if (max_dt > 0. && max_dt < timestep) {
1368  timestep = max_dt;
1369  }
1370  break;
1371  }
1372  std::unique_ptr<UniformClock> clock_for_this_event;
1373  if (modus_.is_list() && (timestep < 0.0)) {
1374  throw std::runtime_error(
1375  "Timestep for the given event is negative. \n"
1376  "This might happen if the formation times of the input particles are "
1377  "larger than the specified end time of the simulation.");
1378  }
1379  clock_for_this_event = make_unique<UniformClock>(start_time, timestep);
1380  parameters_.labclock = std::move(clock_for_this_event);
1381 
1382  // Reset the output clock
1383  parameters_.outputclock->reset(start_time, true);
1384  // remove time before starting time in case of custom output times.
1385  parameters_.outputclock->remove_times_in_past(start_time);
1386 
1387  log.debug("Lab clock: t_start = ", parameters_.labclock->current_time(),
1388  ", dt = ", parameters_.labclock->timestep_duration());
1389 
1390  /* Save the initial conserved quantum numbers and total momentum in
1391  * the system for conservation checks */
1392  conserved_initial_ = QuantumNumbers(particles_);
1393  wall_actions_total_ = 0;
1394  previous_wall_actions_total_ = 0;
1395  interactions_total_ = 0;
1396  previous_interactions_total_ = 0;
1397  total_pauli_blocked_ = 0;
1398  projectile_target_interact_ = false;
1399  total_hypersurface_crossing_actions_ = 0;
1400  total_energy_removed_ = 0.0;
1401  // Print output headers
1402  log.info() << hline;
1403  log.info() << "Time [fm] Ediff [GeV] Scatt.|Decays "
1404  "Particles Timing";
1405  log.info() << hline;
1406 }
1407 
1408 template <typename Modus>
1409 template <typename Container>
1411  Action &action, const Container &particles_before_actions) {
1412  const auto &log = logger<LogArea::Experiment>();
1413  // Make sure to skip invalid and Pauli-blocked actions.
1414  if (!action.is_valid(particles_)) {
1415  log.debug(~einhard::DRed(), "✘ ", action, " (discarded: invalid)");
1416  return false;
1417  }
1418  action.generate_final_state();
1419  log.debug("Process Type is: ", action.get_type());
1420  if (pauli_blocker_ && action.is_pauli_blocked(particles_, *pauli_blocker_)) {
1421  total_pauli_blocked_++;
1422  return false;
1423  }
1424  if (modus_.is_collider()) {
1425  /* Mark incoming nucleons as interacted - now they are permitted
1426  * to collide with nucleons from their native nucleus */
1427  bool incoming_projectile = false;
1428  bool incoming_target = false;
1429  for (const auto &incoming : action.incoming_particles()) {
1430  assert(incoming.id() >= 0);
1431  if (incoming.id() < modus_.total_N_number()) {
1432  nucleon_has_interacted_[incoming.id()] = true;
1433  }
1434  if (incoming.id() < modus_.proj_N_number()) {
1435  incoming_projectile = true;
1436  }
1437  if (incoming.id() >= modus_.proj_N_number() &&
1438  incoming.id() < modus_.total_N_number()) {
1439  incoming_target = true;
1440  }
1441  }
1442  // Check whether particles from different nuclei interacted.
1443  if (incoming_projectile & incoming_target) {
1444  projectile_target_interact_ = true;
1445  }
1446  }
1447  /* Make sure to pick a non-zero integer, because 0 is reserved for "no
1448  * interaction yet". */
1449  const auto id_process = static_cast<uint32_t>(interactions_total_ + 1);
1450  action.perform(&particles_, id_process);
1451  interactions_total_++;
1452  if (action.get_type() == ProcessType::Wall) {
1453  wall_actions_total_++;
1454  }
1455  if (action.get_type() == ProcessType::HyperSurfaceCrossing) {
1456  total_hypersurface_crossing_actions_++;
1457  total_energy_removed_ += action.incoming_particles()[0].momentum().x0();
1458  }
1459  // Calculate Eckart rest frame density at the interaction point
1460  double rho = 0.0;
1461  if (dens_type_ != DensityType::None) {
1462  const FourVector r_interaction = action.get_interaction_point();
1463  constexpr bool compute_grad = false;
1464  const bool smearing = true;
1465  rho = std::get<0>(current_eckart(r_interaction.threevec(),
1466  particles_before_actions, density_param_,
1467  dens_type_, compute_grad, smearing));
1468  }
1484  for (const auto &output : outputs_) {
1485  if (!output->is_dilepton_output() && !output->is_photon_output()) {
1486  if (output->is_IC_output() &&
1487  action.get_type() == ProcessType::HyperSurfaceCrossing) {
1488  output->at_interaction(action, rho);
1489  } else if (!output->is_IC_output()) {
1490  output->at_interaction(action, rho);
1491  }
1492  }
1493  }
1494 
1495  // At every collision photons can be produced.
1496  // Note: We rely here on the lazy evaluation of the arguments to if.
1497  // It may happen that in a wall-crossing-action sqrt_s raises an exception.
1498  // Therefore we first have to check if the incoming particles can undergo
1499  // an em-interaction.
1500  if (photons_switch_ &&
1501  ScatterActionPhoton::is_photon_reaction(action.incoming_particles()) &&
1502  ScatterActionPhoton::is_kinematically_possible(
1503  action.sqrt_s(), action.incoming_particles())) {
1504  /* Time in the action constructor is relative to
1505  * current time of incoming */
1506  constexpr double action_time = 0.;
1507  ScatterActionPhoton photon_act(action.incoming_particles(), action_time,
1508  n_fractional_photons_,
1509  action.get_total_weight());
1510 
1521  photon_act.add_dummy_hadronic_process(action.get_total_weight());
1522 
1523  // Now add the actual photon reaction channel.
1524  photon_act.add_single_process();
1525 
1526  photon_act.perform_photons(outputs_);
1527  }
1528  log.debug(~einhard::Green(), "✔ ", action);
1529  return true;
1530 }
1531 
1552 std::string format_measurements(const Particles &particles,
1553  uint64_t scatterings_this_interval,
1554  const QuantumNumbers &conserved_initial,
1555  SystemTimePoint time_start, double time);
1556 
1557 template <typename Modus>
1559  Actions actions;
1560 
1561  const auto &log = logger<LogArea::Experiment>();
1562 
1563  log.info() << format_measurements(particles_, 0u, conserved_initial_,
1564  time_start_,
1565  parameters_.labclock->current_time());
1566 
1567  while (parameters_.labclock->current_time() < end_time_) {
1568  const double t = parameters_.labclock->current_time();
1569  const double dt =
1570  std::min(parameters_.labclock->timestep_duration(), end_time_ - t);
1571  log.debug("Timestepless propagation for next ", dt, " fm/c.");
1572 
1573  // Perform forced thermalization if required
1574  if (thermalizer_ &&
1575  thermalizer_->is_time_to_thermalize(parameters_.labclock)) {
1576  const bool ignore_cells_under_treshold = true;
1577  thermalizer_->update_thermalizer_lattice(particles_, density_param_,
1578  ignore_cells_under_treshold);
1579  const double current_t = parameters_.labclock->current_time();
1580  thermalizer_->thermalize(particles_, current_t,
1581  parameters_.testparticles);
1582  ThermalizationAction th_act(*thermalizer_, current_t);
1583  if (th_act.any_particles_thermalized()) {
1584  perform_action(th_act, particles_);
1585  }
1586  }
1587 
1588  if (particles_.size() > 0 && action_finders_.size() > 0) {
1589  /* (1.a) Create grid. */
1590  double min_cell_length = compute_min_cell_length(dt);
1591  log.debug("Creating grid with minimal cell length ", min_cell_length);
1592  const auto &grid =
1593  use_grid_ ? modus_.create_grid(particles_, min_cell_length, dt)
1594  : modus_.create_grid(particles_, min_cell_length, dt,
1595  CellSizeStrategy::Largest);
1596 
1597  const double cell_vol = grid.cell_volume();
1598 
1599  /* (1.b) Iterate over cells and find actions. */
1600  grid.iterate_cells(
1601  [&](const ParticleList &search_list) {
1602  for (const auto &finder : action_finders_) {
1603  actions.insert(finder->find_actions_in_cell(
1604  search_list, dt, cell_vol, beam_momentum_));
1605  }
1606  },
1607  [&](const ParticleList &search_list,
1608  const ParticleList &neighbors_list) {
1609  for (const auto &finder : action_finders_) {
1610  actions.insert(finder->find_actions_with_neighbors(
1611  search_list, neighbors_list, dt, beam_momentum_));
1612  }
1613  });
1614  }
1615 
1616  /* \todo (optimizations) Adapt timestep size here */
1617 
1618  /* (2) Propagation from action to action until the end of timestep */
1619  run_time_evolution_timestepless(actions);
1620 
1621  /* (3) Update potentials (if computed on the lattice) and
1622  * compute new momenta according to equations of motion */
1623  if (potentials_) {
1624  update_potentials();
1625  update_momenta(&particles_, parameters_.labclock->timestep_duration(),
1626  *potentials_, FB_lat_.get(), FI3_lat_.get());
1627  }
1628 
1629  /* (4) Expand universe if non-minkowskian metric; updates
1630  * positions and momenta according to the selected expansion */
1631  if (metric_.mode_ != ExpansionMode::NoExpansion) {
1632  expand_space_time(&particles_, parameters_, metric_);
1633  }
1634 
1635  ++(*parameters_.labclock);
1636 
1637  /* (5) Check conservation laws.
1638  *
1639  * Check conservation of conserved quantities if potentials and string
1640  * fragmentation are off. If potentials are on then momentum is conserved
1641  * only in average. If string fragmentation is on, then energy and
1642  * momentum are only very roughly conserved in high-energy collisions. */
1643  if (!potentials_ && !parameters_.strings_switch &&
1644  metric_.mode_ == ExpansionMode::NoExpansion && !IC_output_switch_) {
1645  std::string err_msg = conserved_initial_.report_deviations(particles_);
1646  if (!err_msg.empty()) {
1647  log.error() << err_msg;
1648  throw std::runtime_error("Violation of conserved quantities!");
1649  }
1650  }
1651  }
1652 
1653  if (pauli_blocker_) {
1654  log.info("Interactions: Pauli-blocked/performed = ", total_pauli_blocked_,
1655  "/", interactions_total_ - wall_actions_total_);
1656  }
1657 }
1658 
1659 template <typename Modus>
1661  const double dt =
1662  propagate_straight_line(&particles_, to_time, beam_momentum_);
1663  if (dilepton_finder_ != nullptr) {
1664  for (const auto &output : outputs_) {
1665  dilepton_finder_->shine(particles_, output.get(), dt);
1666  }
1667  }
1668 }
1669 
1677 inline void check_interactions_total(uint64_t interactions_total) {
1678  constexpr uint64_t max_uint32 = std::numeric_limits<uint32_t>::max();
1679  if (interactions_total >= max_uint32) {
1680  throw std::runtime_error("Integer overflow in total interaction number!");
1681  }
1682 }
1683 
1684 template <typename Modus>
1686  const auto &log = logger<LogArea::Experiment>();
1687 
1688  const double start_time = parameters_.labclock->current_time();
1689  const double end_time =
1690  std::min(parameters_.labclock->next_time(), end_time_);
1691  double time_left = end_time - start_time;
1692  log.debug("Timestepless propagation: ", "Actions size = ", actions.size(),
1693  ", start time = ", start_time, ", end time = ", end_time);
1694 
1695  // iterate over all actions
1696  while (!actions.is_empty()) {
1697  // get next action
1698  ActionPtr act = actions.pop();
1699  if (!act->is_valid(particles_)) {
1700  log.debug(~einhard::DRed(), "✘ ", act, " (discarded: invalid)");
1701  continue;
1702  }
1703  if (act->time_of_execution() > end_time) {
1704  log.error(act, " scheduled later than end time: t_action[fm/c] = ",
1705  act->time_of_execution(), ", t_end[fm/c] = ", end_time);
1706  }
1707  log.debug(~einhard::Green(), "✔ ", act);
1708 
1709  while (next_output_time() <= act->time_of_execution()) {
1710  log.debug("Propagating until output time: ", next_output_time());
1711  propagate_and_shine(next_output_time());
1712  ++(*parameters_.outputclock);
1713  intermediate_output();
1714  }
1715 
1716  /* (1) Propagate to the next action. */
1717  log.debug("Propagating until next action ", act,
1718  ", action time = ", act->time_of_execution());
1719  propagate_and_shine(act->time_of_execution());
1720 
1721  /* (2) Perform action.
1722  *
1723  * Update the positions of the incoming particles, because the information
1724  * in the action object will be outdated as the particles have been
1725  * propagated since the construction of the action. */
1726  act->update_incoming(particles_);
1727  const bool performed = perform_action(*act, particles_);
1728 
1729  /* No need to update actions for outgoing particles
1730  * if the action is not performed. */
1731  if (!performed) {
1732  continue;
1733  }
1734 
1735  /* (3) Update actions for newly-produced particles. */
1736 
1737  time_left = end_time - act->time_of_execution();
1738  const ParticleList &outgoing_particles = act->outgoing_particles();
1739  // Cell volume set to zero, since there is no grid
1740  const double cell_vol = 0.0;
1741  for (const auto &finder : action_finders_) {
1742  // Outgoing particles can still decay, cross walls...
1743  actions.insert(finder->find_actions_in_cell(outgoing_particles, time_left,
1744  cell_vol, beam_momentum_));
1745  // ... and collide with other particles.
1746  actions.insert(finder->find_actions_with_surrounding_particles(
1747  outgoing_particles, particles_, time_left, beam_momentum_));
1748  }
1749 
1750  check_interactions_total(interactions_total_);
1751  }
1752 
1753  while (next_output_time() <= end_time) {
1754  log.debug("Propagating until output time: ", next_output_time());
1755  propagate_and_shine(next_output_time());
1756  ++(*parameters_.outputclock);
1757  // Avoid duplicating printout at event end time
1758  if (parameters_.outputclock->current_time() < end_time_) {
1759  intermediate_output();
1760  }
1761  }
1762  log.debug("Propagating to time ", end_time);
1763  propagate_and_shine(end_time);
1764 }
1765 
1766 template <typename Modus>
1768  const auto &log = logger<LogArea::Experiment>();
1769  const uint64_t wall_actions_this_interval =
1770  wall_actions_total_ - previous_wall_actions_total_;
1771  previous_wall_actions_total_ = wall_actions_total_;
1772  const uint64_t interactions_this_interval = interactions_total_ -
1773  previous_interactions_total_ -
1774  wall_actions_this_interval;
1775  previous_interactions_total_ = interactions_total_;
1776  log.info() << format_measurements(particles_, interactions_this_interval,
1777  conserved_initial_, time_start_,
1778  parameters_.outputclock->current_time());
1779  const LatticeUpdate lat_upd = LatticeUpdate::AtOutput;
1780  // save evolution data
1781  for (const auto &output : outputs_) {
1782  if (output->is_dilepton_output() || output->is_photon_output() ||
1783  output->is_IC_output()) {
1784  continue;
1785  }
1786 
1787  output->at_intermediate_time(particles_, parameters_.outputclock,
1788  density_param_);
1789 
1790  // Thermodynamic output on the lattice versus time
1791  switch (dens_type_lattice_printout_) {
1792  case DensityType::Baryon:
1793  update_lattice(jmu_B_lat_.get(), lat_upd, DensityType::Baryon,
1794  density_param_, particles_, false);
1795  output->thermodynamics_output(ThermodynamicQuantity::EckartDensity,
1796  DensityType::Baryon, *jmu_B_lat_);
1797  break;
1798  case DensityType::BaryonicIsospin:
1799  update_lattice(jmu_I3_lat_.get(), lat_upd, DensityType::BaryonicIsospin,
1800  density_param_, particles_, false);
1801  output->thermodynamics_output(ThermodynamicQuantity::EckartDensity,
1802  DensityType::BaryonicIsospin,
1803  *jmu_I3_lat_);
1804  break;
1805  case DensityType::None:
1806  break;
1807  default:
1808  update_lattice(jmu_custom_lat_.get(), lat_upd,
1809  dens_type_lattice_printout_, density_param_, particles_,
1810  false);
1811  output->thermodynamics_output(ThermodynamicQuantity::EckartDensity,
1812  dens_type_lattice_printout_,
1813  *jmu_custom_lat_);
1814  }
1815  if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
1816  update_lattice(Tmn_.get(), lat_upd, dens_type_lattice_printout_,
1817  density_param_, particles_);
1818  if (printout_tmn_) {
1819  output->thermodynamics_output(ThermodynamicQuantity::Tmn,
1820  dens_type_lattice_printout_, *Tmn_);
1821  }
1822  if (printout_tmn_landau_) {
1823  output->thermodynamics_output(ThermodynamicQuantity::TmnLandau,
1824  dens_type_lattice_printout_, *Tmn_);
1825  }
1826  if (printout_v_landau_) {
1827  output->thermodynamics_output(ThermodynamicQuantity::LandauVelocity,
1828  dens_type_lattice_printout_, *Tmn_);
1829  }
1830  }
1831 
1832  if (thermalizer_) {
1833  output->thermodynamics_output(*thermalizer_);
1834  }
1835  }
1836 }
1837 
1838 template <typename Modus>
1840  if (potentials_) {
1841  if (potentials_->use_symmetry() && jmu_I3_lat_ != nullptr) {
1842  update_lattice(jmu_I3_lat_.get(), LatticeUpdate::EveryTimestep,
1843  DensityType::BaryonicIsospin, density_param_, particles_,
1844  true);
1845  }
1846  if ((potentials_->use_skyrme() || potentials_->use_symmetry()) &&
1847  jmu_B_lat_ != nullptr) {
1848  update_lattice(jmu_B_lat_.get(), LatticeUpdate::EveryTimestep,
1849  DensityType::Baryon, density_param_, particles_, true);
1850  const size_t UBlattice_size = UB_lat_->size();
1851  assert(UBlattice_size == UI3_lat_->size());
1852  for (size_t i = 0; i < UBlattice_size; i++) {
1853  auto jB = (*jmu_B_lat_)[i];
1854  const FourVector flow_four_velocity_B =
1855  std::abs(jB.density()) > really_small ? jB.jmu_net() / jB.density()
1856  : FourVector();
1857  double baryon_density = jB.density();
1858  ThreeVector baryon_grad_rho = jB.grad_rho();
1859  ThreeVector baryon_dj_dt = jB.dj_dt();
1860  ThreeVector baryon_rot_j = jB.rot_j();
1861  if (potentials_->use_skyrme()) {
1862  (*UB_lat_)[i] =
1863  flow_four_velocity_B * potentials_->skyrme_pot(baryon_density);
1864  (*FB_lat_)[i] = potentials_->skyrme_force(
1865  baryon_density, baryon_grad_rho, baryon_dj_dt, baryon_rot_j);
1866  }
1867  if (potentials_->use_symmetry() && jmu_I3_lat_ != nullptr) {
1868  auto jI3 = (*jmu_I3_lat_)[i];
1869  const FourVector flow_four_velocity_I3 =
1870  std::abs(jI3.density()) > really_small
1871  ? jI3.jmu_net() / jI3.density()
1872  : FourVector();
1873  (*UI3_lat_)[i] =
1874  flow_four_velocity_I3 *
1875  potentials_->symmetry_pot(jI3.density(), baryon_density);
1876  (*FI3_lat_)[i] = potentials_->symmetry_force(
1877  jI3.density(), jI3.grad_rho(), jI3.dj_dt(), jI3.rot_j(),
1878  baryon_density, baryon_grad_rho, baryon_dj_dt, baryon_rot_j);
1879  }
1880  }
1881  }
1882  }
1883 }
1884 
1885 template <typename Modus>
1887  /* At end of time evolution: Force all resonances to decay. In order to handle
1888  * decay chains, we need to loop until no further actions occur. */
1889  uint64_t interactions_old;
1890  const auto particles_before_actions = particles_.copy_to_vector();
1891  do {
1892  Actions actions;
1893 
1894  interactions_old = interactions_total_;
1895 
1896  // Dileptons: shining of remaining resonances
1897  if (dilepton_finder_ != nullptr) {
1898  for (const auto &output : outputs_) {
1899  dilepton_finder_->shine_final(particles_, output.get(), true);
1900  }
1901  }
1902  // Find actions.
1903  for (const auto &finder : action_finders_) {
1904  actions.insert(finder->find_final_actions(particles_));
1905  }
1906  // Perform actions.
1907  while (!actions.is_empty()) {
1908  perform_action(*actions.pop(), particles_before_actions);
1909  }
1910  // loop until no more decays occur
1911  } while (interactions_total_ > interactions_old);
1912 
1913  // Dileptons: shining of stable particles at the end
1914  if (dilepton_finder_ != nullptr) {
1915  for (const auto &output : outputs_) {
1916  dilepton_finder_->shine_final(particles_, output.get(), false);
1917  }
1918  }
1919 }
1920 
1921 template <typename Modus>
1922 void Experiment<Modus>::final_output(const int evt_num) {
1923  const auto &log = logger<LogArea::Experiment>();
1924  /* make sure the experiment actually ran (note: we should compare this
1925  * to the start time, but we don't know that. Therefore, we check that
1926  * the time is positive, which should heuristically be the same). */
1927  if (likely(parameters_.labclock > 0)) {
1928  const uint64_t wall_actions_this_interval =
1929  wall_actions_total_ - previous_wall_actions_total_;
1930  const uint64_t interactions_this_interval = interactions_total_ -
1931  previous_interactions_total_ -
1932  wall_actions_this_interval;
1933  log.info() << format_measurements(particles_, interactions_this_interval,
1934  conserved_initial_, time_start_,
1935  end_time_);
1936  if (IC_output_switch_ && (particles_.size() == 0)) {
1937  // Verify there is no more energy in the system if all particles were
1938  // removed when crossing the hypersurface
1939  const double remaining_energy =
1940  conserved_initial_.momentum().x0() - total_energy_removed_;
1941  if (remaining_energy > really_small) {
1942  throw std::runtime_error(
1943  "There is remaining energy in the system although all particles "
1944  "were removed.\n"
1945  "E_remain = " +
1946  std::to_string(remaining_energy) + " [GeV]");
1947  } else {
1948  log.info() << hline;
1949  log.info() << "Time real: " << SystemClock::now() - time_start_;
1950  log.info() << "Interactions before reaching hypersurface: "
1951  << interactions_total_ - wall_actions_total_ -
1952  total_hypersurface_crossing_actions_;
1953  log.info() << "Total number of particles removed on hypersurface: "
1954  << total_hypersurface_crossing_actions_;
1955  }
1956  } else {
1957  log.info() << hline;
1958  log.info() << "Time real: " << SystemClock::now() - time_start_;
1959  log.info() << "Final interaction number: "
1960  << interactions_total_ - wall_actions_total_;
1961  }
1962 
1963  // Check if there are unformed particles
1964  int unformed_particles_count = 0;
1965  for (const auto &particle : particles_) {
1966  if (particle.formation_time() > end_time_) {
1967  unformed_particles_count++;
1968  }
1969  }
1970  if (unformed_particles_count > 0) {
1971  log.warn("End time might be too small. ", unformed_particles_count,
1972  " unformed particles were found at the end of the evolution.");
1973  }
1974  }
1975 
1976  for (const auto &output : outputs_) {
1977  output->at_eventend(particles_, evt_num, modus_.impact_parameter(),
1978  !projectile_target_interact_);
1979  }
1980 }
1981 
1982 template <typename Modus>
1984  const auto &mainlog = logger<LogArea::Main>();
1985  for (int j = 0; j < nevents_; j++) {
1986  mainlog.info() << "Event " << j;
1987 
1988  // Sample initial particles, start clock, some printout and book-keeping
1989  initialize_new_event();
1990  /* In the ColliderModus, if the first collisions within the same nucleus are
1991  * forbidden, 'nucleon_has_interacted_', which records whether a nucleon has
1992  * collided with another nucleon, is initialized equal to false. If allowed,
1993  * 'nucleon_has_interacted' is initialized equal to true, which means these
1994  * incoming particles have experienced some fake scatterings, they can
1995  * therefore collide with each other later on since these collisions are not
1996  * "first" to them. */
1997  if (modus_.is_collider()) {
1998  if (!modus_.cll_in_nucleus()) {
1999  nucleon_has_interacted_.assign(modus_.total_N_number(), false);
2000  } else {
2001  nucleon_has_interacted_.assign(modus_.total_N_number(), true);
2002  }
2003  }
2004  /* In the ColliderModus, if Fermi motion is frozen, assign the beam momenta
2005  * to the nucleons in both the projectile and the target. */
2006  if (modus_.is_collider() && modus_.fermi_motion() == FermiMotion::Frozen) {
2007  for (int i = 0; i < modus_.total_N_number(); i++) {
2008  const auto mass_beam = particles_.copy_to_vector()[i].effective_mass();
2009  const auto v_beam = i < modus_.proj_N_number()
2010  ? modus_.velocity_projectile()
2011  : modus_.velocity_target();
2012  const auto gamma = 1.0 / std::sqrt(1.0 - v_beam * v_beam);
2013  beam_momentum_.emplace_back(FourVector(gamma * mass_beam, 0.0, 0.0,
2014  gamma * v_beam * mass_beam));
2015  }
2016  }
2017 
2018  // Output at event start
2019  for (const auto &output : outputs_) {
2020  output->at_eventstart(particles_, j);
2021  }
2022 
2023  run_time_evolution();
2024 
2025  if (force_decays_) {
2026  do_final_decays();
2027  }
2028 
2029  // Output at event end
2030  final_output(j);
2031  }
2032 }
2033 
2034 } // namespace smash
2035 
2036 #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:317
The main class, where the simulation of an experiment is executed.
Definition: experiment.h:135
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:340
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:1677
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
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:411
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:37
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:385
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:404
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:364
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:319
const TimeStepMode time_step_mode_
This indicates whether to use time steps.
Definition: experiment.h:482
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:295
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:111
Non-template interface to Experiment<Modus>.
Definition: experiment.h:84
ExperimentParameters create_experiment_parameters(Configuration config)
Gathers all general Experiment parameters.
Definition: experiment.cc:326
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:426
const bool force_decays_
This indicates whether we force all resonances to decay in the last timestep.
Definition: experiment.h:464
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:432
QuantumNumbers conserved_initial_
The conserved quantities of the system.
Definition: experiment.h:494
ThermalizationAction implements forced thermalization as an Action class.
ExperimentParameters parameters_
Struct of several member variables.
Definition: experiment.h:304
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:467
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:316
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:376
OutputPtr dilepton_output_
The Dilepton output.
Definition: experiment.h:337
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:765
const double end_time_
simulation time at which the evolution is stopped.
Definition: experiment.h:451
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:408
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:392
const bool IC_output_switch_
This indicates whether the IC output is enabled.
Definition: experiment.h:479
#define source_location
Hackery that is required to output the location in the source code where the log statement occurs...
Definition: logging.h:253
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:470
Exception class that is thrown if an invalid modus is requested from the Experiment factory...
Definition: experiment.h:129
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:290
const double delta_time_startup_
The clock&#39;s timestep size at start up.
Definition: experiment.h:458
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:473
std::unique_ptr< ActionFinderInterface > photon_finder_
The (Scatter) Actions Finder for Direct Photons.
Definition: experiment.h:367
std::unique_ptr< Potentials > potentials_
An instance of potentials class, that stores parameters of potentials, calculates them and their grad...
Definition: experiment.h:322
void add_dummy_hadronic_process(double reaction_cross_section)
Adds one hadronic process with a given cross-section.
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:476
std::ostream & operator<<(std::ostream &out, const Experiment< Modus > &e)
Creates a verbose textual description of the setup of the Experiment.
Definition: experiment.h:557
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:334
Modus modus_
Instance of the Modus template parameter.
Definition: experiment.h:313
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:220
std::vector< std::unique_ptr< ActionFinderInterface > > action_finders_
The Action finder objects.
Definition: experiment.h:361
DensityParameters density_param_
Structure to precalculate and hold parameters for density computations.
Definition: experiment.h:307
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:226
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:448
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:33
std::unique_ptr< PauliBlocker > pauli_blocker_
An instance of PauliBlocker class that stores parameters needed for Pauli blocking calculations and c...
Definition: experiment.h:328
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:373
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