Version: SMASH-2.2
configuration.h
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2022
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #ifndef SRC_INCLUDE_SMASH_CONFIGURATION_H_
11 #define SRC_INCLUDE_SMASH_CONFIGURATION_H_
12 
13 #include <array>
14 #include <set>
15 #include <stdexcept>
16 #include <string>
17 #include <utility>
18 #include <vector>
19 
20 #include <yaml-cpp/yaml.h> // NOLINT(build/include_order)
21 
22 #include "density.h"
23 #include "forwarddeclarations.h"
24 
25 namespace YAML {
26 
33 template <typename T>
34 struct convert {
42  static Node encode(const T &x) { return Node{static_cast<std::string>(x)}; }
43 
52  static bool decode(const Node &node, T &x) {
53  if (!node.IsScalar()) {
54  return false;
55  } else {
56  x = static_cast<T>(node.Scalar());
57  return true;
58  }
59  }
60 };
61 } // namespace YAML
62 
63 namespace smash {
475  public:
480  struct IncorrectTypeInAssignment : public std::runtime_error {
481  using std::runtime_error::runtime_error;
482  };
487  struct ParseError : public std::runtime_error {
488  using std::runtime_error::runtime_error;
489  };
490 
495  struct FileDoesNotExist : public std::runtime_error {
496  using std::runtime_error::runtime_error;
497  };
498 
506  class Value {
507  friend class Configuration;
508 
510  const YAML::Node node_;
512  const char *const key_;
513 
520  Value(const YAML::Node &n, const char *key) : node_(n), key_(key) {
521  if (!(n.IsScalar() || n.IsSequence() || n.IsMap())) {
522  std::stringstream err;
523  err << "Configuration value for \"" << key
524  << "\" is missing or invalid";
525  throw std::runtime_error(err.str());
526  }
527  }
528 
529  public:
531  Value(const Value &) = delete;
533  Value &operator=(const Value &) = delete;
534 
561  template <typename T>
562  T convert_for(const T &) const {
563  return *this;
564  }
565 
574  template <typename T>
575  operator T() const {
576  try {
577  return node_.as<T>();
578  } catch (YAML::TypedBadConversion<T> &e) {
580  "The value for key \"" + std::string(key_) +
581  "\" cannot be converted to the requested type.");
582  }
583  }
584 
590  template <typename T>
591  operator std::vector<T>() const {
592  try {
593  return node_.as<std::vector<T>>();
594  } catch (YAML::TypedBadConversion<T> &e) {
596  "One of the values in the sequence for key \"" + std::string(key_) +
597  "\" failed to convert to the requested type. E.g. [1 2] is a "
598  "sequence of one string \"1 2\" and [1, 2] is a sequence of two "
599  "integers. Often there is just a comma missing in the config "
600  "file.");
601  } catch (YAML::TypedBadConversion<std::vector<T>> &e) {
603  "The value for key \"" + std::string(key_) +
604  "\" cannot be converted to the requested type. A sequence was "
605  "expected but apparently not found.");
606  }
607  }
608 
616  template <typename T, size_t N>
617  operator std::array<T, N>() const {
618  const std::vector<T> vec = operator std::vector<T>();
619  const size_t n_read = vec.size();
620  // Alert if size does not match
621  if (n_read != N) {
622  throw IncorrectTypeInAssignment("Wrong number of values in array \"" +
623  std::string(key_) + "\". Expected " +
624  std::to_string(N) +
625  " values,"
626  " found " +
627  std::to_string(n_read) + ".");
628  }
629  std::array<T, N> arr;
630  std::copy_n(vec.begin(), N, arr.begin());
631  return arr;
632  }
633 
641  operator ReactionsBitSet() const {
642  const std::vector<std::string> v = operator std::vector<std::string>();
643  ReactionsBitSet s;
644  for (const auto &x : v) {
645  if (x == "All") {
646  s.set();
647  break;
648  } else if (x == "Elastic") {
650  } else if (x == "NN_to_NR") {
652  } else if (x == "NN_to_DR") {
654  } else if (x == "KN_to_KN") {
656  } else if (x == "KN_to_KDelta") {
658  } else if (x == "Strangeness_exchange") {
660  } else if (x == "NNbar") {
662  } else if (x == "PiDeuteron_to_NN") {
664  } else if (x == "PiDeuteron_to_pidprime") {
666  } else if (x == "NDeuteron_to_Ndprime") {
668  } else {
670  "The value for key \"" + std::string(key_) +
671  "\" should be \"All\", \"Elastic\", \"NN_to_NR\", \"NN_to_DR\","
672  "\"KN_to_KN\", \"KN_to_KDelta\", \"PiDeuteron_to_NN\", "
673  "\"PiDeuteron_to_pidprime\", \"NDeuteron_to_Ndprime\", "
674  "\"Strangeness_exchange\" or "
675  "\"NNbar\", or any combination of these.");
676  }
677  }
678  return s;
679  }
680 
688  operator MultiParticleReactionsBitSet() const {
689  const std::vector<std::string> v = operator std::vector<std::string>();
691  for (const auto &x : v) {
692  if (x == "All") {
693  s.set();
694  break;
695  } else if (x == "Meson_3to1") {
697  } else if (x == "Deuteron_3to2") {
699  } else if (x == "NNbar_5to2") {
701  } else if (x == "A3_Nuclei_4to2") {
703  } else {
705  "The value for key \"" + std::string(key_) +
706  "\" should be \"All\", \"Meson_3to1\", "
707  "\"Deuteron_3to2\" or \"NNbar_5to2\", "
708  "\"A3_Nuclei_4to2\", or any combination of "
709  "these.");
710  }
711  }
712  return s;
713  }
714 
722  operator std::set<ThermodynamicQuantity>() const {
723  const std::vector<std::string> v = operator std::vector<std::string>();
724  std::set<ThermodynamicQuantity> s;
725  for (const auto &x : v) {
726  if (x == "rho_eckart") {
728  } else if (x == "tmn") {
729  s.insert(ThermodynamicQuantity::Tmn);
730  } else if (x == "tmn_landau") {
732  } else if (x == "landau_velocity") {
734  } else if (x == "j_QBS") {
736  } else {
738  "The value for key \"" + std::string(key_) +
739  "\" should be \"rho_eckart\", \"tmn\""
740  ", \"tmn_landau\", \"landau_velocity\" or \"j_QBS\".");
741  }
742  }
743  return s;
744  }
745 
753  operator CalculationFrame() const {
754  const std::string s = operator std::string();
755  if (s == "center of velocity") {
757  }
758  if (s == "center of mass") {
760  }
761  if (s == "fixed target") {
763  }
765  "The value for key \"" + std::string(key_) +
766  "\" should be \"center of velocity\" or \"center of mass\" "
767  "or \"fixed target\".");
768  }
769 
777  operator FermiMotion() const {
778  const std::string s = operator std::string();
779  if (s == "off") {
780  return FermiMotion::Off;
781  }
782  if (s == "on") {
783  return FermiMotion::On;
784  }
785  if (s == "frozen") {
786  return FermiMotion::Frozen;
787  }
789  "The value for key \"" + std::string(key_) +
790  "\" should be \"off\" or \"on\" or \"frozen\".");
791  }
792 
800  operator DensityType() const {
801  const std::string s = operator std::string();
802  if (s == "hadron") {
803  return DensityType::Hadron;
804  }
805  if (s == "baryon") {
806  return DensityType::Baryon;
807  }
808  if (s == "baryonic isospin") {
810  }
811  if (s == "pion") {
812  return DensityType::Pion;
813  }
814  if (s == "total isospin") {
816  }
817  if (s == "none") {
818  return DensityType::None;
819  }
820  throw IncorrectTypeInAssignment("The value for key \"" +
821  std::string(key_) +
822  "\" should be \"hadron\" or \"baryon\" "
823  "or \"baryonic isospin\" or \"pion\" "
824  "or \"none\".");
825  }
826 
834  operator ExpansionMode() const {
835  const std::string s = operator std::string();
836  if (s == "NoExpansion") {
838  }
839  if (s == "MasslessFRW") {
841  }
842  if (s == "MassiveFRW") {
844  }
845  if (s == "Exponential") {
847  }
849  "The value for key \"" + std::string(key_) +
850  "\" should be \"NoExpansion\", \"MasslessFRW\"," +
851  "\"MassiveFRW\" or \"Exponential\".");
852  }
853 
857  operator DerivativesMode() const {
858  const std::string s = operator std::string();
859  if (s == "Covariant Gaussian") {
861  }
862  if (s == "Finite difference") {
864  }
865  if (s == "Off") {
866  return DerivativesMode::Off;
867  }
869  "The value for key \"" + std::string(key_) +
870  "\" should be \"Covariant Gaussian\", \"Finite difference\"," +
871  " or \"Off\".");
872  }
873 
878  const std::string s = operator std::string();
879  if (s == "On") {
881  }
882  if (s == "Off") {
884  }
885  throw IncorrectTypeInAssignment("The value for key \"" +
886  std::string(key_) +
887  "\" should be \"On\" or \"Off\".");
888  }
889 
893  operator FieldDerivativesMode() const {
894  const std::string s = operator std::string();
895  if (s == "Chain Rule") {
897  }
898  if (s == "Direct") {
900  }
902  "The value for key \"" + std::string(key_) +
903  "\" should be \"Chain Rule\" or \"Direct\".");
904  }
905 
909  operator SmearingMode() const {
910  const std::string s = operator std::string();
911  if (s == "Covariant Gaussian") {
913  }
914  if (s == "Discrete") {
915  return SmearingMode::Discrete;
916  }
917  if (s == "Triangular") {
919  }
921  "The value for key \"" + std::string(key_) +
922  "\" should be \"Covariant Gaussian\", \"Discrete\"," +
923  " or \"Triangular\".");
924  }
925 
933  operator TimeStepMode() const {
934  const std::string s = operator std::string();
935  if (s == "None") {
936  return TimeStepMode::None;
937  }
938  if (s == "Fixed") {
939  return TimeStepMode::Fixed;
940  }
941  throw IncorrectTypeInAssignment("The value for key \"" +
942  std::string(key_) +
943  "\" should be \"None\" or \"Fixed\".");
944  }
945 
953  operator BoxInitialCondition() const {
954  const std::string s = operator std::string();
955  if (s == "thermal momenta") {
957  }
958  if (s == "thermal momenta quantum") {
960  }
961  if (s == "peaked momenta") {
963  }
965  "The value for key \"" + std::string(key_) +
966  "\" should be \"thermal momenta\", \"thermal momenta quantum\", " +
967  "or \"peaked momenta\".");
968  }
969 
977  operator SphereInitialCondition() const {
978  const std::string s = operator std::string();
979  if (s == "thermal momenta") {
981  }
982  if (s == "thermal momenta quantum") {
984  }
985  if (s == "IC_ES") {
987  }
988  if (s == "IC_1M") {
990  }
991  if (s == "IC_2M") {
993  }
994  if (s == "IC_Massive") {
996  }
998  "The value for key \"" + std::string(key_) +
999  "\" should be \"thermal momenta\", \"thermal momenta quantum\", " +
1000  "\"IC_ES\", \"IC_1M\", \"IC_2M\" or" + "\"IC_Massive\".");
1001  }
1002 
1010  operator NNbarTreatment() const {
1011  const std::string s = operator std::string();
1012  if (s == "no annihilation") {
1014  }
1015  if (s == "resonances") {
1017  }
1018  if (s == "two to five") {
1020  }
1021  if (s == "strings") {
1022  return NNbarTreatment::Strings;
1023  }
1025  "The value for key \"" + std::string(key_) + "\" should be " +
1026  "\"no annihilation\", \"resonances\", \"two to five\" or " +
1027  " \"strings\".");
1028  }
1029 
1037  operator Sampling() const {
1038  const std::string s = operator std::string();
1039  if (s == "quadratic") {
1040  return Sampling::Quadratic;
1041  }
1042  if (s == "custom") {
1043  return Sampling::Custom;
1044  }
1045  if (s == "uniform") {
1046  return Sampling::Uniform;
1047  }
1049  "The value for key \"" + std::string(key_) +
1050  "\" should be \"quadratic\", \"uniform\" or \"custom\".");
1051  }
1052 
1060  operator ThermalizationAlgorithm() const {
1061  const std::string s = operator std::string();
1062  if (s == "mode sampling") {
1064  }
1065  if (s == "biased BF") {
1067  }
1068  if (s == "unbiased BF") {
1070  }
1072  "The value for key \"" + std::string(key_) +
1073  "\" should be \"mode sampling\", \"biased BF\" or \"unbiased BF\".");
1074  }
1075 
1083  operator CollisionCriterion() const {
1084  const std::string s = operator std::string();
1085  if (s == "Geometric") {
1087  }
1088  if (s == "Stochastic") {
1090  }
1091  if (s == "Covariant") {
1093  }
1095  "The value for key \"" + std::string(key_) + "\" should be " +
1096  "\"Geometric\", \"Stochastic\" " + "or \"Covariant\".");
1097  }
1098 
1106  operator OutputOnlyFinal() const {
1107  const std::string s = operator std::string();
1108  if (s == "Yes") {
1109  return OutputOnlyFinal::Yes;
1110  }
1111  if (s == "No") {
1112  return OutputOnlyFinal::No;
1113  }
1114  if (s == "IfNotEmpty") {
1116  }
1117  throw IncorrectTypeInAssignment("The value for key \"" +
1118  std::string(key_) + "\" should be " +
1119  "\"Yes\", \"No\" or \"IfNotEmpty\".");
1120  }
1121  };
1122 
1126  static const char InitializeFromYAMLString = 'S';
1127 
1133  explicit Configuration(const bf::path &path);
1134 
1142  explicit Configuration(const bf::path &path, const bf::path &filename);
1143 
1152  explicit Configuration(const char *yaml, const char sflag) {
1153  if (sflag == InitializeFromYAMLString) {
1154  merge_yaml(yaml);
1155  } else {
1156  throw std::runtime_error(
1157  "Unknown control flag in Configuration constructor"
1158  " with a YAML formatted string. Please, use"
1159  " Configuration::InitializeFromYAMLString.");
1160  }
1161  }
1162 
1168  explicit Configuration(int invalue) {
1169  if (invalue == 0) {
1170  invalue = 1;
1171  }
1172  }
1173 
1174 #ifdef BUILD_TESTS
1183  explicit Configuration(const char *yaml) : root_node_(YAML::Load(yaml)) {}
1184 #endif
1185 
1187  Configuration(const Configuration &) = default;
1190 
1195 
1206  void merge_yaml(const std::string &yaml);
1207 
1209  std::vector<std::string> list_upmost_nodes();
1210 
1232  Value take(std::initializer_list<const char *> keys);
1233 
1235  template <typename T>
1236  T take(std::initializer_list<const char *> keys, T default_value) {
1237  if (has_value(keys)) {
1238  return take(keys);
1239  }
1240  return default_value;
1241  }
1242 
1257  Value read(std::initializer_list<const char *> keys) const;
1258 
1260  template <typename T>
1261  T read(std::initializer_list<const char *> keys, T default_value) {
1262  if (has_value(keys)) {
1263  return read(keys);
1264  }
1265  return default_value;
1266  }
1267 
1273  void remove_all_but(const std::string &key);
1274 
1289  template <typename T>
1291  return root_node_[std::forward<T>(key)];
1292  }
1293 
1301  template <typename T>
1302  Configuration &operator=(T &&value) {
1303  root_node_ = std::forward<T>(value);
1304  return *this;
1305  }
1306 
1312  std::initializer_list<const char *> keys) const;
1317  bool has_value(std::initializer_list<const char *> keys) const;
1318 
1322  std::string unused_values_report() const;
1323 
1329  std::string to_string() const;
1330 
1331  private:
1338  Configuration(const YAML::Node &node) // NOLINT(runtime/explicit) : see above
1339  : root_node_(node) {}
1340 
1342  YAML::Node root_node_;
1343 };
1344 
1345 } // namespace smash
1346 
1347 #endif // SRC_INCLUDE_SMASH_CONFIGURATION_H_
Return type of Configuration::take that automatically determines the target type.
Value(const YAML::Node &n, const char *key)
Constructs the Value wrapper from a YAML::Node.
Value(const Value &)=delete
If you want to copy this you're doing it wrong.
T convert_for(const T &) const
Convert the value to the type of the supplied argument.
const char *const key_
The key to be interpreted.
const YAML::Node node_
a YAML leaf node
Value & operator=(const Value &)=delete
If you want to copy this you're doing it wrong.
Interface to the SMASH configuration files.
bool has_value(std::initializer_list< const char * > keys) const
Returns whether there is a non-empty value behind the requested keys.
Configuration & operator=(const Configuration &)=default
If you want to copy this you're doing it wrong.
void merge_yaml(const std::string &yaml)
Merge the configuration in yaml into the existing tree.
std::string to_string() const
Returns a YAML string of the current tree.
bool has_value_including_empty(std::initializer_list< const char * > keys) const
Returns if there is a (maybe empty) value behind the requested keys.
std::string unused_values_report() const
Returns a string listing the key/value pairs that have not been taken yet.
Configuration(const Configuration &)=default
If you want to copy this you're doing it wrong.
void remove_all_but(const std::string &key)
Removes all entries in the map except for key.
Configuration & operator=(Configuration &&)=default
Moving is fine.
YAML::Node root_node_
the general_config.yaml contents - fully parsed
Configuration(const bf::path &path)
Reads config.yaml from the specified path.
Configuration(int invalue)
Trivial constructor for testing purposes.
Configuration(const YAML::Node &node)
Creates a subobject that has its root node at the given node.
Configuration & operator=(T &&value)
Assignment overwrites the value of the current YAML node.
Configuration(const char *yaml)
Value take(std::initializer_list< const char * > keys)
The default interface for SMASH to read configuration values.
Configuration(const char *yaml, const char sflag)
Initialize configuration with a YAML formatted string.
Configuration operator[](T &&key)
Access to the YAML::Node behind the requested keys.
Configuration(Configuration &&)=default
Moving is fine.
Value read(std::initializer_list< const char * > keys) const
Additional interface for SMASH to read configuration values without removing them.
T take(std::initializer_list< const char * > keys, T default_value)
static const char InitializeFromYAMLString
Flag to mark initialization with a YAML formatted string.
T read(std::initializer_list< const char * > keys, T default_value)
std::vector< std::string > list_upmost_nodes()
Lists all YAML::Nodes from the configuration setup.
SmearingMode
Modes of smearing.
FermiMotion
Option to use Fermi Motion.
@ On
Use fermi motion in combination with potentials.
@ Frozen
Use fermi motion without potentials.
@ Off
Don't use fermi motion.
std::bitset< 10 > ReactionsBitSet
Container for the 2 to 2 reactions in the code.
ThermalizationAlgorithm
Defines the algorithm used for the forced thermalization.
NNbarTreatment
Treatment of N Nbar Annihilation.
@ NoAnnihilation
No Annihilation.
@ TwoToFive
Directly create 5 pions, use with multi-particle reactions.
@ Resonances
Use intermediate Resonances.
@ Strings
Use string fragmentation.
RestFrameDensityDerivativesMode
Modes of calculating the gradients: whether to calculate the rest frame density derivatives.
TimeStepMode
The time step mode.
@ Fixed
Use fixed time step.
@ None
Don't use time steps; propagate from action to action.
Sampling
Possible methods of impact parameter sampling.
@ Quadratic
Sample from areal / quadratic distribution.
@ Custom
Sample from custom, user-defined distribution.
@ Uniform
Sample from uniform distribution.
std::bitset< 4 > MultiParticleReactionsBitSet
Container for the n to m reactions in the code.
CalculationFrame
The calculation frame.
@ NNbar_5to2
@ A3_Nuclei_4to2
@ Deuteron_3to2
@ Meson_3to1
DerivativesMode
Modes of calculating the gradients.
CollisionCriterion
Criteria used to check collisions.
@ Stochastic
Stochastic Criteiron.
@ Geometric
(Default) geometric criterion.
@ Covariant
Covariant Criterion.
FieldDerivativesMode
Modes of calculating the field gradients: chain rule or direct.
SphereInitialCondition
Initial condition for a particle in a sphere.
@ KN_to_KDelta
@ KN_to_KN
@ NN_to_NR
@ PiDeuteron_to_pidprime
@ NDeuteron_to_Ndprime
@ Strangeness_exchange
@ PiDeuteron_to_NN
@ NN_to_DR
OutputOnlyFinal
Whether and when only final state particles should be printed.
@ IfNotEmpty
Print only final-state particles, and those only if the event is not empty.
@ Yes
Print only final-state particles.
@ No
Print initial, intermediate and final-state particles.
BoxInitialCondition
Initial condition for a particle in a box.
ExpansionMode
Defines properties of expansion for the metric (e.g.
constexpr int n
Neutron.
Definition: action.h:24
DensityType
Allows to choose which kind of density to calculate.
Definition: density.h:36
Convert from YAML::Node to SMASH-readable (C++) format and vice versa.
Definition: configuration.h:34
static bool decode(const Node &node, T &x)
Deserialization: Converts a YAML::Node to any SMASH-readable data type and returns whether or not thi...
Definition: configuration.h:52
static Node encode(const T &x)
Serialization: Converts x (of any type) to a YAML::Node.
Definition: configuration.h:42
Thrown if the file does not exist.
Thrown when the types in the config file and C++ don't match.
Thrown for YAML parse errors.