Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F8725672
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
23 KB
Subscribers
None
View Options
diff --git a/include/RHEJ/exceptions.hh b/include/RHEJ/exceptions.hh
new file mode 100644
index 0000000..c099823
--- /dev/null
+++ b/include/RHEJ/exceptions.hh
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <stdexcept>
+
+namespace RHEJ{
+ struct invalid_type: std::invalid_argument {
+ explicit invalid_type(std::string const & what):
+ std::invalid_argument{what} {};
+ explicit invalid_type(char const * what):
+ std::invalid_argument{what} {};
+ };
+
+ struct unknown_option: std::invalid_argument {
+ explicit unknown_option(std::string const & what):
+ std::invalid_argument{what} {};
+ explicit unknown_option(char const * what):
+ std::invalid_argument{what} {};
+ };
+
+ struct missing_option: std::logic_error {
+ explicit missing_option(std::string const & what):
+ std::logic_error{what} {};
+ explicit missing_option(char const * what):
+ std::logic_error{what} {};
+ };
+}
diff --git a/src/EmptyAnalysis.cc b/src/EmptyAnalysis.cc
index 76067f5..0ebf987 100644
--- a/src/EmptyAnalysis.cc
+++ b/src/EmptyAnalysis.cc
@@ -1,42 +1,54 @@
#include "RHEJ/EmptyAnalysis.hh"
+#include "RHEJ/exceptions.hh"
#include <iostream>
#include <string>
+#include <vector>
#include "yaml-cpp/yaml.h"
namespace RHEJ{
namespace{
- void warn_ignore(std::string const & what){
- std::cerr << "WARNING: ignoring unknown analysis parameter "
- << what << '\n';
- }
-
- void warn_unless_empty(YAML::Node const & parameters){
+ std::vector<std::string> param_as_strings(YAML::Node const & parameters){
using YAML::NodeType;
switch(parameters.Type()){
case NodeType::Null:
case NodeType::Undefined:
- return;
+ return {};
case NodeType::Scalar:
- return warn_ignore(parameters.as<std::string>());
- case NodeType::Sequence:
- for(auto && param: parameters) warn_ignore(param.as<std::string>());
- return;
- case NodeType::Map:
- for(auto && param: parameters) warn_ignore(param.first.as<std::string>());
- return;
+ return {parameters.as<std::string>()};
+ case NodeType::Sequence: {
+ std::vector<std::string> param_strings;
+ for(auto && param: parameters){
+ param_strings.emplace_back(param.as<std::string>());
+ }
+ return param_strings;
+ }
+ case NodeType::Map: {
+ std::vector<std::string> param_strings;
+ for(auto && param: parameters){
+ param_strings.emplace_back(param.first.as<std::string>());
+ }
+ return param_strings;
}
+ default:;
+ }
+ throw std::logic_error{"unreachable"};
}
}
std::unique_ptr<Analysis> EmptyAnalysis::create(
YAML::Node const & parameters
){
- warn_unless_empty(parameters);
+ const auto param_strings = param_as_strings(parameters);
+ if(! param_strings.empty()){
+ std::string error{"Unknown analysis parameter(s):"};
+ for(auto && p: param_strings) error += " " + p;
+ throw unknown_option{error};
+ }
return std::unique_ptr<Analysis>{new EmptyAnalysis{}};
}
void EmptyAnalysis::fill(Event const &){
// do nothing
}
}
diff --git a/src/config.cc b/src/config.cc
index 9ba7ca4..e7e9f5e 100644
--- a/src/config.cc
+++ b/src/config.cc
@@ -1,622 +1,606 @@
#include "RHEJ/config.hh"
+#include "RHEJ/exceptions.hh"
#include <set>
#include <string>
#include <vector>
#include <iostream>
#include <stdexcept>
namespace RHEJ{
FileFormat to_FileFormat(std::string const & name){
static const std::map<std::string, FileFormat> known = {
{"Les Houches", FileFormat::Les_Houches},
{"HepMC", FileFormat::HepMC}
};
const auto res = known.find(name);
if(res == known.end()){
throw std::invalid_argument("Unknown file format " + name);
}
return res->second;
}
std::string extract_suffix(std::string const & filename){
size_t separator = filename.rfind('.');
if(separator == filename.npos) return {};
return filename.substr(separator + 1);
}
FileFormat format_from_suffix(std::string const & filename){
const std::string suffix = extract_suffix(filename);
if(suffix == "lhe") return FileFormat::Les_Houches;
if(suffix == "hepmc3") return FileFormat::HepMC;
throw std::invalid_argument{
"Can't determine format for output file " + filename
};
}
}
namespace YAML {
std::string to_string(NodeType::value type){
switch (type) {
case NodeType::Null: return "Null";
case NodeType::Scalar: return "Scalar";
case NodeType::Sequence: return "Sequence";
case NodeType::Map: return "Map";
case NodeType::Undefined: return "Undefined";
default:
throw std::logic_error{"Missing case in switch statement"};
}
}
template<>
struct convert<RHEJ::OutputFile> {
static Node encode(RHEJ::OutputFile const & outfile) {
Node node;
node[to_string(outfile.format)] = outfile.name;
return node;
}
static bool decode(Node const & node, RHEJ::OutputFile & out) {
switch(node.Type()){
case NodeType::Map: {
YAML::const_iterator it = node.begin();
out.format = RHEJ::to_FileFormat(it->first.as<std::string>());
out.name = it->second.as<std::string>();
return true;
}
case NodeType::Scalar:
out.name = node.as<std::string>();
out.format = RHEJ::format_from_suffix(out.name);
return true;
default:
return false;
}
}
};
}
namespace RHEJ{
namespace{
- struct invalid_type: std::invalid_argument {
- explicit invalid_type(std::string const & what):
- std::invalid_argument{what} {};
- explicit invalid_type(char const * what):
- std::invalid_argument{what} {};
- };
-
- struct missing_option: std::logic_error {
- explicit missing_option(std::string const & what):
- std::logic_error{what} {};
- explicit missing_option(char const * what):
- std::logic_error{what} {};
- };
-
static const std::set<std::string> known = {
{"trials"},
{"min extparton pt"}, {"max ext soft pt fraction"},
{"resummation jets"}, {"fixed order jets"},
{"FKL"}, {"non-FKL"}, {"unordered"},
{"log correction"},
{"event output"},
{"analysis"},
{"unweight"}, {"RanLux init"},
{"scales"}, {"scale factors"}, {"max scale ratio"},
{"Higgs coupling"}
};
static const std::set<std::string> known_jet = {
{"min pt"}, {"algorithm"}, {"R"}
};
template<typename T>
std::string type_string();
template<>
std::string type_string<std::vector<double>>(){
return "array of doubles";
}
template<>
std::string type_string<std::vector<std::string>>(){
return "array of strings";
}
template<>
std::string type_string<int>(){
return "integer";
}
template<>
std::string type_string<double>(){
return "double";
}
template<>
std::string type_string<bool>(){
return "bool";
}
template<>
std::string type_string<std::string>(){
return "string";
}
template<>
std::string type_string<std::vector<OutputFile>>(){
return "array of output files";
}
fastjet::JetAlgorithm to_JetAlgorithm(std::string const & algo){
using namespace fastjet;
static const std::map<std::string, fastjet::JetAlgorithm> known = {
{"kt", kt_algorithm},
{"cambridge", cambridge_algorithm},
{"antikt", antikt_algorithm},
{"genkt", genkt_algorithm},
{"cambridge for passive", cambridge_for_passive_algorithm},
{"genkt for passive", genkt_for_passive_algorithm},
{"ee kt", ee_kt_algorithm},
{"ee genkt", ee_genkt_algorithm},
{"plugin", plugin_algorithm}
};
const auto res = known.find(algo);
if(res == known.end()){
throw std::invalid_argument("Unknown jet algorithm " + algo);
}
return res->second;
}
EventTreatment to_EventTreatment(std::string const & name){
static const std::map<std::string, EventTreatment> known = {
{"reweight", EventTreatment::reweight},
{"keep", EventTreatment::keep},
{"discard", EventTreatment::discard}
};
const auto res = known.find(name);
if(res == known.end()){
throw std::invalid_argument("Unknown event treatment " + name);
}
return res->second;
}
// helper struct to allow partial template specialisation
template<typename T>
struct existing_as_helper{
static T as(YAML::Node const & config, std::string const & entry){
assert(config[entry]);
try{
return config[entry].as<T>();
}
catch(std::exception const &){
throw invalid_type{
"Entry " + entry + " is not of type " + type_string<T>()
};
}
}
};
template<>
struct existing_as_helper<fastjet::JetAlgorithm>{
static fastjet::JetAlgorithm as(
YAML::Node const & config, std::string const & entry
){
assert(config[entry]);
const std::string algo_name =
existing_as_helper<std::string>::as(config, entry);
return to_JetAlgorithm(algo_name);
}
};
template<>
struct existing_as_helper<EventTreatment>{
static EventTreatment as(
YAML::Node const & config, std::string const & entry
){
assert(config[entry]);
const std::string name =
existing_as_helper<std::string>::as(config, entry);
return to_EventTreatment(name);
}
};
template<>
struct existing_as_helper<OutputFile>{
static OutputFile as(
YAML::Node const & config, std::string const & entry
){
assert(config[entry]);
YAML::convert<RHEJ::OutputFile> converter{};
OutputFile out;
if(converter.decode(config[entry], out)) return out;
throw std::invalid_argument{
"Bad output file setting: " + config[entry].as<std::string>()
};
}
};
template<typename T>
struct existing_as_helper<std::vector<T>>{
static std::vector<T> as(
YAML::Node const & config, std::string const & entry
){
assert(config[entry]);
// special case: treat a single value like a vector with one element
if(config[entry].IsScalar()){
return {existing_as_helper<T>::as(config, entry)};
}
try{
return config[entry].as<std::vector<T>>();
}
catch(std::exception const & p){
std::cerr << "Error: " << p.what() << '\n';
throw invalid_type{
"Entry " + entry + " is not of type " + type_string<std::vector<T>>()
};
}
}
};
template<typename T>
T existing_as(YAML::Node const & config, std::string const & entry){
return existing_as_helper<T>::as(config, entry);
}
template<typename T>
T as(YAML::Node const & config, std::string const & entry);
template<>
JetParameters existing_as<JetParameters>(
YAML::Node const & config, std::string const & entry
){
assert(config[entry]);
YAML::Node const & jet_config = config[entry];
JetParameters result;
for(auto const & opt: jet_config){
auto const & opt_name = opt.first.as<std::string>();
if(! known_jet.count(opt_name)){
- std::cerr << "In entry " + entry + ": "
- + "Unknown option " + opt_name + "\n";
+ throw unknown_option{"Unknown option " + opt_name};
}
}
try{
result.def = fastjet::JetDefinition{
as<fastjet::JetAlgorithm>(jet_config, "algorithm"),
as<double>(jet_config, "R")
};
result.min_pt = as<double>(jet_config, "min pt");
return result;
}
catch(missing_option const & exc){
throw missing_option{"In entry " + entry + ":\n" + exc.what()};
}
catch(invalid_type const & exc){
throw invalid_type{"In entry " + entry + ":\n" + exc.what()};
}
}
template<typename T>
T as(YAML::Node const & config, std::string const & entry){
if(!config[entry]){
throw missing_option{"No entry for option " + entry};
}
return existing_as<T>(config, entry);
}
template<typename T>
optional<T> as_optional(YAML::Node const & config, std::string const & entry){
if(!config[entry]) return {};
return {existing_as<T>(config, entry)};
}
template<>
HiggsCouplingSettings as<HiggsCouplingSettings>(
YAML::Node const & config, std::string const & entry
){
static constexpr double mt_max = 2e4;
HiggsCouplingSettings settings;
if(!config[entry]) return settings;
#ifndef RHEJ_BUILD_WITH_QCDLOOP
throw std::invalid_argument{
"Higgs coupling settings require building Reversed HEJ "
"with QCDloop support"
};
#endif
YAML::Node const & node = config[entry];
if(!node.IsMap()){
throw std::invalid_argument{
"entry '" + entry + "' is a " + to_string(node.Type())
+ ", not a Map of properties"
};
}
for(auto const & property: node){
const auto key = property.first.as<std::string>();
auto const & value = property.second;
if(key == "mt") settings.mt = value.as<double>();
else if(key == "mb") settings.mb = value.as<double>();
else if(key == "include bottom"){
settings.include_bottom = value.as<bool>();
}
else if(key == "use impact factors"){
settings.use_impact_factors = value.as<bool>();
}
else{
- std::cerr << "WARNING: unknown option '" << key
- << "' in '" << entry << "'\n";
+ throw unknown_option{"Unknown option '" + key + "'"};
}
}
if(settings.use_impact_factors){
if(settings.mt != std::numeric_limits<double>::infinity()){
throw std::invalid_argument{
"Conflicting settings: "
"impact factors may only be used in the infinite top mass limit"
};
}
}
else{
// huge values of the top mass are numerically unstable
settings.mt = std::min(settings.mt, mt_max);
}
return settings;
}
void update_fixed_order_jet_parameters(
JetParameters & fixed_order_jets, YAML::Node const & yaml
){
YAML::Node const & yaml_jets = yaml["fixed order jets"];
assert(yaml_jets);
for(auto const & opt: yaml_jets){
auto const & opt_name = opt.first.as<std::string>();
if(! known_jet.count(opt_name)){
- std::cerr << "In entry fixed order jets: "
- "Unknown option " + opt_name + "\n";
+ throw unknown_option{"Unknown option '" + opt_name + "'"};
}
}
try{
auto algo = as_optional<fastjet::JetAlgorithm>(yaml_jets, "algorithm");
if(algo){
fixed_order_jets.def = fastjet::JetDefinition{
*algo, fixed_order_jets.def.R()
};
}
auto R = as_optional<double>(yaml_jets, "R");
if(R){
fixed_order_jets.def = fastjet::JetDefinition{
fixed_order_jets.def.jet_algorithm(), *R
};
}
auto min_pt = as_optional<double>(yaml_jets, "min pt");
if(min_pt) fixed_order_jets.min_pt = *min_pt;
}
catch(missing_option const & exc){
throw missing_option{
std::string{"In entry fixed order jets:\n"} + exc.what()
};
}
catch(invalid_type const & exc){
throw invalid_type{
std::string{"In entry fixed order jets:\n"} + exc.what()
};
}
}
// like std::stod, but throw if not the whole string can be converted
double to_double(std::string const & str){
std::size_t pos;
const double result = std::stod(str, &pos);
if(pos < str.size()){
throw std::invalid_argument(str + " is not a valid double value");
}
return result;
}
// simple (as in non-composite) scale functions
/**
* An example for a simple scale function would be Ht,
* Ht/2 is then composite (take Ht and then divide by 2)
*/
std::unique_ptr<ScaleFunction> make_simple_ScaleFunction_ptr(
std::string const & scale_fun
){
using ret_type = std::unique_ptr<ScaleFunction>;
assert(
scale_fun.empty() ||
(!std::isspace(scale_fun.front()) && !std::isspace(scale_fun.back()))
);
if(scale_fun == "input") return ret_type{new InputScales{}};
if(scale_fun == "Ht") return ret_type{new Ht{}};
if(scale_fun == "max jet pperp") return ret_type{new MaxJetPperp{}};
if(scale_fun == "jet invariant mass"){
return ret_type{new JetInvariantMass{}};
}
try{
const double scale = to_double(scale_fun);
return ret_type{new FixedScale{scale}};
} catch(std::invalid_argument const &){}
throw std::invalid_argument{"Unknown scale choice: " + scale_fun};
}
std::string trim_front(std::string const & str){
const auto new_begin = std::find_if(
begin(str), end(str), [](char c){ return ! std::isspace(c); }
);
return std::string(new_begin, end(str));
}
std::string trim_back(std::string str){
size_t pos = str.size() - 1;
// use guaranteed wrap-around behaviour to check whether we have
// traversed the whole string
for(; pos < str.size() && std::isspace(str[pos]); --pos) {}
str.resize(pos + 1); // note that pos + 1 can be 0
return str;
}
std::unique_ptr<ScaleFunction> make_ScaleFunction_ptr(
std::string const & scale_fun
){
assert(
scale_fun.empty() ||
(!std::isspace(scale_fun.front()) && !std::isspace(scale_fun.back()))
);
const size_t delim = scale_fun.find_first_of("*/");
if(delim == scale_fun.npos){
return make_simple_ScaleFunction_ptr(scale_fun);
}
const std::string first = trim_back(std::string{scale_fun, 0, delim});
const std::string second = trim_front(std::string{scale_fun, delim+1});
double factor;
std::unique_ptr<ScaleFunction> fun;
if(scale_fun[delim] == '/'){
factor = 1/to_double(second);
fun = make_simple_ScaleFunction_ptr(first);
}
else{
assert(scale_fun[delim] == '*');
try{
factor = to_double(second);
fun = make_simple_ScaleFunction_ptr(first);
}
catch(std::invalid_argument const &){
factor = to_double(first);
fun = make_simple_ScaleFunction_ptr(second);
}
}
assert(fun != nullptr);
return std::unique_ptr<ScaleFunction>{
new Product{factor, std::move(fun)}
};
}
ScaleConfig to_ScaleConfig(YAML::Node const & yaml){
ScaleConfig config;
const auto scales = as<std::vector<std::string>>(yaml, "scales");
config.scales.reserve(scales.size());
std::transform(
begin(scales), end(scales), std::back_inserter(config.scales),
make_ScaleFunction_ptr
);
auto scale_factors = as_optional<std::vector<double>>(
yaml, "scale factors"
);
if(scale_factors) config.scale_factors = std::move(*scale_factors);
const auto max_scale_ratio = as_optional<double>(yaml, "max scale ratio");
static_assert(
std::numeric_limits<double>::has_infinity, "infinity not supported"
);
config.max_scale_ratio = max_scale_ratio?
*max_scale_ratio:
std::numeric_limits<double>::infinity()
;
return config;
}
EventTreatMap get_event_treatment(
YAML::Node const & yaml
){
using namespace event_class;
EventTreatMap treat {
{no_2_jets, EventTreatment::discard},
{bad_final_state, EventTreatment::discard}
};
treat.emplace(FKL, as<EventTreatment>(yaml, "FKL"));
const auto unordered_treatment = as<EventTreatment>(yaml, "unordered");
treat.emplace(unordered_forward, unordered_treatment);
treat.emplace(unordered_backward, unordered_treatment);
treat.emplace(nonFKL, as<EventTreatment>(yaml, "non-FKL"));
if(treat[nonFKL] == EventTreatment::reweight){
throw std::invalid_argument{"Cannot reweight non-FKL events"};
}
return treat;
}
Config to_Config(YAML::Node const & yaml){
for(auto const & opt: yaml){
auto const & opt_name = opt.first.as<std::string>();
if(! known.count(opt_name)){
- std::cerr << "WARNING: unknown option " + opt_name + "\n";
+ throw unknown_option{"Unknown option '" + opt_name + "'"};
}
}
Config config;
config.resummation_jets = as<JetParameters>(yaml, "resummation jets");
config.fixed_order_jets = config.resummation_jets;
if(yaml["fixed order jets"]){
update_fixed_order_jet_parameters(config.fixed_order_jets, yaml);
}
config.min_extparton_pt = as<double>(yaml, "min extparton pt");
config.max_ext_soft_pt_fraction = yaml["max ext soft pt fraction"]?
as<double>(yaml, "max ext soft pt fraction"):
std::numeric_limits<double>::infinity()
;
config.trials = as<int>(yaml, "trials");
config.log_correction = as<bool>(yaml, "log correction");
config.unweight = as<bool>(yaml, "unweight");
config.treat = get_event_treatment(yaml);
if(yaml["event output"]){
config.output = as<std::vector<OutputFile>>(yaml, "event output");
}
config.RanLux_init = as_optional<std::string>(yaml, "RanLux init");
config.analysis_parameters = yaml["analysis"]?yaml["analysis"]:YAML::Node{};
config.scale_gen = ScaleGenerator{to_ScaleConfig(yaml)};
config.Higgs_coupling = as<HiggsCouplingSettings>(yaml, "Higgs coupling");
return config;
}
} // anonymous namespace
Config load_config(std::string const & config_file){
try{
return to_Config(YAML::LoadFile(config_file));
}
catch(...){
std::cerr << "Error reading " << config_file << ":\n ";
throw;
}
}
Event ScaleGenerator::operator()(Event ev) const{
assert(ev.variations().empty());
assert(! settings_.scales.empty());
auto const & scales = settings_.scales;
auto const & scale_factors = settings_.scale_factors;
const double max_scale_ratio = settings_.max_scale_ratio;
// check if we are doing scale variation at all
if(scales.size() == 1 && scale_factors.empty()){
ev.central() = (*scales.front())(ev);
return ev;
}
for(auto && base_scale: scales){
const EventParameters cur_base = (*base_scale)(ev);
ev.variations().emplace_back(cur_base);
//multiplicative scale variation
for(double mur_factor: scale_factors){
const double mur = cur_base.mur*mur_factor;
for(double muf_factor: scale_factors){
if(muf_factor == 1. && mur_factor == 1.) continue;
const double muf = cur_base.muf*muf_factor;
if(mur/muf < 1/max_scale_ratio || mur/muf > max_scale_ratio) continue;
ev.variations().emplace_back(
EventParameters{mur, muf, cur_base.weight}
);
}
}
};
ev.central() = (*scales.front())(ev);
return ev;
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Jan 21, 2:17 AM (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4243629
Default Alt Text
(23 KB)
Attached To
rHEJ HEJ
Event Timeline
Log In to Comment