52 if (binning.isUniform()) {
54 axis[
"min"] << obs.
getMin();
55 axis[
"max"] << obs.
getMax();
57 auto &edges = axis[
"edges"];
59 double val = binning.binLow(0);
61 for (
int i = 0; i < binning.numBins(); ++i) {
62 val = binning.binHigh(i);
63 edges.append_child() << val;
68double round_prec(
double d,
int nSig)
72 int ndigits = std::floor(std::log10(std::abs(
d))) + 1 - nSig;
73 double sf = std::pow(10, ndigits);
74 if (std::abs(
d / sf) < 2)
76 return sf * std::round(
d / sf);
82constexpr auto staterror =
"staterror";
85void erasePrefix(std::string &str, std::string_view prefix)
88 str.erase(0, prefix.size());
92bool eraseSuffix(std::string &str, std::string_view suffix)
95 str.erase(str.size() - suffix.size());
103void sortByName(Coll &coll)
105 std::sort(coll.begin(), coll.end(), [](
auto &
l,
auto &
r) { return l.name < r.name; });
111 for (
const auto &client :
gamma->clients()) {
112 if (
auto casted =
dynamic_cast<T *
>(client)) {
115 T *
c = findClient<T>(client);
127 RooPoisson *constraint_p = findClient<RooPoisson>(
g);
156inline std::string defaultGammaName(std::string
const &sysname, std::size_t i)
158 return "gamma_" + sysname +
"_bin_" + std::to_string(i);
163void optionallyExportGammaParameters(
JSONNode &mod, std::string
const &sysname, std::vector<RooAbsReal *>
const ¶ms,
164 bool forceExport =
true)
166 std::vector<std::string> paramNames;
167 bool needExport = forceExport;
168 for (std::size_t i = 0; i < params.size(); ++i) {
169 std::string
name(params[i]->GetName());
170 paramNames.push_back(
name);
171 if (
name != defaultGammaName(sysname, i)) {
176 mod[
"parameters"].
fill_seq(paramNames);
180RooRealVar &createNominal(
RooWorkspace &ws, std::string
const &parname,
double val,
double min,
double max)
189std::string constraintName(std::string
const ¶mName)
191 return paramName +
"Constraint";
194ParamHistFunc &createPHF(
const std::string &phfname, std::string
const &sysname,
195 const std::vector<std::string> &parnames,
const std::vector<double> &vals,
197 const std::string &constraintType,
double gammaMin,
double gammaMax,
double minSigma)
201 size_t n = std::max(vals.size(), parnames.size());
203 for (std::size_t i = 0; i <
n; ++i) {
204 const std::string
name = parnames.empty() ? defaultGammaName(sysname, i) : parnames[i];
214 if (vals.size() > 0) {
215 if (constraintType !=
"Const") {
218 for (
auto const &term : constraintsInfo.constraints) {
220 constraints.
add(*ws.
pdf(term->GetName()));
224 gamma->setConstant(
true);
232bool hasStaterror(
const JSONNode &comp)
236 for (
const auto &mod : comp[
"modifiers"].children()) {
237 if (mod[
"type"].val() == ::Literals::staterror)
246 for (
const auto &mod : comp[
"modifiers"].children()) {
247 if (mod[
"type"].val() == ::Literals::staterror)
252 ::Literals::staterror +
" modifier!");
258 if (
auto constrName = mod.
find(
"constraint_name")) {
259 auto constraint_name = constrName->val();
260 auto constraint = tool.
workspace()->
pdf(constraint_name);
268 if (
auto gauss =
dynamic_cast<RooGaussian *const
>(constraint)) {
269 param.
setError(gauss->getSigma().getVal());
273 std::string constraint_type =
"Gauss";
274 if (
auto constrType = mod.
find(
"constraint_type")) {
275 constraint_type = constrType->val();
277 if (constraint_type ==
"Gauss") {
294 std::string prefixedName = fprefix +
"_" + sampleName;
296 std::string channelName = fprefix;
297 erasePrefix(channelName,
"model_");
311 if (hasStaterror(p)) {
312 shapeElems.
add(*mcStatObject);
317 std::vector<double> overall_low;
318 std::vector<double> overall_high;
319 std::vector<int> overall_interp;
326 for (
const auto &mod : p[
"modifiers"].children()) {
327 std::string
const &modtype = mod[
"type"].
val();
328 std::string
const &sysname =
331 : (mod.
has_child(
"parameter") ? mod[
"parameter"].val() :
"syst_" + std::to_string(idx));
333 if (modtype ==
"staterror") {
335 }
else if (modtype ==
"normfactor") {
337 normElems.
add(constrParam);
340 constraints.
add(getOrCreateConstraint(tool, mod, constrParam, sampleName));
342 }
else if (modtype ==
"normsys") {
343 auto *parameter = mod.
find(
"parameter");
344 std::string parname(parameter ? parameter->val() :
"alpha_" + sysname);
345 createNominal(ws, parname, 0.0, -10, 10);
347 overall_nps.
add(par);
348 auto &data = mod[
"data"];
351 interp = mod[
"interpolation"].
val_int();
353 double low = data[
"lo"].val_double();
354 double high = data[
"hi"].val_double();
360 if (interp == 4 && low <= 0)
361 low = std::numeric_limits<double>::epsilon();
362 if (interp == 4 && high <= 0)
363 high = std::numeric_limits<double>::epsilon();
365 overall_low.push_back(low);
366 overall_high.push_back(high);
367 overall_interp.push_back(interp);
369 constraints.
add(getOrCreateConstraint(tool, mod, par, sampleName));
370 }
else if (modtype ==
"histosys") {
371 auto *parameter = mod.
find(
"parameter");
372 std::string parname(parameter ? parameter->val() :
"alpha_" + sysname);
373 createNominal(ws, parname, 0.0, -10, 10);
376 auto &data = mod[
"data"];
378 sysname +
"Low_" + prefixedName, varlist,
381 sysname +
"High_" + prefixedName, varlist,
383 constraints.
add(getOrCreateConstraint(tool, mod, par, sampleName));
384 }
else if (modtype ==
"shapesys" || modtype ==
"shapefactor") {
385 std::string funcName = channelName +
"_" + sysname +
"_ShapeSys";
387 std::vector<double> vals;
388 if (mod[
"data"].has_child(
"vals")) {
389 for (
const auto &
v : mod[
"data"][
"vals"].children()) {
390 vals.push_back(
v.val_double());
393 std::vector<std::string> parnames;
394 for (
const auto &
v : mod[
"parameters"].children()) {
395 parnames.push_back(
v.val());
397 if (vals.empty() && parnames.empty()) {
399 "' with neither values nor parameters!");
401 std::string constraint(mod.
has_child(
"constraint_type") ? mod[
"constraint_type"].val()
402 : mod.
has_child(
"constraint") ? mod[
"constraint"].val()
404 shapeElems.
add(createPHF(funcName, sysname, parnames, vals, tool, constraints, varlist, constraint,
406 }
else if (modtype ==
"custom") {
412 shapeElems.
add(*obj);
421 std::string interpName = sampleName +
"_" + channelName +
"_epsilon";
422 if (!overall_nps.
empty()) {
424 overall_high, overall_interp);
427 if (!histNps.
empty()) {
429 v.setPositiveDefinite();
430 v.setAllInterpCodes(4);
438 if (!normElems.
empty()) {
441 ws.
factory(
"RooConstVar::" + prefixedName +
"_scaleFactors(1.)");
449 bool importArg(RooJSONFactoryWSTool *tool,
const JSONNode &p)
const override
455 double statErrThresh = 0;
456 std::string statErrType =
"Poisson";
457 if (p.
has_child(::Literals::staterror)) {
458 auto &staterr = p[::Literals::staterror];
459 if (staterr.has_child(
"relThreshold"))
460 statErrThresh = staterr[
"relThreshold"].val_double();
461 if (staterr.has_child(
"constraint_type"))
462 statErrType = staterr[
"constraint_type"].val();
464 std::vector<double> sumW;
465 std::vector<double> sumW2;
466 std::vector<std::string> gammaParnames;
469 std::string fprefix =
name;
471 std::vector<std::unique_ptr<RooDataHist>> data;
472 for (
const auto &comp : p[
"samples"].children()) {
475 size_t nbins = dh->numEntries();
477 if (hasStaterror(comp)) {
482 for (
size_t i = 0; i < nbins; ++i) {
483 sumW[i] += dh->weight(i);
484 sumW2[i] += dh->weightSquared(i);
486 if (gammaParnames.empty()) {
487 if (
auto staterrorParams = findStaterror(comp).find(
"parameters")) {
488 for (
const auto &
v : staterrorParams->children()) {
489 gammaParnames.push_back(
v.val());
494 data.emplace_back(std::move(dh));
497 RooAbsArg *mcStatObject =
nullptr;
498 RooArgSet constraints;
500 std::string channelName =
name;
501 erasePrefix(channelName,
"model_");
503 std::vector<double> errs(sumW.size());
504 for (
size_t i = 0; i < sumW.size(); ++i) {
509 errs[i] = std::sqrt(sumW2[i]) / sumW[i];
511 errs[i] = std::max(errs[i], 0.);
515 &createPHF(
"mc_stat_" + channelName,
"stat_" + channelName, gammaParnames, errs, *tool, constraints,
522 for (
const auto &comp : p[
"samples"].children()) {
523 importHistSample(*tool, *data[idx], observables, mcStatObject, fprefix, comp, constraints);
527 funcs.
add(*tool->
request<RooAbsReal>(fprefix +
"_" + compName +
"_shapes",
name));
528 coefs.
add(*tool->
request<RooAbsReal>(fprefix +
"_" + compName +
"_scaleFactors",
name));
531 if (constraints.
empty()) {
534 std::string sumName =
name +
"_model";
535 erasePrefix(sumName,
"model_");
536 auto &
sum = tool->
wsEmplace<RooRealSumPdf>(sumName, funcs, coefs,
true);
546 std::string
const &key()
const override
548 static const std::string keystring =
"interpolation0d";
551 bool exportObject(RooJSONFactoryWSTool *,
const RooAbsArg *func, JSONNode &elem)
const override
553 auto fip =
static_cast<const RooStats::HistFactory::FlexibleInterpVar *
>(func);
554 elem[
"type"] << key();
555 elem[
"interpolationCodes"].
fill_seq(fip->interpolationCodes());
557 elem[
"nom"] << fip->nominal();
558 elem[
"high"].
fill_seq(fip->high(), fip->variables().size());
559 elem[
"low"].
fill_seq(fip->low(), fip->variables().size());
566 std::string
const &key()
const override
568 static const std::string keystring =
"interpolation";
571 bool exportObject(RooJSONFactoryWSTool *,
const RooAbsArg *func, JSONNode &elem)
const override
573 const PiecewiseInterpolation *pip =
static_cast<const PiecewiseInterpolation *
>(func);
574 elem[
"type"] << key();
587 bool importArg(RooJSONFactoryWSTool *tool,
const JSONNode &p)
const override
599 if (p.has_child(
"interpolationCodes")) {
601 for (
auto const &node : p[
"interpolationCodes"].children()) {
602 pip.
setInterpCode(*
static_cast<RooAbsReal *
>(vars.
at(i)), node.val_int(),
true);
613 bool importArg(RooJSONFactoryWSTool *tool,
const JSONNode &p)
const override
626 double nom(p[
"nom"].val_double());
630 std::vector<double> high;
633 std::vector<double> low;
636 if (vars.
size() != low.size() || vars.
size() != high.size()) {
638 "' has non-matching lengths of 'vars', 'high' and 'low'!");
641 auto &fip = tool->
wsEmplace<RooStats::HistFactory::FlexibleInterpVar>(
name, vars, nom, low, high);
643 if (p.has_child(
"interpolationCodes")) {
645 for (
auto const &node : p[
"interpolationCodes"].children()) {
646 fip.setInterpCode(*
static_cast<RooAbsReal *
>(vars.at(i)), node.val_int());
657 RooAbsReal
const *param =
nullptr;
658 RooAbsPdf
const *constraint =
nullptr;
660 NormFactor(RooAbsReal
const &par,
const RooAbsPdf *constr =
nullptr)
661 : name{par.
GetName()}, param{&par}, constraint{constr}
667 std::string name =
"";
668 RooAbsReal
const *param =
nullptr;
671 int interpolationCode = 4;
672 RooAbsPdf
const *constraint =
nullptr;
675 NormSys(
const std::string &
n, RooAbsReal *
const p,
double h,
double l,
int i,
const RooAbsPdf *
c)
676 : name(
n), param(p), low(
l), high(
h), interpolationCode(i), constraint(
c), constraintType(
c->
IsA())
683 RooAbsReal
const *param =
nullptr;
684 std::vector<double> low;
685 std::vector<double> high;
686 RooAbsPdf
const *constraint =
nullptr;
688 HistoSys(
const std::string &
n, RooAbsReal *
const p, RooHistFunc *
l, RooHistFunc *
h,
const RooAbsPdf *
c)
689 : name(
n), param(p), constraint(
c), constraintType(
c->
IsA())
691 low.assign(
l->dataHist().weightArray(),
l->dataHist().weightArray() +
l->dataHist().numEntries());
692 high.assign(
h->dataHist().weightArray(),
h->dataHist().weightArray() +
h->dataHist().numEntries());
697 std::vector<double> constraints;
698 std::vector<RooAbsReal *> parameters;
699 RooAbsPdf
const *constraint =
nullptr;
704struct GenericElement {
706 RooAbsReal *function =
nullptr;
707 GenericElement(RooAbsReal *
e) : name(
e->GetName()), function(
e) {};
710std::string stripOuterParens(
const std::string &s)
713 size_t end = s.size();
715 while (
start < end && s[
start] ==
'(' && s[end - 1] ==
')') {
717 bool balanced =
true;
718 for (
size_t i =
start; i < end - 1; ++i) {
721 else if (s[i] ==
')')
723 if (depth == 0 && i < end - 1) {
738std::vector<std::string> splitTopLevelProduct(
const std::string &expr)
740 std::vector<std::string> parts;
743 bool foundTopLevelStar =
false;
745 for (
size_t i = 0; i < expr.size(); ++i) {
749 }
else if (
c ==
')') {
751 }
else if (
c ==
'*' && depth == 0) {
752 foundTopLevelStar =
true;
753 std::string sub = expr.substr(
start, i -
start);
754 parts.push_back(stripOuterParens(sub));
759 if (!foundTopLevelStar) {
763 std::string sub = expr.substr(
start);
764 parts.push_back(stripOuterParens(sub));
774NormSys parseOverallModifierFormula(
const std::string &s,
RooFormulaVar *formula)
776 static const std::regex pattern(
777 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*$)");
783 if (std::regex_match(s, match, pattern)) {
784 if (match[1].str() ==
"-") {
788 std::string token2 = match[2].str();
789 std::string token3 = match[4].str();
796 auto *constr2 = findConstraint(
v2);
797 auto *constr3 = findConstraint(
v3);
799 if (constr2 && !p3) {
804 }
else if (!p2 && constr3) {
809 }
else if (constr2 && p3 && !constr3) {
810 sys.name =
v2->GetName();
812 sys.high = sign * p3->
getVal();
813 sys.low = -sign * p3->
getVal();
814 }
else if (p2 && !constr2 && constr3) {
815 sys.name =
v3->GetName();
817 sys.high = sign * p2->
getVal();
818 sys.low = -sign * p2->
getVal();
822 sys.interpolationCode = 1;
824 erasePrefix(sys.name,
"alpha_");
831 if (
auto prod =
dynamic_cast<RooProduct *
>(arg)) {
832 for (
const auto &
e : prod->components()) {
833 collectElements(elems,
e);
842 for (
auto *var : list) {
852 std::vector<double> hist;
853 std::vector<double> histError;
854 std::vector<NormFactor> normfactors;
855 std::vector<NormSys> normsys;
856 std::vector<HistoSys> histosys;
857 std::vector<ShapeSys> shapesys;
858 std::vector<GenericElement> tmpElements;
859 std::vector<GenericElement> otherElements;
860 bool useBarlowBeestonLight =
false;
861 std::vector<RooAbsReal *> staterrorParameters;
863 Sample(
const std::string &
n) : name{
n} {}
868 std::string parname = par->
GetName();
869 bool isConstrained =
false;
871 if (
auto gauss =
dynamic_cast<RooGaussian const *
>(pdf)) {
872 if (parname == gauss->getX().GetName()) {
873 sample.normfactors.emplace_back(*par, gauss);
874 isConstrained =
true;
879 sample.normfactors.emplace_back(*par);
890 std::vector<Sample> samples;
891 std::map<int, double> tot_yield;
892 std::map<int, double> tot_yield2;
893 std::map<int, double> rel_errors;
894 RooArgSet
const *varSet =
nullptr;
895 long unsigned int nBins = 0;
904 channel.name = pdfname;
905 erasePrefix(channel.name,
"model_");
906 eraseSuffix(channel.name,
"_model");
908 for (
size_t sampleidx = 0; sampleidx < sumpdf->
funcList().
size(); ++sampleidx) {
910 std::vector<ParamHistFunc *> phfs;
912 const auto func = sumpdf->
funcList().
at(sampleidx);
914 erasePrefix(sample.name,
"L_x_");
915 eraseSuffix(sample.name,
"_shapes");
916 eraseSuffix(sample.name,
"_" + channel.name);
917 erasePrefix(sample.name, pdfname +
"_");
919 auto updateObservables = [&](
RooDataHist const &dataHist) {
920 if (channel.varSet ==
nullptr) {
921 channel.varSet = dataHist.get();
922 channel.nBins = dataHist.numEntries();
924 if (sample.hist.empty()) {
925 auto *w = dataHist.weightArray();
926 sample.hist.assign(w, w + dataHist.numEntries());
929 auto processElements = [&](
const auto &elements,
auto &&self) ->
void {
939 }
else if (
auto constVar =
dynamic_cast<RooConstVar *
>(
e)) {
940 if (constVar->getVal() != 1.) {
941 sample.normfactors.emplace_back(*constVar);
943 }
else if (
auto par =
dynamic_cast<RooRealVar *
>(
e)) {
944 addNormFactor(par, sample, ws);
945 }
else if (
auto hf =
dynamic_cast<const RooHistFunc *
>(
e)) {
946 updateObservables(hf->dataHist());
952 for (
size_t i = 0; i < fip->variables().
size(); ++i) {
954 std::string sysname(var->
GetName());
955 erasePrefix(sysname,
"alpha_");
956 const auto *constraint = findConstraint(var);
960 sample.normsys.emplace_back(sysname, var, fip->high()[i], fip->low()[i],
961 fip->interpolationCodes()[i], constraint);
972 expression.ReplaceAll((
"x[" + std::to_string(i) +
"]").c_str(), p->
GetName());
973 expression.ReplaceAll((
"@" + std::to_string(i)).c_str(), p->
GetName());
975 auto components = splitTopLevelProduct(expression.Data());
976 if (components.size() == 0) {
978 sample.otherElements.push_back(formula);
981 std::vector<RooAbsArg *> realComponents;
983 for (
auto &comp : components) {
987 realComponents.push_back(part);
991 auto normsys = parseOverallModifierFormula(comp, formula);
993 sample.normsys.emplace_back(std::move(normsys));
998 std::string
name = std::string(formula->
GetName()) +
"_part" + std::to_string(idx);
1001 sample.tmpElements.push_back({var});
1003 self(realComponents, self);
1005 }
else if (
auto real =
dynamic_cast<RooAbsReal *
>(
e)) {
1006 sample.otherElements.push_back(real);
1012 collectElements(elems, func);
1013 collectElements(elems, sumpdf->
coefList().
at(sampleidx));
1014 processElements(elems, processElements);
1019 updateObservables(nh->dataHist());
1024 sortByName(sample.normfactors);
1025 sortByName(sample.normsys);
1031 std::string sysname(var->
GetName());
1032 erasePrefix(sysname,
"alpha_");
1035 const auto *constraint = findConstraint(var);
1039 sample.histosys.emplace_back(sysname, var, lo,
hi, constraint);
1044 sortByName(sample.histosys);
1048 if (
startsWith(std::string(phf->GetName()),
"mc_stat_")) {
1050 for (
const auto &
g : phf->paramList()) {
1051 sample.staterrorParameters.push_back(
static_cast<RooRealVar *
>(
g));
1054 if (channel.tot_yield.find(idx) == channel.tot_yield.end()) {
1055 channel.tot_yield[idx] = 0;
1056 channel.tot_yield2[idx] = 0;
1058 channel.tot_yield[idx] += sample.hist[idx - 1];
1059 channel.tot_yield2[idx] += (sample.hist[idx - 1] * sample.hist[idx - 1]);
1061 sample.barlowBeestonLightConstraintType = constraint->
IsA();
1063 double erel = 1. / std::sqrt(constraint_p->
getX().
getVal());
1064 channel.rel_errors[idx] = erel;
1067 channel.rel_errors[idx] = erel;
1070 "currently, only RooPoisson and RooGaussian are supported as constraint types");
1074 sample.useBarlowBeestonLight =
true;
1077 erasePrefix(sys.name, channel.name +
"_");
1078 bool isshapesys = eraseSuffix(sys.name,
"_ShapeSys") || eraseSuffix(sys.name,
"_shapeSys");
1079 bool isshapefactor = eraseSuffix(sys.name,
"_ShapeFactor") || eraseSuffix(sys.name,
"_shapeFactor");
1081 for (
const auto &
g : phf->paramList()) {
1082 sys.parameters.push_back(
static_cast<RooRealVar *
>(
g));
1085 constraint = findConstraint(
g);
1087 constraint = ws->
pdf(constraintName(
g->GetName()));
1088 if (!constraint && !
g->isConstant()) {
1091 }
else if (!isshapefactor) {
1095 sys.constraints.push_back(0.0);
1096 }
else if (
auto constraint_p =
dynamic_cast<RooPoisson *
>(constraint)) {
1097 sys.constraints.push_back(1. / std::sqrt(constraint_p->
getX().
getVal()));
1098 if (!sys.constraint) {
1101 }
else if (
auto constraint_g =
dynamic_cast<RooGaussian *
>(constraint)) {
1103 if (!sys.constraint) {
1108 sample.shapesys.emplace_back(std::move(sys));
1111 sortByName(sample.shapesys);
1114 channel.samples.emplace_back(std::move(sample));
1117 sortByName(channel.samples);
1121void configureStatError(
Channel &channel)
1123 for (
auto &sample : channel.samples) {
1124 if (sample.useBarlowBeestonLight) {
1125 sample.histError.resize(sample.hist.size());
1126 for (
auto bin : channel.rel_errors) {
1129 const int i = bin.first;
1130 const double relerr_tot = bin.second;
1131 const double count = sample.hist[i - 1];
1134 sample.histError[i - 1] =
1135 round_prec(relerr_tot * channel.tot_yield[i] / std::sqrt(channel.tot_yield2[i]) * count, 7);
1145 auto writeConstraint = [](
JSONNode &mod,
auto const &sys) {
1146 if (sys.constraint) {
1147 mod[
"constraint_name"] << sys.constraint->
GetName();
1148 }
else if (sys.constraintType) {
1149 mod[
"constraint_type"] << toString(sys.constraintType);
1153 bool observablesWritten =
false;
1154 for (
const auto &sample : channel.samples) {
1156 elem[
"type"] <<
"histfactory_dist";
1160 auto &modifiers = s[
"modifiers"];
1161 modifiers.set_seq();
1163 for (
const auto &nf : sample.normfactors) {
1166 mod[
"name"] << nf.name;
1167 mod[
"parameter"] << nf.param->GetName();
1168 mod[
"type"] <<
"normfactor";
1169 if (nf.constraint) {
1170 mod[
"constraint_name"] << nf.constraint->GetName();
1175 for (
const auto &sys : sample.normsys) {
1178 mod[
"name"] << sys.name;
1179 mod[
"type"] <<
"normsys";
1180 mod[
"parameter"] << sys.param->
GetName();
1181 if (sys.interpolationCode != 4) {
1182 mod[
"interpolation"] << sys.interpolationCode;
1184 writeConstraint(mod, sys);
1186 data[
"lo"] << sys.low;
1187 data[
"hi"] << sys.high;
1190 for (
const auto &sys : sample.histosys) {
1193 mod[
"name"] << sys.name;
1194 mod[
"type"] <<
"histosys";
1195 mod[
"parameter"] << sys.param->
GetName();
1196 writeConstraint(mod, sys);
1198 if (channel.nBins != sys.low.size() || channel.nBins != sys.high.size()) {
1199 std::stringstream ss;
1200 ss <<
"inconsistent binning: " << channel.nBins <<
" bins expected, but " << sys.low.size() <<
"/"
1201 << sys.high.size() <<
" found in nominal histogram errors!";
1208 for (
const auto &sys : sample.shapesys) {
1211 mod[
"name"] << sys.name;
1212 mod[
"type"] <<
"shapesys";
1213 optionallyExportGammaParameters(mod, sys.name, sys.parameters);
1214 writeConstraint(mod, sys);
1215 auto &vals = mod[
"data"].
set_map()[
"vals"];
1216 if (sys.constraint || sys.constraintType) {
1217 vals.fill_seq(sys.constraints);
1219 vals.fill_seq(std::vector<double>(sys.parameters.size(), 0.0));
1223 for (
const auto &other : sample.otherElements) {
1226 mod[
"name"] << other.name;
1227 mod[
"type"] <<
"custom";
1229 for (
const auto &other : sample.tmpElements) {
1232 mod[
"name"] << other.name;
1233 mod[
"type"] <<
"custom";
1236 if (sample.useBarlowBeestonLight) {
1239 mod[
"name"] << ::Literals::staterror;
1240 mod[
"type"] << ::Literals::staterror;
1241 optionallyExportGammaParameters(mod,
"stat_" + channel.name, sample.staterrorParameters);
1242 mod[
"constraint_type"] << toString(sample.barlowBeestonLightConstraintType);
1245 if (!observablesWritten) {
1246 auto &output = elem[
"axes"].
set_seq();
1248 auto &out = output.append_child().set_map();
1251 out[
"name"] <<
name;
1252 writeAxis(out, *obs);
1254 observablesWritten =
true;
1256 auto &dataNode = s[
"data"].set_map();
1257 if (channel.nBins != sample.hist.size()) {
1258 std::stringstream ss;
1259 ss <<
"inconsistent binning: " << channel.nBins <<
" bins expected, but " << sample.hist.size()
1260 <<
" found in nominal histogram!";
1264 if (!sample.histError.empty()) {
1265 if (channel.nBins != sample.histError.size()) {
1266 std::stringstream ss;
1267 ss <<
"inconsistent binning: " << channel.nBins <<
" bins expected, but " << sample.histError.size()
1268 <<
" found in nominal histogram errors!";
1278std::vector<RooAbsPdf *> findLostConstraints(
const Channel &channel,
const std::vector<RooAbsPdf *> &constraints)
1281 std::set<const RooAbsReal *> vars;
1282 for (
const auto &sample : channel.samples) {
1283 for (
const auto &nf : sample.normfactors) {
1284 vars.insert(nf.param);
1286 for (
const auto &sys : sample.normsys) {
1287 vars.insert(sys.param);
1290 for (
const auto &sys : sample.histosys) {
1291 vars.insert(sys.param);
1293 for (
const auto &sys : sample.shapesys) {
1294 for (
const auto &par : sys.parameters) {
1298 if (sample.useBarlowBeestonLight) {
1299 for (
const auto &par : sample.staterrorParameters) {
1306 std::vector<RooAbsPdf *> lostConstraints;
1307 for (
auto *pdf : constraints) {
1308 bool related =
false;
1309 for (
const auto *var : vars) {
1310 if (pdf->dependsOn(*var)) {
1315 lostConstraints.push_back(pdf);
1319 return lostConstraints;
1323 std::vector<RooAbsPdf *> constraints,
JSONNode &elem)
1328 std::cout << pdfname <<
" is not a sumpdf" << std::endl;
1336 std::cout <<
"sample " << sample->
GetName() <<
" is no RooProduct or RooRealSumPdf in " << pdfname
1342 auto channel = readChannel(tool, pdfname, sumpdf);
1345 if (channel.samples.size() == 0)
1347 for (
auto &sample : channel.samples) {
1348 if (sample.hist.empty()) {
1354 configureStatError(channel);
1356 auto lostConstraints = findLostConstraints(channel, constraints);
1358 for (
const auto *constraint : lostConstraints) {
1360 "losing constraint term '" + std::string(constraint->
GetName()) +
1361 "', implicit constraints are not supported by HS3 yet! The term will appear in the HS3 file, but will not be "
1362 "picked up when creating a likelihood from it! You will have to add it manually as an external constraint.");
1367 for (
const auto &sample : channel.samples) {
1368 for (
auto &modifier : sample.normfactors) {
1369 if (modifier.constraint) {
1373 for (
auto &modifier : sample.normsys) {
1374 if (modifier.constraint) {
1378 for (
auto &modifier : sample.histosys) {
1379 if (modifier.constraint) {
1386 for (
const auto &sample : channel.samples) {
1387 for (
auto &modifier : sample.otherElements) {
1390 for (
auto &modifier : sample.tmpElements) {
1405 return exportChannel(tool, channel, elem);
1410 bool autoExportDependants()
const override {
return false; }
1411 bool tryExport(RooJSONFactoryWSTool *tool,
const RooProdPdf *prodpdf, JSONNode &elem)
const
1413 std::vector<RooAbsPdf *> constraints;
1414 RooRealSumPdf *sumpdf =
nullptr;
1415 for (RooAbsArg *
v : prodpdf->
pdfList()) {
1416 RooAbsPdf *pdf =
static_cast<RooAbsPdf *
>(
v);
1417 auto thispdf =
dynamic_cast<RooRealSumPdf *
>(pdf);
1424 constraints.push_back(pdf);
1430 bool ok = tryExportHistFactory(tool, prodpdf->
GetName(), sumpdf, constraints, elem);
1433 std::string
const &key()
const override
1435 static const std::string keystring =
"histfactory_dist";
1438 bool exportObject(RooJSONFactoryWSTool *tool,
const RooAbsArg *p, JSONNode &elem)
const override
1440 return tryExport(tool,
static_cast<const RooProdPdf *
>(p), elem);
1446 bool autoExportDependants()
const override {
return false; }
1447 bool tryExport(RooJSONFactoryWSTool *tool,
const RooRealSumPdf *sumpdf, JSONNode &elem)
const
1449 std::vector<RooAbsPdf *> constraints;
1450 return tryExportHistFactory(tool, sumpdf->
GetName(), sumpdf, constraints, elem);
1452 std::string
const &key()
const override
1454 static const std::string keystring =
"histfactory_dist";
1457 bool exportObject(RooJSONFactoryWSTool *tool,
const RooAbsArg *p, JSONNode &elem)
const override
1459 return tryExport(tool,
static_cast<const RooRealSumPdf *
>(p), elem);
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
TClass * IsA() const override
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,...
const RooArgList & highList() const
const RooAbsReal * nominalHist() const
Return pointer to the nominal hist function.
bool positiveDefinite() const
const RooArgList & lowList() const
void setInterpCode(RooAbsReal ¶m, int code, bool silent=true)
void setPositiveDefinite(bool flag=true)
const RooArgList & paramList() const
const std::vector< int > & interpolationCodes() 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.
RooFit::OwningPtr< RooArgSet > getParameters(const RooAbsData *data, bool stripDisconnected=true) const
Create a list of leaf nodes in the arg tree starting with ourself as top node that don't match any of...
Abstract container object that can hold multiple RooAbsArg objects.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
Abstract interface for all probability density functions.
TClass * IsA() const override
Int_t numBins(const char *rangeName=nullptr) const override
void setConstant(bool value=true)
virtual double getMax(const char *name=nullptr) const
Get maximum of currently defined range.
virtual double getMin(const char *name=nullptr) const
Get minimum of currently defined range.
Abstract base class for objects that represent a real value and implements functionality common to al...
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
RooArgList is a container object that can hold multiple RooAbsArg objects.
RooAbsArg * at(Int_t idx) const
Return object at given index, or nullptr if index is out of range.
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.
virtual std::string val() const =0
void fill_seq(Collection const &coll)
virtual JSONNode & set_map()=0
virtual JSONNode & append_child()=0
virtual JSONNode & set_seq()=0
virtual bool has_child(std::string const &) const =0
JSONNode const * find(std::string const &key) const
virtual int val_int() const
RooAbsReal const & getMean() const
Get the mean parameter.
RooAbsReal const & getSigma() const
Get the sigma parameter.
A real-valued function sampled from a multidimensional histogram.
RooAbsReal const & getX() const
Get the x variable.
const RooArgList & pdfList() const
Represents the product of a given set of RooAbsReal objects.
Implements a PDF constructed from a sum of functions:
const RooArgList & funcList() const
const RooArgList & coefList() const
Variable that can be changed from the outside.
void setError(double value)
const RooAbsBinning & getBinning(const char *name=nullptr, bool verbose=true, bool createOnTheFly=false, bool shared=true) const override
Return binning definition with name.
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
std::string GetName() const
get name of sample
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.
RooArgSet allPdfs() const
Return set with all probability density function objects.
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.
RooRealVar * var(RooStringView name) const
Retrieve real-valued variable (RooRealVar) with given name. A null pointer is returned if not found.
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.
TClass instances represent classes, structs and namespaces in the ROOT type system.
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
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)
static bool registerImporter(const std::string &key, bool topPriority=true)
static bool registerExporter(const TClass *key, bool topPriority=true)
constexpr double defaultShapeSysGammaMax
constexpr double minShapeUncertainty
constexpr double defaultStatErrorGammaMax
constexpr double defaultGammaMin
Arg_t & getOrCreate(RooWorkspace &ws, std::string const &name, Params_t &&...params)
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)