29 static constexpr
int LCollider = LogArea::Collider::id;
36 if (modus_cfg.
has_value({
"Calculation_Frame"})) {
37 frame_ = modus_cfg.
take({
"Calculation_Frame"});
44 bool same_file =
false;
49 }
else if (proj_cfg.
has_value({
"Custom"})) {
57 throw ColliderEmpty(
"Input Error: Projectile nucleus is empty.");
64 }
else if (targ_cfg.
has_value({
"Custom"})) {
76 if (modus_cfg.
has_value({
"Fermi_Motion"})) {
85 const double mass_target =
target_->mass();
89 const double mass_b =
target_->mass() /
target_->number_of_particles();
96 "Input Error: sqrt(s_NN) is not larger than masses:\n" +
97 std::to_string(
sqrt_s_NN_) +
" GeV <= " + std::to_string(mass_a) +
98 " GeV + " + std::to_string(mass_b) +
" GeV.");
102 mass_projec * mass_target / (mass_a * mass_b) +
103 mass_projec * mass_projec + mass_target * mass_target;
109 const double e_tot = modus_cfg.
take({
"E_Tot"});
113 "E_Tot must be nonnegative.");
117 mass_projec, mass_target);
124 const double e_kin = modus_cfg.
take({
"E_Kin"});
128 "E_Kin must be nonnegative.");
132 mass_projec, mass_target);
138 const double p_lab = modus_cfg.
take({
"P_Lab"});
142 "P_Lab must be nonnegative.");
146 mass_projec, mass_target);
152 const double e_tot_p = proj_cfg.
take({
"E_Tot"});
153 const double e_tot_t = targ_cfg.
take({
"E_Tot"});
154 if (e_tot_p < 0 || e_tot_t < 0) {
157 "E_Tot must be nonnegative.");
160 e_tot_t *
target_->number_of_particles(),
161 mass_projec, mass_target);
167 const double e_kin_p = proj_cfg.
take({
"E_Kin"});
168 const double e_kin_t = targ_cfg.
take({
"E_Kin"});
169 if (e_kin_p < 0 || e_kin_t < 0) {
172 "E_Kin must be nonnegative.");
175 e_kin_t *
target_->number_of_particles(),
176 mass_projec, mass_target);
182 const double p_lab_p = proj_cfg.
take({
"P_Lab"});
183 const double p_lab_t = targ_cfg.
take({
"P_Lab"});
184 if (p_lab_p < 0 || p_lab_t < 0) {
187 "P_Lab must be nonnegative.");
190 p_lab_t *
target_->number_of_particles(),
191 mass_projec, mass_target);
195 if (energy_input == 0) {
196 throw std::domain_error(
197 "Input Error: Non-existent collision energy. "
198 "Please provide one of Sqrtsnn/E_Kin/P_Lab.");
200 if (energy_input > 1) {
201 throw std::domain_error(
202 "Input Error: Redundant collision energy. "
203 "Please provide only one of Sqrtsnn/E_Kin/P_Lab.");
208 if (modus_cfg.
has_value({
"Impact",
"Value"})) {
214 if (modus_cfg.
has_value({
"Impact",
"Sample"})) {
217 if (!(modus_cfg.
has_value({
"Impact",
"Values"}) ||
218 modus_cfg.
has_value({
"Impact",
"Yields"}))) {
219 throw std::domain_error(
220 "Input Error: Need impact parameter spectrum for custom "
222 "Please provide Values and Yields.");
224 const std::vector<double> impacts =
225 modus_cfg.
take({
"Impact",
"Values"});
226 const std::vector<double> yields = modus_cfg.
take({
"Impact",
"Yields"});
227 if (impacts.size() != yields.size()) {
228 throw std::domain_error(
229 "Input Error: Need as many impact parameter values as yields. "
230 "Please make sure that Values and Yields have the same length.");
235 const auto imp_minmax =
236 std::minmax_element(impacts.begin(), impacts.end());
239 yield_max_ = *std::max_element(yields.begin(), yields.end());
242 if (modus_cfg.
has_value({
"Impact",
"Range"})) {
243 const std::array<double, 2> range = modus_cfg.
take({
"Impact",
"Range"});
247 if (modus_cfg.
has_value({
"Impact",
"Max"})) {
255 modus_cfg.
take({
"Impact",
"Random_Reaction_Plane"},
false);
257 if (modus_cfg.
has_value({
"Initial_Distance"})) {
274 return out <<
"-- Collider Modus:\n"
275 <<
"sqrt(S) (nucleus-nucleus) = "
284 Configuration &nucleus_cfg,
int ntest,
const std::string &nucleus_type) {
285 bool automatic_deformation = nucleus_cfg.
take({
"Deformed",
"Automatic"});
286 bool was_any_beta_given = nucleus_cfg.
has_value({
"Deformed",
"Beta_2"}) ||
287 nucleus_cfg.
has_value({
"Deformed",
"Beta_3"}) ||
288 nucleus_cfg.
has_value({
"Deformed",
"Beta_4"});
289 bool was_any_deformation_parameter_given =
290 was_any_beta_given || nucleus_cfg.
has_value({
"Deformed",
"Gamma"});
291 bool was_gamma_given_without_beta_2 =
292 nucleus_cfg.
has_value({
"Deformed",
"Gamma"}) &&
293 !nucleus_cfg.
has_value({
"Deformed",
"Beta_2"});
295 if (automatic_deformation && was_any_deformation_parameter_given) {
296 throw std::domain_error(
297 "Automatic deformation of " + nucleus_type +
298 " nucleus requested, but deformation parameter(s) were provided as"
299 " well. Please, check the 'Deformed' section in your input file.");
300 }
else if (!automatic_deformation && !was_any_beta_given) {
301 throw std::domain_error(
302 "Manual deformation of " + nucleus_type +
303 " nucleus requested, but no deformation beta parameter was provided."
304 " Please, check the 'Deformed' section in your input file.");
305 }
else if (!automatic_deformation && was_gamma_given_without_beta_2) {
306 throw std::domain_error(
307 "Manual deformation of " + nucleus_type +
308 " nucleus requested, but 'Gamma' parameter was provided without "
309 "providing a value of 'Beta_2' having hence no deformation effect. "
310 "Please, check the 'Deformed' section in your input file.");
312 return std::make_unique<DeformedNucleus>(nucleus_cfg, ntest,
313 automatic_deformation);
331 if (v_a >= 1.0 || v_b >= 1.0) {
332 throw std::domain_error(
333 "Found velocity equal to or larger than 1 in "
334 "ColliderModus::initial_conditions.\nConsider using "
335 "the center of velocity reference frame.");
351 target_->generate_fermi_momenta();
354 throw std::domain_error(
"Invalid Fermi_Motion input.");
364 const double d_a = std::max(0.,
projectile_->get_diffusiveness());
365 const double d_b = std::max(0.,
target_->get_diffusiveness());
366 const double r_a =
projectile_->get_nuclear_radius();
367 const double r_b =
target_->get_nuclear_radius();
370 const double simulation_time = -dz / std::abs(v_a);
371 const double proj_z = -dz - std::sqrt(1.0 - v_a * v_a) * (r_a + d_a);
372 const double targ_z =
373 +dz * std::abs(v_b / v_a) + std::sqrt(1.0 - v_b * v_b) * (r_b + d_b);
383 target_->copy_particles(particles);
385 return simulation_time;
394 p.set_3position(pos);
395 p.set_3momentum(mom);
412 double probability_random = 1;
413 double probability = 0;
415 while (probability_random > probability) {
417 probability = (*impact_interpolation_)(b) /
yield_max_;
418 assert(probability < 1.);
443 v_a =
pCM / std::sqrt(m_a * m_a +
pCM *
pCM);
444 v_b = -
pCM / std::sqrt(m_b * m_b +
pCM *
pCM);
450 throw std::domain_error(
451 "Invalid reference frame in "
452 "ColliderModus::get_velocities.");
454 return std::make_pair(v_a, v_b);
458 const std::string &file_name) {
460 if (file_directory.back() ==
'/') {
461 return file_directory + file_name;
463 return file_directory +
'/' + file_name;
472 if (!targ_config.
has_value({
"Custom"})) {
475 std::string projectile_file_directory =
476 proj_config.
read({
"Custom",
"File_Directory"});
477 std::string target_file_directory =
478 targ_config.
read({
"Custom",
"File_Directory"});
479 std::string projectile_file_name = proj_config.
read({
"Custom",
"File_Name"});
480 std::string target_file_name = targ_config.
read({
"Custom",
"File_Name"});
482 std::string proj_path =
484 std::string targ_path =
486 if (proj_path == targ_path) {
ColliderModus: Provides a modus for colliding nuclei.
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.
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")
double velocity_projectile_
Beam velocity of the projectile.
Sampling sampling_
Method used for sampling of impact parameter.
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 ¶meters)
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 ¶meters)
Generates initial state of the particles in the system.
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 ...
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.
double imp_max_
Maximum value of impact parameter.
Interface to the SMASH configuration files.
bool has_value(std::initializer_list< const char * > keys) const
Return whether there is a non-empty value behind the requested keys.
Configuration extract_sub_configuration(std::initializer_list< const char * > keys, Configuration::GetEmpty empty_if_not_existing=Configuration::GetEmpty::No)
Create a new configuration from a then-removed section of the present object.
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.
Represent a piecewise linear interpolation.
ParticleData contains the dynamic information of a certain particle.
The Particles class abstracts the storage and manipulation of particles.
The ThreeVector class represents a physical three-vector with the components .
void rotate_around_z(double theta)
Rotate the vector around the z axis by the given angle theta.
@ On
Use fermi motion in combination with potentials.
@ Frozen
Use fermi motion without potentials.
@ Off
Don't use fermi motion.
@ 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.
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
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...
T pCM(const T sqrts, const T mass_a, const T mass_b) noexcept
double fixed_target_projectile_v(double s, double ma, double mb)
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...
double center_of_velocity_v(double s, double ma, double mb)
T pCM_from_s(const T s, const T mass_a, const T mass_b) noexcept
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...
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...
Thrown when either projectile_ or target_ nuclei are empty.
Helper structure for Experiment.
int testparticles
Number of test-particles.
Thrown when the requested energy is smaller than the masses of two particles.