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_");
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) {
735 return s.substr(start, end - start);
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));
768NormSys parseOverallModifierFormula(
const std::string &s,
RooFormulaVar *formula)
770 static const std::regex pattern(
771 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*$)");
777 if (std::regex_match(s, match, pattern)) {
778 if (match[1].str() ==
"-") {
782 std::string token2 = match[2].str();
783 std::string token3 = match[4].str();
790 auto *constr2 = findConstraint(
v2);
791 auto *constr3 = findConstraint(
v3);
793 if (constr2 && !p3) {
798 }
else if (!p2 && constr3) {
803 }
else if (constr2 && p3 && !constr3) {
804 sys.name =
v2->GetName();
806 sys.high = sign * p3->
getVal();
807 sys.low = -sign * p3->
getVal();
808 }
else if (p2 && !constr2 && constr3) {
809 sys.name =
v3->GetName();
811 sys.high = sign * p2->
getVal();
812 sys.low = -sign * p2->
getVal();
816 sys.interpolationCode = 1;
818 erasePrefix(sys.name,
"alpha_");
825 if (
auto prod =
dynamic_cast<RooProduct *
>(arg)) {
826 for (
const auto &
e : prod->components()) {
827 collectElements(elems,
e);
836 for (
auto *var : list) {
846 std::vector<double> hist;
847 std::vector<double> histError;
848 std::vector<NormFactor> normfactors;
849 std::vector<NormSys> normsys;
850 std::vector<HistoSys> histosys;
851 std::vector<ShapeSys> shapesys;
852 std::vector<GenericElement> tmpElements;
853 std::vector<GenericElement> otherElements;
854 bool useBarlowBeestonLight =
false;
855 std::vector<RooAbsReal *> staterrorParameters;
857 Sample(
const std::string &
n) : name{
n} {}
862 std::string parname = par->
GetName();
863 bool isConstrained =
false;
865 if (
auto gauss =
dynamic_cast<RooGaussian const *
>(pdf)) {
866 if (parname == gauss->getX().GetName()) {
867 sample.normfactors.emplace_back(*par, gauss);
868 isConstrained =
true;
873 sample.normfactors.emplace_back(*par);
884 std::vector<Sample> samples;
885 std::map<int, double> tot_yield;
886 std::map<int, double> tot_yield2;
887 std::map<int, double> rel_errors;
888 RooArgSet
const *varSet =
nullptr;
889 long unsigned int nBins = 0;
898 channel.name = pdfname;
899 erasePrefix(channel.name,
"model_");
900 eraseSuffix(channel.name,
"_model");
902 for (
size_t sampleidx = 0; sampleidx < sumpdf->
funcList().
size(); ++sampleidx) {
904 std::vector<ParamHistFunc *> phfs;
906 const auto func = sumpdf->
funcList().
at(sampleidx);
908 erasePrefix(sample.name,
"L_x_");
909 eraseSuffix(sample.name,
"_shapes");
910 eraseSuffix(sample.name,
"_" + channel.name);
911 erasePrefix(sample.name, pdfname +
"_");
913 auto updateObservables = [&](
RooDataHist const &dataHist) {
914 if (channel.varSet ==
nullptr) {
915 channel.varSet = dataHist.get();
916 channel.nBins = dataHist.numEntries();
918 if (sample.hist.empty()) {
919 auto *
w = dataHist.weightArray();
920 sample.hist.assign(
w,
w + dataHist.numEntries());
923 auto processElements = [&](
const auto &elements,
auto &&self) ->
void {
933 }
else if (
auto constVar =
dynamic_cast<RooConstVar *
>(
e)) {
934 if (constVar->getVal() != 1.) {
935 sample.normfactors.emplace_back(*constVar);
937 }
else if (
auto par =
dynamic_cast<RooRealVar *
>(
e)) {
938 addNormFactor(par, sample, ws);
939 }
else if (
auto hf =
dynamic_cast<const RooHistFunc *
>(
e)) {
940 updateObservables(hf->dataHist());
946 for (
size_t i = 0; i < fip->variables().
size(); ++i) {
948 std::string sysname(var->
GetName());
949 erasePrefix(sysname,
"alpha_");
950 const auto *constraint = findConstraint(var);
954 sample.normsys.emplace_back(sysname, var, fip->high()[i], fip->low()[i],
955 fip->interpolationCodes()[i], constraint);
966 expression.ReplaceAll((
"x[" + std::to_string(i) +
"]").c_str(), p->
GetName());
967 expression.ReplaceAll((
"@" + std::to_string(i)).c_str(), p->
GetName());
969 auto components = splitTopLevelProduct(expression.Data());
970 if (components.size() == 0) {
972 sample.otherElements.push_back(formula);
975 std::vector<RooAbsArg *> realComponents;
977 for (
auto &comp : components) {
981 realComponents.push_back(part);
985 auto normsys = parseOverallModifierFormula(comp, formula);
987 sample.normsys.emplace_back(std::move(normsys));
992 std::string
name = std::string(formula->
GetName()) +
"_part" + std::to_string(idx);
995 sample.tmpElements.push_back({var});
997 self(realComponents, self);
999 }
else if (
auto real =
dynamic_cast<RooAbsReal *
>(
e)) {
1000 sample.otherElements.push_back(real);
1006 collectElements(elems, func);
1007 collectElements(elems, sumpdf->
coefList().
at(sampleidx));
1008 processElements(elems, processElements);
1013 updateObservables(nh->dataHist());
1018 sortByName(sample.normfactors);
1019 sortByName(sample.normsys);
1025 std::string sysname(var->
GetName());
1026 erasePrefix(sysname,
"alpha_");
1029 const auto *constraint = findConstraint(var);
1033 sample.histosys.emplace_back(sysname, var, lo,
hi, constraint);
1038 sortByName(sample.histosys);
1042 if (
startsWith(std::string(phf->GetName()),
"mc_stat_")) {
1044 for (
const auto &
g : phf->paramList()) {
1045 sample.staterrorParameters.push_back(
static_cast<RooRealVar *
>(
g));
1048 if (channel.tot_yield.find(idx) == channel.tot_yield.end()) {
1049 channel.tot_yield[idx] = 0;
1050 channel.tot_yield2[idx] = 0;
1052 channel.tot_yield[idx] += sample.hist[idx - 1];
1053 channel.tot_yield2[idx] += (sample.hist[idx - 1] * sample.hist[idx - 1]);
1055 sample.barlowBeestonLightConstraintType = constraint->
IsA();
1057 double erel = 1. / std::sqrt(constraint_p->
getX().
getVal());
1058 channel.rel_errors[idx] = erel;
1061 channel.rel_errors[idx] = erel;
1064 "currently, only RooPoisson and RooGaussian are supported as constraint types");
1068 sample.useBarlowBeestonLight =
true;
1071 erasePrefix(sys.name, channel.name +
"_");
1072 bool isshapesys = eraseSuffix(sys.name,
"_ShapeSys") || eraseSuffix(sys.name,
"_shapeSys");
1073 bool isshapefactor = eraseSuffix(sys.name,
"_ShapeFactor") || eraseSuffix(sys.name,
"_shapeFactor");
1075 for (
const auto &
g : phf->paramList()) {
1076 sys.parameters.push_back(
static_cast<RooRealVar *
>(
g));
1079 constraint = findConstraint(
g);
1081 constraint = ws->
pdf(constraintName(
g->GetName()));
1082 if (!constraint && !
g->isConstant()) {
1085 }
else if (!isshapefactor) {
1089 sys.constraints.push_back(0.0);
1090 }
else if (
auto constraint_p =
dynamic_cast<RooPoisson *
>(constraint)) {
1091 sys.constraints.push_back(1. / std::sqrt(constraint_p->
getX().
getVal()));
1092 if (!sys.constraint) {
1095 }
else if (
auto constraint_g =
dynamic_cast<RooGaussian *
>(constraint)) {
1097 if (!sys.constraint) {
1102 sample.shapesys.emplace_back(std::move(sys));
1105 sortByName(sample.shapesys);
1108 channel.samples.emplace_back(std::move(sample));
1111 sortByName(channel.samples);
1115void configureStatError(
Channel &channel)
1117 for (
auto &sample : channel.samples) {
1118 if (sample.useBarlowBeestonLight) {
1119 sample.histError.resize(sample.hist.size());
1120 for (
auto bin : channel.rel_errors) {
1123 const int i = bin.first;
1124 const double relerr_tot = bin.second;
1125 const double count = sample.hist[i - 1];
1128 sample.histError[i - 1] =
1129 round_prec(relerr_tot * channel.tot_yield[i] / std::sqrt(channel.tot_yield2[i]) * count, 7);
1139 auto writeConstraint = [](
JSONNode &mod,
auto const &sys) {
1140 if (sys.constraint) {
1141 mod[
"constraint_name"] << sys.constraint->
GetName();
1142 }
else if (sys.constraintType) {
1143 mod[
"constraint_type"] << toString(sys.constraintType);
1147 bool observablesWritten =
false;
1148 for (
const auto &sample : channel.samples) {
1150 elem[
"type"] <<
"histfactory_dist";
1154 auto &modifiers = s[
"modifiers"];
1155 modifiers.set_seq();
1157 for (
const auto &nf : sample.normfactors) {
1160 mod[
"name"] << nf.name;
1161 mod[
"parameter"] << nf.param->GetName();
1162 mod[
"type"] <<
"normfactor";
1163 if (nf.constraint) {
1164 mod[
"constraint_name"] << nf.constraint->GetName();
1169 for (
const auto &sys : sample.normsys) {
1172 mod[
"name"] << sys.name;
1173 mod[
"type"] <<
"normsys";
1174 mod[
"parameter"] << sys.param->
GetName();
1175 if (sys.interpolationCode != 4) {
1176 mod[
"interpolation"] << sys.interpolationCode;
1178 writeConstraint(mod, sys);
1180 data[
"lo"] << sys.low;
1181 data[
"hi"] << sys.high;
1184 for (
const auto &sys : sample.histosys) {
1187 mod[
"name"] << sys.name;
1188 mod[
"type"] <<
"histosys";
1189 mod[
"parameter"] << sys.param->
GetName();
1190 writeConstraint(mod, sys);
1192 if (channel.nBins != sys.low.size() || channel.nBins != sys.high.size()) {
1193 std::stringstream ss;
1194 ss <<
"inconsistent binning: " << channel.nBins <<
" bins expected, but " << sys.low.size() <<
"/"
1195 << sys.high.size() <<
" found in nominal histogram errors!";
1202 for (
const auto &sys : sample.shapesys) {
1205 mod[
"name"] << sys.name;
1206 mod[
"type"] <<
"shapesys";
1207 optionallyExportGammaParameters(mod, sys.name, sys.parameters);
1208 writeConstraint(mod, sys);
1209 auto &vals = mod[
"data"].
set_map()[
"vals"];
1210 if (sys.constraint || sys.constraintType) {
1211 vals.fill_seq(sys.constraints);
1213 vals.fill_seq(std::vector<double>(sys.parameters.size(), 0.0));
1217 for (
const auto &other : sample.otherElements) {
1220 mod[
"name"] << other.name;
1221 mod[
"type"] <<
"custom";
1223 for (
const auto &other : sample.tmpElements) {
1226 mod[
"name"] << other.name;
1227 mod[
"type"] <<
"custom";
1230 if (sample.useBarlowBeestonLight) {
1233 mod[
"name"] << ::Literals::staterror;
1234 mod[
"type"] << ::Literals::staterror;
1235 optionallyExportGammaParameters(mod,
"stat_" + channel.name, sample.staterrorParameters);
1236 mod[
"constraint_type"] << toString(sample.barlowBeestonLightConstraintType);
1239 if (!observablesWritten) {
1240 auto &output = elem[
"axes"].
set_seq();
1242 auto &out = output.append_child().set_map();
1245 out[
"name"] <<
name;
1246 writeAxis(out, *obs);
1248 observablesWritten =
true;
1250 auto &dataNode = s[
"data"].set_map();
1251 if (channel.nBins != sample.hist.size()) {
1252 std::stringstream ss;
1253 ss <<
"inconsistent binning: " << channel.nBins <<
" bins expected, but " << sample.hist.size()
1254 <<
" found in nominal histogram!";
1258 if (!sample.histError.empty()) {
1259 if (channel.nBins != sample.histError.size()) {
1260 std::stringstream ss;
1261 ss <<
"inconsistent binning: " << channel.nBins <<
" bins expected, but " << sample.histError.size()
1262 <<
" found in nominal histogram errors!";
1272std::vector<RooAbsPdf *> findLostConstraints(
const Channel &channel,
const std::vector<RooAbsPdf *> &constraints)
1275 std::set<const RooAbsReal *> vars;
1276 for (
const auto &sample : channel.samples) {
1277 for (
const auto &nf : sample.normfactors) {
1278 vars.insert(nf.param);
1280 for (
const auto &sys : sample.normsys) {
1281 vars.insert(sys.param);
1284 for (
const auto &sys : sample.histosys) {
1285 vars.insert(sys.param);
1287 for (
const auto &sys : sample.shapesys) {
1288 for (
const auto &par : sys.parameters) {
1292 if (sample.useBarlowBeestonLight) {
1293 for (
const auto &par : sample.staterrorParameters) {
1300 std::vector<RooAbsPdf *> lostConstraints;
1301 for (
auto *pdf : constraints) {
1302 bool related =
false;
1303 for (
const auto *var : vars) {
1304 if (pdf->dependsOn(*var)) {
1309 lostConstraints.push_back(pdf);
1313 return lostConstraints;
1317 std::vector<RooAbsPdf *> constraints,
JSONNode &elem)
1322 std::cout << pdfname <<
" is not a sumpdf" << std::endl;
1330 std::cout <<
"sample " << sample->
GetName() <<
" is no RooProduct or RooRealSumPdf in " << pdfname
1336 auto channel = readChannel(tool, pdfname, sumpdf);
1339 if (channel.samples.size() == 0)
1341 for (
auto &sample : channel.samples) {
1342 if (sample.hist.empty()) {
1348 configureStatError(channel);
1350 auto lostConstraints = findLostConstraints(channel, constraints);
1352 for (
const auto *constraint : lostConstraints) {
1354 "losing constraint term '" + std::string(constraint->
GetName()) +
1355 "', implicit constraints are not supported by HS3 yet! The term will appear in the HS3 file, but will not be "
1356 "picked up when creating a likelihood from it! You will have to add it manually as an external constraint.");
1361 for (
const auto &sample : channel.samples) {
1362 for (
auto &
modifier : sample.normfactors) {
1367 for (
auto &
modifier : sample.normsys) {
1372 for (
auto &
modifier : sample.histosys) {
1380 for (
const auto &sample : channel.samples) {
1381 for (
auto &
modifier : sample.otherElements) {
1384 for (
auto &
modifier : sample.tmpElements) {
1399 return exportChannel(tool, channel, elem);
1404 bool autoExportDependants()
const override {
return false; }
1405 bool tryExport(RooJSONFactoryWSTool *tool,
const RooProdPdf *prodpdf, JSONNode &elem)
const
1407 std::vector<RooAbsPdf *> constraints;
1408 RooRealSumPdf *sumpdf =
nullptr;
1410 auto thispdf =
dynamic_cast<RooRealSumPdf *
>(pdf);
1417 constraints.push_back(pdf);
1423 bool ok = tryExportHistFactory(tool, prodpdf->
GetName(), sumpdf, constraints, elem);
1426 std::string
const &key()
const override
1428 static const std::string keystring =
"histfactory_dist";
1431 bool exportObject(RooJSONFactoryWSTool *tool,
const RooAbsArg *p, JSONNode &elem)
const override
1433 return tryExport(tool,
static_cast<const RooProdPdf *
>(p), elem);
1439 bool autoExportDependants()
const override {
return false; }
1440 bool tryExport(RooJSONFactoryWSTool *tool,
const RooRealSumPdf *sumpdf, JSONNode &elem)
const
1442 std::vector<RooAbsPdf *> constraints;
1443 return tryExportHistFactory(tool, sumpdf->
GetName(), sumpdf, constraints, elem);
1445 std::string
const &key()
const override
1447 static const std::string keystring =
"histfactory_dist";
1450 bool exportObject(RooJSONFactoryWSTool *tool,
const RooAbsArg *p, JSONNode &elem)
const override
1452 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
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 w
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 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,...
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)