Version: SMASH-1.7
smash.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2012-2019
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 #include <getopt.h>
10 
11 #include <set>
12 #include <sstream>
13 #include <vector>
14 
15 #include <boost/filesystem/fstream.hpp>
16 
17 #include "smash/cxx14compat.h"
18 #include "smash/decaymodes.h"
19 #include "smash/experiment.h"
20 #include "smash/filelock.h"
21 #include "smash/random.h"
24 #include "smash/stringfunctions.h"
25 /* build dependent variables */
26 #include "smash/config.h"
27 
28 namespace smash {
29 
30 namespace {
42 void usage(const int rc, const std::string &progname) {
127  std::printf("\nUsage: %s [option]\n\n", progname.c_str());
128  std::printf(
129  " -h, --help usage information\n"
130  "\n"
131  " -i, --inputfile <file> path to input configuration file\n"
132  " (default: ./config.yaml)\n"
133  " -d, --decaymodes <file> override default decay modes from file\n"
134  " -p, --particles <file> override default particles from file\n"
135  "\n"
136  " -c, --config <YAML> specify config value overrides\n"
137  " (multiple -c arguments are supported)\n"
138  " -m, --modus <modus> shortcut for -c 'General: { Modus: <modus> "
139  "}'\n"
140  " -e, --endtime <time> shortcut for -c 'General: { End_Time: <time> "
141  "}'"
142  "\n"
143  "\n"
144  " -o, --output <dir> output directory (default: ./data/<runid>)\n"
145  " -l, --list-2-to-n list all possible 2->n reactions (with n>1)\n"
146  " -r, --resonance <pdg> dump width(m) and m*spectral function(m^2)"
147  " for resonance pdg\n"
148  " -s, --cross-sections <pdg1>,<pdg2>[,mass1,mass2[,plab1,...]] \n"
149  " dump all partial cross-sections of "
150  "pdg1 + pdg2 reactions versus sqrt(s).\n"
151  " -S, --cross-sections-fs <pdg1>,<pdg2>[,mass1,mass2[,plab1,...]] \n"
152  " dump an approximation of the final-state"
153  " cross-sections\n"
154  " of pdg1 + pdg2 reactions versus sqrt(s).\n"
155  " Contributions from strings are not considered"
156  " for the final state.\n"
157  " Masses are optional, by default pole masses"
158  " are used.\n"
159  " Note the required comma and no spaces.\n"
160  " -f, --force force overwriting files in the output "
161  "directory"
162  "\n"
163  " -x, --dump_iSS Dump particle table in iSS format\n"
164  " This format is used in MUSIC and CLVisc\n"
165  " relativistic hydro codes\n"
166  " -v, --version\n\n");
167  std::exit(rc);
168 }
169 
172  std::cout
173  << "###################################################################"
174  << "############"
175  << "\n"
176  << "\n"
177  << " :::s.\n"
178  << " .... ''ss:: "
179  "ah:\n"
180  << " a::''. ..:sss "
181  ".HH.\n"
182  << " mss'.. ...s'm. sSA##As mAhh##hsh##s. .hA##ASa sS###As "
183  "hMAh##h.\n"
184  << " :a':'. .'':as sM#' .HHm''HMS''AMs mMA' .AMs aMA. "
185  "'HHa..HM:\n"
186  << " .a:s'. ..''ss 'h#H#S. mMm 'M#' .HH. 'MH. :MA 'h#H#S. "
187  "hMm :M#\n"
188  << " .::ss'. .... 'SMm .HH. SMa hMm sM#..mHMs 'AMa "
189  "'MH. SMa\n"
190  << " .s::' #SMASHh aMS .MH: HM: #MMMmMM. #SMASHh "
191  "aMS .MM.\n"
192  << "\n"
193  << "###################################################################"
194  << "############"
195  << "\n"
196  << " This is SMASH version: " << VERSION_MAJOR << "\n"
197  << " Simulating Many Accelerated Strongly-interacting Hadrons"
198  << "\n"
199  << "\n"
200  << " Distributed under the GNU General Public License 3.0"
201  << " (GPLv3 or later)."
202  << "\n"
203  << " See LICENSE for details."
204  << "\n"
205  << " For the full list of contributors see AUTHORS."
206  << "\n"
207  << "\n"
208  << " When using SMASH, please cite"
209  << "\n"
210  << " J. Weil et al., Phys.Rev. C94 (2016) no.5, 054905"
211  << "\n"
212  << " and in addition, if Pythia is used please cite"
213  << "\n"
214  << " T. Sjöstrand, S. Mrenna and P. Skands, JHEP05 (2006) 026,"
215  << "\n"
216  << " Comput. Phys. Comm. 178 (2008) 852."
217  << "\n"
218  << "\n"
219  << " Webpage: https://smash-transport.github.io"
220  << "\n"
221  << "\n"
222  << " Report issues at https://github.com/smash-transport/smash"
223  << "\n"
224  << " or contact us by email at elfner@th.physik.uni-frankfurt.de"
225  << "\n"
226  << "\n"
227  << "###################################################################"
228  << "############"
229  << "\n"
230  << "\n";
231 }
232 
238 struct OutputDirectoryExists : public std::runtime_error {
239  using std::runtime_error::runtime_error;
240 };
247 struct OutputDirectoryOutOfIds : public std::runtime_error {
248  using std::runtime_error::runtime_error;
249 };
250 
253  const bf::path p = bf::absolute("data");
254  if (!bf::exists(p)) {
255  return p / "0";
256  }
257  bf::path p2;
258  for (int id = 0; id < std::numeric_limits<int>::max(); ++id) {
259  p2 = p / std::to_string(id);
260  if (!bf::exists(p2)) {
261  break;
262  }
263  }
264  if (p == p2) {
265  throw OutputDirectoryOutOfIds("no unique data subdir ID left");
266  }
267  return p2;
268 }
269 
276 void ensure_path_is_valid(const bf::path &path) {
277  if (bf::exists(path)) {
278  if (!bf::is_directory(path)) {
279  throw OutputDirectoryExists("The given path (" + path.native() +
280  ") exists, but it is not a directory.");
281  }
282  } else {
283  if (!bf::create_directories(path)) {
284  throw OutputDirectoryExists(
285  "Race condition detected: The directory " + path.native() +
286  " did not exist a few cycles ago, but was created in the meantime by "
287  "a different process.");
288  }
289  }
290 }
291 
299  // The following parameters are only relevant for nucleus-nucleus collisions.
300  // Setting them to the valuing values makes sure they don't have any effect.
301  const std::vector<bool> nucleon_has_interacted = {};
302  const int N_tot = 0;
303  const int N_proj = 0;
304 
305  ExperimentParameters params = create_experiment_parameters(configuration);
306  return ScatterActionsFinder(configuration, params, nucleon_has_interacted,
307  N_tot, N_proj);
308 }
309 
319  const std::string smash_version = "1.7";
320  const std::set<std::string> compatible_config_versions = {"1.7"};
321 
322  const std::string config_version = configuration.read({"Version"});
323 
324  if (compatible_config_versions.find(config_version) ==
325  compatible_config_versions.end()) {
326  std::stringstream err;
327  err << "The version of the configuration file (" << config_version
328  << ") is not compatible with the SMASH version (" << smash_version
329  << ").\nThe following config versions are supported:\n";
330  for (auto it : compatible_config_versions) {
331  err << it << " ";
332  }
333  err << "\nPlease consider updating your config or using a compatible SMASH"
334  " version.";
335  throw std::runtime_error(err.str());
336  }
337 }
338 
343  const std::string report = configuration.unused_values_report();
344 
345  if (report != "{}") {
346  throw std::runtime_error(
347  "The following configuration values were not used:\n" + report);
348  }
349 }
350 
358  configuration.take({"Version"});
359  configuration.take({"particles"});
360  configuration.take({"decaymodes"});
361  configuration.take({"Modi"});
362  configuration.take({"General"});
363  if (configuration.has_value({"Output"})) {
364  configuration.take({"Output"});
365  }
366  if (configuration.has_value({"Lattice"})) {
367  configuration.take({"Lattice"});
368  }
369  if (configuration.has_value({"Potentials"})) {
370  configuration.take({"Potentials"});
371  }
372  if (configuration.has_value({"Forced_Thermalization"})) {
373  configuration.take({"Forced_Thermalization"});
374  }
375 }
376 
377 } // unnamed namespace
378 
379 } // namespace smash
380 
391 int main(int argc, char *argv[]) {
392  using namespace smash; // NOLINT(build/namespaces)
393 
394  const auto &log = logger<LogArea::Main>();
395 
396  constexpr option longopts[] = {
397  {"config", required_argument, 0, 'c'},
398  {"decaymodes", required_argument, 0, 'd'},
399  {"endtime", required_argument, 0, 'e'},
400  {"force", no_argument, 0, 'f'},
401  {"help", no_argument, 0, 'h'},
402  {"inputfile", required_argument, 0, 'i'},
403  {"modus", required_argument, 0, 'm'},
404  {"particles", required_argument, 0, 'p'},
405  {"output", required_argument, 0, 'o'},
406  {"list-2-to-n", no_argument, 0, 'l'},
407  {"resonance", required_argument, 0, 'r'},
408  {"cross-sections", required_argument, 0, 's'},
409  {"cross-sections-fs", required_argument, 0, 'S'},
410  {"dump-iSS", no_argument, 0, 'x'},
411  {"version", no_argument, 0, 'v'},
412  {nullptr, 0, 0, 0}};
413 
414  // strip any path to progname
415  const std::string progname = bf::path(argv[0]).filename().native();
416 
417  try {
418  bool force_overwrite = false;
419  bf::path output_path = default_output_path(), input_path("./config.yaml");
420  std::vector<std::string> extra_config;
421  char *particles = nullptr, *decaymodes = nullptr, *modus = nullptr,
422  *end_time = nullptr, *pdg_string = nullptr, *cs_string = nullptr;
423  bool list2n_activated = false;
424  bool resonance_dump_activated = false;
425  bool cross_section_dump_activated = false;
426  bool final_state_cross_sections = false;
427  bool particles_dump_iSS_format = false;
428 
429  // parse command-line arguments
430  int opt;
431  bool suppress_disclaimer = false;
432  while ((opt = getopt_long(argc, argv, "c:d:e:fhi:m:p:o:lr:s:S:xv", longopts,
433  nullptr)) != -1) {
434  switch (opt) {
435  case 'c':
436  extra_config.emplace_back(optarg);
437  break;
438  case 'd':
439  decaymodes = optarg;
440  break;
441  case 'f':
442  force_overwrite = true;
443  break;
444  case 'i':
445  input_path = optarg;
446  break;
447  case 'h':
448  usage(EXIT_SUCCESS, progname);
449  break;
450  case 'm':
451  modus = optarg;
452  break;
453  case 'p':
454  particles = optarg;
455  break;
456  case 'e':
457  end_time = optarg;
458  break;
459  case 'o':
460  output_path = optarg;
461  break;
462  case 'l':
463  list2n_activated = true;
464  suppress_disclaimer = true;
465  break;
466  case 'r':
467  resonance_dump_activated = true;
468  pdg_string = optarg;
469  suppress_disclaimer = true;
470  break;
471  case 'S':
472  final_state_cross_sections = true;
473  // fallthrough
474  case 's':
475  cross_section_dump_activated = true;
476  cs_string = optarg;
477  suppress_disclaimer = true;
478  break;
479  case 'x':
480  particles_dump_iSS_format = true;
481  suppress_disclaimer = true;
482  break;
483  case 'v':
484  std::printf(
485  "%s\n"
486  "Branch : %s\nSystem : %s\nCompiler : %s %s\n"
487  "Build : %s\nDate : %s\n",
488  VERSION_MAJOR, GIT_BRANCH, CMAKE_SYSTEM, CMAKE_CXX_COMPILER_ID,
489  CMAKE_CXX_COMPILER_VERSION, CMAKE_BUILD_TYPE, BUILD_DATE);
490  std::exit(EXIT_SUCCESS);
491  default:
492  usage(EXIT_FAILURE, progname);
493  }
494  }
495 
496  // Abort if there are unhandled arguments left.
497  if (optind < argc) {
498  std::cout << argv[0] << ": invalid argument -- '" << argv[optind]
499  << "'\n";
500  usage(EXIT_FAILURE, progname);
501  }
502 
503  if (!suppress_disclaimer) {
505  }
506 
508 
509  // Read in config file
510  Configuration configuration(input_path.parent_path(),
511  input_path.filename());
512  // Merge config passed via command line
513  for (const auto &config : extra_config) {
514  configuration.merge_yaml(config);
515  }
516 
517  // Set up logging
519  configuration.take({"Logging", "default"}, einhard::ALL));
520  create_all_loggers(configuration["Logging"]);
521 
522  // check if version matches before doing anything else
524 
525  log.trace(source_location, " create ParticleType and DecayModes");
526 
527  auto particles_and_decays =
528  load_particles_and_decaymodes(particles, decaymodes);
529  /* For particles and decaymodes: external file is superior to config.
530  * Hovever, warn in case of conflict.
531  */
532  if (configuration.has_value({"particles"}) && particles) {
533  log.warn("Ambiguity: particles from external file ", particles,
534  " requested, but there is also particle list in the config."
535  " Using particles from ",
536  particles);
537  }
538  if (!configuration.has_value({"particles"}) || particles) {
539  configuration["particles"] = particles_and_decays.first;
540  }
541 
542  if (configuration.has_value({"decaymodes"}) && decaymodes) {
543  log.warn("Ambiguity: decaymodes from external file ", decaymodes,
544  " requested, but there is also decaymodes list in the config."
545  " Using decaymodes from",
546  decaymodes);
547  }
548  if (!configuration.has_value({"decaymodes"}) || decaymodes) {
549  configuration["decaymodes"] = particles_and_decays.second;
550  }
554 
555  if (list2n_activated) {
556  /* Print only 2->n, n > 1. Do not dump decays, which can be found in
557  * decaymodes.txt anyway */
558  configuration.merge_yaml("{Collision_Term: {Two_to_One: False}}");
559  auto scat_finder = actions_finder_for_dump(configuration);
560 
563 
564  scat_finder.dump_reactions();
565  std::exit(EXIT_SUCCESS);
566  }
567  if (particles_dump_iSS_format) {
568  ParticleTypePtrList list;
569  list.clear();
570  for (const auto &ptype : ParticleType::list_all()) {
571  list.push_back(&ptype);
572  }
573  std::sort(list.begin(), list.end(),
575  return a->mass() < b->mass();
576  });
577  for (const ParticleTypePtr ptype : list) {
578  if (ptype->pdgcode().is_lepton() || ptype->baryon_number() < 0) {
579  continue;
580  }
581  const auto &decay_modes = ptype->decay_modes();
582  const auto &modelist = decay_modes.decay_mode_list();
583  int ndecays = ptype->is_stable() ? 1 : modelist.size();
584  printf("%13i %s %10.5f %10.5f %5i %5i %5i %5i %5i %5i %5i %5i\n",
585  ptype->pdgcode().get_decimal(),
586  smash::utf8::fill_left(ptype->name(), 12, ' ').c_str(),
587  ptype->mass(), ptype->width_at_pole(),
588  ptype->pdgcode().spin_degeneracy(), ptype->baryon_number(),
589  ptype->strangeness(), ptype->pdgcode().charmness(),
590  ptype->pdgcode().bottomness(), ptype->isospin() + 1,
591  ptype->charge(), ndecays);
592  if (!ptype->is_stable()) {
593  for (const auto &decay : modelist) {
594  auto ptypes = decay->particle_types();
595  printf("%13i %13i %20.5f %13i %13i %13i %13i %13i\n",
596  ptype->pdgcode().get_decimal(), 2, decay->weight(),
597  ptypes[0]->pdgcode().get_decimal(),
598  ptypes[1]->pdgcode().get_decimal(), 0, 0, 0);
599  }
600  } else {
601  printf("%13i %13i %20.5f %13i %13i %13i %13i %13i\n",
602  ptype->pdgcode().get_decimal(), 1, 1.0,
603  ptype->pdgcode().get_decimal(), 0, 0, 0, 0);
604  }
605  }
606  std::exit(EXIT_SUCCESS);
607  }
608  if (resonance_dump_activated) {
609  // Ignore config values that don't make sense.
610  const auto _dummy = ExperimentBase::create(configuration, "");
613 
614  PdgCode pdg(pdg_string);
615  const ParticleType &res = ParticleType::find(pdg);
617  std::exit(EXIT_SUCCESS);
618  }
619  if (cross_section_dump_activated) {
620  std::string arg_string(cs_string);
621  std::vector<std::string> args = split(arg_string, ',');
622  const unsigned int n_arg = args.size();
623  if (n_arg != 2 && n_arg != 4 && n_arg < 5) {
624  throw std::invalid_argument("-s usage: pdg1,pdg2[,m1,m2[,sqrts1,...]]");
625  }
626  PdgCode pdg_a(args[0]), pdg_b(args[1]);
627  const ParticleType &a = ParticleType::find(pdg_a);
628  const ParticleType &b = ParticleType::find(pdg_b);
629  if (n_arg < 4) {
630  for (unsigned int i = 0; i < 4 - n_arg; i++) {
631  args.push_back("");
632  }
633  }
634  double ma = (args[2] == "") ? a.mass() : std::stod(args[2]);
635  double mb = (args[3] == "") ? b.mass() : std::stod(args[3]);
636  if (a.is_stable() && args[2] != "" && std::stod(args[2]) != a.mass()) {
637  ma = a.mass();
638  std::cerr << "Warning: pole mass is used for stable particle "
639  << a.name() << " instead of " << args[2] << std::endl;
640  }
641  if (b.is_stable() && args[3] != "" && std::stod(args[3]) != b.mass()) {
642  mb = b.mass();
643  std::cerr << "Warning: pole mass is used for stable particle "
644  << b.name() << " instead of " << args[3] << std::endl;
645  }
646  const size_t plab_size = n_arg <= 4 ? 0 : n_arg - 4;
647  std::vector<double> plab;
648  plab.reserve(plab_size);
649  for (size_t i = 4; i < n_arg; i++) {
650  plab.push_back(std::stod(args.at(i)));
651  }
652  auto scat_finder = actions_finder_for_dump(configuration);
653 
656 
657  scat_finder.dump_cross_sections(a, b, ma, mb, final_state_cross_sections,
658  plab);
659  std::exit(EXIT_SUCCESS);
660  }
661  if (modus) {
662  configuration["General"]["Modus"] = std::string(modus);
663  }
664  if (end_time) {
665  configuration["General"]["End_Time"] = std::abs(std::atof(end_time));
666  }
667 
668  int64_t seed = configuration.read({"General", "Randomseed"});
669  if (seed < 0) {
670  configuration["General"]["Randomseed"] = random::generate_63bit_seed();
671  }
672 
673  // Check output path
674  ensure_path_is_valid(output_path);
675  const bf::path lock_path = output_path / "smash.lock";
676  FileLock lock(lock_path);
677  if (!lock.acquire()) {
678  throw std::runtime_error(
679  "Another instance of SMASH is already writing to the specified "
680  "output directory. If you are sure this is not the case, remove \"" +
681  lock_path.native() + "\".");
682  }
683  log.debug("output path: ", output_path);
684  if (!force_overwrite && bf::exists(output_path / "config.yaml")) {
685  throw std::runtime_error(
686  "Output directory would get overwritten. Select a different output "
687  "directory, clean up, or tell SMASH to ignore existing files.");
688  }
689 
690  /* Keep a copy of the configuration that was used in the output directory
691  * also save information about SMASH build as a comment */
692  bf::ofstream(output_path / "config.yaml")
693  << "# " << VERSION_MAJOR << '\n'
694  << "# Branch : " << GIT_BRANCH << '\n'
695  << "# System : " << CMAKE_SYSTEM << '\n'
696  << "# Compiler : " << CMAKE_CXX_COMPILER_ID << ' '
697  << CMAKE_CXX_COMPILER_VERSION << '\n'
698  << "# Build : " << CMAKE_BUILD_TYPE << '\n'
699  << "# Date : " << BUILD_DATE << '\n'
700  << configuration.to_string() << '\n';
701  configuration.take({"particles"});
702  configuration.take({"decaymodes"});
703 
704  // Create an experiment
705  log.trace(source_location, " create Experiment");
706  auto experiment = ExperimentBase::create(configuration, output_path);
707 
708  // Version value is not used in experiment. Get rid of it to prevent
709  // warning.
710  configuration.take({"Version"});
712 
713  // Run the experiment
714  log.trace(source_location, " run the Experiment");
715  experiment->run();
716  } catch (std::exception &e) {
717  log.fatal() << "SMASH failed with the following error:\n" << e.what();
718  return EXIT_FAILURE;
719  }
720 
721  log.trace() << source_location << " about to return from main";
722  return 0;
723 }
int main(int argc, char *argv[])
Main program Smashes Many Accelerated Strongly-Interacting Hadrons :-)
Definition: smash.cc:391
std::string to_string() const
Returns a YAML string of the current tree.
Configuration configuration(std::string overrides={})
Return a configuration object filled with data from src/config.yaml.
Definition: setup.h:161
Exception class that is thrown, if the requested output directory already exists and -f was not speci...
Definition: smash.cc:238
bool acquire()
Try to acquire the file lock.
Definition: filelock.cc:20
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:298
std::string unused_values_report() const
Returns a string listing the key/value pairs that have not been taken yet.
bool is_stable() const
Definition: particletype.h:236
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:318
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.
static void load_decaymodes(const std::string &input)
Loads the DecayModes map as described in the input string.
Definition: decaymodes.cc:163
std::pair< std::string, std::string > load_particles_and_decaymodes(const char *particles_file, const char *decaymodes_file)
Loads particles and decaymodes from provided files particles_file and decaymodes_file.
void ensure_path_is_valid(const bf::path &path)
Ensures the output path is valid.
Definition: smash.cc:276
Value read(std::initializer_list< const char * > keys) const
Additional interface for SMASH to read configuration values without removing them.
std::vector< std::string > split(const std::string &s, char delim)
Split string by delimiter.
Interface to the SMASH configuration files.
ExperimentParameters create_experiment_parameters(Configuration config)
Gathers all general Experiment parameters.
Definition: experiment.cc:326
bool has_value(std::initializer_list< const char * > keys) const
Returns whether there is a non-empty value behind the requested keys.
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.
static const ParticleTypeList & list_all()
Definition: particletype.cc:55
double mass() const
Definition: particletype.h:144
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
const std::string & name() const
Definition: particletype.h:141
#define source_location
Hackery that is required to output the location in the source code where the log statement occurs...
Definition: logging.h:253
Value take(std::initializer_list< const char * > keys)
The default interface for SMASH to read configuration values.
Guard to create a file lock.
Definition: filelock.h:30
Particle type contains the static properties of a particle species.
Definition: particletype.h:97
A simple scatter finder: Just loops through all particles and checks each pair for a collision...
void print_disclaimer()
Print the disclaimer.
Definition: smash.cc:171
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.
constexpr int p
Proton.
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
Exception class that is thrown, if no new output path can be generated (there is a directory name for...
Definition: smash.cc:247
A pointer-like interface to global references to ParticleType objects.
Definition: particletype.h:654
int64_t generate_63bit_seed()
Generates a seed with a truly random 63-bit value, if possible.
Definition: random.cc:17
void dump_width_and_spectral_function() const
Prints out width and spectral function versus mass to the standard output.
Log all message.
Definition: einhard.hpp:106
std::unique_ptr< ExperimentBase > experiment(const Configuration &c=configuration())
Create an experiment.
Definition: setup.h:175
void check_for_unused_config_values(const Configuration &configuration)
Checks if there are unused config values.
Definition: smash.cc:342
Helper structure for Experiment.
void ignore_simulation_config_values(Configuration &configuration)
Remove all config values that are only needed for simulations.
Definition: smash.cc:357
Definition: action.h:24