23 const std::filesystem::path &output_path) {
24 if (!std::filesystem::exists(output_path)) {
26 output_path.string() +
31 const std::string modus_chooser = config.
read({
"General",
"Modus"});
32 logg[
LExperiment].debug() <<
"Modus for this calculation: " << modus_chooser;
34 if (modus_chooser ==
"Box") {
35 return std::make_unique<Experiment<BoxModus>>(config, output_path);
36 }
else if (modus_chooser ==
"List") {
37 return std::make_unique<Experiment<ListModus>>(config, output_path);
38 }
else if (modus_chooser ==
"ListBox") {
39 return std::make_unique<Experiment<ListBoxModus>>(config, output_path);
40 }
else if (modus_chooser ==
"Collider") {
41 return std::make_unique<Experiment<ColliderModus>>(config, output_path);
42 }
else if (modus_chooser ==
"Sphere") {
43 return std::make_unique<Experiment<SphereModus>>(config, output_path);
46 ") requested from ExperimentBase::create.");
135 const int ntest = config.
take({
"General",
"Testparticles"}, 1);
137 throw std::invalid_argument(
"Testparticle number should be positive!");
141 const bool only_participants =
142 config.
take({
"Output",
"Thermodynamics",
"Only_Participants"},
false);
144 if (only_participants && config.
has_value({
"Potentials"})) {
145 throw std::invalid_argument(
146 "Only_Participants option cannot be "
147 "set to True when using Potentials.");
150 const std::string modus_chooser = config.
take({
"General",
"Modus"});
154 double box_length = -1.0;
155 if (config.
has_value({
"Modi",
"Box",
"Length"})) {
156 box_length = config.
read({
"Modi",
"Box",
"Length"});
159 if (config.
has_value({
"Modi",
"ListBox",
"Length"})) {
160 box_length = config.
read({
"Modi",
"ListBox",
"Length"});
166 const double dt = config.
take({
"General",
"Delta_Time"}, 1.);
167 const double t_end = config.
read({
"General",
"End_Time"});
170 if (box_length > 0.0 && dt > box_length / 10.0) {
171 throw std::invalid_argument(
172 "Please decrease the timestep size. "
173 "A value of (dt <= l_box / 10) is necessary in the box modus.");
177 std::unique_ptr<Clock> output_clock =
nullptr;
178 if (config.
has_value({
"Output",
"Output_Times"})) {
179 if (config.
has_value({
"Output",
"Output_Interval"})) {
180 throw std::invalid_argument(
181 "Please specify either Output_Interval or Output_Times");
183 std::vector<double> output_times = config.
take({
"Output",
"Output_Times"});
186 output_times.push_back(t_end + 1.);
187 output_clock = std::make_unique<CustomClock>(output_times);
189 const double output_dt = config.
take({
"Output",
"Output_Interval"}, t_end);
190 output_clock = std::make_unique<UniformClock>(0.0, output_dt, t_end);
195 if (config.
has_value({
"Output",
"Photons"}) &&
196 (!config.
has_value({
"Collision_Term",
"Photons"}))) {
197 throw std::invalid_argument(
198 "Photon output is enabled although photon production is disabled. "
199 "Photon production can be configured in the \"Photon\" subsection "
200 "of the \"Collision_Term\".");
204 bool missing_output_2to2 =
false;
205 bool missing_output_brems =
false;
206 if (!(config.
has_value({
"Output",
"Photons"}))) {
207 if (config.
has_value({
"Collision_Term",
"Photons",
"2to2_Scatterings"})) {
208 missing_output_2to2 =
209 config.
read({
"Collision_Term",
"Photons",
"2to2_Scatterings"});
211 if (config.
has_value({
"Collision_Term",
"Photons",
"Bremsstrahlung"})) {
212 missing_output_brems =
213 config.
read({
"Collision_Term",
"Photons",
"Bremsstrahlung"});
216 if (missing_output_2to2 || missing_output_brems) {
217 throw std::invalid_argument(
218 "Photon output is disabled although photon production is enabled. "
219 "Please enable the photon output.");
225 if (config.
has_value({
"Output",
"Dileptons"}) &&
226 (!config.
has_value({
"Collision_Term",
"Dileptons"}))) {
227 throw std::invalid_argument(
228 "Dilepton output is enabled although dilepton production is disabled. "
229 "Dilepton production can be configured in the \"Dileptons\" subsection "
230 "of the \"Collision_Term\".");
234 bool missing_output_decays =
false;
235 if (!(config.
has_value({
"Output",
"Dileptons"}))) {
236 if (config.
has_value({
"Collision_Term",
"Dileptons",
"Decays"})) {
237 missing_output_decays =
238 config.
read({
"Collision_Term",
"Dileptons",
"Decays"});
241 if (missing_output_decays) {
242 throw std::invalid_argument(
243 "Dilepton output is disabled although dilepton production is "
245 "Please enable the dilepton output.");
250 const double low_snn_cut =
251 config.
take({
"Collision_Term",
"Elastic_NN_Cutoff_Sqrts"}, 1.98);
254 if (proton && pion &&
255 low_snn_cut > proton->mass() + proton->mass() + pion->mass()) {
256 logg[
LExperiment].warn(
"The cut-off should be below the threshold energy",
257 " of the process: NN to NNpi");
259 const bool potential_affect_threshold =
260 config.
take({
"Lattice",
"Potentials_Affect_Thresholds"},
false);
261 const double scale_xs =
262 config.
take({
"Collision_Term",
"Cross_Section_Scaling"}, 1.0);
264 const auto criterion = config.
take({
"Collision_Term",
"Collision_Criterion"},
267 if (config.
has_value({
"Collision_Term",
"Fixed_Min_Cell_Length"}) &&
269 throw std::invalid_argument(
270 "Only use a fixed minimal cell length with the stochastic collision "
273 if (config.
has_value({
"Collision_Term",
"Maximum_Cross_Section"}) &&
275 throw std::invalid_argument(
276 "Only use maximum cross section with the "
277 "geometric collision criterion. Use Fixed_Min_Cell_Length to change "
279 "size for the stochastic criterion.");
290 const double maximum_cross_section_default =
293 double maximum_cross_section =
294 config.
take({
"Collision_Term",
"Maximum_Cross_Section"},
295 maximum_cross_section_default);
296 maximum_cross_section *= scale_xs;
298 std::make_unique<UniformClock>(0.0, dt, t_end),
299 std::move(output_clock),
300 config.
take({
"General",
"Ensembles"}, 1),
302 config.
take({
"General",
"Derivatives_Mode"},
307 config.
take({
"General",
"Field_Derivatives_Mode"},
309 config.
take({
"General",
"Smearing_Mode"},
311 config.
take({
"General",
"Gaussian_Sigma"}, 1.),
312 config.
take({
"General",
"Gauss_Cutoff_In_Sigma"}, 4.),
313 config.
take({
"General",
"Discrete_Weight"}, 1. / 3.0),
314 config.
take({
"General",
"Triangular_Range"}, 2.0),
316 config.
take({
"Collision_Term",
"Two_to_One"},
true),
318 config.
take({
"Collision_Term",
"Multi_Particle_Reactions"},
320 config.
take({
"Collision_Term",
"Strings"}, modus_chooser !=
"Box"),
321 config.take({
"Collision_Term",
"Resonance_Lifetime_Modifier"}, 1.),
322 config.take({
"Collision_Term",
"NNbar_Treatment"},
325 potential_affect_threshold,
327 maximum_cross_section,
328 config.take({
"Collision_Term",
"Fixed_Min_Cell_Length"}, 2.5),
331 config.take({
"Collision_Term",
"Include_Weak_And_EM_Decays_At_The_End"},
337 uint64_t scatterings_this_interval,
341 double E_mean_field_initial) {
342 const SystemTimeSpan elapsed_seconds = SystemClock::now() - time_start;
345 const QuantumNumbers difference = current_values - conserved_initial;
346 int total_particles = 0;
347 for (
const Particles &particles : ensembles) {
348 total_particles += particles.size();
353 const double current_energy = current_values.
momentum().
x0();
354 const double energy_per_part =
355 (total_particles > 0) ? (current_energy + E_mean_field) / total_particles
358 std::ostringstream ss;
360 ss << field<7, 3> << time
362 << field<11, 3> << current_energy
364 << field<11, 3> << E_mean_field
366 << field<12, 3> << current_energy + E_mean_field
368 << field<12, 6> << energy_per_part;
370 if (total_particles == 0) {
371 ss << field<13, 6> <<
"N/A";
373 ss << field<13, 6> << (difference.
momentum().
x0()
374 + E_mean_field - E_mean_field_initial)
377 ss << field<14, 3> << scatterings_this_interval
378 << field<10, 3> << total_particles
379 << field<9, 3> << elapsed_seconds;
390 const double V_cell = (jmuB_lat.
cell_sizes())[0] *
393 double E_mean_field = 0.0;
394 double density_mean = 0.0;
395 double density_variance = 0.0;
410 <<
"\nSymmetry energy is not included in the mean field calculation."
426 double C1GeV = (potentials.
skyrme_a()) / 1000.0;
427 double C2GeV = (potentials.
skyrme_b()) / 1000.0;
436 int number_of_nodes = 0;
437 double lattice_mean_field_total = 0.0;
439 for (
auto &node : jmuB_lat) {
442 double rhoB = node.rho();
444 const double j0B = node.jmu_net().x0();
446 const double abs_rhoB = std::abs(rhoB);
451 density_variance += j0B * j0B;
461 double mean_field_contribution_1 = (C1GeV / b1) * std::pow(abs_rhoB, b1) /
463 double mean_field_contribution_2 = (C2GeV / b2) * std::pow(abs_rhoB, b2) /
466 lattice_mean_field_total +=
467 V_cell * (mean_field_contribution_1 + mean_field_contribution_2);
471 density_mean = density_mean / number_of_nodes;
472 density_variance = density_variance / number_of_nodes;
473 double density_scaled_variance =
474 std::sqrt(density_variance - density_mean * density_mean) /
478 <<
"\n\t\t\t\t\t density mean = " << density_mean;
480 <<
"\n\t\t\t\t\t density scaled variance = " << density_scaled_variance;
482 <<
"\n\t\t\t\t\t total mean_field = "
487 E_mean_field = lattice_mean_field_total;
499 <<
"\nSymmetry energy is not included in the VDF mean-field "
501 <<
"\nas VDF potentials haven't been fitted with symmetry energy."
521 int number_of_nodes = 0;
522 double lattice_mean_field_total = 0.0;
524 for (
auto &node : jmuB_lat) {
527 double rhoB = node.rho();
529 const double j0B = node.jmu_net().x0();
530 double abs_rhoB = std::abs(rhoB);
532 density_variance += j0B * j0B;
543 double mean_field_contribution = 0.0;
545 mean_field_contribution +=
547 std::pow(abs_rhoB, potentials.
powers()[i] - 2.0) *
549 ((potentials.
powers()[i] - 1.0) / potentials.
powers()[i]) *
550 abs_rhoB * abs_rhoB) /
551 std::pow(rhoB_0, potentials.
powers()[i] - 1.0);
553 lattice_mean_field_total += V_cell * mean_field_contribution;
557 density_mean = density_mean / number_of_nodes;
558 density_variance = density_variance / number_of_nodes;
559 double density_scaled_variance =
560 std::sqrt(density_variance - density_mean * density_mean) /
564 <<
"\n\t\t\t\t\t density mean = " << density_mean;
566 <<
"\n\t\t\t\t\t density scaled variance = " << density_scaled_variance;
568 <<
"\n\t\t\t\t\t total mean_field = "
573 E_mean_field = lattice_mean_field_total;
576 double electromagnetic_potential = 0.0;
580 double V_cell_em = em_lattice->cell_sizes()[0] *
581 em_lattice->cell_sizes()[1] *
582 em_lattice->cell_sizes()[2];
583 for (
auto &fields : *em_lattice) {
585 electromagnetic_potential +=
586 hbarc * 0.5 * V_cell_em * (fields.first.sqr() + fields.second.sqr());
589 logg[
LExperiment].debug() <<
"Total energy in electromagnetic field = "
590 << electromagnetic_potential;
591 E_mean_field += electromagnetic_potential;
605 double E_mean_field,
double modus_impact_parameter,
607 bool projectile_target_interact,
608 bool kinematic_cut_for_SMASH_IC) {
610 const double E_kinetic_total = current_values.
momentum().
x0();
611 const double E_total = E_kinetic_total + E_mean_field;
613 EventInfo event_info{modus_impact_parameter,
621 !projectile_target_interact,
622 kinematic_cut_for_SMASH_IC};
627 static bool warn_mass_discrepancy =
true;
628 static bool warn_off_shell_particle =
true;
629 for (
auto it = particle_list.begin(); it != particle_list.end();) {
630 auto &particle = *it;
631 auto pdgcode = particle.pdgcode();
634 if (pdgcode == 0x310 || pdgcode == 0x130) {
643 auto valid_smash_particle =
645 pdgcode, particle.effective_mass(), particle.momentum(),
646 LExperiment, warn_mass_discrepancy, warn_off_shell_particle);
647 particle.set_4momentum(valid_smash_particle.momentum());
648 particle.set_cross_section_scaling_factor(1.0);
652 <<
"SMASH does not recognize pdg code " << pdgcode
653 <<
" obtained from hadron list. This particle will be ignored.\n";
654 it = particle_list.erase(it);
Interface to the SMASH configuration files.
bool has_value(std::initializer_list< const char * > keys) const
Return whether there is a non-empty value behind the requested keys.
void remove_all_entries_in_section_but_one(const std::string &key, std::initializer_list< const char * > section={})
Remove all entries in the given section except for key.
Value take(std::initializer_list< const char * > keys)
The default interface for SMASH to read configuration values.
Value read(std::initializer_list< const char * > keys) const
Additional interface for SMASH to read configuration values without removing them.
static std::unique_ptr< ExperimentBase > create(Configuration &config, const std::filesystem::path &output_path)
Factory method that creates and initializes a new Experiment<Modus>.
static const ParticleTypePtr try_find(PdgCode pdgcode)
Returns the ParticleTypePtr for the given pdgcode.
static bool exists(PdgCode pdgcode)
The Particles class abstracts the storage and manipulation of particles.
A class that stores parameters of potentials, calculates potentials and their gradients.
const std::vector< double > & powers() const
virtual bool use_symmetry() const
const std::vector< double > & coeffs() const
virtual bool use_skyrme() const
virtual bool use_coulomb() const
double skyrme_tau() const
int number_of_terms() const
virtual bool use_vdf() const
double saturation_density() const
A container for storing conserved values.
FourVector momentum() const
A container class to hold all the arrays on the lattice and access them.
const std::array< double, 3 > & cell_sizes() const
std::bitset< 10 > ReactionsBitSet
Container for the 2 to 2 reactions in the code.
@ Strings
Use string fragmentation.
std::bitset< 4 > MultiParticleReactionsBitSet
Container for the n to m reactions in the code.
@ Stochastic
Stochastic Criteiron.
@ Covariant
Covariant Criterion.
#define SMASH_SOURCE_LOCATION
Hackery that is required to output the location in the source code where the log statement occurs.
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
T uniform_int(T min, T max)
ParticleData create_valid_smash_particle_matching_provided_quantities(PdgCode pdgcode, double mass, const FourVector &four_momentum, int log_area, bool &mass_warning, bool &on_shell_warning)
This function creates a SMASH particle validating the provided information.
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_.
SystemClock::duration SystemTimeSpan
The time duration type (alias) used for measuring run times.
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.
ExperimentParameters create_experiment_parameters(Configuration &config)
Gathers all general Experiment parameters.
constexpr double very_small_double
A very small double, used to avoid division by zero.
double calculate_mean_field_energy(const Potentials &potentials, RectangularLattice< smash::DensityOnLattice > &jmu_B_lat, RectangularLattice< std::pair< ThreeVector, ThreeVector >> *em_lattice, const ExperimentParameters ¶meters)
Calculate the total mean field energy of the system; this will be printed to the screen when SMASH is...
static constexpr int LExperiment
void validate_and_adjust_particle_list(ParticleList &particle_list)
Validate a particle list adjusting each particle to be a valid SMASH particle.
constexpr double nuclear_density
Ground state density of symmetric nuclear matter [fm^-3].
constexpr double hbarc
GeV <-> fm conversion factor.
std::chrono::time_point< std::chrono::system_clock > SystemTimePoint
Type (alias) that is used to store the current time.
Structure to contain custom data for output.
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 box_length
Length of the box in fm in case of box modus, otherwise -1.
int n_ensembles
Number of parallel ensembles.
std::unique_ptr< Clock > outputclock
Output clock to keep track of the next output time.
int testparticles
Number of test-particles.