Version: SMASH-3.3
collidermodus.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012-2025
3  * SMASH Team
4  *
5  * GNU General Public License (GPLv3 or later)
6  */
7 
8 #include "smash/collidermodus.h"
9 
10 #include <algorithm>
11 #include <cmath>
12 #include <cstdlib>
13 #include <cstring>
14 #include <memory>
15 #include <stdexcept>
16 #include <string>
17 #include <tuple>
18 #include <utility>
19 #include <vector>
20 
21 #include "smash/configuration.h"
22 #include "smash/customnucleus.h"
25 #include "smash/fourvector.h"
26 #include "smash/icparameters.h"
27 #include "smash/input_keys.h"
28 #include "smash/logging.h"
29 #include "smash/nucleus.h"
30 #include "smash/random.h"
31 
32 namespace smash {
33 static constexpr int LCollider = LogArea::Collider::id;
34 static constexpr int LInitialConditions = LogArea::InitialConditions::id;
35 
37  const ExperimentParameters &params) {
38  Configuration modus_cfg = modus_config.extract_complete_sub_configuration(
40  // Get the reference frame for the collision calculation.
42 
45  Configuration targ_cfg =
47  /* Needed to check if projectile and target in customnucleus are read from
48  * the same input file.*/
49  bool same_file = false;
50  // Set up the projectile nucleus
52  projectile_ =
53  create_deformed_nucleus(proj_cfg, params.testparticles, "projectile");
54  } else if (proj_cfg.has_section(InputSections::m_c_p_custom)) {
55  same_file = same_inputfile(proj_cfg, targ_cfg);
56  projectile_ = std::make_unique<CustomNucleus>(
57  proj_cfg, params.testparticles, same_file);
58  } else if (proj_cfg.has_section(InputSections::m_c_p_alphaClustered)) {
59  logg[LCollider].info() << "Projectile is alpha-clustered with woods-saxon "
60  "parameters for the He-clusters listed below.";
62  "projectile");
63  } else {
64  projectile_ = std::make_unique<Nucleus>(proj_cfg, params.testparticles);
65  }
66  if (projectile_->size() < 1) {
67  throw ColliderEmpty("Input Error: Projectile nucleus is empty.");
68  }
70 
71  // Set up the target nucleus
73  target_ = create_deformed_nucleus(targ_cfg, params.testparticles, "target");
74  } else if (targ_cfg.has_section(InputSections::m_c_t_custom)) {
75  target_ = std::make_unique<CustomNucleus>(targ_cfg, params.testparticles,
76  same_file);
77  } else if (targ_cfg.has_section(InputSections::m_c_t_alphaClustered)) {
78  logg[LCollider].info() << "Target is alpha-clustered with woods-saxon "
79  "parameters for the He-clusters listed below.";
80  target_ =
81  create_alphaclustered_nucleus(targ_cfg, params.testparticles, "target");
82  } else {
83  target_ = std::make_unique<Nucleus>(targ_cfg, params.testparticles);
84  }
85  if (target_->size() < 1) {
86  throw ColliderEmpty("Input Error: Target nucleus is empty.");
87  }
88  target_->set_label(BelongsTo::Target);
89 
90  // Get the Fermi-Motion input (off, on, frozen)
93  logg[LCollider].info() << "Fermi motion is ON.";
94  } else if (fermi_motion_ == FermiMotion::Frozen) {
95  logg[LCollider].info() << "FROZEN Fermi motion is on.";
96  } else if (fermi_motion_ == FermiMotion::Off) {
97  logg[LCollider].info() << "Fermi motion is OFF.";
98  }
99 
100  // Get the total nucleus-nucleus collision energy. Since there is
101  // no meaningful choice for a default energy, we require the user to
102  // give one (and only one) energy input from the available options.
103  int energy_input = 0;
104  const double mass_projec = projectile_->mass();
105  const double mass_target = target_->mass();
106  // average mass of a particle in that nucleus
107  const double mass_a =
108  projectile_->mass() / projectile_->number_of_particles();
109  const double mass_b = target_->mass() / target_->number_of_particles();
110  // Option 1: Center of mass energy.
113  // Check that input satisfies the lower bound (everything at rest).
114  if (sqrt_s_NN_ <= mass_a + mass_b) {
116  "Input Error: sqrt(s_NN) is not larger than masses:\n" +
117  std::to_string(sqrt_s_NN_) + " GeV <= " + std::to_string(mass_a) +
118  " GeV + " + std::to_string(mass_b) + " GeV.");
119  }
120  // Set the total nucleus-nucleus collision energy.
121  total_s_ = (sqrt_s_NN_ * sqrt_s_NN_ - mass_a * mass_a - mass_b * mass_b) *
122  mass_projec * mass_target / (mass_a * mass_b) +
123  mass_projec * mass_projec + mass_target * mass_target;
124  energy_input++;
125  }
126  /* Option 2: Total energy per nucleon of the projectile nucleus
127  * (target at rest). */
128  if (modus_cfg.has_value(InputKeys::modi_collider_eTot)) {
129  const double e_tot = modus_cfg.take(InputKeys::modi_collider_eTot);
130  if (e_tot < 0) {
132  "Input Error: "
133  "E_Tot must be nonnegative.");
134  }
135  // Set the total nucleus-nucleus collision energy.
136  total_s_ = s_from_Etot(e_tot * projectile_->number_of_particles(),
137  mass_projec, mass_target);
138  sqrt_s_NN_ = std::sqrt(s_from_Etot(e_tot, mass_a, mass_b));
139  energy_input++;
140  }
141  /* Option 3: Kinetic energy per nucleon of the projectile nucleus
142  * (target at rest). */
143  if (modus_cfg.has_value(InputKeys::modi_collider_eKin)) {
144  const double e_kin = modus_cfg.take(InputKeys::modi_collider_eKin);
145  if (e_kin < 0) {
147  "Input Error: "
148  "E_Kin must be nonnegative.");
149  }
150  // Set the total nucleus-nucleus collision energy.
151  total_s_ = s_from_Ekin(e_kin * projectile_->number_of_particles(),
152  mass_projec, mass_target);
153  sqrt_s_NN_ = std::sqrt(s_from_Ekin(e_kin, mass_a, mass_b));
154  energy_input++;
155  }
156  // Option 4: Momentum of the projectile nucleus (target at rest).
157  if (modus_cfg.has_value(InputKeys::modi_collider_pLab)) {
158  const double p_lab = modus_cfg.take(InputKeys::modi_collider_pLab);
159  if (p_lab < 0) {
161  "Input Error: "
162  "P_Lab must be nonnegative.");
163  }
164  // Set the total nucleus-nucleus collision energy.
165  total_s_ = s_from_plab(p_lab * projectile_->number_of_particles(),
166  mass_projec, mass_target);
167  sqrt_s_NN_ = std::sqrt(s_from_plab(p_lab, mass_a, mass_b));
168  energy_input++;
169  }
170  // Option 5: Total energy per nucleon of _each_ beam
173  const double e_tot_p =
175  const double e_tot_t = targ_cfg.take(InputKeys::modi_collider_target_eTot);
176  if (e_tot_p < 0 || e_tot_t < 0) {
178  "Input Error: "
179  "E_Tot must be nonnegative.");
180  }
181  total_s_ = s_from_Etot(e_tot_p * projectile_->number_of_particles(),
182  e_tot_t * target_->number_of_particles(),
183  mass_projec, mass_target);
184  sqrt_s_NN_ = std::sqrt(s_from_Ekin(e_tot_p, e_tot_t, mass_a, mass_b));
185  energy_input++;
186  }
187  // Option 6: Kinetic energy per nucleon of _each_ beam
190  const double e_kin_p =
192  const double e_kin_t = targ_cfg.take(InputKeys::modi_collider_target_eKin);
193  if (e_kin_p < 0 || e_kin_t < 0) {
195  "Input Error: "
196  "E_Kin must be nonnegative.");
197  }
198  total_s_ = s_from_Ekin(e_kin_p * projectile_->number_of_particles(),
199  e_kin_t * target_->number_of_particles(),
200  mass_projec, mass_target);
201  sqrt_s_NN_ = std::sqrt(s_from_Ekin(e_kin_p, e_kin_t, mass_a, mass_b));
202  energy_input++;
203  }
204  // Option 7: Momentum per nucleon of _each_ beam
207  const double p_lab_p =
209  const double p_lab_t = targ_cfg.take(InputKeys::modi_collider_target_pLab);
210  if (p_lab_p < 0 || p_lab_t < 0) {
212  "Input Error: "
213  "P_Lab must be nonnegative.");
214  }
215  total_s_ = s_from_plab(p_lab_p * projectile_->number_of_particles(),
216  p_lab_t * target_->number_of_particles(),
217  mass_projec, mass_target);
218  sqrt_s_NN_ = std::sqrt(s_from_plab(p_lab_p, p_lab_t, mass_a, mass_b));
219  energy_input++;
220  }
221  if (energy_input == 0) {
222  throw std::domain_error(
223  "Input Error: Non-existent collision energy. "
224  "Please provide one of Sqrtsnn/E_Kin/P_Lab.");
225  }
226  if (energy_input > 1) {
227  throw std::invalid_argument(
228  "Input Error: Redundant collision energy. "
229  "Please provide only one of Sqrtsnn/E_Kin/P_Lab.");
230  }
231 
232  /* Impact parameter setting: Either "Value", "Range", "Max" or "Sample".
233  * Unspecified means 0 impact parameter.*/
236  imp_min_ = impact_;
237  imp_max_ = impact_;
238  } else {
239  // If impact is not supplied by value, inspect sampling parameters:
242  if (sampling_ == Sampling::Custom) {
245  throw std::invalid_argument(
246  "Input Error: Need impact parameter spectrum for custom sampling."
247  " Please provide Values and Yields.");
248  }
249  const std::vector<double> impacts =
251  const std::vector<double> yields =
253  if (impacts.size() != yields.size()) {
254  throw std::invalid_argument(
255  "Input Error: Need as many impact parameter values as yields. "
256  "Please make sure that Values and Yields have the same length.");
257  }
258  impact_interpolation_ = std::make_unique<InterpolateDataLinear<double>>(
259  InterpolateDataLinear<double>(impacts, yields));
260 
261  const auto imp_minmax =
262  std::minmax_element(impacts.begin(), impacts.end());
263  imp_min_ = *imp_minmax.first;
264  imp_max_ = *imp_minmax.second;
265  yield_max_ = *std::max_element(yields.begin(), yields.end());
266  }
267  }
269  const std::array<double, 2> range =
271  imp_min_ = range[0];
272  imp_max_ = range[1];
273  }
275  imp_min_ = 0.0;
277  }
278  }
280  // whether the direction of separation should be randomly sampled
283  // Look for user-defined initial separation between nuclei.
284  // The displacement is half the distance (both nuclei are shifted
285  // initial_z_displacement_ away from origin)
289  IC_for_hybrid_ = true;
290  IC_parameters_ = std::make_unique<InitialConditionParameters>();
291  IC_parameters_->type =
293 
296  if (modus_cfg.has_value(
298  IC_parameters_->proper_time = modus_cfg.take(
300  } else {
301  IC_parameters_->lower_bound = modus_cfg.take(
303  IC_parameters_->proper_time_scaling =
305  }
306  IC_parameters_->rapidity_cut = modus_cfg.take(
308  IC_parameters_->pT_cut =
311  } else if (IC_parameters_->type == FluidizationType::Dynamic) {
313  double threshold = modus_cfg.take(
315  double min_time =
317  double max_time =
319  int cells =
321  double form_time_fraction = modus_cfg.take(
323  if (threshold <= 0 || max_time < min_time || min_time < 0 || cells < 2 ||
324  form_time_fraction < 0) {
325  logg[LInitialConditions].fatal()
326  << "Bad parameters chosen for dynamic initial conditions. At least "
327  "one of the following inequalities is violated:\n"
328  << " Energy_Density_Threshold = " << threshold << " > 0\n"
329  << " Maximum_Time = " << max_time << " > " << min_time
330  << " = Minimum_Time > 0\n"
331  "Fluidization_Cells = "
332  << cells << " > 2\n"
333  << " Formation_Time_Fraction < 0";
334  throw std::invalid_argument("Please adjust the configuration file.");
335  }
336 
337  IC_parameters_->fluidizable_processes = modus_cfg.take(
339 
340  double min_size = std::max(min_time, 40.);
341  std::array<double, 3> length{2 * min_size, 2 * min_size, 2 * min_size};
342  std::array<double, 3> origin{-min_size, -min_size, -min_size};
343  std::array<int, 3> cell_array{cells, cells, cells};
344 
346  std::make_unique<RectangularLattice<EnergyMomentumTensor>>(
347  length, cell_array, origin, false, LatticeUpdate::EveryTimestep);
348  fluid_background_ = std::make_unique<std::map<int32_t, double>>();
349 
350  IC_parameters_->energy_density_threshold = threshold;
351  IC_parameters_->min_time = min_time;
352  IC_parameters_->max_time = max_time;
353  IC_parameters_->num_fluid_cells = cells;
354  logg[LInitialConditions].info()
355  << "Preparing dynamic Initial Conditions with threshold " << threshold
356  << " GeV/fm³ in energy density, between " << min_time << " and "
357  << max_time << " fm.";
358  IC_parameters_->formation_time_fraction = form_time_fraction;
359  IC_parameters_->smearing_kernel_at_0 =
360  std::pow(2 * M_PI * params.gaussian_sigma, -1.5);
361  IC_parameters_->delay_initial_elastic = modus_cfg.take(
363  }
364  }
365 }
366 
368  bool bad_cuts = false;
369  assert(IC_parameters_->rapidity_cut.has_value());
370  assert(IC_parameters_->pT_cut.has_value());
371  const double rapidity = IC_parameters_->rapidity_cut.value();
372  const double pT = IC_parameters_->pT_cut.value();
373  if (rapidity < 0.0) {
374  logg[LInitialConditions].fatal()
375  << "Rapidity cut for initial conditions configured as |y| < "
376  << rapidity
377  << " is unreasonable. \nPlease choose a positive, non-zero value or "
378  "employ SMASH without rapidity cut.";
379  bad_cuts = true;
380  }
381  if (pT < 0.0) {
382  logg[LInitialConditions].fatal()
383  << "Transverse momentum cut for initial conditions configured as pT < "
384  << pT
385  << " is unreasonable. \nPlease choose a positive, non-zero value or "
386  "employ SMASH without pT cut.";
387  bad_cuts = true;
388  }
389  if (bad_cuts) {
390  throw std::runtime_error(
391  "Kinematic cut for initial conditions malconfigured.");
392  }
393 
394  std::ostringstream message{"Extracting iso-tau initial conditions ",
395  std::ios_base::ate};
396  std::vector<std::string> cuts{};
397  if (rapidity > 0.0) {
398  cuts.emplace_back("|y| <= ");
399  cuts.back() += std::to_string(rapidity);
400  }
401  if (pT > 0.0) {
402  cuts.emplace_back("pT <= ");
403  cuts.back() += std::to_string(pT) + " GeV.";
404  }
405  if (cuts.size() > 0) {
406  message << "in kinematic range: " << join(cuts, "; ") << ".";
407  } else {
408  message << "without kinematic cuts.";
409  }
410  logg[LInitialConditions].info() << message.str();
411 }
412 
413 std::ostream &operator<<(std::ostream &out, const ColliderModus &m) {
414  return out << "-- Collider Modus:\n"
415  << "sqrt(S) (nucleus-nucleus) = "
416  << format(std::sqrt(m.total_s_), "GeV\n")
417  << "sqrt(S) (nucleon-nucleon) = " << format(m.sqrt_s_NN_, "GeV\n")
418  << "Projectile:\n"
419  << *m.projectile_ << "\nTarget:\n"
420  << *m.target_;
421 }
422 
423 std::unique_ptr<DeformedNucleus> ColliderModus::create_deformed_nucleus(
424  Configuration &nucleus_cfg, int ntest, const std::string &nucleus_type) {
425  assert(has_projectile_or_target(nucleus_cfg));
426  const bool is_projectile = is_about_projectile(nucleus_cfg);
427  const auto &[automatic_key, beta2_key, beta3_key, beta4_key,
428  gamma_key] = [&is_projectile]() {
429  return is_projectile
430  ? std::make_tuple(
436  : std::make_tuple(
442  }();
443 
444  bool automatic_deformation = nucleus_cfg.take(automatic_key);
445  bool was_any_beta_given = nucleus_cfg.has_value(beta2_key) ||
446  nucleus_cfg.has_value(beta3_key) ||
447  nucleus_cfg.has_value(beta4_key);
448  bool was_any_deformation_parameter_given =
449  was_any_beta_given || nucleus_cfg.has_value(gamma_key);
450  bool was_gamma_given_without_beta_2 =
451  nucleus_cfg.has_value(gamma_key) && !nucleus_cfg.has_value(beta2_key);
452 
453  if (automatic_deformation && was_any_deformation_parameter_given) {
454  throw std::invalid_argument(
455  "Automatic deformation of " + nucleus_type +
456  " nucleus requested, but deformation parameter(s) were provided as"
457  " well. Please, check the 'Deformed' section in your input file.");
458  } else if (!automatic_deformation && !was_any_beta_given) {
459  throw std::invalid_argument(
460  "Manual deformation of " + nucleus_type +
461  " nucleus requested, but no deformation beta parameter was provided."
462  " Please, check the 'Deformed' section in your input file.");
463  } else if (!automatic_deformation && was_gamma_given_without_beta_2) {
464  throw std::invalid_argument(
465  "Manual deformation of " + nucleus_type +
466  " nucleus requested, but 'Gamma' parameter was provided without "
467  "providing a value of 'Beta_2' having hence no deformation effect. "
468  "Please, check the 'Deformed' section in your input file.");
469  } else {
470  return std::make_unique<DeformedNucleus>(nucleus_cfg, ntest,
471  automatic_deformation);
472  }
473 }
474 
475 std::unique_ptr<AlphaClusteredNucleus>
477  int ntest,
478  const std::string &nucleus_type) {
479  const bool is_projectile = is_about_projectile(nucleus_cfg);
480  const auto &[automatic_key, side_length_key] = [&is_projectile]() {
481  return is_projectile
482  ? std::make_tuple(
483  InputKeys::
484  modi_collider_projectile_alphaClustered_automatic,
485  InputKeys::
486  modi_collider_projectile_alphaClustered_sideLength)
487  : std::make_tuple(
490  }();
491 
492  bool automatic_alphaclustering = nucleus_cfg.take(automatic_key);
493  bool was_sidelength_given = nucleus_cfg.has_value(side_length_key);
494 
495  if (automatic_alphaclustering && was_sidelength_given) {
496  throw std::invalid_argument(
497  "Automatic alpha-clustering of " + nucleus_type +
498  " nucleus requested, but a sidelength was provided as"
499  " well. Please, check the 'Alpha_Clustered' section in your input "
500  "file.");
501  } else if (!automatic_alphaclustering && !was_sidelength_given) {
502  throw std::invalid_argument(
503  "Manual alpha-clustering of " + nucleus_type +
504  " nucleus requested, but no sidelength was provided."
505  " Please, check the 'Alpha_Clustered' section in your input file.");
506  } else {
507  return std::make_unique<AlphaClusteredNucleus>(nucleus_cfg, ntest,
508  automatic_alphaclustering);
509  }
510 }
511 
513  const ExperimentParameters &) {
514  // Populate the nuclei with appropriately distributed nucleons.
515  // If deformed, this includes rotating the nucleus.
516  projectile_->arrange_nucleons();
517  target_->arrange_nucleons();
518 
519  // Use the total mandelstam variable to get the frame-dependent velocity for
520  // each nucleus. Position a is projectile, position b is target.
521  double v_a, v_b;
522  std::tie(v_a, v_b) =
523  get_velocities(total_s_, projectile_->mass(), target_->mass());
524 
525  // If velocities are larger or equal to 1, throw an exception.
526  if (v_a >= 1.0 || v_b >= 1.0) {
527  throw std::domain_error(
528  "Found velocity equal to or larger than 1 in "
529  "ColliderModus::initial_conditions.\nConsider using "
530  "the center of velocity reference frame.");
531  }
532 
533  // Calculate the beam velocity of the projectile and the target, which will
534  // be used to calculate the beam momenta in experiment.cc
536  velocity_projectile_ = v_a;
537  velocity_target_ = v_b;
538  }
539 
540  // Generate Fermi momenta if necessary
543  // Frozen: Fermi momenta will be ignored during the propagation to
544  // avoid that the nuclei will fly apart.
545  projectile_->generate_fermi_momenta();
546  target_->generate_fermi_momenta();
547  } else if (fermi_motion_ == FermiMotion::Off) {
548  } else {
549  throw std::invalid_argument("Invalid Fermi_Motion input.");
550  }
551 
552  // Boost the nuclei to the appropriate velocity.
553  projectile_->boost(v_a);
554  target_->boost(v_b);
555 
556  // Shift the nuclei into starting positions. Contracted spheres with
557  // nuclear radii should touch exactly at t=0. Modus starts at negative
558  // time corresponding to additional initial displacement.
559  const double d_a = std::max(0., projectile_->get_diffusiveness());
560  const double d_b = std::max(0., target_->get_diffusiveness());
561  const double r_a = projectile_->get_nuclear_radius();
562  const double r_b = target_->get_nuclear_radius();
563  const double dz = initial_z_displacement_;
564 
565  const double simulation_time = -dz / std::abs(v_a);
566  const double proj_z = -dz - std::sqrt(1.0 - v_a * v_a) * (r_a + d_a);
567  const double targ_z =
568  +dz * std::abs(v_b / v_a) + std::sqrt(1.0 - v_b * v_b) * (r_b + d_b);
569  // rotation angle in the transverse plane
570  const double phi =
571  random_reaction_plane_ ? random::uniform(0.0, 2.0 * M_PI) : 0.0;
572 
573  projectile_->shift(proj_z, +impact_ / 2.0, simulation_time);
574  target_->shift(targ_z, -impact_ / 2.0, simulation_time);
575 
576  // Put the particles in the nuclei into code particles.
577  projectile_->copy_particles(particles);
578  target_->copy_particles(particles);
579  rotate_reaction_plane(phi, particles);
580  return simulation_time;
581 }
582 
583 void ColliderModus::rotate_reaction_plane(double phi, Particles *particles) {
584  for (ParticleData &p : *particles) {
585  ThreeVector pos = p.position().threevec();
586  ThreeVector mom = p.momentum().threevec();
587  pos.rotate_around_z(phi);
588  mom.rotate_around_z(phi);
589  p.set_3position(pos);
590  p.set_3momentum(mom);
591  }
592 }
593 
595  switch (sampling_) {
596  case Sampling::Quadratic: {
597  // quadratic sampling: Note that for bmin > bmax, this still yields
598  // the correct distribution (however canonical() = 0 is then the
599  // upper end, not the lower).
600  impact_ = std::sqrt(imp_min_ * imp_min_ +
603  } break;
604  case Sampling::Custom: {
605  // rejection sampling based on given distribution
606  assert(impact_interpolation_ != nullptr);
607  double probability_random = 1;
608  double probability = 0;
609  double b;
610  while (probability_random > probability) {
612  probability = (*impact_interpolation_)(b) / yield_max_;
613  assert(probability < 1.);
614  probability_random = random::uniform(0., 1.);
615  }
616  impact_ = b;
617  } break;
618  case Sampling::Uniform: {
619  // linear sampling. Still, min > max works fine.
621  }
622  }
623 }
624 
625 std::pair<double, double> ColliderModus::get_velocities(double s, double m_a,
626  double m_b) {
627  double v_a = 0.0;
628  double v_b = 0.0;
629  // Frame dependent calculations of velocities. Assume v_a >= 0, v_b <= 0.
630  switch (frame_) {
632  v_a = center_of_velocity_v(s, m_a, m_b);
633  v_b = -v_a;
634  break;
636  // Compute center of mass momentum.
637  double pCM = pCM_from_s(s, m_a, m_b);
638  v_a = pCM / std::sqrt(m_a * m_a + pCM * pCM);
639  v_b = -pCM / std::sqrt(m_b * m_b + pCM * pCM);
640  } break;
642  v_a = fixed_target_projectile_v(s, m_a, m_b);
643  break;
644  default:
645  throw std::invalid_argument(
646  "Invalid reference frame in "
647  "ColliderModus::get_velocities.");
648  }
649  return std::make_pair(v_a, v_b);
650 }
651 
652 std::string ColliderModus::custom_file_path(const std::string &file_directory,
653  const std::string &file_name) {
654  // make sure that path is correct even if the / at the end is missing
655  if (file_directory.back() == '/') {
656  return file_directory + file_name;
657  } else {
658  return file_directory + '/' + file_name;
659  }
660 }
661 
663  Configuration &targ_config) {
664  /* Check if both nuclei are custom
665  * Only check target as function is called after if statement for
666  * projectile.
667  */
668  if (!targ_config.has_section(InputSections::m_c_t_custom)) {
669  return false;
670  }
671  std::string projectile_file_directory = proj_config.read(
673  std::string target_file_directory =
675  std::string projectile_file_name =
677  std::string target_file_name =
679  // Check if files are the same for projectile and target
680  std::string proj_path =
681  custom_file_path(projectile_file_directory, projectile_file_name);
682  std::string targ_path =
683  custom_file_path(target_file_directory, target_file_name);
684  if (proj_path == targ_path) {
685  return true;
686  } else {
687  return false;
688  }
689 }
690 
692  const double t, const std::vector<Particles> &ensembles,
693  const DensityParameters &dens_par) {
694  if (fluid_lattice_ == nullptr) {
695  throw std::logic_error(
696  "Trying to build fluidization lattice with unset pointer in "
697  "ColliderModus.");
698  }
699  if (t < IC_parameters_->min_time.value() ||
700  t > IC_parameters_->max_time.value()) {
701  return;
702  }
703  const double resizing_rate = 5;
704  double side = fluid_lattice_->lattice_sizes()[0] / 2.;
705  if (t > side) {
706  side += resizing_rate;
707  std::array<double, 3> new_length{2 * side, 2 * side, 2 * side};
708  std::array<double, 3> new_origin{-side, -side, -side};
709  fluid_lattice_->reset_and_resize(new_length, new_origin, std::nullopt);
710  logg[LCollider].debug() << "Fluidization lattice resizing at " << t
711  << " fm to " << 2 * side << " fm";
712  }
713 
716  dens_par, ensembles, false);
717 }
718 
719 } // namespace smash
ColliderModus: Provides a modus for colliding nuclei.
Definition: collidermodus.h:48
CalculationFrame frame_
Reference frame for the system, as specified from config.
double imp_min_
Minimum value of impact parameter.
double initial_z_displacement_
Initial z-displacement of nuclei.
bool IC_for_hybrid_
Whether the particles will serve as initial conditions for hydrodynamics.
double yield_max_
Maximum value of yield. Needed for custom impact parameter sampling.
bool random_reaction_plane_
Whether the reaction plane should be randomized.
void rotate_reaction_plane(double phi, Particles *particles)
Rotate the reaction plane about the angle phi.
std::pair< double, double > get_velocities(double mandelstam_s, double m_a, double m_b)
Get the frame dependent velocity for each nucleus, using the current reference frame.
void sample_impact()
Sample impact parameter.
std::unique_ptr< Nucleus > projectile_
Projectile.
std::unique_ptr< InterpolateDataLinear< double > > impact_interpolation_
Pointer to the impact parameter interpolation.
FermiMotion fermi_motion_
An option to include Fermi motion ("off", "on", "frozen")
static std::unique_ptr< AlphaClusteredNucleus > create_alphaclustered_nucleus(Configuration &nucleus_cfg, const int ntest, const std::string &nucleus_type)
Configure Alpha-Clustered Nucleus.
double velocity_projectile_
Beam velocity of the projectile.
Sampling sampling_
Method used for sampling of impact parameter.
std::unique_ptr< RectangularLattice< EnergyMomentumTensor > > fluid_lattice_
Energy-momentum tensor lattice for dynamic fluidization.
std::string custom_file_path(const std::string &file_directory, const std::string &file_name)
Creates full path string consisting of file_directory and file_name Needed to initialize a customnucl...
double total_s_
Center-of-mass energy squared of the nucleus-nucleus collision.
std::unique_ptr< Nucleus > target_
Target.
ColliderModus(Configuration modus_config, const ExperimentParameters &parameters)
Constructor.
double impact_
Impact parameter.
double sqrt_s_NN_
Center-of-mass energy of a nucleon-nucleon collision.
double initial_conditions(Particles *particles, const ExperimentParameters &parameters)
Generates initial state of the particles in the system.
void build_fluidization_lattice(double t, const std::vector< Particles > &ensembles, const DensityParameters &dens_par)
Build lattice of energy momentum tensor.
bool same_inputfile(Configuration &proj_config, Configuration &targ_config)
Checks if target and projectile are read from the same external file if they are both initialized as ...
std::unique_ptr< std::map< int32_t, double > > fluid_background_
Energy density background from hydrodynamic evolution, with particle indices as keys.
void validate_IC_kinematic_range()
Validate whether the input kinematic range for the Initial Conditions output is valid and inform the ...
static std::unique_ptr< DeformedNucleus > create_deformed_nucleus(Configuration &nucleus_cfg, const int ntest, const std::string &nucleus_type)
Configure Deformed Nucleus.
double velocity_target_
Beam velocity of the target.
std::unique_ptr< InitialConditionParameters > IC_parameters_
Plain Old Data type to hold parameters for initial conditions.
double imp_max_
Maximum value of impact parameter.
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.
Configuration extract_complete_sub_configuration(KeyLabels section, Configuration::GetEmpty empty_if_not_existing=Configuration::GetEmpty::No)
Alternative method to extract a sub-configuration, which retains the labels from the top-level in the...
T take(const Key< T > &key)
The default interface for SMASH to read configuration values.
A class to pre-calculate and store parameters relevant for density calculation.
Definition: density.h:92
static bool remove_particle_
Whether fluidization actions remove the particle from the evolution.
Represent a piecewise linear interpolation.
Definition: interpolation.h:62
double length() const
Definition: modusdefault.h:93
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:59
The Particles class abstracts the storage and manipulation of particles.
Definition: particles.h:33
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
void rotate_around_z(double theta)
Rotate the vector around the z axis by the given angle theta.
Definition: threevector.h:324
@ On
Use fermi motion in combination with potentials.
@ Frozen
Use fermi motion without potentials.
@ Off
Don't use fermi motion.
@ ConstantTau
Hypersurface crossed at a fixed proper time.
@ Dynamic
Dynamic fluidization based on local densities.
@ Quadratic
Sample from areal / quadratic distribution.
@ Custom
Sample from custom, user-defined distribution.
@ Uniform
Sample from uniform distribution.
std::ostream & operator<<(std::ostream &out, const ActionPtr &action)
Convenience: dereferences the ActionPtr to Action.
Definition: action.h:555
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:40
FormattingHelper< T > format(const T &value, const char *unit, int width=-1, int precision=-1)
Acts as a stream modifier for std::ostream to output an object with an optional suffix string and wit...
Definition: logging.h:217
constexpr int p
Proton.
T uniform(T min, T max)
Definition: random.h:88
T canonical()
Definition: random.h:113
Definition: action.h:24
T pCM(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:79
static constexpr int LInitialConditions
Definition: experiment.h:94
double fixed_target_projectile_v(double s, double ma, double mb)
Definition: kinematics.h:39
double s_from_Ekin(double e_kin, double m_P, double m_T)
Convert E_kin to Mandelstam-s for a fixed-target setup, with a projectile of mass m_P and a kinetic e...
Definition: kinematics.h:239
void update_lattice_accumulating_ensembles(RectangularLattice< T > *lat, const LatticeUpdate update, const DensityType dens_type, const DensityParameters &par, const std::vector< Particles > &ensembles, const bool compute_gradient)
Updates the contents on the lattice when ensembles are used.
Definition: density.h:644
std::string join(const std::vector< std::string > &v, const std::string &delim)
Join strings using delimiter.
std::string to_string(ThermodynamicQuantity quantity)
Convert a ThermodynamicQuantity enum value to its corresponding string.
Definition: stringify.cc:26
double center_of_velocity_v(double s, double ma, double mb)
Definition: kinematics.h:26
bool has_projectile_or_target(const Configuration &config)
Find out whether a configuration has a projectile or a target sub-section.
Definition: nucleus.cc:588
bool is_about_projectile(const Configuration &config)
Find out whether a configuration is about projectile or target.
Definition: nucleus.cc:594
T pCM_from_s(const T s, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:66
static constexpr int LCollider
double s_from_Etot(double e_tot, double m_P, double m_T)
Convert E_tot to Mandelstam-s for a fixed-target setup, with a projectile of mass m_P and a total ene...
Definition: kinematics.h:211
double s_from_plab(double plab, double m_P, double m_T)
Convert p_lab to Mandelstam-s for a fixed-target setup, with a projectile of mass m_P and momentum pl...
Definition: kinematics.h:265
Thrown when either projectile_ or target_ nuclei are empty.
Helper structure for Experiment.
int testparticles
Number of test-particles.
double gaussian_sigma
Width of gaussian Wigner density of particles.
A container to keep track of all ever existed input keys.
Definition: input_keys.h:1116
static const Key< double > modi_collider_projectile_eKin
See user guide description for more information.
Definition: input_keys.h:3429
static const Key< double > modi_collider_target_pLab
See user guide description for more information.
Definition: input_keys.h:3480
static const Key< double > modi_collider_target_eTot
See user guide description for more information.
Definition: input_keys.h:3453
static const Key< double > modi_collider_initialDistance
See user guide description for more information.
Definition: input_keys.h:3305
static const Key< bool > modi_collider_projectile_deformed_automatic
See user guide description for more information.
Definition: input_keys.h:3559
static const Key< double > modi_collider_projectile_deformed_beta3
See user guide description for more information.
Definition: input_keys.h:3597
static const Key< std::string > modi_collider_projectile_custom_fileDirectory
See user guide description for more information.
Definition: input_keys.h:3500
static const Key< double > modi_collider_eKin
See user guide description for more information.
Definition: input_keys.h:3185
static const Key< double > modi_collider_pLab
See user guide description for more information.
Definition: input_keys.h:3218
static const Key< bool > modi_collider_initialConditions_delayInitialElastic
See user guide description for more information.
Definition: input_keys.h:4127
static const Key< FluidizationType > modi_collider_initialConditions_type
See user guide description for more information.
Definition: input_keys.h:3928
static const Key< double > modi_collider_sqrtSNN
See user guide description for more information.
Definition: input_keys.h:3233
static const Key< int > modi_collider_initialConditions_fluidCells
See user guide description for more information.
Definition: input_keys.h:4080
static const Key< std::vector< double > > modi_collider_impact_values
See user guide description for more information.
Definition: input_keys.h:3892
static const Key< double > modi_collider_impact_value
See user guide description for more information.
Definition: input_keys.h:3874
static const Key< double > modi_collider_projectile_deformed_beta4
See user guide description for more information.
Definition: input_keys.h:3617
static const Key< bool > modi_collider_impact_randomReactionPlane
See user guide description for more information.
Definition: input_keys.h:3819
static const Key< double > modi_collider_initialConditions_scaling
See user guide description for more information.
Definition: input_keys.h:3983
static const Key< std::array< double, 2 > > modi_collider_impact_range
See user guide description for more information.
Definition: input_keys.h:3832
static const Key< double > modi_collider_initialConditions_maxTime
See user guide description for more information.
Definition: input_keys.h:4067
static const Key< double > modi_collider_initialConditions_minTime
See user guide description for more information.
Definition: input_keys.h:4053
static const Key< FluidizableProcessesBitSet > modi_collider_initialConditions_fluidProcesses
See user guide description for more information.
Definition: input_keys.h:4109
static const Key< bool > modi_collider_target_deformed_automatic
See user guide description for more information.
Definition: input_keys.h:3564
static const Key< double > modi_collider_initialConditions_eDenThreshold
See user guide description for more information.
Definition: input_keys.h:4037
static const Key< double > modi_collider_target_eKin
See user guide description for more information.
Definition: input_keys.h:3434
static const Key< CalculationFrame > modi_collider_calculationFrame
See user guide description for more information.
Definition: input_keys.h:3257
static const Key< double > modi_collider_impact_max
See user guide description for more information.
Definition: input_keys.h:3806
static const Key< std::vector< double > > modi_collider_impact_yields
See user guide description for more information.
Definition: input_keys.h:3908
static const Key< double > modi_collider_initialConditions_formTimeFraction
See user guide description for more information.
Definition: input_keys.h:4146
static const Key< double > modi_collider_target_deformed_beta2
See user guide description for more information.
Definition: input_keys.h:3582
static const Key< double > modi_collider_target_alphaClustered_sideLength
See user guide description for more information.
Definition: input_keys.h:3705
static const Key< double > modi_collider_target_deformed_beta4
See user guide description for more information.
Definition: input_keys.h:3622
static const Key< double > modi_collider_initialConditions_lowerBound
See user guide description for more information.
Definition: input_keys.h:3943
static const Key< double > modi_collider_eTot
See user guide description for more information.
Definition: input_keys.h:3201
static const Key< std::string > modi_collider_target_custom_fileName
See user guide description for more information.
Definition: input_keys.h:3523
static const Key< double > modi_collider_projectile_deformed_beta2
See user guide description for more information.
Definition: input_keys.h:3577
static const Key< std::string > modi_collider_projectile_custom_fileName
See user guide description for more information.
Definition: input_keys.h:3518
static const Key< double > modi_collider_projectile_deformed_gamma
See user guide description for more information.
Definition: input_keys.h:3637
static const Key< double > modi_collider_projectile_pLab
See user guide description for more information.
Definition: input_keys.h:3475
static const Key< double > modi_collider_target_deformed_gamma
See user guide description for more information.
Definition: input_keys.h:3642
static const Key< Sampling > modi_collider_impact_sample
See user guide description for more information.
Definition: input_keys.h:3861
static const Key< double > modi_collider_initialConditions_rapidityCut
See user guide description for more information.
Definition: input_keys.h:4021
static const Key< double > modi_collider_projectile_eTot
See user guide description for more information.
Definition: input_keys.h:3448
static const Key< std::string > modi_collider_target_custom_fileDirectory
See user guide description for more information.
Definition: input_keys.h:3506
static const Key< FermiMotion > modi_collider_fermiMotion
See user guide description for more information.
Definition: input_keys.h:3289
static const Key< double > modi_collider_initialConditions_properTime
See user guide description for more information.
Definition: input_keys.h:3964
static const Key< double > modi_collider_initialConditions_pTCut
See user guide description for more information.
Definition: input_keys.h:4003
static const Key< bool > modi_collider_target_alphaClustered_automatic
See user guide description for more information.
Definition: input_keys.h:3684
static const Key< double > modi_collider_target_deformed_beta3
See user guide description for more information.
Definition: input_keys.h:3602
static const Section m_c_p_alphaClustered
Subsection for the alpha-clustered projectile in collider modus.
Definition: input_keys.h:105
static const Section m_c_p_custom
Subsection for the custom projectile in collider modus.
Definition: input_keys.h:108
static const Section m_collider
Subsection for the collider modus.
Definition: input_keys.h:95
static const Section m_c_p_deformed
Subsection for the deformed projectile in collider modus.
Definition: input_keys.h:111
static const Section m_c_projectile
Subsection for the projectile in collider modus.
Definition: input_keys.h:102
static const Section m_c_t_deformed
Subsection for the deformed target in collider modus.
Definition: input_keys.h:125
static const Section m_c_target
Subsection for the target in collider modus.
Definition: input_keys.h:117
static const Section m_c_initialConditions
Subsection for the initial conditions in collider modus.
Definition: input_keys.h:99
static const Section m_c_t_custom
Subsection for the custom target in collider modus.
Definition: input_keys.h:122
static const Section m_c_t_alphaClustered
Subsection for the alpha-clustered target in collider modus.
Definition: input_keys.h:119
Thrown when the requested energy is smaller than the masses of two particles.
Definition: modusdefault.h:203