Version: SMASH-2.0.2
experiment.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2020
3  * SMASH Team
4  *
5  * GNU General Public License (GPLv3 or later)
6  */
7 #ifndef SRC_INCLUDE_SMASH_EXPERIMENT_H_
8 #define SRC_INCLUDE_SMASH_EXPERIMENT_H_
9 
10 #include <algorithm>
11 #include <limits>
12 #include <memory>
13 #include <string>
14 #include <utility>
15 #include <vector>
16 
17 #include "actionfinderfactory.h"
18 #include "actions.h"
19 #include "bremsstrahlungaction.h"
20 #include "chrono.h"
21 #include "decayactionsfinder.h"
23 #include "energymomentumtensor.h"
24 #include "fourvector.h"
25 #include "grandcan_thermalizer.h"
26 #include "grid.h"
28 #include "outputparameters.h"
29 #include "pauliblocking.h"
30 #include "potential_globals.h"
31 #include "potentials.h"
32 #include "propagation.h"
33 #include "quantumnumbers.h"
34 #include "scatteractionphoton.h"
35 #include "scatteractionsfinder.h"
36 #include "stringprocess.h"
37 #include "thermalizationaction.h"
38 // Output
39 #include "binaryoutput.h"
40 #ifdef SMASH_USE_HEPMC
41 #include "hepmcoutput.h"
42 #endif
43 #ifdef SMASH_USE_RIVET
44 #include "rivetoutput.h"
45 #endif
46 #include "icoutput.h"
47 #include "oscaroutput.h"
48 #include "thermodynamicoutput.h"
49 #ifdef SMASH_USE_ROOT
50 #include "rootoutput.h"
51 #endif
52 #include "vtkoutput.h"
53 #include "wallcrossingaction.h"
54 
55 namespace std {
66 template <typename T, typename Ratio>
67 static ostream &operator<<(ostream &out,
68  const chrono::duration<T, Ratio> &seconds) {
69  using Seconds = chrono::duration<double>;
70  using Minutes = chrono::duration<double, std::ratio<60>>;
71  using Hours = chrono::duration<double, std::ratio<60 * 60>>;
72  constexpr Minutes threshold_for_minutes{10};
73  constexpr Hours threshold_for_hours{3};
74  if (seconds < threshold_for_minutes) {
75  return out << Seconds(seconds).count() << " [s]";
76  }
77  if (seconds < threshold_for_hours) {
78  return out << Minutes(seconds).count() << " [min]";
79  }
80  return out << Hours(seconds).count() << " [h]";
81 }
82 } // namespace std
83 
84 namespace smash {
85 static constexpr int LMain = LogArea::Main::id;
86 static constexpr int LInitialConditions = LogArea::InitialConditions::id;
87 
96  public:
97  ExperimentBase() = default;
102  virtual ~ExperimentBase() = default;
103 
124  static std::unique_ptr<ExperimentBase> create(Configuration config,
125  const bf::path &output_path);
126 
133  virtual void run() = 0;
134 
140  struct InvalidModusRequest : public std::invalid_argument {
141  using std::invalid_argument::invalid_argument;
142  };
143 };
144 
145 template <typename Modus>
147 template <typename Modus>
148 std::ostream &operator<<(std::ostream &out, const Experiment<Modus> &e);
149 
174 template <typename Modus>
175 class Experiment : public ExperimentBase {
176  friend class ExperimentBase;
177 
178  public:
185  void run() override;
186 
200  explicit Experiment(Configuration config, const bf::path &output_path);
201 
207  void initialize_new_event(int event_number);
208 
215  void run_time_evolution();
216 
218  void do_final_decays();
219 
225  void final_output(const int evt_num);
226 
232 
237  Modus *modus() { return &modus_; }
238 
248  int npart_projectile() const {
249  int np = 0;
250  for (size_t i = 0; i < this->modus_.proj_N_number(); i++)
251  np += nucleon_has_interacted_[i] ? 1 : 0;
252  return np;
253  }
254 
264  int npart_target() const {
265  int nt = 0;
266  for (size_t i = this->modus_.proj_N_number();
267  i < this->modus_.total_N_number(); i++)
268  nt += nucleon_has_interacted_[i] ? 1 : 0;
269  return nt;
270  }
274  }
275 
276  private:
288  template <typename Container>
289  bool perform_action(Action &action,
290  const Container &particles_before_actions);
299  void create_output(const std::string &format, const std::string &content,
300  const bf::path &output_path, const OutputParameters &par);
301 
308  void propagate_and_shine(double to_time);
309 
323 
325  void intermediate_output();
326 
328  void update_potentials();
329 
338  double compute_min_cell_length(double dt) const {
339  return std::sqrt(4 * dt * dt + max_transverse_distance_sqr_);
340  }
341 
343  double next_output_time() const {
344  return parameters_.outputclock->next_time();
345  }
346 
353 
356 
361  Modus modus_;
362 
365 
370  std::unique_ptr<Potentials> potentials_;
371 
376  std::unique_ptr<PauliBlocker> pauli_blocker_;
377 
382  OutputsList outputs_;
383 
385  OutputPtr dilepton_output_;
386 
388  OutputPtr photon_output_;
389 
395  std::vector<bool> nucleon_has_interacted_ = {};
400 
406  std::vector<FourVector> beam_momentum_ = {};
407 
409  std::vector<std::unique_ptr<ActionFinderInterface>> action_finders_;
410 
412  std::unique_ptr<DecayActionsFinderDilepton> dilepton_finder_;
413 
415  std::unique_ptr<ActionFinderInterface> photon_finder_;
416 
419 
421  std::unique_ptr<DensityLattice> jmu_B_lat_;
422 
424  std::unique_ptr<DensityLattice> jmu_I3_lat_;
425 
433  std::unique_ptr<DensityLattice> jmu_custom_lat_;
434 
437 
442  std::unique_ptr<RectangularLattice<FourVector>> UB_lat_ = nullptr;
443 
448  std::unique_ptr<RectangularLattice<FourVector>> UI3_lat_ = nullptr;
449 
451  std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
453 
455  std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
457 
459  std::unique_ptr<RectangularLattice<EnergyMomentumTensor>> Tmn_;
460 
462  bool printout_tmn_ = false;
463 
465  bool printout_tmn_landau_ = false;
466 
468  bool printout_v_landau_ = false;
469 
471  bool printout_lattice_td_ = false;
472 
474  std::unique_ptr<GrandCanThermalizer> thermalizer_;
475 
481 
496  const int nevents_;
497 
499  const double end_time_;
500 
506  const double delta_time_startup_;
507 
512  const bool force_decays_;
513 
515  const bool use_grid_;
516 
519 
521  const bool dileptons_switch_;
522 
524  const bool photons_switch_;
525 
528 
530  const bool IC_output_switch_;
531 
534 
536  double max_transverse_distance_sqr_ = std::numeric_limits<double>::max();
537 
546 
552 
554  SystemTimePoint time_start_ = SystemClock::now();
555 
558 
563  uint64_t interactions_total_ = 0;
564 
570 
575  uint64_t wall_actions_total_ = 0;
576 
582 
587  uint64_t total_pauli_blocked_ = 0;
588 
594 
600 
605  double total_energy_removed_ = 0.0;
606 
608  int64_t seed_ = -1;
609 
615  friend std::ostream &operator<<<>(std::ostream &out, const Experiment &e);
616 };
617 
619 template <typename Modus>
620 std::ostream &operator<<(std::ostream &out, const Experiment<Modus> &e) {
621  out << "End time: " << e.end_time_ << " fm/c\n";
622  out << e.modus_;
623  return out;
624 }
625 
626 template <typename Modus>
627 void Experiment<Modus>::create_output(const std::string &format,
628  const std::string &content,
629  const bf::path &output_path,
630  const OutputParameters &out_par) {
631  logg[LExperiment].info() << "Adding output " << content << " of format "
632  << format << std::endl;
633 
634  if (format == "VTK" && content == "Particles") {
635  outputs_.emplace_back(
636  make_unique<VtkOutput>(output_path, content, out_par));
637  } else if (format == "Root") {
638 #ifdef SMASH_USE_ROOT
639  if (content == "Initial_Conditions") {
640  outputs_.emplace_back(
641  make_unique<RootOutput>(output_path, "SMASH_IC", out_par));
642  } else {
643  outputs_.emplace_back(
644  make_unique<RootOutput>(output_path, content, out_par));
645  }
646 #else
647  logg[LExperiment].error(
648  "Root output requested, but Root support not compiled in");
649 #endif
650  } else if (format == "Binary") {
651  if (content == "Collisions" || content == "Dileptons" ||
652  content == "Photons") {
653  outputs_.emplace_back(
654  make_unique<BinaryOutputCollisions>(output_path, content, out_par));
655  } else if (content == "Particles") {
656  outputs_.emplace_back(
657  make_unique<BinaryOutputParticles>(output_path, content, out_par));
658  } else if (content == "Initial_Conditions") {
659  outputs_.emplace_back(make_unique<BinaryOutputInitialConditions>(
660  output_path, content, out_par));
661  }
662  } else if (format == "Oscar1999" || format == "Oscar2013") {
663  outputs_.emplace_back(
664  create_oscar_output(format, content, output_path, out_par));
665  } else if (content == "Thermodynamics" && format == "ASCII") {
666  outputs_.emplace_back(
667  make_unique<ThermodynamicOutput>(output_path, content, out_par));
668  } else if (content == "Thermodynamics" && format == "VTK") {
669  printout_lattice_td_ = true;
670  outputs_.emplace_back(
671  make_unique<VtkOutput>(output_path, content, out_par));
672  } else if (content == "Initial_Conditions" && format == "ASCII") {
673  outputs_.emplace_back(
674  make_unique<ICOutput>(output_path, "SMASH_IC", out_par));
675  } else if (format == "HepMC") {
676 #ifdef SMASH_USE_HEPMC
677  if (content == "Particles") {
678  outputs_.emplace_back(make_unique<HepMcOutput>(
679  output_path, "SMASH_HepMC_particles", false, modus_.total_N_number(),
680  modus_.proj_N_number()));
681  } else if (content == "Collisions") {
682  outputs_.emplace_back(make_unique<HepMcOutput>(
683  output_path, "SMASH_HepMC_collisions", true, modus_.total_N_number(),
684  modus_.proj_N_number()));
685  } else {
686  logg[LExperiment].error(
687  "HepMC only available for Particles and "
688  "Collisions content. Requested for " +
689  content + ".");
690  }
691 #else
692  logg[LExperiment].error(
693  "HepMC output requested, but HepMC support not compiled in");
694 #endif
695  } else if (content == "Rivet") {
696 #ifdef SMASH_USE_RIVET
697  // flag to ensure that the Rivet format has not been already assigned
698  static bool rivet_format_already_selected = false;
699  // if the next check is true, then we are trying to assign the format twice
700  if (rivet_format_already_selected) {
701  logg[LExperiment].warn(
702  "Rivet output format can only be one, either YODA or YODA-full. "
703  "Only your first valid choice will be used.");
704  return;
705  }
706  if (format == "YODA") {
707  outputs_.emplace_back(make_unique<RivetOutput>(
708  output_path, "SMASH_Rivet", false, modus_.total_N_number(),
709  modus_.proj_N_number(), out_par));
710  rivet_format_already_selected = true;
711  } else if (format == "YODA-full") {
712  outputs_.emplace_back(make_unique<RivetOutput>(
713  output_path, "SMASH_Rivet_full", true, modus_.total_N_number(),
714  modus_.proj_N_number(), out_par));
715  rivet_format_already_selected = true;
716  } else {
717  logg[LExperiment].error("Rivet format " + format +
718  "not one of YODA or YODA-full");
719  }
720 #else
721  logg[LExperiment].error(
722  "Rivet output requested, but Rivet support not compiled in");
723 #endif
724  } else {
725  logg[LExperiment].error()
726  << "Unknown combination of format (" << format << ") and content ("
727  << content << "). Fix the config.";
728  }
729 }
730 
739 
901 template <typename Modus>
902 Experiment<Modus>::Experiment(Configuration config, const bf::path &output_path)
903  : parameters_(create_experiment_parameters(config)),
904  density_param_(DensityParameters(parameters_)),
905  modus_(config["Modi"], parameters_),
906  particles_(),
907  nevents_(config.take({"General", "Nevents"})),
908  end_time_(config.take({"General", "End_Time"})),
909  delta_time_startup_(parameters_.labclock->timestep_duration()),
910  force_decays_(
911  config.take({"Collision_Term", "Force_Decays_At_End"}, true)),
912  use_grid_(config.take({"General", "Use_Grid"}, true)),
913  metric_(
914  config.take({"General", "Metric_Type"}, ExpansionMode::NoExpansion),
915  config.take({"General", "Expansion_Rate"}, 0.1)),
916  dileptons_switch_(
917  config.take({"Collision_Term", "Dileptons", "Decays"}, false)),
918  photons_switch_(config.take(
919  {"Collision_Term", "Photons", "2to2_Scatterings"}, false)),
920  bremsstrahlung_switch_(
921  config.take({"Collision_Term", "Photons", "Bremsstrahlung"}, false)),
922  IC_output_switch_(config.has_value({"Output", "Initial_Conditions"})),
923  time_step_mode_(
924  config.take({"General", "Time_Step_Mode"}, TimeStepMode::Fixed)) {
925  logg[LExperiment].info() << *this;
926 
927  if (parameters_.coll_crit == CollisionCriterion::Stochastic &&
928  time_step_mode_ != TimeStepMode::Fixed) {
929  throw std::invalid_argument(
930  "The stochastic criterion can only be employed for fixed time step "
931  "mode!");
932  }
933 
934  // create finders
935  if (dileptons_switch_) {
936  dilepton_finder_ = make_unique<DecayActionsFinderDilepton>();
937  }
938  if (photons_switch_ || bremsstrahlung_switch_) {
939  n_fractional_photons_ =
940  config.take({"Collision_Term", "Photons", "Fractional_Photons"}, 100);
941  }
942  if (parameters_.two_to_one) {
943  if (parameters_.res_lifetime_factor < 0.) {
944  throw std::invalid_argument(
945  "Resonance lifetime modifier cannot be negative!");
946  }
947  if (parameters_.res_lifetime_factor < really_small) {
948  logg[LExperiment].warn(
949  "Resonance lifetime set to zero. Make sure resonances cannot "
950  "interact",
951  "inelastically (e.g. resonance chains), else SMASH is known to "
952  "hang.");
953  }
954  action_finders_.emplace_back(
955  make_unique<DecayActionsFinder>(parameters_.res_lifetime_factor));
956  }
957  bool no_coll = config.take({"Collision_Term", "No_Collisions"}, false);
958  if ((parameters_.two_to_one || parameters_.included_2to2.any() ||
959  parameters_.included_multi.any() || parameters_.strings_switch) &&
960  !no_coll) {
961  auto scat_finder = make_unique<ScatterActionsFinder>(
962  config, parameters_, nucleon_has_interacted_, modus_.total_N_number(),
963  modus_.proj_N_number());
964  max_transverse_distance_sqr_ =
965  scat_finder->max_transverse_distance_sqr(parameters_.testparticles);
966  process_string_ptr_ = scat_finder->get_process_string_ptr();
967  action_finders_.emplace_back(std::move(scat_finder));
968  } else {
969  max_transverse_distance_sqr_ =
970  parameters_.maximum_cross_section / M_PI * fm2_mb;
971  process_string_ptr_ = NULL;
972  }
973  if (modus_.is_box()) {
974  action_finders_.emplace_back(
975  make_unique<WallCrossActionsFinder>(parameters_.box_length));
976  }
977  if (IC_output_switch_) {
978  if (!modus_.is_collider()) {
979  throw std::runtime_error(
980  "Initial conditions can only be extracted in collider modus.");
981  }
982  double proper_time;
983  if (config.has_value({"Output", "Initial_Conditions", "Proper_Time"})) {
984  // Read in proper time from config
985  proper_time =
986  config.take({"Output", "Initial_Conditions", "Proper_Time"});
987  } else {
988  // Default proper time is the passing time of the two nuclei
989  double default_proper_time = modus_.nuclei_passing_time();
990  double lower_bound =
991  config.take({"Output", "Initial_Conditions", "Lower_Bound"}, 0.5);
992  if (default_proper_time >= lower_bound) {
993  proper_time = default_proper_time;
994  } else {
995  logg[LInitialConditions].warn()
996  << "Nuclei passing time is too short, hypersurface proper time set "
997  "to tau = "
998  << lower_bound << " fm.";
999  proper_time = lower_bound;
1000  }
1001  }
1002  action_finders_.emplace_back(
1003  make_unique<HyperSurfaceCrossActionsFinder>(proper_time));
1004  }
1005 
1006  if (config.has_value({"Collision_Term", "Pauli_Blocking"})) {
1007  logg[LExperiment].info() << "Pauli blocking is ON.";
1008  pauli_blocker_ = make_unique<PauliBlocker>(
1009  config["Collision_Term"]["Pauli_Blocking"], parameters_);
1010  }
1011  // In collider setup with sqrts >= 200 GeV particles don't form continuously
1013  config.take({"Collision_Term", "Power_Particle_Formation"},
1014  modus_.sqrt_s_NN() >= 200. ? -1. : 1.);
1015 
1048  // create outputs
1050  " create OutputInterface objects");
1051 
1052  auto output_conf = config["Output"];
1278  dens_type_ = config.take({"Output", "Density_Type"}, DensityType::None);
1279  logg[LExperiment].debug()
1280  << "Density type printed to headers: " << dens_type_;
1281 
1282  const OutputParameters output_parameters(std::move(output_conf));
1283 
1284  std::vector<std::string> output_contents = output_conf.list_upmost_nodes();
1285  for (const auto &content : output_contents) {
1286  auto this_output_conf = output_conf[content.c_str()];
1287  const std::vector<std::string> formats = this_output_conf.take({"Format"});
1288  if (output_path == "") {
1289  continue;
1290  }
1291  for (const auto &format : formats) {
1292  create_output(format, content, output_path, output_parameters);
1293  }
1294  }
1295 
1296  /* We can take away the Fermi motion flag, because the collider modus is
1297  * already initialized. We only need it when potentials are enabled, but we
1298  * always have to take it, otherwise SMASH will complain about unused
1299  * options. We have to provide a default value for modi other than Collider.
1300  */
1301  const FermiMotion motion =
1302  config.take({"Modi", "Collider", "Fermi_Motion"}, FermiMotion::Off);
1303  if (config.has_value({"Potentials"})) {
1304  if (time_step_mode_ == TimeStepMode::None) {
1305  logg[LExperiment].error() << "Potentials only work with time steps!";
1306  throw std::invalid_argument("Can't use potentials without time steps!");
1307  }
1308  if (motion == FermiMotion::Frozen) {
1309  logg[LExperiment].error()
1310  << "Potentials don't work with frozen Fermi momenta! "
1311  "Use normal Fermi motion instead.";
1312  throw std::invalid_argument(
1313  "Can't use potentials "
1314  "with frozen Fermi momenta!");
1315  }
1316  logg[LExperiment].info() << "Potentials are ON. Timestep is "
1317  << parameters_.labclock->timestep_duration();
1318  // potentials need testparticles and gaussian sigma from parameters_
1319  potentials_ = make_unique<Potentials>(config["Potentials"], parameters_);
1320  }
1321 
1377  // Create lattices
1378  if (config.has_value({"Lattice"})) {
1379  // Take lattice properties from config to assign them to all lattices
1380  const std::array<double, 3> l = config.take({"Lattice", "Sizes"});
1381  const std::array<int, 3> n = config.take({"Lattice", "Cell_Number"});
1382  const std::array<double, 3> origin = config.take({"Lattice", "Origin"});
1383  const bool periodic = config.take({"Lattice", "Periodic"});
1384 
1385  if (printout_lattice_td_) {
1386  dens_type_lattice_printout_ = output_parameters.td_dens_type;
1387  printout_tmn_ = output_parameters.td_tmn;
1388  printout_tmn_landau_ = output_parameters.td_tmn_landau;
1389  printout_v_landau_ = output_parameters.td_v_landau;
1390  }
1391  if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
1392  Tmn_ = make_unique<RectangularLattice<EnergyMomentumTensor>>(
1393  l, n, origin, periodic, LatticeUpdate::AtOutput);
1394  }
1395  /* Create baryon and isospin density lattices regardless of config
1396  if potentials are on. This is because they allow to compute
1397  potentials faster */
1398  if (potentials_) {
1399  if (potentials_->use_skyrme()) {
1400  jmu_B_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1402  UB_lat_ = make_unique<RectangularLattice<FourVector>>(
1403  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1404  FB_lat_ = make_unique<
1405  RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1406  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1407  }
1408  if (potentials_->use_symmetry()) {
1409  jmu_I3_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1411  UI3_lat_ = make_unique<RectangularLattice<FourVector>>(
1412  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1413  FI3_lat_ = make_unique<
1414  RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1415  l, n, origin, periodic, LatticeUpdate::EveryTimestep);
1416  }
1417  } else {
1418  if (dens_type_lattice_printout_ == DensityType::Baryon) {
1419  jmu_B_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1421  }
1422  if (dens_type_lattice_printout_ == DensityType::BaryonicIsospin) {
1423  jmu_I3_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1425  }
1426  }
1427  if (dens_type_lattice_printout_ != DensityType::None &&
1428  dens_type_lattice_printout_ != DensityType::BaryonicIsospin &&
1429  dens_type_lattice_printout_ != DensityType::Baryon) {
1430  jmu_custom_lat_ = make_unique<DensityLattice>(l, n, origin, periodic,
1432  }
1433  } else if (printout_lattice_td_) {
1434  logg[LExperiment].error(
1435  "If you want Thermodynamic VTK output, configure a lattice for it.");
1436  }
1437  // Warning for the mean field calculation if lattice is not on.
1438  if ((potentials_ != nullptr) && (jmu_B_lat_ == nullptr)) {
1439  logg[LExperiment].warn() << "Lattice is NOT used. Mean fields are "
1440  << "not going to be calculated.";
1441  }
1442 
1443  // Store pointers to potential and lattice accessible for Action
1444  if (parameters_.potential_affect_threshold) {
1445  UB_lat_pointer = UB_lat_.get();
1446  UI3_lat_pointer = UI3_lat_.get();
1447  pot_pointer = potentials_.get();
1448  }
1449 
1450  // Create forced thermalizer
1451  if (config.has_value({"Forced_Thermalization"})) {
1452  Configuration &&th_conf = config["Forced_Thermalization"];
1453  thermalizer_ = modus_.create_grandcan_thermalizer(th_conf);
1454  }
1455 
1456  /* Take the seed setting only after the configuration was stored to a file
1457  * in smash.cc */
1458  seed_ = config.take({"General", "Randomseed"});
1459 }
1460 
1462 const std::string hline(113, '-');
1463 
1489 std::string format_measurements(const Particles &particles,
1490  uint64_t scatterings_this_interval,
1491  const QuantumNumbers &conserved_initial,
1492  SystemTimePoint time_start, double time,
1493  double E_mean_field,
1494  double E_mean_field_initial);
1508  const Potentials &potentials,
1509  RectangularLattice<smash::DensityOnLattice> &jmu_B_lat,
1510  const ExperimentParameters &parameters);
1511 
1527 EventInfo fill_event_info(const Particles &particles, double E_mean_field,
1528  double modus_impact_parameter,
1529  const ExperimentParameters &parameters,
1530  bool projectile_target_interact);
1531 
1532 template <typename Modus>
1534  random::set_seed(seed_);
1535  logg[LExperiment].info() << "random number seed: " << seed_;
1536  /* Set seed for the next event. It has to be positive, so it can be entered
1537  * in the config.
1538  *
1539  * We have to be careful about the minimal integer, whose absolute value
1540  * cannot be represented. */
1541  int64_t r = random::advance();
1542  while (r == INT64_MIN) {
1543  r = random::advance();
1544  }
1545  seed_ = std::abs(r);
1546  /* Set the random seed used in PYTHIA hadronization
1547  * to be same with the SMASH one.
1548  * In this way we ensure that the results are reproducible
1549  * for every event if one knows SMASH random seed. */
1550  if (process_string_ptr_ != NULL) {
1551  process_string_ptr_->init_pythia_hadron_rndm();
1552  }
1553 
1554  particles_.reset();
1555  // make sure this is initialized
1556  if (modus_.is_collider()) {
1557  nucleon_has_interacted_.assign(modus_.total_N_number(), false);
1558  }
1559 
1560  // Sample particles according to the initial conditions
1561  double start_time = modus_.initial_conditions(&particles_, parameters_);
1562  /* For box modus make sure that particles are in the box. In principle, after
1563  * a correct initialization they should be, so this is just playing it safe.
1564  */
1565  modus_.impose_boundary_conditions(&particles_, outputs_);
1566  // Reset the simulation clock
1567  double timestep = delta_time_startup_;
1568 
1569  switch (time_step_mode_) {
1570  case TimeStepMode::Fixed:
1571  break;
1572  case TimeStepMode::None:
1573  timestep = end_time_ - start_time;
1574  // Take care of the box modus + timestepless propagation
1575  const double max_dt = modus_.max_timestep(max_transverse_distance_sqr_);
1576  if (max_dt > 0. && max_dt < timestep) {
1577  timestep = max_dt;
1578  }
1579  break;
1580  }
1581  std::unique_ptr<UniformClock> clock_for_this_event;
1582  if (modus_.is_list() && (timestep < 0.0)) {
1583  throw std::runtime_error(
1584  "Timestep for the given event is negative. \n"
1585  "This might happen if the formation times of the input particles are "
1586  "larger than the specified end time of the simulation.");
1587  }
1588  clock_for_this_event = make_unique<UniformClock>(start_time, timestep);
1589  parameters_.labclock = std::move(clock_for_this_event);
1590 
1591  // Reset the output clock
1592  parameters_.outputclock->reset(start_time, true);
1593  // remove time before starting time in case of custom output times.
1594  parameters_.outputclock->remove_times_in_past(start_time);
1595 
1596  logg[LExperiment].debug(
1597  "Lab clock: t_start = ", parameters_.labclock->current_time(),
1598  ", dt = ", parameters_.labclock->timestep_duration());
1599 
1600  /* Save the initial conserved quantum numbers and total momentum in
1601  * the system for conservation checks */
1602  conserved_initial_ = QuantumNumbers(particles_);
1603  wall_actions_total_ = 0;
1604  previous_wall_actions_total_ = 0;
1605  interactions_total_ = 0;
1606  previous_interactions_total_ = 0;
1607  discarded_interactions_total_ = 0;
1608  total_pauli_blocked_ = 0;
1609  projectile_target_interact_ = false;
1610  total_hypersurface_crossing_actions_ = 0;
1611  total_energy_removed_ = 0.0;
1612  // Print output headers
1613  logg[LExperiment].info() << hline;
1614  logg[LExperiment].info() << "Time[fm] Ekin[GeV] E_MF[GeV] ETotal[GeV] "
1615  << "ETot/N[GeV] D(ETot/N)[GeV] Scatt&Decays "
1616  << "Particles Comp.Time";
1617  logg[LExperiment].info() << hline;
1618  double E_mean_field = 0.0;
1619  if (potentials_) {
1620  update_potentials();
1621  // using the lattice is necessary
1622  if ((jmu_B_lat_ != nullptr)) {
1623  E_mean_field =
1624  calculate_mean_field_energy(*potentials_, *jmu_B_lat_, parameters_);
1625  }
1626  }
1627  initial_mean_field_energy_ = E_mean_field;
1629  particles_, 0u, conserved_initial_, time_start_,
1630  parameters_.labclock->current_time(), E_mean_field,
1631  initial_mean_field_energy_);
1632 
1633  auto event_info =
1634  fill_event_info(particles_, E_mean_field, modus_.impact_parameter(),
1635  parameters_, projectile_target_interact_);
1636 
1637  // Output at event start
1638  for (const auto &output : outputs_) {
1639  output->at_eventstart(particles_, event_number, event_info);
1640  }
1641 }
1642 
1643 template <typename Modus>
1644 template <typename Container>
1646  Action &action, const Container &particles_before_actions) {
1647  // Make sure to skip invalid and Pauli-blocked actions.
1648  if (!action.is_valid(particles_)) {
1649  discarded_interactions_total_++;
1650  logg[LExperiment].debug(~einhard::DRed(), "✘ ", action,
1651  " (discarded: invalid)");
1652  return false;
1653  }
1654  action.generate_final_state();
1655  logg[LExperiment].debug("Process Type is: ", action.get_type());
1656  if (pauli_blocker_ && action.is_pauli_blocked(particles_, *pauli_blocker_)) {
1657  total_pauli_blocked_++;
1658  return false;
1659  }
1660  if (modus_.is_collider()) {
1661  /* Mark incoming nucleons as interacted - now they are permitted
1662  * to collide with nucleons from their native nucleus */
1663  bool incoming_projectile = false;
1664  bool incoming_target = false;
1665  for (const auto &incoming : action.incoming_particles()) {
1666  assert(incoming.id() >= 0);
1667  if (incoming.id() < modus_.total_N_number()) {
1668  nucleon_has_interacted_[incoming.id()] = true;
1669  }
1670  if (incoming.id() < modus_.proj_N_number()) {
1671  incoming_projectile = true;
1672  }
1673  if (incoming.id() >= modus_.proj_N_number() &&
1674  incoming.id() < modus_.total_N_number()) {
1675  incoming_target = true;
1676  }
1677  }
1678  // Check whether particles from different nuclei interacted.
1679  if (incoming_projectile & incoming_target) {
1680  projectile_target_interact_ = true;
1681  }
1682  }
1683  /* Make sure to pick a non-zero integer, because 0 is reserved for "no
1684  * interaction yet". */
1685  const auto id_process = static_cast<uint32_t>(interactions_total_ + 1);
1686  action.perform(&particles_, id_process);
1687  interactions_total_++;
1688  if (action.get_type() == ProcessType::Wall) {
1689  wall_actions_total_++;
1690  }
1691  if (action.get_type() == ProcessType::HyperSurfaceCrossing) {
1692  total_hypersurface_crossing_actions_++;
1693  total_energy_removed_ += action.incoming_particles()[0].momentum().x0();
1694  }
1695  // Calculate Eckart rest frame density at the interaction point
1696  double rho = 0.0;
1697  if (dens_type_ != DensityType::None) {
1698  const FourVector r_interaction = action.get_interaction_point();
1699  constexpr bool compute_grad = false;
1700  const bool smearing = true;
1701  rho = std::get<0>(current_eckart(r_interaction.threevec(),
1702  particles_before_actions, density_param_,
1703  dens_type_, compute_grad, smearing));
1704  }
1720  for (const auto &output : outputs_) {
1721  if (!output->is_dilepton_output() && !output->is_photon_output()) {
1722  if (output->is_IC_output() &&
1724  output->at_interaction(action, rho);
1725  } else if (!output->is_IC_output()) {
1726  output->at_interaction(action, rho);
1727  }
1728  }
1729  }
1730 
1731  // At every collision photons can be produced.
1732  // Note: We rely here on the lazy evaluation of the arguments to if.
1733  // It may happen that in a wall-crossing-action sqrt_s raises an exception.
1734  // Therefore we first have to check if the incoming particles can undergo
1735  // an em-interaction.
1736  if (photons_switch_ &&
1739  action.sqrt_s(), action.incoming_particles())) {
1740  /* Time in the action constructor is relative to
1741  * current time of incoming */
1742  constexpr double action_time = 0.;
1743  ScatterActionPhoton photon_act(action.incoming_particles(), action_time,
1744  n_fractional_photons_,
1745  action.get_total_weight());
1746 
1757  photon_act.add_dummy_hadronic_process(action.get_total_weight());
1758 
1759  // Now add the actual photon reaction channel.
1760  photon_act.add_single_process();
1761 
1762  photon_act.perform_photons(outputs_);
1763  }
1764 
1765  if (bremsstrahlung_switch_ &&
1767  action.incoming_particles())) {
1768  /* Time in the action constructor is relative to
1769  * current time of incoming */
1770  constexpr double action_time = 0.;
1771 
1772  BremsstrahlungAction brems_act(action.incoming_particles(), action_time,
1773  n_fractional_photons_,
1774  action.get_total_weight());
1775 
1787  brems_act.add_dummy_hadronic_process(action.get_total_weight());
1788 
1789  // Now add the actual bremsstrahlung reaction channel.
1790  brems_act.add_single_process();
1791 
1792  brems_act.perform_bremsstrahlung(outputs_);
1793  }
1794 
1795  logg[LExperiment].debug(~einhard::Green(), "✔ ", action);
1796  return true;
1797 }
1798 
1799 template <typename Modus>
1801  Actions actions;
1802 
1803  while (parameters_.labclock->current_time() < end_time_) {
1804  const double t = parameters_.labclock->current_time();
1805  const double dt =
1806  std::min(parameters_.labclock->timestep_duration(), end_time_ - t);
1807  logg[LExperiment].debug("Timestepless propagation for next ", dt, " fm/c.");
1808 
1809  // Perform forced thermalization if required
1810  if (thermalizer_ &&
1811  thermalizer_->is_time_to_thermalize(parameters_.labclock)) {
1812  const bool ignore_cells_under_treshold = true;
1813  thermalizer_->update_thermalizer_lattice(particles_, density_param_,
1814  ignore_cells_under_treshold);
1815  const double current_t = parameters_.labclock->current_time();
1816  thermalizer_->thermalize(particles_, current_t,
1817  parameters_.testparticles);
1818  ThermalizationAction th_act(*thermalizer_, current_t);
1819  if (th_act.any_particles_thermalized()) {
1820  perform_action(th_act, particles_);
1821  }
1822  }
1823 
1824  if (particles_.size() > 0 && action_finders_.size() > 0) {
1825  /* (1.a) Create grid. */
1826  double min_cell_length = compute_min_cell_length(dt);
1827  logg[LExperiment].debug("Creating grid with minimal cell length ",
1828  min_cell_length);
1829  const auto &grid =
1830  use_grid_ ? modus_.create_grid(particles_, min_cell_length, dt)
1831  : modus_.create_grid(particles_, min_cell_length, dt,
1833 
1834  const double gcell_vol = grid.cell_volume();
1835 
1836  /* (1.b) Iterate over cells and find actions. */
1837  grid.iterate_cells(
1838  [&](const ParticleList &search_list) {
1839  for (const auto &finder : action_finders_) {
1840  actions.insert(finder->find_actions_in_cell(
1841  search_list, dt, gcell_vol, beam_momentum_));
1842  }
1843  },
1844  [&](const ParticleList &search_list,
1845  const ParticleList &neighbors_list) {
1846  for (const auto &finder : action_finders_) {
1847  actions.insert(finder->find_actions_with_neighbors(
1848  search_list, neighbors_list, dt, beam_momentum_));
1849  }
1850  });
1851  }
1852 
1853  /* \todo (optimizations) Adapt timestep size here */
1854 
1855  /* (2) Propagation from action to action until the end of timestep */
1856  run_time_evolution_timestepless(actions);
1857 
1858  /* (3) Update potentials (if computed on the lattice) and
1859  * compute new momenta according to equations of motion */
1860  if (potentials_) {
1861  update_potentials();
1862  update_momenta(&particles_, parameters_.labclock->timestep_duration(),
1863  *potentials_, FB_lat_.get(), FI3_lat_.get());
1864  }
1865 
1866  /* (4) Expand universe if non-minkowskian metric; updates
1867  * positions and momenta according to the selected expansion */
1868  if (metric_.mode_ != ExpansionMode::NoExpansion) {
1869  expand_space_time(&particles_, parameters_, metric_);
1870  }
1871 
1872  ++(*parameters_.labclock);
1873 
1874  /* (5) Check conservation laws.
1875  *
1876  * Check conservation of conserved quantities if potentials and string
1877  * fragmentation are off. If potentials are on then momentum is conserved
1878  * only in average. If string fragmentation is on, then energy and
1879  * momentum are only very roughly conserved in high-energy collisions. */
1880  if (!potentials_ && !parameters_.strings_switch &&
1881  metric_.mode_ == ExpansionMode::NoExpansion && !IC_output_switch_) {
1882  std::string err_msg = conserved_initial_.report_deviations(particles_);
1883  if (!err_msg.empty()) {
1884  logg[LExperiment].error() << err_msg;
1885  throw std::runtime_error("Violation of conserved quantities!");
1886  }
1887  }
1888  }
1889 
1890  if (pauli_blocker_) {
1891  logg[LExperiment].info(
1892  "Interactions: Pauli-blocked/performed = ", total_pauli_blocked_, "/",
1893  interactions_total_ - wall_actions_total_);
1894  }
1895 }
1896 
1897 template <typename Modus>
1899  const double dt =
1900  propagate_straight_line(&particles_, to_time, beam_momentum_);
1901  if (dilepton_finder_ != nullptr) {
1902  for (const auto &output : outputs_) {
1903  dilepton_finder_->shine(particles_, output.get(), dt);
1904  }
1905  }
1906 }
1907 
1915 inline void check_interactions_total(uint64_t interactions_total) {
1916  constexpr uint64_t max_uint32 = std::numeric_limits<uint32_t>::max();
1917  if (interactions_total >= max_uint32) {
1918  throw std::runtime_error("Integer overflow in total interaction number!");
1919  }
1920 }
1921 
1922 template <typename Modus>
1924  const double start_time = parameters_.labclock->current_time();
1925  const double end_time =
1926  std::min(parameters_.labclock->next_time(), end_time_);
1927  double time_left = end_time - start_time;
1928  logg[LExperiment].debug(
1929  "Timestepless propagation: ", "Actions size = ", actions.size(),
1930  ", start time = ", start_time, ", end time = ", end_time);
1931 
1932  // iterate over all actions
1933  while (!actions.is_empty()) {
1934  // get next action
1935  ActionPtr act = actions.pop();
1936  if (!act->is_valid(particles_)) {
1937  discarded_interactions_total_++;
1938  logg[LExperiment].debug(~einhard::DRed(), "✘ ", act,
1939  " (discarded: invalid)");
1940  continue;
1941  }
1942  if (act->time_of_execution() > end_time) {
1943  logg[LExperiment].error(
1944  act, " scheduled later than end time: t_action[fm/c] = ",
1945  act->time_of_execution(), ", t_end[fm/c] = ", end_time);
1946  }
1947  logg[LExperiment].debug(~einhard::Green(), "✔ ", act);
1948 
1949  while (next_output_time() <= act->time_of_execution()) {
1950  logg[LExperiment].debug("Propagating until output time: ",
1951  next_output_time());
1952  propagate_and_shine(next_output_time());
1953  ++(*parameters_.outputclock);
1954  intermediate_output();
1955  }
1956 
1957  /* (1) Propagate to the next action. */
1958  logg[LExperiment].debug("Propagating until next action ", act,
1959  ", action time = ", act->time_of_execution());
1960  propagate_and_shine(act->time_of_execution());
1961 
1962  /* (2) Perform action.
1963  *
1964  * Update the positions of the incoming particles, because the information
1965  * in the action object will be outdated as the particles have been
1966  * propagated since the construction of the action. */
1967  act->update_incoming(particles_);
1968  const bool performed = perform_action(*act, particles_);
1969 
1970  /* No need to update actions for outgoing particles
1971  * if the action is not performed. */
1972  if (!performed) {
1973  continue;
1974  }
1975 
1976  /* (3) Update actions for newly-produced particles. */
1977 
1978  time_left = end_time - act->time_of_execution();
1979  const ParticleList &outgoing_particles = act->outgoing_particles();
1980  // Grid cell volume set to zero, since there is no grid
1981  const double gcell_vol = 0.0;
1982  for (const auto &finder : action_finders_) {
1983  // Outgoing particles can still decay, cross walls...
1984  actions.insert(finder->find_actions_in_cell(outgoing_particles, time_left,
1985  gcell_vol, beam_momentum_));
1986  // ... and collide with other particles.
1987  actions.insert(finder->find_actions_with_surrounding_particles(
1988  outgoing_particles, particles_, time_left, beam_momentum_));
1989  }
1990 
1991  check_interactions_total(interactions_total_);
1992  }
1993 
1994  while (next_output_time() <= end_time) {
1995  logg[LExperiment].debug("Propagating until output time: ",
1996  next_output_time());
1997  propagate_and_shine(next_output_time());
1998  ++(*parameters_.outputclock);
1999  // Avoid duplicating printout at event end time
2000  if (parameters_.outputclock->current_time() < end_time_) {
2001  intermediate_output();
2002  }
2003  }
2004  logg[LExperiment].debug("Propagating to time ", end_time);
2005  propagate_and_shine(end_time);
2006 }
2007 
2008 template <typename Modus>
2010  const uint64_t wall_actions_this_interval =
2011  wall_actions_total_ - previous_wall_actions_total_;
2012  previous_wall_actions_total_ = wall_actions_total_;
2013  const uint64_t interactions_this_interval = interactions_total_ -
2014  previous_interactions_total_ -
2015  wall_actions_this_interval;
2016  previous_interactions_total_ = interactions_total_;
2017  double E_mean_field = 0.0;
2018  if (potentials_) {
2019  // using the lattice is necessary
2020  if ((jmu_B_lat_ != nullptr)) {
2021  E_mean_field =
2022  calculate_mean_field_energy(*potentials_, *jmu_B_lat_, parameters_);
2023  /*
2024  * Mean field calculated in a box should remain approximately constant if
2025  * the system is in equilibrium, and so deviations from its original value
2026  * may signal a phase transition or other dynamical process. This
2027  * comparison only makes sense in the Box Modus, hence the condition.
2028  */
2029  if (modus_.is_box()) {
2030  double tmp = (E_mean_field - initial_mean_field_energy_) /
2031  (E_mean_field + initial_mean_field_energy_);
2032  /*
2033  * This is displayed when the system evolves away from its initial
2034  * configuration (which is when the total mean field energy in the box
2035  * deviates from its initial value).
2036  */
2037  if (std::abs(tmp) > 0.01) {
2038  logg[LExperiment].info()
2039  << "\n\n\n\t The mean field at t = "
2040  << parameters_.outputclock->current_time()
2041  << " [fm/c] differs from the mean field at t = 0:"
2042  << "\n\t\t initial_mean_field_energy_ = "
2043  << initial_mean_field_energy_ << " [GeV]"
2044  << "\n\t\t abs[(E_MF - E_MF(t=0))/(E_MF + E_MF(t=0))] = "
2045  << std::abs(tmp)
2046  << "\n\t\t E_MF/E_MF(t=0) = "
2047  << E_mean_field / initial_mean_field_energy_ << "\n\n";
2048  }
2049  }
2050  }
2051  }
2052 
2054  particles_, interactions_this_interval, conserved_initial_, time_start_,
2055  parameters_.outputclock->current_time(), E_mean_field,
2056  initial_mean_field_energy_);
2057  const LatticeUpdate lat_upd = LatticeUpdate::AtOutput;
2058 
2059  auto event_info =
2060  fill_event_info(particles_, E_mean_field, modus_.impact_parameter(),
2061  parameters_, projectile_target_interact_);
2062  // save evolution data
2063  if (!(modus_.is_box() && parameters_.outputclock->current_time() <
2064  modus_.equilibration_time())) {
2065  for (const auto &output : outputs_) {
2066  if (output->is_dilepton_output() || output->is_photon_output() ||
2067  output->is_IC_output()) {
2068  continue;
2069  }
2070 
2071  output->at_intermediate_time(particles_, parameters_.outputclock,
2072  density_param_, event_info);
2073 
2074  // Thermodynamic output on the lattice versus time
2075  switch (dens_type_lattice_printout_) {
2076  case DensityType::Baryon:
2077  update_lattice(jmu_B_lat_.get(), lat_upd, DensityType::Baryon,
2078  density_param_, particles_, false);
2079  output->thermodynamics_output(ThermodynamicQuantity::EckartDensity,
2080  DensityType::Baryon, *jmu_B_lat_);
2081  break;
2083  update_lattice(jmu_I3_lat_.get(), lat_upd,
2084  DensityType::BaryonicIsospin, density_param_,
2085  particles_, false);
2086  output->thermodynamics_output(ThermodynamicQuantity::EckartDensity,
2088  *jmu_I3_lat_);
2089  break;
2090  case DensityType::None:
2091  break;
2092  default:
2093  update_lattice(jmu_custom_lat_.get(), lat_upd,
2094  dens_type_lattice_printout_, density_param_,
2095  particles_, false);
2096  output->thermodynamics_output(ThermodynamicQuantity::EckartDensity,
2097  dens_type_lattice_printout_,
2098  *jmu_custom_lat_);
2099  }
2100  if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
2101  update_lattice(Tmn_.get(), lat_upd, dens_type_lattice_printout_,
2102  density_param_, particles_);
2103  if (printout_tmn_) {
2104  output->thermodynamics_output(ThermodynamicQuantity::Tmn,
2105  dens_type_lattice_printout_, *Tmn_);
2106  }
2107  if (printout_tmn_landau_) {
2108  output->thermodynamics_output(ThermodynamicQuantity::TmnLandau,
2109  dens_type_lattice_printout_, *Tmn_);
2110  }
2111  if (printout_v_landau_) {
2112  output->thermodynamics_output(ThermodynamicQuantity::LandauVelocity,
2113  dens_type_lattice_printout_, *Tmn_);
2114  }
2115  }
2116 
2117  if (thermalizer_) {
2118  output->thermodynamics_output(*thermalizer_);
2119  }
2120  }
2121  }
2122 }
2123 
2124 template <typename Modus>
2126  if (potentials_) {
2127  if (potentials_->use_symmetry() && jmu_I3_lat_ != nullptr) {
2128  update_lattice(jmu_I3_lat_.get(), LatticeUpdate::EveryTimestep,
2129  DensityType::BaryonicIsospin, density_param_, particles_,
2130  true);
2131  }
2132  if ((potentials_->use_skyrme() || potentials_->use_symmetry()) &&
2133  jmu_B_lat_ != nullptr) {
2134  update_lattice(jmu_B_lat_.get(), LatticeUpdate::EveryTimestep,
2135  DensityType::Baryon, density_param_, particles_, true);
2136  const size_t UBlattice_size = UB_lat_->size();
2137  for (size_t i = 0; i < UBlattice_size; i++) {
2138  auto jB = (*jmu_B_lat_)[i];
2139  const FourVector flow_four_velocity_B =
2140  std::abs(jB.density()) > really_small ? jB.jmu_net() / jB.density()
2141  : FourVector();
2142  double baryon_density = jB.density();
2143  ThreeVector baryon_grad_rho = jB.grad_rho();
2144  ThreeVector baryon_dj_dt = jB.dj_dt();
2145  ThreeVector baryon_rot_j = jB.rot_j();
2146  if (potentials_->use_skyrme()) {
2147  (*UB_lat_)[i] =
2148  flow_four_velocity_B * potentials_->skyrme_pot(baryon_density);
2149  (*FB_lat_)[i] = potentials_->skyrme_force(
2150  baryon_density, baryon_grad_rho, baryon_dj_dt, baryon_rot_j);
2151  }
2152  if (potentials_->use_symmetry() && jmu_I3_lat_ != nullptr) {
2153  auto jI3 = (*jmu_I3_lat_)[i];
2154  const FourVector flow_four_velocity_I3 =
2155  std::abs(jI3.density()) > really_small
2156  ? jI3.jmu_net() / jI3.density()
2157  : FourVector();
2158  (*UI3_lat_)[i] =
2159  flow_four_velocity_I3 *
2160  potentials_->symmetry_pot(jI3.density(), baryon_density);
2161  (*FI3_lat_)[i] = potentials_->symmetry_force(
2162  jI3.density(), jI3.grad_rho(), jI3.dj_dt(), jI3.rot_j(),
2163  baryon_density, baryon_grad_rho, baryon_dj_dt, baryon_rot_j);
2164  }
2165  }
2166  }
2167  }
2168 }
2169 
2170 template <typename Modus>
2172  /* At end of time evolution: Force all resonances to decay. In order to handle
2173  * decay chains, we need to loop until no further actions occur. */
2174  uint64_t interactions_old;
2175  const auto particles_before_actions = particles_.copy_to_vector();
2176  do {
2177  Actions actions;
2178 
2179  interactions_old = interactions_total_;
2180 
2181  // Dileptons: shining of remaining resonances
2182  if (dilepton_finder_ != nullptr) {
2183  for (const auto &output : outputs_) {
2184  dilepton_finder_->shine_final(particles_, output.get(), true);
2185  }
2186  }
2187  // Find actions.
2188  for (const auto &finder : action_finders_) {
2189  actions.insert(finder->find_final_actions(particles_));
2190  }
2191  // Perform actions.
2192  while (!actions.is_empty()) {
2193  perform_action(*actions.pop(), particles_before_actions);
2194  }
2195  // loop until no more decays occur
2196  } while (interactions_total_ > interactions_old);
2197 
2198  // Dileptons: shining of stable particles at the end
2199  if (dilepton_finder_ != nullptr) {
2200  for (const auto &output : outputs_) {
2201  dilepton_finder_->shine_final(particles_, output.get(), false);
2202  }
2203  }
2204 }
2205 
2206 template <typename Modus>
2207 void Experiment<Modus>::final_output(const int evt_num) {
2208  /* make sure the experiment actually ran (note: we should compare this
2209  * to the start time, but we don't know that. Therefore, we check that
2210  * the time is positive, which should heuristically be the same). */
2211  double E_mean_field = 0.0;
2212  if (likely(parameters_.labclock > 0)) {
2213  const uint64_t wall_actions_this_interval =
2214  wall_actions_total_ - previous_wall_actions_total_;
2215  const uint64_t interactions_this_interval = interactions_total_ -
2216  previous_interactions_total_ -
2217  wall_actions_this_interval;
2218  if (potentials_) {
2219  // using the lattice is necessary
2220  if ((jmu_B_lat_ != nullptr)) {
2221  E_mean_field =
2222  calculate_mean_field_energy(*potentials_, *jmu_B_lat_, parameters_);
2223  }
2224  }
2226  particles_, interactions_this_interval, conserved_initial_, time_start_,
2227  end_time_, E_mean_field, initial_mean_field_energy_);
2228  if (IC_output_switch_ && (particles_.size() == 0)) {
2229  // Verify there is no more energy in the system if all particles were
2230  // removed when crossing the hypersurface
2231  const double remaining_energy =
2232  conserved_initial_.momentum().x0() - total_energy_removed_;
2233  if (remaining_energy > really_small) {
2234  throw std::runtime_error(
2235  "There is remaining energy in the system although all particles "
2236  "were removed.\n"
2237  "E_remain = " +
2238  std::to_string(remaining_energy) + " [GeV]");
2239  } else {
2240  logg[LExperiment].info() << hline;
2241  logg[LExperiment].info()
2242  << "Time real: " << SystemClock::now() - time_start_;
2243  logg[LExperiment].info()
2244  << "Interactions before reaching hypersurface: "
2245  << interactions_total_ - wall_actions_total_ -
2246  total_hypersurface_crossing_actions_;
2247  logg[LExperiment].info()
2248  << "Total number of particles removed on hypersurface: "
2249  << total_hypersurface_crossing_actions_;
2250  }
2251  } else {
2252  const double precent_discarded =
2253  interactions_total_ > 0
2254  ? static_cast<double>(discarded_interactions_total_) * 100.0 /
2255  interactions_total_
2256  : 0.0;
2257  std::stringstream msg_discarded;
2258  msg_discarded
2259  << "Discarded interaction number: " << discarded_interactions_total_
2260  << " (" << precent_discarded
2261  << "% of the total interaction number including wall crossings)";
2262 
2263  logg[LExperiment].info() << hline;
2264  logg[LExperiment].info()
2265  << "Time real: " << SystemClock::now() - time_start_;
2266  logg[LExperiment].debug() << msg_discarded.str();
2267 
2268  if (parameters_.coll_crit == CollisionCriterion::Stochastic &&
2269  precent_discarded > 1.0) {
2270  // The choosen threshold of 1% is a heuristical value
2271  logg[LExperiment].warn()
2272  << msg_discarded.str()
2273  << "\nThe number of discarded interactions is large, which means "
2274  "the assumption for the stochastic criterion of\n1 interaction"
2275  "per particle per timestep is probably violated. Consider "
2276  "reducing the timestep size.";
2277  }
2278 
2279  logg[LExperiment].info() << "Final interaction number: "
2280  << interactions_total_ - wall_actions_total_;
2281  }
2282 
2283  // Check if there are unformed particles
2284  int unformed_particles_count = 0;
2285  for (const auto &particle : particles_) {
2286  if (particle.formation_time() > end_time_) {
2287  unformed_particles_count++;
2288  }
2289  }
2290  if (unformed_particles_count > 0) {
2291  logg[LExperiment].warn(
2292  "End time might be too small. ", unformed_particles_count,
2293  " unformed particles were found at the end of the evolution.");
2294  }
2295  }
2296 
2297  auto event_info =
2298  fill_event_info(particles_, E_mean_field, modus_.impact_parameter(),
2299  parameters_, projectile_target_interact_);
2300 
2301  for (const auto &output : outputs_) {
2302  output->at_eventend(particles_, evt_num, event_info);
2303  }
2304 }
2305 
2306 template <typename Modus>
2308  const auto &mainlog = logg[LMain];
2309  for (int j = 0; j < nevents_; j++) {
2310  mainlog.info() << "Event " << j;
2311 
2312  // Sample initial particles, start clock, some printout and book-keeping
2313  initialize_new_event(j);
2314  /* In the ColliderModus, if the first collisions within the same nucleus are
2315  * forbidden, 'nucleon_has_interacted_', which records whether a nucleon has
2316  * collided with another nucleon, is initialized equal to false. If allowed,
2317  * 'nucleon_has_interacted' is initialized equal to true, which means these
2318  * incoming particles have experienced some fake scatterings, they can
2319  * therefore collide with each other later on since these collisions are not
2320  * "first" to them. */
2321  if (modus_.is_collider()) {
2322  if (!modus_.cll_in_nucleus()) {
2323  nucleon_has_interacted_.assign(modus_.total_N_number(), false);
2324  } else {
2325  nucleon_has_interacted_.assign(modus_.total_N_number(), true);
2326  }
2327  }
2328  /* In the ColliderModus, if Fermi motion is frozen, assign the beam momenta
2329  * to the nucleons in both the projectile and the target. */
2330  if (modus_.is_collider() && modus_.fermi_motion() == FermiMotion::Frozen) {
2331  for (int i = 0; i < modus_.total_N_number(); i++) {
2332  const auto mass_beam = particles_.copy_to_vector()[i].effective_mass();
2333  const auto v_beam = i < modus_.proj_N_number()
2334  ? modus_.velocity_projectile()
2335  : modus_.velocity_target();
2336  const auto gamma = 1.0 / std::sqrt(1.0 - v_beam * v_beam);
2337  beam_momentum_.emplace_back(FourVector(gamma * mass_beam, 0.0, 0.0,
2338  gamma * v_beam * mass_beam));
2339  }
2340  }
2341 
2342  run_time_evolution();
2343 
2344  if (force_decays_) {
2345  do_final_decays();
2346  }
2347 
2348  // Output at event end
2349  final_output(j);
2350  }
2351 }
2352 
2353 } // namespace smash
2354 
2355 #endif // SRC_INCLUDE_SMASH_EXPERIMENT_H_
smash::LatticeUpdate
LatticeUpdate
Enumerator option for lattice updates.
Definition: lattice.h:36
smash::Experiment::jmu_I3_lat_
std::unique_ptr< DensityLattice > jmu_I3_lat_
Isospin projection density on the lattices.
Definition: experiment.h:424
smash::Experiment::particles
Particles * particles()
Provides external access to SMASH particles.
Definition: experiment.h:231
smash::Action::get_type
virtual ProcessType get_type() const
Get the process type.
Definition: action.h:131
smash::Experiment::time_step_mode_
const TimeStepMode time_step_mode_
This indicates whether to use time steps.
Definition: experiment.h:533
smash::Experiment::jmu_B_lat_
std::unique_ptr< DensityLattice > jmu_B_lat_
Baryon density on the lattices.
Definition: experiment.h:421
smash
Definition: action.h:24
smash::Experiment::run_time_evolution
void run_time_evolution()
Runs the time evolution of an event with fixed-sized time steps or without timesteps,...
Definition: experiment.h:1800
smash::SystemTimePoint
std::chrono::time_point< std::chrono::system_clock > SystemTimePoint
Type (alias) that is used to store the current time.
Definition: chrono.h:22
smash::Experiment::printout_tmn_
bool printout_tmn_
Whether to print the energy-momentum tensor.
Definition: experiment.h:462
quantumnumbers.h
outputparameters.h
ThermodynamicQuantity::TmnLandau
@ TmnLandau
smash::Experiment::Tmn_
std::unique_ptr< RectangularLattice< EnergyMomentumTensor > > Tmn_
Lattices of energy-momentum tensors for printout.
Definition: experiment.h:459
smash::Experiment::action_finders_
std::vector< std::unique_ptr< ActionFinderInterface > > action_finders_
The Action finder objects.
Definition: experiment.h:409
smash::Experiment::initialize_new_event
void initialize_new_event(int event_number)
This is called in the beginning of each event.
Definition: experiment.h:1533
smash::LInitialConditions
static constexpr int LInitialConditions
Definition: experiment.h:86
smash::expand_space_time
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
smash::Experiment::photons_switch_
const bool photons_switch_
This indicates whether photons are switched on.
Definition: experiment.h:524
smash::ScatterActionPhoton::is_kinematically_possible
static bool is_kinematically_possible(const double s_sqrt, const ParticleList &in)
Check if CM-energy is sufficient to produce hadron in final state.
Definition: scatteractionphoton.cc:154
smash::Action::generate_final_state
virtual void generate_final_state()=0
Generate the final state for this action.
smash::Experiment::total_energy_removed_
double total_energy_removed_
Total energy removed from the system in hypersurface crossing actions.
Definition: experiment.h:605
ThermodynamicQuantity::LandauVelocity
@ LandauVelocity
smash::Experiment::previous_wall_actions_total_
uint64_t previous_wall_actions_total_
Total number of wall-crossings for previous timestep.
Definition: experiment.h:581
smash::DensityParameters
A class to pre-calculate and store parameters relevant for density calculation.
Definition: density.h:108
smash::BremsstrahlungAction::is_bremsstrahlung_reaction
static bool is_bremsstrahlung_reaction(const ParticleList &in)
Check if particles can undergo an implemented photon process.
Definition: bremsstrahlungaction.h:134
smash::Experiment::beam_momentum_
std::vector< FourVector > beam_momentum_
The initial nucleons in the ColliderModus propagate with beam_momentum_, if Fermi motion is frozen.
Definition: experiment.h:406
smash::Experiment::next_output_time
double next_output_time() const
Shortcut for next output time.
Definition: experiment.h:343
smash::Experiment::compute_min_cell_length
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:338
TimeStepMode
TimeStepMode
The time step mode.
Definition: forwarddeclarations.h:114
smash::Actions::insert
void insert(ActionList &&new_acts)
Insert a list of actions into this object.
Definition: actions.h:76
hypersurfacecrossingaction.h
smash::LatticeUpdate::AtOutput
@ AtOutput
smash::Experiment::wall_actions_total_
uint64_t wall_actions_total_
Total number of wall-crossings for current timestep.
Definition: experiment.h:575
smash::Experiment::final_output
void final_output(const int evt_num)
Output at the end of an event.
Definition: experiment.h:2207
smash::check_interactions_total
void check_interactions_total(uint64_t interactions_total)
Make sure interactions_total can be represented as a 32-bit integer.
Definition: experiment.h:1915
smash::Experiment::npart_projectile
int npart_projectile() const
Number of projectile participants.
Definition: experiment.h:248
smash::Experiment::UB_lat_
std::unique_ptr< RectangularLattice< FourVector > > UB_lat_
Lattices for Skyrme potentials (evaluated in the local rest frame) times the baryon flow 4-velocity.
Definition: experiment.h:442
smash::LExperiment
static constexpr int LExperiment
Definition: outputparameters.h:19
decayactionsfinder.h
smash::Experiment::pauli_blocker_
std::unique_ptr< PauliBlocker > pauli_blocker_
An instance of PauliBlocker class that stores parameters needed for Pauli blocking calculations and c...
Definition: experiment.h:376
binaryoutput.h
smash::DensityType::BaryonicIsospin
@ BaryonicIsospin
smash::Action::is_pauli_blocked
bool is_pauli_blocked(const Particles &particles, const PauliBlocker &p_bl) const
Check if the action is Pauli-blocked.
Definition: action.cc:34
ExpansionMode::NoExpansion
@ NoExpansion
smash::Experiment::modus_
Modus modus_
Instance of the Modus template parameter.
Definition: experiment.h:361
smash::Experiment::modus
Modus * modus()
Provides external access to SMASH calculation modus.
Definition: experiment.h:237
smash::hline
const std::string hline(113, '-')
String representing a horizontal line.
smash::format_measurements
std::string format_measurements(const Particles &particles, uint64_t scatterings_this_interval, const QuantumNumbers &conserved_initial, SystemTimePoint time_start, double time, double E_mean_field, double E_mean_field_initial)
Generate the tabulated string which will be printed to the screen when SMASH is running.
Definition: experiment.cc:493
smash::Experiment::projectile_target_interact_
bool projectile_target_interact_
Whether the projectile and the target collided.
Definition: experiment.h:399
FermiMotion::Off
@ Off
Don't use fermi motion.
grid.h
smash::operator<<
std::ostream & operator<<(std::ostream &out, const ActionPtr &action)
Definition: action.h:518
energymomentumtensor.h
smash::Experiment::jmu_custom_lat_
std::unique_ptr< DensityLattice > jmu_custom_lat_
Custom density on the lattices.
Definition: experiment.h:433
smash::Experiment::npart_target
int npart_target() const
Number of target participants.
Definition: experiment.h:264
smash::Experiment::run_time_evolution_timestepless
void run_time_evolution_timestepless(Actions &actions)
Performs all the propagations and actions during a certain time interval neglecting the influence of ...
Definition: experiment.h:1923
smash::random::set_seed
void set_seed(T &&seed)
Sets the seed of the random number engine.
Definition: random.h:71
smash::Experiment::particles_
Particles particles_
Complete particle list.
Definition: experiment.h:364
propagation.h
smash::LatticeUpdate::EveryTimestep
@ EveryTimestep
smash::LMain
static constexpr int LMain
Definition: experiment.h:85
smash::Experiment::run
void run() override
Runs the experiment.
Definition: experiment.h:2307
fourvector.h
smash::Experiment::force_decays_
const bool force_decays_
This indicates whether we force all resonances to decay in the last timestep.
Definition: experiment.h:512
smash::Experiment::total_pauli_blocked_
uint64_t total_pauli_blocked_
Total number of Pauli-blockings for current timestep.
Definition: experiment.h:587
smash::Experiment::dileptons_switch_
const bool dileptons_switch_
This indicates whether dileptons are switched on.
Definition: experiment.h:521
smash::Experiment::dens_type_
DensityType dens_type_
Type of density to be written to collision headers.
Definition: experiment.h:557
FermiMotion::Frozen
@ Frozen
Use fermi motion without potentials.
smash::logg
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
smash::Experiment::photon_output_
OutputPtr photon_output_
The Photon output.
Definition: experiment.h:388
grandcan_thermalizer.h
smash::Experiment::thermalizer_
std::unique_ptr< GrandCanThermalizer > thermalizer_
Instance of class used for forced thermalization.
Definition: experiment.h:474
smash::really_small
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:37
pauliblocking.h
smash::Configuration
Interface to the SMASH configuration files.
Definition: configuration.h:464
smash::StringProcess
String excitation processes used in SMASH.
Definition: stringprocess.h:45
smash::UI3_lat_pointer
RectangularLattice< FourVector > * UI3_lat_pointer
Pointer to the symmmetry potential on the lattice.
Definition: potential_globals.cc:16
wallcrossingaction.h
smash::Experiment::density_param_
DensityParameters density_param_
Structure to precalculate and hold parameters for density computations.
Definition: experiment.h:355
smash::Experiment::nevents_
const int nevents_
Number of events.
Definition: experiment.h:496
smash::Experiment::seed_
int64_t seed_
random seed for the next event.
Definition: experiment.h:608
chrono.h
smash::fill_event_info
EventInfo fill_event_info(const Particles &particles, double E_mean_field, double modus_impact_parameter, const ExperimentParameters &parameters, bool projectile_target_interact)
Generate the EventInfo object which is passed to outputs_.
Definition: experiment.cc:651
smash::ThreeVector
Definition: threevector.h:31
smash::ProcessType::Wall
@ Wall
box wall crossing
smash::ScatterActionPhoton::is_photon_reaction
static bool is_photon_reaction(const ParticleList &in)
Check if particles can undergo an implemented photon process.
Definition: scatteractionphoton.h:145
smash::OutputParameters
Helper structure for Experiment to hold output options and parameters.
Definition: outputparameters.h:25
smash::format
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:307
einhard::Color
A stream modifier that allows to colorize the log output.
Definition: einhard.hpp:142
smash::create_oscar_output
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:769
smash::Experiment::metric_
const ExpansionProperties metric_
This struct contains information on the metric to be used.
Definition: experiment.h:518
CollisionCriterion::Stochastic
@ Stochastic
Stochastic Criteiron.
actions.h
smash::Experiment::printout_tmn_landau_
bool printout_tmn_landau_
Whether to print the energy-momentum tensor in Landau frame.
Definition: experiment.h:465
smash::Experiment::FI3_lat_
std::unique_ptr< RectangularLattice< std::pair< ThreeVector, ThreeVector > > > FI3_lat_
Lattices for the electric and magnetic component of the symmetry force.
Definition: experiment.h:456
smash::create_experiment_parameters
ExperimentParameters create_experiment_parameters(Configuration config)
Gathers all general Experiment parameters.
Definition: experiment.cc:338
smash::Experiment::do_final_decays
void do_final_decays()
Performs the final decays of an event.
Definition: experiment.h:2171
smash::update_lattice
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:402
smash::UB_lat_pointer
RectangularLattice< FourVector > * UB_lat_pointer
Pointer to the skyrme potential on the lattice.
Definition: potential_globals.cc:15
smash::Actions::pop
ActionPtr pop()
Return the first action in the list and removes it from the list.
Definition: actions.h:59
smash::make_unique
std::unique_ptr< T > make_unique(Args &&... args)
Definition for make_unique Is in C++14's standard library; necessary for older compilers.
Definition: cxx14compat.h:26
rootoutput.h
ThermodynamicQuantity::Tmn
@ Tmn
bremsstrahlungaction.h
smash::ThermalizationAction::any_particles_thermalized
bool any_particles_thermalized() const
This method checks, if there are particles in the region to be thermalized.
Definition: thermalizationaction.h:39
smash::Action::is_valid
bool is_valid(const Particles &particles) const
Check whether the action still applies.
Definition: action.cc:28
smash::Experiment::use_grid_
const bool use_grid_
This indicates whether to use the grid.
Definition: experiment.h:515
TimeStepMode::None
@ None
Don't use time steps; propagate from action to action.
smash::Experiment::interactions_total_
uint64_t interactions_total_
Total number of interactions for current timestep.
Definition: experiment.h:563
smash::ExperimentBase::InvalidModusRequest
Definition: experiment.h:140
smash::Action::get_total_weight
virtual double get_total_weight() const =0
Return the total weight value, which is mainly used for the weight output entry.
smash::Experiment::intermediate_output
void intermediate_output()
Intermediate output during an event.
Definition: experiment.h:2009
smash::operator<<
std::ostream & operator<<(std::ostream &out, const Experiment< Modus > &e)
Creates a verbose textual description of the setup of the Experiment.
Definition: experiment.h:620
smash::Actions::is_empty
bool is_empty() const
Definition: actions.h:52
smash::Experiment::propagate_and_shine
void propagate_and_shine(double to_time)
Propagate all particles until time to_time without any interactions and shine dileptons.
Definition: experiment.h:1898
smash::ThermalizationAction
Definition: thermalizationaction.h:24
smash::ParticleData::formation_power_
static double formation_power_
Power with which the cross section scaling factor grows in time.
Definition: particledata.h:378
actionfinderfactory.h
decayactionsfinderdilepton.h
smash::Action::perform
virtual void perform(Particles *particles, uint32_t id_process)
Actually perform the action, e.g.
Definition: action.cc:124
stringprocess.h
smash::Experiment::delta_time_startup_
const double delta_time_startup_
The clock's timestep size at start up.
Definition: experiment.h:506
smash::Experiment::IC_output_switch_
const bool IC_output_switch_
This indicates whether the IC output is enabled.
Definition: experiment.h:530
smash::current_eckart
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:148
smash::Experiment::Experiment
Experiment(Configuration config, const bf::path &output_path)
Create a new Experiment.
smash::CellSizeStrategy::Largest
@ Largest
Make cells as large as possible.
ThermodynamicQuantity::EckartDensity
@ EckartDensity
vtkoutput.h
oscaroutput.h
smash::Experiment::previous_interactions_total_
uint64_t previous_interactions_total_
Total number of interactions for previous timestep.
Definition: experiment.h:569
smash::Action::sqrt_s
double sqrt_s() const
Determine the total energy in the center-of-mass frame [GeV].
Definition: action.h:266
smash::Particles
Definition: particles.h:33
smash::DensityType
DensityType
Allows to choose which kind of density to calculate.
Definition: density.h:36
scatteractionphoton.h
smash::Experiment::perform_action
bool perform_action(Action &action, const Container &particles_before_actions)
Perform the given action.
smash::Experiment::update_potentials
void update_potentials()
Recompute potentials on lattices if necessary.
Definition: experiment.h:2125
smash::random::advance
Engine::result_type advance()
Advance the engine's state and return the generated value.
Definition: random.h:78
smash::Experiment::FB_lat_
std::unique_ptr< RectangularLattice< std::pair< ThreeVector, ThreeVector > > > FB_lat_
Lattices for the electric and magnetic components of the Skyrme force.
Definition: experiment.h:452
smash::ExperimentParameters::outputclock
std::unique_ptr< Clock > outputclock
Output clock to keep track of the next output time.
Definition: experimentparameters.h:29
smash::fm2_mb
constexpr double fm2_mb
mb <-> fm^2 conversion factor.
Definition: constants.h:28
smash::ExperimentBase::~ExperimentBase
virtual ~ExperimentBase()=default
The virtual destructor avoids undefined behavior when destroying derived objects.
smash::Experiment::dens_type_lattice_printout_
DensityType dens_type_lattice_printout_
Type of density for lattice printout.
Definition: experiment.h:436
smash::Experiment::dilepton_finder_
std::unique_ptr< DecayActionsFinderDilepton > dilepton_finder_
The Dilepton Action Finder.
Definition: experiment.h:412
thermalizationaction.h
smash::Actions::size
ActionList::size_type size() const
Definition: actions.h:95
smash::Experiment::printout_lattice_td_
bool printout_lattice_td_
Whether to print the thermodynamics quantities evaluated on the lattices.
Definition: experiment.h:471
smash::Action
Definition: action.h:35
rivetoutput.h
smash::Experiment::create_output
void create_output(const std::string &format, const std::string &content, const bf::path &output_path, const OutputParameters &par)
Create a list of output files.
Definition: experiment.h:627
smash::calculate_mean_field_energy
double calculate_mean_field_energy(const Potentials &potentials, RectangularLattice< smash::DensityOnLattice > &jmu_B_lat, const ExperimentParameters &parameters)
Calculate the total mean field energy of the system; this will be printed to the screen when SMASH is...
Definition: experiment.cc:539
smash::Experiment::n_fractional_photons_
int n_fractional_photons_
Number of fractional photons produced per single reaction.
Definition: experiment.h:418
smash::Experiment::dilepton_output_
OutputPtr dilepton_output_
The Dilepton output.
Definition: experiment.h:385
smash::Experiment::parameters_
ExperimentParameters parameters_
Struct of several member variables.
Definition: experiment.h:352
smash::ProcessType::HyperSurfaceCrossing
@ HyperSurfaceCrossing
Hypersurface crossing Particles are removed from the evolution and printed to a separate output to se...
smash::ExperimentParameters
Helper structure for Experiment.
Definition: experimentparameters.h:24
smash::DensityType::None
@ None
smash::FourVector
Definition: fourvector.h:33
smash::Experiment::end_time_
const double end_time_
simulation time at which the evolution is stopped.
Definition: experiment.h:499
smash::Experiment::nucleon_has_interacted_
std::vector< bool > nucleon_has_interacted_
nucleon_has_interacted_ labels whether the particles in the nuclei have experienced any collisions or...
Definition: experiment.h:395
smash::Experiment::process_string_ptr_
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:480
smash::Action::get_interaction_point
FourVector get_interaction_point() const
Get the interaction point.
Definition: action.cc:67
smash::propagate_straight_line
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:44
smash::Experiment::potentials_
std::unique_ptr< Potentials > potentials_
An instance of potentials class, that stores parameters of potentials, calculates them and their grad...
Definition: experiment.h:370
likely
#define likely(x)
Tell the branch predictor that this expression is likely true.
Definition: macros.h:14
smash::ExperimentBase::ExperimentBase
ExperimentBase()=default
smash::Experiment::initial_mean_field_energy_
double initial_mean_field_energy_
The initial total mean field energy in the system.
Definition: experiment.h:551
hepmcoutput.h
smash::Experiment
The main class, where the simulation of an experiment is executed.
Definition: experiment.h:146
smash::pdg::n
constexpr int n
Neutron.
Definition: pdgcode_constants.h:30
smash::Experiment::outputs_
OutputsList outputs_
A list of output formaters.
Definition: experiment.h:382
smash::pot_pointer
Potentials * pot_pointer
Pointer to a Potential class.
Definition: potential_globals.cc:17
scatteractionsfinder.h
smash::Action::incoming_particles
const ParticleList & incoming_particles() const
Get the list of particles that go into the action.
Definition: action.cc:57
smash::Experiment::total_hypersurface_crossing_actions_
uint64_t total_hypersurface_crossing_actions_
Total number of particles removed from the evolution in hypersurface crossing actions.
Definition: experiment.h:593
smash::DensityType::Baryon
@ Baryon
SMASH_SOURCE_LOCATION
#define SMASH_SOURCE_LOCATION
Hackery that is required to output the location in the source code where the log statement occurs.
Definition: logging.h:243
potential_globals.h
thermodynamicoutput.h
smash::Experiment::printout_v_landau_
bool printout_v_landau_
Whether to print the 4-velocity in Landau fram.
Definition: experiment.h:468
smash::Experiment::discarded_interactions_total_
uint64_t discarded_interactions_total_
Total number of discarded interactions, because they were invalidated before they could be performed.
Definition: experiment.h:599
smash::Experiment::projectile_target_have_interacted
bool projectile_target_have_interacted() const
Return true if any two beam particles interacted.
Definition: experiment.h:272
smash::Experiment::time_start_
SystemTimePoint time_start_
system starting time of the simulation
Definition: experiment.h:554
smash::ExperimentBase::create
static std::unique_ptr< ExperimentBase > create(Configuration config, const bf::path &output_path)
Factory method that creates and initializes a new Experiment<Modus>.
smash::Experiment::UI3_lat_
std::unique_ptr< RectangularLattice< FourVector > > UI3_lat_
Lattices for symmetry potentials (evaluated in the local rest frame) times the isospin flow 4-velocit...
Definition: experiment.h:448
smash::Experiment::bremsstrahlung_switch_
const bool bremsstrahlung_switch_
This indicates whether bremsstrahlung is switched on.
Definition: experiment.h:527
TimeStepMode::Fixed
@ Fixed
Use fixed time step.
smash::QuantumNumbers
Definition: quantumnumbers.h:53
icoutput.h
smash::ExpansionProperties
Struct containing the type of the metric and the expansion parameter of the metric.
Definition: propagation.h:26
FermiMotion
FermiMotion
Option to use Fermi Motion.
Definition: forwarddeclarations.h:94
smash::ExperimentBase::run
virtual void run()=0
Runs the experiment.
smash::Actions
Definition: actions.h:29
smash::update_momenta
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
smash::Experiment::photon_finder_
std::unique_ptr< ActionFinderInterface > photon_finder_
The (Scatter) Actions Finder for Direct Photons.
Definition: experiment.h:415
smash::Experiment::conserved_initial_
QuantumNumbers conserved_initial_
The conserved quantities of the system.
Definition: experiment.h:545
smash::ExperimentBase
Non-template interface to Experiment<Modus>.
Definition: experiment.h:95
smash::Experiment::max_transverse_distance_sqr_
double max_transverse_distance_sqr_
Maximal distance at which particles can interact, squared.
Definition: experiment.h:536
potentials.h