24 const bf::path &output_path) {
49 const std::string modus_chooser = config.read({
"General",
"Modus"});
50 logg[
LExperiment].debug() <<
"Modus for this calculation: " << modus_chooser;
52 if (modus_chooser ==
"Box") {
53 return make_unique<Experiment<BoxModus>>(config, output_path);
54 }
else if (modus_chooser ==
"List") {
55 return make_unique<Experiment<ListModus>>(config, output_path);
56 }
else if (modus_chooser ==
"ListBox") {
57 return make_unique<Experiment<ListBoxModus>>(config, output_path);
58 }
else if (modus_chooser ==
"Collider") {
59 return make_unique<Experiment<ColliderModus>>(config, output_path);
60 }
else if (modus_chooser ==
"Sphere") {
61 return make_unique<Experiment<SphereModus>>(config, output_path);
63 throw InvalidModusRequest(
"Invalid Modus (" + modus_chooser +
64 ") requested from ExperimentBase::create.");
477 const int ntest = config.
take({
"General",
"Testparticles"}, 1);
479 throw std::invalid_argument(
"Testparticle number should be positive!");
483 const bool only_participants =
484 config.
take({
"Output",
"Thermodynamics",
"Only_Participants"},
false);
486 if (only_participants && config.
has_value({
"Potentials"})) {
487 throw std::invalid_argument(
488 "Only_Participants option cannot be "
489 "set to True when using Potentials.");
492 const std::string modus_chooser = config.
take({
"General",
"Modus"});
496 double box_length = -1.0;
497 if (config.
has_value({
"Modi",
"Box",
"Length"})) {
498 box_length = config.
read({
"Modi",
"Box",
"Length"});
501 if (config.
has_value({
"Modi",
"ListBox",
"Length"})) {
502 box_length = config.
read({
"Modi",
"ListBox",
"Length"});
508 const double dt = config.
take({
"General",
"Delta_Time"}, 1.);
509 const double t_end = config.
read({
"General",
"End_Time"});
512 if (box_length > 0.0 && dt > box_length / 10.0) {
513 throw std::invalid_argument(
514 "Please decrease the timestep size. "
515 "A value of (dt < l_box / 10) is recommended in the boxmodus.");
519 std::unique_ptr<Clock> output_clock =
nullptr;
520 if (config.
has_value({
"Output",
"Output_Times"})) {
521 if (config.
has_value({
"Output",
"Output_Interval"})) {
522 throw std::invalid_argument(
523 "Please specify either Output_Interval or Output_Times");
525 std::vector<double> output_times = config.
take({
"Output",
"Output_Times"});
528 output_times.push_back(t_end + 1.);
529 output_clock = make_unique<CustomClock>(output_times);
531 const double output_dt = config.
take({
"Output",
"Output_Interval"}, t_end);
532 output_clock = make_unique<UniformClock>(0.0, output_dt);
537 if (config[
"Output"].has_value({
"Photons"}) &&
538 (!config.
has_value({
"Collision_Term",
"Photons"}))) {
539 throw std::invalid_argument(
540 "Photon output is enabled although photon production is disabled. "
541 "Photon production can be configured in the \"Photon\" subsection "
542 "of the \"Collision_Term\".");
546 bool missing_output_2to2 =
false;
547 bool missing_output_brems =
false;
548 if (!(config[
"Output"].has_value({
"Photons"}))) {
549 if (config.
has_value({
"Collision_Term",
"Photons",
"2to2_Scatterings"})) {
550 missing_output_2to2 =
551 config.
read({
"Collision_Term",
"Photons",
"2to2_Scatterings"});
553 if (config.
has_value({
"Collision_Term",
"Photons",
"Bremsstrahlung"})) {
554 missing_output_brems =
555 config.
read({
"Collision_Term",
"Photons",
"Bremsstrahlung"});
558 if (missing_output_2to2 || missing_output_brems) {
559 throw std::invalid_argument(
560 "Photon output is disabled although photon production is enabled. "
561 "Please enable the photon output.");
567 if (config[
"Output"].has_value({
"Dileptons"}) &&
568 (!config.
has_value({
"Collision_Term",
"Dileptons"}))) {
569 throw std::invalid_argument(
570 "Dilepton output is enabled although dilepton production is disabled. "
571 "Dilepton production can be configured in the \"Dileptons\" subsection "
572 "of the \"Collision_Term\".");
576 bool missing_output_decays =
false;
577 if (!(config[
"Output"].has_value({
"Dileptons"}))) {
578 if (config.
has_value({
"Collision_Term",
"Dileptons",
"Decays"})) {
579 missing_output_decays =
580 config.
read({
"Collision_Term",
"Dileptons",
"Decays"});
583 if (missing_output_decays) {
584 throw std::invalid_argument(
585 "Dilepton output is disabled although dilepton production is "
587 "Please enable the dilepton output.");
591 auto config_coll = config[
"Collision_Term"];
594 const double low_snn_cut =
595 config_coll.
take({
"Elastic_NN_Cutoff_Sqrts"}, 1.98);
598 if (proton && pion &&
599 low_snn_cut > proton->mass() + proton->mass() + pion->mass()) {
600 logg[
LExperiment].warn(
"The cut-off should be below the threshold energy",
601 " of the process: NN to NNpi");
603 const bool potential_affect_threshold =
604 config.
take({
"Lattice",
"Potentials_Affect_Thresholds"},
false);
605 const double scale_xs = config_coll.take({
"Cross_Section_Scaling"}, 1.0);
607 const auto criterion =
610 if (config_coll.has_value({
"Fixed_Min_Cell_Length"}) &&
612 throw std::invalid_argument(
613 "Only use a fixed minimal cell length with the stochastic collision "
616 if (config_coll.has_value({
"Maximum_Cross_Section"}) &&
618 throw std::invalid_argument(
619 "Only use maximum cross section with the "
620 "geometric collision criterion. Use Fixed_Min_Cell_Length to change "
622 "size for the stochastic criterion.");
633 const double maximum_cross_section_default =
636 bool cll_in_nucleus =
637 config.
take({
"Modi",
"Collider",
"Collisions_Within_Nucleus"},
false);
638 double maximum_cross_section = config_coll.take(
639 {
"Maximum_Cross_Section"}, maximum_cross_section_default);
640 maximum_cross_section *= scale_xs;
641 return {make_unique<UniformClock>(0.0, dt),
642 std::move(output_clock),
643 config.
take({
"General",
"Ensembles"}, 1),
645 config.
take({
"General",
"Derivatives_Mode"},
650 config.
take({
"General",
"Field_Derivatives_Mode"},
652 config.
take({
"General",
"Smearing_Mode"},
654 config.
take({
"General",
"Gaussian_Sigma"}, 1.),
655 config.
take({
"General",
"Gauss_Cutoff_In_Sigma"}, 4.),
656 config.
take({
"General",
"Discrete_Weight"}, 1. / 3.0),
657 config.
take({
"General",
"Triangular_Range"}, 2.0),
659 config_coll.take({
"Two_to_One"},
true),
661 config_coll.take({
"Multi_Particle_Reactions"},
663 config_coll.take({
"Strings"}, modus_chooser !=
"Box"),
664 config_coll.take({
"Use_AQM"},
true),
665 config_coll.take({
"Resonance_Lifetime_Modifier"}, 1.),
666 config_coll.take({
"Strings_with_Probability"},
true),
669 potential_affect_threshold,
671 maximum_cross_section,
672 config_coll.take({
"Fixed_Min_Cell_Length"}, 2.5),
675 config_coll.take({
"Additional_Elastic_Cross_Section"}, 0.0),
680 uint64_t scatterings_this_interval,
684 double E_mean_field_initial) {
685 const SystemTimeSpan elapsed_seconds = SystemClock::now() - time_start;
688 const QuantumNumbers difference = current_values - conserved_initial;
689 int total_particles = 0;
690 for (
const Particles &particles : ensembles) {
691 total_particles += particles.size();
696 const double current_energy = current_values.
momentum().
x0();
697 const double energy_per_part =
698 (total_particles > 0) ? (current_energy + E_mean_field) / total_particles
701 std::ostringstream ss;
703 ss << field<7, 3> << time
705 << field<11, 3> << current_energy
707 << field<11, 3> << E_mean_field
709 << field<12, 3> << current_energy + E_mean_field
711 << field<12, 6> << energy_per_part;
713 if (total_particles == 0) {
714 ss << field<13, 6> <<
"N/A";
716 ss << field<13, 6> << (difference.
momentum().
x0()
717 + E_mean_field - E_mean_field_initial)
720 ss << field<14, 3> << scatterings_this_interval
721 << field<10, 3> << total_particles
722 << field<9, 3> << elapsed_seconds;
733 const double V_cell = (jmuB_lat.
cell_sizes())[0] *
736 double E_mean_field = 0.0;
737 double density_mean = 0.0;
738 double density_variance = 0.0;
753 <<
"\nSymmetry energy is not included in the mean field calculation."
769 double C1GeV = (potentials.
skyrme_a()) / 1000.0;
770 double C2GeV = (potentials.
skyrme_b()) / 1000.0;
779 int number_of_nodes = 0;
780 double lattice_mean_field_total = 0.0;
782 for (
auto &node : jmuB_lat) {
785 double rhoB = node.rho();
787 const double j0B = node.jmu_net().x0();
789 const double abs_rhoB = std::abs(rhoB);
794 density_variance += j0B * j0B;
804 double mean_field_contribution_1 = (C1GeV / b1) * std::pow(abs_rhoB, b1) /
806 double mean_field_contribution_2 = (C2GeV / b2) * std::pow(abs_rhoB, b2) /
809 lattice_mean_field_total +=
810 V_cell * (mean_field_contribution_1 + mean_field_contribution_2);
814 density_mean = density_mean / number_of_nodes;
815 density_variance = density_variance / number_of_nodes;
816 double density_scaled_variance =
817 std::sqrt(density_variance - density_mean * density_mean) /
821 <<
"\n\t\t\t\t\t density mean = " << density_mean;
823 <<
"\n\t\t\t\t\t density scaled variance = " << density_scaled_variance;
825 <<
"\n\t\t\t\t\t total mean_field = "
830 E_mean_field = lattice_mean_field_total;
842 <<
"\nSymmetry energy is not included in the VDF mean-field "
844 <<
"\nas VDF potentials haven't been fitted with symmetry energy."
864 int number_of_nodes = 0;
865 double lattice_mean_field_total = 0.0;
867 for (
auto &node : jmuB_lat) {
870 double rhoB = node.rho();
872 const double j0B = node.jmu_net().x0();
873 double abs_rhoB = std::abs(rhoB);
875 density_variance += j0B * j0B;
886 double mean_field_contribution = 0.0;
888 mean_field_contribution +=
890 std::pow(abs_rhoB, potentials.
powers()[i] - 2.0) *
892 ((potentials.
powers()[i] - 1.0) / potentials.
powers()[i]) *
893 abs_rhoB * abs_rhoB) /
894 std::pow(rhoB_0, potentials.
powers()[i] - 1.0);
896 lattice_mean_field_total += V_cell * mean_field_contribution;
900 density_mean = density_mean / number_of_nodes;
901 density_variance = density_variance / number_of_nodes;
902 double density_scaled_variance =
903 std::sqrt(density_variance - density_mean * density_mean) /
907 <<
"\n\t\t\t\t\t density mean = " << density_mean;
909 <<
"\n\t\t\t\t\t density scaled variance = " << density_scaled_variance;
911 <<
"\n\t\t\t\t\t total mean_field = "
916 E_mean_field = lattice_mean_field_total;
919 double electromagnetic_potential = 0.0;
923 double V_cell_em = em_lattice->cell_sizes()[0] *
924 em_lattice->cell_sizes()[1] *
925 em_lattice->cell_sizes()[2];
926 for (
auto &fields : *em_lattice) {
928 electromagnetic_potential +=
929 hbarc * 0.5 * V_cell_em * (fields.first.sqr() + fields.second.sqr());
932 logg[
LExperiment].debug() <<
"Total energy in electromagnetic field = "
933 << electromagnetic_potential;
934 E_mean_field += electromagnetic_potential;
948 double E_mean_field,
double modus_impact_parameter,
950 bool projectile_target_interact) {
952 const double E_kinetic_total = current_values.
momentum().
x0();
953 const double E_total = E_kinetic_total + E_mean_field;
955 EventInfo event_info{modus_impact_parameter,
963 !projectile_target_interact};
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.
@ Stochastic
Stochastic Criteiron.
@ Covariant
Covariant Criterion.
std::bitset< 3 > MultiParticleReactionsBitSet
Container for the n to m reactions in the code.
#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.
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].
EventInfo fill_event_info(const std::vector< Particles > &ensembles, double E_mean_field, double modus_impact_parameter, const ExperimentParameters ¶meters, bool projectile_target_interact)
Generate the EventInfo object which is passed to outputs_.
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.