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.");
341 const int ntest = config.
take({
"General",
"Testparticles"}, 1);
343 throw std::invalid_argument(
"Testparticle number should be positive!");
346 const std::string modus_chooser = config.
take({
"General",
"Modus"});
350 double box_length = -1.0;
351 if (config.
has_value({
"Modi",
"Box",
"Length"})) {
352 box_length = config.
read({
"Modi",
"Box",
"Length"});
358 const double dt = config.
take({
"General",
"Delta_Time"}, 1.);
359 const double t_end = config.
read({
"General",
"End_Time"});
362 if (box_length > 0.0 && dt > box_length / 10.0) {
363 throw std::invalid_argument(
364 "Please decrease the timestep size. "
365 "A value of (dt < l_box / 10) is recommended in the boxmodus.");
369 std::unique_ptr<Clock> output_clock =
nullptr;
370 if (config.
has_value({
"Output",
"Output_Times"})) {
371 if (config.
has_value({
"Output",
"Output_Interval"})) {
372 throw std::invalid_argument(
373 "Please specify either Output_Interval or Output_Times");
375 std::vector<double> output_times = config.
take({
"Output",
"Output_Times"});
378 output_times.push_back(t_end + 1.);
379 output_clock = make_unique<CustomClock>(output_times);
381 const double output_dt = config.
take({
"Output",
"Output_Interval"}, t_end);
382 output_clock = make_unique<UniformClock>(0.0, output_dt);
387 if (config[
"Output"].has_value({
"Photons"}) &&
388 (!config.
has_value({
"Collision_Term",
"Photons"}))) {
389 throw std::invalid_argument(
390 "Photon output is enabled although photon production is disabled. "
391 "Photon production can be configured in the \"Photon\" subsection "
392 "of the \"Collision_Term\".");
396 bool missing_output_2to2 =
false;
397 bool missing_output_brems =
false;
398 if (!(config[
"Output"].has_value({
"Photons"}))) {
399 if (config.
has_value({
"Collision_Term",
"Photons",
"2to2_Scatterings"})) {
400 missing_output_2to2 =
401 config.
read({
"Collision_Term",
"Photons",
"2to2_Scatterings"});
403 if (config.
has_value({
"Collision_Term",
"Photons",
"Bremsstrahlung"})) {
404 missing_output_brems =
405 config.
read({
"Collision_Term",
"Photons",
"Bremsstrahlung"});
408 if (missing_output_2to2 || missing_output_brems) {
409 throw std::invalid_argument(
410 "Photon output is disabled although photon production is enabled. "
411 "Please enable the photon output.");
417 if (config[
"Output"].has_value({
"Dileptons"}) &&
418 (!config.
has_value({
"Collision_Term",
"Dileptons"}))) {
419 throw std::invalid_argument(
420 "Dilepton output is enabled although dilepton production is disabled. "
421 "Dilepton production can be configured in the \"Dileptons\" subsection "
422 "of the \"Collision_Term\".");
426 bool missing_output_decays =
false;
427 if (!(config[
"Output"].has_value({
"Dileptons"}))) {
428 if (config.
has_value({
"Collision_Term",
"Dileptons",
"Decays"})) {
429 missing_output_decays =
430 config.
read({
"Collision_Term",
"Dileptons",
"Decays"});
433 if (missing_output_decays) {
434 throw std::invalid_argument(
435 "Dilepton output is disabled although dilepton production is "
437 "Please enable the dilepton output.");
441 auto config_coll = config[
"Collision_Term"];
444 const double low_snn_cut =
445 config_coll.
take({
"Elastic_NN_Cutoff_Sqrts"}, 1.98);
448 if (proton && pion &&
449 low_snn_cut > proton->mass() + proton->mass() + pion->mass()) {
450 logg[
LExperiment].warn(
"The cut-off should be below the threshold energy",
451 " of the process: NN to NNpi");
453 const bool potential_affect_threshold =
454 config.
take({
"Lattice",
"Potentials_Affect_Thresholds"},
false);
455 const double scale_xs = config_coll.take({
"Cross_Section_Scaling"}, 1.0);
464 const double maximum_cross_section_default =
466 double maximum_cross_section = config_coll.take(
467 {
"Maximum_Cross_Section"}, maximum_cross_section_default);
468 maximum_cross_section *= scale_xs;
470 make_unique<UniformClock>(0.0, dt),
471 std::move(output_clock),
473 config.
take({
"General",
"Gaussian_Sigma"}, 1.),
474 config.
take({
"General",
"Gauss_Cutoff_In_Sigma"}, 4.),
476 config_coll.take({
"Two_to_One"},
true),
478 config_coll.take({
"Multi_Particle_Reactions"},
480 config_coll.take({
"Strings"}, modus_chooser !=
"Box"),
481 config_coll.take({
"Use_AQM"},
true),
482 config_coll.take({
"Resonance_Lifetime_Modifier"}, 1.),
483 config_coll.take({
"Strings_with_Probability"},
true),
486 potential_affect_threshold,
488 maximum_cross_section,
490 config_coll.take({
"Additional_Elastic_Cross_Section"}, 0.0)};
494 uint64_t scatterings_this_interval,
498 double E_mean_field_initial) {
499 const SystemTimeSpan elapsed_seconds = SystemClock::now() - time_start;
502 const QuantumNumbers difference = current_values - conserved_initial;
506 const double current_energy =
508 const double energy_per_part =
509 (particles.
size() > 0)
510 ? (current_energy + E_mean_field) / particles.
size()
513 std::ostringstream ss;
515 ss << field<7, 3> << time
517 << field<11, 3> << current_energy
519 << field<11, 3> << E_mean_field
521 << field<12, 3> << current_energy + E_mean_field
523 << field<12, 6> << energy_per_part;
525 if (particles.
size() == 0) {
526 ss << field<13, 6> <<
"N/A";
528 ss << field<13, 6> << (difference.
momentum().
x0()
529 + E_mean_field - E_mean_field_initial)
532 ss << field<14, 3> << scatterings_this_interval
533 << field<10, 3> << particles.
size()
534 << field<9, 3> << elapsed_seconds;
544 const double V_cell = (jmu_B_lat.
cell_sizes())[0] *
548 double E_mean_field = 0.0;
549 double density_mean = 0.0;
550 double density_variance = 0.0;
565 <<
"\nSymmetry energy is not included in the mean field calculation."
581 double C1GeV = (potentials.
skyrme_a()) / 1000.0;
582 double C2GeV = (potentials.
skyrme_b()) / 1000.0;
591 int number_of_nodes = 0;
592 double lattice_mean_field_total = 0.0;
594 for (
auto &node : jmu_B_lat) {
597 double nB = node.density();
599 const double j0 = node.jmu_net().x0();
601 const double abs_nB = std::abs(nB);
606 density_variance += j0 * j0;
616 double mean_field_contribution_1 = (C1GeV / b1) * std::pow(abs_nB, b1) /
618 double mean_field_contribution_2 = (C2GeV / b2) * std::pow(abs_nB, b2) /
621 lattice_mean_field_total +=
622 V_cell * (mean_field_contribution_1 + mean_field_contribution_2);
626 density_mean = density_mean / number_of_nodes;
627 density_variance = density_variance / number_of_nodes;
628 double density_scaled_variance =
629 std::sqrt(density_variance - density_mean * density_mean) /
633 <<
"\n\t\t\t\t\t density mean = " << density_mean;
635 <<
"\n\t\t\t\t\t density scaled variance = " << density_scaled_variance;
637 <<
"\n\t\t\t\t\t total mean_field = "
638 << lattice_mean_field_total * parameters.
testparticles <<
"\n";
645 E_mean_field = lattice_mean_field_total * parameters.
testparticles;
652 double modus_impact_parameter,
654 bool projectile_target_interact) {
656 const double E_kinetic_total = current_values.
momentum().
x0();
657 const double E_total = E_kinetic_total + E_mean_field;
659 EventInfo event_info{modus_impact_parameter,
666 !projectile_target_interact};