diff --git a/include/HEJ/Fraction.hh b/include/HEJ/Fraction.hh index d7d9e68..358420d 100644 --- a/include/HEJ/Fraction.hh +++ b/include/HEJ/Fraction.hh @@ -1,62 +1,45 @@ /** \file * \brief Header file for fractions, i.e. floating point numbers between 0 and 1. * * \authors The HEJ collaboration (see AUTHORS for details) * \date 2020 * \copyright GPLv2 or later */ #pragma once #include <stdexcept> #include <string> #include <type_traits> -#include "yaml-cpp/yaml.h" - namespace HEJ { //! Class for floating point numbers between 0 and 1 template< class Real, typename = std::enable_if_t<std::is_floating_point<Real>::value> > class Fraction { public: Fraction() = default; explicit Fraction(Real r): f_{r} { if(f_ < 0 || f_ > 1) { throw std::invalid_argument{ std::to_string(f_) + " is not between 0 and 1" }; } } Fraction & operator=(Real r) { f_ = Fraction{r}; return *this; } operator Real() const { return f_; } private: Real f_; }; } - -namespace YAML { - template<class Real> - struct convert<HEJ::Fraction<Real>> { - static Node encode(HEJ::Fraction<Real> const & f) { - return encode(Real{f}); - } - static bool decode(Node const & node, HEJ::Fraction<Real> & f) { - Real r; - if(!convert<Real>::decode(node, r)) return false; - f = r; - return true; - } - }; -} diff --git a/include/HEJ/YAMLreader.hh b/include/HEJ/YAMLreader.hh index 993fbc7..c4b5641 100644 --- a/include/HEJ/YAMLreader.hh +++ b/include/HEJ/YAMLreader.hh @@ -1,253 +1,267 @@ /** \file * \brief The file which handles the configuration file parameters * * The configuration files parameters are read and then stored * within this objects. * * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <string> #include <utility> #include <vector> #include "yaml-cpp/yaml.h" #include "fastjet/JetDefinition.hh" #include "HEJ/Config.hh" #include "HEJ/exceptions.hh" +#include "HEJ/Fraction.hh" #include "HEJ/optional.hh" #include "HEJ/PDG_codes.hh" #include "HEJ/utility.hh" namespace HEJ{ class OutputFile; //! Load configuration from file /** * @param config_file Name of the YAML configuration file * @returns The HEJ 2 configuration */ Config load_config(std::string const & config_file); //! Set option using the corresponding YAML entry /** * @param setting Option variable to be set * @param yaml Root of the YAML configuration * @param names Name of the entry * * If the entry does not exist or has the wrong type or format * an exception is thrown. * * For example * @code * set_from_yaml(foobar, yaml, "foo", "bar") * @endcode * is equivalent to * @code * foobar = yaml["foo"]["bar"].as<decltype(foobar)>() * @endcode * with improved diagnostics on errors. * * @see set_from_yaml_if_defined */ template<typename T, typename... YamlNames> void set_from_yaml( T & setting, YAML::Node const & yaml, YamlNames const & ... names ); //! Set option using the corresponding YAML entry, if present /** * @param setting Option variable to be set * @param yaml Root of the YAML configuration * @param names Name of the entry * * This function works similar to set_from_yaml, but does not * throw any exception if the requested YAML entry does not exist. * * @see set_from_yaml */ template<typename T, typename... YamlNames> void set_from_yaml_if_defined( T & setting, YAML::Node const & yaml, YamlNames const & ... names ); //! Extract jet parameters from YAML configuration JetParameters get_jet_parameters( YAML::Node const & node, std::string const & entry ); //! Extract Higgs coupling settings from YAML configuration HiggsCouplingSettings get_Higgs_coupling( YAML::Node const & node, std::string const & entry ); //! Extract scale setting parameters from YAML configuration ScaleConfig to_ScaleConfig(YAML::Node const & yaml); //! Extract random number generator settings from YAML configuration RNGConfig to_RNGConfig(YAML::Node const & node, std::string const & entry); //! Check whether all options in configuration are supported /** * @param conf Configuration to be checked * @param supported Tree of supported options * * If conf contains an entry that does not appear in supported * an unknown_option exception is thrown. Sub-entries of "analysis" * (if present) are not checked. * * @see unknown_option */ void assert_all_options_known( YAML::Node const & conf, YAML::Node const & supported ); namespace detail{ void set_from_yaml(fastjet::JetAlgorithm & setting, YAML::Node const & yaml); void set_from_yaml(EventTreatment & setting, YAML::Node const & yaml); void set_from_yaml(ParticleID & setting, YAML::Node const & yaml); void set_from_yaml(OutputFile & setting, YAML::Node const & yaml); void set_from_yaml(WeightType & setting, YAML::Node const & yaml); inline void set_from_yaml(YAML::Node & setting, YAML::Node const & yaml){ setting = yaml; } template<typename Scalar> void set_from_yaml(Scalar & setting, YAML::Node const & yaml){ assert(yaml); if(!yaml.IsScalar()){ throw invalid_type{"value is not a scalar"}; } try{ setting = yaml.as<Scalar>(); } catch(...){ throw invalid_type{ "value " + yaml.as<std::string>() + " cannot be converted to a " + type_string(setting) }; } } template<typename T> void set_from_yaml(optional<T> & setting, YAML::Node const & yaml){ T tmp; set_from_yaml(tmp, yaml); setting = tmp; } template<typename T> void set_from_yaml(std::vector<T> & setting, YAML::Node const & yaml){ assert(yaml); // special case: treat a single value like a vector with one element if(yaml.IsScalar()){ setting.resize(1); return set_from_yaml(setting.front(), yaml); } if(yaml.IsSequence()){ setting.resize(yaml.size()); for(size_t i = 0; i < setting.size(); ++i){ set_from_yaml(setting[i], yaml[i]); } return; } throw invalid_type{""}; } template<typename T, typename FirstName, typename... YamlNames> void set_from_yaml( T & setting, YAML::Node const & yaml, FirstName const & name, YamlNames && ... names ){ if(!yaml[name]) throw missing_option{""}; set_from_yaml( setting, yaml[name], std::forward<YamlNames>(names)... ); } template<typename T> void set_from_yaml_if_defined(T & setting, YAML::Node const & yaml){ return set_from_yaml(setting, yaml); } template<typename T, typename FirstName, typename... YamlNames> void set_from_yaml_if_defined( T & setting, YAML::Node const & yaml, FirstName const & name, YamlNames && ... names ){ if(!yaml[name]) return; set_from_yaml_if_defined( setting, yaml[name], std::forward<YamlNames>(names)... ); } } // namespace detail template<typename T, typename... YamlNames> void set_from_yaml( T & setting, YAML::Node const & yaml, YamlNames const & ... names ){ try{ detail::set_from_yaml(setting, yaml, names...); } catch(invalid_type const & ex){ throw invalid_type{ "In option " + join(": ", names...) + ": " + ex.what() }; } catch(missing_option const &){ throw missing_option{ "No entry for mandatory option " + join(": ", names...) }; } catch(std::invalid_argument const & ex){ throw missing_option{ "In option " + join(": ", names...) + ":" " invalid value " + ex.what() }; } } template<typename T, typename... YamlNames> void set_from_yaml_if_defined( T & setting, YAML::Node const & yaml, YamlNames const & ... names ){ try{ detail::set_from_yaml_if_defined(setting, yaml, names...); } catch(invalid_type const & ex){ throw invalid_type{ "In option " + join(": ", names...) + ": " + ex.what() }; } catch(std::invalid_argument const & ex){ throw missing_option{ "In option " + join(": ", names...) + ":" " invalid value " + ex.what() }; } } } // namespace HEJ namespace YAML { template<> struct convert<HEJ::OutputFile> { static Node encode(HEJ::OutputFile const & outfile); static bool decode(Node const & node, HEJ::OutputFile & out); }; + + template<class Real> + struct convert<HEJ::Fraction<Real>> { + static Node encode(HEJ::Fraction<Real> const & f) { + return encode(Real{f}); + } + static bool decode(Node const & node, HEJ::Fraction<Real> & f) { + Real r; + if(!convert<Real>::decode(node, r)) return false; + f = r; + return true; + } + }; }