23 const std::filesystem::path &output_path) {
24 if (!std::filesystem::exists(output_path)) {
26 output_path.string() +
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.");
141 const bool only_participants =
144 const bool ignore_unformed =
148 throw std::invalid_argument(
149 "Only_Participants option cannot be "
150 "set to True when using Potentials.");
157 double box_length = -1.0;
169 if (box_length > 0.0 && dt > box_length / 10.0) {
170 throw std::invalid_argument(
171 "Please decrease the timestep size. "
172 "A value of (dt <= l_box / 10) is necessary in the box modus.");
176 std::unique_ptr<Clock> output_clock =
nullptr;
179 throw std::invalid_argument(
180 "Please specify either Output_Interval or Output_Times");
182 std::vector<double> output_times =
186 output_times.push_back(t_end + 1.);
187 output_clock = std::make_unique<CustomClock>(output_times);
189 const double output_dt =
191 if (output_dt <= 0.) {
192 throw std::invalid_argument(
193 "Output_Interval cannot be zero or negative.");
195 output_clock = std::make_unique<UniformClock>(0.0, output_dt, t_end);
202 throw std::invalid_argument(
203 "Photon output is enabled although photon production is disabled. "
204 "Photon production can be configured in the \"Photon\" subsection "
205 "of the \"Collision_Term\".");
210 const bool missing_output_2to2 =
212 missing_output_brems =
214 if (missing_output_2to2 || missing_output_brems) {
215 throw std::invalid_argument(
216 "Photon output is disabled although photon production is enabled. "
217 "Please enable the photon output.");
225 throw std::invalid_argument(
226 "Dilepton output is enabled although dilepton production is disabled. "
227 "Dilepton production can be configured in the \"Dileptons\" subsection "
228 "of the \"Collision_Term\".");
233 const bool missing_output_decays =
235 if (missing_output_decays) {
236 throw std::invalid_argument(
237 "Dilepton output is disabled although dilepton production is "
238 "enabled. Please enable the dilepton output.");
244 const double low_snn_cut =
247 const bool potential_affect_threshold =
255 throw std::invalid_argument(
256 "Only use a fixed minimal cell length with the stochastic collision "
261 throw std::invalid_argument(
262 "Only use maximum cross section with the geometric collision "
263 "criterion. Use Fixed_Min_Cell_Length to change the grid size for the "
264 "stochastic criterion.");
275 const double maximum_cross_section_default =
278 double maximum_cross_section = config.
take(
280 maximum_cross_section *= scale_xs;
281 return {std::make_unique<UniformClock>(0.0, dt, t_end),
282 std::move(output_clock),
304 potential_affect_threshold,
306 maximum_cross_section,
319 uint64_t scatterings_this_interval,
323 double E_mean_field_initial) {
324 const SystemTimeSpan elapsed_seconds = SystemClock::now() - time_start;
327 const QuantumNumbers difference = current_values - conserved_initial;
328 int total_particles = 0;
329 for (
const Particles &particles : ensembles) {
330 total_particles += particles.size();
335 const double current_energy = current_values.
momentum().
x0();
336 const double energy_per_part =
337 (total_particles > 0) ? (current_energy + E_mean_field) / total_particles
340 std::ostringstream ss;
342 ss << field<7, 3> << time
344 << field<11, 3> << current_energy
346 << field<11, 3> << E_mean_field
348 << field<12, 3> << current_energy + E_mean_field
350 << field<12, 6> << energy_per_part;
352 if (total_particles == 0) {
353 ss << field<13, 6> <<
"N/A";
355 ss << field<13, 6> << (difference.
momentum().
x0()
356 + E_mean_field - E_mean_field_initial)
359 ss << field<14, 3> << scatterings_this_interval
360 << field<10, 3> << total_particles
361 << field<9, 3> << elapsed_seconds;
372 const double V_cell = (jmuB_lat.
cell_sizes())[0] *
375 double E_mean_field = 0.0;
376 double density_mean = 0.0;
377 double density_variance = 0.0;
392 <<
"\nSymmetry energy is not included in the mean field calculation."
408 double C1GeV = (
potentials.skyrme_a()) / 1000.0;
409 double C2GeV = (
potentials.skyrme_b()) / 1000.0;
418 int number_of_nodes = 0;
419 double lattice_mean_field_total = 0.0;
421 for (
auto &node : jmuB_lat) {
424 double rhoB = node.rho();
426 const double j0B = node.jmu_net().x0();
428 const double abs_rhoB = std::abs(rhoB);
433 density_variance += j0B * j0B;
443 double mean_field_contribution_1 = (C1GeV / b1) * std::pow(abs_rhoB, b1) /
445 double mean_field_contribution_2 = (C2GeV / b2) * std::pow(abs_rhoB, b2) /
448 lattice_mean_field_total +=
449 V_cell * (mean_field_contribution_1 + mean_field_contribution_2);
453 density_mean = density_mean / number_of_nodes;
454 density_variance = density_variance / number_of_nodes;
455 double density_scaled_variance =
456 std::sqrt(density_variance - density_mean * density_mean) /
460 <<
"\n\t\t\t\t\t density mean = " << density_mean;
462 <<
"\n\t\t\t\t\t density scaled variance = " << density_scaled_variance;
464 <<
"\n\t\t\t\t\t total mean_field = "
469 E_mean_field = lattice_mean_field_total;
481 <<
"\nSymmetry energy is not included in the VDF mean-field "
483 <<
"\nas VDF potentials haven't been fitted with symmetry energy."
496 double rhoB_0 =
potentials.saturation_density();
503 int number_of_nodes = 0;
504 double lattice_mean_field_total = 0.0;
506 for (
auto &node : jmuB_lat) {
509 double rhoB = node.rho();
511 const double j0B = node.jmu_net().x0();
512 double abs_rhoB = std::abs(rhoB);
514 density_variance += j0B * j0B;
525 double mean_field_contribution = 0.0;
526 for (
int i = 0; i <
potentials.number_of_terms(); i++) {
527 mean_field_contribution +=
529 std::pow(abs_rhoB,
potentials.powers()[i] - 2.0) *
532 abs_rhoB * abs_rhoB) /
533 std::pow(rhoB_0,
potentials.powers()[i] - 1.0);
535 lattice_mean_field_total += V_cell * mean_field_contribution;
539 density_mean = density_mean / number_of_nodes;
540 density_variance = density_variance / number_of_nodes;
541 double density_scaled_variance =
542 std::sqrt(density_variance - density_mean * density_mean) /
546 <<
"\n\t\t\t\t\t density mean = " << density_mean;
548 <<
"\n\t\t\t\t\t density scaled variance = " << density_scaled_variance;
550 <<
"\n\t\t\t\t\t total mean_field = "
555 E_mean_field = lattice_mean_field_total;
558 double electromagnetic_potential = 0.0;
562 double V_cell_em = em_lattice->cell_sizes()[0] *
563 em_lattice->cell_sizes()[1] *
564 em_lattice->cell_sizes()[2];
565 for (
auto &fields : *em_lattice) {
567 electromagnetic_potential +=
568 hbarc * 0.5 * V_cell_em * (fields.first.sqr() + fields.second.sqr());
571 logg[
LExperiment].debug() <<
"Total energy in electromagnetic field = "
572 << electromagnetic_potential;
573 E_mean_field += electromagnetic_potential;
587 double E_mean_field,
double modus_impact_parameter,
589 bool projectile_target_interact,
590 bool kinematic_cut_for_SMASH_IC) {
592 const double E_kinetic_total = current_values.
momentum().
x0();
593 const double E_total = E_kinetic_total + E_mean_field;
595 EventInfo event_info{modus_impact_parameter,
603 !projectile_target_interact,
604 kinematic_cut_for_SMASH_IC};
609 static bool warn_mass_discrepancy =
true;
610 static bool warn_off_shell_particle =
true;
611 for (
auto it = particle_list.begin(); it != particle_list.end();) {
612 auto &particle = *it;
613 auto pdgcode = particle.pdgcode();
616 if (pdgcode == 0x310 || pdgcode == 0x130) {
626 auto valid_smash_particle =
628 pdgcode, particle.effective_mass(), particle.position(),
629 particle.momentum(),
LExperiment, warn_mass_discrepancy,
630 warn_off_shell_particle);
631 particle.set_4position(valid_smash_particle.position());
632 particle.set_4momentum(valid_smash_particle.momentum());
633 particle.set_cross_section_scaling_factor(
634 valid_smash_particle.xsec_scaling_factor());
638 <<
"SMASH does not recognize pdg code " << pdgcode
639 <<
" obtained from hadron list. This particle will be ignored.\n";
640 it = particle_list.erase(it);
Interface to the SMASH configuration files.
T read(const Key< T > &key) const
Additional interface for SMASH to read configuration values without removing them.
bool has_value(const Key< T > &key) const
Return whether there is a non-empty value behind the requested key (which is supposed not to refer to...
bool has_section(const KeyLabels &labels) const
Return whether there is a (possibly empty) section with the given labels.
T take(const Key< T > &key)
The default interface for SMASH to read configuration values.
void remove_all_entries_in_section_but_one(const std::string &key, KeyLabels section={})
Remove all entries in the given section except for key.
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 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.
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
@ Stochastic
Stochastic Criteiron.
#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)
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].
ParticleData create_valid_smash_particle_matching_provided_quantities(PdgCode pdgcode, double mass, const FourVector &four_position, const FourVector &four_momentum, int log_area, bool &mass_warning, bool &on_shell_warning)
This function creates a SMASH particle validating the provided information.
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.