24 const bf::path &output_path) {
25 if (!bf::exists(output_path)) {
26 throw NonExistingOutputPathRequest(
"The requested output path (" +
27 output_path.string() +
54 const std::string modus_chooser = config.read({
"General",
"Modus"});
55 logg[
LExperiment].debug() <<
"Modus for this calculation: " << modus_chooser;
57 if (modus_chooser ==
"Box") {
58 return make_unique<Experiment<BoxModus>>(config, output_path);
59 }
else if (modus_chooser ==
"List") {
60 return make_unique<Experiment<ListModus>>(config, output_path);
61 }
else if (modus_chooser ==
"ListBox") {
62 return make_unique<Experiment<ListBoxModus>>(config, output_path);
63 }
else if (modus_chooser ==
"Collider") {
64 return make_unique<Experiment<ColliderModus>>(config, output_path);
65 }
else if (modus_chooser ==
"Sphere") {
66 return make_unique<Experiment<SphereModus>>(config, output_path);
68 throw InvalidModusRequest(
"Invalid Modus (" + modus_chooser +
69 ") requested from ExperimentBase::create.");
497 const int ntest = config.
take({
"General",
"Testparticles"}, 1);
499 throw std::invalid_argument(
"Testparticle number should be positive!");
503 const bool only_participants =
504 config.
take({
"Output",
"Thermodynamics",
"Only_Participants"},
false);
506 if (only_participants && config.
has_value({
"Potentials"})) {
507 throw std::invalid_argument(
508 "Only_Participants option cannot be "
509 "set to True when using Potentials.");
512 const std::string modus_chooser = config.
take({
"General",
"Modus"});
516 double box_length = -1.0;
517 if (config.
has_value({
"Modi",
"Box",
"Length"})) {
518 box_length = config.
read({
"Modi",
"Box",
"Length"});
521 if (config.
has_value({
"Modi",
"ListBox",
"Length"})) {
522 box_length = config.
read({
"Modi",
"ListBox",
"Length"});
528 const double dt = config.
take({
"General",
"Delta_Time"}, 1.);
529 const double t_end = config.
read({
"General",
"End_Time"});
532 if (box_length > 0.0 && dt > box_length / 10.0) {
533 throw std::invalid_argument(
534 "Please decrease the timestep size. "
535 "A value of (dt < l_box / 10) is recommended in the boxmodus.");
539 std::unique_ptr<Clock> output_clock =
nullptr;
540 if (config.
has_value({
"Output",
"Output_Times"})) {
541 if (config.
has_value({
"Output",
"Output_Interval"})) {
542 throw std::invalid_argument(
543 "Please specify either Output_Interval or Output_Times");
545 std::vector<double> output_times = config.
take({
"Output",
"Output_Times"});
548 output_times.push_back(t_end + 1.);
549 output_clock = make_unique<CustomClock>(output_times);
551 const double output_dt = config.
take({
"Output",
"Output_Interval"}, t_end);
552 output_clock = make_unique<UniformClock>(0.0, output_dt);
557 if (config[
"Output"].has_value({
"Photons"}) &&
558 (!config.
has_value({
"Collision_Term",
"Photons"}))) {
559 throw std::invalid_argument(
560 "Photon output is enabled although photon production is disabled. "
561 "Photon production can be configured in the \"Photon\" subsection "
562 "of the \"Collision_Term\".");
566 bool missing_output_2to2 =
false;
567 bool missing_output_brems =
false;
568 if (!(config[
"Output"].has_value({
"Photons"}))) {
569 if (config.
has_value({
"Collision_Term",
"Photons",
"2to2_Scatterings"})) {
570 missing_output_2to2 =
571 config.
read({
"Collision_Term",
"Photons",
"2to2_Scatterings"});
573 if (config.
has_value({
"Collision_Term",
"Photons",
"Bremsstrahlung"})) {
574 missing_output_brems =
575 config.
read({
"Collision_Term",
"Photons",
"Bremsstrahlung"});
578 if (missing_output_2to2 || missing_output_brems) {
579 throw std::invalid_argument(
580 "Photon output is disabled although photon production is enabled. "
581 "Please enable the photon output.");
587 if (config[
"Output"].has_value({
"Dileptons"}) &&
588 (!config.
has_value({
"Collision_Term",
"Dileptons"}))) {
589 throw std::invalid_argument(
590 "Dilepton output is enabled although dilepton production is disabled. "
591 "Dilepton production can be configured in the \"Dileptons\" subsection "
592 "of the \"Collision_Term\".");
596 bool missing_output_decays =
false;
597 if (!(config[
"Output"].has_value({
"Dileptons"}))) {
598 if (config.
has_value({
"Collision_Term",
"Dileptons",
"Decays"})) {
599 missing_output_decays =
600 config.
read({
"Collision_Term",
"Dileptons",
"Decays"});
603 if (missing_output_decays) {
604 throw std::invalid_argument(
605 "Dilepton output is disabled although dilepton production is "
607 "Please enable the dilepton output.");
611 auto config_coll = config[
"Collision_Term"];
614 const double low_snn_cut =
615 config_coll.
take({
"Elastic_NN_Cutoff_Sqrts"}, 1.98);
618 if (proton && pion &&
619 low_snn_cut > proton->mass() + proton->mass() + pion->mass()) {
620 logg[
LExperiment].warn(
"The cut-off should be below the threshold energy",
621 " of the process: NN to NNpi");
623 const bool potential_affect_threshold =
624 config.
take({
"Lattice",
"Potentials_Affect_Thresholds"},
false);
625 const double scale_xs = config_coll.take({
"Cross_Section_Scaling"}, 1.0);
627 const auto criterion =
630 if (config_coll.has_value({
"Fixed_Min_Cell_Length"}) &&
632 throw std::invalid_argument(
633 "Only use a fixed minimal cell length with the stochastic collision "
636 if (config_coll.has_value({
"Maximum_Cross_Section"}) &&
638 throw std::invalid_argument(
639 "Only use maximum cross section with the "
640 "geometric collision criterion. Use Fixed_Min_Cell_Length to change "
642 "size for the stochastic criterion.");
653 const double maximum_cross_section_default =
656 bool cll_in_nucleus =
657 config.
take({
"Modi",
"Collider",
"Collisions_Within_Nucleus"},
false);
658 double maximum_cross_section = config_coll.take(
659 {
"Maximum_Cross_Section"}, maximum_cross_section_default);
660 maximum_cross_section *= scale_xs;
661 return {make_unique<UniformClock>(0.0, dt),
662 std::move(output_clock),
663 config.
take({
"General",
"Ensembles"}, 1),
665 config.
take({
"General",
"Derivatives_Mode"},
670 config.
take({
"General",
"Field_Derivatives_Mode"},
672 config.
take({
"General",
"Smearing_Mode"},
674 config.
take({
"General",
"Gaussian_Sigma"}, 1.),
675 config.
take({
"General",
"Gauss_Cutoff_In_Sigma"}, 4.),
676 config.
take({
"General",
"Discrete_Weight"}, 1. / 3.0),
677 config.
take({
"General",
"Triangular_Range"}, 2.0),
679 config_coll.take({
"Two_to_One"},
true),
681 config_coll.take({
"Multi_Particle_Reactions"},
683 config_coll.take({
"Strings"}, modus_chooser !=
"Box"),
684 config_coll.take({
"Use_AQM"},
true),
685 config_coll.take({
"Resonance_Lifetime_Modifier"}, 1.),
686 config_coll.take({
"Strings_with_Probability"},
true),
689 potential_affect_threshold,
691 maximum_cross_section,
692 config_coll.take({
"Fixed_Min_Cell_Length"}, 2.5),
695 config_coll.take({
"Additional_Elastic_Cross_Section"}, 0.0),
697 config_coll.take({
"Include_Weak_And_EM_Decays_At_The_End"},
false)};
701 uint64_t scatterings_this_interval,
705 double E_mean_field_initial) {
706 const SystemTimeSpan elapsed_seconds = SystemClock::now() - time_start;
709 const QuantumNumbers difference = current_values - conserved_initial;
710 int total_particles = 0;
711 for (
const Particles &particles : ensembles) {
712 total_particles += particles.size();
717 const double current_energy = current_values.
momentum().
x0();
718 const double energy_per_part =
719 (total_particles > 0) ? (current_energy + E_mean_field) / total_particles
722 std::ostringstream ss;
724 ss << field<7, 3> << time
726 << field<11, 3> << current_energy
728 << field<11, 3> << E_mean_field
730 << field<12, 3> << current_energy + E_mean_field
732 << field<12, 6> << energy_per_part;
734 if (total_particles == 0) {
735 ss << field<13, 6> <<
"N/A";
737 ss << field<13, 6> << (difference.
momentum().
x0()
738 + E_mean_field - E_mean_field_initial)
741 ss << field<14, 3> << scatterings_this_interval
742 << field<10, 3> << total_particles
743 << field<9, 3> << elapsed_seconds;
754 const double V_cell = (jmuB_lat.
cell_sizes())[0] *
757 double E_mean_field = 0.0;
758 double density_mean = 0.0;
759 double density_variance = 0.0;
774 <<
"\nSymmetry energy is not included in the mean field calculation."
790 double C1GeV = (potentials.
skyrme_a()) / 1000.0;
791 double C2GeV = (potentials.
skyrme_b()) / 1000.0;
800 int number_of_nodes = 0;
801 double lattice_mean_field_total = 0.0;
803 for (
auto &node : jmuB_lat) {
806 double rhoB = node.rho();
808 const double j0B = node.jmu_net().x0();
810 const double abs_rhoB = std::abs(rhoB);
815 density_variance += j0B * j0B;
825 double mean_field_contribution_1 = (C1GeV / b1) * std::pow(abs_rhoB, b1) /
827 double mean_field_contribution_2 = (C2GeV / b2) * std::pow(abs_rhoB, b2) /
830 lattice_mean_field_total +=
831 V_cell * (mean_field_contribution_1 + mean_field_contribution_2);
835 density_mean = density_mean / number_of_nodes;
836 density_variance = density_variance / number_of_nodes;
837 double density_scaled_variance =
838 std::sqrt(density_variance - density_mean * density_mean) /
842 <<
"\n\t\t\t\t\t density mean = " << density_mean;
844 <<
"\n\t\t\t\t\t density scaled variance = " << density_scaled_variance;
846 <<
"\n\t\t\t\t\t total mean_field = "
851 E_mean_field = lattice_mean_field_total;
863 <<
"\nSymmetry energy is not included in the VDF mean-field "
865 <<
"\nas VDF potentials haven't been fitted with symmetry energy."
885 int number_of_nodes = 0;
886 double lattice_mean_field_total = 0.0;
888 for (
auto &node : jmuB_lat) {
891 double rhoB = node.rho();
893 const double j0B = node.jmu_net().x0();
894 double abs_rhoB = std::abs(rhoB);
896 density_variance += j0B * j0B;
907 double mean_field_contribution = 0.0;
909 mean_field_contribution +=
911 std::pow(abs_rhoB, potentials.
powers()[i] - 2.0) *
913 ((potentials.
powers()[i] - 1.0) / potentials.
powers()[i]) *
914 abs_rhoB * abs_rhoB) /
915 std::pow(rhoB_0, potentials.
powers()[i] - 1.0);
917 lattice_mean_field_total += V_cell * mean_field_contribution;
921 density_mean = density_mean / number_of_nodes;
922 density_variance = density_variance / number_of_nodes;
923 double density_scaled_variance =
924 std::sqrt(density_variance - density_mean * density_mean) /
928 <<
"\n\t\t\t\t\t density mean = " << density_mean;
930 <<
"\n\t\t\t\t\t density scaled variance = " << density_scaled_variance;
932 <<
"\n\t\t\t\t\t total mean_field = "
937 E_mean_field = lattice_mean_field_total;
940 double electromagnetic_potential = 0.0;
944 double V_cell_em = em_lattice->cell_sizes()[0] *
945 em_lattice->cell_sizes()[1] *
946 em_lattice->cell_sizes()[2];
947 for (
auto &fields : *em_lattice) {
949 electromagnetic_potential +=
950 hbarc * 0.5 * V_cell_em * (fields.first.sqr() + fields.second.sqr());
953 logg[
LExperiment].debug() <<
"Total energy in electromagnetic field = "
954 << electromagnetic_potential;
955 E_mean_field += electromagnetic_potential;
969 double E_mean_field,
double modus_impact_parameter,
971 bool projectile_target_interact,
972 bool kinematic_cut_for_SMASH_IC) {
974 const double E_kinetic_total = current_values.
momentum().
x0();
975 const double E_total = E_kinetic_total + E_mean_field;
977 EventInfo event_info{modus_impact_parameter,
985 !projectile_target_interact,
986 kinematic_cut_for_SMASH_IC};
Interface to the SMASH configuration files.
bool has_value(std::initializer_list< const char * > keys) const
Returns whether there is a non-empty value behind the requested keys.
void remove_all_but(const std::string &key)
Removes all entries in the map 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 bf::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.
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.
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
constexpr double nuclear_density
Ground state density of symmetric nuclear matter [fm^-3].
constexpr double hbarc
GeV <-> fm conversion factor.
ExperimentParameters create_experiment_parameters(Configuration config)
Gathers all general Experiment parameters.
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.
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.