54double round_prec(
double d,
int nSig)
58 int ndigits = std::floor(std::log10(std::abs(
d))) + 1 - nSig;
59 double sf = std::pow(10, ndigits);
60 if (std::abs(
d / sf) < 2)
62 return sf * std::round(
d / sf);
68constexpr auto staterror =
"staterror";
74 std::optional<std::string> out;
76 bool operator==(
const Interpolation &other)
const
78 return std::tie(type, in, out) == std::tie(other.type, other.in, other.out);
81 bool operator!=(
const Interpolation &other)
const {
return !(*
this == other); }
83 bool operator<(
const Interpolation &other)
const
85 return std::tie(type, in, out) < std::tie(other.type, other.in, other.out);
89const Interpolation additivePiecewiseLinear{
"add",
"poly1", std::nullopt};
90const Interpolation multiplicativePiecewiseExponential{
"mult",
"exp", std::nullopt};
91const Interpolation additiveQuadraticLinear{
"add",
"poly2",
"poly1"};
92const Interpolation additivePolynomialLinear{
"add",
"poly6",
"poly1"};
93const Interpolation multiplicativePolynomialExponential{
"mult",
"poly6",
"exp"};
94const Interpolation multiplicativePolynomialLinear{
"mult",
"poly6",
"poly1"};
96std::string interpolationString(
const Interpolation &interpolation)
99 ss << R
"({"type":")" << interpolation.type << R"(","in":")" << interpolation.in << R"(","out":)";
100 if (interpolation.out) {
101 ss <<
'"' << *interpolation.out <<
'"';
109bool isInterpolationFunction(std::string_view function)
111 return function ==
"poly1" || function ==
"poly2" || function ==
"poly6" || function ==
"exp";
114Interpolation readInterpolation(
const JSONNode &node,
const std::string &context)
119 for (
const char *component : {
"type",
"in",
"out"}) {
125 const auto &typeNode = node[
"type"];
126 const auto &inNode = node[
"in"];
127 const auto &outNode = node[
"out"];
128 if (typeNode.is_container() || typeNode.is_null() || inNode.is_container() || inNode.is_null()) {
132 Interpolation interpolation{typeNode.val(), inNode.val(), std::nullopt};
133 if (interpolation.type !=
"add" && interpolation.type !=
"mult") {
136 if (!isInterpolationFunction(interpolation.in)) {
140 if (!outNode.is_null()) {
141 if (outNode.is_container()) {
144 interpolation.out = outNode.val();
145 if (!isInterpolationFunction(*interpolation.out)) {
150 return interpolation;
153void writeInterpolation(
JSONNode &node,
const Interpolation &interpolation)
156 node[
"type"] << interpolation.type;
157 node[
"in"] << interpolation.in;
158 if (interpolation.out) {
159 node[
"out"] << *interpolation.out;
165int readLegacyInterpolationCode(
const JSONNode &node,
const std::string &context)
171 const std::string
value = node.
val();
180enum class InterpolationClass {
190struct InterpolationCodes {
191 const Interpolation &descriptor;
196constexpr int kUnrepresentable = -1;
199const std::vector<InterpolationCodes> interpolationTable{
200 {additivePiecewiseLinear, 0, 0},
201 {multiplicativePiecewiseExponential, 1, 1},
202 {additiveQuadraticLinear, 2, 2},
203 {additivePolynomialLinear, 4, kUnrepresentable},
204 {multiplicativePolynomialExponential, 5, 4},
205 {multiplicativePolynomialLinear, 6, kUnrepresentable},
209int codeForClass(
const InterpolationCodes &row, InterpolationClass interpolationClass)
211 return interpolationClass == InterpolationClass::Piecewise ? row.piecewise : row.flexible;
214const char *interpolationClassName(InterpolationClass interpolationClass)
216 return interpolationClass == InterpolationClass::Piecewise ?
"PiecewiseInterpolation" :
"FlexibleInterpVar";
219Interpolation interpolationFromCode(
int code, InterpolationClass interpolationClass,
const std::string &context)
226 if (interpolationClass == InterpolationClass::Flexible && code == 5) {
229 for (
const auto &row : interpolationTable) {
230 const int rowCode = codeForClass(row, interpolationClass);
231 if (rowCode != kUnrepresentable && rowCode == code) {
232 return row.descriptor;
236 std::to_string(code));
239int codeFromInterpolation(
const Interpolation &interpolation, InterpolationClass interpolationClass,
240 const std::string &context)
242 for (
const auto &row : interpolationTable) {
243 const int rowCode = codeForClass(row, interpolationClass);
244 if (rowCode != kUnrepresentable && row.descriptor == interpolation) {
249 interpolationClassName(interpolationClass));
252void writeInterpolations(
JSONNode &node,
const std::vector<int> &codes, InterpolationClass interpolationClass,
253 const std::string &context)
255 auto &interpolations = node.
set_seq();
260 std::vector<Interpolation> descriptors;
261 descriptors.reserve(codes.size());
262 for (std::size_t i = 0; i < codes.size(); ++i) {
263 descriptors.push_back(
264 interpolationFromCode(codes[i], interpolationClass, context +
" at parameter index " + std::to_string(i)));
267 bool allEqual =
true;
268 for (std::size_t i = 1; i < descriptors.size(); ++i) {
269 if (descriptors[i] != descriptors.front()) {
275 const std::size_t outputSize = allEqual ? 1 : descriptors.size();
276 for (std::size_t i = 0; i < outputSize; ++i) {
277 writeInterpolation(interpolations.append_child(), descriptors[i]);
281std::vector<int> readInterpolations(
const JSONNode &
object, std::size_t nParameters,
282 InterpolationClass interpolationClass,
const std::string &context)
284 if (
const auto *interpolations =
object.find(
"interpolations")) {
285 if (!interpolations->is_seq()) {
289 const std::size_t
size = interpolations->num_children();
290 const bool validSize = nParameters == 0 ?
size == 0 :
size == 1 ||
size == nParameters;
293 " component 'interpolations' must contain either one descriptor or one "
294 "descriptor per parameter (got " +
295 std::to_string(
size) +
" for " + std::to_string(nParameters) +
" parameters)");
298 std::vector<int> codes;
301 for (
const auto &node : interpolations->children()) {
302 const std::string entryContext = context +
" component 'interpolations' at index " + std::to_string(i);
304 codeFromInterpolation(readInterpolation(node, entryContext), interpolationClass, entryContext));
308 codes.resize(nParameters, codes.front());
313 std::vector<int> codes(nParameters, 0);
314 if (
const auto *legacyCodes =
object.find(
"interpolationCodes")) {
315 if (!legacyCodes->is_seq()) {
318 if (legacyCodes->num_children() != nParameters) {
320 " legacy component 'interpolationCodes' must contain one code per "
322 std::to_string(legacyCodes->num_children()) +
" for " +
323 std::to_string(nParameters) +
" parameters)");
327 for (
const auto &node : legacyCodes->children()) {
328 const std::string entryContext =
329 context +
" legacy component 'interpolationCodes' at index " + std::to_string(i);
330 const Interpolation interpolation =
331 interpolationFromCode(readLegacyInterpolationCode(node, entryContext), interpolationClass, entryContext);
332 codes[i] = codeFromInterpolation(interpolation, interpolationClass, entryContext);
339int interpolationCode(
const JSONNode &
modifier,
const std::optional<Interpolation> &defaultInterpolation,
340 InterpolationClass interpolationClass,
const std::string &context)
342 const auto toCode = [&](
const Interpolation &interpolation) {
343 return codeFromInterpolation(interpolation, interpolationClass, context);
346 if (
const auto *interpolationNode =
modifier.find(
"interpolation")) {
347 if (interpolationNode->is_map()) {
348 return toCode(readInterpolation(*interpolationNode, context));
350 const int legacyCode = readLegacyInterpolationCode(*interpolationNode, context);
351 const Interpolation interpolation = interpolationFromCode(legacyCode, interpolationClass, context);
352 return toCode(interpolation);
354 if (defaultInterpolation) {
355 return toCode(*defaultInterpolation);
364void erasePrefix(std::string &str, std::string_view prefix)
367 str.erase(0, prefix.size());
371bool eraseSuffix(std::string &str, std::string_view suffix)
374 str.erase(str.size() - suffix.size());
382void sortByName(Coll &coll)
384 std::sort(coll.begin(), coll.end(), [](
auto &
l,
auto &
r) { return l.name < r.name; });
390 for (
const auto &client :
gamma->clients()) {
391 if (
auto casted =
dynamic_cast<T *
>(client)) {
394 T *
c = findClient<T>(client);
406 if (
auto *constraint = findClient<RooPoisson>(
g))
408 if (
auto *constraint = findClient<RooGaussian>(
g))
410 return findClient<RooLognormal>(
g);
413inline std::string defaultGammaName(std::string
const &sysname, std::size_t i)
415 return "gamma_" + sysname +
"_bin_" + std::to_string(i);
419void exportGammaParameters(
JSONNode &mod, std::vector<RooAbsReal *>
const ¶ms)
421 std::vector<std::string> paramNames;
423 paramNames.emplace_back(param->GetName());
425 mod[
"parameters"].
fill_seq(paramNames);
428RooRealVar &createNominal(
RooWorkspace &ws, std::string
const &parname,
double val,
double min,
double max)
430 RooRealVar &nom = getOrCreate<RooRealVar>(ws,
"nom_" + parname, val, min, max);
437std::string constraintName(std::string
const ¶mName)
439 return paramName +
"Constraint";
442bool isLegacyConstraintType(std::string
const &
value)
449 if (
auto *constraint = tool.
workspace()->
pdf(constraintName)) {
456 if (err.
child() != constraintName) {
465 std::string
const &constraintType)
467 if (constraintType ==
"Gauss") {
469 return getOrCreate<RooGaussian>(*tool.
workspace(), constraintName(param.
GetName()), param,
475 "' is a known constraint type, but it cannot be resolved in this context");
478ParamHistFunc &createPHF(
const std::string &phfname, std::string
const &sysname,
479 const std::vector<std::string> &parnames,
const std::vector<double> &vals,
481 const std::string &constraintType,
double gammaMin,
double gammaMax,
double minSigma,
482 bool createConstraints =
true)
486 size_t n = std::max(vals.size(), parnames.size());
488 for (std::size_t i = 0; i <
n; ++i) {
489 const std::string
name = parnames.empty() ? defaultGammaName(sysname, i) : parnames[i];
494 gammas.
add(getOrCreate<RooRealVar>(ws,
name, 1., gammaMin, gammaMax));
499 if (vals.size() > 0) {
500 if (!createConstraints) {
502 }
else if (constraintType !=
"Const") {
505 for (
auto const &term : constraintsInfo.constraints) {
507 constraints.
add(*ws.
pdf(term->GetName()));
511 gamma->setConstant(
true);
523 for (
const auto &mod : comp[
"modifiers"].children()) {
524 if (mod[
"type"].val() == ::Literals::staterror)
534 JSONNode const *constrName = mod.
find(
"constraint_name");
536 auto constraint_name = constrName->
val();
537 auto constraint = findNamedConstraint(tool, constraint_name, sample);
542 if (
auto gauss =
dynamic_cast<RooGaussian *const
>(constraint)) {
543 param.
setError(gauss->getSigma().getVal());
548 if (
auto constr = mod.
find(
"constraint")) {
549 std::string constraintValue = constr->val();
550 if (
auto *constraint = findNamedConstraint(tool, constraintValue, sample)) {
551 if (
auto gauss =
dynamic_cast<RooGaussian *const
>(constraint)) {
552 param.
setError(gauss->getSigma().getVal());
557 if (isLegacyConstraintType(constraintValue)) {
558 return createLegacyConstraint(tool, mod, param, constraintValue);
563 "': this looks like a legacy workspace where the 'constraint' field is neither a "
564 "constraint pdf name nor a supported legacy constraint type");
567 std::string constraint_type =
"Gauss";
568 if (
auto constrType = mod.
find(
"constraint_type")) {
569 constraint_type = constrType->val();
571 if (isLegacyConstraintType(constraint_type)) {
572 return createLegacyConstraint(tool, mod, param, constraint_type);
581 std::string(constraint.
GetName()));
589 if (
auto const *tau =
dynamic_cast<RooConstVar const *
>(arg)) {
590 return tau->getVal();
595 if (
auto const *real =
dynamic_cast<RooAbsReal const *
>(arg)) {
596 if (real->isConstant() ||
endsWith(std::string(real->GetName()),
"_tau")) {
597 return real->getVal();
603 std::string(constraint.
GetName()));
604 return std::numeric_limits<double>::quiet_NaN();
611 if (
auto constraintP =
dynamic_cast<RooPoisson const *
>(&constraint)) {
612 return 1. / std::sqrt(poissonTau(*constraintP, gamma));
614 if (
auto constraintG =
dynamic_cast<RooGaussian const *
>(&constraint)) {
615 return constraintG->getSigma().getVal() / constraintG->getMean().getVal();
618 return std::numeric_limits<double>::quiet_NaN();
623 const std::optional<Interpolation> &defaultInterpolation,
RooArgSet &constraints)
628 std::string prefixedName = fprefix +
"_" + sampleName;
630 std::string channelName = fprefix;
631 erasePrefix(channelName,
"model_");
633 if (!
p.has_child(
"data")) {
645 if (findStaterror(
p)) {
646 shapeElems.
add(*mcStatObject);
649 if (
p.has_child(
"modifiers")) {
651 std::vector<double> overall_low;
652 std::vector<double> overall_high;
653 std::vector<int> overall_interp;
658 std::vector<int> histoInterp;
661 for (
const auto &mod :
p[
"modifiers"].children()) {
662 std::string
const &modtype = mod[
"type"].
val();
663 std::string
const &sysname =
666 : (mod.
has_child(
"parameter") ? mod[
"parameter"].
val() :
"syst_" + std::to_string(idx));
668 if (modtype ==
"staterror") {
670 }
else if (modtype ==
"normfactor") {
671 RooRealVar &constrParam = getOrCreate<RooRealVar>(ws, sysname, 1., -3, 5);
673 normElems.
add(constrParam);
676 constraints.
add(getOrCreateConstraint(tool, mod, constrParam, sampleName));
678 }
else if (modtype ==
"normsys") {
679 auto *parameter = mod.
find(
"parameter");
680 std::string parname(parameter ? parameter->val() :
"alpha_" + sysname);
681 createNominal(ws, parname, 0.0, -10, 10);
682 auto &par = getOrCreate<RooRealVar>(ws, parname, 0., -5, 5);
683 overall_nps.
add(par);
684 auto &
data = mod[
"data"];
685 const std::string context =
"interpolation for normsys modifier '" + sysname +
"' in sample '" +
686 sampleName +
"' of channel '" + channelName +
"'";
687 const int interp = interpolationCode(mod, defaultInterpolation, InterpolationClass::Flexible, context);
688 double low =
data[
"lo"].val_double();
689 double high =
data[
"hi"].val_double();
695 if (interp == 4 && low <= 0)
696 low = std::numeric_limits<double>::epsilon();
697 if (interp == 4 && high <= 0)
698 high = std::numeric_limits<double>::epsilon();
700 overall_low.push_back(low);
701 overall_high.push_back(high);
702 overall_interp.push_back(interp);
704 constraints.
add(getOrCreateConstraint(tool, mod, par, sampleName));
705 }
else if (modtype ==
"histosys") {
706 auto *parameter = mod.
find(
"parameter");
707 std::string parname(parameter ? parameter->val() :
"alpha_" + sysname);
708 createNominal(ws, parname, 0.0, -10, 10);
709 auto &par = getOrCreate<RooRealVar>(ws, parname, 0., -5, 5);
711 auto &
data = mod[
"data"];
713 sysname +
"Low_" + prefixedName, varlist,
716 sysname +
"High_" + prefixedName, varlist,
718 const std::string context =
"interpolation for histosys modifier '" + sysname +
"' in sample '" +
719 sampleName +
"' of channel '" + channelName +
"'";
720 histoInterp.push_back(interpolationCode(mod, defaultInterpolation, InterpolationClass::Piecewise, context));
721 constraints.
add(getOrCreateConstraint(tool, mod, par, sampleName));
722 }
else if (modtype ==
"shapesys" || modtype ==
"shapefactor") {
723 std::string funcName = channelName +
"_" + sysname +
"_ShapeSys";
725 std::vector<double> vals;
726 if (mod[
"data"].has_child(
"vals")) {
727 for (
const auto &
v : mod[
"data"][
"vals"].children()) {
728 vals.push_back(
v.val_double());
731 std::vector<std::string> parnames;
732 for (
const auto &
v : mod[
"parameters"].children()) {
733 parnames.push_back(
v.val());
735 if (vals.empty() && parnames.empty()) {
737 "' with neither values nor parameters!");
739 std::string constraint =
"unknown";
740 std::vector<RooAbsPdf *> constraintPdfs;
741 bool const hasConstraintList = mod.
has_child(
"constraints");
742 if (hasConstraintList) {
743 for (
const auto &
v : mod[
"constraints"].children()) {
745 constraintPdfs.push_back(
nullptr);
747 std::string constraintName =
v.val();
748 auto *constraintPdf = findNamedConstraint(tool, constraintName, sampleName);
749 if (!constraintPdf) {
753 constraintPdfs.push_back(constraintPdf);
756 std::size_t
const nGammas = std::max(vals.size(), parnames.size());
757 if (constraintPdfs.size() != nGammas) {
758 std::stringstream ss;
760 <<
" constraints, but " << nGammas <<
" parameters";
763 }
else if (mod.
has_child(
"constraint_type")) {
764 constraint = mod[
"constraint_type"].
val();
765 }
else if (mod.
has_child(
"constraint")) {
766 std::string constraintValue = mod[
"constraint"].
val();
767 if (isLegacyConstraintType(constraintValue)) {
768 constraint = constraintValue;
772 "': this looks like a legacy workspace where the 'constraint' field is "
773 "not a supported legacy constraint type");
776 shapeElems.
add(createPHF(funcName, sysname, parnames, vals, tool, constraints, varlist, constraint,
778 !hasConstraintList));
779 for (
auto *constraintPdf : constraintPdfs) {
781 constraints.
add(*constraintPdf);
784 }
else if (modtype ==
"custom") {
790 shapeElems.
add(*obj);
799 std::string interpName = sampleName +
"_" + channelName +
"_epsilon";
800 if (!overall_nps.
empty()) {
802 overall_high, overall_interp);
805 if (!histNps.
empty()) {
816 if (!normElems.
empty()) {
819 ws.
factory(
"RooConstVar::" + prefixedName +
"_scaleFactors(1.)");
830 if (!
p.has_child(
"samples")) {
833 double statErrThresh = 0;
834 std::string statErrType =
"Poisson";
835 std::optional<Interpolation> defaultInterpolation;
836 if (
p.has_child(
"default_interpolation")) {
837 defaultInterpolation =
838 readInterpolation(
p[
"default_interpolation"],
"default_interpolation of channel '" +
name +
"'");
840 if (
p.has_child(::Literals::staterror)) {
841 auto &staterr =
p[::Literals::staterror];
842 if (staterr.has_child(
"relThreshold"))
843 statErrThresh = staterr[
"relThreshold"].val_double();
844 if (staterr.has_child(
"constraint_type"))
845 statErrType = staterr[
"constraint_type"].val();
847 std::vector<double> sumW;
848 std::vector<double> sumW2;
849 std::vector<std::string> gammaParnames;
852 std::string fprefix =
name;
854 std::vector<std::unique_ptr<RooDataHist>>
data;
855 for (
const auto &comp :
p[
"samples"].children()) {
858 size_t nbins = dh->numEntries();
860 if (
const JSONNode *staterror = findStaterror(comp)) {
865 for (
size_t i = 0; i < nbins; ++i) {
866 sumW[i] += dh->weight(i);
867 sumW2[i] += dh->weightSquared(i);
869 if (gammaParnames.empty()) {
870 if (
auto staterrorParams = staterror->find(
"parameters")) {
871 for (
const auto &
v : staterrorParams->children()) {
872 gammaParnames.push_back(
v.val());
877 data.emplace_back(std::move(dh));
883 std::string channelName =
name;
884 erasePrefix(channelName,
"model_");
886 std::vector<double> errs(sumW.size());
887 for (
size_t i = 0; i < sumW.size(); ++i) {
892 errs[i] = std::sqrt(sumW2[i]) / sumW[i];
894 errs[i] = std::max(errs[i], 0.);
898 &createPHF(
"mc_stat_" + channelName,
"stat_" + channelName, gammaParnames, errs, *tool, constraints,
905 for (
const auto &comp :
p[
"samples"].children()) {
906 importHistSample(*tool, *
data[idx], observables, mcStatObject, fprefix, comp, defaultInterpolation,
915 if (constraints.
empty()) {
918 std::string sumName =
name +
"_model";
919 erasePrefix(sumName,
"model_");
930 std::string
const &key()
const override
932 static const std::string keystring =
"interpolation0d";
939 if (fip->low().size() != nParameters || fip->high().size() != nParameters ||
940 fip->interpolationCodes().size() != nParameters) {
942 "' has non-matching parameter, variation, and interpolation lengths");
944 elem[
"type"] << key();
945 writeInterpolations(elem[
"interpolations"], fip->interpolationCodes(), InterpolationClass::Flexible,
946 "FlexibleInterpVar '" + std::string{fip->GetName()} +
"'");
948 elem[
"nom"] << fip->nominal();
949 elem[
"high"].
fill_seq(fip->high(), fip->variables().size());
950 elem[
"low"].
fill_seq(fip->low(), fip->variables().size());
957 std::string
const &key()
const override
959 static const std::string keystring =
"interpolation";
969 "' has non-matching parameter, variation, and interpolation lengths");
971 elem[
"type"] << key();
972 writeInterpolations(elem[
"interpolations"], pip->
interpolationCodes(), InterpolationClass::Piecewise,
973 "PiecewiseInterpolation '" + std::string{pip->GetName()} +
"'");
992 if (vars.size() != low.size() || vars.size() != high.size()) {
994 "' has non-matching lengths of 'vars', 'high' and 'low'");
996 const std::vector<int> codes =
997 readInterpolations(
p, vars.size(), InterpolationClass::Piecewise,
"PiecewiseInterpolation '" +
name +
"'");
1013 if (!
p.has_child(
"high")) {
1016 if (!
p.has_child(
"low")) {
1019 if (!
p.has_child(
"nom")) {
1023 double nom(
p[
"nom"].val_double());
1027 std::vector<double> high;
1030 std::vector<double> low;
1033 if (vars.size() != low.size() || vars.size() != high.size()) {
1035 "' has non-matching lengths of 'vars', 'high' and 'low'!");
1037 const std::vector<int> codes =
1038 readInterpolations(
p, vars.size(), InterpolationClass::Flexible,
"FlexibleInterpVar '" +
name +
"'");
1051 :
name{par.
GetName()}, param{&par}, constraint{constr}
1057 std::string
name =
"";
1061 Interpolation interpolation = multiplicativePolynomialExponential;
1065 :
name(
n), param(
p), low(
l), high(
h), interpolation(std::move(i)), constraint(
c)
1073 std::vector<double> low;
1074 std::vector<double> high;
1075 Interpolation interpolation = additivePolynomialLinear;
1079 :
name(
n), param(
p), interpolation(std::move(i)), constraint(
c)
1081 low.assign(
l->dataHist().weightArray(),
l->dataHist().weightArray() +
l->dataHist().numEntries());
1082 high.assign(
h->dataHist().weightArray(),
h->dataHist().weightArray() +
h->dataHist().numEntries());
1087 std::vector<double> constraints;
1088 std::vector<RooAbsPdf const *> constraintPdfs;
1089 std::vector<RooAbsReal *> parameters;
1093struct GenericElement {
1099std::string stripOuterParens(
const std::string &s)
1102 size_t end = s.size();
1104 while (start < end && s[start] ==
'(' && s[end - 1] ==
')') {
1106 bool balanced =
true;
1107 for (
size_t i = start; i < end - 1; ++i) {
1110 else if (s[i] ==
')')
1112 if (depth == 0 && i < end - 1) {
1124 return s.substr(start, end - start);
1127std::vector<std::string> splitTopLevelProduct(
const std::string &expr)
1129 std::vector<std::string> parts;
1132 bool foundTopLevelStar =
false;
1134 for (
size_t i = 0; i < expr.size(); ++i) {
1138 }
else if (
c ==
')') {
1140 }
else if (
c ==
'*' && depth == 0) {
1141 foundTopLevelStar =
true;
1142 std::string sub = expr.substr(start, i - start);
1143 parts.push_back(stripOuterParens(sub));
1148 if (!foundTopLevelStar) {
1152 std::string sub = expr.substr(start);
1153 parts.push_back(stripOuterParens(sub));
1157NormSys parseOverallModifierFormula(
const std::string &s,
RooFormulaVar *formula)
1159 static const std::regex pattern(
1160 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*$)");
1166 if (std::regex_match(s, match, pattern)) {
1167 if (match[1].str() ==
"-") {
1171 std::string token2 = match[2].str();
1172 std::string token3 = match[4].str();
1179 auto *constr2 = findConstraint(
v2);
1180 auto *constr3 = findConstraint(
v3);
1182 if (constr2 && !p3) {
1185 sys.high = sign *
toDouble(token3);
1186 sys.low = -sign *
toDouble(token3);
1187 }
else if (!p2 && constr3) {
1190 sys.high = sign *
toDouble(token2);
1191 sys.low = -sign *
toDouble(token2);
1192 }
else if (constr2 && p3 && !constr3) {
1193 sys.name =
v2->GetName();
1195 sys.high = sign * p3->
getVal();
1196 sys.low = -sign * p3->
getVal();
1197 }
else if (p2 && !constr2 && constr3) {
1198 sys.name =
v3->GetName();
1200 sys.high = sign * p2->
getVal();
1201 sys.low = -sign * p2->
getVal();
1205 sys.interpolation = multiplicativePiecewiseExponential;
1207 erasePrefix(sys.name,
"alpha_");
1214 if (
auto prod =
dynamic_cast<RooProduct *
>(arg)) {
1215 for (
const auto &
e : prod->components()) {
1216 collectElements(elems,
e);
1225 for (
auto *var : list) {
1235 std::vector<double> hist;
1236 std::vector<double> histError;
1237 std::vector<NormFactor> normfactors;
1238 std::vector<NormSys> normsys;
1239 std::vector<HistoSys> histosys;
1240 std::vector<ShapeSys> shapesys;
1241 std::vector<GenericElement> tmpElements;
1242 std::vector<GenericElement> otherElements;
1243 bool useBarlowBeestonLight =
false;
1244 std::vector<RooAbsReal *> staterrorParameters;
1250 std::string parname = par->
GetName();
1251 bool isConstrained =
false;
1252 for (
RooAbsArg const *pdf : ws->allPdfs()) {
1253 if (
auto gauss =
dynamic_cast<RooGaussian const *
>(pdf)) {
1254 if (parname == gauss->getX().GetName()) {
1255 sample.normfactors.emplace_back(*par, gauss);
1256 isConstrained =
true;
1261 sample.normfactors.emplace_back(*par);
1266 std::vector<Sample> samples;
1267 std::map<int, double> tot_yield;
1268 std::map<int, double> tot_yield2;
1269 std::map<int, double> rel_errors;
1271 long unsigned int nBins = 0;
1280 channel.name = pdfname;
1281 erasePrefix(channel.name,
"model_");
1282 eraseSuffix(channel.name,
"_model");
1284 for (
size_t sampleidx = 0; sampleidx < sumpdf->
funcList().
size(); ++sampleidx) {
1286 std::vector<ParamHistFunc *> phfs;
1288 const auto func = sumpdf->
funcList().
at(sampleidx);
1290 erasePrefix(sample.name,
"L_x_");
1291 eraseSuffix(sample.name,
"_shapes");
1292 eraseSuffix(sample.name,
"_" + channel.name);
1293 erasePrefix(sample.name, pdfname +
"_");
1295 auto updateObservables = [&](
RooDataHist const &dataHist) {
1296 if (channel.varSet ==
nullptr) {
1297 channel.varSet = dataHist.get();
1298 channel.nBins = dataHist.numEntries();
1300 if (sample.hist.empty()) {
1301 auto *
w = dataHist.weightArray();
1302 sample.hist.assign(
w,
w + dataHist.numEntries());
1305 auto processElements = [&](
const auto &elements,
auto &&self) ->
void {
1315 }
else if (
auto constVar =
dynamic_cast<RooConstVar *
>(
e)) {
1316 if (constVar->getVal() != 1.) {
1317 sample.normfactors.emplace_back(*constVar);
1319 }
else if (
auto par =
dynamic_cast<RooRealVar *
>(
e)) {
1320 addNormFactor(par, sample, ws);
1321 }
else if (
auto hf =
dynamic_cast<const RooHistFunc *
>(
e)) {
1322 updateObservables(hf->dataHist());
1324 phfs.push_back(phf);
1328 for (
size_t i = 0; i < fip->variables().size(); ++i) {
1330 std::string sysname(var->
GetName());
1331 erasePrefix(sysname,
"alpha_");
1332 const auto *constraint = findConstraint(var);
1336 const std::string context =
"normsys modifier '" + sysname +
"' in sample '" + sample.name +
1337 "' of channel '" + channel.name +
"'";
1338 sample.normsys.emplace_back(
1339 sysname, var, fip->high()[i], fip->low()[i],
1340 interpolationFromCode(fip->interpolationCodes()[i], InterpolationClass::Flexible, context),
1352 expression.ReplaceAll((
"x[" + std::to_string(i) +
"]").c_str(),
p->
GetName());
1353 expression.ReplaceAll((
"@" + std::to_string(i)).c_str(),
p->
GetName());
1355 auto components = splitTopLevelProduct(expression.Data());
1356 if (components.size() == 0) {
1358 sample.otherElements.push_back(formula);
1361 std::vector<RooAbsArg *> realComponents;
1363 for (
auto &comp : components) {
1367 realComponents.push_back(part);
1371 auto normsys = parseOverallModifierFormula(comp, formula);
1372 if (normsys.param) {
1373 sample.normsys.emplace_back(std::move(normsys));
1378 std::string
name = std::string(formula->
GetName()) +
"_part" + std::to_string(idx);
1381 sample.tmpElements.push_back({var});
1383 self(realComponents, self);
1385 }
else if (
auto real =
dynamic_cast<RooAbsReal *
>(
e)) {
1386 sample.otherElements.push_back(real);
1392 collectElements(elems, func);
1393 collectElements(elems, sumpdf->
coefList().
at(sampleidx));
1394 processElements(elems, processElements);
1399 updateObservables(nh->dataHist());
1404 sortByName(sample.normfactors);
1405 sortByName(sample.normsys);
1411 std::string sysname(var->
GetName());
1412 erasePrefix(sysname,
"alpha_");
1415 const auto *constraint = findConstraint(var);
1419 const std::string context =
"histosys modifier '" + sysname +
"' in sample '" + sample.name +
1420 "' of channel '" + channel.name +
"'";
1421 sample.histosys.emplace_back(
1422 sysname, var, lo,
hi,
1423 interpolationFromCode(pip->
interpolationCodes()[i], InterpolationClass::Piecewise, context),
1429 sortByName(sample.histosys);
1433 if (
startsWith(std::string(phf->GetName()),
"mc_stat_")) {
1435 for (
const auto &
g : phf->paramList()) {
1436 sample.staterrorParameters.push_back(
static_cast<RooRealVar *
>(
g));
1439 channel.tot_yield[idx] += sample.hist[idx - 1];
1440 channel.tot_yield2[idx] += (sample.hist[idx - 1] * sample.hist[idx - 1]);
1442 channel.rel_errors[idx] = constraintRelError(*constraint, *
g);
1445 sample.useBarlowBeestonLight =
true;
1448 erasePrefix(sys.name, channel.name +
"_");
1449 bool isshapesys = eraseSuffix(sys.name,
"_ShapeSys") || eraseSuffix(sys.name,
"_shapeSys");
1450 bool isshapefactor = eraseSuffix(sys.name,
"_ShapeFactor") || eraseSuffix(sys.name,
"_shapeFactor");
1452 for (
const auto &
g : phf->paramList()) {
1453 sys.parameters.push_back(
static_cast<RooRealVar *
>(
g));
1456 constraint = findConstraint(
g);
1458 constraint = ws->
pdf(constraintName(
g->GetName()));
1459 if (!constraint && !
g->isConstant()) {
1462 }
else if (!isshapefactor) {
1466 sys.constraints.push_back(0.0);
1467 sys.constraintPdfs.push_back(
nullptr);
1469 sys.constraints.push_back(constraintRelError(*constraint, *
g));
1470 sys.constraintPdfs.push_back(constraint);
1473 sample.shapesys.emplace_back(std::move(sys));
1476 sortByName(sample.shapesys);
1479 channel.samples.emplace_back(std::move(sample));
1482 sortByName(channel.samples);
1494[[noreturn]]
void duplicateModifierError(
const Channel &channel,
const Sample &sample, std::string_view
type,
1495 std::string_view
name, std::string_view reason)
1497 std::stringstream ss;
1498 ss <<
"cannot combine duplicate modifier '" <<
name <<
"' of type '" <<
type <<
"' in sample '" << sample.name
1499 <<
"' of channel '" << channel.name <<
"': " << reason;
1503void warnDuplicateModifiersCombined(
const Channel &channel,
const Sample &sample, std::string_view
type,
1504 std::string_view
name, std::size_t count)
1506 std::stringstream ss;
1507 ss <<
"combined " << count <<
" duplicate modifiers named '" <<
name <<
"' of type '" <<
type <<
"' in sample '"
1508 << sample.name <<
"' of channel '" << channel.name <<
"'";
1517bool normSysSupportsMultiplicativeMerge(
const Interpolation &interpolation)
1519 return interpolation == multiplicativePiecewiseExponential || interpolation == multiplicativePolynomialExponential;
1525template <
class Modifiers,
class CombineFn>
1526void mergeDuplicateModifiers(
const Channel &channel,
const Sample &sample, Modifiers &modifiers, std::string_view
type,
1529 Modifiers mergedModifiers;
1530 mergedModifiers.reserve(modifiers.size());
1532 for (std::size_t begin = 0; begin < modifiers.size();) {
1533 std::size_t end = begin + 1;
1534 while (end < modifiers.size() && modifiers[end].name == modifiers[begin].name) {
1538 auto merged = modifiers[begin];
1539 for (std::size_t i = begin + 1; i < end; ++i) {
1540 const auto &
modifier = modifiers[i];
1541 if (!hasSameMetadata(merged.constraint,
modifier.constraint)) {
1542 duplicateModifierError(channel, sample,
type, merged.name,
"constraint metadata differs");
1544 if (!hasSameMetadata(merged.param,
modifier.param)) {
1545 duplicateModifierError(channel, sample,
type, merged.name,
"parameter metadata differs");
1547 if (merged.interpolation !=
modifier.interpolation) {
1548 duplicateModifierError(channel, sample,
type, merged.name,
"interpolation behaviours differ");
1553 if (end - begin > 1) {
1554 warnDuplicateModifiersCombined(channel, sample,
type, merged.name, end - begin);
1556 mergedModifiers.emplace_back(std::move(merged));
1560 modifiers = std::move(mergedModifiers);
1563void mergeDuplicateNormSys(
const Channel &channel,
Sample &sample)
1565 mergeDuplicateModifiers(channel, sample, sample.normsys,
"normsys", [&](NormSys &merged,
const NormSys &
modifier) {
1566 if (!normSysSupportsMultiplicativeMerge(merged.interpolation)) {
1567 duplicateModifierError(channel, sample,
"normsys", merged.name,
1568 "multiplicative combination is only valid for log-space interpolation");
1575void mergeDuplicateHistoSys(
const Channel &channel,
Sample &sample)
1577 const std::size_t nBins = sample.hist.size();
1578 mergeDuplicateModifiers(
1580 if (merged.interpolation != additivePolynomialLinear) {
1581 duplicateModifierError(channel, sample,
"histosys", merged.name,
1582 "this interpolation cannot currently be combined for duplicate histosys "
1585 if (merged.low.size() != nBins || merged.high.size() != nBins ||
modifier.low.size() != nBins ||
1587 duplicateModifierError(channel, sample,
"histosys", merged.name,
"histogram binning differs");
1589 for (std::size_t bin = 0; bin < nBins; ++bin) {
1590 merged.low[bin] +=
modifier.low[bin] - sample.hist[bin];
1591 merged.high[bin] +=
modifier.high[bin] - sample.hist[bin];
1596void ensureUniqueModifiers(
const Channel &channel,
const Sample &sample)
1598 std::set<std::pair<std::string, std::string>> seen;
1599 auto add = [&](std::string
type,
const std::string &
name) {
1600 if (!seen.emplace(
type,
name).second) {
1601 duplicateModifierError(channel, sample,
type,
name,
1602 "this modifier type cannot be combined without changing its meaning");
1606 for (
const auto &
modifier : sample.normfactors)
1608 for (
const auto &
modifier : sample.normsys)
1610 for (
const auto &
modifier : sample.histosys)
1612 for (
const auto &
modifier : sample.shapesys)
1614 for (
const auto &
modifier : sample.otherElements)
1616 for (
const auto &
modifier : sample.tmpElements)
1618 if (sample.useBarlowBeestonLight)
1619 add(::Literals::staterror, ::Literals::staterror);
1622void canonicalizeModifiers(
Channel &channel)
1624 for (
auto &sample : channel.samples) {
1625 mergeDuplicateNormSys(channel, sample);
1626 mergeDuplicateHistoSys(channel, sample);
1627 ensureUniqueModifiers(channel, sample);
1631void configureStatError(
Channel &channel)
1633 for (
auto &sample : channel.samples) {
1634 if (sample.useBarlowBeestonLight) {
1635 sample.histError.resize(sample.hist.size());
1636 for (
auto bin : channel.rel_errors) {
1639 const int i = bin.first;
1640 const double relerr_tot = bin.second;
1641 const double count = sample.hist[i - 1];
1644 sample.histError[i - 1] =
1645 round_prec(relerr_tot * channel.tot_yield[i] / std::sqrt(channel.tot_yield2[i]) * count, 7);
1651std::optional<Interpolation> defaultInterpolation(
const Channel &channel)
1653 std::map<Interpolation, std::size_t> counts;
1654 for (
const auto &sample : channel.samples) {
1655 for (
const auto &
modifier : sample.normsys) {
1658 for (
const auto &
modifier : sample.histosys) {
1662 if (counts.empty()) {
1663 return std::nullopt;
1666 auto best = counts.begin();
1667 for (
auto current = std::next(counts.begin()); current != counts.end(); ++current) {
1668 if (current->second > best->second ||
1669 (current->second == best->second && current->first == multiplicativePolynomialExponential &&
1670 best->first != multiplicativePolynomialExponential)) {
1681 auto writeConstraint = [](
JSONNode &mod,
auto const &sys) {
1682 if (sys.constraint) {
1683 mod[
"constraint"] << sys.constraint->GetName();
1689 mod[
"name"] <<
name;
1690 mod[
"type"] <<
type;
1694 elem[
"type"] <<
"histfactory_dist";
1695 const auto channelDefaultInterpolation = defaultInterpolation(channel);
1696 if (channelDefaultInterpolation) {
1697 writeInterpolation(elem[
"default_interpolation"], *channelDefaultInterpolation);
1700 bool observablesWritten =
false;
1701 for (
const auto &sample : channel.samples) {
1705 auto &modifiers = s[
"modifiers"];
1708 for (
const auto &nf : sample.normfactors) {
1711 mod[
"name"] << nf.name;
1712 mod[
"parameter"] << nf.param->GetName();
1713 mod[
"type"] <<
"normfactor";
1714 if (nf.constraint) {
1715 mod[
"constraint"] << nf.constraint->GetName();
1720 for (
const auto &sys : sample.normsys) {
1721 auto &mod = addModifier(modifiers, sys.name,
"normsys");
1722 mod[
"parameter"] << sys.param->GetName();
1723 if (!channelDefaultInterpolation || sys.interpolation != *channelDefaultInterpolation) {
1724 writeInterpolation(mod[
"interpolation"], sys.interpolation);
1726 writeConstraint(mod, sys);
1728 data[
"lo"] << sys.low;
1729 data[
"hi"] << sys.high;
1732 for (
const auto &sys : sample.histosys) {
1733 auto &mod = addModifier(modifiers, sys.name,
"histosys");
1734 mod[
"parameter"] << sys.param->GetName();
1735 if (!channelDefaultInterpolation || sys.interpolation != *channelDefaultInterpolation) {
1736 writeInterpolation(mod[
"interpolation"], sys.interpolation);
1738 writeConstraint(mod, sys);
1740 if (channel.nBins != sys.low.size() || channel.nBins != sys.high.size()) {
1742 " bins expected, but " + std::to_string(sys.low.size()) +
"/" +
1743 std::to_string(sys.high.size()) +
" found in nominal histogram errors!");
1749 for (
const auto &sys : sample.shapesys) {
1750 auto &mod = addModifier(modifiers, sys.name,
"shapesys");
1751 exportGammaParameters(mod, sys.parameters);
1752 if (std::any_of(sys.constraintPdfs.begin(), sys.constraintPdfs.end(),
1753 [](
auto *pdf) { return pdf != nullptr; })) {
1754 auto &constraintNames = mod[
"constraints"].
set_seq();
1755 for (
auto *constraint : sys.constraintPdfs) {
1759 constraintNames.append_child().set_null();
1766 for (
const auto &other : sample.otherElements) {
1767 addModifier(modifiers, other.name,
"custom");
1769 for (
const auto &other : sample.tmpElements) {
1770 addModifier(modifiers, other.name,
"custom");
1773 if (sample.useBarlowBeestonLight) {
1774 auto &mod = addModifier(modifiers, ::Literals::staterror, ::Literals::staterror);
1775 exportGammaParameters(mod, sample.staterrorParameters);
1778 if (!observablesWritten) {
1779 auto &output = elem[
"axes"].
set_seq();
1783 observablesWritten =
true;
1785 auto &dataNode = s[
"data"].set_map();
1786 if (channel.nBins != sample.hist.size()) {
1788 std::to_string(sample.hist.size()) +
" found in nominal histogram!");
1791 if (!sample.histError.empty()) {
1792 if (channel.nBins != sample.histError.size()) {
1794 " bins expected, but " + std::to_string(sample.histError.size()) +
1795 " found in nominal histogram errors!");
1804std::vector<RooAbsPdf *> findLostConstraints(
const Channel &channel,
const std::vector<RooAbsPdf *> &constraints)
1807 std::set<const RooAbsReal *> vars;
1808 for (
const auto &sample : channel.samples) {
1809 for (
const auto &nf : sample.normfactors) {
1810 vars.insert(nf.param);
1812 for (
const auto &sys : sample.normsys) {
1813 vars.insert(sys.param);
1816 for (
const auto &sys : sample.histosys) {
1817 vars.insert(sys.param);
1819 for (
const auto &sys : sample.shapesys) {
1820 for (
const auto &par : sys.parameters) {
1824 if (sample.useBarlowBeestonLight) {
1825 for (
const auto &par : sample.staterrorParameters) {
1832 std::vector<RooAbsPdf *> lostConstraints;
1833 for (
auto *pdf : constraints) {
1834 bool related =
false;
1835 for (
const auto *var : vars) {
1836 if (pdf->dependsOn(*var)) {
1841 lostConstraints.push_back(pdf);
1845 return lostConstraints;
1849 std::vector<RooAbsPdf *> constraints,
JSONNode &elem)
1856 for (
RooAbsArg *sample : sumpdf->funcList()) {
1862 auto channel = readChannel(tool, pdfname, sumpdf);
1865 if (channel.samples.size() == 0)
1867 for (
auto &sample : channel.samples) {
1868 if (sample.hist.empty()) {
1873 canonicalizeModifiers(channel);
1876 configureStatError(channel);
1878 auto lostConstraints = findLostConstraints(channel, constraints);
1880 for (
const auto *constraint : lostConstraints) {
1882 "losing constraint term '" + std::string(constraint->
GetName()) +
1883 "', implicit constraints are not supported by HS3 yet! The term will appear in the HS3 file, but will not be "
1884 "picked up when creating a likelihood from it! You will have to add it manually as an external constraint.");
1889 auto queueConstraints = [&](
auto const &modifiers) {
1896 for (
const auto &sample : channel.samples) {
1897 queueConstraints(sample.normfactors);
1898 queueConstraints(sample.normsys);
1899 queueConstraints(sample.histosys);
1900 for (
auto &
modifier : sample.shapesys) {
1901 for (
auto *constraint :
modifier.constraintPdfs) {
1910 for (
const auto &sample : channel.samples) {
1911 for (
auto &
modifier : sample.otherElements) {
1914 for (
auto &
modifier : sample.tmpElements) {
1929 return exportChannel(tool, channel, elem);
1934 bool autoExportDependants()
const override {
return false; }
1937 std::vector<RooAbsPdf *> constraints;
1947 constraints.push_back(pdf);
1953 bool ok = tryExportHistFactory(tool, prodpdf->
GetName(), sumpdf, constraints, elem);
1956 std::string
const &key()
const override
1958 static const std::string keystring =
"histfactory_dist";
1963 return tryExport(tool,
static_cast<const RooProdPdf *
>(
p), elem);
1969 bool autoExportDependants()
const override {
return false; }
1972 std::vector<RooAbsPdf *> constraints;
1973 return tryExportHistFactory(tool, sumpdf->
GetName(), sumpdf, constraints, elem);
1975 std::string
const &key()
const override
1977 static const std::string keystring =
"histfactory_dist";
1982 return tryExport(tool,
static_cast<const RooRealSumPdf *
>(
p), elem);
1989 registerImporter<HistFactoryImporter>(
"histfactory_dist",
true);
1990 registerImporter<PiecewiseInterpolationFactory>(
"interpolation",
true);
1991 registerImporter<FlexibleInterpVarFactory>(
"interpolation0d",
true);
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
Bool_t operator!=(const TDatime &d1, const TDatime &d2)
Bool_t operator<(const TDatime &d1, const TDatime &d2)
Bool_t operator==(const TDatime &d1, const TDatime &d2)
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 char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
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
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 Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
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 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.
TClass * IsA() const override
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.
void setConstant(bool value=true)
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_null()=0
virtual JSONNode & set_seq()=0
virtual bool is_container() const =0
virtual bool is_map() const =0
virtual bool has_child(std::string const &) const =0
JSONNode const * find(std::string const &key) const
virtual bool is_null() const =0
virtual bool has_val() const =0
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:
const RooArgList & funcList() const
const RooArgList & coefList() const
Variable that can be changed from the outside.
void setError(double value)
This class encapsulates all information for the statistical interpretation of one experiment.
const RooListProxy & variables() const
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.
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.
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
const char * GetName() const override
Returns name of object.
virtual const char * GetName() const
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)
if(fPos !=fText.size()) Fail("unexpected trailing content")
std::string GetName(TCppScope_t)
#define STATIC_EXECUTE(MY_FUNC)
static uint64_t sum(uint64_t i)