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.");
142 throw std::invalid_argument(
"Testparticle number should be positive!");
146 const bool only_participants =
150 throw std::invalid_argument(
151 "Only_Participants option cannot be "
152 "set to True when using Potentials.");
159 double box_length = -1.0;
172 throw std::invalid_argument(
"Delta_Time cannot be zero or negative.");
177 throw std::invalid_argument(
"End_Time cannot be zero or negative.");
181 if (box_length > 0.0 && dt > box_length / 10.0) {
182 throw std::invalid_argument(
183 "Please decrease the timestep size. "
184 "A value of (dt <= l_box / 10) is necessary in the box modus.");
188 std::unique_ptr<Clock> output_clock =
nullptr;
191 throw std::invalid_argument(
192 "Please specify either Output_Interval or Output_Times");
194 std::vector<double> output_times =
198 output_times.push_back(t_end + 1.);
199 output_clock = std::make_unique<CustomClock>(output_times);
201 const double output_dt =
203 if (output_dt <= 0.) {
204 throw std::invalid_argument(
205 "Output_Interval cannot be zero or negative.");
207 output_clock = std::make_unique<UniformClock>(0.0, output_dt, t_end);
214 throw std::invalid_argument(
215 "Photon output is enabled although photon production is disabled. "
216 "Photon production can be configured in the \"Photon\" subsection "
217 "of the \"Collision_Term\".");
222 const bool missing_output_2to2 =
224 missing_output_brems =
226 if (missing_output_2to2 || missing_output_brems) {
227 throw std::invalid_argument(
228 "Photon output is disabled although photon production is enabled. "
229 "Please enable the photon output.");
237 throw std::invalid_argument(
238 "Dilepton output is enabled although dilepton production is disabled. "
239 "Dilepton production can be configured in the \"Dileptons\" subsection "
240 "of the \"Collision_Term\".");
245 const bool missing_output_decays =
247 if (missing_output_decays) {
248 throw std::invalid_argument(
249 "Dilepton output is disabled although dilepton production is "
251 "Please enable the dilepton output.");
256 const double low_snn_cut =
260 if (proton && pion &&
261 low_snn_cut > proton->mass() + proton->mass() + pion->mass()) {
262 logg[
LExperiment].warn(
"The cut-off should be below the threshold energy",
263 " of the process: NN to NNpi");
265 const bool potential_affect_threshold =
273 throw std::invalid_argument(
274 "Only use a fixed minimal cell length with the stochastic collision "
279 throw std::invalid_argument(
280 "Only use maximum cross section with the geometric collision "
281 "criterion. Use Fixed_Min_Cell_Length to change the grid size for the "
282 "stochastic criterion.");
293 const double maximum_cross_section_default =
296 double maximum_cross_section = config.
take(
298 maximum_cross_section *= scale_xs;
299 return {std::make_unique<UniformClock>(0.0, dt, t_end),
300 std::move(output_clock),
321 potential_affect_threshold,
323 maximum_cross_section,
334 uint64_t scatterings_this_interval,
338 double E_mean_field_initial) {
339 const SystemTimeSpan elapsed_seconds = SystemClock::now() - time_start;
342 const QuantumNumbers difference = current_values - conserved_initial;
343 int total_particles = 0;
344 for (
const Particles &particles : ensembles) {
345 total_particles += particles.size();
350 const double current_energy = current_values.
momentum().
x0();
351 const double energy_per_part =
352 (total_particles > 0) ? (current_energy + E_mean_field) / total_particles
355 std::ostringstream ss;
357 ss << field<7, 3> << time
359 << field<11, 3> << current_energy
361 << field<11, 3> << E_mean_field
363 << field<12, 3> << current_energy + E_mean_field
365 << field<12, 6> << energy_per_part;
367 if (total_particles == 0) {
368 ss << field<13, 6> <<
"N/A";
370 ss << field<13, 6> << (difference.
momentum().
x0()
371 + E_mean_field - E_mean_field_initial)
374 ss << field<14, 3> << scatterings_this_interval
375 << field<10, 3> << total_particles
376 << field<9, 3> << elapsed_seconds;
387 const double V_cell = (jmuB_lat.
cell_sizes())[0] *
390 double E_mean_field = 0.0;
391 double density_mean = 0.0;
392 double density_variance = 0.0;
407 <<
"\nSymmetry energy is not included in the mean field calculation."
423 double C1GeV = (potentials.
skyrme_a()) / 1000.0;
424 double C2GeV = (potentials.
skyrme_b()) / 1000.0;
433 int number_of_nodes = 0;
434 double lattice_mean_field_total = 0.0;
436 for (
auto &node : jmuB_lat) {
439 double rhoB = node.rho();
441 const double j0B = node.jmu_net().x0();
443 const double abs_rhoB = std::abs(rhoB);
448 density_variance += j0B * j0B;
458 double mean_field_contribution_1 = (C1GeV / b1) * std::pow(abs_rhoB, b1) /
460 double mean_field_contribution_2 = (C2GeV / b2) * std::pow(abs_rhoB, b2) /
463 lattice_mean_field_total +=
464 V_cell * (mean_field_contribution_1 + mean_field_contribution_2);
468 density_mean = density_mean / number_of_nodes;
469 density_variance = density_variance / number_of_nodes;
470 double density_scaled_variance =
471 std::sqrt(density_variance - density_mean * density_mean) /
475 <<
"\n\t\t\t\t\t density mean = " << density_mean;
477 <<
"\n\t\t\t\t\t density scaled variance = " << density_scaled_variance;
479 <<
"\n\t\t\t\t\t total mean_field = "
484 E_mean_field = lattice_mean_field_total;
496 <<
"\nSymmetry energy is not included in the VDF mean-field "
498 <<
"\nas VDF potentials haven't been fitted with symmetry energy."
518 int number_of_nodes = 0;
519 double lattice_mean_field_total = 0.0;
521 for (
auto &node : jmuB_lat) {
524 double rhoB = node.rho();
526 const double j0B = node.jmu_net().x0();
527 double abs_rhoB = std::abs(rhoB);
529 density_variance += j0B * j0B;
540 double mean_field_contribution = 0.0;
542 mean_field_contribution +=
544 std::pow(abs_rhoB, potentials.
powers()[i] - 2.0) *
546 ((potentials.
powers()[i] - 1.0) / potentials.
powers()[i]) *
547 abs_rhoB * abs_rhoB) /
548 std::pow(rhoB_0, potentials.
powers()[i] - 1.0);
550 lattice_mean_field_total += V_cell * mean_field_contribution;
554 density_mean = density_mean / number_of_nodes;
555 density_variance = density_variance / number_of_nodes;
556 double density_scaled_variance =
557 std::sqrt(density_variance - density_mean * density_mean) /
561 <<
"\n\t\t\t\t\t density mean = " << density_mean;
563 <<
"\n\t\t\t\t\t density scaled variance = " << density_scaled_variance;
565 <<
"\n\t\t\t\t\t total mean_field = "
570 E_mean_field = lattice_mean_field_total;
573 double electromagnetic_potential = 0.0;
577 double V_cell_em = em_lattice->cell_sizes()[0] *
578 em_lattice->cell_sizes()[1] *
579 em_lattice->cell_sizes()[2];
580 for (
auto &fields : *em_lattice) {
582 electromagnetic_potential +=
583 hbarc * 0.5 * V_cell_em * (fields.first.sqr() + fields.second.sqr());
586 logg[
LExperiment].debug() <<
"Total energy in electromagnetic field = "
587 << electromagnetic_potential;
588 E_mean_field += electromagnetic_potential;
602 double E_mean_field,
double modus_impact_parameter,
604 bool projectile_target_interact,
605 bool kinematic_cut_for_SMASH_IC) {
607 const double E_kinetic_total = current_values.
momentum().
x0();
608 const double E_total = E_kinetic_total + E_mean_field;
610 EventInfo event_info{modus_impact_parameter,
618 !projectile_target_interact,
619 kinematic_cut_for_SMASH_IC};
624 static bool warn_mass_discrepancy =
true;
625 static bool warn_off_shell_particle =
true;
626 for (
auto it = particle_list.begin(); it != particle_list.end();) {
627 auto &particle = *it;
628 auto pdgcode = particle.pdgcode();
631 if (pdgcode == 0x310 || pdgcode == 0x130) {
641 auto valid_smash_particle =
643 pdgcode, particle.effective_mass(), particle.position(),
644 particle.momentum(),
LExperiment, warn_mass_discrepancy,
645 warn_off_shell_particle);
646 particle.set_4position(valid_smash_particle.position());
647 particle.set_4momentum(valid_smash_particle.momentum());
648 particle.set_cross_section_scaling_factor(
649 valid_smash_particle.xsec_scaling_factor());
653 <<
"SMASH does not recognize pdg code " << pdgcode
654 <<
" obtained from hadron list. This particle will be ignored.\n";
655 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 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
@ 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.