Version: SMASH-1.5
smash.cc File Reference
#include <getopt.h>
#include <set>
#include <sstream>
#include <vector>
#include <boost/filesystem/fstream.hpp>
#include "smash/cxx14compat.h"
#include "smash/decaymodes.h"
#include "smash/experiment.h"
#include "smash/filelock.h"
#include "smash/inputfunctions.h"
#include "smash/random.h"
#include "smash/scatteractionsfinder.h"
#include "smash/stringfunctions.h"
#include "smash/config.h"

Go to the source code of this file.

Classes

struct  smash::anonymous_namespace{smash.cc}::OutputDirectoryExists
 Exception class that is thrown, if the requested output directory already exists and -f was not specified on the command line. More...
 
struct  smash::anonymous_namespace{smash.cc}::OutputDirectoryOutOfIds
 Exception class that is thrown, if no new output path can be generated (there is a directory name for each positive integer value) More...
 

Namespaces

 smash
 
 smash::anonymous_namespace{smash.cc}
 

Functions

void smash::anonymous_namespace{smash.cc}::print_disclaimer ()
 Print the disclaimer. More...
 
bf::path smash::anonymous_namespace{smash.cc}::default_output_path ()
 
void smash::anonymous_namespace{smash.cc}::ensure_path_is_valid (const bf::path &path)
 Ensures the output path is valid. More...
 
ScatterActionsFinder smash::anonymous_namespace{smash.cc}::actions_finder_for_dump (Configuration configuration)
 Prepares ActionsFinder for cross-section and reaction dumps. More...
 
void smash::anonymous_namespace{smash.cc}::check_config_version_is_compatible (Configuration configuration)
 Checks if the SMASH version is compatible with the version of the configuration file. More...
 
int main (int argc, char *argv[])
 Main program Smashes Many Accelerated Strongly-Interacting Hadrons :-) More...
 

Function Documentation

◆ main()

int main ( int  argc,
char *  argv[] 
)

Main program Smashes Many Accelerated Strongly-Interacting Hadrons :-)

Do command line parsing and hence decides modus

Parameters
[in]argcNumber of arguments on command-line
[in]argvList of arguments on command-line
Returns
Either 0 or EXIT_FAILURE.

Definition at line 333 of file smash.cc.

333  {
334  using namespace smash; // NOLINT(build/namespaces)
335 
336  const auto &log = logger<LogArea::Main>();
337 
338  constexpr option longopts[] = {
339  {"config", required_argument, 0, 'c'},
340  {"decaymodes", required_argument, 0, 'd'},
341  {"endtime", required_argument, 0, 'e'},
342  {"force", no_argument, 0, 'f'},
343  {"help", no_argument, 0, 'h'},
344  {"inputfile", required_argument, 0, 'i'},
345  {"modus", required_argument, 0, 'm'},
346  {"particles", required_argument, 0, 'p'},
347  {"output", required_argument, 0, 'o'},
348  {"list-2-to-n", no_argument, 0, 'l'},
349  {"resonance", required_argument, 0, 'r'},
350  {"cross-sections", required_argument, 0, 's'},
351  {"cross-sections-fs", required_argument, 0, 'S'},
352  {"version", no_argument, 0, 'v'},
353  {nullptr, 0, 0, 0}};
354 
355  // strip any path to progname
356  const std::string progname = bf::path(argv[0]).filename().native();
357 
358  try {
359  bool force_overwrite = false;
360  bf::path output_path = default_output_path(), input_path("./config.yaml");
361  std::vector<std::string> extra_config;
362  char *particles = nullptr, *decaymodes = nullptr, *modus = nullptr,
363  *end_time = nullptr, *pdg_string = nullptr, *cs_string = nullptr;
364  bool list2n_activated = false;
365  bool resonance_dump_activated = false;
366  bool cross_section_dump_activated = false;
367  bool final_state_cross_sections = false;
368 
369  // parse command-line arguments
370  int opt;
371  bool suppress_disclaimer = false;
372  while ((opt = getopt_long(argc, argv, "c:d:e:fhi:m:p:o:lr:s:S:v", longopts,
373  nullptr)) != -1) {
374  switch (opt) {
375  case 'c':
376  extra_config.emplace_back(optarg);
377  break;
378  case 'd':
379  decaymodes = optarg;
380  break;
381  case 'f':
382  force_overwrite = true;
383  break;
384  case 'i':
385  input_path = optarg;
386  break;
387  case 'h':
388  usage(EXIT_SUCCESS, progname);
389  break;
390  case 'm':
391  modus = optarg;
392  break;
393  case 'p':
394  particles = optarg;
395  break;
396  case 'e':
397  end_time = optarg;
398  break;
399  case 'o':
400  output_path = optarg;
401  break;
402  case 'l':
403  list2n_activated = true;
404  suppress_disclaimer = true;
405  break;
406  case 'r':
407  resonance_dump_activated = true;
408  pdg_string = optarg;
409  suppress_disclaimer = true;
410  break;
411  case 'S':
412  final_state_cross_sections = true;
413  // fallthrough
414  case 's':
415  cross_section_dump_activated = true;
416  cs_string = optarg;
417  suppress_disclaimer = true;
418  break;
419  case 'v':
420  std::printf(
421  "%s\n"
422  "Branch : %s\nSystem : %s\nCompiler : %s %s\n"
423  "Build : %s\nDate : %s\n",
424  VERSION_MAJOR, GIT_BRANCH, CMAKE_SYSTEM, CMAKE_CXX_COMPILER_ID,
425  CMAKE_CXX_COMPILER_VERSION, CMAKE_BUILD_TYPE, BUILD_DATE);
426  std::exit(EXIT_SUCCESS);
427  default:
428  usage(EXIT_FAILURE, progname);
429  }
430  }
431 
432  // Abort if there are unhandled arguments left.
433  if (optind < argc) {
434  std::cout << argv[0] << ": invalid argument -- '" << argv[optind]
435  << "'\n";
436  usage(EXIT_FAILURE, progname);
437  }
438 
439  if (!suppress_disclaimer) {
441  }
442 
444 
445  // Read in config file
446  Configuration configuration(input_path.parent_path(),
447  input_path.filename());
448  for (const auto &config : extra_config) {
449  configuration.merge_yaml(config);
450  }
451 
452  // check if version matches before doing anything else
454 
455  if (particles) {
456  if (!bf::exists(particles)) {
457  std::stringstream err;
458  err << "The particles file was expected at '" << particles
459  << "', but the file does not exist.";
460  throw std::runtime_error(err.str());
461  }
462  std::string particle_string = read_all(bf::ifstream{particles});
463  if (has_crlf_line_ending(particle_string)) {
464  std::stringstream err;
465  err << "The particles file has CR LF line endings. Please use LF"
466  " line endings.";
467  throw std::runtime_error(err.str());
468  }
469  configuration["particles"] = particle_string;
470  }
471  if (decaymodes) {
472  if (!bf::exists(decaymodes)) {
473  std::stringstream err;
474  err << "The decay modes file was expected at '" << decaymodes
475  << "', but the file does not exist.";
476  throw std::runtime_error(err.str());
477  }
478  std::string decay_string = read_all(bf::ifstream{decaymodes});
479  if (has_crlf_line_ending(decay_string)) {
480  std::stringstream err;
481  err << "The decay mode file has CR LF line endings. Please use LF"
482  " line endings.";
483  throw std::runtime_error(err.str());
484  }
485  configuration["decaymodes"] = decay_string;
486  }
487  if (list2n_activated) {
488  /* Print only 2->n, n > 1. Do not dump decays, which can be found in
489  * decaymodes.txt anyway */
490  configuration.merge_yaml("{Collision_Term: {Two_to_One: False}}");
494  auto scat_finder = actions_finder_for_dump(configuration);
495  scat_finder.dump_reactions();
496  std::exit(EXIT_SUCCESS);
497  }
498  if (resonance_dump_activated) {
502  PdgCode pdg(pdg_string);
503  const ParticleType &res = ParticleType::find(pdg);
505  std::exit(EXIT_SUCCESS);
506  }
507  if (cross_section_dump_activated) {
511  std::string arg_string(cs_string);
512  std::vector<std::string> args = split(arg_string, ',');
513  const unsigned int n_arg = args.size();
514  if (n_arg < 2 || n_arg > 4) {
515  throw std::invalid_argument("-s usage: pdg1,pdg2[,m1][,m2]");
516  }
517  PdgCode pdg_a(args[0]), pdg_b(args[1]);
518  const ParticleType &a = ParticleType::find(pdg_a);
519  const ParticleType &b = ParticleType::find(pdg_b);
520  for (unsigned int i = 0; i < 4 - n_arg; i++) {
521  args.push_back("");
522  }
523  double ma = (args[2] == "") ? a.mass() : std::stod(args[2]);
524  double mb = (args[3] == "") ? b.mass() : std::stod(args[3]);
525  if (a.is_stable() && args[2] != "") {
526  ma = a.mass();
527  std::cout << "Warning: pole mass is used for stable particle "
528  << a.name() << " instead of " << args[2] << std::endl;
529  }
530  if (b.is_stable() && args[3] != "") {
531  mb = b.mass();
532  std::cout << "Warning: pole mass is used for stable particle "
533  << b.name() << " instead of " << args[3] << std::endl;
534  }
535  auto scat_finder = actions_finder_for_dump(configuration);
536  scat_finder.dump_cross_sections(a, b, ma, mb, final_state_cross_sections);
537  std::exit(EXIT_SUCCESS);
538  }
539  if (modus) {
540  configuration["General"]["Modus"] = std::string(modus);
541  }
542  if (end_time) {
543  configuration["General"]["End_Time"] = std::abs(std::atof(end_time));
544  }
545 
546  // Set up logging
548  configuration.take({"Logging", "default"}, einhard::ALL));
549  create_all_loggers(configuration["Logging"]);
550 
551  int64_t seed = configuration.read({"General", "Randomseed"});
552  if (seed < 0) {
553  // Seed with a truly random 63-bit value, if possible
554  std::random_device rd;
555  static_assert(std::is_same<decltype(rd()), uint32_t>::value,
556  "random_device is assumed to generate uint32_t");
557  uint64_t unsigned_seed =
558  (static_cast<uint64_t>(rd()) << 32) | static_cast<uint64_t>(rd());
559  // Discard the highest bit to make sure it fits into a positive int64_t
560  seed = static_cast<int64_t>(unsigned_seed >> 1);
561  configuration["General"]["Randomseed"] = seed;
562  }
563 
564  // Check output path
565  ensure_path_is_valid(output_path);
566  const bf::path lock_path = output_path / "smash.lock";
567  FileLock lock(lock_path);
568  if (!lock.acquire()) {
569  throw std::runtime_error(
570  "Another instance of SMASH is already writing to the specified "
571  "output directory. If you are sure this is not the case, remove \"" +
572  lock_path.native() + "\".");
573  }
574  log.debug("output path: ", output_path);
575  if (!force_overwrite && bf::exists(output_path / "config.yaml")) {
576  throw std::runtime_error(
577  "Output directory would get overwritten. Select a different output "
578  "directory, clean up, or tell SMASH to ignore existing files.");
579  }
580 
581  /* Keep a copy of the configuration that was used in the output directory
582  * also save information about SMASH build as a comment */
583  bf::ofstream(output_path / "config.yaml")
584  << "# " << VERSION_MAJOR << '\n'
585  << "# Branch : " << GIT_BRANCH << '\n'
586  << "# System : " << CMAKE_SYSTEM << '\n'
587  << "# Compiler : " << CMAKE_CXX_COMPILER_ID << ' '
588  << CMAKE_CXX_COMPILER_VERSION << '\n'
589  << "# Build : " << CMAKE_BUILD_TYPE << '\n'
590  << "# Date : " << BUILD_DATE << '\n'
591  << configuration.to_string() << '\n';
592 
593  log.trace(source_location, " create ParticleType and DecayModes");
597 
598  // Create an experiment
599  log.trace(source_location, " create Experiment");
600  auto experiment = ExperimentBase::create(configuration, output_path);
601  //
602  // version value is not used in experiment. Get rid of it to prevent
603  // warning.
604  configuration.take({"Version"});
605  const std::string report = configuration.unused_values_report();
606 
607  if (report != "{}") {
608  throw std::runtime_error(
609  "The following configuration values were not used:\n" + report);
610  }
611 
612  // Run the experiment
613  log.trace(source_location, " run the Experiment");
614  experiment->run();
615  } catch (std::exception &e) {
616  log.fatal() << "SMASH failed with the following error:\n" << e.what();
617  return EXIT_FAILURE;
618  }
619 
620  log.trace() << source_location << " about to return from main";
621  return 0;
622 }
Value read(std::initializer_list< const char *> keys) const
Additional interface for SMASH to read configuration values without removing them.
std::string unused_values_report() const
Returns a string listing the key/value pairs that have not been taken yet.
Configuration configuration(std::string overrides={})
Return a configuration object filled with data from src/config.yaml.
Definition: setup.h:161
double mass() const
Definition: particletype.h:134
static std::unique_ptr< ExperimentBase > create(Configuration config, const bf::path &output_path)
Factory method that creates and initializes a new Experiment<Modus>.
ScatterActionsFinder actions_finder_for_dump(Configuration configuration)
Prepares ActionsFinder for cross-section and reaction dumps.
Definition: smash.cc:283
static void check_consistency()
void check_config_version_is_compatible(Configuration configuration)
Checks if the SMASH version is compatible with the version of the configuration file.
Definition: smash.cc:298
static void load_decaymodes(const std::string &input)
Loads the DecayModes map as described in the input string.
Definition: decaymodes.cc:163
void dump_width_and_spectral_function() const
Prints out width and spectral function versus mass to the standard output.
void ensure_path_is_valid(const bf::path &path)
Ensures the output path is valid.
Definition: smash.cc:261
std::vector< std::string > split(const std::string &s, char delim)
Split string by delimiter.
Interface to the SMASH configuration files.
void setup_default_float_traps()
Setup the floating-point traps used throughout SMASH.
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode.
void merge_yaml(const std::string &yaml)
Merge the configuration in yaml into the existing tree.
void create_all_loggers(Configuration config)
Called from main() right after the Configuration object is fully set up to create all logger objects ...
Definition: logging.cc:116
bool is_stable() const
Definition: particletype.h:226
#define source_location
Hackery that is required to output the location in the source code where the log statement occurs...
Definition: logging.h:246
Guard to create a file lock.
Definition: filelock.h:30
Particle type contains the static properties of a particle species.
Definition: particletype.h:87
void print_disclaimer()
Print the disclaimer.
Definition: smash.cc:156
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
Definition: pdgcode.h:108
static void create_type_list(const std::string &particles)
Initialize the global ParticleType list (list_all) from the given input data.
bool has_crlf_line_ending(const std::string in)
Check if a line in the string ends with \r\n.
void set_default_loglevel(einhard::LogLevel level)
Set the default log level (what will be returned from subsequent default_loglevel calls)...
Definition: logging.cc:24
Value take(std::initializer_list< const char *> keys)
The default interface for SMASH to read configuration values.
Log all message.
Definition: einhard.hpp:106
std::unique_ptr< ExperimentBase > experiment(const Configuration &c=configuration())
Create an experiment.
Definition: setup.h:175
std::string to_string() const
Returns a YAML string of the current tree.
Definition: action.h:24
const std::string & name() const
Definition: particletype.h:131
std::string read_all(std::istream &&input)
Utility function to read a complete input stream (e.g.
Here is the call graph for this function: