Version: SMASH-1.8
collidermodus.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2020
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/angles.h"
22 #include "smash/configuration.h"
23 #include "smash/customnucleus.h"
24 #include "smash/cxx14compat.h"
26 #include "smash/fourvector.h"
27 #include "smash/interpolation.h"
28 #include "smash/kinematics.h"
29 #include "smash/logging.h"
30 #include "smash/numerics.h"
31 #include "smash/particles.h"
32 #include "smash/pdgcode.h"
33 #include "smash/random.h"
34 
35 namespace smash {
36 static constexpr int LCollider = LogArea::Collider::id;
265  const ExperimentParameters &params) {
266  Configuration modus_cfg = modus_config["Collider"];
267  // Get the reference frame for the collision calculation.
268  if (modus_cfg.has_value({"Calculation_Frame"})) {
269  frame_ = modus_cfg.take({"Calculation_Frame"});
270  }
271 
272  // Determine whether to allow the first collisions within the same nucleus
273  if (modus_cfg.has_value({"Collisions_Within_Nucleus"})) {
274  cll_in_nucleus_ = modus_cfg.take({"Collisions_Within_Nucleus"});
275  }
276  Configuration proj_cfg = modus_cfg["Projectile"];
277  Configuration targ_cfg = modus_cfg["Target"];
278  /* Needed to check if projectile and target in customnucleus are read from
279  * the same input file.*/
280  bool same_file = false;
281  // Set up the projectile nucleus
282  if (proj_cfg.has_value({"Deformed"})) {
283  projectile_ =
284  create_deformed_nucleus(proj_cfg, params.testparticles, "projectile");
285  } else if (proj_cfg.has_value({"Custom"})) {
286  same_file = same_inputfile(proj_cfg, targ_cfg);
287  projectile_ =
288  make_unique<CustomNucleus>(proj_cfg, params.testparticles, same_file);
289  } else {
290  projectile_ = make_unique<Nucleus>(proj_cfg, params.testparticles);
291  }
292  if (projectile_->size() < 1) {
293  throw ColliderEmpty("Input Error: Projectile nucleus is empty.");
294  }
295 
296  // Set up the target nucleus
297  if (targ_cfg.has_value({"Deformed"})) {
298  target_ = create_deformed_nucleus(targ_cfg, params.testparticles, "target");
299  } else if (targ_cfg.has_value({"Custom"})) {
300  target_ =
301  make_unique<CustomNucleus>(targ_cfg, params.testparticles, same_file);
302  } else {
303  target_ = make_unique<Nucleus>(targ_cfg, params.testparticles);
304  }
305  if (target_->size() < 1) {
306  throw ColliderEmpty("Input Error: Target nucleus is empty.");
307  }
308 
309  // Get the Fermi-Motion input (off, on, frozen)
310  if (modus_cfg.has_value({"Fermi_Motion"})) {
311  // We only read the value, because it is still required by the experiment
312  // class to make sure we don't use frozen Fermi momenta with potentials.
313  fermi_motion_ = modus_cfg.read({"Fermi_Motion"});
314  }
315 
316  // Get the total nucleus-nucleus collision energy. Since there is
317  // no meaningful choice for a default energy, we require the user to
318  // give one (and only one) energy input from the available options.
319  int energy_input = 0;
320  const double mass_projec = projectile_->mass();
321  const double mass_target = target_->mass();
322  // average mass of a particle in that nucleus
323  const double mass_a =
324  projectile_->mass() / projectile_->number_of_particles();
325  const double mass_b = target_->mass() / target_->number_of_particles();
326  // Option 1: Center of mass energy.
327  if (modus_cfg.has_value({"Sqrtsnn"})) {
328  sqrt_s_NN_ = modus_cfg.take({"Sqrtsnn"});
329  // Check that input satisfies the lower bound (everything at rest).
330  if (sqrt_s_NN_ <= mass_a + mass_b) {
332  "Input Error: sqrt(s_NN) is not larger than masses:\n" +
333  std::to_string(sqrt_s_NN_) + " GeV <= " + std::to_string(mass_a) +
334  " GeV + " + std::to_string(mass_b) + " GeV.");
335  }
336  // Set the total nucleus-nucleus collision energy.
337  total_s_ = (sqrt_s_NN_ * sqrt_s_NN_ - mass_a * mass_a - mass_b * mass_b) *
338  mass_projec * mass_target / (mass_a * mass_b) +
339  mass_projec * mass_projec + mass_target * mass_target;
340  energy_input++;
341  }
342  /* Option 2: Kinetic energy per nucleon of the projectile nucleus
343  * (target at rest). */
344  if (modus_cfg.has_value({"E_Kin"})) {
345  const double e_kin = modus_cfg.take({"E_Kin"});
346  if (e_kin < 0) {
348  "Input Error: "
349  "E_Kin must be nonnegative.");
350  }
351  // Set the total nucleus-nucleus collision energy.
352  total_s_ = s_from_Ekin(e_kin * projectile_->number_of_particles(),
353  mass_projec, mass_target);
354  sqrt_s_NN_ = std::sqrt(s_from_Ekin(e_kin, mass_a, mass_b));
355  energy_input++;
356  }
357  // Option 3: Momentum of the projectile nucleus (target at rest).
358  if (modus_cfg.has_value({"P_Lab"})) {
359  const double p_lab = modus_cfg.take({"P_Lab"});
360  if (p_lab < 0) {
362  "Input Error: "
363  "P_Lab must be nonnegative.");
364  }
365  // Set the total nucleus-nucleus collision energy.
366  total_s_ = s_from_plab(p_lab * projectile_->number_of_particles(),
367  mass_projec, mass_target);
368  sqrt_s_NN_ = std::sqrt(s_from_plab(p_lab, mass_a, mass_b));
369  energy_input++;
370  }
371  if (energy_input == 0) {
372  throw std::domain_error(
373  "Input Error: Non-existent collision energy. "
374  "Please provide one of Sqrtsnn/E_Kin/P_Lab.");
375  }
376  if (energy_input > 1) {
377  throw std::domain_error(
378  "Input Error: Redundant collision energy. "
379  "Please provide only one of Sqrtsnn/E_Kin/P_Lab.");
380  }
381 
382  /* Impact parameter setting: Either "Value", "Range", "Max" or "Sample".
383  * Unspecified means 0 impact parameter.*/
384  if (modus_cfg.has_value({"Impact", "Value"})) {
385  impact_ = modus_cfg.take({"Impact", "Value"});
386  imp_min_ = impact_;
387  imp_max_ = impact_;
388  } else {
389  // If impact is not supplied by value, inspect sampling parameters:
390  if (modus_cfg.has_value({"Impact", "Sample"})) {
391  sampling_ = modus_cfg.take({"Impact", "Sample"});
392  if (sampling_ == Sampling::Custom) {
393  if (!(modus_cfg.has_value({"Impact", "Values"}) ||
394  modus_cfg.has_value({"Impact", "Yields"}))) {
395  throw std::domain_error(
396  "Input Error: Need impact parameter spectrum for custom "
397  "sampling. "
398  "Please provide Values and Yields.");
399  }
400  const std::vector<double> impacts =
401  modus_cfg.take({"Impact", "Values"});
402  const std::vector<double> yields = modus_cfg.take({"Impact", "Yields"});
403  if (impacts.size() != yields.size()) {
404  throw std::domain_error(
405  "Input Error: Need as many impact parameter values as yields. "
406  "Please make sure that Values and Yields have the same length.");
407  }
408  impact_interpolation_ = make_unique<InterpolateDataLinear<double>>(
409  InterpolateDataLinear<double>(impacts, yields));
410 
411  const auto imp_minmax =
412  std::minmax_element(impacts.begin(), impacts.end());
413  imp_min_ = *imp_minmax.first;
414  imp_max_ = *imp_minmax.second;
415  yield_max_ = *std::max_element(yields.begin(), yields.end());
416  }
417  }
418  if (modus_cfg.has_value({"Impact", "Range"})) {
419  const std::array<double, 2> range = modus_cfg.take({"Impact", "Range"});
420  imp_min_ = range[0];
421  imp_max_ = range[1];
422  }
423  if (modus_cfg.has_value({"Impact", "Max"})) {
424  imp_min_ = 0.0;
425  imp_max_ = modus_cfg.take({"Impact", "Max"});
426  }
427  }
429  // whether the direction of separation should be ramdomly smapled
431  modus_cfg.take({"Impact", "Random_Reaction_Plane"}, false);
432  // Look for user-defined initial separation between nuclei.
433  if (modus_cfg.has_value({"Initial_Distance"})) {
434  initial_z_displacement_ = modus_cfg.take({"Initial_Distance"});
435  // the displacement is half the distance (both nuclei are shifted
436  // initial_z_displacement_ away from origin)
438  }
439 }
440 
441 std::ostream &operator<<(std::ostream &out, const ColliderModus &m) {
442  return out << "-- Collider Modus:\n"
443  << "sqrt(S) (nucleus-nucleus) = "
444  << format(std::sqrt(m.total_s_), "GeV\n")
445  << "sqrt(S) (nucleon-nucleon) = " << format(m.sqrt_s_NN_, "GeV\n")
446  << "Projectile:\n"
447  << *m.projectile_ << "\nTarget:\n"
448  << *m.target_;
449 }
450 
451 std::unique_ptr<DeformedNucleus> ColliderModus::create_deformed_nucleus(
452  Configuration &nucleus_cfg, int ntest, const std::string &nucleus_type) {
453  bool auto_deform = nucleus_cfg.take({"Deformed", "Automatic"});
454  bool is_beta2 = nucleus_cfg.has_value({"Deformed", "Beta_2"}) ? true : false;
455  bool is_beta4 = nucleus_cfg.has_value({"Deformed", "Beta_4"}) ? true : false;
456  std::unique_ptr<DeformedNucleus> nucleus;
457 
458  if ((auto_deform && (!is_beta2 && !is_beta4)) ||
459  (!auto_deform && (is_beta2 && is_beta4))) {
460  nucleus = make_unique<DeformedNucleus>(nucleus_cfg, ntest, auto_deform);
461  return nucleus;
462  } else {
463  throw std::domain_error("Deformation of " + nucleus_type +
464  " nucleus not configured "
465  "properly, please check whether all necessary "
466  "parameters are set.");
467  }
468 }
469 
471  const ExperimentParameters &) {
472  sample_impact();
473 
474  logg[LCollider].info() << "Impact parameter = " << format(impact_, "fm");
475  // Populate the nuclei with appropriately distributed nucleons.
476  // If deformed, this includes rotating the nucleus.
477  projectile_->arrange_nucleons();
478  target_->arrange_nucleons();
479 
480  // Use the total mandelstam variable to get the frame-dependent velocity for
481  // each nucleus. Position a is projectile, position b is target.
482  double v_a, v_b;
483  std::tie(v_a, v_b) =
484  get_velocities(total_s_, projectile_->mass(), target_->mass());
485 
486  // If velocities are larger or equal to 1, throw an exception.
487  if (v_a >= 1.0 || v_b >= 1.0) {
488  throw std::domain_error(
489  "Found velocity equal to or larger than 1 in "
490  "ColliderModus::initial_conditions.\nConsider using "
491  "the center of velocity reference frame.");
492  }
493 
494  // Calculate the beam velocity of the projectile and the target, which will be
495  // used to calculate the beam momenta in experiment.cc
497  velocity_projectile_ = v_a;
498  velocity_target_ = v_b;
499  }
500 
501  // Generate Fermi momenta if necessary
504  // Frozen: Fermi momenta will be ignored during the propagation to
505  // avoid that the nuclei will fly apart.
506  projectile_->generate_fermi_momenta();
507  target_->generate_fermi_momenta();
509  logg[LCollider].info() << "Fermi motion is ON.";
510  } else {
511  logg[LCollider].info() << "FROZEN Fermi motion is on.";
512  }
513  } else if (fermi_motion_ == FermiMotion::Off) {
514  // No Fermi-momenta are generated in this case
515  logg[LCollider].info() << "Fermi motion is OFF.";
516  } else {
517  throw std::domain_error("Invalid Fermi_Motion input.");
518  }
519 
520  // Boost the nuclei to the appropriate velocity.
521  projectile_->boost(v_a);
522  target_->boost(v_b);
523 
524  // Shift the nuclei into starting positions. Contracted spheres with
525  // nuclear radii should touch exactly at t=0. Modus starts at negative
526  // time corresponding to additional initial displacement.
527  const double d_a = std::max(0., projectile_->get_diffusiveness());
528  const double d_b = std::max(0., target_->get_diffusiveness());
529  const double r_a = projectile_->get_nuclear_radius();
530  const double r_b = target_->get_nuclear_radius();
531  const double dz = initial_z_displacement_;
532 
533  const double simulation_time = -dz / std::abs(v_a);
534  const double proj_z = -dz - std::sqrt(1.0 - v_a * v_a) * (r_a + d_a);
535  const double targ_z =
536  +dz * std::abs(v_b / v_a) + std::sqrt(1.0 - v_b * v_b) * (r_b + d_b);
537  // rotation angle in the transverse plane
538  const double phi =
539  random_reaction_plane_ ? random::uniform(0.0, 2.0 * M_PI) : 0.0;
540 
541  projectile_->shift(proj_z, +impact_ / 2.0, simulation_time);
542  target_->shift(targ_z, -impact_ / 2.0, simulation_time);
543 
544  // Put the particles in the nuclei into code particles.
545  projectile_->copy_particles(particles);
546  target_->copy_particles(particles);
547  rotate_reaction_plane(phi, particles);
548  return simulation_time;
549 }
550 
551 void ColliderModus::rotate_reaction_plane(double phi, Particles *particles) {
552  for (ParticleData &p : *particles) {
553  ThreeVector pos = p.position().threevec();
554  ThreeVector mom = p.momentum().threevec();
555  pos.rotate_around_z(phi);
556  mom.rotate_around_z(phi);
557  p.set_3position(pos);
558  p.set_3momentum(mom);
559  }
560 }
561 
563  switch (sampling_) {
564  case Sampling::Quadratic: {
565  // quadratic sampling: Note that for bmin > bmax, this still yields
566  // the correct distribution (however canonical() = 0 is then the
567  // upper end, not the lower).
568  impact_ = std::sqrt(imp_min_ * imp_min_ +
571  } break;
572  case Sampling::Custom: {
573  // rejection sampling based on given distribution
574  assert(impact_interpolation_ != nullptr);
575  double probability_random = 1;
576  double probability = 0;
577  double b;
578  while (probability_random > probability) {
580  probability = (*impact_interpolation_)(b) / yield_max_;
581  assert(probability < 1.);
582  probability_random = random::uniform(0., 1.);
583  }
584  impact_ = b;
585  } break;
586  case Sampling::Uniform: {
587  // linear sampling. Still, min > max works fine.
589  }
590  }
591 }
592 
593 std::pair<double, double> ColliderModus::get_velocities(double s, double m_a,
594  double m_b) {
595  double v_a = 0.0;
596  double v_b = 0.0;
597  // Frame dependent calculations of velocities. Assume v_a >= 0, v_b <= 0.
598  switch (frame_) {
600  v_a = center_of_velocity_v(s, m_a, m_b);
601  v_b = -v_a;
602  break;
604  // Compute center of mass momentum.
605  double pCM = pCM_from_s(s, m_a, m_b);
606  v_a = pCM / std::sqrt(m_a * m_a + pCM * pCM);
607  v_b = -pCM / std::sqrt(m_b * m_b + pCM * pCM);
608  } break;
610  v_a = fixed_target_projectile_v(s, m_a, m_b);
611  break;
612  default:
613  throw std::domain_error(
614  "Invalid reference frame in "
615  "ColliderModus::get_velocities.");
616  }
617  return std::make_pair(v_a, v_b);
618 }
619 
620 std::string ColliderModus::custom_file_path(const std::string &file_directory,
621  const std::string &file_name) {
622  // make sure that path is correct even if the / at the end is missing
623  if (file_directory.back() == '/') {
624  return file_directory + file_name;
625  } else {
626  return file_directory + '/' + file_name;
627  }
628 }
629 
631  Configuration &targ_config) {
632  /* Check if both nuclei are custom
633  * Only check target as function is called after if statement for projectile.
634  */
635  if (!targ_config.has_value({"Custom"})) {
636  return false;
637  }
638  std::string projectile_file_directory =
639  proj_config.read({"Custom", "File_Directory"});
640  std::string target_file_directory =
641  targ_config.read({"Custom", "File_Directory"});
642  std::string projectile_file_name = proj_config.read({"Custom", "File_Name"});
643  std::string target_file_name = targ_config.read({"Custom", "File_Name"});
644  // Check if files are the same for projectile and target
645  std::string proj_path =
646  custom_file_path(projectile_file_directory, projectile_file_name);
647  std::string targ_path =
648  custom_file_path(target_file_directory, target_file_name);
649  if (proj_path == targ_path) {
650  return true;
651  } else {
652  return false;
653  }
654 }
655 
656 } // namespace smash
smash::ColliderModus::impact_interpolation_
std::unique_ptr< InterpolateDataLinear< double > > impact_interpolation_
Pointer to the impact parameter interpolation.
Definition: collidermodus.h:202
smash::ColliderModus::initial_z_displacement_
double initial_z_displacement_
Initial z-displacement of nuclei.
Definition: collidermodus.h:230
smash
Definition: action.h:24
smash::ColliderModus::imp_min_
double imp_min_
Minimum value of impact parameter.
Definition: collidermodus.h:196
smash::ColliderModus::custom_file_path
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...
Definition: collidermodus.cc:620
customnucleus.h
Sampling::Quadratic
Sample from areal / quadratic distribution.
CalculationFrame::CenterOfVelocity
smash::ColliderModus::cll_in_nucleus_
bool cll_in_nucleus_
An option to accept first collisions within the same nucleus.
Definition: collidermodus.h:242
smash::ColliderModus::fermi_motion_
FermiMotion fermi_motion_
An option to include Fermi motion ("off", "on", "frozen")
Definition: collidermodus.h:238
smash::ParticleData
Definition: particledata.h:52
smash::ColliderModus::random_reaction_plane_
bool random_reaction_plane_
Whether the reaction plane should be randomized.
Definition: collidermodus.h:192
interpolation.h
smash::Configuration::read
Value read(std::initializer_list< const char * > keys) const
Additional interface for SMASH to read configuration values without removing them.
Definition: configuration.cc:158
smash::ColliderModus::sampling_
Sampling sampling_
Method used for sampling of impact parameter.
Definition: collidermodus.h:194
smash::ColliderModus::sqrt_s_NN_
double sqrt_s_NN_
Center-of-mass energy of a nucleon-nucleon collision.
Definition: collidermodus.h:160
smash::s_from_plab
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:224
cxx14compat.h
smash::ColliderModus::target_
std::unique_ptr< Nucleus > target_
Target.
Definition: collidermodus.h:148
smash::fixed_target_projectile_v
double fixed_target_projectile_v(double s, double ma, double mb)
Definition: kinematics.h:39
FermiMotion::Off
Don't use fermi motion.
smash::ColliderModus::same_inputfile
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 ...
Definition: collidermodus.cc:630
smash::operator<<
std::ostream & operator<<(std::ostream &out, const ActionPtr &action)
Definition: action.h:463
smash::ColliderModus::sample_impact
void sample_impact()
Sample impact parameter.
Definition: collidermodus.cc:562
experimentparameters.h
smash::s_from_Ekin
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:211
smash::Configuration::has_value
bool has_value(std::initializer_list< const char * > keys) const
Returns whether there is a non-empty value behind the requested keys.
Definition: configuration.cc:181
smash::ColliderModus::initial_conditions
double initial_conditions(Particles *particles, const ExperimentParameters &parameters)
Generates initial state of the particles in the system.
Definition: collidermodus.cc:470
fourvector.h
smash::ThreeVector::rotate_around_z
void rotate_around_z(double theta)
Rotate the vector around the z axis by the given angle theta.
Definition: threevector.h:308
FermiMotion::Frozen
Use fermi motion without potentials.
smash::logg
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
Sampling::Custom
Sample from custom, user-defined distribution.
smash::ColliderModus::velocity_projectile_
double velocity_projectile_
Beam velocity of the projectile.
Definition: collidermodus.h:246
smash::pCM
T pCM(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:79
random.h
smash::center_of_velocity_v
double center_of_velocity_v(double s, double ma, double mb)
Definition: kinematics.h:26
angles.h
smash::Configuration
Interface to the SMASH configuration files.
Definition: configuration.h:464
smash::ColliderModus::imp_max_
double imp_max_
Maximum value of impact parameter.
Definition: collidermodus.h:198
smash::ThreeVector
Definition: threevector.h:31
smash::format
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:304
smash::ColliderModus::total_s_
double total_s_
Center-of-mass energy squared of the nucleus-nucleus collision.
Definition: collidermodus.h:154
smash::ColliderModus::frame_
CalculationFrame frame_
Reference frame for the system, as specified from config.
Definition: collidermodus.h:234
smash::LCollider
static constexpr int LCollider
Definition: collidermodus.cc:36
collidermodus.h
smash::InterpolateDataLinear< double >
CalculationFrame::FixedTarget
smash::ColliderModus::yield_max_
double yield_max_
Maximum value of yield. Needed for custom impact parameter sampling.
Definition: collidermodus.h:200
particles.h
kinematics.h
smash::Particles
Definition: particles.h:33
smash::ColliderModus::impact_
double impact_
Impact parameter.
Definition: collidermodus.h:190
smash::ColliderModus
Definition: collidermodus.h:42
smash::ColliderModus::ColliderEmpty
Definition: collidermodus.h:129
numerics.h
Sampling::Uniform
Sample from uniform distribution.
pdgcode.h
FermiMotion::On
Use fermi motion in combination with potentials.
smash::ColliderModus::projectile_
std::unique_ptr< Nucleus > projectile_
Projectile.
Definition: collidermodus.h:140
logging.h
configuration.h
smash::ColliderModus::velocity_target_
double velocity_target_
Beam velocity of the target.
Definition: collidermodus.h:250
smash::Configuration::take
Value take(std::initializer_list< const char * > keys)
The default interface for SMASH to read configuration values.
Definition: configuration.cc:140
smash::ExperimentParameters
Helper structure for Experiment.
Definition: experimentparameters.h:23
smash::pdg::p
constexpr int p
Proton.
Definition: pdgcode_constants.h:28
smash::random::uniform
T uniform(T min, T max)
Definition: random.h:88
CalculationFrame::CenterOfMass
smash::ColliderModus::create_deformed_nucleus
static std::unique_ptr< DeformedNucleus > create_deformed_nucleus(Configuration &nucleus_cfg, const int ntest, const std::string &nucleus_type)
Configure Deformed Nucleus.
Definition: collidermodus.cc:451
smash::ExperimentParameters::testparticles
int testparticles
Number of test particle.
Definition: experimentparameters.h:31
smash::ColliderModus::rotate_reaction_plane
void rotate_reaction_plane(double phi, Particles *particles)
Rotate the reaction plane about the angle phi.
Definition: collidermodus.cc:551
smash::ColliderModus::get_velocities
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.
Definition: collidermodus.cc:593
smash::random::canonical
T canonical()
Definition: random.h:113
smash::ColliderModus::ColliderModus
ColliderModus(Configuration modus_config, const ExperimentParameters &parameters)
Constructor.
Definition: collidermodus.cc:264
smash::ModusDefault::InvalidEnergy
Definition: modusdefault.h:191
smash::pCM_from_s
T pCM_from_s(const T s, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:66