Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F19244558
YAMLreader.cc
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
16 KB
Referenced Files
None
Subscribers
None
YAMLreader.cc
View Options
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#include
"HEJ/YAMLreader.hh"
#include
<algorithm>
#include
<iostream>
#include
<limits>
#include
<map>
#include
<string>
#include
<unordered_map>
#include
<vector>
#include
<dlfcn.h>
#include
"HEJ/ScaleFunction.hh"
#include
"HEJ/event_types.hh"
#include
"HEJ/output_formats.hh"
#include
"HEJ/Constants.hh"
namespace
HEJ
{
class
Event
;
namespace
{
//! Get YAML tree of supported options
/**
* The configuration file is checked against this tree of options
* in assert_all_options_known.
*/
YAML
::
Node
const
&
get_supported_options
(){
const
static
YAML
::
Node
supported
=
[](){
YAML
::
Node
supported
;
static
const
auto
opts
=
{
"trials"
,
"min extparton pt"
,
"max ext soft pt fraction"
,
"FKL"
,
"unordered"
,
"extremal qqx"
,
"central qqx"
,
"non-resummable"
,
"scales"
,
"scale factors"
,
"max scale ratio"
,
"import scales"
,
"log correction"
,
"event output"
,
"analysis"
,
"regulator parameter"
};
// add subnodes to "supported" - the assigned value is irrelevant
for
(
auto
&&
opt
:
opts
)
supported
[
opt
]
=
""
;
for
(
auto
&&
jet_opt
:
{
"min pt"
,
"algorithm"
,
"R"
}){
supported
[
"resummation jets"
][
jet_opt
]
=
""
;
supported
[
"fixed order jets"
][
jet_opt
]
=
""
;
}
for
(
auto
&&
opt
:
{
"mt"
,
"use impact factors"
,
"include bottom"
,
"mb"
}){
supported
[
"Higgs coupling"
][
opt
]
=
""
;
}
for
(
auto
&&
opt
:
{
"name"
,
"seed"
}){
supported
[
"random generator"
][
opt
]
=
""
;
}
return
supported
;
}();
return
supported
;
}
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
},
{
"cambridge for passive"
,
cambridge_for_passive_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
;
}
}
// namespace anonymous
namespace
detail
{
void
set_from_yaml
(
fastjet
::
JetAlgorithm
&
setting
,
YAML
::
Node
const
&
yaml
){
setting
=
to_JetAlgorithm
(
yaml
.
as
<
std
::
string
>
());
}
void
set_from_yaml
(
EventTreatment
&
setting
,
YAML
::
Node
const
&
yaml
){
setting
=
to_EventTreatment
(
yaml
.
as
<
std
::
string
>
());
}
void
set_from_yaml
(
ParticleID
&
setting
,
YAML
::
Node
const
&
yaml
){
setting
=
to_ParticleID
(
yaml
.
as
<
std
::
string
>
());
}
}
// namespace detail
JetParameters
get_jet_parameters
(
YAML
::
Node
const
&
node
,
std
::
string
const
&
entry
){
assert
(
node
);
JetParameters
result
;
fastjet
::
JetAlgorithm
jet_algo
=
fastjet
::
antikt_algorithm
;
double
R
;
set_from_yaml_if_defined
(
jet_algo
,
node
,
entry
,
"algorithm"
);
set_from_yaml
(
R
,
node
,
entry
,
"R"
);
result
.
def
=
fastjet
::
JetDefinition
{
jet_algo
,
R
};
set_from_yaml
(
result
.
min_pt
,
node
,
entry
,
"min pt"
);
return
result
;
}
RNGConfig
to_RNGConfig
(
YAML
::
Node
const
&
node
,
std
::
string
const
&
entry
){
assert
(
node
);
RNGConfig
result
;
set_from_yaml
(
result
.
name
,
node
,
entry
,
"name"
);
set_from_yaml_if_defined
(
result
.
seed
,
node
,
entry
,
"seed"
);
return
result
;
}
HiggsCouplingSettings
get_Higgs_coupling
(
YAML
::
Node
const
&
node
,
std
::
string
const
&
entry
){
assert
(
node
);
static
constexpr
double
mt_max
=
2e4
;
#ifndef HEJ_BUILD_WITH_QCDLOOP
if
(
node
[
entry
]){
throw
std
::
invalid_argument
{
"Higgs coupling settings require building HEJ 2 "
"with QCDloop support"
};
}
#endif
HiggsCouplingSettings
settings
;
set_from_yaml_if_defined
(
settings
.
mt
,
node
,
entry
,
"mt"
);
set_from_yaml_if_defined
(
settings
.
mb
,
node
,
entry
,
"mb"
);
set_from_yaml_if_defined
(
settings
.
include_bottom
,
node
,
entry
,
"include bottom"
);
set_from_yaml_if_defined
(
settings
.
use_impact_factors
,
node
,
entry
,
"use impact factors"
);
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
;
}
FileFormat
to_FileFormat
(
std
::
string
const
&
name
){
static
const
std
::
map
<
std
::
string
,
FileFormat
>
known
=
{
{
"Les Houches"
,
FileFormat
::
Les_Houches
},
{
"HepMC"
,
FileFormat
::
HepMC
},
{
"HepMC2"
,
FileFormat
::
HepMC2
},
{
"HepMC3"
,
FileFormat
::
HepMC3
}
};
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
==
"hepmc"
)
return
FileFormat
::
HepMC
;
if
(
suffix
==
"hepmc3"
)
return
FileFormat
::
HepMC3
;
if
(
suffix
==
"hepmc2"
)
return
FileFormat
::
HepMC2
;
throw
std
::
invalid_argument
{
"Can't determine format for output file "
+
filename
};
}
void
assert_all_options_known
(
YAML
::
Node
const
&
conf
,
YAML
::
Node
const
&
supported
){
if
(
!
conf
.
IsMap
())
return
;
if
(
!
supported
.
IsMap
())
throw
invalid_type
{
"must not have sub-entries"
};
for
(
auto
const
&
entry
:
conf
){
const
auto
name
=
entry
.
first
.
as
<
std
::
string
>
();
if
(
!
supported
[
name
])
throw
unknown_option
{
name
};
/* check sub-options, e.g. 'resummation jets: min pt'
* we don't check analysis sub-options
* those depend on the analysis being used and should be checked there
* similar for "import scales"
*/
if
(
name
!=
"analysis"
&&
name
!=
"import scales"
){
try
{
assert_all_options_known
(
conf
[
name
],
supported
[
name
]);
}
catch
(
unknown_option
const
&
ex
){
throw
unknown_option
{
name
+
": "
+
ex
.
what
()};
}
catch
(
invalid_type
const
&
ex
){
throw
invalid_type
{
name
+
": "
+
ex
.
what
()};
}
}
}
}
}
// namespace HEJ
namespace
YAML
{
Node
convert
<
HEJ
::
OutputFile
>::
encode
(
HEJ
::
OutputFile
const
&
outfile
)
{
Node
node
;
node
[
to_string
(
outfile
.
format
)]
=
outfile
.
name
;
return
node
;
};
bool
convert
<
HEJ
::
OutputFile
>::
decode
(
Node
const
&
node
,
HEJ
::
OutputFile
&
out
)
{
switch
(
node
.
Type
()){
case
NodeType
::
Map
:
{
YAML
::
const_iterator
it
=
node
.
begin
();
out
.
format
=
HEJ
::
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
=
HEJ
::
format_from_suffix
(
out
.
name
);
return
true
;
default
:
return
false
;
}
}
}
// namespace YAML
namespace
HEJ
{
namespace
detail
{
void
set_from_yaml
(
OutputFile
&
setting
,
YAML
::
Node
const
&
yaml
){
setting
=
yaml
.
as
<
OutputFile
>
();
}
}
namespace
{
void
update_fixed_order_jet_parameters
(
JetParameters
&
fixed_order_jets
,
YAML
::
Node
const
&
yaml
){
if
(
!
yaml
[
"fixed order jets"
])
return
;
set_from_yaml_if_defined
(
fixed_order_jets
.
min_pt
,
yaml
,
"fixed order jets"
,
"min pt"
);
fastjet
::
JetAlgorithm
algo
=
fixed_order_jets
.
def
.
jet_algorithm
();
set_from_yaml_if_defined
(
algo
,
yaml
,
"fixed order jets"
,
"algorithm"
);
double
R
=
fixed_order_jets
.
def
.
R
();
set_from_yaml_if_defined
(
R
,
yaml
,
"fixed order jets"
,
"R"
);
fixed_order_jets
.
def
=
fastjet
::
JetDefinition
{
algo
,
R
};
}
// 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
;
}
using
EventScale
=
double
(
*
)(
Event
const
&
);
void
import_scale_functions
(
std
::
string
const
&
file
,
std
::
vector
<
std
::
string
>
const
&
scale_names
,
std
::
unordered_map
<
std
::
string
,
EventScale
>
&
known
)
{
auto
handle
=
dlopen
(
file
.
c_str
(),
RTLD_NOW
);
char
*
error
=
dlerror
();
if
(
error
!=
nullptr
)
throw
std
::
runtime_error
{
error
};
for
(
auto
const
&
scale
:
scale_names
)
{
void
*
sym
=
dlsym
(
handle
,
scale
.
c_str
());
error
=
dlerror
();
if
(
error
!=
nullptr
)
throw
std
::
runtime_error
{
error
};
known
.
emplace
(
scale
,
reinterpret_cast
<
EventScale
>
(
sym
));
}
}
auto
get_scale_map
(
YAML
::
Node
const
&
yaml
)
{
std
::
unordered_map
<
std
::
string
,
EventScale
>
scale_map
;
scale_map
.
emplace
(
"H_T"
,
H_T
);
scale_map
.
emplace
(
"max jet pperp"
,
max_jet_pt
);
scale_map
.
emplace
(
"jet invariant mass"
,
jet_invariant_mass
);
scale_map
.
emplace
(
"m_j1j2"
,
m_j1j2
);
if
(
yaml
[
"import scales"
])
{
if
(
!
yaml
[
"import scales"
].
IsMap
())
{
throw
invalid_type
{
"Entry 'import scales' is not a map"
};
}
for
(
auto
const
&
import
:
yaml
[
"import scales"
])
{
const
auto
file
=
import
.
first
.
as
<
std
::
string
>
();
const
auto
scale_names
=
import
.
second
.
IsSequence
()
?
import
.
second
.
as
<
std
::
vector
<
std
::
string
>>
()
:
std
::
vector
<
std
::
string
>
{
import
.
second
.
as
<
std
::
string
>
()};
import_scale_functions
(
file
,
scale_names
,
scale_map
);
}
}
return
scale_map
;
}
// simple (as in non-composite) scale functions
/**
* An example for a simple scale function would be H_T,
* H_T/2 is then composite (take H_T and then divide by 2)
*/
ScaleFunction
parse_simple_ScaleFunction
(
std
::
string
const
&
scale_fun
,
std
::
unordered_map
<
std
::
string
,
EventScale
>
const
&
known
)
{
assert
(
scale_fun
.
empty
()
||
(
!
std
::
isspace
(
scale_fun
.
front
())
&&
!
std
::
isspace
(
scale_fun
.
back
()))
);
const
auto
it
=
known
.
find
(
scale_fun
);
if
(
it
!=
end
(
known
))
return
{
it
->
first
,
it
->
second
};
try
{
const
double
scale
=
to_double
(
scale_fun
);
return
{
scale_fun
,
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
;
}
ScaleFunction
parse_ScaleFunction
(
std
::
string
const
&
scale_fun
,
std
::
unordered_map
<
std
::
string
,
EventScale
>
const
&
known
){
assert
(
scale_fun
.
empty
()
||
(
!
std
::
isspace
(
scale_fun
.
front
())
&&
!
std
::
isspace
(
scale_fun
.
back
()))
);
// parse from right to left => a/b/c gives (a/b)/c
const
size_t
delim
=
scale_fun
.
find_last_of
(
"*/"
);
if
(
delim
==
scale_fun
.
npos
){
return
parse_simple_ScaleFunction
(
scale_fun
,
known
);
}
const
std
::
string
first
=
trim_back
(
std
::
string
{
scale_fun
,
0
,
delim
});
const
std
::
string
second
=
trim_front
(
std
::
string
{
scale_fun
,
delim
+
1
});
if
(
scale_fun
[
delim
]
==
'/'
){
return
parse_ScaleFunction
(
first
,
known
)
/
parse_ScaleFunction
(
second
,
known
);
}
else
{
assert
(
scale_fun
[
delim
]
==
'*'
);
return
parse_ScaleFunction
(
first
,
known
)
*
parse_ScaleFunction
(
second
,
known
);
}
}
EventTreatMap
get_event_treatment
(
YAML
::
Node
const
&
yaml
){
using
namespace
event_type
;
EventTreatMap
treat
{
{
no_2_jets
,
EventTreatment
::
discard
},
{
bad_final_state
,
EventTreatment
::
discard
},
{
FKL
,
EventTreatment
::
reweight
},
{
unob
,
EventTreatment
::
keep
},
{
unof
,
EventTreatment
::
keep
},
{
qqxexb
,
EventTreatment
::
keep
},
{
qqxexf
,
EventTreatment
::
keep
},
{
qqxmid
,
EventTreatment
::
keep
},
{
non_resummable
,
EventTreatment
::
keep
}
};
set_from_yaml
(
treat
.
at
(
FKL
),
yaml
,
"FKL"
);
set_from_yaml
(
treat
.
at
(
unob
),
yaml
,
"unordered"
);
treat
.
at
(
unof
)
=
treat
.
at
(
unob
);
set_from_yaml
(
treat
.
at
(
qqxexb
),
yaml
,
"extremal qqx"
);
set_from_yaml
(
treat
.
at
(
qqxexf
),
yaml
,
"extremal qqx"
);
set_from_yaml
(
treat
.
at
(
qqxmid
),
yaml
,
"central qqx"
);
set_from_yaml
(
treat
.
at
(
non_resummable
),
yaml
,
"non-resummable"
);
if
(
treat
[
non_resummable
]
==
EventTreatment
::
reweight
){
throw
std
::
invalid_argument
{
"Cannot reweight Fixed Order events"
};
}
return
treat
;
}
Config
to_Config
(
YAML
::
Node
const
&
yaml
){
try
{
assert_all_options_known
(
yaml
,
get_supported_options
());
}
catch
(
unknown_option
const
&
ex
){
throw
unknown_option
{
std
::
string
{
"Unknown option '"
}
+
ex
.
what
()
+
"'"
};
}
Config
config
;
config
.
resummation_jets
=
get_jet_parameters
(
yaml
,
"resummation jets"
);
config
.
fixed_order_jets
=
config
.
resummation_jets
;
update_fixed_order_jet_parameters
(
config
.
fixed_order_jets
,
yaml
);
set_from_yaml
(
config
.
min_extparton_pt
,
yaml
,
"min extparton pt"
);
// Sets the standard value, then changes this if defined
config
.
regulator_lambda
=
CLAMBDA
;
set_from_yaml_if_defined
(
config
.
regulator_lambda
,
yaml
,
"regulator parameter"
);
config
.
max_ext_soft_pt_fraction
=
0.1
;
set_from_yaml_if_defined
(
config
.
max_ext_soft_pt_fraction
,
yaml
,
"max ext soft pt fraction"
);
set_from_yaml
(
config
.
trials
,
yaml
,
"trials"
);
set_from_yaml
(
config
.
log_correction
,
yaml
,
"log correction"
);
config
.
treat
=
get_event_treatment
(
yaml
);
set_from_yaml_if_defined
(
config
.
output
,
yaml
,
"event output"
);
config
.
rng
=
to_RNGConfig
(
yaml
,
"random generator"
);
set_from_yaml_if_defined
(
config
.
analysis_parameters
,
yaml
,
"analysis"
);
config
.
scales
=
to_ScaleConfig
(
yaml
);
config
.
Higgs_coupling
=
get_Higgs_coupling
(
yaml
,
"Higgs coupling"
);
return
config
;
}
}
// namespace anonymous
ScaleConfig
to_ScaleConfig
(
YAML
::
Node
const
&
yaml
){
ScaleConfig
config
;
auto
scale_funs
=
get_scale_map
(
yaml
);
std
::
vector
<
std
::
string
>
scales
;
set_from_yaml
(
scales
,
yaml
,
"scales"
);
config
.
base
.
reserve
(
scales
.
size
());
std
::
transform
(
begin
(
scales
),
end
(
scales
),
std
::
back_inserter
(
config
.
base
),
[
scale_funs
](
auto
const
&
entry
){
return
parse_ScaleFunction
(
entry
,
scale_funs
);
}
);
set_from_yaml_if_defined
(
config
.
factors
,
yaml
,
"scale factors"
);
config
.
max_ratio
=
std
::
numeric_limits
<
double
>::
infinity
();
set_from_yaml_if_defined
(
config
.
max_ratio
,
yaml
,
"max scale ratio"
);
return
config
;
}
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
;
}
}
}
// namespace HEJ
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Tue, Sep 30, 4:43 AM (1 d, 4 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
6489440
Default Alt Text
YAMLreader.cc (16 KB)
Attached To
Mode
rHEJ HEJ
Attached
Detach File
Event Timeline
Log In to Comment