Version: SMASH-3.4
smash.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2012-2024,2026
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 #include <getopt.h>
10 
11 #include <filesystem>
12 #include <set>
13 #include <sstream>
14 #include <vector>
15 
16 #include "smash/decaymodes.h"
17 #include "smash/experiment.h"
18 #include "smash/filelock.h"
19 #include "smash/random.h"
22 #include "smash/sha256.h"
23 #include "smash/stringfunctions.h"
24 /* build dependent variables */
25 #include "smash/config.h"
26 #include "smash/library.h"
27 
28 namespace smash {
29 
30 /*!\Userguide
31  * \page doxypage_software_execution
32  *
33  * SMASH can be run simply by executing the binary without any options (i.e.
34  * there are no required arguments). It does require an input file, though
35  * (see \ref doxypage_input_configuration).
36  * Per default, the input file is expected in the current working directory
37  * with the name '`config.yaml`'.
38  *
39  * The following options are supported:
40  *
41  * <table>
42  * <tr><th>Short&nbsp;Variant <th>Long&nbsp;Variant <th>Documentation
43  * <tr><td>`-h` <td>`--help`
44  * <td>Prints usage information and quits the program.
45  * <tr><td>`-v` <td>`--version`
46  * <td>Prints the version of SMASH and quits the program.
47  * <tr><td>`-i <file>` <td>`--inputfile <file>`
48  * <td>Overrides the location of the default '`config.yaml`' input file. The
49  * input settings will be read from the specified file instead.
50  * <tr><td>`-o <dir>` <td>`--output <dir>`
51  * <td>Sets the output directory. The default output directory is
52  * `./data/<runid>`, where `<rundid>` is an automatically incrementing
53  * integer. Note that this might cause races if several instances of SMASH
54  * run in parallel. In that case, make sure to specify a different output
55  * directory for every instance of SMASH.
56  * <tr><td>`-f` <td>`--force`
57  * <td>Forces overwriting files in the output directory. By default, if an
58  * output directory is specified with `-o`, the directory must be empty.
59  * With `-f` this check is skipped.
60  * <tr><td>`-d <file>` <td>`--decaymodes <file>`
61  * <td>The default decay modes are compiled in. With this argument you can
62  * override the decay modes to the exact set defined in the file. Multiple
63  * `-d` arguments are not supported.
64  * <tr><td>`-p <file>` <td>`--particles <file>`
65  * <td>The default particle data is compiled in. With this argument you can
66  * override the particles to the exact set defined in the file. Multiple
67  * `-p` arguments are not supported.
68  * <tr><td>`-q` <td>`--quiet`
69  * <td>Quiets the disclaimer for scenarios where no printout is wanted. To
70  * suppress the entire SMASH printout, logging needs to be disabled in the
71  * configuration file.
72  * <tr><td>`-n` <td>`--no-cache`
73  * <td>Disables caching integrals in form of tabulations on the disk. Usually,
74  * in order for future SMASH runs to save computational time, the
75  * tabulations folder is created next to the output directory and contains
76  * the results of integrals stored in many different files. Using this
77  * option, such a folder is not created. Note: this option cannot be used
78  * together with `-t`.
79  * <tr><td>`-t <dir>` <td>`--tabulations <dir>`
80  * <td>Overrides the path where tabulations are read from and written to. If the
81  * input files for particles/decaymodes or SMASH version change, the
82  * tabulations are automatically recalculated in the specified folder. By
83  * default, the tabulations folder is created next to the output directory.
84  * This is useful to make several runs share the same tabulations folder,
85  * even if these are in different output directories &ndash; as may be the
86  * case in parameter scans, for example &ndash; avoiding creating several
87  * sets of possibly identical files. Note: this option cannot be used
88  * together with `-n`.
89  * <tr><td>`-c <%YAML string>` <td>`--config <%YAMLstring>`
90  * <td>The string argument to `-c` contains %YAML markup to override
91  * input key values of the input file (`-i`) and/or supply additional keys.
92  * Multiple `-c` arguments are supported. Later specified values of the same
93  * key will override preceding settings. This can be a handy way to test
94  * different scenarios from a script.
95  * <tr><td>`-m <modus>` <td>`--modus <modus>`
96  * <td>This is a shortcut for <tt>-c 'General: { Modus: <modus> }'</tt>.
97  * Note that `-m` always overrides `-c`.
98  * <tr><td>`-e <time>` <td>`--endtime <time>`
99  * <td>This is a shortcut for <tt>-c 'General: { End_Time: <time> }'</tt>.
100  * Note that `-e` always overrides `-c`.
101  * <tr><td>`-l` <td>`--list-2-to-n`
102  * <td>Prints the list of all possible 2 &rarr; n reactions (n > 1). Note that
103  * resonance decays and formations are NOT dumped. Every particle
104  * available in SMASH is collided against every and reactions with
105  * non-zero cross-section are dumped. Both colliding particles are
106  * assigned momenta from 0.1 to 10 GeV in the opposite directions to
107  * scan the possible \f$\sqrt{s}\f$.
108  * <tr><td>`-r <pdg>` <td>`--resonance <pdg>`
109  * <td>Prints the width(m) and m * spectral function(m^2) versus resonance
110  * mass m.
111  * <tr><td>`-s <pdg1>,<pdg2>[,mass1,mass2[,plab1,...]]`
112  * <td>`--cross-sections <pdg1>,<pdg2>[,mass1,mass2[,plab1,...]]`
113  * <td>Prints all the partial cross-sections of `<pdg1> + <pdg2>` with
114  * masses `mass1` and `mass2`. Masses are optional, default values are
115  * pole masses. Optionally, the lab frame momenta (fixed target) in GeV
116  * can be specified. Multiple momenta can be provided. The values of `plab`
117  * depend on the order of the particles. The first particle is considered
118  * to be the projectile, the second one the target. These cross sections are
119  * not rescaled to match the parametrized total.
120  * <tr><td>`-S <pdg1>,<pdg2>[,mass1,mass2[,plab1,...]]`
121  * <td>`--cross-sections-fs <pdg1>,<pdg2>[,mass1,mass2[,plab1,...]]`
122  * <td>Prints an approximation of the final-state cross-sections of `<pdg1> +
123  * <pdg2>` with masses `mass1` and `mass2`. Masses are optional, default
124  * values are pole masses. Optionally, the lab frame momenta (fixed target)
125  * in GeV can be specified. Multiple momenta can be provided. The values of
126  * `plab` depend on the order of the particles. The first is considered to
127  * be the projectile, the second one the target. After the initial
128  * collision, only decays are considered and all resonances are assumed to
129  * have their pole mass. This may yield different results than a full
130  * simulation with SMASH, where the resonances masses are sampled from the
131  * spectral function. Typically, this results in errors of less than 1 mb in
132  * the worst case. Also, contributions from strings are not considered, and
133  * the values are not rescaled to match the parametrized total cross
134  * section.
135  * <tr><td>`-x` <td> `--dump_iSS`
136  * <td>Prints a particles table in iSS format. This format is used in MUSIC and
137  * CLVisc relativistic hydro codes.
138  * </table>
139  */
140 
141 namespace {
142 /**
143  * Prints usage information and exits the program
144  *
145  * \param[out] rc Exit status to return
146  * \param[in] progname Name of the program
147  *
148  * usage() is called when either the `--help` or `-h` command line
149  * options are given to the program; in this case, the exit status is
150  * EXIT_SUCCESS, or when an unknown option is given; in this case,
151  * the exit status is EXIT_FAIL.
152  */
153 void usage(const int rc, const std::string &progname) {
154  // Implement some tools to format helper using Einhard colors
155  const auto colorize = [](const auto &color,
156  const std::string s) -> std::string {
157  return color + s + einhard::NoColor_t_::ANSI();
158  };
159  const auto print_option = [&colorize](
160  const std::string &short_option,
161  const std::string &long_option,
162  std::optional<std::string> value_placeholder,
163  const std::string &description) {
164  const auto option_color = std::string{einhard::Cyan_t_::ANSI()};
165  const auto value_color = std::string{einhard::DCyan_t_::ANSI()};
166  const auto default_color = std::string{einhard::NoColor_t_::ANSI()};
167  const int indentation = 2;
168  const int effective_option_column_width = 29;
169  /* Calculate the width of the option column including the bytes from the
170  * ANSI color code which don't appear on screen but are "eaten up" by
171  * std::printf and thus must be added here. */
172  const int option_column_width =
173  effective_option_column_width +
174  3 * (option_color.length() + default_color.length());
175  const int padding = indentation + effective_option_column_width;
176  const int raw_option_length =
177  short_option.length() + 2 + long_option.length() +
178  ((value_placeholder) ? (1 + value_placeholder->length()) : 0);
179  const std::string option{
180  colorize(option_color, short_option) + ", " +
181  colorize(option_color, long_option) + (value_placeholder ? " " : "") +
182  colorize(value_color, value_placeholder.value_or(""))};
183  std::printf("%*s%-*s", indentation, "", option_column_width,
184  option.c_str());
185  bool skip_padding = true;
186  if (raw_option_length >= effective_option_column_width) {
187  std::printf("\n");
188  skip_padding = false;
189  }
190  for (const auto &line : smash::split(description, '\n')) {
191  std::printf("%*s%s\n", (skip_padding) ? 0 : padding, "", line.c_str());
192  skip_padding = false;
193  }
194  };
195 
196  // Print synopsis
197  std::printf(
198  "\n Usage: %s\n\n",
199  colorize(einhard::Yellow_t_::ANSI(), progname + " [option]").c_str());
200 
201  // Print options
202  print_option("-h", "--help", std::nullopt, "Print usage information");
203  print_option("-v", "--version", std::nullopt, "Print version");
204  std::printf("\n");
205  print_option("-i", "--inputfile", "<file>",
206  "Path to input configuration file (default: ./config.yaml)");
207  print_option("-o", "--output", "<dir>",
208  "Output directory (default: ./data/<runid>)");
209  print_option("-f", "--force", std::nullopt,
210  "Force overwriting files in the output directory");
211  print_option("-d", "--decaymodes", "<file>",
212  "Override default decay modes from file");
213  print_option("-p", "--particles", "<file>",
214  "Override default particles from file");
215  print_option("-t", "--tabulations", "<dir>",
216  "Tabulations cache directory (default: ./data/tabulations)");
217  print_option("-q", "--quiet", std::nullopt, "Suppress disclaimer printout");
218  print_option("-n", "--no-cache", std::nullopt,
219  "Disable caching integrals on disk");
220  std::printf("\n");
221  print_option(
222  "-c", "--config", "<YAML string>",
223  "Specify config value overrides (multiple -c arguments are supported)");
224  print_option("-m", "--modus", "<modus>",
225  "Shortcut for -c 'General: { Modus: <modus> }'");
226  print_option("-e", "--endtime", "<time>",
227  "Shortcut for -c 'General: { End_Time: <time> }'");
228  std::printf("\n");
229  print_option("-l", "--list-2-to-n", std::nullopt,
230  "Print list of all possible 2->n reactions (with n>1)");
231  print_option("-r", "--resonance", "<pdg>",
232  "Print width(m) and m*spectral function(m^2) for resonance pdg");
233  print_option(
234  "-s", "--cross-sections", "<pdg1>,<pdg2>[,mass1,mass2[,plab1,...]]",
235  "Print all partial cross-sections of pdg1 + pdg2 reactions versus "
236  "sqrt(s)");
237  print_option("-S", "--cross-sections-fs",
238  "<pdg1>,<pdg2>[,mass1,mass2[,plab1,...]]",
239  "Print an approximation of the final-state cross-sections of "
240  "pdg1 + pdg2\nreactions versus sqrt(s). Contributions from "
241  "strings are not considered\nfor the final state. Masses are "
242  "optional, by default pole masses are used.\nNote the required "
243  "comma and no spaces");
244  print_option("-x", "--dump_iSS", std::nullopt,
245  "Print particles table in iSS format. This format is used in "
246  "MUSIC and\nCLVisc relativistic hydro codes");
247  std::printf("\n");
248  std::exit(rc);
249 }
250 
251 /// Print the disclaimer.
253  std::cout
254  << "###################################################################"
255  << "############"
256  << "\n"
257  << "\n"
258  << " :::s.\n"
259  << " .... ''ss:: "
260  "ah:\n"
261  << " a::''. ..:sss "
262  ".HH.\n"
263  << " mss'.. ...s'm. sSA##As mAhh##hsh##s. .hA##ASa sS###As "
264  "hMAh##h.\n"
265  << " :a':'. .'':as sM#' .HHm''HMS''AMs mMA' .AMs aMA. "
266  "'HHa..HM:\n"
267  << " .a:s'. ..''ss 'h#H#S. mMm 'M#' .HH. 'MH. :MA 'h#H#S. "
268  "hMm :M#\n"
269  << " .::ss'. .... 'SMm .HH. SMa hMm sM#..mHMs 'AMa "
270  "'MH. SMa\n"
271  << " .s::' #SMASHh aMS .MH: HM: #MMMmMM. #SMASHh "
272  "aMS .MM.\n"
273  << "\n"
274  << "###################################################################"
275  << "############"
276  << "\n"
277  << " This is SMASH version: " << SMASH_VERSION << "\n"
278  << " Simulating Many Accelerated Strongly-interacting Hadrons"
279  << "\n"
280  << "\n"
281  << " Distributed under the GNU General Public License 3.0"
282  << " (GPLv3 or later)."
283  << "\n"
284  << " See LICENSE for details."
285  << "\n"
286  << " For the full list of contributors see the AUTHORS.md file."
287  << "\n"
288  << "\n"
289  << " When using SMASH, please cite"
290  << "\n"
291  << " J. Weil et al., Phys.Rev. C94 (2016) no.5, 054905"
292  << "\n"
293  << " together with the software DOI for the specific code version "
294  << "employed:"
295  << "\n"
296  << " https://doi.org/10.5281/zenodo.3484711"
297  << "\n"
298  << " In addition, if Pythia is used please cite"
299  << "\n"
300  << " C. Bierlich et al, SciPost Phys. Codebases 8 (2022)"
301  << "\n"
302  << " together with the Codebase release you used:"
303  << "\n"
304  << " https://doi.org/10.21468/SciPostPhysCodeb.8-r8.3"
305  << "\n"
306  << "\n"
307  << " Webpage: https://smash-transport.github.io"
308  << "\n"
309  << "\n"
310  << " Report issues at https://github.com/smash-transport/smash"
311  << "\n"
312  << " or contact us by email at elfner@itp.uni-frankfurt.de"
313  << "\n"
314  << "\n"
315  << "###################################################################"
316  << "############"
317  << "\n"
318  << "\n";
319 }
320 
321 /**
322  * \ingroup exception
323  * Exception class that is thrown, if the requested output directory
324  * already exists and `-f` was not specified on the command line.
325  */
326 struct OutputDirectoryExists : public std::runtime_error {
327  using std::runtime_error::runtime_error;
328 };
329 /**
330  * \ingroup exception
331  * Exception class that is thrown, if no new output path can be
332  * generated (there is a directory name for each positive integer
333  * value)
334  */
335 struct OutputDirectoryOutOfIds : public std::runtime_error {
336  using std::runtime_error::runtime_error;
337 };
338 
339 /// \return the default path for output.
340 std::filesystem::path default_output_path() {
341  const std::filesystem::path p = std::filesystem::absolute("data");
342  if (!std::filesystem::exists(p)) {
343  return p / "0";
344  }
345  std::filesystem::path p2;
346  for (int id = 0; id < std::numeric_limits<int>::max(); ++id) {
347  p2 = p / std::to_string(id);
348  if (!std::filesystem::exists(p2)) {
349  break;
350  }
351  }
352  if (p == p2) {
353  throw OutputDirectoryOutOfIds("no unique data subdir ID left");
354  }
355  return p2;
356 }
357 
358 /**
359  * Ensures the output path is valid.
360  *
361  * \throw OutputDirectoryExists if the Output directory already exists.
362  * \param[in] path The output path to be written to
363  */
364 void ensure_path_is_valid(const std::filesystem::path &path) {
365  if (std::filesystem::exists(path)) {
366  if (!std::filesystem::is_directory(path)) {
367  throw OutputDirectoryExists("The given path (" + path.native() +
368  ") exists, but it is not a directory.");
369  }
370  } else {
371  if (!std::filesystem::create_directories(path)) {
372  throw OutputDirectoryExists(
373  "Race condition detected: The directory " + path.native() +
374  " did not exist a few cycles ago, but was created in the meantime by "
375  "a different process.");
376  }
377  }
378 }
379 
380 /**
381  * Prepares ActionsFinder for cross-section and reaction dumps.
382  *
383  * \param[inout] configuration Necessary parameters to switch reactions on/off
384  * \return The constructed \c ScatterActionsFinder .
385  */
387  ExperimentParameters params = create_experiment_parameters(configuration);
388  return ScatterActionsFinder(configuration, params);
389 }
390 
391 /**
392  * Checks if there are unused config values.
393  */
394 void check_for_unused_config_values(const Configuration &configuration) {
395  if (!configuration.is_empty()) {
396  throw std::runtime_error(
397  "The following configuration values were not used:\n" +
398  configuration.to_string());
399  }
400 }
401 
402 /**
403  * Remove all config values that are only needed for simulations.
404  *
405  * This is useful when checking for unused config value when SMASH only
406  * outputs cross sections, resonance properties or possible reactions.
407  */
409  for (const auto &key : {InputKeys::particles, InputKeys::decaymodes}) {
410  if (configuration.has_value(key)) {
411  configuration.take(key);
412  }
413  }
414  for (const auto &section :
418  if (configuration.has_section(section)) {
419  configuration.extract_sub_configuration(section).clear();
420  }
421  }
422 }
423 
424 } // unnamed namespace
425 
426 } // namespace smash
427 
428 /**
429  * Main program
430  * Smashes Many Accelerated Strongly-Interacting Hadrons :-)
431  *
432  * Do command line parsing and hence decides modus
433  *
434  * \param[in] argc Number of arguments on command-line
435  * \param[in] argv List of arguments on command-line
436  * \return Either 0 or EXIT_FAILURE.
437  */
438 int main(int argc, char *argv[]) {
439  using namespace smash; // NOLINT(build/namespaces)
440 
441  constexpr option longopts[] = {
442  {"config", required_argument, 0, 'c'},
443  {"decaymodes", required_argument, 0, 'd'},
444  {"endtime", required_argument, 0, 'e'},
445  {"force", no_argument, 0, 'f'},
446  {"help", no_argument, 0, 'h'},
447  {"inputfile", required_argument, 0, 'i'},
448  {"modus", required_argument, 0, 'm'},
449  {"particles", required_argument, 0, 'p'},
450  {"output", required_argument, 0, 'o'},
451  {"tabulations", required_argument, 0, 't'},
452  {"list-2-to-n", no_argument, 0, 'l'},
453  {"resonance", required_argument, 0, 'r'},
454  {"cross-sections", required_argument, 0, 's'},
455  {"cross-sections-fs", required_argument, 0, 'S'},
456  {"dump-iSS", no_argument, 0, 'x'},
457  {"version", no_argument, 0, 'v'},
458  {"no-cache", no_argument, 0, 'n'},
459  {"quiet", no_argument, 0, 'q'},
460  {nullptr, 0, 0, 0}};
461 
462  // strip any path to progname
463  const std::string progname =
464  std::filesystem::path(argv[0]).filename().native();
465 
466  try {
467  bool force_overwrite = false;
468  std::filesystem::path output_path = default_output_path();
469  std::string input_path("./config.yaml"), particles, decaymodes;
470  std::vector<std::string> extra_config;
471  char *modus = nullptr, *end_time = nullptr, *pdg_string = nullptr,
472  *cs_string = nullptr;
473  std::string custom_tabulations_path;
474  bool list2n_activated = false;
475  bool resonance_dump_activated = false;
476  bool cross_section_dump_activated = false;
477  bool final_state_cross_sections = false;
478  bool particles_dump_iSS_format = false;
479  bool cache_integrals = true;
480  bool suppress_disclaimer = false;
481 
482  // parse command-line arguments
483  int opt;
484  while ((opt = getopt_long(argc, argv, "c:d:e:fhi:m:p:o:t:lr:s:S:xvnq",
485  longopts, nullptr)) != -1) {
486  switch (opt) {
487  case 'c':
488  extra_config.emplace_back(optarg);
489  break;
490  case 'd':
491  decaymodes = optarg;
492  break;
493  case 'f':
494  force_overwrite = true;
495  break;
496  case 'i':
497  input_path = optarg;
498  break;
499  case 'h':
500  usage(EXIT_SUCCESS, progname);
501  break;
502  case 'm':
503  modus = optarg;
504  break;
505  case 'p':
506  particles = optarg;
507  break;
508  case 'e':
509  end_time = optarg;
510  break;
511  case 'o':
512  output_path = optarg;
513  break;
514  case 't':
515  custom_tabulations_path = optarg;
516  break;
517  case 'l':
518  list2n_activated = true;
519  suppress_disclaimer = true;
520  break;
521  case 'r':
522  resonance_dump_activated = true;
523  pdg_string = optarg;
524  suppress_disclaimer = true;
525  break;
526  case 'S':
527  final_state_cross_sections = true;
528  // fallthrough
529  case 's':
530  cross_section_dump_activated = true;
531  cs_string = optarg;
532  suppress_disclaimer = true;
533  break;
534  case 'x':
535  particles_dump_iSS_format = true;
536  suppress_disclaimer = true;
537  break;
538  case 'v':
539  std::printf(
540  "%s\n"
541 #ifdef GIT_BRANCH
542  "Branch : %s\n"
543 #endif
544  "System : %s\nCompiler : %s %s\n"
545  "Build : %s\nDate : %s\n",
546  SMASH_VERSION,
547 #ifdef GIT_BRANCH
548  GIT_BRANCH,
549 #endif
550  CMAKE_SYSTEM, CMAKE_CXX_COMPILER_ID, CMAKE_CXX_COMPILER_VERSION,
551  CMAKE_BUILD_TYPE, BUILD_DATE);
552  std::exit(EXIT_SUCCESS);
553  case 'n':
554  cache_integrals = false;
555  break;
556  case 'q':
557  suppress_disclaimer = true;
558  break;
559  default:
560  usage(EXIT_FAILURE, progname);
561  }
562  }
563 
564  // Abort if there are unhandled arguments left.
565  if (optind < argc) {
566  std::cout << argv[0] << ": invalid argument -- '" << argv[optind]
567  << "'\n";
568  usage(EXIT_FAILURE, progname);
569  }
570 
571  if (!suppress_disclaimer) {
573  }
574 
575  auto configuration = setup_config_and_logging(input_path, particles,
576  decaymodes, extra_config);
577 
579 
580  // Check output path
581  ensure_path_is_valid(output_path);
582  if (!cache_integrals && !custom_tabulations_path.empty()) {
583  throw std::invalid_argument(
584  "--tabulations cannot be used together with --no-cache.");
585  }
586  std::string tabulations_path;
587  if (cache_integrals) {
588  if (!custom_tabulations_path.empty()) {
589  tabulations_path = custom_tabulations_path;
590  } else {
591  tabulations_path = output_path.has_parent_path()
592  ? output_path.parent_path().string()
593  : ".";
594  tabulations_path += "/tabulations";
595  }
596  } else {
597  tabulations_path = "";
598  }
599  const std::string version(SMASH_VERSION);
600 
601  if (list2n_activated) {
602  /* Print only 2->n, n > 1. Do not dump decays, which can be found in
603  * decaymodes.txt anyway */
604  configuration.merge_yaml("{Collision_Term: {Two_to_One: False}}");
605  initialize_particles_decays_and_tabulations(configuration, version,
606  tabulations_path);
607  auto scat_finder = actions_finder_for_dump(configuration);
608 
609  ignore_simulation_config_values(configuration);
610  check_for_unused_config_values(configuration);
611 
612  scat_finder.dump_reactions();
613  std::exit(EXIT_SUCCESS);
614  }
615  if (particles_dump_iSS_format) {
616  initialize_particles_decays_and_tabulations(configuration, version,
617  tabulations_path);
618  ParticleTypePtrList list;
619  list.clear();
620  for (const auto &ptype : ParticleType::list_all()) {
621  list.push_back(&ptype);
622  }
623  std::sort(list.begin(), list.end(),
625  return a->mass() < b->mass();
626  });
627  for (const ParticleTypePtr &ptype : list) {
628  if (ptype->pdgcode().is_lepton() || ptype->baryon_number() < 0) {
629  continue;
630  }
631  const auto &decay_modes = ptype->decay_modes();
632  const auto &modelist = decay_modes.decay_mode_list();
633  int ndecays = ptype->is_stable() ? 1 : modelist.size();
634  std::printf("%13i %s %10.5f %10.5f %5i %5i %5i %5i %5i %5i %5i %5i\n",
635  ptype->pdgcode().get_decimal(),
636  smash::utf8::fill_left(ptype->name(), 12, ' ').c_str(),
637  ptype->mass(), ptype->width_at_pole(),
638  ptype->pdgcode().spin_degeneracy(), ptype->baryon_number(),
639  ptype->strangeness(), ptype->pdgcode().charmness(),
640  ptype->pdgcode().bottomness(), ptype->isospin() + 1,
641  ptype->charge(), ndecays);
642  if (!ptype->is_stable()) {
643  for (const auto &decay : modelist) {
644  auto ptypes = decay->particle_types();
645  std::printf("%13i %13i %20.5f %13i %13i %13i %13i %13i\n",
646  ptype->pdgcode().get_decimal(), 2, decay->weight(),
647  ptypes[0]->pdgcode().get_decimal(),
648  ptypes[1]->pdgcode().get_decimal(), 0, 0, 0);
649  }
650  } else {
651  std::printf("%13i %13i %20.5f %13i %13i %13i %13i %13i\n",
652  ptype->pdgcode().get_decimal(), 1, 1.0,
653  ptype->pdgcode().get_decimal(), 0, 0, 0, 0);
654  }
655  }
656  std::exit(EXIT_SUCCESS);
657  }
658  if (resonance_dump_activated) {
659  // Ignore config values that don't make sense.
660  initialize_particles_decays_and_tabulations(configuration, version,
661  tabulations_path);
662  const auto _dummy = ExperimentBase::create(configuration, output_path);
663  ignore_simulation_config_values(configuration);
664  check_for_unused_config_values(configuration);
665 
666  PdgCode pdg(pdg_string);
667  const ParticleType &res = ParticleType::find(pdg);
669  std::exit(EXIT_SUCCESS);
670  }
671  if (cross_section_dump_activated) {
672  initialize_particles_decays_and_tabulations(configuration, version,
673  tabulations_path);
674  std::string arg_string(cs_string);
675  std::vector<std::string> args = split(arg_string, ',');
676  const unsigned int n_arg = args.size();
677  if (n_arg != 2 && n_arg != 4 && n_arg < 5) {
678  throw std::invalid_argument("-s usage: pdg1,pdg2[,m1,m2[,plab1,...]]");
679  }
680  PdgCode pdg_a(args[0]), pdg_b(args[1]);
681  const ParticleType &a = ParticleType::find(pdg_a);
682  const ParticleType &b = ParticleType::find(pdg_b);
683  if (n_arg < 4) {
684  for (unsigned int i = 0; i < 4 - n_arg; i++) {
685  args.push_back("");
686  }
687  }
688  double ma = (args[2] == "") ? a.mass() : std::stod(args[2]);
689  double mb = (args[3] == "") ? b.mass() : std::stod(args[3]);
690  if (a.is_stable() && args[2] != "" && std::stod(args[2]) != a.mass()) {
691  ma = a.mass();
692  std::ostringstream warn_msg{"Pole mass ", std::ios::ate};
693  warn_msg << a.mass() << " GeV is used for stable particle " << a.name()
694  << " instead of the provided " << args[2] << " GeV.\n";
695  logg[LMain].warn(warn_msg.str());
696  }
697  if (b.is_stable() && args[3] != "" && std::stod(args[3]) != b.mass()) {
698  mb = b.mass();
699  std::ostringstream warn_msg{"Pole mass ", std::ios::ate};
700  warn_msg << b.mass() << " GeV is used for stable particle " << b.name()
701  << " instead of the provided " << args[3] << " GeV.\n";
702  logg[LMain].warn(warn_msg.str());
703  }
704  const size_t plab_size = n_arg <= 4 ? 0 : n_arg - 4;
705  std::vector<double> plab;
706  plab.reserve(plab_size);
707  for (size_t i = 4; i < n_arg; i++) {
708  plab.push_back(std::stod(args.at(i)));
709  }
710  auto scat_finder = actions_finder_for_dump(configuration);
711 
712  ignore_simulation_config_values(configuration);
713  check_for_unused_config_values(configuration);
714 
715  scat_finder.dump_cross_sections(a, b, ma, mb, final_state_cross_sections,
716  plab);
717  std::exit(EXIT_SUCCESS);
718  }
719  if (modus) {
720  configuration.set_value(InputKeys::gen_modus, std::string(modus));
721  }
722  if (end_time) {
723  configuration.set_value(InputKeys::gen_endTime,
724  std::abs(std::atof(end_time)));
725  }
726 
727  int64_t seed = configuration.read(InputKeys::gen_randomseed);
728  if (seed < 0) {
729  configuration.set_value(InputKeys::gen_randomseed,
731  }
732 
733  // Avoid overwriting SMASH output
734  const std::filesystem::path lock_path = output_path / "smash.lock";
735  FileLock lock(lock_path);
736  if (!lock.acquire()) {
737  throw std::runtime_error(
738  "Another instance of SMASH is already writing to the specified "
739  "output directory. If you are sure this is not the case, remove \"" +
740  lock_path.native() + "\".");
741  }
742  logg[LMain].debug("output path: ", output_path);
743  if (!force_overwrite &&
744  std::filesystem::exists(output_path / "config.yaml")) {
745  throw std::runtime_error(
746  "Output directory would get overwritten. Select a different output "
747  "directory, clean up, or tell SMASH to ignore existing files.");
748  }
749 
750  /* Keep a copy of the configuration that was used in the output directory
751  * also save information about SMASH build as a comment */
752  std::ofstream(output_path / "config.yaml")
753  << "# " << SMASH_VERSION << '\n'
754 #ifdef GIT_BRANCH
755  << "# Branch : " << GIT_BRANCH << '\n'
756 #endif
757  << "# System : " << CMAKE_SYSTEM << '\n'
758  << "# Compiler : " << CMAKE_CXX_COMPILER_ID << ' '
759  << CMAKE_CXX_COMPILER_VERSION << '\n'
760  << "# Build : " << CMAKE_BUILD_TYPE << '\n'
761  << "# Date : " << BUILD_DATE << '\n'
762  << configuration.to_string() << '\n';
763 
764  const auto hash =
765  initialize_particles_decays_and_return_hash(configuration, version);
766 
767  // Create an experiment
768  logg[LMain].trace(SMASH_SOURCE_LOCATION, " create Experiment");
769  auto experiment = ExperimentBase::create(configuration, output_path);
770  check_for_unused_config_values(configuration);
771  tabulate_resonance_integrals(hash, tabulations_path);
772 
773  // Run the experiment
774  logg[LMain].trace(SMASH_SOURCE_LOCATION, " run the Experiment");
775  experiment->run();
776  } catch (std::exception &e) {
777  logg[LMain].fatal() << "SMASH failed with the following error:\n"
778  << e.what();
779  return EXIT_FAILURE;
780  }
781 
782  logg[LMain].trace() << SMASH_SOURCE_LOCATION << " about to return from main";
783  return 0;
784 }
Interface to the SMASH configuration files.
std::string to_string() const
Return a string of the current YAML tree.
Configuration extract_sub_configuration(KeyLabels section, Configuration::GetEmpty empty_if_not_existing=Configuration::GetEmpty::No)
Create a new configuration from a then-removed section of the present object.
bool is_empty() const
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...
void clear()
Erase the Configuration content.
bool has_section(const KeyLabels &labels) const
Return whether there is a (possibly empty) section with the given labels.
T take(const Key< T > &key)
The default interface for SMASH to read configuration values.
static std::unique_ptr< ExperimentBase > create(Configuration &config, const std::filesystem::path &output_path)
Factory method that creates and initializes a new Experiment<Modus>.
Definition: experiment.cc:22
Guard to create a file lock.
Definition: filelock.h:30
bool acquire()
Try to acquire the file lock.
Definition: filelock.cc:22
A pointer-like interface to global references to ParticleType objects.
Definition: particletype.h:731
Particle type contains the static properties of a particle species.
Definition: particletype.h:100
void dump_width_and_spectral_function() const
Prints out width and spectral function versus mass to the standard output.
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode.
Definition: particletype.cc:99
const std::string & name() const
Definition: particletype.h:144
static const ParticleTypeList & list_all()
Definition: particletype.cc:51
bool is_stable() const
Definition: particletype.h:251
double mass() const
Definition: particletype.h:147
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
Definition: pdgcode.h:108
A simple scatter finder: Just loops through all particles and checks each pair for a collision.
#define SMASH_SOURCE_LOCATION
Hackery that is required to output the location in the source code where the log statement occurs.
Definition: logging.h:153
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > & logg
An array that stores all pre-configured Logger objects.
Definition: logging.h:245
std::unique_ptr< ExperimentBase > experiment(Configuration c)
Create an experiment given an input configuration.
Definition: setup.h:169
constexpr Section output
Section for the output information.
Definition: input_keys.h:205
constexpr Section general
General section.
Definition: input_keys.h:143
constexpr Section forcedThermalization
Section for the forced thermalization.
Definition: input_keys.h:140
constexpr Section potentials
Section for the potentials information.
Definition: input_keys.h:228
constexpr Section lattice
Section for the lattice.
Definition: input_keys.h:149
constexpr Section modi
Section for the modus specific information.
Definition: input_keys.h:155
void ignore_simulation_config_values(Configuration &configuration)
Remove all config values that are only needed for simulations.
Definition: smash.cc:408
ScatterActionsFinder actions_finder_for_dump(Configuration &configuration)
Prepares ActionsFinder for cross-section and reaction dumps.
Definition: smash.cc:386
void usage(const int rc, const std::string &progname)
Prints usage information and exits the program.
Definition: smash.cc:153
void ensure_path_is_valid(const std::filesystem::path &path)
Ensures the output path is valid.
Definition: smash.cc:364
void check_for_unused_config_values(const Configuration &configuration)
Checks if there are unused config values.
Definition: smash.cc:394
void print_disclaimer()
Print the disclaimer.
Definition: smash.cc:252
std::filesystem::path default_output_path()
Definition: smash.cc:340
constexpr int p
Proton.
int64_t generate_63bit_seed()
Generates a seed with a truly random 63-bit value, if possible.
Definition: random.cc:21
std::string fill_left(const std::string &s, size_t width, char fill=' ')
Fill string with characters to the left until the given width is reached.
Definition: action.h:24
std::vector< std::string > split(const std::string &s, char delim)
Split string by delimiter.
void initialize_particles_decays_and_tabulations(Configuration &configuration, const std::string &version, const std::string &tabulations_dir={})
Wrapper over a function that initializes the particles and decays from the given configuration,...
Definition: library.cc:46
void tabulate_resonance_integrals(const sha256::Hash &hash, const std::string &tabulations_dir)
Tabulate the resonance integrals.
Definition: library.cc:75
Configuration setup_config_and_logging(const std::string &config_file, const std::string &particles_file={}, const std::string &decaymodes_file={}, const std::vector< std::string > &extra_config={})
Set up configuration and logging from input files and extra config.
Definition: library.cc:34
sha256::Hash initialize_particles_decays_and_return_hash(Configuration &configuration, const std::string &version)
Initialize the particles and decays from the given configuration.
Definition: library.cc:54
ExperimentParameters create_experiment_parameters(Configuration &config)
Gathers all general Experiment parameters.
Definition: experiment.cc:135
std::string to_string(ThermodynamicQuantity quantity)
Convert a ThermodynamicQuantity enum value to its corresponding string.
Definition: stringify.cc:26
void setup_default_float_traps()
Setup the floating-point traps used throughout SMASH.
static constexpr int LMain
Definition: experiment.h:94
int main(int argc, char *argv[])
Main program Smashes Many Accelerated Strongly-Interacting Hadrons :-)
Definition: smash.cc:438
Helper structure for Experiment.
static const Key< std::string > particles
See user guide description for more information.
Definition: input_keys.h:1309
static const Key< int64_t > gen_randomseed
See user guide description for more information.
Definition: input_keys.h:1398
static const Key< std::string > gen_modus
See user guide description for more information.
Definition: input_keys.h:1361
static const Key< std::string > decaymodes
See user guide description for more information.
Definition: input_keys.h:1314
static const Key< double > gen_endTime
See user guide description for more information.
Definition: input_keys.h:1333
Exception class that is thrown, if the requested output directory already exists and -f was not speci...
Definition: smash.cc:326
Exception class that is thrown, if no new output path can be generated (there is a directory name for...
Definition: smash.cc:335