25 #include "smash/config.h"
153 void usage(
const int rc,
const std::string &progname) {
155 const auto colorize = [](
const auto &color,
156 const std::string s) -> std::string {
157 return color + s + einhard::NoColor_t_::ANSI();
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;
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,
185 bool skip_padding =
true;
186 if (raw_option_length >= effective_option_column_width) {
188 skip_padding =
false;
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;
199 colorize(einhard::Yellow_t_::ANSI(), progname +
" [option]").c_str());
202 print_option(
"-h",
"--help", std::nullopt,
"Print usage information");
203 print_option(
"-v",
"--version", std::nullopt,
"Print version");
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");
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> }'");
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");
234 "-s",
"--cross-sections",
"<pdg1>,<pdg2>[,mass1,mass2[,plab1,...]]",
235 "Print all partial cross-sections of pdg1 + pdg2 reactions versus "
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");
254 <<
"###################################################################"
263 <<
" mss'.. ...s'm. sSA##As mAhh##hsh##s. .hA##ASa sS###As "
265 <<
" :a':'. .'':as sM#' .HHm''HMS''AMs mMA' .AMs aMA. "
267 <<
" .a:s'. ..''ss 'h#H#S. mMm 'M#' .HH. 'MH. :MA 'h#H#S. "
269 <<
" .::ss'. .... 'SMm .HH. SMa hMm sM#..mHMs 'AMa "
271 <<
" .s::' #SMASHh aMS .MH: HM: #MMMmMM. #SMASHh "
274 <<
"###################################################################"
277 <<
" This is SMASH version: " << SMASH_VERSION <<
"\n"
278 <<
" Simulating Many Accelerated Strongly-interacting Hadrons"
281 <<
" Distributed under the GNU General Public License 3.0"
282 <<
" (GPLv3 or later)."
284 <<
" See LICENSE for details."
286 <<
" For the full list of contributors see the AUTHORS.md file."
289 <<
" When using SMASH, please cite"
291 <<
" J. Weil et al., Phys.Rev. C94 (2016) no.5, 054905"
293 <<
" together with the software DOI for the specific code version "
296 <<
" https://doi.org/10.5281/zenodo.3484711"
298 <<
" In addition, if Pythia is used please cite"
300 <<
" C. Bierlich et al, SciPost Phys. Codebases 8 (2022)"
302 <<
" together with the Codebase release you used:"
304 <<
" https://doi.org/10.21468/SciPostPhysCodeb.8-r8.3"
307 <<
" Webpage: https://smash-transport.github.io"
310 <<
" Report issues at https://github.com/smash-transport/smash"
312 <<
" or contact us by email at elfner@itp.uni-frankfurt.de"
315 <<
"###################################################################"
327 using std::runtime_error::runtime_error;
336 using std::runtime_error::runtime_error;
341 const std::filesystem::path
p = std::filesystem::absolute(
"data");
342 if (!std::filesystem::exists(
p)) {
345 std::filesystem::path p2;
346 for (
int id = 0; id < std::numeric_limits<int>::max(); ++id) {
348 if (!std::filesystem::exists(p2)) {
365 if (std::filesystem::exists(path)) {
366 if (!std::filesystem::is_directory(path)) {
368 ") exists, but it is not a directory.");
371 if (!std::filesystem::create_directories(path)) {
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.");
396 throw std::runtime_error(
397 "The following configuration values were not used:\n" +
411 configuration.
take(key);
414 for (
const auto §ion :
438 int main(
int argc,
char *argv[]) {
439 using namespace smash;
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'},
463 const std::string progname =
464 std::filesystem::path(argv[0]).filename().native();
467 bool force_overwrite =
false;
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;
484 while ((opt = getopt_long(argc, argv,
"c:d:e:fhi:m:p:o:t:lr:s:S:xvnq",
485 longopts,
nullptr)) != -1) {
488 extra_config.emplace_back(optarg);
494 force_overwrite =
true;
500 usage(EXIT_SUCCESS, progname);
512 output_path = optarg;
515 custom_tabulations_path = optarg;
518 list2n_activated =
true;
519 suppress_disclaimer =
true;
522 resonance_dump_activated =
true;
524 suppress_disclaimer =
true;
527 final_state_cross_sections =
true;
530 cross_section_dump_activated =
true;
532 suppress_disclaimer =
true;
535 particles_dump_iSS_format =
true;
536 suppress_disclaimer =
true;
544 "System : %s\nCompiler : %s %s\n"
545 "Build : %s\nDate : %s\n",
550 CMAKE_SYSTEM, CMAKE_CXX_COMPILER_ID, CMAKE_CXX_COMPILER_VERSION,
551 CMAKE_BUILD_TYPE, BUILD_DATE);
552 std::exit(EXIT_SUCCESS);
554 cache_integrals =
false;
557 suppress_disclaimer =
true;
560 usage(EXIT_FAILURE, progname);
566 std::cout << argv[0] <<
": invalid argument -- '" << argv[optind]
568 usage(EXIT_FAILURE, progname);
571 if (!suppress_disclaimer) {
576 decaymodes, extra_config);
582 if (!cache_integrals && !custom_tabulations_path.empty()) {
583 throw std::invalid_argument(
584 "--tabulations cannot be used together with --no-cache.");
586 std::string tabulations_path;
587 if (cache_integrals) {
588 if (!custom_tabulations_path.empty()) {
589 tabulations_path = custom_tabulations_path;
591 tabulations_path = output_path.has_parent_path()
592 ? output_path.parent_path().string()
594 tabulations_path +=
"/tabulations";
597 tabulations_path =
"";
599 const std::string version(SMASH_VERSION);
601 if (list2n_activated) {
604 configuration.merge_yaml(
"{Collision_Term: {Two_to_One: False}}");
612 scat_finder.dump_reactions();
613 std::exit(EXIT_SUCCESS);
615 if (particles_dump_iSS_format) {
618 ParticleTypePtrList list;
621 list.push_back(&ptype);
623 std::sort(list.begin(), list.end(),
625 return a->mass() < b->mass();
628 if (ptype->pdgcode().is_lepton() || ptype->baryon_number() < 0) {
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(),
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);
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);
656 std::exit(EXIT_SUCCESS);
658 if (resonance_dump_activated) {
669 std::exit(EXIT_SUCCESS);
671 if (cross_section_dump_activated) {
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,...]]");
680 PdgCode pdg_a(args[0]), pdg_b(args[1]);
684 for (
unsigned int i = 0; i < 4 - n_arg; i++) {
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()) {
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";
697 if (b.
is_stable() && args[3] !=
"" && std::stod(args[3]) != 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";
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)));
715 scat_finder.dump_cross_sections(a, b, ma, mb, final_state_cross_sections,
717 std::exit(EXIT_SUCCESS);
724 std::abs(std::atof(end_time)));
734 const std::filesystem::path lock_path = output_path /
"smash.lock";
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() +
"\".");
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.");
752 std::ofstream(output_path /
"config.yaml")
753 <<
"# " << SMASH_VERSION <<
'\n'
755 <<
"# Branch : " << GIT_BRANCH <<
'\n'
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';
776 }
catch (std::exception &e) {
777 logg[
LMain].fatal() <<
"SMASH failed with the following error:\n"
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 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>.
Guard to create a file lock.
bool acquire()
Try to acquire the file lock.
A pointer-like interface to global references to ParticleType objects.
Particle type contains the static properties of a particle species.
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.
const std::string & name() const
static const ParticleTypeList & list_all()
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
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.
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > & logg
An array that stores all pre-configured Logger objects.
std::unique_ptr< ExperimentBase > experiment(Configuration c)
Create an experiment given an input configuration.
void ignore_simulation_config_values(Configuration &configuration)
Remove all config values that are only needed for simulations.
ScatterActionsFinder actions_finder_for_dump(Configuration &configuration)
Prepares ActionsFinder for cross-section and reaction dumps.
void usage(const int rc, const std::string &progname)
Prints usage information and exits the program.
void ensure_path_is_valid(const std::filesystem::path &path)
Ensures the output path is valid.
void check_for_unused_config_values(const Configuration &configuration)
Checks if there are unused config values.
void print_disclaimer()
Print the disclaimer.
std::filesystem::path default_output_path()
int64_t generate_63bit_seed()
Generates a seed with a truly random 63-bit value, if possible.
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.
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,...
void tabulate_resonance_integrals(const sha256::Hash &hash, const std::string &tabulations_dir)
Tabulate the resonance integrals.
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.
sha256::Hash initialize_particles_decays_and_return_hash(Configuration &configuration, const std::string &version)
Initialize the particles and decays from the given configuration.
ExperimentParameters create_experiment_parameters(Configuration &config)
Gathers all general Experiment parameters.
std::string to_string(ThermodynamicQuantity quantity)
Convert a ThermodynamicQuantity enum value to its corresponding string.
void setup_default_float_traps()
Setup the floating-point traps used throughout SMASH.
static constexpr int LMain
int main(int argc, char *argv[])
Main program Smashes Many Accelerated Strongly-Interacting Hadrons :-)
Helper structure for Experiment.
Exception class that is thrown, if the requested output directory already exists and -f was not speci...
Exception class that is thrown, if no new output path can be generated (there is a directory name for...