7 #ifndef SRC_INCLUDE_SMASH_EXPERIMENT_H_
8 #define SRC_INCLUDE_SMASH_EXPERIMENT_H_
42 #ifdef SMASH_USE_HEPMC
45 #ifdef SMASH_USE_RIVET
70 template <
typename T,
typename Ratio>
72 const chrono::duration<T, Ratio> &seconds) {
73 using Seconds = chrono::duration<double>;
74 using Minutes = chrono::duration<double, std::ratio<60>>;
75 using Hours = chrono::duration<double, std::ratio<60 * 60>>;
76 constexpr Minutes threshold_for_minutes{10};
77 constexpr Hours threshold_for_hours{3};
78 if (seconds < threshold_for_minutes) {
79 return out << Seconds(seconds).count() <<
" [s]";
81 if (seconds < threshold_for_hours) {
82 return out << Minutes(seconds).count() <<
" [min]";
84 return out << Hours(seconds).count() <<
" [h]";
89 static constexpr
int LMain = LogArea::Main::id;
128 static std::unique_ptr<ExperimentBase>
create(
129 Configuration &config,
const std::filesystem::path &output_path);
145 using std::invalid_argument::invalid_argument;
154 using std::invalid_argument::invalid_argument;
158 template <
typename Modus>
160 template <
typename Modus>
187 template <
typename Modus>
214 const std::filesystem::path &output_path);
241 ParticleList &&remove_plist = {});
287 bool include_pauli_blocking =
true);
297 const std::filesystem::path &output_path,
322 const double end_time_propagation);
462 std::unique_ptr<RectangularLattice<FourVector>>
UB_lat_ =
nullptr;
468 std::unique_ptr<RectangularLattice<FourVector>>
UI3_lat_ =
nullptr;
474 std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
478 std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
482 std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
486 std::unique_ptr<RectangularLattice<EnergyMomentumTensor>>
Tmn_;
493 std::unique_ptr<RectangularLattice<std::array<FourVector, 4>>>
501 std::unique_ptr<RectangularLattice<std::array<FourVector, 4>>>
708 friend std::ostream &operator<<<>(std::ostream &out,
const Experiment &e);
712 template <
typename Modus>
714 out <<
"End time: " << e.
end_time_ <<
" fm\n";
719 template <
typename Modus>
721 const std::string &content,
722 const std::filesystem::path &output_path,
724 logg[
LExperiment].info() <<
"Adding output " << content <<
" of format "
727 if (
format ==
"VTK" && content ==
"Particles") {
728 outputs_.emplace_back(
729 std::make_unique<VtkOutput>(output_path, content, out_par));
730 }
else if (
format ==
"Root") {
731 #ifdef SMASH_USE_ROOT
732 if (content ==
"Initial_Conditions") {
733 outputs_.emplace_back(
734 std::make_unique<RootOutput>(output_path,
"SMASH_IC", out_par));
736 outputs_.emplace_back(
737 std::make_unique<RootOutput>(output_path, content, out_par));
741 "Root output requested, but Root support not compiled in");
743 }
else if (
format ==
"Binary") {
744 if (content ==
"Collisions" || content ==
"Dileptons" ||
745 content ==
"Photons") {
746 outputs_.emplace_back(std::make_unique<BinaryOutputCollisions>(
747 output_path, content, out_par));
748 }
else if (content ==
"Particles") {
749 outputs_.emplace_back(std::make_unique<BinaryOutputParticles>(
750 output_path, content, out_par));
751 }
else if (content ==
"Initial_Conditions") {
752 outputs_.emplace_back(std::make_unique<BinaryOutputInitialConditions>(
753 output_path, content, out_par));
755 }
else if (
format ==
"Oscar1999" ||
format ==
"Oscar2013") {
756 outputs_.emplace_back(
758 }
else if (content ==
"Thermodynamics" &&
format ==
"ASCII") {
759 outputs_.emplace_back(
760 std::make_unique<ThermodynamicOutput>(output_path, content, out_par));
761 }
else if (content ==
"Thermodynamics" &&
762 (
format ==
"Lattice_ASCII" ||
format ==
"Lattice_Binary")) {
763 printout_full_lattice_any_td_ =
true;
764 outputs_.emplace_back(std::make_unique<ThermodynamicLatticeOutput>(
765 output_path, content, out_par,
format ==
"Lattice_ASCII",
766 format ==
"Lattice_Binary"));
767 }
else if (content ==
"Thermodynamics" &&
format ==
"VTK") {
768 printout_lattice_td_ =
true;
769 outputs_.emplace_back(
770 std::make_unique<VtkOutput>(output_path, content, out_par));
771 }
else if (content ==
"Initial_Conditions" &&
format ==
"ASCII") {
772 outputs_.emplace_back(
773 std::make_unique<ICOutput>(output_path,
"SMASH_IC", out_par));
774 }
else if ((
format ==
"HepMC") || (
format ==
"HepMC_asciiv3") ||
775 (
format ==
"HepMC_treeroot")) {
776 #ifdef SMASH_USE_HEPMC
777 if (content ==
"Particles") {
778 if ((
format ==
"HepMC") || (
format ==
"HepMC_asciiv3")) {
779 outputs_.emplace_back(std::make_unique<HepMcOutput>(
780 output_path,
"SMASH_HepMC_particles",
false,
"asciiv3"));
781 }
else if (
format ==
"HepMC_treeroot") {
782 #ifdef SMASH_USE_HEPMC_ROOTIO
783 outputs_.emplace_back(std::make_unique<HepMcOutput>(
784 output_path,
"SMASH_HepMC_particles",
false,
"root"));
787 "Requested HepMC_treeroot output not available, "
788 "ROOT or HepMC3 ROOTIO missing or not found by cmake.");
791 }
else if (content ==
"Collisions") {
792 if ((
format ==
"HepMC") || (
format ==
"HepMC_asciiv3")) {
793 outputs_.emplace_back(std::make_unique<HepMcOutput>(
794 output_path,
"SMASH_HepMC_collisions",
true,
"asciiv3"));
795 }
else if (
format ==
"HepMC_treeroot") {
796 #ifdef SMASH_USE_HEPMC_ROOTIO
797 outputs_.emplace_back(std::make_unique<HepMcOutput>(
798 output_path,
"SMASH_HepMC_collisions",
true,
"root"));
801 "Requested HepMC_treeroot output not available, "
802 "ROOT or HepMC3 ROOTIO missing or not found by cmake.");
807 "HepMC only available for Particles and "
808 "Collisions content. Requested for " +
813 "HepMC output requested, but HepMC support not compiled in");
815 }
else if (content ==
"Coulomb" &&
format ==
"VTK") {
816 outputs_.emplace_back(
817 std::make_unique<VtkOutput>(output_path,
"Fields", out_par));
818 }
else if (content ==
"Rivet") {
819 #ifdef SMASH_USE_RIVET
821 static bool rivet_format_already_selected =
false;
823 if (rivet_format_already_selected) {
825 "Rivet output format can only be one, either YODA or YODA-full. "
826 "Only your first valid choice will be used.");
830 outputs_.emplace_back(std::make_unique<RivetOutput>(
832 rivet_format_already_selected =
true;
833 }
else if (
format ==
"YODA-full") {
834 outputs_.emplace_back(std::make_unique<RivetOutput>(
836 rivet_format_already_selected =
true;
839 "not one of YODA or YODA-full");
843 "Rivet output requested, but Rivet support not compiled in");
847 <<
"Unknown combination of format (" <<
format <<
") and content ("
848 << content <<
"). Fix the config.";
861 template <
typename Modus>
863 const std::filesystem::path &output_path)
866 modus_(std::invoke([&]() {
875 const std::initializer_list<const char *> key_labels = {
876 "Modi",
"Collider",
"Collisions_Within_Nucleus"};
877 const bool restore_key = config.
has_value(key_labels);
878 const bool temporary_taken_key = config.
take(key_labels,
false);
881 config.
set_value(key_labels, temporary_taken_key);
883 return Modus{std::move(modus_config),
parameters_};
885 ensembles_(parameters_.n_ensembles),
886 nevents_(config.
take({
"General",
"Nevents"}, 0)),
887 end_time_(config.
take({
"General",
"End_Time"})),
888 delta_time_startup_(parameters_.labclock->timestep_duration()),
890 config.
take({
"Collision_Term",
"Force_Decays_At_End"},
true)),
891 use_grid_(config.
take({
"General",
"Use_Grid"},
true)),
894 config.
take({
"General",
"Expansion_Rate"}, 0.1)),
896 config.
take({
"Collision_Term",
"Dileptons",
"Decays"},
false)),
897 photons_switch_(config.
take(
898 {
"Collision_Term",
"Photons",
"2to2_Scatterings"},
false)),
899 bremsstrahlung_switch_(
900 config.
take({
"Collision_Term",
"Photons",
"Bremsstrahlung"},
false)),
901 IC_output_switch_(config.
has_value({
"Output",
"Initial_Conditions"})),
906 if (config.
has_value({
"General",
"Minimum_Nonempty_Ensembles"})) {
907 if (config.
has_value({
"General",
"Nevents"})) {
908 throw std::invalid_argument(
909 "Please specify either Nevents or Minimum_Nonempty_Ensembles.");
912 minimum_nonempty_ensembles_ =
913 config.
take({
"General",
"Minimum_Nonempty_Ensembles",
"Number"});
914 int max_ensembles = config.
take(
915 {
"General",
"Minimum_Nonempty_Ensembles",
"Maximum_Ensembles_Run"});
917 std::ceil(
static_cast<double>(max_ensembles) / parameters_.n_ensembles);
925 throw std::invalid_argument(
926 "Covariant Gaussian derivatives only make sense for Covariant Gaussian "
934 parameters_.discrete_weight < (1. / 7.)) {
935 throw std::invalid_argument(
936 "The central weight for discrete smearing should be >= 1./7.");
941 throw std::invalid_argument(
942 "The stochastic criterion can only be employed for fixed time step "
943 "mode and with a grid!");
947 throw std::invalid_argument(
948 "The box modus can only be used with the fixed time step mode!");
952 " testparticles per particle.");
954 " parallel ensembles.");
956 if (modus_.is_box() &&
957 config.
read({
"Collision_Term",
"Total_Cross_Section_Strategy"},
961 "To preserve detailed balance in a box simulation, it is recommended "
962 "to use the bottom-up strategy for evaluating total cross sections.\n"
963 "Consider adding the following line to the 'Collision_Term' section "
964 "in your configuration file:\n"
965 " Total_Cross_Section_Strategy: \"BottomUp\"");
967 if (modus_.is_box() &&
968 config.
read({
"Collision_Term",
"Pseudoresonance"},
972 "To preserve detailed balance in a box simulation, it is recommended "
973 "to not include the pseudoresonances,\nas they artificially increase "
974 "the resonance production without changing the corresponding "
975 "decay.\nConsider adding the following line to the 'Collision_Term' "
976 "section in your configuration file:\n Pseudoresonance: \"None\"");
988 {
"Collision_Term",
"String_Parameters",
"Power_Particle_Formation"},
989 modus_.sqrt_s_NN() >= 200. ? -1. : 1.);
992 if (dileptons_switch_) {
993 dilepton_finder_ = std::make_unique<DecayActionsFinderDilepton>();
995 if (photons_switch_ || bremsstrahlung_switch_) {
996 n_fractional_photons_ =
997 config.
take({
"Collision_Term",
"Photons",
"Fractional_Photons"}, 100);
999 if (parameters_.two_to_one) {
1000 if (parameters_.res_lifetime_factor < 0.) {
1001 throw std::invalid_argument(
1002 "Resonance lifetime modifier cannot be negative!");
1006 "Resonance lifetime set to zero. Make sure resonances cannot "
1008 "inelastically (e.g. resonance chains), else SMASH is known to "
1011 action_finders_.emplace_back(std::make_unique<DecayActionsFinder>(
1012 parameters_.res_lifetime_factor, parameters_.do_weak_decays));
1014 bool no_coll = config.
take({
"Collision_Term",
"No_Collisions"},
false);
1015 if ((parameters_.two_to_one || parameters_.included_2to2.any() ||
1016 parameters_.included_multi.any() || parameters_.strings_switch) &&
1018 parameters_.use_monash_tune_default =
1019 (modus_.is_collider() && modus_.sqrt_s_NN() >= 200.);
1021 std::make_unique<ScatterActionsFinder>(config, parameters_);
1022 max_transverse_distance_sqr_ =
1023 scat_finder->max_transverse_distance_sqr(parameters_.testparticles);
1024 process_string_ptr_ = scat_finder->get_process_string_ptr();
1025 action_finders_.emplace_back(std::move(scat_finder));
1027 max_transverse_distance_sqr_ =
1028 parameters_.maximum_cross_section / M_PI *
fm2_mb;
1029 process_string_ptr_ = NULL;
1031 if (modus_.is_box()) {
1032 action_finders_.emplace_back(
1033 std::make_unique<WallCrossActionsFinder>(parameters_.box_length));
1035 if (IC_output_switch_) {
1036 if (!modus_.is_collider()) {
1037 throw std::runtime_error(
1038 "Initial conditions can only be extracted in collider modus.");
1041 if (config.
has_value({
"Output",
"Initial_Conditions",
"Proper_Time"})) {
1044 config.
take({
"Output",
"Initial_Conditions",
"Proper_Time"});
1047 double default_proper_time = modus_.nuclei_passing_time();
1048 double lower_bound =
1049 config.
take({
"Output",
"Initial_Conditions",
"Lower_Bound"}, 0.5);
1050 if (default_proper_time >= lower_bound) {
1051 proper_time = default_proper_time;
1054 <<
"Nuclei passing time is too short, hypersurface proper time set "
1056 << lower_bound <<
" fm.";
1057 proper_time = lower_bound;
1061 double rapidity_cut = 0.0;
1062 if (config.
has_value({
"Output",
"Initial_Conditions",
"Rapidity_Cut"})) {
1064 config.
take({
"Output",
"Initial_Conditions",
"Rapidity_Cut"});
1065 if (rapidity_cut <= 0.0) {
1067 <<
"Rapidity cut for initial conditions configured as abs(y) < "
1068 << rapidity_cut <<
" is unreasonable. \nPlease choose a positive, "
1069 <<
"non-zero value or employ SMASH without rapidity cut.";
1070 throw std::runtime_error(
1071 "Kinematic cut for initial conditions malconfigured.");
1075 if (modus_.calculation_frame_is_fixed_target() && rapidity_cut != 0.0) {
1076 throw std::runtime_error(
1077 "Rapidity cut for initial conditions output is not implemented "
1078 "in the fixed target calculation frame. \nPlease use "
1079 "\"center of velocity\" or \"center of mass\" as a "
1080 "\"Calculation_Frame\" instead.");
1083 double transverse_momentum_cut = 0.0;
1084 if (config.
has_value({
"Output",
"Initial_Conditions",
"pT_Cut"})) {
1085 transverse_momentum_cut =
1086 config.
take({
"Output",
"Initial_Conditions",
"pT_Cut"});
1087 if (transverse_momentum_cut <= 0.0) {
1089 <<
"transverse momentum cut for initial conditions configured as "
1091 << rapidity_cut <<
" is unreasonable. \nPlease choose a positive, "
1092 <<
"non-zero value or employ SMASH without pT cut.";
1093 throw std::runtime_error(
1094 "Kinematic cut for initial conditions misconfigured.");
1098 if (rapidity_cut > 0.0 || transverse_momentum_cut > 0.0) {
1099 kinematic_cuts_for_IC_output_ =
true;
1102 if (rapidity_cut > 0.0 && transverse_momentum_cut > 0.0) {
1104 <<
"Extracting initial conditions in kinematic range: "
1105 << -rapidity_cut <<
" <= y <= " << rapidity_cut
1106 <<
"; pT <= " << transverse_momentum_cut <<
" GeV.";
1107 }
else if (rapidity_cut > 0.0) {
1109 <<
"Extracting initial conditions in kinematic range: "
1110 << -rapidity_cut <<
" <= y <= " << rapidity_cut <<
".";
1111 }
else if (transverse_momentum_cut > 0.0) {
1113 <<
"Extracting initial conditions in kinematic range: pT <= "
1114 << transverse_momentum_cut <<
" GeV.";
1117 <<
"Extracting initial conditions without kinematic cuts.";
1120 action_finders_.emplace_back(
1121 std::make_unique<HyperSurfaceCrossActionsFinder>(
1122 proper_time, rapidity_cut, transverse_momentum_cut));
1125 if (config.
has_value({
"Collision_Term",
"Pauli_Blocking"})) {
1127 pauli_blocker_ = std::make_unique<PauliBlocker>(
1373 " create OutputInterface objects");
1376 <<
"Density type printed to headers: " << dens_type_;
1382 if (output_path ==
"") {
1383 throw std::invalid_argument(
1384 "Invalid empty output path provided to Experiment constructor.");
1385 }
else if (!std::filesystem::exists(output_path)) {
1387 "Output path \"" + output_path.string() +
1388 "\" used to create an Experiment object does not exist.");
1389 throw NonExistingOutputPathRequest(
"Attempt to use not existing path.");
1390 }
else if (!std::filesystem::is_directory(output_path)) {
1392 "\" used to create an Experiment object "
1393 "exists, but it is not a directory.");
1394 throw std::logic_error(
"Attempt to use invalid existing path.");
1396 if (output_conf.is_empty()) {
1397 logg[
LExperiment].warn() <<
"No \"Output\" section found in the input "
1398 "file. No output file will be produced.";
1400 const std::vector<std::string> output_contents =
1401 output_conf.list_upmost_nodes();
1402 std::vector<std::vector<std::string>> list_of_formats(output_contents.size());
1404 output_contents.cbegin(), output_contents.cend(), list_of_formats.begin(),
1405 [&output_conf](std::string content) -> std::vector<std::string> {
1409 return output_conf.take({content.c_str(),
"Format"},
1410 std::vector<std::string>{});
1412 const OutputParameters output_parameters(std::move(output_conf));
1413 std::size_t total_number_of_requested_formats = 0;
1414 auto abort_because_of_invalid_input_file = []() {
1415 throw std::invalid_argument(
"Invalid configuration input file.");
1417 for (std::size_t i = 0; i < output_contents.size(); ++i) {
1418 if (list_of_formats[i].empty()) {
1420 <<
"Empty or unspecified list of formats for "
1421 << std::quoted(output_contents[i]) <<
" content.";
1422 abort_because_of_invalid_input_file();
1423 }
else if (std::find(list_of_formats[i].begin(), list_of_formats[i].end(),
1424 "None") != list_of_formats[i].end()) {
1425 if (list_of_formats[i].size() > 1) {
1427 <<
"Use of \"None\" output format together with other formats is "
1428 "not allowed.\nInvalid \"Format\" key for "
1429 << std::quoted(output_contents[i]) <<
" content.";
1430 abort_because_of_invalid_input_file();
1433 list_of_formats[i].clear();
1435 }
else if (std::set<std::string> tmp_set(list_of_formats[i].begin(),
1436 list_of_formats[i].end());
1437 list_of_formats[i].size() != tmp_set.size()) {
1438 auto join_container = [](
const auto &container) {
1439 std::string result{};
1441 [&result](
const std::string s) {
1442 result += (result ==
"") ? s :
", " + s;
1446 const std::string old_formats = join_container(list_of_formats[i]),
1447 new_formats = join_container(tmp_set);
1449 <<
"Found the same output format multiple times for "
1450 << std::quoted(output_contents[i])
1451 <<
" content. Duplicates will be ignored:\n 'Format: [" << old_formats
1452 <<
"] -> [" << new_formats <<
"]'";
1453 list_of_formats[i].assign(tmp_set.begin(), tmp_set.end());
1455 for (
const auto &
format : list_of_formats[i]) {
1456 create_output(
format, output_contents[i], output_path, output_parameters);
1457 ++total_number_of_requested_formats;
1460 if (outputs_.size() != total_number_of_requested_formats) {
1462 <<
"At least one invalid output format has been provided.";
1463 abort_because_of_invalid_input_file();
1474 throw std::invalid_argument(
"Can't use potentials without time steps!");
1478 <<
"Potentials don't work with frozen Fermi momenta! "
1479 "Use normal Fermi motion instead.";
1480 throw std::invalid_argument(
1481 "Can't use potentials "
1482 "with frozen Fermi momenta!");
1485 << parameters_.labclock->timestep_duration();
1487 potentials_ = std::make_unique<Potentials>(
1491 if (potentials_->use_skyrme() && potentials_->use_vdf()) {
1492 throw std::runtime_error(
1493 "Can't use Skyrme and VDF potentials at the same time!");
1495 if (potentials_->use_symmetry() && potentials_->use_vdf()) {
1496 throw std::runtime_error(
1497 "Can't use symmetry and VDF potentials at the same time!");
1499 if (potentials_->use_skyrme()) {
1502 <<
"\t\tSkyrme_A [MeV] = " << potentials_->skyrme_a() <<
"\n";
1504 <<
"\t\tSkyrme_B [MeV] = " << potentials_->skyrme_b() <<
"\n";
1506 <<
"\t\t Skyrme_tau = " << potentials_->skyrme_tau() <<
"\n";
1508 if (potentials_->use_symmetry()) {
1510 <<
"Symmetry potential is:"
1511 <<
"\n S_pot [MeV] = " << potentials_->symmetry_S_pot() <<
"\n";
1513 if (potentials_->use_vdf()) {
1516 << potentials_->saturation_density() <<
"\n";
1517 for (
int i = 0; i < potentials_->number_of_terms(); i++) {
1519 <<
"\t\tCoefficient_" << i + 1 <<
" = "
1520 << 1000.0 * (potentials_->coeffs())[i] <<
" [MeV] \t Power_"
1521 << i + 1 <<
" = " << (potentials_->powers())[i] <<
"\n";
1527 throw std::invalid_argument(
1528 "Derivatives are necessary for running with potentials.\n"
1529 "Derivatives_Mode: \"Off\" only makes sense for "
1530 "Field_Derivatives_Mode: \"Direct\"!\nUse \"Covariant Gaussian\" or "
1531 "\"Finite difference\".");
1539 switch (parameters_.derivatives_mode) {
1550 switch (parameters_.rho_derivatives_mode) {
1559 if (potentials_->use_vdf()) {
1560 switch (parameters_.field_derivatives_mode) {
1573 if (potentials_->use_vdf() && (parameters_.rho_derivatives_mode ==
1575 parameters_.field_derivatives_mode ==
1577 throw std::runtime_error(
1578 "Can't use VDF potentials without rest frame density derivatives or "
1579 "direct field derivatives!");
1584 throw std::runtime_error(
1585 "Can't use potentials without gradients of baryon current (Skyrme, "
1587 " or direct field derivatives (VDF)!");
1590 if (!(potentials_->use_vdf()) &&
1592 throw std::invalid_argument(
1593 "Field_Derivatives_Mode: \"Direct\" only makes sense for the VDF "
1594 "potentials!\nUse Field_Derivatives_Mode: \"Chain Rule\" or comment "
1595 "this option out (Chain Rule is default)");
1600 switch (parameters_.smearing_mode) {
1606 << parameters_.discrete_weight;
1610 << parameters_.triangular_range;
1616 bool automatic = config.
take({
"Lattice",
"Automatic"},
false);
1617 bool all_geometrical_properties_specified =
1618 config.
has_value({
"Lattice",
"Cell_Number"}) &&
1619 config.
has_value({
"Lattice",
"Origin"}) &&
1621 if (!automatic && !all_geometrical_properties_specified) {
1622 throw std::invalid_argument(
1623 "The lattice was requested to be manually generated, but some\n"
1624 "lattice geometrical property was not specified. Be sure to provide\n"
1625 "both \"Cell_Number\" and \"Origin\" and \"Sizes\".");
1627 if (automatic && all_geometrical_properties_specified) {
1628 throw std::invalid_argument(
1629 "The lattice was requested to be automatically generated, but all\n"
1630 "lattice geometrical properties were specified. In this case you\n"
1631 "need to set \"Automatic: False\".");
1633 bool periodic = config.
take({
"Lattice",
"Periodic"}, modus_.is_box());
1634 const auto [l,
n, origin] = [&config, automatic,
this]() {
1636 return std::make_tuple<std::array<double, 3>, std::array<int, 3>,
1637 std::array<double, 3>>(
1638 config.
take({
"Lattice",
"Sizes"}),
1639 config.
take({
"Lattice",
"Cell_Number"}),
1640 config.
take({
"Lattice",
"Origin"}));
1642 std::array<double, 3> l_default{20., 20., 20.};
1643 std::array<int, 3> n_default{10, 10, 10};
1644 std::array<double, 3> origin_default{-20., -20., -20.};
1645 if (modus_.is_collider() || (modus_.is_list() && !modus_.is_box())) {
1648 const double gam = modus_.is_collider()
1651 const double max_z = 5.0 / gam + end_time_;
1652 const double estimated_max_transverse_velocity = 0.7;
1653 const double max_xy =
1654 5.0 + estimated_max_transverse_velocity * end_time_;
1655 origin_default = {-max_xy, -max_xy, -max_z};
1656 l_default = {2 * max_xy, 2 * max_xy, 2 * max_z};
1659 const int n_xy = std::ceil(2 * max_xy / 0.8);
1660 int nz = std::ceil(2 * max_z / 0.8);
1665 nz =
static_cast<int>(std::ceil(2 * max_z / 0.8 * gam));
1667 n_default = {n_xy, n_xy, nz};
1668 }
else if (modus_.is_box()) {
1669 origin_default = {0., 0., 0.};
1670 const double bl = modus_.length();
1671 l_default = {bl, bl, bl};
1672 const int n_xyz = std::ceil(bl / 0.5);
1673 n_default = {n_xyz, n_xyz, n_xyz};
1674 }
else if (modus_.is_sphere()) {
1677 const double max_d = modus_.radius() + end_time_;
1678 origin_default = {-max_d, -max_d, -max_d};
1679 l_default = {2 * max_d, 2 * max_d, 2 * max_d};
1681 const int n_xyz = std::ceil(2 * max_d / 0.8);
1682 n_default = {n_xyz, n_xyz, n_xyz};
1685 return std::make_tuple<std::array<double, 3>, std::array<int, 3>,
1686 std::array<double, 3>>(
1687 config.
take({
"Lattice",
"Sizes"}, l_default),
1688 config.
take({
"Lattice",
"Cell_Number"}, n_default),
1689 config.
take({
"Lattice",
"Origin"}, origin_default));
1694 <<
"Lattice is ON. Origin = (" << origin[0] <<
"," << origin[1] <<
","
1695 << origin[2] <<
"), sizes = (" << l[0] <<
"," << l[1] <<
"," << l[2]
1696 <<
"), number of cells = (" <<
n[0] <<
"," <<
n[1] <<
"," <<
n[2]
1697 <<
"), periodic = " << std::boolalpha << periodic;
1699 if (printout_lattice_td_ || printout_full_lattice_any_td_) {
1700 dens_type_lattice_printout_ = output_parameters.td_dens_type;
1701 printout_rho_eckart_ = output_parameters.td_rho_eckart;
1702 printout_tmn_ = output_parameters.td_tmn;
1703 printout_tmn_landau_ = output_parameters.td_tmn_landau;
1704 printout_v_landau_ = output_parameters.td_v_landau;
1705 printout_j_QBS_ = output_parameters.td_jQBS;
1707 if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
1708 Tmn_ = std::make_unique<RectangularLattice<EnergyMomentumTensor>>(
1709 l,
n, origin, periodic, LatticeUpdate::AtOutput);
1711 if (printout_j_QBS_) {
1712 j_QBS_lat_ = std::make_unique<DensityLattice>(l,
n, origin, periodic,
1713 LatticeUpdate::AtOutput);
1720 old_jmu_auxiliary_ = std::make_unique<RectangularLattice<FourVector>>(
1721 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1722 new_jmu_auxiliary_ = std::make_unique<RectangularLattice<FourVector>>(
1723 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1724 four_gradient_auxiliary_ =
1725 std::make_unique<RectangularLattice<std::array<FourVector, 4>>>(
1726 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1728 if (potentials_->use_skyrme()) {
1729 jmu_B_lat_ = std::make_unique<DensityLattice>(
1730 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1731 UB_lat_ = std::make_unique<RectangularLattice<FourVector>>(
1732 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1733 FB_lat_ = std::make_unique<
1734 RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1735 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1737 if (potentials_->use_symmetry()) {
1738 jmu_I3_lat_ = std::make_unique<DensityLattice>(
1739 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1740 UI3_lat_ = std::make_unique<RectangularLattice<FourVector>>(
1741 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1742 FI3_lat_ = std::make_unique<
1743 RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1744 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1746 if (potentials_->use_coulomb()) {
1747 jmu_el_lat_ = std::make_unique<DensityLattice>(
1748 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1749 EM_lat_ = std::make_unique<
1750 RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1751 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1753 if (potentials_->use_vdf()) {
1754 jmu_B_lat_ = std::make_unique<DensityLattice>(
1755 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1756 UB_lat_ = std::make_unique<RectangularLattice<FourVector>>(
1757 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1758 FB_lat_ = std::make_unique<
1759 RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1760 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1764 old_fields_auxiliary_ =
1765 std::make_unique<RectangularLattice<FourVector>>(
1766 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1767 new_fields_auxiliary_ =
1768 std::make_unique<RectangularLattice<FourVector>>(
1769 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1770 fields_four_gradient_auxiliary_ =
1771 std::make_unique<RectangularLattice<std::array<FourVector, 4>>>(
1772 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1775 fields_lat_ = std::make_unique<FieldsLattice>(
1776 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1779 if (dens_type_lattice_printout_ == DensityType::Baryon && !jmu_B_lat_) {
1780 jmu_B_lat_ = std::make_unique<DensityLattice>(l,
n, origin, periodic,
1781 LatticeUpdate::AtOutput);
1783 if (dens_type_lattice_printout_ == DensityType::BaryonicIsospin &&
1785 jmu_I3_lat_ = std::make_unique<DensityLattice>(l,
n, origin, periodic,
1786 LatticeUpdate::AtOutput);
1788 if (dens_type_lattice_printout_ != DensityType::None &&
1789 dens_type_lattice_printout_ != DensityType::BaryonicIsospin &&
1790 dens_type_lattice_printout_ != DensityType::Baryon) {
1791 jmu_custom_lat_ = std::make_unique<DensityLattice>(
1792 l,
n, origin, periodic, LatticeUpdate::AtOutput);
1794 }
else if (printout_lattice_td_ || printout_full_lattice_any_td_) {
1796 "If you want Therm. VTK or Lattice output, configure a lattice for "
1798 }
else if (potentials_ && potentials_->use_coulomb()) {
1800 "Coulomb potential requires a lattice. Please add one to the "
1805 if ((potentials_ !=
nullptr) && (jmu_B_lat_ ==
nullptr)) {
1806 logg[
LExperiment].warn() <<
"Lattice is NOT used. Mean-field energy is "
1807 <<
"not going to be calculated.";
1811 if (parameters_.potential_affect_threshold) {
1819 (jmu_B_lat_ ==
nullptr)) {
1820 throw std::runtime_error(
1821 "Lattice is necessary to calculate finite difference gradients.");
1825 if (config.
has_value({
"Forced_Thermalization"})) {
1826 Configuration th_conf =
1828 thermalizer_ = modus_.create_grandcan_thermalizer(th_conf);
1833 seed_ = config.
take({
"General",
"Randomseed"});
1864 uint64_t scatterings_this_interval,
1867 double E_mean_field,
1868 double E_mean_field_initial);
1905 double E_mean_field,
double modus_impact_parameter,
1907 bool projectile_target_interact,
1908 bool kinematic_cut_for_SMASH_IC);
1910 template <
typename Modus>
1920 while (r == INT64_MIN) {
1923 seed_ = std::abs(r);
1928 if (process_string_ptr_ != NULL) {
1929 process_string_ptr_->init_pythia_hadron_rndm();
1932 for (
Particles &particles : ensembles_) {
1937 double start_time = -1.0;
1941 if (modus_.is_collider()) {
1942 modus_.sample_impact();
1943 logg[
LExperiment].info(
"Impact parameter = ", modus_.impact_parameter(),
1946 for (
Particles &particles : ensembles_) {
1947 start_time = modus_.initial_conditions(&particles, parameters_);
1952 for (
Particles &particles : ensembles_) {
1953 modus_.impose_boundary_conditions(&particles, outputs_);
1956 double timestep = delta_time_startup_;
1958 switch (time_step_mode_) {
1962 timestep = end_time_ - start_time;
1964 const double max_dt = modus_.max_timestep(max_transverse_distance_sqr_);
1965 if (max_dt > 0. && max_dt < timestep) {
1970 std::unique_ptr<UniformClock> clock_for_this_event;
1971 if (modus_.is_list() && (timestep < 0.0)) {
1972 throw std::runtime_error(
1973 "Timestep for the given event is negative. \n"
1974 "This might happen if the formation times of the input particles are "
1975 "larger than the specified end time of the simulation.");
1977 clock_for_this_event =
1978 std::make_unique<UniformClock>(start_time, timestep, end_time_);
1979 parameters_.labclock = std::move(clock_for_this_event);
1982 parameters_.outputclock->reset(start_time,
true);
1984 parameters_.outputclock->remove_times_in_past(start_time);
1987 "Lab clock: t_start = ", parameters_.labclock->current_time(),
1988 ", dt = ", parameters_.labclock->timestep_duration());
1993 wall_actions_total_ = 0;
1994 previous_wall_actions_total_ = 0;
1995 interactions_total_ = 0;
1996 previous_interactions_total_ = 0;
1997 discarded_interactions_total_ = 0;
1998 total_pauli_blocked_ = 0;
1999 projectile_target_interact_.assign(parameters_.n_ensembles,
false);
2000 total_hypersurface_crossing_actions_ = 0;
2001 total_energy_removed_ = 0.0;
2002 total_energy_violated_by_Pythia_ = 0.0;
2005 logg[
LExperiment].info() <<
"Time[fm] Ekin[GeV] E_MF[GeV] ETotal[GeV] "
2006 <<
"ETot/N[GeV] D(ETot/N)[GeV] Scatt&Decays "
2007 <<
"Particles Comp.Time";
2009 double E_mean_field = 0.0;
2014 if ((jmu_B_lat_ !=
nullptr)) {
2016 new_jmu_auxiliary_.get(), four_gradient_auxiliary_.get(),
2017 LatticeUpdate::EveryTimestep, DensityType::Baryon,
2018 density_param_, ensembles_,
2019 parameters_.labclock->timestep_duration(),
true);
2023 for (
auto &node : *jmu_B_lat_) {
2024 node.overwrite_drho_dt_to_zero();
2025 node.overwrite_djmu_dt_to_zero();
2028 EM_lat_.get(), parameters_);
2031 initial_mean_field_energy_ = E_mean_field;
2033 ensembles_, 0u, conserved_initial_, time_start_,
2034 parameters_.labclock->current_time(), E_mean_field,
2035 initial_mean_field_energy_);
2038 for (
const auto &output : outputs_) {
2039 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2041 ensembles_, E_mean_field, modus_.impact_parameter(), parameters_,
2042 projectile_target_interact_[i_ens], kinematic_cuts_for_IC_output_);
2043 output->at_eventstart(ensembles_[i_ens],
2045 event_ * parameters_.n_ensembles + i_ens,
2049 output->at_eventstart(ensembles_, event_);
2051 if (printout_full_lattice_any_td_) {
2052 if (printout_rho_eckart_) {
2053 switch (dens_type_lattice_printout_) {
2054 case DensityType::Baryon:
2056 DensityType::Baryon, *jmu_B_lat_);
2058 case DensityType::BaryonicIsospin:
2060 DensityType::BaryonicIsospin, *jmu_I3_lat_);
2062 case DensityType::None:
2066 DensityType::BaryonicIsospin,
2070 if (printout_tmn_) {
2072 dens_type_lattice_printout_, *Tmn_);
2074 if (printout_tmn_landau_) {
2076 dens_type_lattice_printout_, *Tmn_);
2078 if (printout_v_landau_) {
2080 dens_type_lattice_printout_, *Tmn_);
2082 if (printout_j_QBS_) {
2084 dens_type_lattice_printout_, *j_QBS_lat_);
2096 const double m = particle.effective_mass();
2097 double v_beam = 0.0;
2098 if (particle.belongs_to() == BelongsTo::Projectile) {
2099 v_beam = modus_.velocity_projectile();
2100 }
else if (particle.belongs_to() == BelongsTo::Target) {
2101 v_beam = modus_.velocity_target();
2103 const double gamma = 1.0 / std::sqrt(1.0 - v_beam * v_beam);
2104 beam_momentum_.emplace_back(
2105 FourVector(gamma * m, 0.0, 0.0, gamma * v_beam * m));
2110 template <
typename Modus>
2112 bool include_pauli_blocking) {
2113 Particles &particles = ensembles_[i_ensemble];
2116 discarded_interactions_total_++;
2118 " (discarded: invalid)");
2123 }
catch (Action::StochasticBelowEnergyThreshold &) {
2127 if (include_pauli_blocking && pauli_blocker_ &&
2129 total_pauli_blocked_++;
2135 if (modus_.is_collider()) {
2136 int count_target = 0, count_projectile = 0;
2138 if (incoming.belongs_to() == BelongsTo::Projectile) {
2140 }
else if (incoming.belongs_to() == BelongsTo::Target) {
2144 if (count_target > 0 && count_projectile > 0) {
2145 projectile_target_interact_[i_ensemble] =
true;
2151 const auto id_process =
static_cast<uint32_t
>(interactions_total_ + 1);
2153 total_energy_violated_by_Pythia_ += action.
perform(&particles, id_process);
2155 interactions_total_++;
2156 if (action.
get_type() == ProcessType::Wall) {
2157 wall_actions_total_++;
2159 if (action.
get_type() == ProcessType::HyperSurfaceCrossing) {
2160 total_hypersurface_crossing_actions_++;
2165 if (dens_type_ != DensityType::None) {
2167 constexpr
bool compute_grad =
false;
2168 const bool smearing =
true;
2171 rho = std::get<0>(
current_eckart(r_interaction.threevec(), particles,
2172 density_param_, dens_type_, compute_grad,
2190 for (
const auto &output : outputs_) {
2191 if (!output->is_dilepton_output() && !output->is_photon_output()) {
2192 if (output->is_IC_output() &&
2193 action.
get_type() == ProcessType::HyperSurfaceCrossing) {
2194 output->at_interaction(action, rho);
2195 }
else if (!output->is_IC_output()) {
2196 output->at_interaction(action, rho);
2206 if (photons_switch_ &&
2208 ScatterActionPhoton::is_kinematically_possible(
2212 constexpr
double action_time = 0.;
2214 n_fractional_photons_,
2230 photon_act.add_single_process();
2232 photon_act.perform_photons(outputs_);
2235 if (bremsstrahlung_switch_ &&
2236 BremsstrahlungAction::is_bremsstrahlung_reaction(
2240 constexpr
double action_time = 0.;
2243 n_fractional_photons_,
2260 brems_act.add_single_process();
2262 brems_act.perform_bremsstrahlung(outputs_);
2281 template <
typename Modus>
2283 ParticleList &&add_plist,
2284 ParticleList &&remove_plist) {
2285 if (!add_plist.empty() || !remove_plist.empty()) {
2286 if (ensembles_.size() > 1) {
2287 throw std::runtime_error(
2288 "Adding or removing particles from SMASH is only possible when one "
2289 "ensemble is used.");
2291 const double action_time = parameters_.labclock->current_time();
2295 if (!add_plist.empty()) {
2298 if (!add_plist.empty()) {
2300 auto action_add_particles = std::make_unique<FreeforallAction>(
2301 ParticleList{}, add_plist, action_time);
2302 perform_action(*action_add_particles, 0);
2305 if (!remove_plist.empty()) {
2308 if (!remove_plist.empty()) {
2309 ParticleList found_particles_to_remove;
2310 for (
const auto &particle_to_remove : remove_plist) {
2311 const auto iterator_to_particle_to_be_removed_in_ensemble =
2313 ensembles_[0].begin(), ensembles_[0].end(),
2314 [&particle_to_remove, &action_time](
const ParticleData &
p) {
2316 particle_to_remove,
p, action_time);
2318 if (iterator_to_particle_to_be_removed_in_ensemble !=
2319 ensembles_[0].end())
2320 found_particles_to_remove.push_back(
2321 *iterator_to_particle_to_be_removed_in_ensemble);
2325 std::sort(found_particles_to_remove.begin(),
2326 found_particles_to_remove.end(),
2328 return p1.id() < p2.id();
2330 const auto iterator_to_first_duplicate = std::adjacent_find(
2331 found_particles_to_remove.begin(), found_particles_to_remove.end(),
2333 return p1.id() == p2.id();
2335 if (iterator_to_first_duplicate != found_particles_to_remove.end()) {
2336 logg[
LExperiment].error() <<
"The same particle has been asked to be "
2337 "removed multiple times:\n"
2338 << *iterator_to_first_duplicate;
2339 throw std::logic_error(
"Particle cannot be removed twice!");
2341 if (
auto delta = remove_plist.size() - found_particles_to_remove.size();
2344 "When trying to remove particle(s) at the beginning ",
2345 "of the system evolution,\n", delta,
2346 " particle(s) could not be found and will be ignored.");
2348 if (!found_particles_to_remove.empty()) {
2349 [[maybe_unused]]
const auto number_particles_before_removal =
2350 ensembles_[0].size();
2352 auto action_remove_particles = std::make_unique<FreeforallAction>(
2353 found_particles_to_remove, ParticleList{}, action_time);
2354 perform_action(*action_remove_particles, 0);
2356 assert(number_particles_before_removal -
2357 found_particles_to_remove.size() ==
2358 ensembles_[0].size());
2363 if (t_end > end_time_) {
2365 <<
"Evolution asked to be run until " << t_end <<
" > " << end_time_
2366 <<
" and this cannot be done (because of how the clock works).";
2367 throw std::logic_error(
2368 "Experiment cannot evolve the system beyond End_Time.");
2370 while (*(parameters_.labclock) < t_end) {
2371 const double dt = parameters_.labclock->timestep_duration();
2372 logg[
LExperiment].debug(
"Timestepless propagation for next ", dt,
" fm.");
2376 thermalizer_->is_time_to_thermalize(parameters_.labclock)) {
2377 const bool ignore_cells_under_treshold =
true;
2380 thermalizer_->update_thermalizer_lattice(ensembles_, density_param_,
2381 ignore_cells_under_treshold);
2382 const double current_t = parameters_.labclock->current_time();
2383 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2384 thermalizer_->thermalize(ensembles_[i_ens], current_t,
2385 parameters_.testparticles);
2388 perform_action(th_act, i_ens);
2393 std::vector<Actions> actions(parameters_.n_ensembles);
2394 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2395 actions[i_ens].clear();
2396 if (ensembles_[i_ens].size() > 0 && action_finders_.size() > 0) {
2398 const double min_cell_length = compute_min_cell_length(dt);
2403 const bool include_unformed_particles = IC_output_switch_;
2405 use_grid_ ? modus_.create_grid(ensembles_[i_ens], min_cell_length,
2406 dt, parameters_.coll_crit,
2407 include_unformed_particles)
2408 : modus_.create_grid(ensembles_[i_ens], min_cell_length,
2409 dt, parameters_.coll_crit,
2410 include_unformed_particles,
2411 CellSizeStrategy::Largest);
2413 const double gcell_vol = grid.cell_volume();
2416 [&](
const ParticleList &search_list) {
2417 for (
const auto &finder : action_finders_) {
2418 actions[i_ens].insert(finder->find_actions_in_cell(
2419 search_list, dt, gcell_vol, beam_momentum_));
2422 [&](
const ParticleList &search_list,
2423 const ParticleList &neighbors_list) {
2424 for (
const auto &finder : action_finders_) {
2425 actions[i_ens].insert(finder->find_actions_with_neighbors(
2426 search_list, neighbors_list, dt, beam_momentum_));
2435 const double end_timestep_time = parameters_.labclock->next_time();
2436 while (next_output_time() < end_timestep_time) {
2437 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2438 run_time_evolution_timestepless(actions[i_ens], i_ens,
2439 next_output_time());
2441 ++(*parameters_.outputclock);
2443 intermediate_output();
2445 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2446 run_time_evolution_timestepless(actions[i_ens], i_ens, end_timestep_time);
2452 update_potentials();
2453 update_momenta(ensembles_, parameters_.labclock->timestep_duration(),
2454 *potentials_, FB_lat_.get(), FI3_lat_.get(), EM_lat_.get(),
2461 for (
Particles &particles : ensembles_) {
2466 ++(*parameters_.labclock);
2474 if (!potentials_ && !parameters_.strings_switch &&
2476 std::string err_msg = conserved_initial_.report_deviations(ensembles_);
2477 if (!err_msg.empty()) {
2479 throw std::runtime_error(
"Violation of conserved quantities!");
2484 if (pauli_blocker_) {
2486 "Interactions: Pauli-blocked/performed = ", total_pauli_blocked_,
"/",
2487 interactions_total_ - wall_actions_total_);
2491 template <
typename Modus>
2496 if (dilepton_finder_ !=
nullptr) {
2497 for (
const auto &output : outputs_) {
2498 dilepton_finder_->shine(particles, output.get(), dt);
2511 constexpr uint64_t max_uint32 = std::numeric_limits<uint32_t>::max();
2512 if (interactions_total >= max_uint32) {
2513 throw std::runtime_error(
"Integer overflow in total interaction number!");
2517 template <
typename Modus>
2519 Actions &actions,
int i_ensemble,
const double end_time_propagation) {
2520 Particles &particles = ensembles_[i_ensemble];
2522 "Timestepless propagation: ",
"Actions size = ", actions.
size(),
2523 ", end time = ", end_time_propagation);
2531 ActionPtr act = actions.
pop();
2532 if (!act->is_valid(particles)) {
2533 discarded_interactions_total_++;
2535 " (discarded: invalid)");
2539 ", action time = ", act->time_of_execution());
2542 propagate_and_shine(act->time_of_execution(), particles);
2549 act->update_incoming(particles);
2550 const bool performed = perform_action(*act, i_ensemble);
2560 const double end_time_timestep = parameters_.labclock->next_time();
2562 const double time_left = end_time_timestep - act->time_of_execution();
2563 const ParticleList &outgoing_particles = act->outgoing_particles();
2565 const double gcell_vol = 0.0;
2566 for (
const auto &finder : action_finders_) {
2568 actions.
insert(finder->find_actions_in_cell(outgoing_particles, time_left,
2569 gcell_vol, beam_momentum_));
2571 actions.
insert(finder->find_actions_with_surrounding_particles(
2572 outgoing_particles, particles, time_left, beam_momentum_));
2578 propagate_and_shine(end_time_propagation, particles);
2581 template <
typename Modus>
2583 const uint64_t wall_actions_this_interval =
2584 wall_actions_total_ - previous_wall_actions_total_;
2585 previous_wall_actions_total_ = wall_actions_total_;
2586 const uint64_t interactions_this_interval = interactions_total_ -
2587 previous_interactions_total_ -
2588 wall_actions_this_interval;
2589 previous_interactions_total_ = interactions_total_;
2590 double E_mean_field = 0.0;
2593 double computational_frame_time = 0.0;
2596 if ((jmu_B_lat_ !=
nullptr)) {
2598 EM_lat_.get(), parameters_);
2605 if (modus_.is_box()) {
2606 double tmp = (E_mean_field - initial_mean_field_energy_) /
2607 (E_mean_field + initial_mean_field_energy_);
2613 if (std::abs(tmp) > 0.01) {
2615 <<
"\n\n\n\t The mean field at t = "
2616 << parameters_.outputclock->current_time()
2617 <<
" [fm] differs from the mean field at t = 0:"
2618 <<
"\n\t\t initial_mean_field_energy_ = "
2619 << initial_mean_field_energy_ <<
" [GeV]"
2620 <<
"\n\t\t abs[(E_MF - E_MF(t=0))/(E_MF + E_MF(t=0))] = "
2622 <<
"\n\t\t E_MF/E_MF(t=0) = "
2623 << E_mean_field / initial_mean_field_energy_ <<
"\n\n";
2630 ensembles_, interactions_this_interval, conserved_initial_, time_start_,
2631 parameters_.outputclock->current_time(), E_mean_field,
2632 initial_mean_field_energy_);
2636 if (!(modus_.is_box() && parameters_.outputclock->current_time() <
2637 modus_.equilibration_time())) {
2638 for (
const auto &output : outputs_) {
2639 if (output->is_dilepton_output() || output->is_photon_output() ||
2640 output->is_IC_output()) {
2643 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2645 ensembles_, E_mean_field, modus_.impact_parameter(), parameters_,
2646 projectile_target_interact_[i_ens], kinematic_cuts_for_IC_output_);
2648 output->at_intermediate_time(ensembles_[i_ens], parameters_.outputclock,
2649 density_param_, event_info);
2650 computational_frame_time = event_info.current_time;
2653 output->at_intermediate_time(ensembles_, parameters_.outputclock,
2657 if (printout_rho_eckart_) {
2658 switch (dens_type_lattice_printout_) {
2659 case DensityType::Baryon:
2661 density_param_, ensembles_,
false);
2663 DensityType::Baryon, *jmu_B_lat_);
2664 output->thermodynamics_lattice_output(*jmu_B_lat_,
2665 computational_frame_time);
2667 case DensityType::BaryonicIsospin:
2669 DensityType::BaryonicIsospin, density_param_,
2672 DensityType::BaryonicIsospin,
2674 output->thermodynamics_lattice_output(*jmu_I3_lat_,
2675 computational_frame_time);
2677 case DensityType::None:
2681 dens_type_lattice_printout_, density_param_,
2684 dens_type_lattice_printout_,
2686 output->thermodynamics_lattice_output(*jmu_custom_lat_,
2687 computational_frame_time);
2690 if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
2692 density_param_, ensembles_,
false);
2693 if (printout_tmn_) {
2695 dens_type_lattice_printout_, *Tmn_);
2696 output->thermodynamics_lattice_output(
2699 if (printout_tmn_landau_) {
2701 dens_type_lattice_printout_, *Tmn_);
2702 output->thermodynamics_lattice_output(
2704 computational_frame_time);
2706 if (printout_v_landau_) {
2708 dens_type_lattice_printout_, *Tmn_);
2709 output->thermodynamics_lattice_output(
2711 computational_frame_time);
2715 output->fields_output(
"Efield",
"Bfield", *EM_lat_);
2717 if (printout_j_QBS_) {
2718 output->thermodynamics_lattice_output(
2719 *j_QBS_lat_, computational_frame_time, ensembles_, density_param_);
2723 output->thermodynamics_output(*thermalizer_);
2729 template <
typename Modus>
2732 if (potentials_->use_symmetry() && jmu_I3_lat_ !=
nullptr) {
2734 new_jmu_auxiliary_.get(), four_gradient_auxiliary_.get(),
2735 LatticeUpdate::EveryTimestep, DensityType::BaryonicIsospin,
2736 density_param_, ensembles_,
2737 parameters_.labclock->timestep_duration(),
true);
2739 if ((potentials_->use_skyrme() || potentials_->use_symmetry()) &&
2740 jmu_B_lat_ !=
nullptr) {
2742 new_jmu_auxiliary_.get(), four_gradient_auxiliary_.get(),
2743 LatticeUpdate::EveryTimestep, DensityType::Baryon,
2744 density_param_, ensembles_,
2745 parameters_.labclock->timestep_duration(),
true);
2746 const size_t UBlattice_size = UB_lat_->size();
2747 for (
size_t i = 0; i < UBlattice_size; i++) {
2748 auto jB = (*jmu_B_lat_)[i];
2752 double baryon_density = jB.rho();
2756 if (potentials_->use_skyrme()) {
2758 flow_four_velocity_B * potentials_->skyrme_pot(baryon_density);
2760 potentials_->skyrme_force(baryon_density, baryon_grad_j0,
2761 baryon_dvecj_dt, baryon_curl_vecj);
2763 if (potentials_->use_symmetry() && jmu_I3_lat_ !=
nullptr) {
2764 auto jI3 = (*jmu_I3_lat_)[i];
2767 ? jI3.jmu_net() / jI3.rho()
2769 (*UI3_lat_)[i] = flow_four_velocity_I3 *
2770 potentials_->symmetry_pot(jI3.rho(), baryon_density);
2771 (*FI3_lat_)[i] = potentials_->symmetry_force(
2772 jI3.rho(), jI3.grad_j0(), jI3.dvecj_dt(), jI3.curl_vecj(),
2773 baryon_density, baryon_grad_j0, baryon_dvecj_dt,
2778 if (potentials_->use_coulomb()) {
2780 DensityType::Charge, density_param_, ensembles_,
true);
2781 for (
size_t i = 0; i < EM_lat_->size(); i++) {
2783 ThreeVector position = jmu_el_lat_->cell_center(i);
2784 jmu_el_lat_->integrate_volume(electric_field,
2785 Potentials::E_field_integrand,
2786 potentials_->coulomb_r_cut(), position);
2788 jmu_el_lat_->integrate_volume(magnetic_field,
2789 Potentials::B_field_integrand,
2790 potentials_->coulomb_r_cut(), position);
2791 (*EM_lat_)[i] = std::make_pair(electric_field, magnetic_field);
2794 if (potentials_->use_vdf() && jmu_B_lat_ !=
nullptr) {
2796 new_jmu_auxiliary_.get(), four_gradient_auxiliary_.get(),
2797 LatticeUpdate::EveryTimestep, DensityType::Baryon,
2798 density_param_, ensembles_,
2799 parameters_.labclock->timestep_duration(),
true);
2802 fields_lat_.get(), old_fields_auxiliary_.get(),
2803 new_fields_auxiliary_.get(), fields_four_gradient_auxiliary_.get(),
2804 jmu_B_lat_.get(), LatticeUpdate::EveryTimestep, *potentials_,
2805 parameters_.labclock->timestep_duration());
2807 const size_t UBlattice_size = UB_lat_->size();
2808 for (
size_t i = 0; i < UBlattice_size; i++) {
2809 auto jB = (*jmu_B_lat_)[i];
2810 (*UB_lat_)[i] = potentials_->vdf_pot(jB.rho(), jB.jmu_net());
2811 switch (parameters_.field_derivatives_mode) {
2813 (*FB_lat_)[i] = potentials_->vdf_force(
2814 jB.rho(), jB.drho_dxnu().x0(), jB.drho_dxnu().threevec(),
2815 jB.grad_rho_cross_vecj(), jB.jmu_net().x0(), jB.grad_j0(),
2816 jB.jmu_net().threevec(), jB.dvecj_dt(), jB.curl_vecj());
2819 auto Amu = (*fields_lat_)[i];
2820 (*FB_lat_)[i] = potentials_->vdf_force(
2821 Amu.grad_A0(), Amu.dvecA_dt(), Amu.curl_vecA());
2829 template <
typename Modus>
2833 bool actions_performed, decays_found;
2834 uint64_t interactions_old;
2836 decays_found =
false;
2837 interactions_old = interactions_total_;
2838 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2842 if (dilepton_finder_ !=
nullptr) {
2843 for (
const auto &output : outputs_) {
2844 dilepton_finder_->shine_final(ensembles_[i_ens], output.get(),
true);
2848 for (
const auto &finder : action_finders_) {
2849 auto found_actions = finder->find_final_actions(ensembles_[i_ens]);
2850 if (!found_actions.empty()) {
2851 actions.
insert(std::move(found_actions));
2852 decays_found =
true;
2857 perform_action(*actions.
pop(), i_ens,
false);
2860 actions_performed = interactions_total_ > interactions_old;
2862 if (decays_found && !actions_performed) {
2863 throw std::runtime_error(
"Final decays were found but not performed.");
2866 }
while (actions_performed);
2869 if (dilepton_finder_ !=
nullptr) {
2870 for (
const auto &output : outputs_) {
2871 for (
Particles &particles : ensembles_) {
2872 dilepton_finder_->shine_final(particles, output.get(),
false);
2878 template <
typename Modus>
2883 double E_mean_field = 0.0;
2884 if (
likely(parameters_.labclock > 0)) {
2885 const uint64_t wall_actions_this_interval =
2886 wall_actions_total_ - previous_wall_actions_total_;
2887 const uint64_t interactions_this_interval = interactions_total_ -
2888 previous_interactions_total_ -
2889 wall_actions_this_interval;
2892 if ((jmu_B_lat_ !=
nullptr)) {
2894 EM_lat_.get(), parameters_);
2897 if (std::abs(parameters_.labclock->current_time() - end_time_) >
2900 <<
"SMASH not propagated until configured end time. Current time = "
2901 << parameters_.labclock->current_time()
2902 <<
"fm. End time = " << end_time_ <<
"fm.";
2905 ensembles_, interactions_this_interval, conserved_initial_,
2906 time_start_, end_time_, E_mean_field, initial_mean_field_energy_);
2908 int total_particles = 0;
2909 for (
const Particles &particles : ensembles_) {
2910 total_particles += particles.
size();
2912 if (IC_output_switch_ && (total_particles == 0)) {
2913 const double initial_system_energy_plus_Pythia_violations =
2914 conserved_initial_.momentum().x0() + total_energy_violated_by_Pythia_;
2915 const double fraction_of_total_system_energy_removed =
2916 initial_system_energy_plus_Pythia_violations / total_energy_removed_;
2919 if (std::fabs(fraction_of_total_system_energy_removed - 1.) >
2921 throw std::runtime_error(
2922 "There is remaining energy in the system although all particles "
2925 std::to_string((initial_system_energy_plus_Pythia_violations -
2926 total_energy_removed_)) +
2931 <<
"Time real: " << SystemClock::now() - time_start_;
2933 <<
"Interactions before reaching hypersurface: "
2934 << interactions_total_ - wall_actions_total_ -
2935 total_hypersurface_crossing_actions_;
2937 <<
"Total number of particles removed on hypersurface: "
2938 << total_hypersurface_crossing_actions_;
2941 const double precent_discarded =
2942 interactions_total_ > 0
2943 ?
static_cast<double>(discarded_interactions_total_) * 100.0 /
2946 std::stringstream msg_discarded;
2948 <<
"Discarded interaction number: " << discarded_interactions_total_
2949 <<
" (" << precent_discarded
2950 <<
"% of the total interaction number including wall crossings)";
2954 <<
"Time real: " << SystemClock::now() - time_start_;
2958 precent_discarded > 1.0) {
2961 << msg_discarded.str()
2962 <<
"\nThe number of discarded interactions is large, which means "
2963 "the assumption for the stochastic criterion of\n1 interaction "
2964 "per particle per timestep is probably violated. Consider "
2965 "reducing the timestep size.";
2969 << interactions_total_ - wall_actions_total_;
2973 int unformed_particles_count = 0;
2974 for (
const Particles &particles : ensembles_) {
2976 if (particle.formation_time() > end_time_) {
2977 unformed_particles_count++;
2981 if (unformed_particles_count > 0) {
2983 "End time might be too small. ", unformed_particles_count,
2984 " unformed particles were found at the end of the evolution.");
2989 count_nonempty_ensembles();
2991 for (
const auto &output : outputs_) {
2992 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2994 ensembles_, E_mean_field, modus_.impact_parameter(), parameters_,
2995 projectile_target_interact_[i_ens], kinematic_cuts_for_IC_output_);
2996 output->at_eventend(ensembles_[i_ens],
2998 event_ * parameters_.n_ensembles + i_ens, event_info);
3001 output->at_eventend(ensembles_, event_);
3004 if (printout_rho_eckart_) {
3005 if (dens_type_lattice_printout_ != DensityType::None) {
3007 dens_type_lattice_printout_);
3011 if (printout_tmn_) {
3013 dens_type_lattice_printout_);
3016 if (printout_tmn_landau_) {
3018 dens_type_lattice_printout_);
3021 if (printout_v_landau_) {
3023 dens_type_lattice_printout_);
3026 if (printout_j_QBS_) {
3032 template <
typename Modus>
3034 for (
bool has_interaction : projectile_target_interact_) {
3035 if (has_interaction) {
3036 nonempty_ensembles_++;
3041 template <
typename Modus>
3044 return event_ >= nevents_;
3047 if (nonempty_ensembles_ >= minimum_nonempty_ensembles_) {
3050 if (event_ >= max_events_) {
3052 <<
"Maximum number of events (" << max_events_
3053 <<
") exceeded. Stopping calculation. "
3054 <<
"The fraction of empty ensembles is "
3055 << (1.0 -
static_cast<double>(nonempty_ensembles_) /
3056 (event_ * parameters_.n_ensembles))
3057 <<
". If this fraction is expected, try increasing the "
3058 "Maximum_Ensembles_Run.";
3063 throw std::runtime_error(
"Event counting option is invalid");
3067 template <
typename Modus>
3072 template <
typename Modus>
3075 for (event_ = 0; !is_finished(); event_++) {
3076 mainlog.info() <<
"Event " << event_;
3079 initialize_new_event();
3081 run_time_evolution(end_time_);
3083 if (force_decays_) {
Collection of useful type aliases to measure and output the (real) runtime.
A stream modifier that allows to colorize the log output.
Action is the base class for a generic process that takes a number of incoming particles and transfor...
virtual ProcessType get_type() const
Get the process type.
virtual double get_total_weight() const =0
Return the total weight value, which is mainly used for the weight output entry.
virtual double perform(Particles *particles, uint32_t id_process)
Actually perform the action, e.g.
const ParticleList & incoming_particles() const
Get the list of particles that go into the action.
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].
FourVector get_interaction_point() const
Get the interaction point.
bool is_valid(const Particles &particles) const
Check whether the action still applies.
bool is_pauli_blocked(const std::vector< Particles > &ensembles, const PauliBlocker &p_bl) const
Check if the action is Pauli-blocked.
The Actions class abstracts the storage and manipulation of actions.
ActionPtr pop()
Return the first action in the list and removes it from the list.
double earliest_time() const
Return time of execution of earliest action.
ActionList::size_type size() const
void insert(ActionList &&new_acts)
Insert a list of actions into this object.
Interface to the SMASH configuration files.
bool has_value(std::initializer_list< const char * > keys) const
Return whether there is a non-empty value behind the requested keys.
void set_value(std::initializer_list< const char * > keys, T &&value)
Overwrite the value of the specified YAML node.
Configuration extract_sub_configuration(std::initializer_list< const char * > keys, Configuration::GetEmpty empty_if_not_existing=Configuration::GetEmpty::No)
Create a new configuration from a then-removed section of the present object.
Value take(std::initializer_list< const char * > keys)
The default interface for SMASH to read configuration values.
Value read(std::initializer_list< const char * > keys) const
Additional interface for SMASH to read configuration values without removing them.
A class to pre-calculate and store parameters relevant for density calculation.
Non-template interface to Experiment<Modus>.
static std::unique_ptr< ExperimentBase > create(Configuration &config, const std::filesystem::path &output_path)
Factory method that creates and initializes a new Experiment<Modus>.
virtual ~ExperimentBase()=default
The virtual destructor avoids undefined behavior when destroying derived objects.
virtual void run()=0
Runs the experiment.
The main class, where the simulation of an experiment is executed.
const bool bremsstrahlung_switch_
This indicates whether bremsstrahlung is switched on.
void propagate_and_shine(double to_time, Particles &particles)
Propagate all particles until time to_time without any interactions and shine dileptons.
Experiment(Configuration &config, const std::filesystem::path &output_path)
Create a new Experiment.
const ExpansionProperties metric_
This struct contains information on the metric to be used.
std::unique_ptr< ActionFinderInterface > photon_finder_
The (Scatter) Actions Finder for Direct Photons.
const bool force_decays_
This indicates whether we force all resonances to decay in the last timestep.
double initial_mean_field_energy_
The initial total mean field energy in the system.
void create_output(const std::string &format, const std::string &content, const std::filesystem::path &output_path, const OutputParameters &par)
Create a list of output files.
std::vector< std::unique_ptr< ActionFinderInterface > > action_finders_
The Action finder objects.
bool printout_tmn_
Whether to print the energy-momentum tensor.
QuantumNumbers conserved_initial_
The conserved quantities of the system.
DensityParameters density_param_
Structure to precalculate and hold parameters for density computations.
double next_output_time() const
Shortcut for next output time.
double total_energy_removed_
Total energy removed from the system in hypersurface crossing actions.
DensityType dens_type_lattice_printout_
Type of density for lattice printout.
double max_transverse_distance_sqr_
Maximal distance at which particles can interact in case of the geometric criterion,...
bool printout_j_QBS_
Whether to print the Q, B, S 4-currents.
std::unique_ptr< GrandCanThermalizer > thermalizer_
Instance of class used for forced thermalization.
void count_nonempty_ensembles()
Counts the number of ensembles in wich interactions took place at the end of an event.
const TimeStepMode time_step_mode_
This indicates whether to use time steps.
std::unique_ptr< DensityLattice > jmu_custom_lat_
Custom density on the lattices.
bool printout_full_lattice_any_td_
Whether to print the thermodynamics quantities evaluated on the lattices, point by point,...
void increase_event_number()
Increases the event number by one.
void run_time_evolution_timestepless(Actions &actions, int i_ensemble, const double end_time_propagation)
Performs all the propagations and actions during a certain time interval neglecting the influence of ...
Particles * first_ensemble()
Provides external access to SMASH particles.
void run_time_evolution(const double t_end, ParticleList &&add_plist={}, ParticleList &&remove_plist={})
Runs the time evolution of an event with fixed-size time steps or without timesteps,...
int minimum_nonempty_ensembles_
The number of ensembles, in which interactions take place, to be calculated.
std::unique_ptr< DensityLattice > jmu_B_lat_
Baryon density on the lattice.
DensityType dens_type_
Type of density to be written to collision headers.
const int nevents_
Number of events.
void intermediate_output()
Intermediate output during an event.
std::vector< FourVector > beam_momentum_
The initial nucleons in the ColliderModus propagate with beam_momentum_, if Fermi motion is frozen.
std::unique_ptr< RectangularLattice< std::pair< ThreeVector, ThreeVector > > > FI3_lat_
Lattices for the electric and magnetic component of the symmetry force.
std::unique_ptr< RectangularLattice< FourVector > > new_jmu_auxiliary_
Auxiliary lattice for values of jmu at a time step t0 + dt.
double compute_min_cell_length(double dt) const
Calculate the minimal size for the grid cells such that the ScatterActionsFinder will find all collis...
void initialize_new_event()
This is called in the beginning of each event.
bool is_finished()
Checks wether the desired number events have been calculated.
int n_fractional_photons_
Number of fractional photons produced per single reaction.
const double delta_time_startup_
The clock's timestep size at start up.
std::unique_ptr< RectangularLattice< EnergyMomentumTensor > > Tmn_
Lattices of energy-momentum tensors for printout.
std::vector< Particles > ensembles_
Complete particle list, all ensembles in one vector.
std::unique_ptr< RectangularLattice< FourVector > > new_fields_auxiliary_
Auxiliary lattice for values of Amu at a time step t0 + dt.
SystemTimePoint time_start_
system starting time of the simulation
uint64_t previous_wall_actions_total_
Total number of wall-crossings for previous timestep.
std::unique_ptr< RectangularLattice< std::pair< ThreeVector, ThreeVector > > > FB_lat_
Lattices for the electric and magnetic components of the Skyrme or VDF force.
OutputsList outputs_
A list of output formaters.
bool printout_rho_eckart_
Whether to print the Eckart rest frame density.
std::unique_ptr< RectangularLattice< std::array< FourVector, 4 > > > fields_four_gradient_auxiliary_
Auxiliary lattice for calculating the four-gradient of Amu.
void do_final_decays()
Performs the final decays of an event.
std::unique_ptr< PauliBlocker > pauli_blocker_
An instance of PauliBlocker class that stores parameters needed for Pauli blocking calculations and c...
bool printout_v_landau_
Whether to print the 4-velocity in Landau frame.
bool perform_action(Action &action, int i_ensemble, bool include_pauli_blocking=true)
Perform the given action.
std::unique_ptr< RectangularLattice< FourVector > > UI3_lat_
Lattices for symmetry potentials (evaluated in the local rest frame) times the isospin flow 4-velocit...
bool printout_lattice_td_
Whether to print the thermodynamics quantities evaluated on the lattices.
std::unique_ptr< RectangularLattice< std::pair< ThreeVector, ThreeVector > > > EM_lat_
Lattices for electric and magnetic field in fm^-2.
std::unique_ptr< FieldsLattice > fields_lat_
Mean-field A^mu on the lattice.
int max_events_
Maximum number of events to be calculated in order obtain the desired number of non-empty events usin...
int nonempty_ensembles_
Number of ensembles containing an interaction.
OutputPtr photon_output_
The Photon output.
EventCounting event_counting_
The way in which the number of calculated events is specified.
const bool dileptons_switch_
This indicates whether dileptons are switched on.
Modus modus_
Instance of the Modus template parameter.
std::unique_ptr< RectangularLattice< FourVector > > old_jmu_auxiliary_
Auxiliary lattice for values of jmu at a time step t0.
std::unique_ptr< DecayActionsFinderDilepton > dilepton_finder_
The Dilepton Action Finder.
std::unique_ptr< DensityLattice > j_QBS_lat_
4-current for j_QBS lattice output
bool printout_tmn_landau_
Whether to print the energy-momentum tensor in Landau frame.
std::unique_ptr< RectangularLattice< std::array< FourVector, 4 > > > four_gradient_auxiliary_
Auxiliary lattice for calculating the four-gradient of jmu.
const bool photons_switch_
This indicates whether photons are switched on.
StringProcess * process_string_ptr_
Pointer to the string process class object, which is used to set the random seed for PYTHIA objects i...
std::unique_ptr< RectangularLattice< FourVector > > UB_lat_
Lattices for Skyrme or VDF potentials (evaluated in the local rest frame) times the baryon flow 4-vel...
ExperimentParameters parameters_
Struct of several member variables.
std::unique_ptr< RectangularLattice< FourVector > > old_fields_auxiliary_
Auxiliary lattice for values of Amu at a time step t0.
std::unique_ptr< DensityLattice > jmu_el_lat_
Electric charge density on the lattice.
std::unique_ptr< Potentials > potentials_
An instance of potentials class, that stores parameters of potentials, calculates them and their grad...
uint64_t wall_actions_total_
Total number of wall-crossings for current timestep.
uint64_t total_hypersurface_crossing_actions_
Total number of particles removed from the evolution in hypersurface crossing actions.
uint64_t interactions_total_
Total number of interactions for current timestep.
const bool use_grid_
This indicates whether to use the grid.
std::unique_ptr< DensityLattice > jmu_I3_lat_
Isospin projection density on the lattice.
uint64_t total_pauli_blocked_
Total number of Pauli-blockings for current timestep.
void final_output()
Output at the end of an event.
std::vector< bool > projectile_target_interact_
Whether the projectile and the target collided.
Modus * modus()
Provides external access to SMASH calculation modus.
void update_potentials()
Recompute potentials on lattices if necessary.
const bool IC_output_switch_
This indicates whether the IC output is enabled.
OutputPtr dilepton_output_
The Dilepton output.
int64_t seed_
random seed for the next event.
std::vector< Particles > * all_ensembles()
Getter for all ensembles.
uint64_t previous_interactions_total_
Total number of interactions for previous timestep.
uint64_t discarded_interactions_total_
Total number of discarded interactions, because they were invalidated before they could be performed.
void run() override
Runs the experiment.
bool kinematic_cuts_for_IC_output_
This indicates whether kinematic cuts are enabled for the IC output.
const double end_time_
simulation time at which the evolution is stopped.
double total_energy_violated_by_Pythia_
Total energy violation introduced by Pythia.
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
default_type default_value() const
Get the default value of the key.
ParticleData contains the dynamic information of a certain particle.
static double formation_power_
Power with which the cross section scaling factor grows in time.
The Particles class abstracts the storage and manipulation of particles.
A class that stores parameters of potentials, calculates potentials and their gradients.
A container for storing conserved values.
A container class to hold all the arrays on the lattice and access them.
String excitation processes used in SMASH.
ThermalizationAction implements forced thermalization as an Action class.
bool any_particles_thermalized() const
This method checks, if there are particles in the region to be thermalized.
The ThreeVector class represents a physical three-vector with the components .
@ Frozen
Use fermi motion without potentials.
TimeStepMode
The time step mode.
@ Fixed
Use fixed time step.
@ None
Don't use time steps; propagate from action to action.
@ EckartDensity
Density in the Eckart frame.
@ Tmn
Energy-momentum tensor in lab frame.
@ LandauVelocity
Velocity of the Landau rest frame.
@ j_QBS
Electric (Q), baryonic (B) and strange (S) currents.
@ TmnLandau
Energy-momentum tensor in Landau rest frame.
@ BottomUp
Sum the existing partial contributions.
@ Stochastic
Stochastic Criteiron.
@ None
No pseudo-resonance is created.
EventCounting
Defines how the number of events is determined.
@ Invalid
Unused, only in the code for internal logic.
@ FixedNumber
The desired number of events is simulated disregarding of whether an interaction took place.
@ MinimumNonEmpty
Events are simulated until there are at least a given number of ensembles in which an interaction too...
#define SMASH_SOURCE_LOCATION
Hackery that is required to output the location in the source code where the log statement occurs.
std::ostream & operator<<(std::ostream &out, const ActionPtr &action)
Convenience: dereferences the ActionPtr to Action.
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
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...
std::unique_ptr< OutputInterface > create_oscar_output(const std::string &format, const std::string &content, const std::filesystem::path &path, const OutputParameters &out_par)
#define likely(x)
Tell the branch predictor that this expression is likely true.
Engine::result_type advance()
Advance the engine's state and return the generated value.
void set_seed(T &&seed)
Sets the seed of the random number engine.
static constexpr int LInitialConditions
void update_momenta(std::vector< Particles > &particles, double dt, const Potentials &pot, RectangularLattice< std::pair< ThreeVector, ThreeVector >> *FB_lat, RectangularLattice< std::pair< ThreeVector, ThreeVector >> *FI3_lat, RectangularLattice< std::pair< ThreeVector, ThreeVector >> *EM_lat, DensityLattice *jB_lat)
Updates the momenta of all particles at the current time step according to the equations of motion:
UnaryFunction for_each(Container &&c, UnaryFunction &&f)
Convenience wrapper for std::for_each that operates on a complete container.
EventInfo fill_event_info(const std::vector< Particles > &ensembles, double E_mean_field, double modus_impact_parameter, const ExperimentParameters ¶meters, bool projectile_target_interact, bool kinematic_cut_for_SMASH_IC)
Generate the EventInfo object which is passed to outputs_.
std::string format_measurements(const std::vector< Particles > &ensembles, uint64_t scatterings_this_interval, const QuantumNumbers &conserved_initial, SystemTimePoint time_start, double time, double E_mean_field, double E_mean_field_initial)
Generate a string which will be printed to the screen when SMASH is running.
void expand_space_time(Particles *particles, const ExperimentParameters ¶meters, const ExpansionProperties &metric)
Modifies positions and momentum of all particles to account for space-time deformation.
void update_lattice(RectangularLattice< T > *lat, const LatticeUpdate update, const DensityType dens_type, const DensityParameters &par, const std::vector< Particles > &ensembles, const bool compute_gradient)
Updates the contents on the lattice.
void check_interactions_total(uint64_t interactions_total)
Make sure interactions_total can be represented as a 32-bit integer.
std::tuple< double, FourVector, ThreeVector, ThreeVector, FourVector, FourVector, FourVector, FourVector > 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...
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.
ExperimentParameters create_experiment_parameters(Configuration &config)
Gathers all general Experiment parameters.
constexpr double very_small_double
A very small double, used to avoid division by zero.
double calculate_mean_field_energy(const Potentials &potentials, RectangularLattice< smash::DensityOnLattice > &jmu_B_lat, RectangularLattice< std::pair< ThreeVector, ThreeVector >> *em_lattice, const ExperimentParameters ¶meters)
Calculate the total mean field energy of the system; this will be printed to the screen when SMASH is...
static constexpr int LExperiment
void update_fields_lattice(RectangularLattice< FieldsOnLattice > *fields_lat, RectangularLattice< FourVector > *old_fields, RectangularLattice< FourVector > *new_fields, RectangularLattice< std::array< FourVector, 4 >> *fields_four_grad_lattice, DensityLattice *jmu_B_lat, const LatticeUpdate fields_lat_update, const Potentials &potentials, const double time_step)
Updates the contents on the lattice of FieldsOnLattice type.
bool are_particles_identical_at_given_time(const ParticleData &p1, const ParticleData &p2, double time)
Utility function to compare two ParticleData instances with respect to their PDG code,...
void validate_and_adjust_particle_list(ParticleList &particle_list)
Validate a particle list adjusting each particle to be a valid SMASH particle.
constexpr double nucleon_mass
Nucleon mass in GeV.
LatticeUpdate
Enumerator option for lattice updates.
std::ostream & operator<<(std::ostream &out, const Experiment< Modus > &e)
Creates a verbose textual description of the setup of the Experiment.
Potentials * pot_pointer
Pointer to a Potential class.
static constexpr int LMain
constexpr double really_small
Numerical error tolerance.
DensityType
Allows to choose which kind of density to calculate.
RectangularLattice< FourVector > * UB_lat_pointer
Pointer to the skyrme potential on the lattice.
std::chrono::time_point< std::chrono::system_clock > SystemTimePoint
Type (alias) that is used to store the current time.
const std::string hline(113, '-')
String representing a horizontal line.
RectangularLattice< FourVector > * UI3_lat_pointer
Pointer to the symmmetry potential on the lattice.
constexpr double fm2_mb
mb <-> fm^2 conversion factor.
Structure to contain custom data for output.
Struct containing the type of the metric and the expansion parameter of the metric.
Exception class that is thrown if an invalid modus is requested from the Experiment factory.
Exception class that is thrown if the requested output path in the Experiment factory is not existing...
Helper structure for Experiment.
double fixed_min_cell_length
Fixed minimal grid cell length (in fm).
const CollisionCriterion coll_crit
Employed collision criterion.
std::unique_ptr< Clock > outputclock
Output clock to keep track of the next output time.
Helper structure for Experiment to hold output options and parameters.
RivetOutputParameters rivet_parameters
Rivet specfic parameters.