7 #ifndef SRC_INCLUDE_SMASH_EXPERIMENT_H_
8 #define SRC_INCLUDE_SMASH_EXPERIMENT_H_
46 #ifdef SMASH_USE_HEPMC
49 #ifdef SMASH_USE_RIVET
74 template <
typename T,
typename Ratio>
76 const chrono::duration<T, Ratio> &seconds) {
77 using Seconds = chrono::duration<double>;
78 using Minutes = chrono::duration<double, std::ratio<60>>;
79 using Hours = chrono::duration<double, std::ratio<60 * 60>>;
80 constexpr Minutes threshold_for_minutes{10};
81 constexpr Hours threshold_for_hours{3};
82 if (seconds < threshold_for_minutes) {
83 return out << Seconds(seconds).count() <<
" [s]";
85 if (seconds < threshold_for_hours) {
86 return out << Minutes(seconds).count() <<
" [min]";
88 return out << Hours(seconds).count() <<
" [h]";
93 static constexpr
int LMain = LogArea::Main::id;
132 static std::unique_ptr<ExperimentBase>
create(
133 Configuration &config,
const std::filesystem::path &output_path);
149 using std::invalid_argument::invalid_argument;
158 using std::invalid_argument::invalid_argument;
162 template <
typename Modus>
164 template <
typename Modus>
191 template <
typename Modus>
218 const std::filesystem::path &output_path);
245 ParticleList &&remove_plist = {});
291 bool include_pauli_blocking =
true);
301 const std::filesystem::path &output_path,
326 const double end_time_propagation);
466 std::unique_ptr<RectangularLattice<FourVector>>
UB_lat_ =
nullptr;
472 std::unique_ptr<RectangularLattice<FourVector>>
UI3_lat_ =
nullptr;
478 std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
482 std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
486 std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
490 std::unique_ptr<RectangularLattice<EnergyMomentumTensor>>
Tmn_;
497 std::unique_ptr<RectangularLattice<std::array<FourVector, 4>>>
505 std::unique_ptr<RectangularLattice<std::array<FourVector, 4>>>
718 friend std::ostream &operator<<<>(std::ostream &out,
const Experiment &e);
722 template <
typename Modus>
724 out <<
"End time: " << e.
end_time_ <<
" fm\n";
729 template <
typename Modus>
731 const std::string &content,
732 const std::filesystem::path &output_path,
735 if (ensembles_.size() > 1) {
736 auto abort_because_of = [](
const std::string &s) {
737 throw std::invalid_argument(
738 s +
" output is not available with multiple parallel ensembles.");
740 if (content ==
"Initial_Conditions") {
741 abort_because_of(
"Initial_Conditions");
743 if ((
format ==
"HepMC") || (
format ==
"HepMC_asciiv3") ||
744 (
format ==
"HepMC_treeroot")) {
745 abort_because_of(
"HepMC");
747 if (content ==
"Rivet") {
748 abort_because_of(
"Rivet");
750 if (content ==
"Collisions") {
752 "Information coming from different ensembles in 'Collisions' output "
753 "is not distinguishable.\nSuch an output with multiple parallel "
754 "ensembles should only be used if later in the data analysis\nit is "
755 "not necessary to trace back which data belongs to which ensemble.");
759 if (
format ==
"VTK" && content ==
"Particles") {
760 outputs_.emplace_back(
761 std::make_unique<VtkOutput>(output_path, content, out_par));
762 }
else if (
format ==
"Root") {
763 #ifdef SMASH_USE_ROOT
764 if (content ==
"Initial_Conditions") {
765 outputs_.emplace_back(
766 std::make_unique<RootOutput>(output_path,
"SMASH_IC", out_par));
768 outputs_.emplace_back(
769 std::make_unique<RootOutput>(output_path, content, out_par));
773 "Root output requested, but Root support not compiled in");
775 }
else if ((
format ==
"Binary" ||
format ==
"Oscar2013_bin") &&
776 (content ==
"Collisions" || content ==
"Particles" ||
777 content ==
"Dileptons" || content ==
"Photons" ||
778 content ==
"Initial_Conditions")) {
779 outputs_.emplace_back(
781 }
else if (
format ==
"Oscar1999" ||
format ==
"Oscar2013") {
782 outputs_.emplace_back(
784 }
else if (
format ==
"ASCII" &&
785 (content ==
"Particles" || content ==
"Collisions" ||
786 content ==
"Dileptons" || content ==
"Photons" ||
787 content ==
"Initial_Conditions")) {
788 outputs_.emplace_back(
790 }
else if (content ==
"Thermodynamics" &&
format ==
"ASCII") {
791 outputs_.emplace_back(
792 std::make_unique<ThermodynamicOutput>(output_path, content, out_par));
793 }
else if (content ==
"Thermodynamics" &&
794 (
format ==
"Lattice_ASCII" ||
format ==
"Lattice_Binary")) {
795 printout_full_lattice_any_td_ =
true;
796 outputs_.emplace_back(std::make_unique<ThermodynamicLatticeOutput>(
797 output_path, content, out_par,
format ==
"Lattice_ASCII",
798 format ==
"Lattice_Binary"));
799 }
else if (content ==
"Thermodynamics" &&
format ==
"VTK") {
800 printout_lattice_td_ =
true;
801 outputs_.emplace_back(
802 std::make_unique<VtkOutput>(output_path, content, out_par));
803 }
else if (content ==
"Initial_Conditions" &&
format ==
"For_vHLLE") {
805 throw std::invalid_argument(
806 "Dynamic initial conditions are only available in Oscar2013 and "
809 outputs_.emplace_back(
810 std::make_unique<ICOutput>(output_path,
"SMASH_IC_For_vHLLE", out_par));
811 }
else if ((
format ==
"HepMC") || (
format ==
"HepMC_asciiv3") ||
812 (
format ==
"HepMC_treeroot")) {
813 #ifdef SMASH_USE_HEPMC
814 if (content ==
"Particles") {
815 if ((
format ==
"HepMC") || (
format ==
"HepMC_asciiv3")) {
816 outputs_.emplace_back(std::make_unique<HepMcOutput>(
817 output_path,
"SMASH_HepMC_particles",
false,
"asciiv3"));
818 }
else if (
format ==
"HepMC_treeroot") {
819 #ifdef SMASH_USE_HEPMC_ROOTIO
820 outputs_.emplace_back(std::make_unique<HepMcOutput>(
821 output_path,
"SMASH_HepMC_particles",
false,
"root"));
824 "Requested HepMC_treeroot output not available, "
825 "ROOT or HepMC3_ROOTIO missing or not found by cmake.");
828 }
else if (content ==
"Collisions") {
829 if ((
format ==
"HepMC") || (
format ==
"HepMC_asciiv3")) {
830 outputs_.emplace_back(std::make_unique<HepMcOutput>(
831 output_path,
"SMASH_HepMC_collisions",
true,
"asciiv3"));
832 }
else if (
format ==
"HepMC_treeroot") {
833 #ifdef SMASH_USE_HEPMC_ROOTIO
834 outputs_.emplace_back(std::make_unique<HepMcOutput>(
835 output_path,
"SMASH_HepMC_collisions",
true,
"root"));
838 "Requested HepMC_treeroot output not available, "
839 "ROOT or HepMC3_ROOTIO missing or not found by cmake.");
844 "HepMC only available for Particles and "
845 "Collisions content. Requested for " +
850 "HepMC output requested, but HepMC support not compiled in");
852 }
else if (content ==
"Coulomb" &&
format ==
"VTK") {
853 outputs_.emplace_back(
854 std::make_unique<VtkOutput>(output_path,
"Fields", out_par));
855 }
else if (content ==
"Rivet") {
856 #ifdef SMASH_USE_RIVET
858 static bool rivet_format_already_selected =
false;
860 if (rivet_format_already_selected) {
862 "Rivet output format can only be one, either YODA or YODA-full. "
863 "Only your first valid choice will be used.");
867 outputs_.emplace_back(std::make_unique<RivetOutput>(
869 rivet_format_already_selected =
true;
870 }
else if (
format ==
"YODA-full") {
871 outputs_.emplace_back(std::make_unique<RivetOutput>(
873 rivet_format_already_selected =
true;
876 "not one of YODA or YODA-full");
880 "Rivet output requested, but Rivet support not compiled in");
884 <<
"Unknown combination of format (" <<
format <<
") and content ("
885 << content <<
"). Fix the config.";
888 logg[
LExperiment].info() <<
"Added output " << content <<
" of format "
901 template <
typename Modus>
903 const std::filesystem::path &output_path)
906 modus_(std::invoke([&]() {
916 const bool restore_key = config.
has_value(key);
917 const bool temporary_taken_key = config.
take(key);
921 config.
set_value(key, temporary_taken_key);
923 return Modus{std::move(modus_config),
parameters_};
925 ensembles_(parameters_.n_ensembles),
927 delta_time_startup_(parameters_.labclock->timestep_duration()),
935 bremsstrahlung_switch_(
938 modus_.is_IC_for_hybrid()),
939 IC_dynamic_(IC_switch_ ? (modus_.IC_parameters().type ==
946 const bool user_wants_min_nonempty =
948 if (user_wants_nevents == user_wants_min_nonempty) {
949 throw std::invalid_argument(
950 "Please specify either Nevents or Minimum_Nonempty_Ensembles.");
952 if (user_wants_nevents) {
957 minimum_nonempty_ensembles_ =
961 max_events_ = numeric_cast<int>(std::ceil(
962 static_cast<double>(max_ensembles) / parameters_.n_ensembles));
968 throw std::invalid_argument(
969 "Covariant Gaussian derivatives only make sense for Covariant Gaussian "
977 parameters_.discrete_weight < (1. / 7.)) {
978 throw std::invalid_argument(
979 "The central weight for discrete smearing should be >= 1./7.");
984 throw std::invalid_argument(
985 "The stochastic criterion can only be employed for fixed time step "
986 "mode and with a grid!");
990 throw std::invalid_argument(
991 "The box modus can only be used with the fixed time step mode!");
995 " testparticles per particle.");
997 " parallel ensembles.");
1002 "To preserve detailed balance in a box simulation, it is recommended\n"
1003 "to use the bottom-up strategy for evaluating total cross sections.\n"
1004 "Consider adding the following line to the 'Collision_Term' section "
1005 "in your configuration file:\n"
1006 " Total_Cross_Section_Strategy: \"BottomUp\"");
1011 "To preserve detailed balance in a box simulation, it is recommended "
1012 "to not include the pseudoresonances,\nas they artificially increase "
1013 "the resonance production without changing the corresponding "
1014 "decay.\nConsider adding the following line to the 'Collision_Term' "
1015 "section in your configuration file:\n Pseudoresonance: \"None\"");
1019 if (IC_output != modus_.is_IC_for_hybrid()) {
1020 throw std::invalid_argument(
1021 "The 'Initial_Conditions' subsection must be present in both 'Output' "
1022 "and 'Modi: Collider' sections.");
1035 modus_.sqrt_s_NN() >= 200. ? -1. : 1.);
1038 if (dileptons_switch_) {
1039 dilepton_finder_ = std::make_unique<DecayActionsFinderDilepton>();
1041 if (photons_switch_ || bremsstrahlung_switch_) {
1042 n_fractional_photons_ =
1045 if (parameters_.two_to_one) {
1046 if (parameters_.res_lifetime_factor < 0.) {
1047 throw std::invalid_argument(
1048 "Resonance lifetime modifier cannot be negative!");
1052 "Resonance lifetime set to zero. Make sure resonances cannot "
1054 "inelastically (e.g. resonance chains), else SMASH is known to "
1057 action_finders_.emplace_back(std::make_unique<DecayActionsFinder>(
1058 parameters_.res_lifetime_factor, parameters_.do_non_strong_decays,
1059 force_decays_, parameters_.spin_interaction_type));
1062 if ((parameters_.two_to_one || parameters_.included_2to2.any() ||
1063 parameters_.included_multi.any() || parameters_.strings_switch) &&
1065 parameters_.use_monash_tune_default =
1066 (modus_.is_collider() && modus_.sqrt_s_NN() >= 200.);
1068 std::make_unique<ScatterActionsFinder>(config, parameters_);
1069 max_transverse_distance_sqr_ =
1070 scat_finder->max_transverse_distance_sqr(parameters_.testparticles);
1071 process_string_ptr_ = scat_finder->get_process_string_ptr();
1072 action_finders_.emplace_back(std::move(scat_finder));
1074 max_transverse_distance_sqr_ =
1075 parameters_.maximum_cross_section / M_PI *
fm2_mb;
1076 process_string_ptr_ = NULL;
1078 if (modus_.is_box()) {
1079 action_finders_.emplace_back(
1080 std::make_unique<WallCrossActionsFinder>(parameters_.box_length));
1084 const InitialConditionParameters &IC_parameters = modus_.IC_parameters();
1087 action_finders_.emplace_back(std::make_unique<DynamicFluidizationFinder>(
1088 modus_.fluid_lattice(), modus_.fluid_background(), IC_parameters));
1091 double rapidity_cut = IC_parameters.rapidity_cut.value();
1093 if (modus_.calculation_frame_is_fixed_target() && rapidity_cut != 0.0) {
1094 throw std::runtime_error(
1095 "Rapidity cut for initial conditions output is not implemented "
1096 "in the fixed target calculation frame. \nPlease use "
1097 "\"center of velocity\" or \"center of mass\" as a "
1098 "\"Calculation_Frame\" instead.");
1101 double pT_cut = IC_parameters.pT_cut.value();
1102 if (rapidity_cut > 0.0 || pT_cut > 0.0) {
1103 kinematic_cuts_for_IC_output_ =
true;
1106 const double proper_time = std::invoke([&]() {
1107 if (IC_parameters.proper_time.has_value()) {
1108 return IC_parameters.proper_time.value();
1111 const double scaling = IC_parameters.proper_time_scaling.value();
1113 const double lower_bound =
1114 IC_parameters.lower_bound.value() * scaling;
1116 const double default_proper_time =
1117 modus_.nuclei_passing_time() * scaling;
1118 if (default_proper_time >= lower_bound) {
1119 logg[LInitialConditions].info()
1120 <<
"Nuclei passing time is " << default_proper_time <<
" fm.";
1121 return default_proper_time;
1123 logg[LInitialConditions].warn()
1124 <<
"Nuclei passing time is too short, hypersurface proper time "
1125 <<
"set to tau = " << lower_bound <<
" fm.";
1131 action_finders_.emplace_back(
1132 std::make_unique<HyperSurfaceCrossActionsFinder>(
1133 proper_time, rapidity_cut, pT_cut));
1139 pauli_blocker_ = std::make_unique<PauliBlocker>(
1441 " create OutputInterface objects");
1444 <<
"Density type printed to headers: " << dens_type_;
1455 if (output_path ==
"") {
1456 throw std::invalid_argument(
1457 "Invalid empty output path provided to Experiment constructor.");
1458 }
else if (!std::filesystem::exists(output_path)) {
1460 "Output path \"" + output_path.string() +
1461 "\" used to create an Experiment object does not exist.");
1462 throw NonExistingOutputPathRequest(
"Attempt to use not existing path.");
1463 }
else if (!std::filesystem::is_directory(output_path)) {
1465 "\" used to create an Experiment object "
1466 "exists, but it is not a directory.");
1467 throw std::logic_error(
"Attempt to use invalid existing path.");
1469 const std::vector<std::string> output_contents =
1470 output_conf.list_upmost_nodes();
1471 if (output_conf.is_empty()) {
1472 logg[
LExperiment].warn() <<
"No \"Output\" section found in the input "
1473 "file. No output file will be produced.";
1477 std::vector<std::vector<std::string>> list_of_formats(output_contents.size());
1479 output_contents.cbegin(), output_contents.cend(), list_of_formats.begin(),
1480 [&output_conf](std::string content) -> std::vector<std::string> {
1484 return output_conf.take(InputKeys::get_output_format_key(content));
1486 auto abort_because_of_invalid_input_file = []() {
1487 throw std::invalid_argument(
"Invalid configuration input file.");
1489 const OutputParameters output_parameters(std::move(output_conf));
1490 for (std::size_t i = 0; i < output_contents.size(); ++i) {
1491 if (output_contents[i] ==
"Particles" ||
1492 output_contents[i] ==
"Collisions" ||
1493 output_contents[i] ==
"Dileptons" || output_contents[i] ==
"Photons" ||
1494 output_contents[i] ==
"Initial_Conditions") {
1495 assert(output_parameters.quantities.count(output_contents[i]) > 0);
1496 const bool quantities_given_nonempty =
1497 !output_parameters.quantities.at(output_contents[i]).empty();
1498 auto formats_contains = [&list_of_formats, &i](
const std::string &label) {
1499 return std::find(list_of_formats[i].begin(), list_of_formats[i].end(),
1500 label) != list_of_formats[i].end();
1502 const bool custom_ascii_requested = formats_contains(
"ASCII");
1503 const bool custom_binary_requested = formats_contains(
"Binary");
1504 const bool custom_requested =
1505 custom_ascii_requested || custom_binary_requested;
1506 const bool oscar2013_requested = formats_contains(
"Oscar2013");
1507 const bool oscar2013_bin_requested = formats_contains(
"Oscar2013_bin");
1508 const bool is_extended = (output_contents[i] ==
"Particles")
1509 ? output_parameters.part_extended
1510 : output_parameters.coll_extended;
1511 const auto &default_quantities =
1514 const bool are_given_quantities_oscar2013_ones =
1515 output_parameters.quantities.at(output_contents[i]) ==
1517 if (quantities_given_nonempty != custom_requested) {
1519 <<
"Non-empty \"Quantities\" and \"ASCII\"/\"Binary\" format have "
1520 <<
"not been specified both for " << std::quoted(output_contents[i])
1521 <<
" in config file.";
1522 abort_because_of_invalid_input_file();
1524 if (custom_ascii_requested && oscar2013_requested &&
1525 are_given_quantities_oscar2013_ones) {
1527 <<
"The specified \"Quantities\" for the ASCII format are the same "
1528 "as those of the requested \"Oscar2013\"\nformat for "
1529 << std::quoted(output_contents[i])
1530 <<
" and this would produce the same output file twice.";
1531 abort_because_of_invalid_input_file();
1533 if (custom_binary_requested && oscar2013_bin_requested &&
1534 are_given_quantities_oscar2013_ones) {
1536 <<
"The specified \"Quantities\" for the binary format are the "
1537 "same as those of the requested \"Oscar2013_bin\"\nformat for "
1538 << std::quoted(output_contents[i])
1539 <<
" and this would produce the same output file twice.";
1540 abort_because_of_invalid_input_file();
1544 if (list_of_formats[i].empty()) {
1546 <<
"Empty or unspecified list of formats for "
1547 << std::quoted(output_contents[i]) <<
" content.";
1548 abort_because_of_invalid_input_file();
1549 }
else if (std::find(list_of_formats[i].begin(), list_of_formats[i].end(),
1550 "None") != list_of_formats[i].end()) {
1551 if (list_of_formats[i].size() > 1) {
1553 <<
"Use of \"None\" output format together with other formats is "
1554 "not allowed.\nInvalid \"Format\" key for "
1555 << std::quoted(output_contents[i]) <<
" content.";
1556 abort_because_of_invalid_input_file();
1559 list_of_formats[i].clear();
1561 }
else if (std::set<std::string> tmp_set(list_of_formats[i].begin(),
1562 list_of_formats[i].end());
1563 list_of_formats[i].size() != tmp_set.size()) {
1564 auto join_container = [](
const auto &container) {
1565 std::string result{};
1567 [&result](
const std::string s) {
1568 result += (result ==
"") ? s :
", " + s;
1572 const std::string old_formats = join_container(list_of_formats[i]),
1573 new_formats = join_container(tmp_set);
1575 <<
"Found the same output format multiple times for "
1576 << std::quoted(output_contents[i])
1577 <<
" content. Duplicates will be ignored:\n 'Format: [" << old_formats
1578 <<
"] -> [" << new_formats <<
"]'";
1579 list_of_formats[i].assign(tmp_set.begin(), tmp_set.end());
1585 std::size_t total_number_of_requested_formats = 0;
1586 for (std::size_t i = 0; i < output_contents.size(); ++i) {
1587 for (
const auto &
format : list_of_formats[i]) {
1588 create_output(
format, output_contents[i], output_path, output_parameters);
1589 ++total_number_of_requested_formats;
1593 if (outputs_.size() != total_number_of_requested_formats) {
1595 <<
"At least one invalid output format has been provided.";
1596 abort_because_of_invalid_input_file();
1607 throw std::invalid_argument(
"Can't use potentials without time steps!");
1611 <<
"Potentials don't work with frozen Fermi momenta! "
1612 "Use normal Fermi motion instead.";
1613 throw std::invalid_argument(
1614 "Can't use potentials "
1615 "with frozen Fermi momenta!");
1618 << parameters_.labclock->timestep_duration();
1620 potentials_ = std::make_unique<Potentials>(
1625 if (potentials_->use_skyrme() && potentials_->use_vdf()) {
1626 throw std::runtime_error(
1627 "Can't use Skyrme and VDF potentials at the same time!");
1629 if (potentials_->use_symmetry() && potentials_->use_vdf()) {
1630 throw std::runtime_error(
1631 "Can't use symmetry and VDF potentials at the same time!");
1633 if (potentials_->use_skyrme()) {
1636 <<
"\t\tSkyrme_A [MeV] = " << potentials_->skyrme_a() <<
"\n";
1638 <<
"\t\tSkyrme_B [MeV] = " << potentials_->skyrme_b() <<
"\n";
1640 <<
"\t\t Skyrme_tau = " << potentials_->skyrme_tau() <<
"\n";
1642 if (potentials_->use_symmetry()) {
1644 <<
"Symmetry potential is:"
1645 <<
"\n S_pot [MeV] = " << potentials_->symmetry_S_pot() <<
"\n";
1647 if (potentials_->use_vdf()) {
1650 << potentials_->saturation_density() <<
"\n";
1651 for (
int i = 0; i < potentials_->number_of_terms(); i++) {
1653 <<
"\t\tCoefficient_" << i + 1 <<
" = "
1654 << 1000.0 * (potentials_->coeffs())[i] <<
" [MeV] \t Power_"
1655 << i + 1 <<
" = " << (potentials_->powers())[i] <<
"\n";
1661 throw std::invalid_argument(
1662 "Derivatives are necessary for running with potentials.\n"
1663 "Derivatives_Mode: \"Off\" only makes sense for "
1664 "Field_Derivatives_Mode: \"Direct\"!\nUse \"Covariant Gaussian\" or "
1665 "\"Finite difference\".");
1673 switch (parameters_.derivatives_mode) {
1684 switch (parameters_.rho_derivatives_mode) {
1693 if (potentials_->use_vdf()) {
1694 switch (parameters_.field_derivatives_mode) {
1707 if (potentials_->use_vdf() && (parameters_.rho_derivatives_mode ==
1709 parameters_.field_derivatives_mode ==
1711 throw std::runtime_error(
1712 "Can't use VDF potentials without rest frame density derivatives or "
1713 "direct field derivatives!");
1718 throw std::runtime_error(
1719 "Can't use potentials without gradients of baryon current (Skyrme, "
1721 " or direct field derivatives (VDF)!");
1724 if (!(potentials_->use_vdf()) &&
1726 throw std::invalid_argument(
1727 "Field_Derivatives_Mode: \"Direct\" only makes sense for the VDF "
1728 "potentials!\nUse Field_Derivatives_Mode: \"Chain Rule\" or comment "
1729 "this option out (Chain Rule is default)");
1734 switch (parameters_.smearing_mode) {
1740 << parameters_.discrete_weight;
1744 << parameters_.triangular_range;
1751 bool all_geometrical_properties_specified =
1755 if (!automatic && !all_geometrical_properties_specified) {
1756 throw std::invalid_argument(
1757 "The lattice was requested to be manually generated, but some\n"
1758 "lattice geometrical property was not specified. Be sure to provide\n"
1759 "both \"Cell_Number\" and \"Origin\" and \"Sizes\".");
1761 if (automatic && all_geometrical_properties_specified) {
1762 throw std::invalid_argument(
1763 "The lattice was requested to be automatically generated, but all\n"
1764 "lattice geometrical properties were specified. In this case you\n"
1765 "need to set \"Automatic: False\".");
1768 const auto [l,
n, origin] = [&config, automatic,
this]() {
1770 return std::make_tuple<std::array<double, 3>, std::array<int, 3>,
1771 std::array<double, 3>>(
1776 std::array<double, 3> l_default{20., 20., 20.};
1777 std::array<int, 3> n_default{10, 10, 10};
1778 std::array<double, 3> origin_default{-20., -20., -20.};
1779 if (modus_.is_list() && !modus_.is_box()) {
1781 "The lattice in List modus should be manually specified.");
1782 throw std::invalid_argument(
"Invalid Lattice setup.");
1783 }
else if (modus_.is_collider()) {
1786 const double gamma = modus_.sqrt_s_NN() / (2.0 *
nucleon_mass);
1787 const double max_z = 5.0 / gamma + end_time_;
1788 const double estimated_max_transverse_velocity = 0.7;
1789 const double max_xy =
1790 5.0 + estimated_max_transverse_velocity * end_time_;
1791 origin_default = {-max_xy, -max_xy, -max_z};
1792 l_default = {2 * max_xy, 2 * max_xy, 2 * max_z};
1796 const double minimum_extension = 30.;
1797 for (
auto i = std::size_t{0}; i < l_default.size(); i++) {
1798 if (l_default[i] < minimum_extension) {
1800 <<
"Automatic lattice extension in direction " << i
1801 <<
" heuristically determined as " << l_default[i]
1802 <<
" fm is smaller than " << minimum_extension
1803 <<
" fm. Imposing minimum size.";
1804 l_default[i] = minimum_extension;
1805 origin_default[i] = -0.5 * minimum_extension;
1811 const int n_xy = numeric_cast<int>(std::ceil(l_default[0] / 0.8));
1812 const bool to_be_contracted =
1815 const double contraction_factor = (to_be_contracted) ? gamma : 1.0;
1816 const int nz = numeric_cast<int>(
1817 std::ceil(l_default[2] / 0.8 * contraction_factor));
1818 n_default = {n_xy, n_xy, nz};
1819 }
else if (modus_.is_box()) {
1820 origin_default = {0., 0., 0.};
1821 const double bl = modus_.length();
1822 l_default = {bl, bl, bl};
1823 const int n_xyz = numeric_cast<int>(std::ceil(bl / 0.5));
1824 n_default = {n_xyz, n_xyz, n_xyz};
1825 }
else if (modus_.is_sphere()) {
1828 const double max_d = modus_.radius() + end_time_;
1829 origin_default = {-max_d, -max_d, -max_d};
1830 l_default = {2 * max_d, 2 * max_d, 2 * max_d};
1832 const int n_xyz = numeric_cast<int>(std::ceil(2 * max_d / 0.8));
1833 n_default = {n_xyz, n_xyz, n_xyz};
1836 return std::make_tuple<std::array<double, 3>, std::array<int, 3>,
1837 std::array<double, 3>>(
1845 <<
"Lattice is ON. Origin = (" << origin[0] <<
"," << origin[1] <<
","
1846 << origin[2] <<
"), sizes = (" << l[0] <<
"," << l[1] <<
"," << l[2]
1847 <<
"), number of cells = (" <<
n[0] <<
"," <<
n[1] <<
"," <<
n[2]
1848 <<
"), periodic = " << std::boolalpha << periodic;
1850 if (printout_lattice_td_ || printout_full_lattice_any_td_) {
1851 dens_type_lattice_printout_ = output_parameters.td_dens_type;
1852 printout_rho_eckart_ = output_parameters.td_rho_eckart;
1853 printout_tmn_ = output_parameters.td_tmn;
1854 printout_tmn_landau_ = output_parameters.td_tmn_landau;
1855 printout_v_landau_ = output_parameters.td_v_landau;
1856 printout_j_QBS_ = output_parameters.td_jQBS;
1858 if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
1859 Tmn_ = std::make_unique<RectangularLattice<EnergyMomentumTensor>>(
1862 if (printout_j_QBS_) {
1863 j_QBS_lat_ = std::make_unique<DensityLattice>(l,
n, origin, periodic,
1871 old_jmu_auxiliary_ = std::make_unique<RectangularLattice<FourVector>>(
1873 new_jmu_auxiliary_ = std::make_unique<RectangularLattice<FourVector>>(
1875 four_gradient_auxiliary_ =
1876 std::make_unique<RectangularLattice<std::array<FourVector, 4>>>(
1879 if (potentials_->use_skyrme()) {
1880 jmu_B_lat_ = std::make_unique<DensityLattice>(
1882 UB_lat_ = std::make_unique<RectangularLattice<FourVector>>(
1884 FB_lat_ = std::make_unique<
1885 RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1888 if (potentials_->use_symmetry()) {
1889 jmu_I3_lat_ = std::make_unique<DensityLattice>(
1891 UI3_lat_ = std::make_unique<RectangularLattice<FourVector>>(
1893 FI3_lat_ = std::make_unique<
1894 RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1897 if (potentials_->use_coulomb()) {
1898 jmu_el_lat_ = std::make_unique<DensityLattice>(
1900 EM_lat_ = std::make_unique<
1901 RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1904 if (potentials_->use_vdf()) {
1905 jmu_B_lat_ = std::make_unique<DensityLattice>(
1907 UB_lat_ = std::make_unique<RectangularLattice<FourVector>>(
1909 FB_lat_ = std::make_unique<
1910 RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1915 old_fields_auxiliary_ =
1916 std::make_unique<RectangularLattice<FourVector>>(
1918 new_fields_auxiliary_ =
1919 std::make_unique<RectangularLattice<FourVector>>(
1921 fields_four_gradient_auxiliary_ =
1922 std::make_unique<RectangularLattice<std::array<FourVector, 4>>>(
1926 fields_lat_ = std::make_unique<FieldsLattice>(
1931 jmu_B_lat_ = std::make_unique<DensityLattice>(l,
n, origin, periodic,
1936 jmu_I3_lat_ = std::make_unique<DensityLattice>(l,
n, origin, periodic,
1942 jmu_custom_lat_ = std::make_unique<DensityLattice>(
1945 }
else if (printout_lattice_td_ || printout_full_lattice_any_td_) {
1947 "If you want Therm. VTK or Lattice output, configure a lattice for "
1949 }
else if (potentials_ && potentials_->use_coulomb()) {
1951 "Coulomb potential requires a lattice. Please add one to the "
1956 if ((potentials_ !=
nullptr) && (jmu_B_lat_ ==
nullptr)) {
1957 logg[
LExperiment].warn() <<
"Lattice is NOT used. Mean-field energy is "
1958 <<
"not going to be calculated.";
1962 if (parameters_.potential_affect_threshold) {
1970 (jmu_B_lat_ ==
nullptr)) {
1971 throw std::runtime_error(
1972 "Lattice is necessary to calculate finite difference gradients.");
1979 thermalizer_ = modus_.create_grandcan_thermalizer(th_conf);
2015 uint64_t scatterings_this_interval,
2018 double E_mean_field,
2019 double E_mean_field_initial);
2056 double E_mean_field,
double modus_impact_parameter,
2058 bool projectile_target_interact,
2059 bool kinematic_cut_for_SMASH_IC);
2061 template <
typename Modus>
2071 while (r == INT64_MIN) {
2074 seed_ = std::abs(r);
2079 if (process_string_ptr_ != NULL) {
2080 process_string_ptr_->init_pythia_hadron_rndm();
2083 for (
Particles &particles : ensembles_) {
2088 double start_time = -1.0;
2092 if (modus_.is_collider()) {
2093 modus_.sample_impact();
2094 logg[
LExperiment].info(
"Impact parameter = ", modus_.impact_parameter(),
2097 for (
Particles &particles : ensembles_) {
2098 start_time = modus_.initial_conditions(&particles, parameters_);
2103 for (
Particles &particles : ensembles_) {
2104 modus_.impose_boundary_conditions(&particles, outputs_);
2107 double timestep = delta_time_startup_;
2109 switch (time_step_mode_) {
2113 timestep = end_time_ - start_time;
2115 const double max_dt = modus_.max_timestep(max_transverse_distance_sqr_);
2116 if (max_dt > 0. && max_dt < timestep) {
2121 std::unique_ptr<UniformClock> clock_for_this_event;
2122 if (modus_.is_list() && (timestep < 0.0)) {
2123 throw std::runtime_error(
2124 "Timestep for the given event is negative. \n"
2125 "This might happen if the formation times of the input particles are "
2126 "larger than the specified end time of the simulation.");
2128 clock_for_this_event =
2129 std::make_unique<UniformClock>(start_time, timestep, end_time_);
2130 parameters_.labclock = std::move(clock_for_this_event);
2133 parameters_.outputclock->reset(start_time,
true);
2135 parameters_.outputclock->remove_times_in_past(start_time);
2138 "Lab clock: t_start = ", parameters_.labclock->current_time(),
2139 ", dt = ", parameters_.labclock->timestep_duration());
2144 wall_actions_total_ = 0;
2145 previous_wall_actions_total_ = 0;
2146 interactions_total_ = 0;
2147 previous_interactions_total_ = 0;
2148 discarded_interactions_total_ = 0;
2149 total_pauli_blocked_ = 0;
2150 projectile_target_interact_.assign(parameters_.n_ensembles,
false);
2151 total_hypersurface_crossing_actions_ = 0;
2152 total_energy_removed_ = 0.0;
2153 total_energy_violated_by_Pythia_ = 0.0;
2156 logg[
LExperiment].info() <<
"Time[fm] Ekin[GeV] E_MF[GeV] ETotal[GeV] "
2157 <<
"ETot/N[GeV] D(ETot/N)[GeV] Scatt&Decays "
2158 <<
"Particles Comp.Time";
2160 double E_mean_field = 0.0;
2165 if ((jmu_B_lat_ !=
nullptr)) {
2167 new_jmu_auxiliary_.get(), four_gradient_auxiliary_.get(),
2169 density_param_, ensembles_,
2170 parameters_.labclock->timestep_duration(),
true);
2174 for (
auto &node : *jmu_B_lat_) {
2175 node.overwrite_drho_dt_to_zero();
2176 node.overwrite_djmu_dt_to_zero();
2179 EM_lat_.get(), parameters_);
2182 initial_mean_field_energy_ = E_mean_field;
2184 ensembles_, 0u, conserved_initial_, time_start_,
2185 parameters_.labclock->current_time(), E_mean_field,
2186 initial_mean_field_energy_);
2189 for (
const auto &output : outputs_) {
2190 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2192 ensembles_, E_mean_field, modus_.impact_parameter(), parameters_,
2193 projectile_target_interact_[i_ens], kinematic_cuts_for_IC_output_);
2194 output->at_eventstart(ensembles_[i_ens], {event_, i_ens}, event_info);
2197 output->at_eventstart(ensembles_, event_);
2199 if (printout_full_lattice_any_td_) {
2200 if (printout_rho_eckart_) {
2201 switch (dens_type_lattice_printout_) {
2218 if (printout_tmn_) {
2220 dens_type_lattice_printout_, *Tmn_);
2222 if (printout_tmn_landau_) {
2224 dens_type_lattice_printout_, *Tmn_);
2226 if (printout_v_landau_) {
2228 dens_type_lattice_printout_, *Tmn_);
2230 if (printout_j_QBS_) {
2232 dens_type_lattice_printout_, *j_QBS_lat_);
2244 const double m = particle.effective_mass();
2245 double v_beam = 0.0;
2246 if (particle.belongs_to() == BelongsTo::Projectile) {
2247 v_beam = modus_.velocity_projectile();
2248 }
else if (particle.belongs_to() == BelongsTo::Target) {
2249 v_beam = modus_.velocity_target();
2251 const double gamma = 1.0 / std::sqrt(1.0 - v_beam * v_beam);
2252 beam_momentum_.emplace_back(
2253 FourVector(gamma * m, 0.0, 0.0, gamma * v_beam * m));
2258 template <
typename Modus>
2260 bool include_pauli_blocking) {
2261 Particles &particles = ensembles_[i_ensemble];
2265 discarded_interactions_total_++;
2267 " (discarded: invalid)");
2270 const bool core_in_incoming =
2271 std::any_of(incoming.begin(), incoming.end(),
2272 [](
const ParticleData &
p) { return p.is_core(); });
2273 if (core_in_incoming) {
2274 if (action.
get_type() == ProcessType::FluidizationNoRemoval) {
2281 const bool all_core_in_incoming =
2283 [](
const ParticleData &
p) { return p.is_core(); });
2284 if (!all_core_in_incoming) {
2291 }
catch (Action::StochasticBelowEnergyThreshold &) {
2295 if (include_pauli_blocking && pauli_blocker_ &&
2297 total_pauli_blocked_++;
2303 if (modus_.is_collider()) {
2304 int count_target = 0, count_projectile = 0;
2305 for (
const auto &
p : incoming) {
2306 if (
p.belongs_to() == BelongsTo::Projectile) {
2308 }
else if (
p.belongs_to() == BelongsTo::Target) {
2312 if (count_target > 0 && count_projectile > 0) {
2313 projectile_target_interact_[i_ensemble] =
true;
2319 const auto id_process =
static_cast<uint32_t
>(interactions_total_ + 1);
2321 total_energy_violated_by_Pythia_ += action.
perform(&particles, id_process);
2323 interactions_total_++;
2324 if (action.
get_type() == ProcessType::Wall) {
2325 wall_actions_total_++;
2327 if (action.
get_type() == ProcessType::Fluidization) {
2328 total_hypersurface_crossing_actions_++;
2335 constexpr
bool compute_grad =
false;
2336 const bool smearing =
true;
2339 rho = std::get<0>(
current_eckart(r_interaction.threevec(), particles,
2340 density_param_, dens_type_, compute_grad,
2358 for (
const auto &output : outputs_) {
2359 if (output->is_dilepton_output() || output->is_photon_output()) {
2362 if (output->is_IC_output()) {
2363 if (action.
get_type() == ProcessType::Fluidization ||
2364 action.
get_type() == ProcessType::FluidizationNoRemoval) {
2365 output->at_interaction(action, rho);
2368 output->at_interaction(action, rho);
2377 if (photons_switch_ &&
2379 ScatterActionPhoton::is_kinematically_possible(
2383 constexpr
double action_time = 0.;
2384 ScatterActionPhoton photon_act(
2401 photon_act.add_single_process();
2403 photon_act.perform_photons(outputs_);
2406 if (bremsstrahlung_switch_ &&
2407 BremsstrahlungAction::is_bremsstrahlung_reaction(
2411 constexpr
double action_time = 0.;
2413 BremsstrahlungAction brems_act(
2431 brems_act.add_single_process();
2433 brems_act.perform_bremsstrahlung(outputs_);
2452 template <
typename Modus>
2454 ParticleList &&add_plist,
2455 ParticleList &&remove_plist) {
2456 if (!add_plist.empty() || !remove_plist.empty()) {
2457 if (ensembles_.size() > 1) {
2458 throw std::runtime_error(
2459 "Adding or removing particles from SMASH is only possible when one "
2460 "ensemble is used.");
2462 const double action_time = parameters_.labclock->current_time();
2466 if (!add_plist.empty()) {
2469 if (!add_plist.empty()) {
2471 auto action_add_particles = std::make_unique<FreeforallAction>(
2472 ParticleList{}, add_plist, action_time);
2473 perform_action(*action_add_particles, 0);
2476 if (!remove_plist.empty()) {
2479 if (!remove_plist.empty()) {
2480 ParticleList found_particles_to_remove;
2481 for (
const auto &particle_to_remove : remove_plist) {
2482 const auto iterator_to_particle_to_be_removed_in_ensemble =
2484 ensembles_[0].begin(), ensembles_[0].end(),
2485 [&particle_to_remove, &action_time](
const ParticleData &
p) {
2487 particle_to_remove,
p, action_time);
2489 if (iterator_to_particle_to_be_removed_in_ensemble !=
2490 ensembles_[0].end())
2491 found_particles_to_remove.push_back(
2492 *iterator_to_particle_to_be_removed_in_ensemble);
2496 std::sort(found_particles_to_remove.begin(),
2497 found_particles_to_remove.end(),
2499 return p1.id() < p2.id();
2501 const auto iterator_to_first_duplicate = std::adjacent_find(
2502 found_particles_to_remove.begin(), found_particles_to_remove.end(),
2504 return p1.id() == p2.id();
2506 if (iterator_to_first_duplicate != found_particles_to_remove.end()) {
2507 logg[
LExperiment].error() <<
"The same particle has been asked to be "
2508 "removed multiple times:\n"
2509 << *iterator_to_first_duplicate;
2510 throw std::logic_error(
"Particle cannot be removed twice!");
2512 if (
auto delta = remove_plist.size() - found_particles_to_remove.size();
2515 "When trying to remove particle(s) at the beginning ",
2516 "of the system evolution,\n", delta,
2517 " particle(s) could not be found and will be ignored.");
2519 if (!found_particles_to_remove.empty()) {
2520 [[maybe_unused]]
const auto number_particles_before_removal =
2521 ensembles_[0].size();
2523 auto action_remove_particles = std::make_unique<FreeforallAction>(
2524 found_particles_to_remove, ParticleList{}, action_time);
2525 perform_action(*action_remove_particles, 0);
2527 assert(number_particles_before_removal -
2528 found_particles_to_remove.size() ==
2529 ensembles_[0].size());
2534 if (t_end > end_time_) {
2536 <<
"Evolution asked to be run until " << t_end <<
" > " << end_time_
2537 <<
" and this cannot be done (because of how the clock works).";
2538 throw std::logic_error(
2539 "Experiment cannot evolve the system beyond End_Time.");
2541 while (*(parameters_.labclock) < t_end) {
2542 const double dt = parameters_.labclock->timestep_duration();
2543 logg[
LExperiment].debug(
"Timestepless propagation for next ", dt,
" fm.");
2547 thermalizer_->is_time_to_thermalize(parameters_.labclock)) {
2548 const bool ignore_cells_under_treshold =
true;
2551 thermalizer_->update_thermalizer_lattice(ensembles_, density_param_,
2552 ignore_cells_under_treshold);
2553 const double current_t = parameters_.labclock->current_time();
2554 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2555 thermalizer_->thermalize(ensembles_[i_ens], current_t,
2556 parameters_.testparticles);
2559 perform_action(th_act, i_ens);
2565 modus_.build_fluidization_lattice(parameters_.labclock->current_time(),
2566 ensembles_, density_param_);
2569 std::vector<Actions> actions(parameters_.n_ensembles);
2570 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2571 actions[i_ens].clear();
2572 if (ensembles_[i_ens].size() > 0 && action_finders_.size() > 0) {
2574 const double min_cell_length = compute_min_cell_length(dt);
2579 const bool include_unformed_particles = IC_switch_;
2581 use_grid_ ? modus_.create_grid(ensembles_[i_ens], min_cell_length,
2582 dt, parameters_.coll_crit,
2583 include_unformed_particles)
2584 : modus_.create_grid(ensembles_[i_ens], min_cell_length,
2585 dt, parameters_.coll_crit,
2586 include_unformed_particles,
2587 CellSizeStrategy::Largest);
2589 const double gcell_vol = grid.cell_volume();
2592 [&](
const ParticleList &search_list) {
2593 for (
const auto &finder : action_finders_) {
2594 actions[i_ens].insert(finder->find_actions_in_cell(
2595 search_list, dt, gcell_vol, beam_momentum_));
2598 [&](
const ParticleList &search_list,
2599 const ParticleList &neighbors_list) {
2600 for (
const auto &finder : action_finders_) {
2601 actions[i_ens].insert(finder->find_actions_with_neighbors(
2602 search_list, neighbors_list, dt, beam_momentum_));
2611 const double end_timestep_time = parameters_.labclock->next_time();
2612 while (next_output_time() < end_timestep_time) {
2613 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2614 run_time_evolution_timestepless(actions[i_ens], i_ens,
2615 next_output_time());
2617 ++(*parameters_.outputclock);
2619 intermediate_output();
2621 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2622 run_time_evolution_timestepless(actions[i_ens], i_ens, end_timestep_time);
2628 update_potentials();
2629 update_momenta(ensembles_, parameters_.labclock->timestep_duration(),
2630 *potentials_, FB_lat_.get(), FI3_lat_.get(), EM_lat_.get(),
2637 for (
Particles &particles : ensembles_) {
2642 ++(*parameters_.labclock);
2650 if (!potentials_ && !parameters_.strings_switch &&
2652 std::string err_msg = conserved_initial_.report_deviations(ensembles_);
2653 if (!err_msg.empty()) {
2655 throw std::runtime_error(
"Violation of conserved quantities!");
2668 ++(*parameters_.outputclock);
2670 if (pauli_blocker_) {
2672 "Interactions: Pauli-blocked/performed = ", total_pauli_blocked_,
"/",
2673 interactions_total_ - wall_actions_total_);
2677 template <
typename Modus>
2682 if (dilepton_finder_ !=
nullptr) {
2683 for (
const auto &output : outputs_) {
2684 dilepton_finder_->shine(particles, output.get(), dt);
2697 constexpr uint64_t max_uint32 = std::numeric_limits<uint32_t>::max();
2698 if (interactions_total >= max_uint32) {
2699 throw std::runtime_error(
"Integer overflow in total interaction number!");
2703 template <
typename Modus>
2705 Actions &actions,
int i_ensemble,
const double end_time_propagation) {
2706 Particles &particles = ensembles_[i_ensemble];
2708 "Timestepless propagation: ",
"Actions size = ", actions.
size(),
2709 ", end time = ", end_time_propagation);
2717 ActionPtr act = actions.
pop();
2718 if (!act->is_valid(particles)) {
2719 discarded_interactions_total_++;
2721 " (discarded: invalid)");
2725 ", action time = ", act->time_of_execution());
2728 propagate_and_shine(act->time_of_execution(), particles);
2735 act->update_incoming(particles);
2736 const bool performed = perform_action(*act, i_ensemble);
2746 const double end_time_timestep = parameters_.labclock->next_time();
2748 const double time_left = end_time_timestep - act->time_of_execution();
2749 const ParticleList &outgoing_particles = act->outgoing_particles();
2751 const double gcell_vol = 0.0;
2752 for (
const auto &finder : action_finders_) {
2754 actions.
insert(finder->find_actions_in_cell(outgoing_particles, time_left,
2755 gcell_vol, beam_momentum_));
2757 actions.
insert(finder->find_actions_with_surrounding_particles(
2758 outgoing_particles, particles, time_left, beam_momentum_));
2764 propagate_and_shine(end_time_propagation, particles);
2767 template <
typename Modus>
2769 const uint64_t wall_actions_this_interval =
2770 wall_actions_total_ - previous_wall_actions_total_;
2771 previous_wall_actions_total_ = wall_actions_total_;
2772 const uint64_t interactions_this_interval = interactions_total_ -
2773 previous_interactions_total_ -
2774 wall_actions_this_interval;
2775 previous_interactions_total_ = interactions_total_;
2776 double E_mean_field = 0.0;
2779 double computational_frame_time = 0.0;
2782 if ((jmu_B_lat_ !=
nullptr)) {
2784 EM_lat_.get(), parameters_);
2791 if (modus_.is_box()) {
2792 double tmp = (E_mean_field - initial_mean_field_energy_) /
2793 (E_mean_field + initial_mean_field_energy_);
2799 if (std::abs(tmp) > 0.01) {
2801 <<
"\n\n\n\t The mean field at t = "
2802 << parameters_.outputclock->current_time()
2803 <<
" [fm] differs from the mean field at t = 0:"
2804 <<
"\n\t\t initial_mean_field_energy_ = "
2805 << initial_mean_field_energy_ <<
" [GeV]"
2806 <<
"\n\t\t abs[(E_MF - E_MF(t=0))/(E_MF + E_MF(t=0))] = "
2808 <<
"\n\t\t E_MF/E_MF(t=0) = "
2809 << E_mean_field / initial_mean_field_energy_ <<
"\n\n";
2816 ensembles_, interactions_this_interval, conserved_initial_, time_start_,
2817 parameters_.outputclock->current_time(), E_mean_field,
2818 initial_mean_field_energy_);
2822 if (!(modus_.is_box() && parameters_.outputclock->current_time() <
2823 modus_.equilibration_time())) {
2824 for (
const auto &output : outputs_) {
2825 if (output->is_dilepton_output() || output->is_photon_output() ||
2826 output->is_IC_output()) {
2829 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2831 ensembles_, E_mean_field, modus_.impact_parameter(), parameters_,
2832 projectile_target_interact_[i_ens], kinematic_cuts_for_IC_output_);
2834 output->at_intermediate_time(ensembles_[i_ens], parameters_.outputclock,
2835 density_param_, {event_, i_ens},
2837 computational_frame_time = event_info.current_time;
2840 output->at_intermediate_time(ensembles_, parameters_.outputclock,
2844 if (printout_rho_eckart_) {
2845 switch (dens_type_lattice_printout_) {
2852 output->thermodynamics_lattice_output(*jmu_B_lat_,
2853 computational_frame_time);
2858 density_param_, ensembles_,
false);
2862 output->thermodynamics_lattice_output(*jmu_I3_lat_,
2863 computational_frame_time);
2869 jmu_custom_lat_.get(), lat_upd, dens_type_lattice_printout_,
2870 density_param_, ensembles_,
false);
2872 dens_type_lattice_printout_,
2874 output->thermodynamics_lattice_output(*jmu_custom_lat_,
2875 computational_frame_time);
2878 if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
2880 Tmn_.get(), lat_upd, dens_type_lattice_printout_, density_param_,
2882 if (printout_tmn_) {
2884 dens_type_lattice_printout_, *Tmn_);
2885 output->thermodynamics_lattice_output(
2888 if (printout_tmn_landau_) {
2890 dens_type_lattice_printout_, *Tmn_);
2891 output->thermodynamics_lattice_output(
2893 computational_frame_time);
2895 if (printout_v_landau_) {
2897 dens_type_lattice_printout_, *Tmn_);
2898 output->thermodynamics_lattice_output(
2900 computational_frame_time);
2904 output->fields_output(
"Efield",
"Bfield", *EM_lat_);
2906 if (printout_j_QBS_) {
2907 output->thermodynamics_lattice_output(
2908 *j_QBS_lat_, computational_frame_time, ensembles_, density_param_);
2912 output->thermodynamics_output(*thermalizer_);
2918 template <
typename Modus>
2921 if (potentials_->use_symmetry() && jmu_I3_lat_ !=
nullptr) {
2923 new_jmu_auxiliary_.get(), four_gradient_auxiliary_.get(),
2925 density_param_, ensembles_,
2926 parameters_.labclock->timestep_duration(),
true);
2928 if ((potentials_->use_skyrme() || potentials_->use_symmetry()) &&
2929 jmu_B_lat_ !=
nullptr) {
2931 new_jmu_auxiliary_.get(), four_gradient_auxiliary_.get(),
2933 density_param_, ensembles_,
2934 parameters_.labclock->timestep_duration(),
true);
2935 const size_t UBlattice_size = UB_lat_->size();
2936 for (
size_t i = 0; i < UBlattice_size; i++) {
2937 auto jB = (*jmu_B_lat_)[i];
2941 double baryon_density = jB.rho();
2945 if (potentials_->use_skyrme()) {
2947 flow_four_velocity_B * potentials_->skyrme_pot(baryon_density);
2949 potentials_->skyrme_force(baryon_density, baryon_grad_j0,
2950 baryon_dvecj_dt, baryon_curl_vecj);
2952 if (potentials_->use_symmetry() && jmu_I3_lat_ !=
nullptr) {
2953 auto jI3 = (*jmu_I3_lat_)[i];
2956 ? jI3.jmu_net() / jI3.rho()
2958 (*UI3_lat_)[i] = flow_four_velocity_I3 *
2959 potentials_->symmetry_pot(jI3.rho(), baryon_density);
2960 (*FI3_lat_)[i] = potentials_->symmetry_force(
2961 jI3.rho(), jI3.grad_j0(), jI3.dvecj_dt(), jI3.curl_vecj(),
2962 baryon_density, baryon_grad_j0, baryon_dvecj_dt,
2967 if (potentials_->use_coulomb()) {
2970 density_param_, ensembles_,
true);
2971 for (
size_t i = 0; i < EM_lat_->size(); i++) {
2973 ThreeVector position = jmu_el_lat_->cell_center(i);
2974 jmu_el_lat_->integrate_volume(electric_field,
2975 Potentials::E_field_integrand,
2976 potentials_->coulomb_r_cut(), position);
2978 jmu_el_lat_->integrate_volume(magnetic_field,
2979 Potentials::B_field_integrand,
2980 potentials_->coulomb_r_cut(), position);
2981 (*EM_lat_)[i] = std::make_pair(electric_field, magnetic_field);
2984 if (potentials_->use_vdf() && jmu_B_lat_ !=
nullptr) {
2986 new_jmu_auxiliary_.get(), four_gradient_auxiliary_.get(),
2988 density_param_, ensembles_,
2989 parameters_.labclock->timestep_duration(),
true);
2992 fields_lat_.get(), old_fields_auxiliary_.get(),
2993 new_fields_auxiliary_.get(), fields_four_gradient_auxiliary_.get(),
2994 jmu_B_lat_.get(), LatticeUpdate::EveryTimestep, *potentials_,
2995 parameters_.labclock->timestep_duration());
2997 const size_t UBlattice_size = UB_lat_->size();
2998 for (
size_t i = 0; i < UBlattice_size; i++) {
2999 auto jB = (*jmu_B_lat_)[i];
3000 (*UB_lat_)[i] = potentials_->vdf_pot(jB.rho(), jB.jmu_net());
3001 switch (parameters_.field_derivatives_mode) {
3003 (*FB_lat_)[i] = potentials_->vdf_force(
3004 jB.rho(), jB.drho_dxnu().x0(), jB.drho_dxnu().threevec(),
3005 jB.grad_rho_cross_vecj(), jB.jmu_net().x0(), jB.grad_j0(),
3006 jB.jmu_net().threevec(), jB.dvecj_dt(), jB.curl_vecj());
3009 auto Amu = (*fields_lat_)[i];
3010 (*FB_lat_)[i] = potentials_->vdf_force(
3011 Amu.grad_A0(), Amu.dvecA_dt(), Amu.curl_vecA());
3019 template <
typename Modus>
3023 bool actions_performed, actions_found;
3024 uint64_t interactions_old;
3026 actions_found =
false;
3027 interactions_old = interactions_total_;
3028 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
3031 if (dilepton_finder_ !=
nullptr) {
3032 for (
const auto &output : outputs_) {
3033 dilepton_finder_->shine_final(ensembles_[i_ens], output.get(),
true);
3037 for (
const auto &finder : action_finders_) {
3038 auto found_actions = finder->find_final_actions(ensembles_[i_ens]);
3039 if (!found_actions.empty()) {
3040 actions.
insert(std::move(found_actions));
3041 actions_found =
true;
3046 perform_action(*actions.
pop(), i_ens,
false);
3049 actions_performed = interactions_total_ > interactions_old;
3051 if (actions_found && !actions_performed) {
3052 throw std::runtime_error(
"Final actions were found but not performed.");
3055 }
while (actions_performed);
3058 if (dilepton_finder_ !=
nullptr) {
3059 for (
const auto &output : outputs_) {
3060 for (
Particles &particles : ensembles_) {
3061 dilepton_finder_->shine_final(particles, output.get(),
false);
3067 template <
typename Modus>
3072 double E_mean_field = 0.0;
3073 if (
likely(parameters_.labclock > 0)) {
3074 const uint64_t wall_actions_this_interval =
3075 wall_actions_total_ - previous_wall_actions_total_;
3076 const uint64_t interactions_this_interval = interactions_total_ -
3077 previous_interactions_total_ -
3078 wall_actions_this_interval;
3081 if ((jmu_B_lat_ !=
nullptr)) {
3083 EM_lat_.get(), parameters_);
3086 if (std::abs(parameters_.labclock->current_time() - end_time_) >
3089 <<
"SMASH not propagated until configured end time. Current time = "
3090 << parameters_.labclock->current_time()
3091 <<
"fm. End time = " << end_time_ <<
"fm.";
3094 ensembles_, interactions_this_interval, conserved_initial_,
3095 time_start_, end_time_, E_mean_field, initial_mean_field_energy_);
3097 int total_particles = 0;
3098 for (
const Particles &particles : ensembles_) {
3099 total_particles += particles.
size();
3101 if (IC_switch_ && (total_particles == 0)) {
3102 const double initial_system_energy_plus_Pythia_violations =
3103 conserved_initial_.momentum().x0() + total_energy_violated_by_Pythia_;
3104 const double fraction_of_total_system_energy_removed =
3105 initial_system_energy_plus_Pythia_violations / total_energy_removed_;
3108 if (std::fabs(fraction_of_total_system_energy_removed - 1.) >
3110 throw std::runtime_error(
3111 "There is remaining energy in the system although all particles "
3115 total_energy_removed_)) +
3120 <<
"Time real: " << SystemClock::now() - time_start_;
3122 <<
"Interactions before reaching hypersurface: "
3123 << interactions_total_ - wall_actions_total_ -
3124 total_hypersurface_crossing_actions_;
3126 <<
"Total number of particles removed on hypersurface: "
3127 << total_hypersurface_crossing_actions_;
3130 const double precent_discarded =
3131 interactions_total_ > 0
3132 ?
static_cast<double>(discarded_interactions_total_) * 100.0 /
3135 std::stringstream msg_discarded;
3137 <<
"Discarded interaction number: " << discarded_interactions_total_
3138 <<
" (" << precent_discarded
3139 <<
"% of the total interaction number including wall crossings)";
3143 <<
"Time real: " << SystemClock::now() - time_start_;
3147 precent_discarded > 1.0) {
3150 << msg_discarded.str()
3151 <<
"\nThe number of discarded interactions is large, which means "
3152 "the assumption for the stochastic criterion of\n1 interaction "
3153 "per particle per timestep is probably violated. Consider "
3154 "reducing the timestep size.";
3158 << interactions_total_ - wall_actions_total_;
3162 int unformed_particles_count = 0;
3163 for (
const Particles &particles : ensembles_) {
3165 if (particle.formation_time() > end_time_) {
3166 unformed_particles_count++;
3170 if (unformed_particles_count > 0) {
3172 "End time might be too small. ", unformed_particles_count,
3173 " unformed particles were found at the end of the evolution.");
3178 count_nonempty_ensembles();
3180 for (
const auto &output : outputs_) {
3181 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
3183 ensembles_, E_mean_field, modus_.impact_parameter(), parameters_,
3184 projectile_target_interact_[i_ens], kinematic_cuts_for_IC_output_);
3185 output->at_eventend(ensembles_[i_ens], {event_, i_ens}, event_info);
3188 output->at_eventend(ensembles_, event_);
3191 if (printout_rho_eckart_) {
3196 if (printout_tmn_) {
3199 if (printout_tmn_landau_) {
3202 if (printout_v_landau_) {
3205 if (printout_j_QBS_) {
3211 template <
typename Modus>
3213 for (
bool has_interaction : projectile_target_interact_) {
3214 if (has_interaction) {
3215 nonempty_ensembles_++;
3220 template <
typename Modus>
3223 return event_ >= nevents_;
3226 if (nonempty_ensembles_ >= minimum_nonempty_ensembles_) {
3229 if (event_ >= max_events_) {
3231 <<
"Maximum number of events (" << max_events_
3232 <<
") exceeded. Stopping calculation. "
3233 <<
"The fraction of empty ensembles is "
3234 << (1.0 -
static_cast<double>(nonempty_ensembles_) /
3235 (event_ * parameters_.n_ensembles))
3236 <<
". If this fraction is expected, try increasing the "
3237 "Maximum_Ensembles_Run.";
3242 throw std::runtime_error(
"Event counting option is invalid");
3246 template <
typename Modus>
3251 template <
typename Modus>
3254 for (event_ = 0; !is_finished(); event_++) {
3255 mainlog.info() <<
"Event " << event_;
3258 initialize_new_event();
3260 run_time_evolution(end_time_);
3262 do_final_interactions();
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.
void set_value(Key< U > key, T &&value)
Overwrite the value of the YAML node corresponding to the specified key.
Configuration extract_sub_configuration(KeyLabels section, Configuration::GetEmpty empty_if_not_existing=Configuration::GetEmpty::No)
Create a new configuration from a then-removed section of the present object.
T read(const Key< T > &key) const
Additional interface for SMASH to read configuration values without removing them.
bool has_value(const Key< T > &key) const
Return whether there is a non-empty value behind the requested key (which is supposed not to refer to...
bool has_section(const KeyLabels &labels) const
Return whether there is a (possibly empty) section with the given labels.
Configuration extract_complete_sub_configuration(KeyLabels section, Configuration::GetEmpty empty_if_not_existing=Configuration::GetEmpty::No)
Alternative method to extract a sub-configuration, which retains the labels from the top-level in the...
T take(const Key< T > &key)
The default interface for SMASH to read configuration values.
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,...
const bool IC_dynamic_
This indicates if the IC is dynamic.
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.
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.
const bool IC_switch_
This indicates whether the experiment will be used as initial condition for hydrodynamics.
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.
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.
void do_final_interactions()
Performs the final decays of an event.
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.
int nevents_
Number of events.
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.
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.
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.
@ Dynamic
Dynamic fluidization based on local densities.
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...
DensityType
Allows to choose which kind of density to calculate.
#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)
std::unique_ptr< OutputInterface > create_binary_output(const std::string &format, const std::string &content, const std::filesystem::path &path, const OutputParameters &out_par)
Create a binary output object.
#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 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 update_lattice_accumulating_ensembles(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 when ensembles are used.
void validate_and_adjust_particle_list(ParticleList &particle_list)
Validate a particle list adjusting each particle to be a valid SMASH particle.
bool all_of(Container &&c, UnaryPredicate &&p)
Convenience wrapper for std::all_of that operates on a complete container.
std::string to_string(ThermodynamicQuantity quantity)
Convert a ThermodynamicQuantity enum value to its corresponding string.
constexpr double nucleon_mass
Nucleon mass in GeV.
void update_lattice(RectangularLattice< DensityOnLattice > *lat, RectangularLattice< FourVector > *old_jmu, RectangularLattice< FourVector > *new_jmu, RectangularLattice< std::array< FourVector, 4 >> *four_grad_lattice, const LatticeUpdate update, const DensityType dens_type, const DensityParameters &par, const std::vector< Particles > &ensembles, const double time_step, const bool compute_gradient)
Updates the contents on the lattice of DensityOnLattice type.
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.
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.
static const std::vector< std::string > oscar2013
Quantities output in OSCAR2013 format.
static const std::vector< std::string > oscar2013extended
Quantities output in Extended OSCAR2013 format.
Helper structure for Experiment to hold output options and parameters.
RivetOutputParameters rivet_parameters
Rivet specfic parameters.