53 int ndigits = std::floor(std::log10(std::abs(
d))) + 1 -
nSig;
55 if (std::abs(
d /
sf) < 2)
57 return sf * std::round(
d /
sf);
66void erasePrefix(std::string &str, std::string_view prefix)
69 str.erase(0, prefix.size());
76 str.erase(str.size() -
suffix.size());
92 for (
const auto &client :
gamma->clients()) {
93 if (
auto casted =
dynamic_cast<T *
>(client)) {
122 return "gamma_" +
sysname +
"_bin_" + std::to_string(i);
132 for (std::size_t i = 0; i < params.size(); ++i) {
133 std::string
name(params[i]->GetName());
147 nom.setConstant(
true);
186 *
tool.workspace()->var(std::string(
"nom_") + param.
GetName()), 1.);
191 "' is a known constraint type, but it cannot be resolved in this context");
195 const std::vector<std::string> &
parnames,
const std::vector<double> &vals,
202 size_t n = std::max(vals.size(),
parnames.size());
204 for (std::size_t i = 0; i <
n; ++i) {
215 if (vals.size() > 0) {
227 gamma->setConstant(
true);
237 if (!
comp.has_child(
"modifiers"))
239 for (
const auto &
mod :
comp[
"modifiers"].children()) {
240 if (
mod[
"type"].val() == ::Literals::staterror)
248 if (
comp.has_child(
"modifiers")) {
249 for (
const auto &
mod :
comp[
"modifiers"].children()) {
250 if (
mod[
"type"].val() == ::Literals::staterror)
255 ::Literals::staterror +
" modifier!");
270 param.
setError(gauss->getSigma().getVal());
275 if (
auto constr =
mod.find(
"constraint")) {
279 param.
setError(gauss->getSigma().getVal());
290 "': this looks like a legacy workspace where the 'constraint' field is neither a "
291 "constraint pdf name nor a supported legacy constraint type");
308 std::string(constraint.
GetName()));
316 if (
auto const *tau =
dynamic_cast<RooConstVar const *
>(arg)) {
317 return tau->getVal();
324 return real->getVal();
330 std::string(constraint.
GetName()));
331 return std::numeric_limits<double>::quiet_NaN();
346 if (!
p.has_child(
"data")) {
362 if (
p.has_child(
"modifiers")) {
373 for (
const auto &
mod :
p[
"modifiers"].children()) {
374 std::string
const &
modtype =
mod[
"type"].val();
376 mod.has_child(
"name")
378 : (
mod.has_child(
"parameter") ?
mod[
"parameter"].val() :
"syst_" + std::to_string(idx));
382 }
else if (
modtype ==
"normfactor") {
386 if (
mod.has_child(
"constraint") ||
mod.has_child(
"constraint_name") ||
mod.has_child(
"constraint_type")) {
390 }
else if (
modtype ==
"normsys") {
398 if (
mod.has_child(
"interpolation")) {
401 double low =
data[
"lo"].val_double();
402 double high =
data[
"hi"].val_double();
408 if (
interp == 4 && low <= 0)
409 low = std::numeric_limits<double>::epsilon();
410 if (
interp == 4 && high <= 0)
411 high = std::numeric_limits<double>::epsilon();
418 }
else if (
modtype ==
"histosys") {
435 std::vector<double> vals;
436 if (
mod[
"data"].has_child(
"vals")) {
437 for (
const auto &
v :
mod[
"data"][
"vals"].children()) {
438 vals.push_back(
v.val_double());
442 for (
const auto &
v :
mod[
"parameters"].children()) {
445 if (vals.empty() &&
parnames.empty()) {
447 "' with neither values nor parameters!");
449 std::string constraint =
"unknown";
450 std::vector<RooAbsPdf *> constraintPdfs;
453 for (
const auto &
v :
mod[
"constraints"].children()) {
455 constraintPdfs.push_back(
nullptr);
467 if (constraintPdfs.size() !=
nGammas) {
468 std::stringstream
ss;
470 <<
" constraints, but " <<
nGammas <<
" parameters";
473 }
else if (
mod.has_child(
"constraint_type")) {
474 constraint =
mod[
"constraint_type"].val();
475 }
else if (
mod.has_child(
"constraint")) {
482 "': this looks like a legacy workspace where the 'constraint' field is "
483 "not a supported legacy constraint type");
494 }
else if (
modtype ==
"custom") {
518 v.setAllInterpCodes(4);
540 if (!
p.has_child(
"samples")) {
545 if (
p.has_child(::Literals::staterror)) {
546 auto &
staterr =
p[::Literals::staterror];
547 if (
staterr.has_child(
"relThreshold"))
549 if (
staterr.has_child(
"constraint_type"))
552 std::vector<double>
sumW;
553 std::vector<double>
sumW2;
559 std::vector<std::unique_ptr<RooDataHist>>
data;
560 for (
const auto &
comp :
p[
"samples"].children()) {
563 size_t nbins =
dh->numEntries();
570 for (
size_t i = 0; i <
nbins; ++i) {
572 sumW2[i] +=
dh->weightSquared(i);
582 data.emplace_back(std::move(
dh));
591 std::vector<double>
errs(
sumW.size());
592 for (
size_t i = 0; i <
sumW.size(); ++i) {
610 for (
const auto &
comp :
p[
"samples"].children()) {
619 if (constraints.
empty()) {
634 std::string
const &key()
const override
636 static const std::string
keystring =
"interpolation0d";
642 elem[
"type"] << key();
643 elem[
"interpolationCodes"].fill_seq(
fip->interpolationCodes());
646 elem[
"high"].fill_seq(
fip->high(),
fip->variables().size());
647 elem[
"low"].fill_seq(
fip->low(),
fip->variables().size());
654 std::string
const &key()
const override
656 static const std::string
keystring =
"interpolation";
662 elem[
"type"] << key();
663 elem[
"interpolationCodes"].fill_seq(
pip->interpolationCodes());
664 elem[
"positiveDefinite"] <<
pip->positiveDefinite();
666 elem[
"nom"] <<
pip->nominalHist()->GetName();
685 pip.setPositiveDefinite(
p[
"positiveDefinite"].val_bool());
687 if (
p.has_child(
"interpolationCodes")) {
689 for (
auto const &node :
p[
"interpolationCodes"].children()) {
690 pip.setInterpCode(*
static_cast<RooAbsReal *
>(vars.at(i)), node.val_int(),
true);
704 if (!
p.has_child(
"high")) {
707 if (!
p.has_child(
"low")) {
710 if (!
p.has_child(
"nom")) {
714 double nom(
p[
"nom"].val_double());
718 std::vector<double> high;
721 std::vector<double> low;
724 if (vars.size() != low.size() || vars.size() != high.size()) {
726 "' has non-matching lengths of 'vars', 'high' and 'low'!");
731 if (
p.has_child(
"interpolationCodes")) {
733 for (
auto const &node :
p[
"interpolationCodes"].children()) {
734 fip.setInterpCode(*
static_cast<RooAbsReal *
>(vars.at(i)), node.val_int());
754 std::string
name =
"";
758 int interpolationCode = 4;
762 :
name(
n), param(
p), low(
l), high(
h), interpolationCode(i), constraint(
c)
770 std::vector<double> low;
771 std::vector<double> high;
774 :
name(
n), param(
p), constraint(
c)
776 low.assign(
l->dataHist().weightArray(),
l->dataHist().weightArray() +
l->dataHist().numEntries());
777 high.assign(
h->dataHist().weightArray(),
h->dataHist().weightArray() +
h->dataHist().numEntries());
782 std::vector<double> constraints;
783 std::vector<RooAbsPdf const *> constraintPdfs;
784 std::vector<RooAbsReal *> parameters;
788struct GenericElement {
797 size_t end = s.size();
799 while (start < end && s[start] ==
'(' && s[end - 1] ==
')') {
802 for (
size_t i = start; i < end - 1; ++i) {
805 else if (s[i] ==
')')
807 if (
depth == 0 && i < end - 1) {
819 return s.substr(start, end - start);
824 std::vector<std::string>
parts;
829 for (
size_t i = 0; i <
expr.size(); ++i) {
833 }
else if (
c ==
')') {
835 }
else if (
c ==
'*' &&
depth == 0) {
837 std::string sub =
expr.substr(start, i - start);
847 std::string sub =
expr.substr(start);
854 static const std::regex pattern(
855 R
"(^\s*1(?:\.0)?\s*([\+\-])\s*([a-zA-Z_][a-zA-Z0-9_]*|[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)\s*\*\s*([a-zA-Z_][a-zA-Z0-9_]*|[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)\s*$)");
861 if (std::regex_match(s, match, pattern)) {
862 if (match[1].str() ==
"-") {
866 std::string
token2 = match[2].str();
867 std::string
token3 = match[4].str();
878 sys.name =
p2->GetName();
883 sys.name =
p3->GetName();
888 sys.name =
v2->GetName();
890 sys.high =
sign *
p3->getVal();
891 sys.low = -
sign *
p3->getVal();
893 sys.name =
v3->GetName();
895 sys.high =
sign *
p2->getVal();
896 sys.low = -
sign *
p2->getVal();
900 sys.interpolationCode = 1;
909 if (
auto prod =
dynamic_cast<RooProduct *
>(arg)) {
910 for (
const auto &
e : prod->components()) {
920 for (
auto *var : list) {
930 std::vector<double> hist;
931 std::vector<double> histError;
932 std::vector<NormFactor> normfactors;
933 std::vector<NormSys> normsys;
934 std::vector<HistoSys> histosys;
935 std::vector<ShapeSys> shapesys;
936 std::vector<GenericElement> tmpElements;
937 std::vector<GenericElement> otherElements;
938 bool useBarlowBeestonLight =
false;
939 std::vector<RooAbsReal *> staterrorParameters;
947 for (
RooAbsArg const *pdf : ws->allPdfs()) {
948 if (
auto gauss =
dynamic_cast<RooGaussian const *
>(pdf)) {
949 if (
parname == gauss->getX().GetName()) {
950 sample.normfactors.emplace_back(*par, gauss);
956 sample.normfactors.emplace_back(*par);
967 std::vector<Sample> samples;
968 std::map<int, double> tot_yield;
969 std::map<int, double> tot_yield2;
970 std::map<int, double> rel_errors;
972 long unsigned int nBins = 0;
987 std::vector<ParamHistFunc *>
phfs;
997 if (channel.varSet ==
nullptr) {
998 channel.varSet = dataHist.get();
999 channel.nBins = dataHist.numEntries();
1001 if (
sample.hist.empty()) {
1002 auto *
w = dataHist.weightArray();
1003 sample.hist.assign(
w,
w + dataHist.numEntries());
1020 }
else if (
auto par =
dynamic_cast<RooRealVar *
>(
e)) {
1029 for (
size_t i = 0; i <
fip->variables().size(); ++i) {
1038 fip->interpolationCodes()[i], constraint);
1049 expression.ReplaceAll((
"x[" + std::to_string(i) +
"]").c_str(),
p->GetName());
1050 expression.ReplaceAll((
"@" + std::to_string(i)).c_str(),
p->GetName());
1053 if (components.size() == 0) {
1055 sample.otherElements.push_back(formula);
1058 std::vector<RooAbsArg *> realComponents;
1060 for (
auto &
comp : components) {
1064 realComponents.push_back(
part);
1069 if (normsys.param) {
1070 sample.normsys.emplace_back(std::move(normsys));
1075 std::string
name = std::string(formula->
GetName()) +
"_part" + std::to_string(idx);
1078 sample.tmpElements.push_back({var});
1106 for (
size_t i = 0; i <
pip->paramList().
size(); ++i) {
1110 if (
auto lo =
dynamic_cast<RooHistFunc *
>(
pip->lowList().at(i))) {
1127 for (
const auto &
g :
phf->paramList()) {
1131 if (channel.tot_yield.find(idx) == channel.tot_yield.end()) {
1132 channel.tot_yield[idx] = 0;
1133 channel.tot_yield2[idx] = 0;
1135 channel.tot_yield[idx] +=
sample.hist[idx - 1];
1136 channel.tot_yield2[idx] += (
sample.hist[idx - 1] *
sample.hist[idx - 1]);
1140 channel.rel_errors[idx] =
erel;
1143 channel.rel_errors[idx] =
erel;
1146 "currently, only RooPoisson and RooGaussian are supported as constraint types");
1150 sample.useBarlowBeestonLight =
true;
1157 for (
const auto &
g :
phf->paramList()) {
1158 sys.parameters.push_back(
static_cast<RooRealVar *
>(
g));
1164 if (!constraint && !
g->isConstant()) {
1171 sys.constraints.push_back(0.0);
1172 sys.constraintPdfs.push_back(
nullptr);
1181 "currently, only RooPoisson and RooGaussian are supported as constraint types");
1184 sample.shapesys.emplace_back(std::move(sys));
1190 channel.samples.emplace_back(std::move(
sample));
1199 for (
auto &
sample : channel.samples) {
1200 if (
sample.useBarlowBeestonLight) {
1202 for (
auto bin : channel.rel_errors) {
1205 const int i =
bin.first;
1207 const double count =
sample.hist[i - 1];
1210 sample.histError[i - 1] =
1222 if (sys.constraint) {
1223 mod[
"constraint"] << sys.constraint->GetName();
1228 for (
const auto &
sample : channel.samples) {
1230 elem[
"type"] <<
"histfactory_dist";
1237 for (
const auto &
nf :
sample.normfactors) {
1240 mod[
"name"] <<
nf.name;
1241 mod[
"parameter"] <<
nf.param->GetName();
1242 mod[
"type"] <<
"normfactor";
1243 if (
nf.constraint) {
1244 mod[
"constraint"] <<
nf.constraint->GetName();
1245 tool->queueExport(*
nf.constraint);
1249 for (
const auto &sys :
sample.normsys) {
1252 mod[
"name"] << sys.name;
1253 mod[
"type"] <<
"normsys";
1254 mod[
"parameter"] << sys.param->GetName();
1255 if (sys.interpolationCode != 4) {
1256 mod[
"interpolation"] << sys.interpolationCode;
1259 auto &
data =
mod[
"data"].set_map();
1260 data[
"lo"] << sys.low;
1261 data[
"hi"] << sys.high;
1264 for (
const auto &sys :
sample.histosys) {
1267 mod[
"name"] << sys.name;
1268 mod[
"type"] <<
"histosys";
1269 mod[
"parameter"] << sys.param->GetName();
1271 auto &
data =
mod[
"data"].set_map();
1272 if (channel.nBins != sys.low.size() || channel.nBins != sys.high.size()) {
1273 std::stringstream
ss;
1274 ss <<
"inconsistent binning: " << channel.nBins <<
" bins expected, but " << sys.low.size() <<
"/"
1275 << sys.high.size() <<
" found in nominal histogram errors!";
1282 for (
const auto &sys :
sample.shapesys) {
1285 mod[
"name"] << sys.name;
1286 mod[
"type"] <<
"shapesys";
1288 if (std::any_of(sys.constraintPdfs.begin(), sys.constraintPdfs.end(),
1289 [](
auto *pdf) { return pdf != nullptr; })) {
1291 for (
auto *constraint : sys.constraintPdfs) {
1299 mod[
"data"].set_map()[
"vals"].fill_seq(sys.constraints);
1306 mod[
"type"] <<
"custom";
1312 mod[
"type"] <<
"custom";
1315 if (
sample.useBarlowBeestonLight) {
1318 mod[
"name"] << ::Literals::staterror;
1319 mod[
"type"] << ::Literals::staterror;
1324 auto &output =
elem[
"axes"].set_seq();
1330 auto &
dataNode = s[
"data"].set_map();
1331 if (channel.nBins !=
sample.hist.size()) {
1332 std::stringstream
ss;
1333 ss <<
"inconsistent binning: " << channel.nBins <<
" bins expected, but " <<
sample.hist.size()
1334 <<
" found in nominal histogram!";
1338 if (!
sample.histError.empty()) {
1339 if (channel.nBins !=
sample.histError.size()) {
1340 std::stringstream
ss;
1341 ss <<
"inconsistent binning: " << channel.nBins <<
" bins expected, but " <<
sample.histError.size()
1342 <<
" found in nominal histogram errors!";
1355 std::set<const RooAbsReal *> vars;
1356 for (
const auto &
sample : channel.samples) {
1357 for (
const auto &
nf :
sample.normfactors) {
1358 vars.insert(
nf.param);
1360 for (
const auto &sys :
sample.normsys) {
1361 vars.insert(sys.param);
1364 for (
const auto &sys :
sample.histosys) {
1365 vars.insert(sys.param);
1367 for (
const auto &sys :
sample.shapesys) {
1368 for (
const auto &par : sys.parameters) {
1372 if (
sample.useBarlowBeestonLight) {
1373 for (
const auto &par :
sample.staterrorParameters) {
1381 for (
auto *pdf : constraints) {
1383 for (
const auto *var : vars) {
1384 if (pdf->dependsOn(*var)) {
1402 std::cout <<
pdfname <<
" is not a sumpdf" << std::endl;
1410 std::cout <<
"sample " <<
sample->GetName() <<
" is no RooProduct or RooRealSumPdf in " <<
pdfname
1419 if (channel.samples.size() == 0)
1421 for (
auto &
sample : channel.samples) {
1422 if (
sample.hist.empty()) {
1434 "losing constraint term '" + std::string(constraint->
GetName()) +
1435 "', implicit constraints are not supported by HS3 yet! The term will appear in the HS3 file, but will not be "
1436 "picked up when creating a likelihood from it! You will have to add it manually as an external constraint.");
1437 tool->queueExport(*constraint);
1441 for (
const auto &
sample : channel.samples) {
1458 for (
auto *constraint :
modifier.constraintPdfs) {
1460 tool->queueExport(*constraint);
1467 for (
const auto &
sample : channel.samples) {
1478 sumpdf->getParameters(channel.varSet, parameters);
1482 tool->queueExport(*param);
1491 bool autoExportDependants()
const override {
return false; }
1494 std::vector<RooAbsPdf *> constraints;
1504 constraints.push_back(pdf);
1513 std::string
const &key()
const override
1515 static const std::string
keystring =
"histfactory_dist";
1526 bool autoExportDependants()
const override {
return false; }
1529 std::vector<RooAbsPdf *> constraints;
1532 std::string
const &key()
const override
1534 static const std::string
keystring =
"histfactory_dist";
bool startsWith(std::string_view str, std::string_view prefix)
bool endsWith(std::string_view str, std::string_view suffix)
ROOT::RRangeCast< T, false, Range_t > static_range_cast(Range_t &&coll)
double toDouble(const char *s)
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void funcs
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t modifier
A class which maps the current values of a RooRealVar (or a set of RooRealVars) to one of a number of...
The PiecewiseInterpolation is a class that can morph distributions into each other,...
void setPositiveDefinite(bool flag=true)
const_iterator begin() const
const_iterator end() const
Common abstract base class for objects that represent a value and a "shape" in RooFit.
bool dependsOn(const RooAbsCollection &serverList, const RooAbsArg *ignoreArg=nullptr, bool valueOnly=false) const
Test whether we depend on (ie, are served by) any object in the specified collection.
bool isConstant() const
Check if the "Constant" attribute is set.
Abstract container object that can hold multiple RooAbsArg objects.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Abstract interface for all probability density functions.
Abstract base class for objects that represent a real value and implements functionality common to al...
RooArgList is a container object that can hold multiple RooAbsArg objects.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Returns the bin width (or volume) given a RooHistFunc.
Represents a constant real-valued object.
Container class to hold N-dimensional binned data.
A real-valued function sampled from a multidimensional histogram.
RooAbsReal const & getMean() const
Get the mean parameter.
Efficient implementation of a product of PDFs of the form.
Represents the product of a given set of RooAbsReal objects.
Implements a PDF constructed from a sum of functions:
Variable that can be changed from the outside.
void setError(double value)
This class encapsulates all information for the statistical interpretation of one experiment.
Configuration for a constrained, coherent shape variation of affected samples.
Configuration for an un- constrained overall systematic to scale sample normalisations.
std::string GetName() const
Constrained bin-by-bin variation of affected histogram.
Persistable container for RooFit projects.
TObject * obj(RooStringView name) const
Return any type of object (RooAbsArg, RooAbsData or generic object) with given name)
RooAbsPdf * pdf(RooStringView name) const
Retrieve p.d.f (RooAbsPdf) with given name. A null pointer is returned if not found.
RooAbsReal * function(RooStringView name) const
Retrieve function (RooAbsReal) with given name. Note that all RooAbsPdfs are also RooAbsReals....
RooFactoryWSTool & factory()
Return instance to factory tool.
bool import(const RooAbsArg &arg, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}, const RooCmdArg &arg9={})
Import a RooAbsArg object, e.g.
const char * GetName() const override
Returns name of object.
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
RooCmdArg RecycleConflictNodes(bool flag=true)
RooCmdArg Conditional(const RooArgSet &pdfSet, const RooArgSet &depSet, bool depsAreCond=false)
constexpr double defaultShapeSysGammaMax
constexpr double minShapeUncertainty
constexpr double defaultStatErrorGammaMax
constexpr double defaultGammaMin
void configureConstrainedGammas(RooArgList const &gammas, std::span< const double > relSigmas, double minSigma)
Configure constrained gamma parameters for fitting.
CreateGammaConstraintsOutput createGammaConstraints(RooArgList const ¶mList, std::span< const double > relSigmas, double minSigma, Constraint::Type type)
#define STATIC_EXECUTE(MY_FUNC)
static uint64_t sum(uint64_t i)