24 const bf::path &output_path) {
47 const std::string modus_chooser = config.read({
"General",
"Modus"});
48 logg[
LExperiment].debug() <<
"Modus for this calculation: " << modus_chooser;
50 if (modus_chooser ==
"Box") {
51 return make_unique<Experiment<BoxModus>>(config, output_path);
52 }
else if (modus_chooser ==
"List") {
53 return make_unique<Experiment<ListModus>>(config, output_path);
54 }
else if (modus_chooser ==
"Collider") {
55 return make_unique<Experiment<ColliderModus>>(config, output_path);
56 }
else if (modus_chooser ==
"Sphere") {
57 return make_unique<Experiment<SphereModus>>(config, output_path);
59 throw InvalidModusRequest(
"Invalid Modus (" + modus_chooser +
60 ") requested from ExperimentBase::create.");
338 const int ntest = config.
take({
"General",
"Testparticles"}, 1);
340 throw std::invalid_argument(
"Testparticle number should be positive!");
343 const std::string modus_chooser = config.
take({
"General",
"Modus"});
347 double box_length = -1.0;
348 if (config.
has_value({
"Modi",
"Box",
"Length"})) {
349 box_length = config.
read({
"Modi",
"Box",
"Length"});
355 const double dt = config.
take({
"General",
"Delta_Time"}, 1.);
356 const double t_end = config.
read({
"General",
"End_Time"});
359 if (box_length > 0.0 && dt > box_length / 10.0) {
360 throw std::invalid_argument(
361 "Please decrease the timestep size. "
362 "A value of (dt < l_box / 10) is recommended in the boxmodus.");
366 std::unique_ptr<Clock> output_clock =
nullptr;
367 if (config.
has_value({
"Output",
"Output_Times"})) {
368 if (config.
has_value({
"Output",
"Output_Interval"})) {
369 throw std::invalid_argument(
370 "Please specify either Output_Interval or Output_Times");
372 std::vector<double> output_times = config.
take({
"Output",
"Output_Times"});
375 output_times.push_back(t_end + 1.);
376 output_clock = make_unique<CustomClock>(output_times);
378 const double output_dt = config.
take({
"Output",
"Output_Interval"}, t_end);
379 output_clock = make_unique<UniformClock>(0.0, output_dt);
384 if (config[
"Output"].has_value({
"Photons"}) &&
385 (!config.
has_value({
"Collision_Term",
"Photons"}))) {
386 throw std::invalid_argument(
387 "Photon output is enabled although photon production is disabled. "
388 "Photon production can be configured in the \"Photon\" subsection "
389 "of the \"Collision_Term\".");
393 bool missing_output_2to2 =
false;
394 bool missing_output_brems =
false;
395 if (!(config[
"Output"].has_value({
"Photons"}))) {
396 if (config.
has_value({
"Collision_Term",
"Photons",
"2to2_Scatterings"})) {
397 missing_output_2to2 =
398 config.
read({
"Collision_Term",
"Photons",
"2to2_Scatterings"});
400 if (config.
has_value({
"Collision_Term",
"Photons",
"Bremsstrahlung"})) {
401 missing_output_brems =
402 config.
read({
"Collision_Term",
"Photons",
"Bremsstrahlung"});
405 if (missing_output_2to2 || missing_output_brems) {
406 throw std::invalid_argument(
407 "Photon output is disabled although photon production is enabled. "
408 "Please enable the photon output.");
414 if (config[
"Output"].has_value({
"Dileptons"}) &&
415 (!config.
has_value({
"Collision_Term",
"Dileptons"}))) {
416 throw std::invalid_argument(
417 "Dilepton output is enabled although dilepton production is disabled. "
418 "Dilepton production can be configured in the \"Dileptons\" subsection "
419 "of the \"Collision_Term\".");
423 bool missing_output_decays =
false;
424 if (!(config[
"Output"].has_value({
"Dileptons"}))) {
425 if (config.
has_value({
"Collision_Term",
"Dileptons",
"Decays"})) {
426 missing_output_decays =
427 config.
read({
"Collision_Term",
"Dileptons",
"Decays"});
430 if (missing_output_decays) {
431 throw std::invalid_argument(
432 "Dilepton output is disabled although dilepton production is "
434 "Please enable the dilepton output.");
438 auto config_coll = config[
"Collision_Term"];
441 const double low_snn_cut =
442 config_coll.
take({
"Elastic_NN_Cutoff_Sqrts"}, 1.98);
445 if (proton && pion &&
446 low_snn_cut > proton->mass() + proton->mass() + pion->mass()) {
447 logg[
LExperiment].warn(
"The cut-off should be below the threshold energy",
448 " of the process: NN to NNpi");
450 const bool potential_affect_threshold =
451 config.
take({
"Lattice",
"Potentials_Affect_Thresholds"},
false);
452 const double scale_xs = config_coll.take({
"Cross_Section_Scaling"}, 1.0);
461 const double maximum_cross_section_default =
463 double maximum_cross_section = config_coll.take(
464 {
"Maximum_Cross_Section"}, maximum_cross_section_default);
465 maximum_cross_section *= scale_xs;
467 make_unique<UniformClock>(0.0, dt),
468 std::move(output_clock),
470 config.
take({
"General",
"Gaussian_Sigma"}, 1.),
471 config.
take({
"General",
"Gauss_Cutoff_In_Sigma"}, 4.),
473 config_coll.take({
"Two_to_One"},
true),
475 config_coll.take({
"Multi_Particle_Reactions"},
477 config_coll.take({
"Strings"}, modus_chooser !=
"Box"),
478 config_coll.take({
"Use_AQM"},
true),
479 config_coll.take({
"Resonance_Lifetime_Modifier"}, 1.),
480 config_coll.take({
"Strings_with_Probability"},
true),
483 potential_affect_threshold,
485 maximum_cross_section,
487 config_coll.take({
"Additional_Elastic_Cross_Section"}, 0.0)};
491 uint64_t scatterings_this_interval,
495 double E_mean_field_initial) {
496 const SystemTimeSpan elapsed_seconds = SystemClock::now() - time_start;
499 const QuantumNumbers difference = current_values - conserved_initial;
503 const double current_energy =
505 const double energy_per_part =
506 (particles.
size() > 0)
507 ? (current_energy + E_mean_field) / particles.
size()
510 std::ostringstream ss;
512 ss << field<7, 3> << time
514 << field<11, 3> << current_energy
516 << field<11, 3> << E_mean_field
518 << field<12, 3> << current_energy + E_mean_field
520 << field<12, 6> << energy_per_part;
522 if (particles.
size() == 0) {
523 ss << field<13, 6> <<
"N/A";
525 ss << field<13, 6> << (difference.
momentum().
x0()
526 + E_mean_field - E_mean_field_initial)
529 ss << field<14, 3> << scatterings_this_interval
530 << field<10, 3> << particles.
size()
531 << field<9, 3> << elapsed_seconds;
541 const double V_cell = (jmu_B_lat.
cell_sizes())[0] *
545 double E_mean_field = 0.0;
546 double density_mean = 0.0;
547 double density_variance = 0.0;
562 <<
"\nSymmetry energy is not included in the mean field calculation."
578 double C1GeV = (potentials.
skyrme_a()) / 1000.0;
579 double C2GeV = (potentials.
skyrme_b()) / 1000.0;
588 int number_of_nodes = 0;
589 double lattice_mean_field_total = 0.0;
591 for (
auto &node : jmu_B_lat) {
594 double nB = node.density();
596 const double j0 = node.jmu_net().x0();
598 const double abs_nB = std::abs(nB);
603 density_variance += j0 * j0;
613 double mean_field_contribution_1 = (C1GeV / b1) * std::pow(abs_nB, b1) /
615 double mean_field_contribution_2 = (C2GeV / b2) * std::pow(abs_nB, b2) /
618 lattice_mean_field_total +=
619 V_cell * (mean_field_contribution_1 + mean_field_contribution_2);
623 density_mean = density_mean / number_of_nodes;
624 density_variance = density_variance / number_of_nodes;
625 double density_scaled_variance =
626 std::sqrt(density_variance - density_mean * density_mean) /
630 <<
"\n\t\t\t\t\t density mean = " << density_mean;
632 <<
"\n\t\t\t\t\t density scaled variance = " << density_scaled_variance;
634 <<
"\n\t\t\t\t\t total mean_field = "
635 << lattice_mean_field_total * parameters.
testparticles <<
"\n";
642 E_mean_field = lattice_mean_field_total * parameters.
testparticles;
649 double modus_impact_parameter,
651 bool projectile_target_interact) {
653 const double E_kinetic_total = current_values.
momentum().
x0();
654 const double E_total = E_kinetic_total + E_mean_field;
656 EventInfo event_info{modus_impact_parameter,
663 !projectile_target_interact};