7 #ifndef SRC_INCLUDE_EXPERIMENT_H_ 8 #define SRC_INCLUDE_EXPERIMENT_H_ 57 template <
typename T,
typename Ratio>
59 const chrono::duration<T, Ratio> &seconds) {
60 using Seconds = chrono::duration<double>;
61 using Minutes = chrono::duration<double, std::ratio<60>>;
62 using Hours = chrono::duration<double, std::ratio<60 * 60>>;
63 constexpr Minutes threshold_for_minutes{10};
64 constexpr Hours threshold_for_hours{3};
65 if (seconds < threshold_for_minutes) {
66 return out << Seconds(seconds).count() <<
" [s]";
68 if (seconds < threshold_for_hours) {
69 return out << Minutes(seconds).count() <<
" [min]";
71 return out << Hours(seconds).count() <<
" [h]";
113 static std::unique_ptr<ExperimentBase> create(
Configuration config,
114 const bf::path &output_path);
122 virtual void run() = 0;
130 using std::invalid_argument::invalid_argument;
134 template <
typename Modus>
136 template <
typename Modus>
137 std::ostream &operator<<(std::ostream &out, const Experiment<Modus> &e);
163 template <
typename Modus>
196 void initialize_new_event();
204 void run_time_evolution();
207 void do_final_decays();
214 void final_output(
const int evt_num);
240 template <
typename Container>
241 bool perform_action(
Action &action,
242 const Container &particles_before_actions);
251 void create_output(
const std::string &
format,
const std::string &content,
260 void propagate_and_shine(
double to_time);
274 void run_time_evolution_timestepless(
Actions &actions);
277 void intermediate_output();
280 void update_potentials();
291 return std::sqrt(4 * dt * dt + max_transverse_distance_sqr_);
296 return parameters_.outputclock->next_time();
347 std::vector<bool> nucleon_has_interacted_ = {};
351 bool projectile_target_interact_ =
false;
358 std::vector<FourVector> beam_momentum_ = {};
370 int n_fractional_photons_ = 100;
394 std::unique_ptr<RectangularLattice<FourVector>> UB_lat_ =
nullptr;
400 std::unique_ptr<RectangularLattice<FourVector>> UI3_lat_ =
nullptr;
403 std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
407 std::unique_ptr<RectangularLattice<std::pair<ThreeVector, ThreeVector>>>
411 std::unique_ptr<RectangularLattice<EnergyMomentumTensor>>
Tmn_;
414 bool printout_tmn_ =
false;
417 bool printout_tmn_landau_ =
false;
420 bool printout_v_landau_ =
false;
423 bool printout_lattice_td_ =
false;
485 double max_transverse_distance_sqr_ = std::numeric_limits<double>::max();
506 uint64_t interactions_total_ = 0;
512 uint64_t previous_interactions_total_ = 0;
518 uint64_t wall_actions_total_ = 0;
524 uint64_t previous_wall_actions_total_ = 0;
530 uint64_t total_pauli_blocked_ = 0;
536 uint64_t total_hypersurface_crossing_actions_ = 0;
542 double total_energy_removed_ = 0.0;
552 friend std::ostream &operator<<<>(std::ostream &out,
const Experiment &e);
556 template <
typename Modus>
557 std::ostream &operator<<(std::ostream &out, const Experiment<Modus> &e) {
558 out <<
"End time: " << e.end_time_ <<
" fm/c\n";
563 template <
typename Modus>
565 const std::string &content,
566 const bf::path &output_path,
568 const auto &log = logger<LogArea::Experiment>();
569 log.info() <<
"Adding output " << content <<
" of format " << format
572 if (format ==
"VTK" && content ==
"Particles") {
573 outputs_.emplace_back(
574 make_unique<VtkOutput>(output_path, content, out_par));
575 }
else if (format ==
"Root") {
576 #ifdef SMASH_USE_ROOT 577 if (content ==
"Initial_Conditions") {
578 outputs_.emplace_back(
579 make_unique<RootOutput>(output_path,
"SMASH_IC", out_par));
581 outputs_.emplace_back(
582 make_unique<RootOutput>(output_path, content, out_par));
585 log.error(
"Root output requested, but Root support not compiled in");
587 }
else if (format ==
"Binary") {
588 if (content ==
"Collisions" || content ==
"Dileptons" ||
589 content ==
"Photons") {
590 outputs_.emplace_back(
591 make_unique<BinaryOutputCollisions>(output_path, content, out_par));
592 }
else if (content ==
"Particles") {
593 outputs_.emplace_back(
594 make_unique<BinaryOutputParticles>(output_path, content, out_par));
595 }
else if (content ==
"Initial_Conditions") {
596 outputs_.emplace_back(make_unique<BinaryOutputInitialConditions>(
597 output_path, content, out_par));
599 }
else if (format ==
"Oscar1999" || format ==
"Oscar2013") {
600 outputs_.emplace_back(
602 }
else if (content ==
"Thermodynamics" && format ==
"ASCII") {
603 outputs_.emplace_back(
604 make_unique<ThermodynamicOutput>(output_path, content, out_par));
605 }
else if (content ==
"Thermodynamics" && format ==
"VTK") {
606 printout_lattice_td_ =
true;
607 outputs_.emplace_back(
608 make_unique<VtkOutput>(output_path, content, out_par));
609 }
else if (content ==
"Initial_Conditions" && format ==
"ASCII") {
610 outputs_.emplace_back(
611 make_unique<ICOutput>(output_path,
"SMASH_IC", out_par));
613 log.error() <<
"Unknown combination of format (" << format
614 <<
") and content (" << content <<
"). Fix the config.";
755 template <
typename Modus>
759 modus_(config[
"Modi"], parameters_),
761 nevents_(config.
take({
"General",
"Nevents"})),
762 end_time_(config.
take({
"General",
"End_Time"})),
763 delta_time_startup_(parameters_.labclock->timestep_duration()),
765 config.
take({
"Collision_Term",
"Force_Decays_At_End"},
true)),
766 use_grid_(config.
take({
"General",
"Use_Grid"},
true)),
769 config.
take({
"General",
"Expansion_Rate"}, 0.1)),
770 dileptons_switch_(config.
has_value({
"Output",
"Dileptons"})),
771 photons_switch_(config.
has_value({
"Output",
"Photons"})),
772 IC_output_switch_(config.
has_value({
"Output",
"Initial_Conditions"})),
775 const auto &log = logger<LogArea::Experiment>();
779 if (dileptons_switch_) {
780 dilepton_finder_ = make_unique<DecayActionsFinderDilepton>();
782 if (parameters_.photons_switch) {
783 n_fractional_photons_ = config.
take({
"Output",
"Photons",
"Fractions"});
785 if (parameters_.two_to_one) {
786 action_finders_.emplace_back(make_unique<DecayActionsFinder>());
788 bool no_coll = config.
take({
"Collision_Term",
"No_Collisions"},
false);
789 if ((parameters_.two_to_one || parameters_.included_2to2.any() ||
790 parameters_.strings_switch) &&
792 auto scat_finder = make_unique<ScatterActionsFinder>(
793 config, parameters_, nucleon_has_interacted_, modus_.total_N_number(),
794 modus_.proj_N_number());
795 max_transverse_distance_sqr_ =
796 scat_finder->max_transverse_distance_sqr(parameters_.testparticles);
797 process_string_ptr_ = scat_finder->get_process_string_ptr();
798 action_finders_.emplace_back(std::move(scat_finder));
801 process_string_ptr_ = NULL;
803 const double modus_l = modus_.length();
805 action_finders_.emplace_back(make_unique<WallCrossActionsFinder>(modus_l));
807 if (IC_output_switch_) {
808 if (!modus_.is_collider()) {
809 throw std::runtime_error(
810 "Initial conditions can only be extracted in collider modus.");
813 if (config.
has_value({
"Output",
"Initial_Conditions",
"Proper_Time"})) {
816 config.
take({
"Output",
"Initial_Conditions",
"Proper_Time"});
819 proper_time = modus_.nuclei_passing_time();
821 action_finders_.emplace_back(
822 make_unique<HyperSurfaceCrossActionsFinder>(proper_time));
825 if (config.
has_value({
"Collision_Term",
"Pauli_Blocking"})) {
826 log.info() <<
"Pauli blocking is ON.";
827 pauli_blocker_ = make_unique<PauliBlocker>(
828 config[
"Collision_Term"][
"Pauli_Blocking"], parameters_);
830 ParticleData::formation_power_ =
831 config.
take({
"Collision_Term",
"Power_Particle_Formation"}, 1.);
869 auto output_conf = config[
"Output"];
1147 dens_type_ = config.
take({
"Output",
"Density_Type"}, DensityType::None);
1148 log.debug() <<
"Density type printed to headers: " << dens_type_;
1152 std::vector<std::string> output_contents = output_conf.list_upmost_nodes();
1153 for (
const auto &content : output_contents) {
1154 auto this_output_conf = output_conf[content.c_str()];
1155 const std::vector<std::string> formats = this_output_conf.take({
"Format"});
1156 if (output_path ==
"") {
1159 for (
const auto &
format : formats) {
1160 create_output(
format, content, output_path, output_parameters);
1173 log.error() <<
"Potentials only work with time steps!";
1174 throw std::invalid_argument(
"Can't use potentials without time steps!");
1177 log.error() <<
"Potentials don't work with frozen Fermi momenta! " 1178 "Use normal Fermi motion instead.";
1179 throw std::invalid_argument(
1180 "Can't use potentials " 1181 "with frozen Fermi momenta!");
1183 log.info() <<
"Potentials are ON. Timestep is " 1184 << parameters_.labclock->timestep_duration();
1186 potentials_ = make_unique<Potentials>(config[
"Potentials"], parameters_);
1246 const std::array<double, 3> l = config.
take({
"Lattice",
"Sizes"});
1247 const std::array<int, 3>
n = config.
take({
"Lattice",
"Cell_Number"});
1248 const std::array<double, 3> origin = config.
take({
"Lattice",
"Origin"});
1249 const bool periodic = config.
take({
"Lattice",
"Periodic"});
1251 if (printout_lattice_td_) {
1252 dens_type_lattice_printout_ = output_parameters.
td_dens_type;
1253 printout_tmn_ = output_parameters.
td_tmn;
1255 printout_v_landau_ = output_parameters.
td_v_landau;
1257 if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
1258 Tmn_ = make_unique<RectangularLattice<EnergyMomentumTensor>>(
1259 l,
n, origin, periodic, LatticeUpdate::AtOutput);
1265 if (potentials_->use_skyrme()) {
1266 jmu_B_lat_ = make_unique<DensityLattice>(l,
n, origin, periodic,
1267 LatticeUpdate::EveryTimestep);
1268 UB_lat_ = make_unique<RectangularLattice<FourVector>>(
1269 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1272 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1274 if (potentials_->use_symmetry()) {
1275 jmu_I3_lat_ = make_unique<DensityLattice>(l,
n, origin, periodic,
1276 LatticeUpdate::EveryTimestep);
1277 UI3_lat_ = make_unique<RectangularLattice<FourVector>>(
1278 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1281 l,
n, origin, periodic, LatticeUpdate::EveryTimestep);
1284 if (dens_type_lattice_printout_ == DensityType::Baryon) {
1285 jmu_B_lat_ = make_unique<DensityLattice>(l,
n, origin, periodic,
1286 LatticeUpdate::AtOutput);
1288 if (dens_type_lattice_printout_ == DensityType::BaryonicIsospin) {
1289 jmu_I3_lat_ = make_unique<DensityLattice>(l,
n, origin, periodic,
1290 LatticeUpdate::AtOutput);
1293 if (dens_type_lattice_printout_ != DensityType::None &&
1294 dens_type_lattice_printout_ != DensityType::BaryonicIsospin &&
1295 dens_type_lattice_printout_ != DensityType::Baryon) {
1296 jmu_custom_lat_ = make_unique<DensityLattice>(l,
n, origin, periodic,
1297 LatticeUpdate::AtOutput);
1299 }
else if (printout_lattice_td_) {
1301 "If you want Thermodynamic VTK output, configure a lattice for it.");
1305 if (parameters_.potential_affect_threshold) {
1312 if (config.
has_value({
"Forced_Thermalization"})) {
1314 thermalizer_ = modus_.create_grandcan_thermalizer(th_conf);
1319 seed_ = config.
take({
"General",
"Randomseed"});
1323 const std::string
hline(67,
'-');
1325 template <
typename Modus>
1327 const auto &log = logger<LogArea::Experiment>();
1330 log.info() <<
"random number seed: " << seed_;
1337 while (r == INT64_MIN) {
1340 seed_ = std::abs(r);
1345 if (process_string_ptr_ != NULL) {
1346 process_string_ptr_->init_pythia_hadron_rndm();
1352 double start_time = modus_.initial_conditions(&particles_, parameters_);
1356 modus_.impose_boundary_conditions(&particles_, outputs_);
1358 double timestep = delta_time_startup_;
1360 switch (time_step_mode_) {
1364 timestep = end_time_ - start_time;
1366 const double max_dt = modus_.max_timestep(max_transverse_distance_sqr_);
1367 if (max_dt > 0. && max_dt < timestep) {
1372 std::unique_ptr<UniformClock> clock_for_this_event;
1373 if (modus_.is_list() && (timestep < 0.0)) {
1374 throw std::runtime_error(
1375 "Timestep for the given event is negative. \n" 1376 "This might happen if the formation times of the input particles are " 1377 "larger than the specified end time of the simulation.");
1379 clock_for_this_event = make_unique<UniformClock>(start_time, timestep);
1380 parameters_.labclock = std::move(clock_for_this_event);
1383 parameters_.outputclock->reset(start_time,
true);
1385 parameters_.outputclock->remove_times_in_past(start_time);
1387 log.debug(
"Lab clock: t_start = ", parameters_.labclock->current_time(),
1388 ", dt = ", parameters_.labclock->timestep_duration());
1393 wall_actions_total_ = 0;
1394 previous_wall_actions_total_ = 0;
1395 interactions_total_ = 0;
1396 previous_interactions_total_ = 0;
1397 total_pauli_blocked_ = 0;
1398 projectile_target_interact_ =
false;
1399 total_hypersurface_crossing_actions_ = 0;
1400 total_energy_removed_ = 0.0;
1402 log.info() <<
hline;
1403 log.info() <<
"Time [fm] Ediff [GeV] Scatt.|Decays " 1405 log.info() <<
hline;
1408 template <
typename Modus>
1409 template <
typename Container>
1411 Action &action,
const Container &particles_before_actions) {
1412 const auto &log = logger<LogArea::Experiment>();
1414 if (!action.
is_valid(particles_)) {
1415 log.debug(~
einhard::DRed(),
"✘ ", action,
" (discarded: invalid)");
1419 log.debug(
"Process Type is: ", action.
get_type());
1420 if (pauli_blocker_ && action.
is_pauli_blocked(particles_, *pauli_blocker_)) {
1421 total_pauli_blocked_++;
1424 if (modus_.is_collider()) {
1427 bool incoming_projectile =
false;
1428 bool incoming_target =
false;
1430 assert(incoming.id() >= 0);
1431 if (incoming.id() < modus_.total_N_number()) {
1432 nucleon_has_interacted_[incoming.id()] =
true;
1434 if (incoming.id() < modus_.proj_N_number()) {
1435 incoming_projectile =
true;
1437 if (incoming.id() >= modus_.proj_N_number() &&
1438 incoming.id() < modus_.total_N_number()) {
1439 incoming_target =
true;
1443 if (incoming_projectile & incoming_target) {
1444 projectile_target_interact_ =
true;
1449 const auto id_process =
static_cast<uint32_t
>(interactions_total_ + 1);
1450 action.
perform(&particles_, id_process);
1451 interactions_total_++;
1452 if (action.
get_type() == ProcessType::Wall) {
1453 wall_actions_total_++;
1455 if (action.
get_type() == ProcessType::HyperSurfaceCrossing) {
1456 total_hypersurface_crossing_actions_++;
1461 if (dens_type_ != DensityType::None) {
1463 constexpr
bool compute_grad =
false;
1464 const bool smearing =
true;
1466 particles_before_actions, density_param_,
1467 dens_type_, compute_grad, smearing));
1484 for (
const auto &output : outputs_) {
1485 if (!output->is_dilepton_output() && !output->is_photon_output()) {
1486 if (output->is_IC_output() &&
1487 action.
get_type() == ProcessType::HyperSurfaceCrossing) {
1488 output->at_interaction(action, rho);
1489 }
else if (!output->is_IC_output()) {
1490 output->at_interaction(action, rho);
1500 if (photons_switch_ &&
1502 ScatterActionPhoton::is_kinematically_possible(
1506 constexpr
double action_time = 0.;
1508 n_fractional_photons_,
1524 photon_act.add_single_process();
1526 photon_act.perform_photons(outputs_);
1553 uint64_t scatterings_this_interval,
1557 template <
typename Modus>
1561 const auto &log = logger<LogArea::Experiment>();
1565 parameters_.labclock->current_time());
1567 while (parameters_.labclock->current_time() < end_time_) {
1568 const double t = parameters_.labclock->current_time();
1570 std::min(parameters_.labclock->timestep_duration(), end_time_ - t);
1571 log.debug(
"Timestepless propagation for next ", dt,
" fm/c.");
1575 thermalizer_->is_time_to_thermalize(parameters_.labclock)) {
1576 const bool ignore_cells_under_treshold =
true;
1577 thermalizer_->update_thermalizer_lattice(particles_, density_param_,
1578 ignore_cells_under_treshold);
1579 const double current_t = parameters_.labclock->current_time();
1580 thermalizer_->thermalize(particles_, current_t,
1581 parameters_.testparticles);
1584 perform_action(th_act, particles_);
1588 if (particles_.size() > 0 && action_finders_.size() > 0) {
1590 double min_cell_length = compute_min_cell_length(dt);
1591 log.debug(
"Creating grid with minimal cell length ", min_cell_length);
1593 use_grid_ ? modus_.create_grid(particles_, min_cell_length, dt)
1594 : modus_.create_grid(particles_, min_cell_length, dt,
1595 CellSizeStrategy::Largest);
1597 const double cell_vol = grid.cell_volume();
1601 [&](
const ParticleList &search_list) {
1602 for (
const auto &finder : action_finders_) {
1603 actions.
insert(finder->find_actions_in_cell(
1604 search_list, dt, cell_vol, beam_momentum_));
1607 [&](
const ParticleList &search_list,
1608 const ParticleList &neighbors_list) {
1609 for (
const auto &finder : action_finders_) {
1610 actions.
insert(finder->find_actions_with_neighbors(
1611 search_list, neighbors_list, dt, beam_momentum_));
1619 run_time_evolution_timestepless(actions);
1624 update_potentials();
1625 update_momenta(&particles_, parameters_.labclock->timestep_duration(),
1626 *potentials_, FB_lat_.get(), FI3_lat_.get());
1635 ++(*parameters_.labclock);
1643 if (!potentials_ && !parameters_.strings_switch &&
1645 std::string err_msg = conserved_initial_.report_deviations(particles_);
1646 if (!err_msg.empty()) {
1647 log.error() << err_msg;
1648 throw std::runtime_error(
"Violation of conserved quantities!");
1653 if (pauli_blocker_) {
1654 log.info(
"Interactions: Pauli-blocked/performed = ", total_pauli_blocked_,
1655 "/", interactions_total_ - wall_actions_total_);
1659 template <
typename Modus>
1663 if (dilepton_finder_ !=
nullptr) {
1664 for (
const auto &output : outputs_) {
1665 dilepton_finder_->shine(particles_, output.get(), dt);
1678 constexpr uint64_t max_uint32 = std::numeric_limits<uint32_t>::max();
1679 if (interactions_total >= max_uint32) {
1680 throw std::runtime_error(
"Integer overflow in total interaction number!");
1684 template <
typename Modus>
1686 const auto &log = logger<LogArea::Experiment>();
1688 const double start_time = parameters_.labclock->current_time();
1689 const double end_time =
1690 std::min(parameters_.labclock->next_time(), end_time_);
1691 double time_left = end_time - start_time;
1692 log.debug(
"Timestepless propagation: ",
"Actions size = ", actions.
size(),
1693 ", start time = ", start_time,
", end time = ", end_time);
1698 ActionPtr act = actions.
pop();
1699 if (!act->is_valid(particles_)) {
1700 log.debug(~
einhard::DRed(),
"✘ ", act,
" (discarded: invalid)");
1703 if (act->time_of_execution() > end_time) {
1704 log.error(act,
" scheduled later than end time: t_action[fm/c] = ",
1705 act->time_of_execution(),
", t_end[fm/c] = ", end_time);
1709 while (next_output_time() <= act->time_of_execution()) {
1710 log.debug(
"Propagating until output time: ", next_output_time());
1711 propagate_and_shine(next_output_time());
1712 ++(*parameters_.outputclock);
1713 intermediate_output();
1717 log.debug(
"Propagating until next action ", act,
1718 ", action time = ", act->time_of_execution());
1719 propagate_and_shine(act->time_of_execution());
1726 act->update_incoming(particles_);
1727 const bool performed = perform_action(*act, particles_);
1737 time_left = end_time - act->time_of_execution();
1738 const ParticleList &outgoing_particles = act->outgoing_particles();
1740 const double cell_vol = 0.0;
1741 for (
const auto &finder : action_finders_) {
1743 actions.
insert(finder->find_actions_in_cell(outgoing_particles, time_left,
1744 cell_vol, beam_momentum_));
1746 actions.
insert(finder->find_actions_with_surrounding_particles(
1747 outgoing_particles, particles_, time_left, beam_momentum_));
1753 while (next_output_time() <= end_time) {
1754 log.debug(
"Propagating until output time: ", next_output_time());
1755 propagate_and_shine(next_output_time());
1756 ++(*parameters_.outputclock);
1758 if (parameters_.outputclock->current_time() < end_time_) {
1759 intermediate_output();
1762 log.debug(
"Propagating to time ", end_time);
1763 propagate_and_shine(end_time);
1766 template <
typename Modus>
1768 const auto &log = logger<LogArea::Experiment>();
1769 const uint64_t wall_actions_this_interval =
1770 wall_actions_total_ - previous_wall_actions_total_;
1771 previous_wall_actions_total_ = wall_actions_total_;
1772 const uint64_t interactions_this_interval = interactions_total_ -
1773 previous_interactions_total_ -
1774 wall_actions_this_interval;
1775 previous_interactions_total_ = interactions_total_;
1777 conserved_initial_, time_start_,
1778 parameters_.outputclock->current_time());
1781 for (
const auto &output : outputs_) {
1782 if (output->is_dilepton_output() || output->is_photon_output() ||
1783 output->is_IC_output()) {
1787 output->at_intermediate_time(particles_, parameters_.outputclock,
1791 switch (dens_type_lattice_printout_) {
1792 case DensityType::Baryon:
1794 density_param_, particles_,
false);
1796 DensityType::Baryon, *jmu_B_lat_);
1798 case DensityType::BaryonicIsospin:
1799 update_lattice(jmu_I3_lat_.get(), lat_upd, DensityType::BaryonicIsospin,
1800 density_param_, particles_,
false);
1802 DensityType::BaryonicIsospin,
1805 case DensityType::None:
1809 dens_type_lattice_printout_, density_param_, particles_,
1812 dens_type_lattice_printout_,
1815 if (printout_tmn_ || printout_tmn_landau_ || printout_v_landau_) {
1817 density_param_, particles_);
1818 if (printout_tmn_) {
1820 dens_type_lattice_printout_, *Tmn_);
1822 if (printout_tmn_landau_) {
1824 dens_type_lattice_printout_, *Tmn_);
1826 if (printout_v_landau_) {
1828 dens_type_lattice_printout_, *Tmn_);
1833 output->thermodynamics_output(*thermalizer_);
1838 template <
typename Modus>
1841 if (potentials_->use_symmetry() && jmu_I3_lat_ !=
nullptr) {
1843 DensityType::BaryonicIsospin, density_param_, particles_,
1846 if ((potentials_->use_skyrme() || potentials_->use_symmetry()) &&
1847 jmu_B_lat_ !=
nullptr) {
1849 DensityType::Baryon, density_param_, particles_,
true);
1850 const size_t UBlattice_size = UB_lat_->size();
1851 assert(UBlattice_size == UI3_lat_->size());
1852 for (
size_t i = 0; i < UBlattice_size; i++) {
1853 auto jB = (*jmu_B_lat_)[i];
1855 std::abs(jB.density()) >
really_small ? jB.jmu_net() / jB.density()
1857 double baryon_density = jB.density();
1861 if (potentials_->use_skyrme()) {
1863 flow_four_velocity_B * potentials_->skyrme_pot(baryon_density);
1864 (*FB_lat_)[i] = potentials_->skyrme_force(
1865 baryon_density, baryon_grad_rho, baryon_dj_dt, baryon_rot_j);
1867 if (potentials_->use_symmetry() && jmu_I3_lat_ !=
nullptr) {
1868 auto jI3 = (*jmu_I3_lat_)[i];
1871 ? jI3.jmu_net() / jI3.density()
1874 flow_four_velocity_I3 *
1875 potentials_->symmetry_pot(jI3.density(), baryon_density);
1876 (*FI3_lat_)[i] = potentials_->symmetry_force(
1877 jI3.density(), jI3.grad_rho(), jI3.dj_dt(), jI3.rot_j(),
1878 baryon_density, baryon_grad_rho, baryon_dj_dt, baryon_rot_j);
1885 template <
typename Modus>
1889 uint64_t interactions_old;
1890 const auto particles_before_actions = particles_.copy_to_vector();
1894 interactions_old = interactions_total_;
1897 if (dilepton_finder_ !=
nullptr) {
1898 for (
const auto &output : outputs_) {
1899 dilepton_finder_->shine_final(particles_, output.get(),
true);
1903 for (
const auto &finder : action_finders_) {
1904 actions.
insert(finder->find_final_actions(particles_));
1908 perform_action(*actions.
pop(), particles_before_actions);
1911 }
while (interactions_total_ > interactions_old);
1914 if (dilepton_finder_ !=
nullptr) {
1915 for (
const auto &output : outputs_) {
1916 dilepton_finder_->shine_final(particles_, output.get(),
false);
1921 template <
typename Modus>
1923 const auto &log = logger<LogArea::Experiment>();
1927 if (
likely(parameters_.labclock > 0)) {
1928 const uint64_t wall_actions_this_interval =
1929 wall_actions_total_ - previous_wall_actions_total_;
1930 const uint64_t interactions_this_interval = interactions_total_ -
1931 previous_interactions_total_ -
1932 wall_actions_this_interval;
1934 conserved_initial_, time_start_,
1936 if (IC_output_switch_ && (particles_.size() == 0)) {
1939 const double remaining_energy =
1940 conserved_initial_.momentum().x0() - total_energy_removed_;
1942 throw std::runtime_error(
1943 "There is remaining energy in the system although all particles " 1946 std::to_string(remaining_energy) +
" [GeV]");
1948 log.info() <<
hline;
1949 log.info() <<
"Time real: " << SystemClock::now() - time_start_;
1950 log.info() <<
"Interactions before reaching hypersurface: " 1951 << interactions_total_ - wall_actions_total_ -
1952 total_hypersurface_crossing_actions_;
1953 log.info() <<
"Total number of particles removed on hypersurface: " 1954 << total_hypersurface_crossing_actions_;
1957 log.info() <<
hline;
1958 log.info() <<
"Time real: " << SystemClock::now() - time_start_;
1959 log.info() <<
"Final interaction number: " 1960 << interactions_total_ - wall_actions_total_;
1964 int unformed_particles_count = 0;
1965 for (
const auto &particle : particles_) {
1966 if (particle.formation_time() > end_time_) {
1967 unformed_particles_count++;
1970 if (unformed_particles_count > 0) {
1971 log.warn(
"End time might be too small. ", unformed_particles_count,
1972 " unformed particles were found at the end of the evolution.");
1976 for (
const auto &output : outputs_) {
1977 output->at_eventend(particles_, evt_num, modus_.impact_parameter(),
1978 !projectile_target_interact_);
1982 template <
typename Modus>
1984 const auto &mainlog = logger<LogArea::Main>();
1985 for (
int j = 0; j < nevents_; j++) {
1986 mainlog.info() <<
"Event " << j;
1989 initialize_new_event();
1997 if (modus_.is_collider()) {
1998 if (!modus_.cll_in_nucleus()) {
1999 nucleon_has_interacted_.assign(modus_.total_N_number(),
false);
2001 nucleon_has_interacted_.assign(modus_.total_N_number(),
true);
2007 for (
int i = 0; i < modus_.total_N_number(); i++) {
2008 const auto mass_beam = particles_.copy_to_vector()[i].effective_mass();
2009 const auto v_beam = i < modus_.proj_N_number()
2010 ? modus_.velocity_projectile()
2011 : modus_.velocity_target();
2012 const auto gamma = 1.0 / std::sqrt(1.0 - v_beam * v_beam);
2013 beam_momentum_.emplace_back(
FourVector(gamma * mass_beam, 0.0, 0.0,
2014 gamma * v_beam * mass_beam));
2019 for (
const auto &output : outputs_) {
2020 output->at_eventstart(particles_, j);
2023 run_time_evolution();
2025 if (force_decays_) {
2036 #endif // SRC_INCLUDE_EXPERIMENT_H_ FormattingHelper< T > format(const T &value, const char *unit, int width=-1, int precision=-1)
Acts as a stream modifier for std::ostream to output an object with an optional suffix string and wit...
The main class, where the simulation of an experiment is executed.
A class to pre-calculate and store parameters relevant for density calculation.
OutputPtr photon_output_
The Photon output.
Potentials * pot_pointer
Pointer to a Potential class.
FermiMotion
Option to use Fermi Motion.
void check_interactions_total(uint64_t interactions_total)
Make sure interactions_total can be represented as a 32-bit integer.
The ThreeVector class represents a physical three-vector with the components .
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].
std::unique_ptr< RectangularLattice< EnergyMomentumTensor > > Tmn_
Lattices of energy-momentum tensors for printout.
constexpr double really_small
Numerical error tolerance.
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.
The Actions class abstracts the storage and manipulation of actions.
std::unique_ptr< DensityLattice > jmu_custom_lat_
Custom density on the lattices.
String excitation processes used in SMASH.
std::unique_ptr< T > make_unique(Args &&...args)
Definition for make_unique Is in C++14's standard library; necessary for older compilers.
DensityType td_dens_type
Type (e.g., baryon/pion/hadron) of thermodynamic quantity.
std::unique_ptr< RectangularLattice< std::pair< ThreeVector, ThreeVector > > > FB_lat_
Lattices for the electric and magnetic components of the Skyrme force.
RectangularLattice< FourVector > * UI3_lat_pointer
Pointer to the symmmetry potential on the lattice.
#define likely(x)
Tell the branch predictor that this expression is likely true.
void update_momenta(Particles *particles, double dt, const Potentials &pot, RectangularLattice< std::pair< ThreeVector, ThreeVector >> *FB_lat, RectangularLattice< std::pair< ThreeVector, ThreeVector >> *FI3_lat)
Updates the momenta of all particles at the current time step according to the equations of motion: ...
void insert(ActionList &&new_acts)
Insert a list of actions into this object.
std::unique_ptr< DecayActionsFinderDilepton > dilepton_finder_
The Dilepton Action Finder.
void update_lattice(RectangularLattice< T > *lat, const LatticeUpdate update, const DensityType dens_type, const DensityParameters &par, const Particles &particles, const bool compute_gradient=false)
Updates the contents on the lattice.
ThreeVector threevec() const
const TimeStepMode time_step_mode_
This indicates whether to use time steps.
constexpr double fm2_mb
mb <-> fm^2 conversion factor.
void set_seed(T &&seed)
Sets the seed of the random number engine.
LatticeUpdate
Enumerator option for lattice updates.
Interface to the SMASH configuration files.
double next_output_time() const
Shortcut for next output time.
bool is_pauli_blocked(const Particles &particles, const PauliBlocker &p_bl) const
Check if the action is Pauli-blocked.
constexpr double maximum_cross_section
The maximal cross section (in mb) for which it is guaranteed that all collisions with this cross sect...
Non-template interface to Experiment<Modus>.
ExperimentParameters create_experiment_parameters(Configuration config)
Gathers all general Experiment parameters.
virtual ProcessType get_type() const
Get the process type.
bool has_value(std::initializer_list< const char * > keys) const
Returns whether there is a non-empty value behind the requested keys.
std::unique_ptr< GrandCanThermalizer > thermalizer_
Instance of class used for forced thermalization.
const bool force_decays_
This indicates whether we force all resonances to decay in the last timestep.
bool td_tmn_landau
Print out energy-momentum tensor in Landau rest frame (of type td_dens_type) or not?
StringProcess * process_string_ptr_
Pointer to the string process class object, which is used to set the random seed for PYTHIA objects i...
QuantumNumbers conserved_initial_
The conserved quantities of the system.
ThermalizationAction implements forced thermalization as an Action class.
ExperimentParameters parameters_
Struct of several member variables.
bool any_particles_thermalized() const
This method checks, if there are particles in the region to be thermalized.
const bool use_grid_
This indicates whether to use the grid.
A container class to hold all the arrays on the lattice and access them.
Particles particles_
Complete particle list.
const std::string hline(67, '-')
String representing a horizontal line.
RectangularLattice< FourVector > * UB_lat_pointer
Pointer to the skyrme potential on the lattice.
std::unique_ptr< DensityLattice > jmu_I3_lat_
Isospin projection density on the lattices.
OutputPtr dilepton_output_
The Dilepton output.
Collection of useful type aliases to measure and output the (real) runtime.
std::unique_ptr< OutputInterface > create_oscar_output(const std::string &format, const std::string &content, const bf::path &path, const OutputParameters &out_par)
const double end_time_
simulation time at which the evolution is stopped.
TimeStepMode
The time step mode.
std::unique_ptr< RectangularLattice< std::pair< ThreeVector, ThreeVector > > > FI3_lat_
Lattices for the electric and magnetic component of the symmetry force.
Engine::result_type advance()
Advance the engine's state and return the generated value.
std::string format_measurements(const Particles &particles, uint64_t scatterings_this_interval, const QuantumNumbers &conserved_initial, SystemTimePoint time_start, double time)
Generate the tabulated string which will be printed to the screen when SMASH is running.
const bool IC_output_switch_
This indicates whether the IC output is enabled.
#define source_location
Hackery that is required to output the location in the source code where the log statement occurs...
Value take(std::initializer_list< const char * > keys)
The default interface for SMASH to read configuration values.
Don't use time steps; propagate from action to action.
const ExpansionProperties metric_
This struct contains information on the metric to be used.
Exception class that is thrown if an invalid modus is requested from the Experiment factory...
double compute_min_cell_length(double dt) const
Calculate the minimal size for the grid cells such that the ScatterActionsFinder will find all collis...
const double delta_time_startup_
The clock's timestep size at start up.
A container for storing conserved values.
Don't use fermi motion.
ActionPtr pop()
Return the first action in the list and removes it from the list.
Helper structure for Experiment to hold output options and parameters.
const bool dileptons_switch_
This indicates whether dileptons are switched on.
std::unique_ptr< ActionFinderInterface > photon_finder_
The (Scatter) Actions Finder for Direct Photons.
std::unique_ptr< Potentials > potentials_
An instance of potentials class, that stores parameters of potentials, calculates them and their grad...
void add_dummy_hadronic_process(double reaction_cross_section)
Adds one hadronic process with a given cross-section.
Action is the base class for a generic process that takes a number of incoming particles and transfor...
virtual double get_total_weight() const =0
Return the total weight value, which is mainly used for the weight output entry.
ScatterActionPhoton is a special action which takes two incoming particles and performs a perturbativ...
const bool photons_switch_
This indicates whether photons are switched on.
std::ostream & operator<<(std::ostream &out, const Experiment< Modus > &e)
Creates a verbose textual description of the setup of the Experiment.
Use fermi motion without potentials.
bool is_valid(const Particles &particles) const
Check whether the action still applies.
FourVector get_interaction_point() const
Get the interaction point.
std::tuple< double, FourVector, ThreeVector, ThreeVector, ThreeVector > current_eckart(const ThreeVector &r, const ParticleList &plist, const DensityParameters &par, DensityType dens_type, bool compute_gradient, bool smearing)
Calculates Eckart rest frame density and 4-current of a given density type and optionally the gradien...
std::chrono::time_point< std::chrono::system_clock > SystemTimePoint
Type (alias) that is used to store the current time.
OutputsList outputs_
A list of output formaters.
Modus modus_
Instance of the Modus template parameter.
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.
bool td_tmn
Print out energy-momentum tensor of type td_dens_type or not?
Particles * particles()
Provides external access to SMASH particles.
std::vector< std::unique_ptr< ActionFinderInterface > > action_finders_
The Action finder objects.
DensityParameters density_param_
Structure to precalculate and hold parameters for density computations.
A stream modifier that allows to colorize the log output.
const ParticleList & incoming_particles() const
Get the list of particles that go into the action.
Modus * modus()
Provides external access to SMASH calculation modus.
The Particles class abstracts the storage and manipulation of particles.
bool td_v_landau
Print out Landau velocity of type td_dens_type or not?
DensityType
Allows to choose which kind of density to calculate.
const int nevents_
Number of events.
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
std::unique_ptr< PauliBlocker > pauli_blocker_
An instance of PauliBlocker class that stores parameters needed for Pauli blocking calculations and c...
Struct containing the type of the metric and the expansion parameter of the metric.
std::unique_ptr< DensityLattice > jmu_B_lat_
Baryon density on the lattices.
ActionList::size_type size() const
Helper structure for Experiment.
virtual void perform(Particles *particles, uint32_t id_process)
Actually perform the action, e.g.