7 #ifndef SRC_INCLUDE_SMASH_EXPERIMENT_H_
8 #define SRC_INCLUDE_SMASH_EXPERIMENT_H_
41 #ifdef SMASH_USE_HEPMC
44 #ifdef SMASH_USE_RIVET
68 template <
typename T,
typename Ratio>
70 const chrono::duration<T, Ratio> &seconds) {
71 using Seconds = chrono::duration<double>;
72 using Minutes = chrono::duration<double, std::ratio<60>>;
73 using Hours = chrono::duration<double, std::ratio<60 * 60>>;
74 constexpr Minutes threshold_for_minutes{10};
75 constexpr Hours threshold_for_hours{3};
76 if (seconds < threshold_for_minutes) {
77 return out << Seconds(seconds).count() <<
" [s]";
79 if (seconds < threshold_for_hours) {
80 return out << Minutes(seconds).count() <<
" [min]";
82 return out << Hours(seconds).count() <<
" [h]";
87 static constexpr
int LMain = LogArea::Main::id;
127 const bf::path &output_path);
143 using std::invalid_argument::invalid_argument;
152 using std::invalid_argument::invalid_argument;
156 template <
typename Modus>
158 template <
typename Modus>
185 template <
typename Modus>
272 bool include_pauli_blocking =
true);
307 const double end_time_propagation,
308 const double end_time_run);
448 std::unique_ptr<RectangularLattice<FourVector>>
UB_lat_ =
nullptr;
454 std::unique_ptr<RectangularLattice<FourVector>>
UI3_lat_ =
nullptr;
460 std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
464 std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
468 std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
472 std::unique_ptr<RectangularLattice<EnergyMomentumTensor>>
Tmn_;
479 std::unique_ptr<RectangularLattice<std::array<FourVector, 4>>>
487 std::unique_ptr<RectangularLattice<std::array<FourVector, 4>>>
695 friend std::ostream &operator<<<>(std::ostream &out,
const Experiment &e);
699 template <
typename Modus>
701 out <<
"End time: " << e.
end_time_ <<
" fm/c\n";
706 template <
typename Modus>
708 const std::string &content,
709 const bf::path &output_path,
711 logg[
LExperiment].info() <<
"Adding output " << content <<
" of format "
714 if (
format ==
"VTK" && content ==
"Particles") {
715 outputs_.emplace_back(
716 make_unique<VtkOutput>(output_path, content, out_par));
717 }
else if (
format ==
"Root") {
718 #ifdef SMASH_USE_ROOT
719 if (content ==
"Initial_Conditions") {
720 outputs_.emplace_back(
721 make_unique<RootOutput>(output_path,
"SMASH_IC", out_par));
723 outputs_.emplace_back(
724 make_unique<RootOutput>(output_path, content, out_par));
728 "Root output requested, but Root support not compiled in");
730 }
else if (
format ==
"Binary") {
731 if (content ==
"Collisions" || content ==
"Dileptons" ||
732 content ==
"Photons") {
733 outputs_.emplace_back(
734 make_unique<BinaryOutputCollisions>(output_path, content, out_par));
735 }
else if (content ==
"Particles") {
736 outputs_.emplace_back(
737 make_unique<BinaryOutputParticles>(output_path, content, out_par));
738 }
else if (content ==
"Initial_Conditions") {
739 outputs_.emplace_back(make_unique<BinaryOutputInitialConditions>(
740 output_path, content, out_par));
742 }
else if (
format ==
"Oscar1999" ||
format ==
"Oscar2013") {
743 outputs_.emplace_back(
745 }
else if (content ==
"Thermodynamics" &&
format ==
"ASCII") {
746 outputs_.emplace_back(
747 make_unique<ThermodynamicOutput>(output_path, content, out_par));
748 }
else if (content ==
"Thermodynamics" &&
749 (
format ==
"Lattice_ASCII" ||
format ==
"Lattice_Binary")) {
750 printout_full_lattice_any_td_ =
true;
751 if (
format ==
"Lattice_ASCII") {
752 printout_full_lattice_ascii_td_ =
true;
754 if (
format ==
"Lattice_Binary") {
755 printout_full_lattice_binary_td_ =
true;
757 outputs_.emplace_back(make_unique<ThermodynamicLatticeOutput>(
758 output_path, content, out_par, printout_full_lattice_ascii_td_,
759 printout_full_lattice_binary_td_));
760 }
else if (content ==
"Thermodynamics" &&
format ==
"VTK") {
761 printout_lattice_td_ =
true;
762 outputs_.emplace_back(
763 make_unique<VtkOutput>(output_path, content, out_par));
764 }
else if (content ==
"Initial_Conditions" &&
format ==
"ASCII") {
765 outputs_.emplace_back(
766 make_unique<ICOutput>(output_path,
"SMASH_IC", out_par));
767 }
else if ((
format ==
"HepMC") || (
format ==
"HepMC_asciiv3") ||
768 (
format ==
"HepMC_treeroot")) {
769 #ifdef SMASH_USE_HEPMC
770 if (content ==
"Particles") {
771 if ((
format ==
"HepMC") || (
format ==
"HepMC_asciiv3")) {
772 outputs_.emplace_back(make_unique<HepMcOutput>(
773 output_path,
"SMASH_HepMC_particles",
false,
"asciiv3"));
774 }
else if (
format ==
"HepMC_treeroot") {
775 #ifdef SMASH_USE_HEPMC_ROOTIO
776 outputs_.emplace_back(make_unique<HepMcOutput>(
777 output_path,
"SMASH_HepMC_particles",
false,
"root"));
780 "Requested HepMC_treeroot output not available, "
781 "ROOT or HepMC3 ROOTIO missing or not found by cmake.");
784 }
else if (content ==
"Collisions") {
785 if ((
format ==
"HepMC") || (
format ==
"HepMC_asciiv3")) {
786 outputs_.emplace_back(make_unique<HepMcOutput>(
787 output_path,
"SMASH_HepMC_collisions",
true,
"asciiv3"));
788 }
else if (
format ==
"HepMC_treeroot") {
789 #ifdef SMASH_USE_HEPMC_ROOTIO
790 outputs_.emplace_back(make_unique<HepMcOutput>(
791 output_path,
"SMASH_HepMC_collisions",
true,
"root"));
794 "Requested HepMC_treeroot output not available, "
795 "ROOT or HepMC3 ROOTIO missing or not found by cmake.");
800 "HepMC only available for Particles and "
801 "Collisions content. Requested for " +
806 "HepMC output requested, but HepMC support not compiled in");
808 }
else if (content ==
"Coulomb" &&
format ==
"VTK") {
809 outputs_.emplace_back(
810 make_unique<VtkOutput>(output_path,
"Fields", out_par));
811 }
else if (content ==
"Rivet") {
812 #ifdef SMASH_USE_RIVET
814 static bool rivet_format_already_selected =
false;
816 if (rivet_format_already_selected) {
818 "Rivet output format can only be one, either YODA or YODA-full. "
819 "Only your first valid choice will be used.");
823 outputs_.emplace_back(
824 make_unique<RivetOutput>(output_path,
"SMASH_Rivet",
false, out_par));
825 rivet_format_already_selected =
true;
826 }
else if (
format ==
"YODA-full") {
827 outputs_.emplace_back(make_unique<RivetOutput>(
828 output_path,
"SMASH_Rivet_full",
true, out_par));
829 rivet_format_already_selected =
true;
832 "not one of YODA or YODA-full");
836 "Rivet output requested, but Rivet support not compiled in");
840 <<
"Unknown combination of format (" <<
format <<
") and content ("
841 << content <<
"). Fix the config.";
1072 template <
typename Modus>
1076 modus_(config[
"Modi"], parameters_),
1077 ensembles_(parameters_.n_ensembles),
1078 nevents_(config.take({
"General",
"Nevents"}, 0)),
1079 end_time_(config.take({
"General",
"End_Time"})),
1080 delta_time_startup_(parameters_.labclock->timestep_duration()),
1082 config.take({
"Collision_Term",
"Force_Decays_At_End"},
true)),
1083 use_grid_(config.take({
"General",
"Use_Grid"},
true)),
1086 config.take({
"General",
"Expansion_Rate"}, 0.1)),
1088 config.take({
"Collision_Term",
"Dileptons",
"Decays"},
false)),
1089 photons_switch_(config.take(
1090 {
"Collision_Term",
"Photons",
"2to2_Scatterings"},
false)),
1091 bremsstrahlung_switch_(
1092 config.take({
"Collision_Term",
"Photons",
"Bremsstrahlung"},
false)),
1093 IC_output_switch_(config.has_value({
"Output",
"Initial_Conditions"})),
1098 if (config.has_value({
"General",
"Minimum_Nonempty_Ensembles"})) {
1099 if (config.has_value({
"General",
"Nevents"})) {
1100 throw std::invalid_argument(
1101 "Please specify either Nevents or Minimum_Nonempty_Ensembles.");
1104 minimum_nonempty_ensembles_ =
1105 config.take({
"General",
"Minimum_Nonempty_Ensembles",
"Number"});
1106 int max_ensembles = config.take(
1107 {
"General",
"Minimum_Nonempty_Ensembles",
"Maximum_Ensembles_Run"});
1109 std::ceil(
static_cast<double>(max_ensembles) / parameters_.n_ensembles);
1117 throw std::invalid_argument(
1118 "Covariant Gaussian derivatives only make sense for Covariant Gaussian "
1126 parameters_.discrete_weight < (1. / 7.)) {
1127 throw std::invalid_argument(
1128 "The central weight for discrete smearing should be >= 1./7.");
1133 throw std::invalid_argument(
1134 "The stochastic criterion can only be employed for fixed time step "
1135 "mode and with a grid!");
1139 " testparticles per particle.");
1141 " parallel ensembles.");
1144 if (dileptons_switch_) {
1145 dilepton_finder_ = make_unique<DecayActionsFinderDilepton>();
1147 if (photons_switch_ || bremsstrahlung_switch_) {
1148 n_fractional_photons_ =
1149 config.take({
"Collision_Term",
"Photons",
"Fractional_Photons"}, 100);
1151 if (parameters_.two_to_one) {
1152 if (parameters_.res_lifetime_factor < 0.) {
1153 throw std::invalid_argument(
1154 "Resonance lifetime modifier cannot be negative!");
1158 "Resonance lifetime set to zero. Make sure resonances cannot "
1160 "inelastically (e.g. resonance chains), else SMASH is known to "
1163 action_finders_.emplace_back(make_unique<DecayActionsFinder>(
1164 parameters_.res_lifetime_factor, parameters_.do_weak_decays));
1166 bool no_coll = config.take({
"Collision_Term",
"No_Collisions"},
false);
1167 if ((parameters_.two_to_one || parameters_.included_2to2.any() ||
1168 parameters_.included_multi.any() || parameters_.strings_switch) &&
1170 auto scat_finder = make_unique<ScatterActionsFinder>(config, parameters_);
1171 max_transverse_distance_sqr_ =
1172 scat_finder->max_transverse_distance_sqr(parameters_.testparticles);
1173 process_string_ptr_ = scat_finder->get_process_string_ptr();
1174 action_finders_.emplace_back(std::move(scat_finder));
1176 max_transverse_distance_sqr_ =
1177 parameters_.maximum_cross_section / M_PI *
fm2_mb;
1178 process_string_ptr_ = NULL;
1180 if (modus_.is_box()) {
1181 action_finders_.emplace_back(
1182 make_unique<WallCrossActionsFinder>(parameters_.box_length));
1184 if (IC_output_switch_) {
1185 if (!modus_.is_collider()) {
1186 throw std::runtime_error(
1187 "Initial conditions can only be extracted in collider modus.");
1190 if (config.has_value({
"Output",
"Initial_Conditions",
"Proper_Time"})) {
1193 config.take({
"Output",
"Initial_Conditions",
"Proper_Time"});
1196 double default_proper_time = modus_.nuclei_passing_time();
1197 double lower_bound =
1198 config.take({
"Output",
"Initial_Conditions",
"Lower_Bound"}, 0.5);
1199 if (default_proper_time >= lower_bound) {
1200 proper_time = default_proper_time;
1203 <<
"Nuclei passing time is too short, hypersurface proper time set "
1205 << lower_bound <<
" fm.";
1206 proper_time = lower_bound;
1210 double rapidity_cut = 0.0;
1211 if (config.has_value({
"Output",
"Initial_Conditions",
"Rapidity_Cut"})) {
1213 config.take({
"Output",
"Initial_Conditions",
"Rapidity_Cut"});
1214 if (rapidity_cut <= 0.0) {
1216 <<
"Rapidity cut for initial conditions configured as abs(y) < "
1217 << rapidity_cut <<
" is unreasonable. \nPlease choose a positive, "
1218 <<
"non-zero value or employ SMASH without rapidity cut.";
1219 throw std::runtime_error(
1220 "Kinematic cut for initial conditions malconfigured.");
1224 if (modus_.calculation_frame_is_fixed_target() && rapidity_cut != 0.0) {
1225 throw std::runtime_error(
1226 "Rapidity cut for initial conditions output is not implemented "
1227 "in the fixed target calculation frame. \nPlease use "
1228 "\"center of velocity\" or \"center of mass\" as a "
1229 "\"Calculation_Frame\" instead.");
1232 double transverse_momentum_cut = 0.0;
1233 if (config.has_value({
"Output",
"Initial_Conditions",
"pT_Cut"})) {
1234 transverse_momentum_cut =
1235 config.take({
"Output",
"Initial_Conditions",
"pT_Cut"});
1236 if (transverse_momentum_cut <= 0.0) {
1238 <<
"transverse momentum cut for initial conditions configured as "
1240 << rapidity_cut <<
" is unreasonable. \nPlease choose a positive, "
1241 <<
"non-zero value or employ SMASH without pT cut.";
1242 throw std::runtime_error(
1243 "Kinematic cut for initial conditions malconfigured.");
1247 if (rapidity_cut > 0.0 || transverse_momentum_cut > 0.0) {
1248 kinematic_cuts_for_IC_output_ =
true;
1251 if (rapidity_cut > 0.0 && transverse_momentum_cut > 0.0) {
1253 <<
"Extracting initial conditions in kinematic range: "
1254 << -rapidity_cut <<
" <= y <= " << rapidity_cut
1255 <<
"; pT <= " << transverse_momentum_cut <<
" GeV.";
1256 }
else if (rapidity_cut > 0.0) {
1258 <<
"Extracting initial conditions in kinematic range: "
1259 << -rapidity_cut <<
" <= y <= " << rapidity_cut <<
".";
1260 }
else if (transverse_momentum_cut > 0.0) {
1262 <<
"Extracting initial conditions in kinematic range: pT <= "
1263 << transverse_momentum_cut <<
" GeV.";
1266 <<
"Extracting initial conditions without kinematic cuts.";
1269 action_finders_.emplace_back(make_unique<HyperSurfaceCrossActionsFinder>(
1270 proper_time, rapidity_cut, transverse_momentum_cut));
1273 if (config.has_value({
"Collision_Term",
"Pauli_Blocking"})) {
1275 pauli_blocker_ = make_unique<PauliBlocker>(
1276 config[
"Collision_Term"][
"Pauli_Blocking"], parameters_);
1280 config.take({
"Collision_Term",
"Power_Particle_Formation"},
1281 modus_.sqrt_s_NN() >= 200. ? -1. : 1.);
1317 " create OutputInterface objects");
1319 auto output_conf = config[
"Output"];
1549 <<
"Density type printed to headers: " << dens_type_;
1551 const OutputParameters output_parameters(std::move(output_conf));
1553 std::vector<std::string> output_contents = output_conf.list_upmost_nodes();
1554 for (
const auto &content : output_contents) {
1555 auto this_output_conf = output_conf[content.c_str()];
1556 const std::vector<std::string> formats = this_output_conf.take({
"Format"});
1557 if (output_path ==
"") {
1560 for (
const auto &
format : formats) {
1561 create_output(
format, content, output_path, output_parameters);
1572 if (config.has_value({
"Potentials"})) {
1575 throw std::invalid_argument(
"Can't use potentials without time steps!");
1579 <<
"Potentials don't work with frozen Fermi momenta! "
1580 "Use normal Fermi motion instead.";
1581 throw std::invalid_argument(
1582 "Can't use potentials "
1583 "with frozen Fermi momenta!");
1586 << parameters_.labclock->timestep_duration();
1588 potentials_ = make_unique<Potentials>(config[
"Potentials"], parameters_);
1591 if (potentials_->use_skyrme() && potentials_->use_vdf()) {
1592 throw std::runtime_error(
1593 "Can't use Skyrme and VDF potentials at the same time!");
1595 if (potentials_->use_symmetry() && potentials_->use_vdf()) {
1596 throw std::runtime_error(
1597 "Can't use symmetry and VDF potentials at the same time!");
1599 if (potentials_->use_skyrme()) {
1602 <<
"\t\tSkyrme_A [MeV] = " << potentials_->skyrme_a() <<
"\n";
1604 <<
"\t\tSkyrme_B [MeV] = " << potentials_->skyrme_b() <<
"\n";
1606 <<
"\t\t Skyrme_tau = " << potentials_->skyrme_tau() <<
"\n";
1608 if (potentials_->use_symmetry()) {
1610 <<
"Symmetry potential is:"
1611 <<
"\n S_pot [MeV] = " << potentials_->symmetry_S_pot() <<
"\n";
1613 if (potentials_->use_vdf()) {
1616 << potentials_->saturation_density() <<
"\n";
1617 for (
int i = 0; i < potentials_->number_of_terms(); i++) {
1619 <<
"\t\tCoefficient_" << i + 1 <<
" = "
1620 << 1000.0 * (potentials_->coeffs())[i] <<
" [MeV] \t Power_"
1621 << i + 1 <<
" = " << (potentials_->powers())[i] <<
"\n";
1627 throw std::invalid_argument(
1628 "Derivatives are necessary for running with potentials.\n"
1629 "Derivatives_Mode: \"Off\" only makes sense for "
1630 "Field_Derivatives_Mode: \"Direct\"!\nUse \"Covariant Gaussian\" or "
1631 "\"Finite difference\".");
1639 switch (parameters_.derivatives_mode) {
1650 switch (parameters_.rho_derivatives_mode) {
1659 if (potentials_->use_vdf()) {
1660 switch (parameters_.field_derivatives_mode) {
1673 if (potentials_->use_vdf() && (parameters_.rho_derivatives_mode ==
1675 parameters_.field_derivatives_mode ==
1677 throw std::runtime_error(
1678 "Can't use VDF potentials without rest frame density derivatives or "
1679 "direct field derivatives!");
1684 throw std::runtime_error(
1685 "Can't use potentials without gradients of baryon current (Skyrme, "
1687 " or direct field derivatives (VDF)!");
1690 if (!(potentials_->use_vdf()) &&
1692 throw std::invalid_argument(
1693 "Field_Derivatives_Mode: \"Direct\" only makes sense for the VDF "
1694 "potentials!\nUse Field_Derivatives_Mode: \"Chain Rule\" or comment "
1695 "this option out (Chain Rule is default)");
1700 switch (parameters_.smearing_mode) {
1706 << parameters_.discrete_weight;
1710 << parameters_.triangular_range;
1794 if (config.has_value({
"Lattice"})) {
1795 std::array<double, 3> l_default{20., 20., 20.};
1796 std::array<int, 3> n_default{10, 10, 10};
1797 std::array<double, 3> origin_default{-20., -20., -20.};
1798 bool periodic_default =
false;
1799 if (modus_.is_collider()) {
1801 const double gam = modus_.sqrt_s_NN() / (2.0 *
nucleon_mass);
1802 const double max_z = 5.0 / gam + end_time_;
1803 const double estimated_max_transverse_velocity = 0.7;
1804 const double max_xy = 5.0 + estimated_max_transverse_velocity * end_time_;
1805 origin_default = {-max_xy, -max_xy, -max_z};
1806 l_default = {2 * max_xy, 2 * max_xy, 2 * max_z};
1809 const int n_xy = std::ceil(2 * max_xy / 0.8);
1810 int nz = std::ceil(2 * max_z / 0.8);
1815 nz =
static_cast<int>(std::ceil(2 * max_z / 0.8 * gam));
1817 n_default = {n_xy, n_xy, nz};
1818 }
else if (modus_.is_box()) {
1819 periodic_default =
true;
1820 origin_default = {0., 0., 0.};
1821 const double bl = modus_.length();
1822 l_default = {bl, bl, bl};
1823 const int n_xyz = 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 = std::ceil(2 * max_d / 0.8);
1833 n_default = {n_xyz, n_xyz, n_xyz};
1836 const std::array<double, 3> l =
1837 config.take({
"Lattice",
"Sizes"}, l_default);
1838 const std::array<int, 3>
n =
1839 config.take({
"Lattice",
"Cell_Number"}, n_default);
1840 const std::array<double, 3> origin =
1841 config.take({
"Lattice",
"Origin"}, origin_default);
1842 const bool periodic =
1843 config.take({
"Lattice",
"Periodic"}, periodic_default);
1846 <<
"Lattice is ON. Origin = (" << origin[0] <<
"," << origin[1] <<
","
1847 << origin[2] <<
"), sizes = (" << l[0] <<
"," << l[1] <<
"," << l[2]
1848 <<
"), number of cells = (" <<
n[0] <<
"," <<
n[1] <<
"," <<
n[2]
1851 if (printout_lattice_td_ || printout_full_lattice_any_td_) {
1852 dens_type_lattice_printout_ = output_parameters.td_dens_type;
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_ = make_unique<RectangularLattice<EnergyMomentumTensor>>(
1862 if (printout_j_QBS_) {
1863 j_QBS_lat_ = make_unique<DensityLattice>(l,
n, origin, periodic,
1871 old_jmu_auxiliary_ = make_unique<RectangularLattice<FourVector>>(
1873 new_jmu_auxiliary_ = make_unique<RectangularLattice<FourVector>>(
1875 four_gradient_auxiliary_ =
1876 make_unique<RectangularLattice<std::array<FourVector, 4>>>(
1879 if (potentials_->use_skyrme()) {
1880 jmu_B_lat_ = make_unique<DensityLattice>(l,
n, origin, periodic,
1882 UB_lat_ = make_unique<RectangularLattice<FourVector>>(
1885 RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1888 if (potentials_->use_symmetry()) {
1889 jmu_I3_lat_ = make_unique<DensityLattice>(l,
n, origin, periodic,
1891 UI3_lat_ = make_unique<RectangularLattice<FourVector>>(
1894 RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1897 if (potentials_->use_coulomb()) {
1898 jmu_el_lat_ = make_unique<DensityLattice>(l,
n, origin, periodic,
1901 RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1904 if (potentials_->use_vdf()) {
1905 jmu_B_lat_ = make_unique<DensityLattice>(l,
n, origin, periodic,
1907 UB_lat_ = make_unique<RectangularLattice<FourVector>>(
1910 RectangularLattice<std::pair<ThreeVector, ThreeVector>>>(
1915 old_fields_auxiliary_ = make_unique<RectangularLattice<FourVector>>(
1917 new_fields_auxiliary_ = make_unique<RectangularLattice<FourVector>>(
1919 fields_four_gradient_auxiliary_ =
1920 make_unique<RectangularLattice<std::array<FourVector, 4>>>(
1924 fields_lat_ = make_unique<FieldsLattice>(l,
n, origin, periodic,
1929 jmu_B_lat_ = make_unique<DensityLattice>(l,
n, origin, periodic,
1933 jmu_I3_lat_ = make_unique<DensityLattice>(l,
n, origin, periodic,
1940 jmu_custom_lat_ = make_unique<DensityLattice>(l,
n, origin, periodic,
1943 }
else if (printout_lattice_td_ || printout_full_lattice_any_td_) {
1945 "If you want Therm. VTK or Lattice output, configure a lattice for "
1947 }
else if (potentials_ && potentials_->use_coulomb()) {
1949 "Coulomb potential requires a lattice. Please add one to the "
1954 if ((potentials_ !=
nullptr) && (jmu_B_lat_ ==
nullptr)) {
1955 logg[
LExperiment].warn() <<
"Lattice is NOT used. Mean-field energy is "
1956 <<
"not going to be calculated.";
1960 if (parameters_.potential_affect_threshold) {
1968 (jmu_B_lat_ ==
nullptr)) {
1969 throw std::runtime_error(
1970 "Lattice is necessary to calculate finite difference gradients.");
1974 if (config.has_value({
"Forced_Thermalization"})) {
1975 Configuration &&th_conf = config[
"Forced_Thermalization"];
1976 thermalizer_ = modus_.create_grandcan_thermalizer(th_conf);
1981 seed_ = config.take({
"General",
"Randomseed"});
2012 uint64_t scatterings_this_interval,
2015 double E_mean_field,
2016 double E_mean_field_initial);
2053 double E_mean_field,
double modus_impact_parameter,
2055 bool projectile_target_interact,
2056 bool kinematic_cut_for_SMASH_IC);
2058 template <
typename Modus>
2068 while (r == INT64_MIN) {
2071 seed_ = std::abs(r);
2076 if (process_string_ptr_ != NULL) {
2077 process_string_ptr_->init_pythia_hadron_rndm();
2080 for (
Particles &particles : ensembles_) {
2085 double start_time = -1.0;
2089 if (modus_.is_collider()) {
2090 modus_.sample_impact();
2091 logg[
LExperiment].info(
"Impact parameter = ", modus_.impact_parameter(),
2094 for (
Particles &particles : ensembles_) {
2095 start_time = modus_.initial_conditions(&particles, parameters_);
2100 for (
Particles &particles : ensembles_) {
2101 modus_.impose_boundary_conditions(&particles, outputs_);
2104 double timestep = delta_time_startup_;
2106 switch (time_step_mode_) {
2110 timestep = end_time_ - start_time;
2112 const double max_dt = modus_.max_timestep(max_transverse_distance_sqr_);
2113 if (max_dt > 0. && max_dt < timestep) {
2118 std::unique_ptr<UniformClock> clock_for_this_event;
2119 if (modus_.is_list() && (timestep < 0.0)) {
2120 throw std::runtime_error(
2121 "Timestep for the given event is negative. \n"
2122 "This might happen if the formation times of the input particles are "
2123 "larger than the specified end time of the simulation.");
2125 clock_for_this_event = make_unique<UniformClock>(start_time, timestep);
2126 parameters_.labclock = std::move(clock_for_this_event);
2129 parameters_.outputclock->reset(start_time,
true);
2131 parameters_.outputclock->remove_times_in_past(start_time);
2134 "Lab clock: t_start = ", parameters_.labclock->current_time(),
2135 ", dt = ", parameters_.labclock->timestep_duration());
2140 wall_actions_total_ = 0;
2141 previous_wall_actions_total_ = 0;
2142 interactions_total_ = 0;
2143 previous_interactions_total_ = 0;
2144 discarded_interactions_total_ = 0;
2145 total_pauli_blocked_ = 0;
2146 projectile_target_interact_.assign(parameters_.n_ensembles,
false);
2147 total_hypersurface_crossing_actions_ = 0;
2148 total_energy_removed_ = 0.0;
2151 logg[
LExperiment].info() <<
"Time[fm] Ekin[GeV] E_MF[GeV] ETotal[GeV] "
2152 <<
"ETot/N[GeV] D(ETot/N)[GeV] Scatt&Decays "
2153 <<
"Particles Comp.Time";
2155 double E_mean_field = 0.0;
2160 if ((jmu_B_lat_ !=
nullptr)) {
2162 new_jmu_auxiliary_.get(), four_gradient_auxiliary_.get(),
2164 density_param_, ensembles_,
2165 parameters_.labclock->timestep_duration(),
true);
2169 for (
auto &node : *jmu_B_lat_) {
2170 node.overwrite_drho_dt_to_zero();
2171 node.overwrite_djmu_dt_to_zero();
2174 EM_lat_.get(), parameters_);
2177 initial_mean_field_energy_ = E_mean_field;
2179 ensembles_, 0u, conserved_initial_, time_start_,
2180 parameters_.labclock->current_time(), E_mean_field,
2181 initial_mean_field_energy_);
2184 for (
const auto &output : outputs_) {
2185 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2187 ensembles_, E_mean_field, modus_.impact_parameter(), parameters_,
2188 projectile_target_interact_[i_ens], kinematic_cuts_for_IC_output_);
2189 output->at_eventstart(ensembles_[i_ens],
2191 event_ * parameters_.n_ensembles + i_ens,
2195 output->at_eventstart(ensembles_, event_);
2197 if (printout_full_lattice_any_td_) {
2198 switch (dens_type_lattice_printout_) {
2213 if (printout_tmn_) {
2215 dens_type_lattice_printout_, *Tmn_);
2217 if (printout_tmn_landau_) {
2219 dens_type_lattice_printout_, *Tmn_);
2221 if (printout_v_landau_) {
2223 dens_type_lattice_printout_, *Tmn_);
2225 if (printout_j_QBS_) {
2227 dens_type_lattice_printout_, *j_QBS_lat_);
2239 const double m = particle.effective_mass();
2240 double v_beam = 0.0;
2242 v_beam = modus_.velocity_projectile();
2244 v_beam = modus_.velocity_target();
2246 const double gamma = 1.0 / std::sqrt(1.0 - v_beam * v_beam);
2247 beam_momentum_.emplace_back(
2248 FourVector(gamma * m, 0.0, 0.0, gamma * v_beam * m));
2253 template <
typename Modus>
2255 bool include_pauli_blocking) {
2256 Particles &particles = ensembles_[i_ensemble];
2259 discarded_interactions_total_++;
2261 " (discarded: invalid)");
2266 if (include_pauli_blocking && pauli_blocker_ &&
2268 total_pauli_blocked_++;
2274 if (modus_.is_collider()) {
2275 int count_target = 0, count_projectile = 0;
2283 if (count_target > 0 && count_projectile > 0) {
2284 projectile_target_interact_[i_ensemble] =
true;
2290 const auto id_process =
static_cast<uint32_t
>(interactions_total_ + 1);
2291 action.
perform(&particles, id_process);
2292 interactions_total_++;
2294 wall_actions_total_++;
2297 total_hypersurface_crossing_actions_++;
2304 constexpr
bool compute_grad =
false;
2305 const bool smearing =
true;
2308 rho = std::get<0>(
current_eckart(r_interaction.threevec(), particles,
2309 density_param_, dens_type_, compute_grad,
2327 for (
const auto &output : outputs_) {
2328 if (!output->is_dilepton_output() && !output->is_photon_output()) {
2329 if (output->is_IC_output() &&
2331 output->at_interaction(action, rho);
2332 }
else if (!output->is_IC_output()) {
2333 output->at_interaction(action, rho);
2343 if (photons_switch_ &&
2349 constexpr
double action_time = 0.;
2351 n_fractional_photons_,
2367 photon_act.add_single_process();
2369 photon_act.perform_photons(outputs_);
2372 if (bremsstrahlung_switch_ &&
2377 constexpr
double action_time = 0.;
2380 n_fractional_photons_,
2397 brems_act.add_single_process();
2399 brems_act.perform_bremsstrahlung(outputs_);
2406 template <
typename Modus>
2408 while (parameters_.labclock->current_time() < t_end) {
2409 const double t = parameters_.labclock->current_time();
2411 std::min(parameters_.labclock->timestep_duration(), t_end - t);
2412 logg[
LExperiment].debug(
"Timestepless propagation for next ", dt,
" fm/c.");
2416 thermalizer_->is_time_to_thermalize(parameters_.labclock)) {
2417 const bool ignore_cells_under_treshold =
true;
2420 thermalizer_->update_thermalizer_lattice(ensembles_, density_param_,
2421 ignore_cells_under_treshold);
2422 const double current_t = parameters_.labclock->current_time();
2423 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2424 thermalizer_->thermalize(ensembles_[i_ens], current_t,
2425 parameters_.testparticles);
2428 perform_action(th_act, i_ens);
2433 std::vector<Actions> actions(parameters_.n_ensembles);
2434 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2435 actions[i_ens].clear();
2436 if (ensembles_[i_ens].size() > 0 && action_finders_.size() > 0) {
2438 const double min_cell_length = compute_min_cell_length(dt);
2443 const bool include_unformed_particles = IC_output_switch_;
2445 use_grid_ ? modus_.create_grid(ensembles_[i_ens], min_cell_length,
2446 dt, parameters_.coll_crit,
2447 include_unformed_particles)
2448 : modus_.create_grid(ensembles_[i_ens], min_cell_length,
2449 dt, parameters_.coll_crit,
2450 include_unformed_particles,
2453 const double gcell_vol = grid.cell_volume();
2456 [&](
const ParticleList &search_list) {
2457 for (
const auto &finder : action_finders_) {
2458 actions[i_ens].insert(finder->find_actions_in_cell(
2459 search_list, dt, gcell_vol, beam_momentum_));
2462 [&](
const ParticleList &search_list,
2463 const ParticleList &neighbors_list) {
2464 for (
const auto &finder : action_finders_) {
2465 actions[i_ens].insert(finder->find_actions_with_neighbors(
2466 search_list, neighbors_list, dt, beam_momentum_));
2475 const double end_timestep_time =
2476 std::min(parameters_.labclock->next_time(), t_end);
2477 while (next_output_time() <= end_timestep_time) {
2478 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2479 run_time_evolution_timestepless(actions[i_ens], i_ens,
2480 next_output_time(), t_end);
2482 ++(*parameters_.outputclock);
2485 if (parameters_.outputclock->current_time() < t_end) {
2486 intermediate_output();
2489 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2490 run_time_evolution_timestepless(actions[i_ens], i_ens, end_timestep_time,
2497 update_potentials();
2498 update_momenta(ensembles_, parameters_.labclock->timestep_duration(),
2499 *potentials_, FB_lat_.get(), FI3_lat_.get(),
2506 for (
Particles &particles : ensembles_) {
2511 ++(*parameters_.labclock);
2519 if (!potentials_ && !parameters_.strings_switch &&
2521 std::string err_msg = conserved_initial_.report_deviations(ensembles_);
2522 if (!err_msg.empty()) {
2524 throw std::runtime_error(
"Violation of conserved quantities!");
2529 if (pauli_blocker_) {
2531 "Interactions: Pauli-blocked/performed = ", total_pauli_blocked_,
"/",
2532 interactions_total_ - wall_actions_total_);
2536 template <
typename Modus>
2541 if (dilepton_finder_ !=
nullptr) {
2542 for (
const auto &output : outputs_) {
2543 dilepton_finder_->shine(particles, output.get(), dt);
2556 constexpr uint64_t max_uint32 = std::numeric_limits<uint32_t>::max();
2557 if (interactions_total >= max_uint32) {
2558 throw std::runtime_error(
"Integer overflow in total interaction number!");
2562 template <
typename Modus>
2564 Actions &actions,
int i_ensemble,
const double end_time_propagation,
2565 const double end_time_run) {
2566 Particles &particles = ensembles_[i_ensemble];
2568 "Timestepless propagation: ",
"Actions size = ", actions.
size(),
2569 ", end time = ", end_time_propagation);
2577 ActionPtr act = actions.
pop();
2578 if (!act->is_valid(particles)) {
2579 discarded_interactions_total_++;
2581 " (discarded: invalid)");
2585 ", action time = ", act->time_of_execution());
2588 propagate_and_shine(act->time_of_execution(), particles);
2595 act->update_incoming(particles);
2596 const bool performed = perform_action(*act, i_ensemble);
2606 const double end_time_timestep =
2607 std::min(parameters_.labclock->next_time(), end_time_run);
2608 assert(!(end_time_propagation > end_time_timestep));
2610 const double time_left = end_time_timestep - act->time_of_execution();
2611 const ParticleList &outgoing_particles = act->outgoing_particles();
2613 const double gcell_vol = 0.0;
2614 for (
const auto &finder : action_finders_) {
2616 actions.
insert(finder->find_actions_in_cell(outgoing_particles, time_left,
2617 gcell_vol, beam_momentum_));
2619 actions.
insert(finder->find_actions_with_surrounding_particles(
2620 outgoing_particles, particles, time_left, beam_momentum_));
2626 propagate_and_shine(end_time_propagation, particles);
2629 template <
typename Modus>
2631 const uint64_t wall_actions_this_interval =
2632 wall_actions_total_ - previous_wall_actions_total_;
2633 previous_wall_actions_total_ = wall_actions_total_;
2634 const uint64_t interactions_this_interval = interactions_total_ -
2635 previous_interactions_total_ -
2636 wall_actions_this_interval;
2637 previous_interactions_total_ = interactions_total_;
2638 double E_mean_field = 0.0;
2641 double computational_frame_time = 0.0;
2644 if ((jmu_B_lat_ !=
nullptr)) {
2646 EM_lat_.get(), parameters_);
2653 if (modus_.is_box()) {
2654 double tmp = (E_mean_field - initial_mean_field_energy_) /
2655 (E_mean_field + initial_mean_field_energy_);
2661 if (std::abs(tmp) > 0.01) {
2663 <<
"\n\n\n\t The mean field at t = "
2664 << parameters_.outputclock->current_time()
2665 <<
" [fm/c] differs from the mean field at t = 0:"
2666 <<
"\n\t\t initial_mean_field_energy_ = "
2667 << initial_mean_field_energy_ <<
" [GeV]"
2668 <<
"\n\t\t abs[(E_MF - E_MF(t=0))/(E_MF + E_MF(t=0))] = "
2670 <<
"\n\t\t E_MF/E_MF(t=0) = "
2671 << E_mean_field / initial_mean_field_energy_ <<
"\n\n";
2678 ensembles_, interactions_this_interval, conserved_initial_, time_start_,
2679 parameters_.outputclock->current_time(), E_mean_field,
2680 initial_mean_field_energy_);
2684 if (!(modus_.is_box() && parameters_.outputclock->current_time() <
2685 modus_.equilibration_time())) {
2686 for (
const auto &output : outputs_) {
2687 if (output->is_dilepton_output() || output->is_photon_output() ||
2688 output->is_IC_output()) {
2691 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2693 ensembles_, E_mean_field, modus_.impact_parameter(), parameters_,
2694 projectile_target_interact_[i_ens], kinematic_cuts_for_IC_output_);
2696 output->at_intermediate_time(ensembles_[i_ens], parameters_.outputclock,
2697 density_param_, event_info);
2698 computational_frame_time = event_info.current_time;
2701 output->at_intermediate_time(ensembles_, parameters_.outputclock,
2705 switch (dens_type_lattice_printout_) {
2708 density_param_, ensembles_,
false);
2711 output->thermodynamics_lattice_output(*jmu_B_lat_,
2712 computational_frame_time);
2721 output->thermodynamics_lattice_output(*jmu_I3_lat_,
2722 computational_frame_time);
2728 dens_type_lattice_printout_, density_param_,
2731 dens_type_lattice_printout_,
2733 output->thermodynamics_lattice_output(*jmu_custom_lat_,
2734 computational_frame_time);
2736 if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
2738 density_param_, ensembles_,
false);
2739 if (printout_tmn_) {
2741 dens_type_lattice_printout_, *Tmn_);
2742 output->thermodynamics_lattice_output(
2745 if (printout_tmn_landau_) {
2747 dens_type_lattice_printout_, *Tmn_);
2748 output->thermodynamics_lattice_output(
2750 computational_frame_time);
2752 if (printout_v_landau_) {
2754 dens_type_lattice_printout_, *Tmn_);
2755 output->thermodynamics_lattice_output(
2757 computational_frame_time);
2761 output->fields_output(
"Efield",
"Bfield", *EM_lat_);
2763 if (printout_j_QBS_) {
2764 output->thermodynamics_lattice_output(
2765 *j_QBS_lat_, computational_frame_time, ensembles_, density_param_);
2769 output->thermodynamics_output(*thermalizer_);
2775 template <
typename Modus>
2778 if (potentials_->use_symmetry() && jmu_I3_lat_ !=
nullptr) {
2780 new_jmu_auxiliary_.get(), four_gradient_auxiliary_.get(),
2782 density_param_, ensembles_,
2783 parameters_.labclock->timestep_duration(),
true);
2785 if ((potentials_->use_skyrme() || potentials_->use_symmetry()) &&
2786 jmu_B_lat_ !=
nullptr) {
2788 new_jmu_auxiliary_.get(), four_gradient_auxiliary_.get(),
2790 density_param_, ensembles_,
2791 parameters_.labclock->timestep_duration(),
true);
2792 const size_t UBlattice_size = UB_lat_->size();
2793 for (
size_t i = 0; i < UBlattice_size; i++) {
2794 auto jB = (*jmu_B_lat_)[i];
2798 double baryon_density = jB.rho();
2802 if (potentials_->use_skyrme()) {
2804 flow_four_velocity_B * potentials_->skyrme_pot(baryon_density);
2806 potentials_->skyrme_force(baryon_density, baryon_grad_j0,
2807 baryon_dvecj_dt, baryon_curl_vecj);
2809 if (potentials_->use_symmetry() && jmu_I3_lat_ !=
nullptr) {
2810 auto jI3 = (*jmu_I3_lat_)[i];
2813 ? jI3.jmu_net() / jI3.rho()
2815 (*UI3_lat_)[i] = flow_four_velocity_I3 *
2816 potentials_->symmetry_pot(jI3.rho(), baryon_density);
2817 (*FI3_lat_)[i] = potentials_->symmetry_force(
2818 jI3.rho(), jI3.grad_j0(), jI3.dvecj_dt(), jI3.curl_vecj(),
2819 baryon_density, baryon_grad_j0, baryon_dvecj_dt,
2824 if (potentials_->use_coulomb()) {
2827 for (
size_t i = 0; i < EM_lat_->size(); i++) {
2829 ThreeVector position = jmu_el_lat_->cell_center(i);
2830 jmu_el_lat_->integrate_volume(electric_field,
2832 potentials_->coulomb_r_cut(), position);
2834 jmu_el_lat_->integrate_volume(magnetic_field,
2836 potentials_->coulomb_r_cut(), position);
2837 (*EM_lat_)[i] = std::make_pair(electric_field, magnetic_field);
2840 if (potentials_->use_vdf() && jmu_B_lat_ !=
nullptr) {
2842 new_jmu_auxiliary_.get(), four_gradient_auxiliary_.get(),
2844 density_param_, ensembles_,
2845 parameters_.labclock->timestep_duration(),
true);
2848 fields_lat_.get(), old_fields_auxiliary_.get(),
2849 new_fields_auxiliary_.get(), fields_four_gradient_auxiliary_.get(),
2851 parameters_.labclock->timestep_duration());
2853 const size_t UBlattice_size = UB_lat_->size();
2854 for (
size_t i = 0; i < UBlattice_size; i++) {
2855 auto jB = (*jmu_B_lat_)[i];
2856 (*UB_lat_)[i] = potentials_->vdf_pot(jB.rho(), jB.jmu_net());
2857 switch (parameters_.field_derivatives_mode) {
2859 (*FB_lat_)[i] = potentials_->vdf_force(
2860 jB.rho(), jB.drho_dxnu().x0(), jB.drho_dxnu().threevec(),
2861 jB.grad_rho_cross_vecj(), jB.jmu_net().x0(), jB.grad_j0(),
2862 jB.jmu_net().threevec(), jB.dvecj_dt(), jB.curl_vecj());
2865 auto Amu = (*fields_lat_)[i];
2866 (*FB_lat_)[i] = potentials_->vdf_force(
2867 Amu.grad_A0(), Amu.dvecA_dt(), Amu.curl_vecA());
2875 template <
typename Modus>
2879 bool actions_performed, decays_found;
2880 uint64_t interactions_old;
2882 decays_found =
false;
2883 interactions_old = interactions_total_;
2884 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
2888 if (dilepton_finder_ !=
nullptr) {
2889 for (
const auto &output : outputs_) {
2890 dilepton_finder_->shine_final(ensembles_[i_ens], output.get(),
true);
2894 for (
const auto &finder : action_finders_) {
2895 auto found_actions = finder->find_final_actions(ensembles_[i_ens]);
2896 if (!found_actions.empty()) {
2897 actions.
insert(std::move(found_actions));
2898 decays_found =
true;
2903 perform_action(*actions.
pop(), i_ens,
false);
2906 actions_performed = interactions_total_ > interactions_old;
2908 if (decays_found && !actions_performed) {
2909 throw std::runtime_error(
"Final decays were found but not performed.");
2912 }
while (actions_performed);
2915 if (dilepton_finder_ !=
nullptr) {
2916 for (
const auto &output : outputs_) {
2917 for (
Particles &particles : ensembles_) {
2918 dilepton_finder_->shine_final(particles, output.get(),
false);
2924 template <
typename Modus>
2929 double E_mean_field = 0.0;
2930 if (
likely(parameters_.labclock > 0)) {
2931 const uint64_t wall_actions_this_interval =
2932 wall_actions_total_ - previous_wall_actions_total_;
2933 const uint64_t interactions_this_interval = interactions_total_ -
2934 previous_interactions_total_ -
2935 wall_actions_this_interval;
2938 if ((jmu_B_lat_ !=
nullptr)) {
2940 EM_lat_.get(), parameters_);
2944 ensembles_, interactions_this_interval, conserved_initial_, time_start_,
2945 end_time_, E_mean_field, initial_mean_field_energy_);
2946 int total_particles = 0;
2947 for (
const Particles &particles : ensembles_) {
2948 total_particles += particles.
size();
2950 if (IC_output_switch_ && (total_particles == 0)) {
2953 const double remaining_energy =
2954 conserved_initial_.momentum().x0() - total_energy_removed_;
2956 throw std::runtime_error(
2957 "There is remaining energy in the system although all particles "
2960 std::to_string(remaining_energy) +
" [GeV]");
2964 <<
"Time real: " << SystemClock::now() - time_start_;
2966 <<
"Interactions before reaching hypersurface: "
2967 << interactions_total_ - wall_actions_total_ -
2968 total_hypersurface_crossing_actions_;
2970 <<
"Total number of particles removed on hypersurface: "
2971 << total_hypersurface_crossing_actions_;
2974 const double precent_discarded =
2975 interactions_total_ > 0
2976 ?
static_cast<double>(discarded_interactions_total_) * 100.0 /
2979 std::stringstream msg_discarded;
2981 <<
"Discarded interaction number: " << discarded_interactions_total_
2982 <<
" (" << precent_discarded
2983 <<
"% of the total interaction number including wall crossings)";
2987 <<
"Time real: " << SystemClock::now() - time_start_;
2991 precent_discarded > 1.0) {
2994 << msg_discarded.str()
2995 <<
"\nThe number of discarded interactions is large, which means "
2996 "the assumption for the stochastic criterion of\n1 interaction "
2997 "per particle per timestep is probably violated. Consider "
2998 "reducing the timestep size.";
3002 << interactions_total_ - wall_actions_total_;
3006 int unformed_particles_count = 0;
3007 for (
const Particles &particles : ensembles_) {
3009 if (particle.formation_time() > end_time_) {
3010 unformed_particles_count++;
3014 if (unformed_particles_count > 0) {
3016 "End time might be too small. ", unformed_particles_count,
3017 " unformed particles were found at the end of the evolution.");
3022 count_nonempty_ensembles();
3024 for (
const auto &output : outputs_) {
3025 for (
int i_ens = 0; i_ens < parameters_.n_ensembles; i_ens++) {
3027 ensembles_, E_mean_field, modus_.impact_parameter(), parameters_,
3028 projectile_target_interact_[i_ens], kinematic_cuts_for_IC_output_);
3029 output->at_eventend(ensembles_[i_ens],
3031 event_ * parameters_.n_ensembles + i_ens, event_info);
3034 output->at_eventend(ensembles_, event_);
3039 dens_type_lattice_printout_);
3042 if (printout_tmn_) {
3044 dens_type_lattice_printout_);
3047 if (printout_tmn_landau_) {
3049 dens_type_lattice_printout_);
3052 if (printout_v_landau_) {
3054 dens_type_lattice_printout_);
3057 if (printout_j_QBS_) {
3063 template <
typename Modus>
3065 for (
bool has_interaction : projectile_target_interact_) {
3066 if (has_interaction) {
3067 nonempty_ensembles_++;
3072 template <
typename Modus>
3075 return event_ >= nevents_;
3078 if (nonempty_ensembles_ >= minimum_nonempty_ensembles_) {
3081 if (event_ >= max_events_) {
3083 <<
"Maximum number of events (" << max_events_
3084 <<
") exceeded. Stopping calculation. "
3085 <<
"The fraction of empty ensembles is "
3086 << (1.0 -
static_cast<double>(nonempty_ensembles_) /
3087 (event_ * parameters_.n_ensembles))
3088 <<
". If this fraction is expected, try increasing the "
3089 "Maximum_Ensembles_Run.";
3094 throw std::runtime_error(
"Event counting option is invalid");
3098 template <
typename Modus>
3101 for (event_ = 0; !is_finished(); event_++) {
3102 mainlog.info() <<
"Event " << event_;
3105 initialize_new_event();
3107 run_time_evolution(end_time_);
3109 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.
const ParticleList & incoming_particles() const
Get the list of particles that go into the action.
virtual void perform(Particles *particles, uint32_t id_process)
Actually perform the action, e.g.
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.
static bool is_bremsstrahlung_reaction(const ParticleList &in)
Check if particles can undergo an implemented photon process.
Interface to the SMASH configuration files.
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 bf::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.
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.
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.
bool printout_full_lattice_ascii_td_
Whether to print the thermodynamics quantities evaluated on the lattices, point by point,...
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,...
Particles * first_ensemble()
Provides external access to SMASH particles.
int minimum_nonempty_ensembles_
The number of ensembles, in which interactions take place, to be calculated.
void run_time_evolution_timestepless(Actions &actions, int i_ensemble, const double end_time_propagation, const double end_time_run)
Performs all the propagations and actions during a certain time interval neglecting the influence of ...
std::unique_ptr< DensityLattice > jmu_B_lat_
Baryon density on the lattice.
void create_output(const std::string &format, const std::string &content, const bf::path &output_path, const OutputParameters &par)
Create a list of output files.
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.
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.
Experiment(Configuration config, const bf::path &output_path)
Create a new Experiment.
bool printout_full_lattice_binary_td_
Whether to print the thermodynamics quantities evaluated on the lattices, point by point,...
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.
void run_time_evolution(const double t_end)
Runs the time evolution of an event with fixed-sized time steps or without timesteps,...
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.
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.
static ThreeVector B_field_integrand(ThreeVector pos, DensityOnLattice &charge_density, ThreeVector point)
Integrand for calculating the magnetic field using the Biot-Savart formula.
static ThreeVector E_field_integrand(ThreeVector pos, DensityOnLattice &charge_density, ThreeVector point)
Integrand for calculating the electric field.
A container for storing conserved values.
A container class to hold all the arrays on the lattice and access them.
static bool is_photon_reaction(const ParticleList &in)
Check if particles can undergo an implemented photon process.
static bool is_kinematically_possible(const double s_sqrt, const ParticleList &in)
Check if CM-energy is sufficient to produce hadron in final state.
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 .
FermiMotion
Option to use Fermi Motion.
@ Frozen
Use fermi motion without potentials.
@ Off
Don't use fermi motion.
TimeStepMode
The time step mode.
@ Fixed
Use fixed time step.
@ None
Don't use time steps; propagate from action to action.
@ Stochastic
Stochastic Criteiron.
EventCounting
Defines how the number of events is determined.
#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 bf::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.
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)
Updates the momenta of all particles at the current time step according to the equations of motion:
static constexpr int LInitialConditions
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.
@ HyperSurfaceCrossing
Hypersurface crossing Particles are removed from the evolution and printed to a separate output to se...
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.
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.
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.
ExperimentParameters create_experiment_parameters(Configuration config)
Gathers all general Experiment parameters.
std::unique_ptr< T > make_unique(Args &&... args)
Definition for make_unique Is in C++14's standard library; necessary for older compilers.
@ Largest
Make cells as large as possible.
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.